diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 17:35:05 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 17:39:31 +0000 |
commit | 85c675d0d09a45a135bddd15d7b385f8758c32fb (patch) | |
tree | 76267dbc9b9a130337be3640948fe397b04ac629 /drivers/media | |
parent | Adding upstream version 6.6.15. (diff) | |
download | linux-85c675d0d09a45a135bddd15d7b385f8758c32fb.tar.xz linux-85c675d0d09a45a135bddd15d7b385f8758c32fb.zip |
Adding upstream version 6.7.7.upstream/6.7.7
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/media')
353 files changed, 15002 insertions, 9786 deletions
diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c index 09ca83c233..6bb49bb3f9 100644 --- a/drivers/media/cec/core/cec-adap.c +++ b/drivers/media/cec/core/cec-adap.c @@ -1688,6 +1688,11 @@ void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) } EXPORT_SYMBOL_GPL(cec_s_phys_addr); +/* + * Note: In the drm subsystem, prefer calling (if possible): + * + * cec_s_phys_addr(adap, connector->display_info.source_physical_address, false); + */ void cec_s_phys_addr_from_edid(struct cec_adapter *adap, const struct edid *edid) { diff --git a/drivers/media/cec/core/cec-notifier.c b/drivers/media/cec/core/cec-notifier.c index a41f24172b..1fed0b1c71 100644 --- a/drivers/media/cec/core/cec-notifier.c +++ b/drivers/media/cec/core/cec-notifier.c @@ -196,6 +196,11 @@ void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) } EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr); +/* + * Note: In the drm subsystem, prefer calling (if possible): + * + * cec_notifier_set_phys_addr(n, connector->display_info.source_physical_address); + */ void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n, const struct edid *edid) { diff --git a/drivers/media/cec/platform/Kconfig b/drivers/media/cec/platform/Kconfig index b672d3142e..ede81fe331 100644 --- a/drivers/media/cec/platform/Kconfig +++ b/drivers/media/cec/platform/Kconfig @@ -99,7 +99,7 @@ config CEC_TEGRA config CEC_SECO tristate "SECO Boards HDMI CEC driver" - depends on (X86 || IA64) || COMPILE_TEST + depends on X86 || COMPILE_TEST depends on PCI && DMI select CEC_CORE select CEC_NOTIFIER diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index c17faf0028..42dde3f0db 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -22,50 +22,124 @@ #define DRV_NAME "cros-ec-cec" /** - * struct cros_ec_cec - Driver data for EC CEC + * struct cros_ec_cec_port - Driver data for a single EC CEC port * - * @cros_ec: Pointer to EC device - * @notifier: Notifier info for responding to EC events + * @port_num: port number * @adap: CEC adapter * @notify: CEC notifier pointer * @rx_msg: storage for a received message + * @cros_ec_cec: pointer to the parent struct */ -struct cros_ec_cec { - struct cros_ec_device *cros_ec; - struct notifier_block notifier; +struct cros_ec_cec_port { + int port_num; struct cec_adapter *adap; struct cec_notifier *notify; struct cec_msg rx_msg; + struct cros_ec_cec *cros_ec_cec; +}; + +/** + * struct cros_ec_cec - Driver data for EC CEC + * + * @cros_ec: Pointer to EC device + * @notifier: Notifier info for responding to EC events + * @write_cmd_version: Highest supported version of EC_CMD_CEC_WRITE_MSG. + * @num_ports: Number of CEC ports + * @ports: Array of ports + */ +struct cros_ec_cec { + struct cros_ec_device *cros_ec; + struct notifier_block notifier; + int write_cmd_version; + int num_ports; + struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS]; }; +static void cros_ec_cec_received_message(struct cros_ec_cec_port *port, + uint8_t *msg, uint8_t len) +{ + if (len > CEC_MAX_MSG_SIZE) + len = CEC_MAX_MSG_SIZE; + + port->rx_msg.len = len; + memcpy(port->rx_msg.msg, msg, len); + + cec_received_msg(port->adap, &port->rx_msg); +} + static void handle_cec_message(struct cros_ec_cec *cros_ec_cec) { struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; uint8_t *cec_message = cros_ec->event_data.data.cec_message; unsigned int len = cros_ec->event_size; + struct cros_ec_cec_port *port; + /* + * There are two ways of receiving CEC messages: + * 1. Old EC firmware which only supports one port sends the data in a + * cec_message MKBP event. + * 2. New EC firmware which supports multiple ports uses + * EC_MKBP_CEC_HAVE_DATA to notify that data is ready and + * EC_CMD_CEC_READ_MSG to read it. + * Check that the EC only has one CEC port, and then we can assume the + * message is from port 0. + */ + if (cros_ec_cec->num_ports != 1) { + dev_err(cros_ec->dev, + "received cec_message on device with %d ports\n", + cros_ec_cec->num_ports); + return; + } + port = cros_ec_cec->ports[0]; - if (len > CEC_MAX_MSG_SIZE) - len = CEC_MAX_MSG_SIZE; - cros_ec_cec->rx_msg.len = len; - memcpy(cros_ec_cec->rx_msg.msg, cec_message, len); + cros_ec_cec_received_message(port, cec_message, len); +} + +static void cros_ec_cec_read_message(struct cros_ec_cec_port *port) +{ + struct cros_ec_device *cros_ec = port->cros_ec_cec->cros_ec; + struct ec_params_cec_read params = { + .port = port->port_num, + }; + struct ec_response_cec_read response; + int ret; - cec_received_msg(cros_ec_cec->adap, &cros_ec_cec->rx_msg); + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_READ_MSG, ¶ms, + sizeof(params), &response, sizeof(response)); + if (ret < 0) { + dev_err(cros_ec->dev, + "error reading CEC message on EC: %d\n", ret); + return; + } + + cros_ec_cec_received_message(port, response.msg, response.msg_len); } static void handle_cec_event(struct cros_ec_cec *cros_ec_cec) { struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - uint32_t events = cros_ec->event_data.data.cec_events; + uint32_t cec_events = cros_ec->event_data.data.cec_events; + uint32_t port_num = EC_MKBP_EVENT_CEC_GET_PORT(cec_events); + uint32_t events = EC_MKBP_EVENT_CEC_GET_EVENTS(cec_events); + struct cros_ec_cec_port *port; + + if (port_num >= cros_ec_cec->num_ports) { + dev_err(cros_ec->dev, + "received CEC event for invalid port %d\n", port_num); + return; + } + port = cros_ec_cec->ports[port_num]; if (events & EC_MKBP_CEC_SEND_OK) - cec_transmit_attempt_done(cros_ec_cec->adap, - CEC_TX_STATUS_OK); + cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK); /* FW takes care of all retries, tell core to avoid more retries */ if (events & EC_MKBP_CEC_SEND_FAILED) - cec_transmit_attempt_done(cros_ec_cec->adap, + cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_NACK); + + if (events & EC_MKBP_CEC_HAVE_DATA) + cros_ec_cec_read_message(port); } static int cros_ec_cec_event(struct notifier_block *nb, @@ -93,20 +167,18 @@ static int cros_ec_cec_event(struct notifier_block *nb, static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) { - struct cros_ec_cec *cros_ec_cec = adap->priv; + struct cros_ec_cec_port *port = adap->priv; + struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - struct { - struct cros_ec_command msg; - struct ec_params_cec_set data; - } __packed msg = {}; + struct ec_params_cec_set params = { + .cmd = CEC_CMD_LOGICAL_ADDRESS, + .port = port->port_num, + .val = logical_addr, + }; int ret; - msg.msg.command = EC_CMD_CEC_SET; - msg.msg.outsize = sizeof(msg.data); - msg.data.cmd = CEC_CMD_LOGICAL_ADDRESS; - msg.data.val = logical_addr; - - ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params), + NULL, 0); if (ret < 0) { dev_err(cros_ec->dev, "error setting CEC logical address on EC: %d\n", ret); @@ -119,19 +191,26 @@ static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts, u32 signal_free_time, struct cec_msg *cec_msg) { - struct cros_ec_cec *cros_ec_cec = adap->priv; + struct cros_ec_cec_port *port = adap->priv; + struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - struct { - struct cros_ec_command msg; - struct ec_params_cec_write data; - } __packed msg = {}; + struct ec_params_cec_write params; + struct ec_params_cec_write_v1 params_v1; int ret; - msg.msg.command = EC_CMD_CEC_WRITE_MSG; - msg.msg.outsize = cec_msg->len; - memcpy(msg.data.msg, cec_msg->msg, cec_msg->len); + if (cros_ec_cec->write_cmd_version == 0) { + memcpy(params.msg, cec_msg->msg, cec_msg->len); + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, ¶ms, + cec_msg->len, NULL, 0); + } else { + params_v1.port = port->port_num; + params_v1.msg_len = cec_msg->len; + memcpy(params_v1.msg, cec_msg->msg, cec_msg->len); + ret = cros_ec_cmd(cros_ec, cros_ec_cec->write_cmd_version, + EC_CMD_CEC_WRITE_MSG, ¶ms_v1, + sizeof(params_v1), NULL, 0); + } - ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); if (ret < 0) { dev_err(cros_ec->dev, "error writing CEC msg on EC: %d\n", ret); @@ -143,20 +222,18 @@ static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts, static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable) { - struct cros_ec_cec *cros_ec_cec = adap->priv; + struct cros_ec_cec_port *port = adap->priv; + struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - struct { - struct cros_ec_command msg; - struct ec_params_cec_set data; - } __packed msg = {}; + struct ec_params_cec_set params = { + .cmd = CEC_CMD_ENABLE, + .port = port->port_num, + .val = enable, + }; int ret; - msg.msg.command = EC_CMD_CEC_SET; - msg.msg.outsize = sizeof(msg.data); - msg.data.cmd = CEC_CMD_ENABLE; - msg.data.val = enable; - - ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); + ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params), + NULL, 0); if (ret < 0) { dev_err(cros_ec->dev, "error %sabling CEC on EC: %d\n", @@ -203,38 +280,54 @@ static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops, #if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI) /* - * The Firmware only handles a single CEC interface tied to a single HDMI - * connector we specify along with the DRM device name handling the HDMI output + * Specify the DRM device name handling the HDMI output and the HDMI connector + * corresponding to each CEC port. The order of connectors must match the order + * in the EC (first connector is EC port 0, ...), and the number of connectors + * must match the number of ports in the EC (which can be queried using the + * EC_CMD_CEC_PORT_COUNT host command). */ struct cec_dmi_match { const char *sys_vendor; const char *product_name; const char *devname; - const char *conn; + const char *const *conns; }; +static const char *const port_b_conns[] = { "Port B", NULL }; +static const char *const port_db_conns[] = { "Port D", "Port B", NULL }; +static const char *const port_ba_conns[] = { "Port B", "Port A", NULL }; +static const char *const port_d_conns[] = { "Port D", NULL }; + static const struct cec_dmi_match cec_dmi_match_table[] = { /* Google Fizz */ - { "Google", "Fizz", "0000:00:02.0", "Port B" }, + { "Google", "Fizz", "0000:00:02.0", port_b_conns }, /* Google Brask */ - { "Google", "Brask", "0000:00:02.0", "Port B" }, + { "Google", "Brask", "0000:00:02.0", port_b_conns }, /* Google Moli */ - { "Google", "Moli", "0000:00:02.0", "Port B" }, + { "Google", "Moli", "0000:00:02.0", port_b_conns }, /* Google Kinox */ - { "Google", "Kinox", "0000:00:02.0", "Port B" }, + { "Google", "Kinox", "0000:00:02.0", port_b_conns }, /* Google Kuldax */ - { "Google", "Kuldax", "0000:00:02.0", "Port B" }, + { "Google", "Kuldax", "0000:00:02.0", port_b_conns }, /* Google Aurash */ - { "Google", "Aurash", "0000:00:02.0", "Port B" }, + { "Google", "Aurash", "0000:00:02.0", port_b_conns }, /* Google Gladios */ - { "Google", "Gladios", "0000:00:02.0", "Port B" }, + { "Google", "Gladios", "0000:00:02.0", port_b_conns }, /* Google Lisbon */ - { "Google", "Lisbon", "0000:00:02.0", "Port B" }, + { "Google", "Lisbon", "0000:00:02.0", port_b_conns }, + /* Google Dibbi */ + { "Google", "Dibbi", "0000:00:02.0", port_db_conns }, + /* Google Constitution */ + { "Google", "Constitution", "0000:00:02.0", port_ba_conns }, + /* Google Boxy */ + { "Google", "Boxy", "0000:00:02.0", port_d_conns }, + /* Google Taranza */ + { "Google", "Taranza", "0000:00:02.0", port_db_conns }, }; static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, - const char **conn) + const char * const **conns) { int i; @@ -251,7 +344,7 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, if (!d) return ERR_PTR(-EPROBE_DEFER); put_device(d); - *conn = m->conn; + *conns = m->conns; return d; } } @@ -265,23 +358,137 @@ static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, #else static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, - const char **conn) + const char * const **conns) { return ERR_PTR(-ENODEV); } #endif +static int cros_ec_cec_get_num_ports(struct cros_ec_cec *cros_ec_cec) +{ + struct ec_response_cec_port_count response; + int ret; + + ret = cros_ec_cmd(cros_ec_cec->cros_ec, 0, EC_CMD_CEC_PORT_COUNT, NULL, + 0, &response, sizeof(response)); + if (ret < 0) { + /* + * Old EC firmware only supports one port and does not support + * the port count command, so fall back to assuming one port. + */ + cros_ec_cec->num_ports = 1; + return 0; + } + + if (response.port_count == 0) { + dev_err(cros_ec_cec->cros_ec->dev, + "EC reports 0 CEC ports\n"); + return -ENODEV; + } + + if (response.port_count > EC_CEC_MAX_PORTS) { + dev_err(cros_ec_cec->cros_ec->dev, + "EC reports too many ports: %d\n", response.port_count); + return -EINVAL; + } + + cros_ec_cec->num_ports = response.port_count; + return 0; +} + +static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec) +{ + struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; + struct ec_params_get_cmd_versions_v1 params = { + .cmd = EC_CMD_CEC_WRITE_MSG, + }; + struct ec_response_get_cmd_versions response; + int ret; + + ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GET_CMD_VERSIONS, ¶ms, + sizeof(params), &response, sizeof(response)); + if (ret < 0) { + dev_err(cros_ec->dev, + "error getting CEC write command version: %d\n", ret); + return ret; + } + + if (response.version_mask & EC_VER_MASK(1)) { + cros_ec_cec->write_cmd_version = 1; + } else { + if (cros_ec_cec->num_ports != 1) { + dev_err(cros_ec->dev, + "v0 write command only supports 1 port, %d reported\n", + cros_ec_cec->num_ports); + return -EINVAL; + } + cros_ec_cec->write_cmd_version = 0; + } + + return 0; +} + +static int cros_ec_cec_init_port(struct device *dev, + struct cros_ec_cec *cros_ec_cec, + int port_num, struct device *hdmi_dev, + const char * const *conns) +{ + struct cros_ec_cec_port *port; + int ret; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + port->cros_ec_cec = cros_ec_cec; + port->port_num = port_num; + + port->adap = cec_allocate_adapter(&cros_ec_cec_ops, port, DRV_NAME, + CEC_CAP_DEFAULTS | + CEC_CAP_CONNECTOR_INFO, 1); + if (IS_ERR(port->adap)) + return PTR_ERR(port->adap); + + if (!conns[port_num]) { + dev_err(dev, "no conn for port %d\n", port_num); + ret = -ENODEV; + goto out_probe_adapter; + } + + port->notify = cec_notifier_cec_adap_register(hdmi_dev, conns[port_num], + port->adap); + if (!port->notify) { + ret = -ENOMEM; + goto out_probe_adapter; + } + + ret = cec_register_adapter(port->adap, dev); + if (ret < 0) + goto out_probe_notify; + + cros_ec_cec->ports[port_num] = port; + + return 0; + +out_probe_notify: + cec_notifier_cec_adap_unregister(port->notify, port->adap); +out_probe_adapter: + cec_delete_adapter(port->adap); + return ret; +} + static int cros_ec_cec_probe(struct platform_device *pdev) { struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); struct cros_ec_device *cros_ec = ec_dev->ec_dev; struct cros_ec_cec *cros_ec_cec; + struct cros_ec_cec_port *port; struct device *hdmi_dev; - const char *conn = NULL; + const char * const *conns = NULL; int ret; - hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conn); + hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns); if (IS_ERR(hdmi_dev)) return PTR_ERR(hdmi_dev); @@ -295,18 +502,19 @@ static int cros_ec_cec_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec, - DRV_NAME, - CEC_CAP_DEFAULTS | - CEC_CAP_CONNECTOR_INFO, 1); - if (IS_ERR(cros_ec_cec->adap)) - return PTR_ERR(cros_ec_cec->adap); + ret = cros_ec_cec_get_num_ports(cros_ec_cec); + if (ret) + return ret; - cros_ec_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, conn, - cros_ec_cec->adap); - if (!cros_ec_cec->notify) { - ret = -ENOMEM; - goto out_probe_adapter; + ret = cros_ec_cec_get_write_cmd_version(cros_ec_cec); + if (ret) + return ret; + + for (int i = 0; i < cros_ec_cec->num_ports; i++) { + ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i, + hdmi_dev, conns); + if (ret) + goto unregister_ports; } /* Get CEC events from the EC. */ @@ -315,20 +523,24 @@ static int cros_ec_cec_probe(struct platform_device *pdev) &cros_ec_cec->notifier); if (ret) { dev_err(&pdev->dev, "failed to register notifier\n"); - goto out_probe_notify; + goto unregister_ports; } - ret = cec_register_adapter(cros_ec_cec->adap, &pdev->dev); - if (ret < 0) - goto out_probe_notify; - return 0; -out_probe_notify: - cec_notifier_cec_adap_unregister(cros_ec_cec->notify, - cros_ec_cec->adap); -out_probe_adapter: - cec_delete_adapter(cros_ec_cec->adap); +unregister_ports: + /* + * Unregister any adapters which have been registered. We don't add the + * port to the array until the adapter has been registered successfully, + * so any non-NULL ports must have been registered. + */ + for (int i = 0; i < cros_ec_cec->num_ports; i++) { + port = cros_ec_cec->ports[i]; + if (!port) + break; + cec_notifier_cec_adap_unregister(port->notify, port->adap); + cec_unregister_adapter(port->adap); + } return ret; } @@ -336,6 +548,7 @@ static void cros_ec_cec_remove(struct platform_device *pdev) { struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; + struct cros_ec_cec_port *port; int ret; /* @@ -349,9 +562,11 @@ static void cros_ec_cec_remove(struct platform_device *pdev) if (ret) dev_err(dev, "failed to unregister notifier\n"); - cec_notifier_cec_adap_unregister(cros_ec_cec->notify, - cros_ec_cec->adap); - cec_unregister_adapter(cros_ec_cec->adap); + for (int i = 0; i < cros_ec_cec->num_ports; i++) { + port = cros_ec_cec->ports[i]; + cec_notifier_cec_adap_unregister(port->notify, port->adap); + cec_unregister_adapter(port->adap); + } } static struct platform_driver cros_ec_cec_driver = { diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index e0beefd80d..73990e469d 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -353,31 +353,21 @@ static const struct file_operations debugfs_stats_ops = { int smsdvb_debugfs_create(struct smsdvb_client_t *client) { struct smscore_device_t *coredev = client->coredev; - struct dentry *d; struct smsdvb_debugfs *debug_data; if (!smsdvb_debugfs_usb_root || !coredev->is_usb_device) return -ENODEV; - client->debugfs = debugfs_create_dir(coredev->devpath, - smsdvb_debugfs_usb_root); - if (IS_ERR_OR_NULL(client->debugfs)) { - pr_info("Unable to create debugfs %s directory.\n", - coredev->devpath); - return -ENODEV; - } - - d = debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs, - client, &debugfs_stats_ops); - if (!d) { - debugfs_remove(client->debugfs); - return -ENOMEM; - } - debug_data = kzalloc(sizeof(*client->debug_data), GFP_KERNEL); if (!debug_data) return -ENOMEM; + client->debugfs = debugfs_create_dir(coredev->devpath, + smsdvb_debugfs_usb_root); + + debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs, + client, &debugfs_stats_ops); + client->debug_data = debug_data; client->prt_dvb_stats = smsdvb_print_dvb_stats; client->prt_isdb_stats = smsdvb_print_isdb_stats; diff --git a/drivers/media/common/videobuf2/frame_vector.c b/drivers/media/common/videobuf2/frame_vector.c index fd87747be9..41f289c75c 100644 --- a/drivers/media/common/videobuf2/frame_vector.c +++ b/drivers/media/common/videobuf2/frame_vector.c @@ -159,7 +159,7 @@ EXPORT_SYMBOL(frame_vector_to_pfns); struct frame_vector *frame_vector_create(unsigned int nr_frames) { struct frame_vector *vec; - int size = sizeof(struct frame_vector) + sizeof(void *) * nr_frames; + int size = struct_size(vec, ptrs, nr_frames); if (WARN_ON_ONCE(nr_frames == 0)) return NULL; diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index cf6727d9c8..19f80ff497 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -2648,9 +2648,14 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) return -EBUSY; /* - * Start with count 1, driver can increase it in queue_setup() + * Start with q->min_buffers_needed + 1, driver can increase it in + * queue_setup() + * + * 'min_buffers_needed' buffers need to be queued up before you + * can start streaming, plus 1 for userspace (or in this case, + * kernelspace) processing. */ - count = 1; + count = max(2, q->min_buffers_needed + 1); dprintk(q, 3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n", (read) ? "read" : "write", count, q->fileio_read_once, @@ -2890,7 +2895,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ if (copy_timestamp) b->timestamp = ktime_get_ns(); ret = vb2_core_qbuf(q, index, NULL, NULL); - dprintk(q, 5, "vb2_dbuf result: %d\n", ret); + dprintk(q, 5, "vb2_qbuf result: %d\n", ret); if (ret) return ret; diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index 2fa455d4a0..3d4fd4ef53 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -542,13 +542,14 @@ static void vb2_dc_put_userptr(void *buf_priv) */ dma_unmap_sgtable(buf->dev, sgt, buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC); - pages = frame_vector_pages(buf->vec); - /* sgt should exist only if vector contains pages... */ - BUG_ON(IS_ERR(pages)); if (buf->dma_dir == DMA_FROM_DEVICE || - buf->dma_dir == DMA_BIDIRECTIONAL) - for (i = 0; i < frame_vector_count(buf->vec); i++) - set_page_dirty_lock(pages[i]); + buf->dma_dir == DMA_BIDIRECTIONAL) { + pages = frame_vector_pages(buf->vec); + /* sgt should exist only if vector contains pages... */ + if (!WARN_ON_ONCE(IS_ERR(pages))) + for (i = 0; i < frame_vector_count(buf->vec); i++) + set_page_dirty_lock(pages[i]); + } sg_free_table(sgt); kfree(sgt); } else { diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 7c635e2921..7d953706f3 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -133,13 +133,15 @@ static void vb2_vmalloc_put_userptr(void *buf_priv) if (!buf->vec->is_pfns) { n_pages = frame_vector_count(buf->vec); - pages = frame_vector_pages(buf->vec); if (vaddr) vm_unmap_ram((void *)vaddr, n_pages); if (buf->dma_dir == DMA_FROM_DEVICE || - buf->dma_dir == DMA_BIDIRECTIONAL) - for (i = 0; i < n_pages; i++) - set_page_dirty_lock(pages[i]); + buf->dma_dir == DMA_BIDIRECTIONAL) { + pages = frame_vector_pages(buf->vec); + if (!WARN_ON_ONCE(IS_ERR(pages))) + for (i = 0; i < n_pages; i++) + set_page_dirty_lock(pages[i]); + } } else { iounmap((__force void __iomem *)buf->vaddr); } diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index a738573c8c..19d8de400a 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -4779,8 +4779,8 @@ set_frequency(struct drx_demod_instance *demod, bool image_to_select; s32 fm_frequency_shift = 0; - rf_mirror = (ext_attr->mirror == DRX_MIRROR_YES) ? true : false; - tuner_mirror = demod->my_common_attr->mirror_freq_spect ? false : true; + rf_mirror = ext_attr->mirror == DRX_MIRROR_YES; + tuner_mirror = !demod->my_common_attr->mirror_freq_spect; /* Program frequency shifter No need to account for mirroring on RF @@ -8765,7 +8765,7 @@ static int qam_flip_spec(struct drx_demod_instance *demod, struct drx_channel *c goto rw_error; } ext_attr->iqm_fs_rate_ofs = iqm_fs_rate_ofs; - ext_attr->pos_image = (ext_attr->pos_image) ? false : true; + ext_attr->pos_image = !ext_attr->pos_image; /* freeze dq/fq updating */ rc = drxj_dap_read_reg16(dev_addr, QAM_DQ_MODE__A, &data, 0); diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index affaa36d31..e0272054fc 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -1923,8 +1923,7 @@ static void m88ds3103_remove(struct i2c_client *client) dev_dbg(&client->dev, "\n"); - if (dev->dt_client) - i2c_unregister_device(dev->dt_client); + i2c_unregister_device(dev->dt_client); i2c_mux_del_adapters(dev->muxc); diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 53b443be5a..59ee0ca2c9 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -216,6 +216,16 @@ config VIDEO_MT9M111 This driver supports MT9M111, MT9M112 and MT9M131 cameras from Micron/Aptina +config VIDEO_MT9M114 + tristate "onsemi MT9M114 sensor support" + select V4L2_CCI_I2C + help + This is a Video4Linux2 sensor-level driver for the onsemi MT9M114 + camera. + + To compile this driver as a module, choose M here: the + module will be called mt9m114. + config VIDEO_MT9P031 tristate "Aptina MT9P031 support" select VIDEO_APTINA_PLL diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 80b00d39b4..f5010f80a2 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o +obj-$(CONFIG_VIDEO_MT9M114) += mt9m114.o obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o obj-$(CONFIG_VIDEO_MT9T112) += mt9t112.o obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index 98ca417b80..5ace7b5804 100644 --- a/drivers/media/i2c/adp1653.c +++ b/drivers/media/i2c/adp1653.c @@ -411,43 +411,44 @@ static int adp1653_of_init(struct i2c_client *client, struct device_node *node) { struct adp1653_platform_data *pd; - struct device_node *child; + struct device_node *node_indicator = NULL; + struct device_node *node_flash; pd = devm_kzalloc(&client->dev, sizeof(*pd), GFP_KERNEL); if (!pd) return -ENOMEM; flash->platform_data = pd; - child = of_get_child_by_name(node, "flash"); - if (!child) + node_flash = of_get_child_by_name(node, "flash"); + if (!node_flash) return -EINVAL; - if (of_property_read_u32(child, "flash-timeout-us", + if (of_property_read_u32(node_flash, "flash-timeout-us", &pd->max_flash_timeout)) goto err; - if (of_property_read_u32(child, "flash-max-microamp", + if (of_property_read_u32(node_flash, "flash-max-microamp", &pd->max_flash_intensity)) goto err; pd->max_flash_intensity /= 1000; - if (of_property_read_u32(child, "led-max-microamp", + if (of_property_read_u32(node_flash, "led-max-microamp", &pd->max_torch_intensity)) goto err; pd->max_torch_intensity /= 1000; - of_node_put(child); - child = of_get_child_by_name(node, "indicator"); - if (!child) - return -EINVAL; + node_indicator = of_get_child_by_name(node, "indicator"); + if (!node_indicator) + goto err; - if (of_property_read_u32(child, "led-max-microamp", + if (of_property_read_u32(node_indicator, "led-max-microamp", &pd->max_indicator_intensity)) goto err; - of_node_put(child); + of_node_put(node_flash); + of_node_put(node_indicator); pd->enable_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_LOW); if (IS_ERR(pd->enable_gpio)) { @@ -458,7 +459,8 @@ static int adp1653_of_init(struct i2c_client *client, return 0; err: dev_err(&client->dev, "Required property not found\n"); - of_node_put(child); + of_node_put(node_flash); + of_node_put(node_indicator); return -EINVAL; } diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 99ba925e8e..5413447318 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -5,6 +5,7 @@ * Copyright (C) 2013 Cogent Embedded, Inc. * Copyright (C) 2013 Renesas Solutions Corp. */ +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> @@ -1395,7 +1396,6 @@ out_unlock: static int adv7180_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct device_node *np = client->dev.of_node; struct adv7180_state *state; struct v4l2_subdev *sd; @@ -1411,7 +1411,7 @@ static int adv7180_probe(struct i2c_client *client) state->client = client; state->field = V4L2_FIELD_ALTERNATE; - state->chip_info = (struct adv7180_chip_info *)id->driver_data; + state->chip_info = i2c_get_match_data(client); state->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", GPIOD_OUT_HIGH); @@ -1536,22 +1536,6 @@ static void adv7180_remove(struct i2c_client *client) mutex_destroy(&state->mutex); } -static const struct i2c_device_id adv7180_id[] = { - { "adv7180", (kernel_ulong_t)&adv7180_info }, - { "adv7180cp", (kernel_ulong_t)&adv7180_info }, - { "adv7180st", (kernel_ulong_t)&adv7180_info }, - { "adv7182", (kernel_ulong_t)&adv7182_info }, - { "adv7280", (kernel_ulong_t)&adv7280_info }, - { "adv7280-m", (kernel_ulong_t)&adv7280_m_info }, - { "adv7281", (kernel_ulong_t)&adv7281_info }, - { "adv7281-m", (kernel_ulong_t)&adv7281_m_info }, - { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info }, - { "adv7282", (kernel_ulong_t)&adv7282_info }, - { "adv7282-m", (kernel_ulong_t)&adv7282_m_info }, - {}, -}; -MODULE_DEVICE_TABLE(i2c, adv7180_id); - #ifdef CONFIG_PM_SLEEP static int adv7180_suspend(struct device *dev) { @@ -1585,30 +1569,43 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume); #define ADV7180_PM_OPS NULL #endif -#ifdef CONFIG_OF -static const struct of_device_id adv7180_of_id[] = { - { .compatible = "adi,adv7180", }, - { .compatible = "adi,adv7180cp", }, - { .compatible = "adi,adv7180st", }, - { .compatible = "adi,adv7182", }, - { .compatible = "adi,adv7280", }, - { .compatible = "adi,adv7280-m", }, - { .compatible = "adi,adv7281", }, - { .compatible = "adi,adv7281-m", }, - { .compatible = "adi,adv7281-ma", }, - { .compatible = "adi,adv7282", }, - { .compatible = "adi,adv7282-m", }, - { }, +static const struct i2c_device_id adv7180_id[] = { + { "adv7180", (kernel_ulong_t)&adv7180_info }, + { "adv7180cp", (kernel_ulong_t)&adv7180_info }, + { "adv7180st", (kernel_ulong_t)&adv7180_info }, + { "adv7182", (kernel_ulong_t)&adv7182_info }, + { "adv7280", (kernel_ulong_t)&adv7280_info }, + { "adv7280-m", (kernel_ulong_t)&adv7280_m_info }, + { "adv7281", (kernel_ulong_t)&adv7281_info }, + { "adv7281-m", (kernel_ulong_t)&adv7281_m_info }, + { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info }, + { "adv7282", (kernel_ulong_t)&adv7282_info }, + { "adv7282-m", (kernel_ulong_t)&adv7282_m_info }, + {} }; +MODULE_DEVICE_TABLE(i2c, adv7180_id); +static const struct of_device_id adv7180_of_id[] = { + { .compatible = "adi,adv7180", &adv7180_info }, + { .compatible = "adi,adv7180cp", &adv7180_info }, + { .compatible = "adi,adv7180st", &adv7180_info }, + { .compatible = "adi,adv7182", &adv7182_info }, + { .compatible = "adi,adv7280", &adv7280_info }, + { .compatible = "adi,adv7280-m", &adv7280_m_info }, + { .compatible = "adi,adv7281", &adv7281_info }, + { .compatible = "adi,adv7281-m", &adv7281_m_info }, + { .compatible = "adi,adv7281-ma", &adv7281_ma_info }, + { .compatible = "adi,adv7282", &adv7282_info }, + { .compatible = "adi,adv7282-m", &adv7282_m_info }, + {} +}; MODULE_DEVICE_TABLE(of, adv7180_of_id); -#endif static struct i2c_driver adv7180_driver = { .driver = { .name = KBUILD_MODNAME, .pm = ADV7180_PM_OPS, - .of_match_table = of_match_ptr(adv7180_of_id), + .of_match_table = adv7180_of_id, }, .probe = adv7180_probe, .remove = adv7180_remove, diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c index a4e39871e8..701f36345f 100644 --- a/drivers/media/i2c/ar0521.c +++ b/drivers/media/i2c/ar0521.c @@ -133,8 +133,6 @@ struct ar0521_dev { u16 mult2; u16 vt_pix; } pll; - - bool streaming; }; static inline struct ar0521_dev *to_ar0521_dev(struct v4l2_subdev *sd) @@ -991,12 +989,9 @@ static int ar0521_s_stream(struct v4l2_subdev *sd, int enable) int ret; mutex_lock(&sensor->lock); - ret = ar0521_set_stream(sensor, enable); - if (!ret) - sensor->streaming = enable; - mutex_unlock(&sensor->lock); + return ret; } @@ -1023,28 +1018,6 @@ static const struct v4l2_subdev_ops ar0521_subdev_ops = { .pad = &ar0521_pad_ops, }; -static int __maybe_unused ar0521_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ar0521_dev *sensor = to_ar0521_dev(sd); - - if (sensor->streaming) - ar0521_set_stream(sensor, 0); - - return 0; -} - -static int __maybe_unused ar0521_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ar0521_dev *sensor = to_ar0521_dev(sd); - - if (sensor->streaming) - return ar0521_set_stream(sensor, 1); - - return 0; -} - static int ar0521_probe(struct i2c_client *client) { struct v4l2_fwnode_endpoint ep = { @@ -1183,7 +1156,6 @@ static void ar0521_remove(struct i2c_client *client) } static const struct dev_pm_ops ar0521_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ar0521_suspend, ar0521_resume) SET_RUNTIME_PM_OPS(ar0521_power_off, ar0521_power_on, NULL) }; static const struct of_device_id ar0521_dt_ids[] = { diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 6f8fbd82e2..12e6f0a26f 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -508,9 +508,8 @@ static void __ccs_update_exposure_limits(struct ccs_sensor *sensor) struct v4l2_ctrl *ctrl = sensor->exposure; int max; - max = sensor->pixel_array->crop[CCS_PA_PAD_SRC].height - + sensor->vblank->val - - CCS_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN); + max = sensor->pa_src.height + sensor->vblank->val - + CCS_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN); __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max); } @@ -728,15 +727,12 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_VBLANK: rval = ccs_write(sensor, FRAME_LENGTH_LINES, - sensor->pixel_array->crop[ - CCS_PA_PAD_SRC].height - + ctrl->val); + sensor->pa_src.height + ctrl->val); break; case V4L2_CID_HBLANK: rval = ccs_write(sensor, LINE_LENGTH_PCK, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width - + ctrl->val); + sensor->pa_src.width + ctrl->val); break; case V4L2_CID_TEST_PATTERN: @@ -1214,15 +1210,13 @@ static void ccs_update_blanking(struct ccs_sensor *sensor) min = max_t(int, CCS_LIM(sensor, MIN_FRAME_BLANKING_LINES), - min_fll - sensor->pixel_array->crop[CCS_PA_PAD_SRC].height); - max = max_fll - sensor->pixel_array->crop[CCS_PA_PAD_SRC].height; + min_fll - sensor->pa_src.height); + max = max_fll - sensor->pa_src.height; __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min); - min = max_t(int, - min_llp - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width, - min_lbp); - max = max_llp - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width; + min = max_t(int, min_llp - sensor->pa_src.width, min_lbp); + max = max_llp - sensor->pa_src.width; __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min); @@ -1246,10 +1240,8 @@ static int ccs_pll_blanking_update(struct ccs_sensor *sensor) dev_dbg(&client->dev, "real timeperframe\t100/%d\n", sensor->pll.pixel_rate_pixel_array / - ((sensor->pixel_array->crop[CCS_PA_PAD_SRC].width - + sensor->hblank->val) * - (sensor->pixel_array->crop[CCS_PA_PAD_SRC].height - + sensor->vblank->val) / 100)); + ((sensor->pa_src.width + sensor->hblank->val) * + (sensor->pa_src.height + sensor->vblank->val) / 100)); return 0; } @@ -1756,28 +1748,22 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) goto out; /* Analog crop start coordinates */ - rval = ccs_write(sensor, X_ADDR_START, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].left); + rval = ccs_write(sensor, X_ADDR_START, sensor->pa_src.left); if (rval < 0) goto out; - rval = ccs_write(sensor, Y_ADDR_START, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].top); + rval = ccs_write(sensor, Y_ADDR_START, sensor->pa_src.top); if (rval < 0) goto out; /* Analog crop end coordinates */ - rval = ccs_write( - sensor, X_ADDR_END, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].left - + sensor->pixel_array->crop[CCS_PA_PAD_SRC].width - 1); + rval = ccs_write(sensor, X_ADDR_END, + sensor->pa_src.left + sensor->pa_src.width - 1); if (rval < 0) goto out; - rval = ccs_write( - sensor, Y_ADDR_END, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].top - + sensor->pixel_array->crop[CCS_PA_PAD_SRC].height - 1); + rval = ccs_write(sensor, Y_ADDR_END, + sensor->pa_src.top + sensor->pa_src.height - 1); if (rval < 0) goto out; @@ -1789,27 +1775,23 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) /* Digital crop */ if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { - rval = ccs_write( - sensor, DIGITAL_CROP_X_OFFSET, - sensor->scaler->crop[CCS_PAD_SINK].left); + rval = ccs_write(sensor, DIGITAL_CROP_X_OFFSET, + sensor->scaler_sink.left); if (rval < 0) goto out; - rval = ccs_write( - sensor, DIGITAL_CROP_Y_OFFSET, - sensor->scaler->crop[CCS_PAD_SINK].top); + rval = ccs_write(sensor, DIGITAL_CROP_Y_OFFSET, + sensor->scaler_sink.top); if (rval < 0) goto out; - rval = ccs_write( - sensor, DIGITAL_CROP_IMAGE_WIDTH, - sensor->scaler->crop[CCS_PAD_SINK].width); + rval = ccs_write(sensor, DIGITAL_CROP_IMAGE_WIDTH, + sensor->scaler_sink.width); if (rval < 0) goto out; - rval = ccs_write( - sensor, DIGITAL_CROP_IMAGE_HEIGHT, - sensor->scaler->crop[CCS_PAD_SINK].height); + rval = ccs_write(sensor, DIGITAL_CROP_IMAGE_HEIGHT, + sensor->scaler_sink.height); if (rval < 0) goto out; } @@ -1827,12 +1809,10 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) } /* Output size from sensor */ - rval = ccs_write(sensor, X_OUTPUT_SIZE, - sensor->src->crop[CCS_PAD_SRC].width); + rval = ccs_write(sensor, X_OUTPUT_SIZE, sensor->src_src.width); if (rval < 0) goto out; - rval = ccs_write(sensor, Y_OUTPUT_SIZE, - sensor->src->crop[CCS_PAD_SRC].height); + rval = ccs_write(sensor, Y_OUTPUT_SIZE, sensor->src_src.height); if (rval < 0) goto out; @@ -1923,9 +1903,6 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); int rval; - if (sensor->streaming == enable) - return 0; - if (!enable) { ccs_stop_streaming(sensor); sensor->streaming = false; @@ -2053,24 +2030,8 @@ static int __ccs_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(subdev, sd_state, - fmt->pad); - } else { - struct v4l2_rect *r; - - if (fmt->pad == ssd->source_pad) - r = &ssd->crop[ssd->source_pad]; - else - r = &ssd->sink_fmt; - - fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); - fmt->format.width = r->width; - fmt->format.height = r->height; - fmt->format.field = V4L2_FIELD_NONE; - } + fmt->format = *v4l2_subdev_get_pad_format(subdev, sd_state, fmt->pad); + fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); return 0; } @@ -2092,28 +2053,18 @@ static int ccs_get_format(struct v4l2_subdev *subdev, static void ccs_get_crop_compose(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_rect **crops, - struct v4l2_rect **comps, int which) + struct v4l2_rect **comps) { struct ccs_subdev *ssd = to_ccs_subdev(subdev); unsigned int i; - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { - if (crops) - for (i = 0; i < subdev->entity.num_pads; i++) - crops[i] = &ssd->crop[i]; - if (comps) - *comps = &ssd->compose; - } else { - if (crops) { - for (i = 0; i < subdev->entity.num_pads; i++) - crops[i] = v4l2_subdev_get_try_crop(subdev, - sd_state, - i); - } - if (comps) - *comps = v4l2_subdev_get_try_compose(subdev, sd_state, - CCS_PAD_SINK); - } + if (crops) + for (i = 0; i < subdev->entity.num_pads; i++) + crops[i] = + v4l2_subdev_get_pad_crop(subdev, sd_state, i); + if (comps) + *comps = v4l2_subdev_get_pad_compose(subdev, sd_state, + ssd->sink_pad); } /* Changes require propagation only on sink pad. */ @@ -2124,8 +2075,9 @@ static void ccs_propagate(struct v4l2_subdev *subdev, struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); struct v4l2_rect *comp, *crops[CCS_PADS]; + struct v4l2_mbus_framefmt *fmt; - ccs_get_crop_compose(subdev, sd_state, crops, &comp, which); + ccs_get_crop_compose(subdev, sd_state, crops, &comp); switch (target) { case V4L2_SEL_TGT_CROP: @@ -2136,6 +2088,7 @@ static void ccs_propagate(struct v4l2_subdev *subdev, sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); sensor->scaling_mode = CCS_SCALING_MODE_NO_SCALING; + sensor->scaler_sink = *comp; } else if (ssd == sensor->binner) { sensor->binning_horizontal = 1; sensor->binning_vertical = 1; @@ -2144,6 +2097,11 @@ static void ccs_propagate(struct v4l2_subdev *subdev, fallthrough; case V4L2_SEL_TGT_COMPOSE: *crops[CCS_PAD_SRC] = *comp; + fmt = v4l2_subdev_get_pad_format(subdev, sd_state, CCS_PAD_SRC); + fmt->width = comp->width; + fmt->height = comp->height; + if (which == V4L2_SUBDEV_FORMAT_ACTIVE && ssd == sensor->src) + sensor->src_src = *crops[CCS_PAD_SRC]; break; default: WARN_ON_ONCE(1); @@ -2252,14 +2210,12 @@ static int ccs_set_format(struct v4l2_subdev *subdev, CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), CCS_LIM(sensor, MAX_Y_OUTPUT_SIZE)); - ccs_get_crop_compose(subdev, sd_state, crops, NULL, fmt->which); + ccs_get_crop_compose(subdev, sd_state, crops, NULL); crops[ssd->sink_pad]->left = 0; crops[ssd->sink_pad]->top = 0; crops[ssd->sink_pad]->width = fmt->format.width; crops[ssd->sink_pad]->height = fmt->format.height; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - ssd->sink_fmt = *crops[ssd->sink_pad]; ccs_propagate(subdev, sd_state, fmt->which, V4L2_SEL_TGT_CROP); mutex_unlock(&sensor->mutex); @@ -2482,7 +2438,7 @@ static int ccs_set_compose(struct v4l2_subdev *subdev, struct ccs_subdev *ssd = to_ccs_subdev(subdev); struct v4l2_rect *comp, *crops[CCS_PADS]; - ccs_get_crop_compose(subdev, sd_state, crops, &comp, sel->which); + ccs_get_crop_compose(subdev, sd_state, crops, &comp); sel->r.top = 0; sel->r.left = 0; @@ -2501,8 +2457,8 @@ static int ccs_set_compose(struct v4l2_subdev *subdev, return 0; } -static int __ccs_sel_supported(struct v4l2_subdev *subdev, - struct v4l2_subdev_selection *sel) +static int ccs_sel_supported(struct v4l2_subdev *subdev, + struct v4l2_subdev_selection *sel) { struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); @@ -2545,33 +2501,18 @@ static int ccs_set_crop(struct v4l2_subdev *subdev, { struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct v4l2_rect *src_size, *crops[CCS_PADS]; - struct v4l2_rect _r; + struct v4l2_rect src_size = { 0 }, *crops[CCS_PADS], *comp; - ccs_get_crop_compose(subdev, sd_state, crops, NULL, sel->which); + ccs_get_crop_compose(subdev, sd_state, crops, &comp); - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - if (sel->pad == ssd->sink_pad) - src_size = &ssd->sink_fmt; - else - src_size = &ssd->compose; + if (sel->pad == ssd->sink_pad) { + struct v4l2_mbus_framefmt *mfmt = + v4l2_subdev_get_pad_format(subdev, sd_state, sel->pad); + + src_size.width = mfmt->width; + src_size.height = mfmt->height; } else { - if (sel->pad == ssd->sink_pad) { - _r.left = 0; - _r.top = 0; - _r.width = v4l2_subdev_get_try_format(subdev, - sd_state, - sel->pad) - ->width; - _r.height = v4l2_subdev_get_try_format(subdev, - sd_state, - sel->pad) - ->height; - src_size = &_r; - } else { - src_size = v4l2_subdev_get_try_compose( - subdev, sd_state, ssd->sink_pad); - } + src_size = *comp; } if (ssd == sensor->src && sel->pad == CCS_PAD_SRC) { @@ -2579,16 +2520,19 @@ static int ccs_set_crop(struct v4l2_subdev *subdev, sel->r.top = 0; } - sel->r.width = min(sel->r.width, src_size->width); - sel->r.height = min(sel->r.height, src_size->height); + sel->r.width = min(sel->r.width, src_size.width); + sel->r.height = min(sel->r.height, src_size.height); - sel->r.left = min_t(int, sel->r.left, src_size->width - sel->r.width); - sel->r.top = min_t(int, sel->r.top, src_size->height - sel->r.height); + sel->r.left = min_t(int, sel->r.left, src_size.width - sel->r.width); + sel->r.top = min_t(int, sel->r.top, src_size.height - sel->r.height); *crops[sel->pad] = sel->r; if (ssd != sensor->pixel_array && sel->pad == CCS_PAD_SINK) ccs_propagate(subdev, sd_state, sel->which, V4L2_SEL_TGT_CROP); + else if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && + ssd == sensor->pixel_array) + sensor->pa_src = sel->r; return 0; } @@ -2601,44 +2545,36 @@ static void ccs_get_native_size(struct ccs_subdev *ssd, struct v4l2_rect *r) r->height = CCS_LIM(ssd->sensor, Y_ADDR_MAX) + 1; } -static int __ccs_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_selection *sel) +static int ccs_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) { struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct ccs_subdev *ssd = to_ccs_subdev(subdev); struct v4l2_rect *comp, *crops[CCS_PADS]; - struct v4l2_rect sink_fmt; int ret; - ret = __ccs_sel_supported(subdev, sel); + ret = ccs_sel_supported(subdev, sel); if (ret) return ret; - ccs_get_crop_compose(subdev, sd_state, crops, &comp, sel->which); - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sink_fmt = ssd->sink_fmt; - } else { - struct v4l2_mbus_framefmt *fmt = - v4l2_subdev_get_try_format(subdev, sd_state, - ssd->sink_pad); - - sink_fmt.left = 0; - sink_fmt.top = 0; - sink_fmt.width = fmt->width; - sink_fmt.height = fmt->height; - } + ccs_get_crop_compose(subdev, sd_state, crops, &comp); switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_NATIVE_SIZE: - if (ssd == sensor->pixel_array) + if (ssd == sensor->pixel_array) { ccs_get_native_size(ssd, &sel->r); - else if (sel->pad == ssd->sink_pad) - sel->r = sink_fmt; - else + } else if (sel->pad == ssd->sink_pad) { + struct v4l2_mbus_framefmt *sink_fmt = + v4l2_subdev_get_pad_format(subdev, sd_state, + ssd->sink_pad); + sel->r.top = sel->r.left = 0; + sel->r.width = sink_fmt->width; + sel->r.height = sink_fmt->height; + } else { sel->r = *comp; + } break; case V4L2_SEL_TGT_CROP: case V4L2_SEL_TGT_COMPOSE_BOUNDS: @@ -2652,20 +2588,6 @@ static int __ccs_get_selection(struct v4l2_subdev *subdev, return 0; } -static int ccs_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_selection *sel) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - int rval; - - mutex_lock(&sensor->mutex); - rval = __ccs_get_selection(subdev, sd_state, sel); - mutex_unlock(&sensor->mutex); - - return rval; -} - static int ccs_set_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) @@ -2673,7 +2595,7 @@ static int ccs_set_selection(struct v4l2_subdev *subdev, struct ccs_sensor *sensor = to_ccs_sensor(subdev); int ret; - ret = __ccs_sel_supported(subdev, sel); + ret = ccs_sel_supported(subdev, sel); if (ret) return ret; @@ -2945,7 +2867,6 @@ static int ccs_identify_module(struct ccs_sensor *sensor) } static const struct v4l2_subdev_ops ccs_ops; -static const struct v4l2_subdev_internal_ops ccs_internal_ops; static const struct media_entity_operations ccs_entity_ops; static int ccs_register_subdev(struct ccs_sensor *sensor, @@ -2959,12 +2880,6 @@ static int ccs_register_subdev(struct ccs_sensor *sensor, if (!sink_ssd) return 0; - rval = media_entity_pads_init(&ssd->sd.entity, ssd->npads, ssd->pads); - if (rval) { - dev_err(&client->dev, "media_entity_pads_init failed\n"); - return rval; - } - rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, &ssd->sd); if (rval) { dev_err(&client->dev, "v4l2_device_register_subdev failed\n"); @@ -3025,6 +2940,12 @@ out_err: static void ccs_cleanup(struct ccs_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + unsigned int i; + + for (i = 0; i < sensor->ssds_used; i++) { + v4l2_subdev_cleanup(&sensor->ssds[2].sd); + media_entity_cleanup(&sensor->ssds[i].sd.entity); + } device_remove_file(&client->dev, &dev_attr_nvm); device_remove_file(&client->dev, &dev_attr_ident); @@ -3032,14 +2953,17 @@ static void ccs_cleanup(struct ccs_sensor *sensor) ccs_free_controls(sensor); } -static void ccs_create_subdev(struct ccs_sensor *sensor, - struct ccs_subdev *ssd, const char *name, - unsigned short num_pads, u32 function) +static int ccs_init_subdev(struct ccs_sensor *sensor, + struct ccs_subdev *ssd, const char *name, + unsigned short num_pads, u32 function, + const char *lock_name, + struct lock_class_key *lock_key) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; if (!ssd) - return; + return 0; if (ssd != sensor->src) v4l2_subdev_init(&ssd->sd, &ccs_ops); @@ -3053,57 +2977,70 @@ static void ccs_create_subdev(struct ccs_sensor *sensor, v4l2_i2c_subdev_set_name(&ssd->sd, client, sensor->minfo.name, name); - ccs_get_native_size(ssd, &ssd->sink_fmt); - - ssd->compose.width = ssd->sink_fmt.width; - ssd->compose.height = ssd->sink_fmt.height; - ssd->crop[ssd->source_pad] = ssd->compose; ssd->pads[ssd->source_pad].flags = MEDIA_PAD_FL_SOURCE; - if (ssd != sensor->pixel_array) { - ssd->crop[ssd->sink_pad] = ssd->compose; + if (ssd != sensor->pixel_array) ssd->pads[ssd->sink_pad].flags = MEDIA_PAD_FL_SINK; - } ssd->sd.entity.ops = &ccs_entity_ops; - if (ssd == sensor->src) - return; + if (ssd != sensor->src) { + ssd->sd.owner = THIS_MODULE; + ssd->sd.dev = &client->dev; + v4l2_set_subdevdata(&ssd->sd, client); + } + + rval = media_entity_pads_init(&ssd->sd.entity, ssd->npads, ssd->pads); + if (rval) { + dev_err(&client->dev, "media_entity_pads_init failed\n"); + return rval; + } - ssd->sd.internal_ops = &ccs_internal_ops; - ssd->sd.owner = THIS_MODULE; - ssd->sd.dev = &client->dev; - v4l2_set_subdevdata(&ssd->sd, client); + rval = __v4l2_subdev_init_finalize(&ssd->sd, lock_name, lock_key); + if (rval) { + media_entity_cleanup(&ssd->sd.entity); + return rval; + } + + return 0; } -static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +static int ccs_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { struct ccs_subdev *ssd = to_ccs_subdev(sd); struct ccs_sensor *sensor = ssd->sensor; - unsigned int i; + unsigned int pad = ssd == sensor->pixel_array ? + CCS_PA_PAD_SRC : CCS_PAD_SINK; + struct v4l2_mbus_framefmt *fmt = + v4l2_subdev_get_pad_format(sd, sd_state, pad); + struct v4l2_rect *crop = + v4l2_subdev_get_pad_crop(sd, sd_state, pad); + bool is_active = !sd->active_state || sd->active_state == sd_state; mutex_lock(&sensor->mutex); - for (i = 0; i < ssd->npads; i++) { - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->state, i); - struct v4l2_rect *try_crop = - v4l2_subdev_get_try_crop(sd, fh->state, i); - struct v4l2_rect *try_comp; + ccs_get_native_size(ssd, crop); - ccs_get_native_size(ssd, try_crop); + fmt->width = crop->width; + fmt->height = crop->height; + fmt->code = sensor->internal_csi_format->code; + fmt->field = V4L2_FIELD_NONE; - try_fmt->width = try_crop->width; - try_fmt->height = try_crop->height; - try_fmt->code = sensor->internal_csi_format->code; - try_fmt->field = V4L2_FIELD_NONE; + if (ssd == sensor->pixel_array) { + if (is_active) + sensor->pa_src = *crop; - if (ssd == sensor->pixel_array) - continue; - - try_comp = v4l2_subdev_get_try_compose(sd, fh->state, i); - *try_comp = *try_crop; + mutex_unlock(&sensor->mutex); + return 0; } + fmt = v4l2_subdev_get_pad_format(sd, sd_state, CCS_PAD_SRC); + fmt->code = ssd == sensor->src ? + sensor->csi_format->code : sensor->internal_csi_format->code; + fmt->field = V4L2_FIELD_NONE; + + ccs_propagate(sd, sd_state, is_active, V4L2_SEL_TGT_CROP); + mutex_unlock(&sensor->mutex); return 0; @@ -3116,6 +3053,7 @@ static const struct v4l2_subdev_video_ops ccs_video_ops = { }; static const struct v4l2_subdev_pad_ops ccs_pad_ops = { + .init_cfg = ccs_init_cfg, .enum_mbus_code = ccs_enum_mbus_code, .get_fmt = ccs_get_format, .set_fmt = ccs_set_format, @@ -3141,53 +3079,12 @@ static const struct media_entity_operations ccs_entity_ops = { static const struct v4l2_subdev_internal_ops ccs_internal_src_ops = { .registered = ccs_registered, .unregistered = ccs_unregistered, - .open = ccs_open, -}; - -static const struct v4l2_subdev_internal_ops ccs_internal_ops = { - .open = ccs_open, }; /* ----------------------------------------------------------------------------- * I2C Driver */ -static int __maybe_unused ccs_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - bool streaming = sensor->streaming; - int rval; - - rval = pm_runtime_resume_and_get(dev); - if (rval < 0) - return rval; - - if (sensor->streaming) - ccs_stop_streaming(sensor); - - /* save state for resume */ - sensor->streaming = streaming; - - return 0; -} - -static int __maybe_unused ccs_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - int rval = 0; - - pm_runtime_put(dev); - - if (sensor->streaming) - rval = ccs_start_streaming(sensor); - - return rval; -} - static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) { struct ccs_hwconfig *hwcfg = &sensor->hwcfg; @@ -3311,6 +3208,8 @@ static int ccs_firmware_name(struct i2c_client *client, static int ccs_probe(struct i2c_client *client) { + static struct lock_class_key pixel_array_lock_key, binner_lock_key, + scaler_lock_key; const struct ccs_device *ccsdev = device_get_match_data(&client->dev); struct ccs_sensor *sensor; const struct firmware *fw; @@ -3587,12 +3486,27 @@ static int ccs_probe(struct i2c_client *client) sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); - ccs_create_subdev(sensor, sensor->scaler, " scaler", 2, - MEDIA_ENT_F_PROC_VIDEO_SCALER); - ccs_create_subdev(sensor, sensor->binner, " binner", 2, - MEDIA_ENT_F_PROC_VIDEO_SCALER); - ccs_create_subdev(sensor, sensor->pixel_array, " pixel_array", 1, - MEDIA_ENT_F_CAM_SENSOR); + rval = ccs_get_mbus_formats(sensor); + if (rval) { + rval = -ENODEV; + goto out_cleanup; + } + + rval = ccs_init_subdev(sensor, sensor->scaler, " scaler", 2, + MEDIA_ENT_F_PROC_VIDEO_SCALER, + "ccs scaler mutex", &scaler_lock_key); + if (rval) + goto out_cleanup; + rval = ccs_init_subdev(sensor, sensor->binner, " binner", 2, + MEDIA_ENT_F_PROC_VIDEO_SCALER, + "ccs binner mutex", &binner_lock_key); + if (rval) + goto out_cleanup; + rval = ccs_init_subdev(sensor, sensor->pixel_array, " pixel_array", 1, + MEDIA_ENT_F_CAM_SENSOR, "ccs pixel array mutex", + &pixel_array_lock_key); + if (rval) + goto out_cleanup; rval = ccs_init_controls(sensor); if (rval < 0) @@ -3602,12 +3516,6 @@ static int ccs_probe(struct i2c_client *client) if (rval) goto out_cleanup; - rval = ccs_get_mbus_formats(sensor); - if (rval) { - rval = -ENODEV; - goto out_cleanup; - } - rval = ccs_init_late_controls(sensor); if (rval) { rval = -ENODEV; @@ -3625,14 +3533,9 @@ static int ccs_probe(struct i2c_client *client) sensor->streaming = false; sensor->dev_init_done = true; - rval = media_entity_pads_init(&sensor->src->sd.entity, 2, - sensor->src->pads); - if (rval < 0) - goto out_media_entity_cleanup; - rval = ccs_write_msr_regs(sensor); if (rval) - goto out_media_entity_cleanup; + goto out_cleanup; pm_runtime_set_active(&client->dev); pm_runtime_get_noresume(&client->dev); @@ -3652,9 +3555,6 @@ out_disable_runtime_pm: pm_runtime_put_noidle(&client->dev); pm_runtime_disable(&client->dev); -out_media_entity_cleanup: - media_entity_cleanup(&sensor->src->sd.entity); - out_cleanup: ccs_cleanup(sensor); @@ -3687,10 +3587,8 @@ static void ccs_remove(struct i2c_client *client) ccs_power_off(&client->dev); pm_runtime_set_suspended(&client->dev); - for (i = 0; i < sensor->ssds_used; i++) { + for (i = 0; i < sensor->ssds_used; i++) v4l2_device_unregister_subdev(&sensor->ssds[i].sd); - media_entity_cleanup(&sensor->ssds[i].sd.entity); - } ccs_cleanup(sensor); mutex_destroy(&sensor->mutex); kfree(sensor->ccs_limits); @@ -3720,7 +3618,6 @@ static const struct of_device_id ccs_of_table[] = { MODULE_DEVICE_TABLE(of, ccs_of_table); static const struct dev_pm_ops ccs_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ccs_suspend, ccs_resume) SET_RUNTIME_PM_OPS(ccs_power_off, ccs_power_on, NULL) }; diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index a94c796cea..9c3587b2fb 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -182,9 +182,6 @@ struct ccs_binning_subtype { struct ccs_subdev { struct v4l2_subdev sd; struct media_pad pads[CCS_PADS]; - struct v4l2_rect sink_fmt; - struct v4l2_rect crop[CCS_PADS]; - struct v4l2_rect compose; /* compose on sink */ unsigned short sink_pad; unsigned short source_pad; int npads; @@ -220,6 +217,7 @@ struct ccs_sensor { u32 mbus_frame_fmts; const struct ccs_csi_data_format *csi_format; const struct ccs_csi_data_format *internal_csi_format; + struct v4l2_rect pa_src, scaler_sink, src_src; u32 default_mbus_frame_fmts; int default_pixel_order; struct ccs_data_container sdata, mdata; diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 5aec252890..04461c893d 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -2738,10 +2738,801 @@ static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status, #define DIF_BPF_COEFF3435 (0x38c) #define DIF_BPF_COEFF36 (0x390) +static const u32 ifhz_coeffs[][19] = { + { // 3.0 MHz + 0x00000002, 0x00080012, 0x001e0024, 0x001bfff8, + 0xffb4ff50, 0xfed8fe68, 0xfe24fe34, 0xfebaffc7, + 0x014d031f, 0x04f0065d, 0x07010688, 0x04c901d6, + 0xfe00f9d3, 0xf600f342, 0xf235f337, 0xf64efb22, + 0x0105070f, 0x0c460fce, 0x110d0000, + }, { // 3.1 MHz + 0x00000001, 0x00070012, 0x00220032, 0x00370026, + 0xfff0ff91, 0xff0efe7c, 0xfe01fdcc, 0xfe0afedb, + 0x00440224, 0x0434060c, 0x0738074e, 0x06090361, + 0xff99fb39, 0xf6fef3b6, 0xf21af2a5, 0xf573fa33, + 0x0034067d, 0x0bfb0fb9, 0x110d0000, + }, { // 3.2 MHz + 0x00000000, 0x0004000e, 0x00200038, 0x004c004f, + 0x002fffdf, 0xff5cfeb6, 0xfe0dfd92, 0xfd7ffe03, + 0xff36010a, 0x03410575, 0x072607d2, 0x071804d5, + 0x0134fcb7, 0xf81ff451, 0xf223f22e, 0xf4a7f94b, + 0xff6405e8, 0x0bae0fa4, 0x110d0000, + }, { // 3.3 MHz + 0x0000ffff, 0x00000008, 0x001a0036, 0x0056006d, + 0x00670030, 0xffbdff10, 0xfe46fd8d, 0xfd25fd4f, + 0xfe35ffe0, 0x0224049f, 0x06c9080e, 0x07ef0627, + 0x02c9fe45, 0xf961f513, 0xf250f1d2, 0xf3ecf869, + 0xfe930552, 0x0b5f0f8f, 0x110d0000, + }, { // 3.4 MHz + 0xfffffffe, 0xfffd0001, 0x000f002c, 0x0054007d, + 0x0093007c, 0x0024ff82, 0xfea6fdbb, 0xfd03fcca, + 0xfd51feb9, 0x00eb0392, 0x06270802, 0x08880750, + 0x044dffdb, 0xfabdf5f8, 0xf2a0f193, 0xf342f78f, + 0xfdc404b9, 0x0b0e0f78, 0x110d0000, + }, { // 3.5 MHz + 0xfffffffd, 0xfffafff9, 0x0002001b, 0x0046007d, + 0x00ad00ba, 0x00870000, 0xff26fe1a, 0xfd1bfc7e, + 0xfc99fda4, 0xffa5025c, 0x054507ad, 0x08dd0847, + 0x05b80172, 0xfc2ef6ff, 0xf313f170, 0xf2abf6bd, + 0xfcf6041f, 0x0abc0f61, 0x110d0000, + }, { // 3.6 MHz + 0xfffffffd, 0xfff8fff3, 0xfff50006, 0x002f006c, + 0x00b200e3, 0x00dc007e, 0xffb9fea0, 0xfd6bfc71, + 0xfc17fcb1, 0xfe65010b, 0x042d0713, 0x08ec0906, + 0x07020302, 0xfdaff823, 0xf3a7f16a, 0xf228f5f5, + 0xfc2a0384, 0x0a670f4a, 0x110d0000, + }, { // 3.7 MHz + 0x0000fffd, 0xfff7ffef, 0xffe9fff1, 0x0010004d, + 0x00a100f2, 0x011a00f0, 0x0053ff44, 0xfdedfca2, + 0xfbd3fbef, 0xfd39ffae, 0x02ea0638, 0x08b50987, + 0x08230483, 0xff39f960, 0xf45bf180, 0xf1b8f537, + 0xfb6102e7, 0x0a110f32, 0x110d0000, + }, { // 3.8 MHz + 0x0000fffe, 0xfff9ffee, 0xffe1ffdd, 0xfff00024, + 0x007c00e5, 0x013a014a, 0x00e6fff8, 0xfe98fd0f, + 0xfbd3fb67, 0xfc32fe54, 0x01880525, 0x083909c7, + 0x091505ee, 0x00c7fab3, 0xf52df1b4, 0xf15df484, + 0xfa9b0249, 0x09ba0f19, 0x110d0000, + }, { // 3.9 MHz + 0x00000000, 0xfffbfff0, 0xffdeffcf, 0xffd1fff6, + 0x004800be, 0x01390184, 0x016300ac, 0xff5efdb1, + 0xfc17fb23, 0xfb5cfd0d, 0x001703e4, 0x077b09c4, + 0x09d2073c, 0x0251fc18, 0xf61cf203, 0xf118f3dc, + 0xf9d801aa, 0x09600eff, 0x110d0000, + }, { // 4.0 MHz + 0x00000001, 0xfffefff4, 0xffe1ffc8, 0xffbaffca, + 0x000b0082, 0x01170198, 0x01c10152, 0x0030fe7b, + 0xfc99fb24, 0xfac3fbe9, 0xfea5027f, 0x0683097f, + 0x0a560867, 0x03d2fd89, 0xf723f26f, 0xf0e8f341, + 0xf919010a, 0x09060ee5, 0x110d0000, + }, { // 4.1 MHz + 0x00010002, 0x0002fffb, 0xffe8ffca, 0xffacffa4, + 0xffcd0036, 0x00d70184, 0x01f601dc, 0x00ffff60, + 0xfd51fb6d, 0xfa6efaf5, 0xfd410103, 0x055708f9, + 0x0a9e0969, 0x0543ff02, 0xf842f2f5, 0xf0cef2b2, + 0xf85e006b, 0x08aa0ecb, 0x110d0000, + }, { // 4.2 MHz + 0x00010003, 0x00050003, 0xfff3ffd3, 0xffaaff8b, + 0xff95ffe5, 0x0080014a, 0x01fe023f, 0x01ba0050, + 0xfe35fbf8, 0xfa62fa3b, 0xfbf9ff7e, 0x04010836, + 0x0aa90a3d, 0x069f007f, 0xf975f395, 0xf0cbf231, + 0xf7a9ffcb, 0x084c0eaf, 0x110d0000, + }, { // 4.3 MHz + 0x00010003, 0x0008000a, 0x0000ffe4, 0xffb4ff81, + 0xff6aff96, 0x001c00f0, 0x01d70271, 0x0254013b, + 0xff36fcbd, 0xfa9ff9c5, 0xfadbfdfe, 0x028c073b, + 0x0a750adf, 0x07e101fa, 0xfab8f44e, 0xf0ddf1be, + 0xf6f9ff2b, 0x07ed0e94, 0x110d0000, + }, { // 4.4 MHz + 0x00000003, 0x0009000f, 0x000efff8, 0xffc9ff87, + 0xff52ff54, 0xffb5007e, 0x01860270, 0x02c00210, + 0x0044fdb2, 0xfb22f997, 0xf9f2fc90, 0x0102060f, + 0x0a050b4c, 0x0902036e, 0xfc0af51e, 0xf106f15a, + 0xf64efe8b, 0x078d0e77, 0x110d0000, + }, { // 4.5 MHz + 0x00000002, 0x00080012, 0x0019000e, 0xffe5ff9e, + 0xff4fff25, 0xff560000, 0x0112023b, 0x02f702c0, + 0x014dfec8, 0xfbe5f9b3, 0xf947fb41, 0xff7004b9, + 0x095a0b81, 0x0a0004d8, 0xfd65f603, 0xf144f104, + 0xf5aafdec, 0x072b0e5a, 0x110d0000, + }, { // 4.6 MHz + 0x00000001, 0x00060012, 0x00200022, 0x0005ffc1, + 0xff61ff10, 0xff09ff82, 0x008601d7, 0x02f50340, + 0x0241fff0, 0xfcddfa19, 0xf8e2fa1e, 0xfde30343, + 0x08790b7f, 0x0ad50631, 0xfec7f6fc, 0xf198f0bd, + 0xf50dfd4e, 0x06c90e3d, 0x110d0000, + }, { // 4.7 MHz + 0x0000ffff, 0x0003000f, 0x00220030, 0x0025ffed, + 0xff87ff15, 0xfed6ff10, 0xffed014c, 0x02b90386, + 0x03110119, 0xfdfefac4, 0xf8c6f92f, 0xfc6701b7, + 0x07670b44, 0x0b7e0776, 0x002df807, 0xf200f086, + 0xf477fcb1, 0x06650e1e, 0x110d0000, + }, { // 4.8 MHz + 0xfffffffe, 0xffff0009, 0x001e0038, 0x003f001b, + 0xffbcff36, 0xfec2feb6, 0xff5600a5, 0x0248038d, + 0x03b00232, 0xff39fbab, 0xf8f4f87f, 0xfb060020, + 0x062a0ad2, 0x0bf908a3, 0x0192f922, 0xf27df05e, + 0xf3e8fc14, 0x06000e00, 0x110d0000, + }, { // 4.9 MHz + 0xfffffffd, 0xfffc0002, 0x00160037, 0x00510046, + 0xfff9ff6d, 0xfed0fe7c, 0xfecefff0, 0x01aa0356, + 0x0413032b, 0x007ffcc5, 0xf96cf812, 0xf9cefe87, + 0x04c90a2c, 0x0c4309b4, 0x02f3fa4a, 0xf30ef046, + 0xf361fb7a, 0x059b0de0, 0x110d0000, + }, { // 5.0 MHz + 0xfffffffd, 0xfff9fffa, 0x000a002d, 0x00570067, + 0x0037ffb5, 0xfefffe68, 0xfe62ff3d, 0x00ec02e3, + 0x043503f6, 0x01befe05, 0xfa27f7ee, 0xf8c6fcf8, + 0x034c0954, 0x0c5c0aa4, 0x044cfb7e, 0xf3b1f03f, + 0xf2e2fae1, 0x05340dc0, 0x110d0000, + }, { // 5.1 MHz + 0x0000fffd, 0xfff8fff4, 0xfffd001e, 0x0051007b, + 0x006e0006, 0xff48fe7c, 0xfe1bfe9a, 0x001d023e, + 0x04130488, 0x02e6ff5b, 0xfb1ef812, 0xf7f7fb7f, + 0x01bc084e, 0x0c430b72, 0x059afcba, 0xf467f046, + 0xf26cfa4a, 0x04cd0da0, 0x110d0000, + }, { // 5.2 MHz + 0x0000fffe, 0xfff8ffef, 0xfff00009, 0x003f007f, + 0x00980056, 0xffa5feb6, 0xfe00fe15, 0xff4b0170, + 0x03b004d7, 0x03e800b9, 0xfc48f87f, 0xf768fa23, + 0x0022071f, 0x0bf90c1b, 0x06dafdfd, 0xf52df05e, + 0xf1fef9b5, 0x04640d7f, 0x110d0000, + }, { // 5.3 MHz + 0x0000ffff, 0xfff9ffee, 0xffe6fff3, 0x00250072, + 0x00af009c, 0x000cff10, 0xfe13fdb8, 0xfe870089, + 0x031104e1, 0x04b8020f, 0xfd98f92f, 0xf71df8f0, + 0xfe8805ce, 0x0b7e0c9c, 0x0808ff44, 0xf603f086, + 0xf19af922, 0x03fb0d5e, 0x110d0000, + }, { // 5.4 MHz + 0x00000001, 0xfffcffef, 0xffe0ffe0, 0x00050056, + 0x00b000d1, 0x0071ff82, 0xfe53fd8c, 0xfddfff99, + 0x024104a3, 0x054a034d, 0xff01fa1e, 0xf717f7ed, + 0xfcf50461, 0x0ad50cf4, 0x0921008d, 0xf6e7f0bd, + 0xf13ff891, 0x03920d3b, 0x110d0000, + }, { // 5.5 MHz + 0x00010002, 0xfffffff3, 0xffdeffd1, 0xffe5002f, + 0x009c00ed, 0x00cb0000, 0xfebafd94, 0xfd61feb0, + 0x014d0422, 0x05970464, 0x0074fb41, 0xf759f721, + 0xfb7502de, 0x0a000d21, 0x0a2201d4, 0xf7d9f104, + 0xf0edf804, 0x03280d19, 0x110d0000, + }, { // 5.6 MHz + 0x00010003, 0x0003fffa, 0xffe3ffc9, 0xffc90002, + 0x007500ef, 0x010e007e, 0xff3dfdcf, 0xfd16fddd, + 0x00440365, 0x059b0548, 0x01e3fc90, 0xf7dff691, + 0xfa0f014d, 0x09020d23, 0x0b0a0318, 0xf8d7f15a, + 0xf0a5f779, 0x02bd0cf6, 0x110d0000, + }, { // 5.7 MHz + 0x00010003, 0x00060001, 0xffecffc9, 0xffb4ffd4, + 0x004000d5, 0x013600f0, 0xffd3fe39, 0xfd04fd31, + 0xff360277, 0x055605ef, 0x033efdfe, 0xf8a5f642, + 0xf8cbffb6, 0x07e10cfb, 0x0bd50456, 0xf9dff1be, + 0xf067f6f2, 0x02520cd2, 0x110d0000, + }, { // 5.8 MHz + 0x00000003, 0x00080009, 0xfff8ffd2, 0xffaaffac, + 0x000200a3, 0x013c014a, 0x006dfec9, 0xfd2bfcb7, + 0xfe350165, 0x04cb0651, 0x0477ff7e, 0xf9a5f635, + 0xf7b1fe20, 0x069f0ca8, 0x0c81058b, 0xfaf0f231, + 0xf033f66d, 0x01e60cae, 0x110d0000, + }, { // 5.9 MHz + 0x00000002, 0x0009000e, 0x0005ffe1, 0xffacff90, + 0xffc5005f, 0x01210184, 0x00fcff72, 0xfd8afc77, + 0xfd51003f, 0x04020669, 0x05830103, 0xfad7f66b, + 0xf6c8fc93, 0x05430c2b, 0x0d0d06b5, 0xfc08f2b2, + 0xf00af5ec, 0x017b0c89, 0x110d0000, + }, { // 6.0 MHz + 0x00000001, 0x00070012, 0x0012fff5, 0xffbaff82, + 0xff8e000f, 0x00e80198, 0x01750028, 0xfe18fc75, + 0xfc99ff15, 0x03050636, 0x0656027f, 0xfc32f6e2, + 0xf614fb17, 0x03d20b87, 0x0d7707d2, 0xfd26f341, + 0xefeaf56f, 0x010f0c64, 0x110d0000, + }, { // 6.1 MHz + 0xffff0000, 0x00050012, 0x001c000b, 0xffd1ff84, + 0xff66ffbe, 0x00960184, 0x01cd00da, 0xfeccfcb2, + 0xfc17fdf9, 0x01e005bc, 0x06e703e4, 0xfdabf798, + 0xf599f9b3, 0x02510abd, 0x0dbf08df, 0xfe48f3dc, + 0xefd5f4f6, 0x00a20c3e, 0x110d0000, + }, { // 6.2 MHz + 0xfffffffe, 0x0002000f, 0x0021001f, 0xfff0ff97, + 0xff50ff74, 0x0034014a, 0x01fa0179, 0xff97fd2a, + 0xfbd3fcfa, 0x00a304fe, 0x07310525, 0xff37f886, + 0xf55cf86e, 0x00c709d0, 0x0de209db, 0xff6df484, + 0xefcbf481, 0x00360c18, 0x110d0000, + }, { // 6.3 MHz + 0xfffffffd, 0xfffe000a, 0x0021002f, 0x0010ffb8, + 0xff50ff3b, 0xffcc00f0, 0x01fa01fa, 0x0069fdd4, + 0xfbd3fc26, 0xff5d0407, 0x07310638, 0x00c9f9a8, + 0xf55cf74e, 0xff3908c3, 0x0de20ac3, 0x0093f537, + 0xefcbf410, 0xffca0bf2, 0x110d0000, + }, { // 6.4 MHz + 0xfffffffd, 0xfffb0003, 0x001c0037, 0x002fffe2, + 0xff66ff17, 0xff6a007e, 0x01cd0251, 0x0134fea5, + 0xfc17fb8b, 0xfe2002e0, 0x06e70713, 0x0255faf5, + 0xf599f658, 0xfdaf0799, 0x0dbf0b96, 0x01b8f5f5, + 0xefd5f3a3, 0xff5e0bca, 0x110d0000, + }, { // 6.5 MHz + 0x0000fffd, 0xfff9fffb, 0x00120037, 0x00460010, + 0xff8eff0f, 0xff180000, 0x01750276, 0x01e8ff8d, + 0xfc99fb31, 0xfcfb0198, 0x065607ad, 0x03cefc64, + 0xf614f592, 0xfc2e0656, 0x0d770c52, 0x02daf6bd, + 0xefeaf33b, 0xfef10ba3, 0x110d0000, + }, { // 6.6 MHz + 0x0000fffe, 0xfff7fff5, 0x0005002f, 0x0054003c, + 0xffc5ff22, 0xfedfff82, 0x00fc0267, 0x0276007e, + 0xfd51fb1c, 0xfbfe003e, 0x05830802, 0x0529fdec, + 0xf6c8f4fe, 0xfabd04ff, 0x0d0d0cf6, 0x03f8f78f, + 0xf00af2d7, 0xfe850b7b, 0x110d0000, + }, { // 6.7 MHz + 0x0000ffff, 0xfff8fff0, 0xfff80020, 0x00560060, + 0x0002ff4e, 0xfec4ff10, 0x006d0225, 0x02d50166, + 0xfe35fb4e, 0xfb35fee1, 0x0477080e, 0x065bff82, + 0xf7b1f4a0, 0xf9610397, 0x0c810d80, 0x0510f869, + 0xf033f278, 0xfe1a0b52, 0x110d0000, + }, { // 6.8 MHz + 0x00010000, 0xfffaffee, 0xffec000c, 0x004c0078, + 0x0040ff8e, 0xfecafeb6, 0xffd301b6, 0x02fc0235, + 0xff36fbc5, 0xfaaafd90, 0x033e07d2, 0x075b011b, + 0xf8cbf47a, 0xf81f0224, 0x0bd50def, 0x0621f94b, + 0xf067f21e, 0xfdae0b29, 0x110d0000, + }, { // 6.9 MHz + 0x00010001, 0xfffdffef, 0xffe3fff6, 0x0037007f, + 0x0075ffdc, 0xfef2fe7c, 0xff3d0122, 0x02ea02dd, + 0x0044fc79, 0xfa65fc5d, 0x01e3074e, 0x082102ad, + 0xfa0ff48c, 0xf6fe00a9, 0x0b0a0e43, 0x0729fa33, + 0xf0a5f1c9, 0xfd430b00, 0x110d0000, + }, { // 7.0 MHz + 0x00010002, 0x0001fff3, 0xffdeffe2, 0x001b0076, + 0x009c002d, 0xff35fe68, 0xfeba0076, 0x029f0352, + 0x014dfd60, 0xfa69fb53, 0x00740688, 0x08a7042d, + 0xfb75f4d6, 0xf600ff2d, 0x0a220e7a, 0x0827fb22, + 0xf0edf17a, 0xfcd80ad6, 0x110d0000, + }, { // 7.1 MHz + 0x00000003, 0x0004fff9, 0xffe0ffd2, 0xfffb005e, + 0x00b0007a, 0xff8ffe7c, 0xfe53ffc1, 0x0221038c, + 0x0241fe6e, 0xfab6fa80, 0xff010587, 0x08e90590, + 0xfcf5f556, 0xf52bfdb3, 0x09210e95, 0x0919fc15, + 0xf13ff12f, 0xfc6e0aab, 0x110d0000, + }, { // 7.2 MHz + 0x00000003, 0x00070000, 0xffe6ffc9, 0xffdb0039, + 0x00af00b8, 0xfff4feb6, 0xfe13ff10, 0x01790388, + 0x0311ff92, 0xfb48f9ed, 0xfd980453, 0x08e306cd, + 0xfe88f60a, 0xf482fc40, 0x08080e93, 0x09fdfd0c, + 0xf19af0ea, 0xfc050a81, 0x110d0000, + }, { // 7.3 MHz + 0x00000002, 0x00080008, 0xfff0ffc9, 0xffc1000d, + 0x009800e2, 0x005bff10, 0xfe00fe74, 0x00b50345, + 0x03b000bc, 0xfc18f9a1, 0xfc4802f9, 0x089807dc, + 0x0022f6f0, 0xf407fada, 0x06da0e74, 0x0ad3fe06, + 0xf1fef0ab, 0xfb9c0a55, 0x110d0000, + }, { // 7.4 MHz + 0x00000001, 0x0008000e, 0xfffdffd0, 0xffafffdf, + 0x006e00f2, 0x00b8ff82, 0xfe1bfdf8, 0xffe302c8, + 0x041301dc, 0xfd1af99e, 0xfb1e0183, 0x080908b5, + 0x01bcf801, 0xf3bdf985, 0x059a0e38, 0x0b99ff03, + 0xf26cf071, 0xfb330a2a, 0x110d0000, + }, { // 7.5 MHz + 0xffff0000, 0x00070011, 0x000affdf, 0xffa9ffb5, + 0x003700e6, 0x01010000, 0xfe62fda8, 0xff140219, + 0x043502e1, 0xfe42f9e6, 0xfa270000, 0x073a0953, + 0x034cf939, 0xf3a4f845, 0x044c0de1, 0x0c4f0000, + 0xf2e2f03c, 0xfacc09fe, 0x110d0000, + }, { // 7.6 MHz + 0xffffffff, 0x00040012, 0x0016fff3, 0xffafff95, + 0xfff900c0, 0x0130007e, 0xfecefd89, 0xfe560146, + 0x041303bc, 0xff81fa76, 0xf96cfe7d, 0x063209b1, + 0x04c9fa93, 0xf3bdf71e, 0x02f30d6e, 0x0cf200fd, + 0xf361f00e, 0xfa6509d1, 0x110d0000, + }, { // 7.7 MHz + 0xfffffffe, 0x00010010, 0x001e0008, 0xffc1ff84, + 0xffbc0084, 0x013e00f0, 0xff56fd9f, 0xfdb8005c, + 0x03b00460, 0x00c7fb45, 0xf8f4fd07, 0x04fa09ce, + 0x062afc07, 0xf407f614, 0x01920ce0, 0x0d8301fa, + 0xf3e8efe5, 0xfa0009a4, 0x110d0000, + }, { // 7.8 MHz + 0x0000fffd, 0xfffd000b, 0x0022001d, 0xffdbff82, + 0xff870039, 0x012a014a, 0xffedfde7, 0xfd47ff6b, + 0x031104c6, 0x0202fc4c, 0xf8c6fbad, 0x039909a7, + 0x0767fd8e, 0xf482f52b, 0x002d0c39, 0x0e0002f4, + 0xf477efc2, 0xf99b0977, 0x110d0000, + }, { // 7.9 MHz + 0x0000fffd, 0xfffa0004, 0x0020002d, 0xfffbff91, + 0xff61ffe8, 0x00f70184, 0x0086fe5c, 0xfd0bfe85, + 0x024104e5, 0x0323fd7d, 0xf8e2fa79, 0x021d093f, + 0x0879ff22, 0xf52bf465, 0xfec70b79, 0x0e6803eb, + 0xf50defa5, 0xf937094a, 0x110d0000, + }, { // 8.0 MHz + 0x0000fffe, 0xfff8fffd, 0x00190036, 0x001bffaf, + 0xff4fff99, 0x00aa0198, 0x0112fef3, 0xfd09fdb9, + 0x014d04be, 0x041bfecc, 0xf947f978, 0x00900897, + 0x095a00b9, 0xf600f3c5, 0xfd650aa3, 0x0ebc04de, + 0xf5aaef8e, 0xf8d5091c, 0x110d0000, + }, { // 8.1 MHz + 0x0000ffff, 0xfff7fff6, 0x000e0038, 0x0037ffd7, + 0xff52ff56, 0x004b0184, 0x0186ffa1, 0xfd40fd16, + 0x00440452, 0x04de0029, 0xf9f2f8b2, 0xfefe07b5, + 0x0a05024d, 0xf6fef34d, 0xfc0a09b8, 0x0efa05cd, + 0xf64eef7d, 0xf87308ed, 0x110d0000, + }, { // 8.2 MHz + 0x00010000, 0xfff8fff0, 0x00000031, 0x004c0005, + 0xff6aff27, 0xffe4014a, 0x01d70057, 0xfdacfca6, + 0xff3603a7, 0x05610184, 0xfadbf82e, 0xfd74069f, + 0x0a7503d6, 0xf81ff2ff, 0xfab808b9, 0x0f2306b5, + 0xf6f9ef72, 0xf81308bf, 0x110d0000, + }, { // 8.3 MHz + 0x00010001, 0xfffbffee, 0xfff30022, 0x00560032, + 0xff95ff10, 0xff8000f0, 0x01fe0106, 0xfe46fc71, + 0xfe3502c7, 0x059e02ce, 0xfbf9f7f2, 0xfbff055b, + 0x0aa9054c, 0xf961f2db, 0xf97507aa, 0x0f350797, + 0xf7a9ef6d, 0xf7b40890, 0x110d0000, + }, { // 8.4 MHz + 0x00010002, 0xfffeffee, 0xffe8000f, 0x00540058, + 0xffcdff14, 0xff29007e, 0x01f6019e, 0xff01fc7c, + 0xfd5101bf, 0x059203f6, 0xfd41f7fe, 0xfaa903f3, + 0x0a9e06a9, 0xfabdf2e2, 0xf842068b, 0x0f320871, + 0xf85eef6e, 0xf7560860, 0x110d0000, + }, { // 8.5 MHz + 0x00000003, 0x0002fff2, 0xffe1fff9, 0x00460073, + 0x000bff34, 0xfee90000, 0x01c10215, 0xffd0fcc5, + 0xfc99009d, 0x053d04f1, 0xfea5f853, 0xf97d0270, + 0x0a5607e4, 0xfc2ef314, 0xf723055f, 0x0f180943, + 0xf919ef75, 0xf6fa0830, 0x110d0000, + }, { // 8.6 MHz + 0x00000003, 0x0005fff8, 0xffdeffe4, 0x002f007f, + 0x0048ff6b, 0xfec7ff82, 0x0163025f, 0x00a2fd47, + 0xfc17ff73, 0x04a405b2, 0x0017f8ed, 0xf88500dc, + 0x09d208f9, 0xfdaff370, 0xf61c0429, 0x0ee80a0b, + 0xf9d8ef82, 0xf6a00800, 0x110d0000, + }, { // 8.7 MHz + 0x00000003, 0x0007ffff, 0xffe1ffd4, 0x0010007a, + 0x007cffb2, 0xfec6ff10, 0x00e60277, 0x0168fdf9, + 0xfbd3fe50, 0x03ce0631, 0x0188f9c8, 0xf7c7ff43, + 0x091509e3, 0xff39f3f6, 0xf52d02ea, 0x0ea30ac9, + 0xfa9bef95, 0xf64607d0, 0x110d0000, + }, { // 8.8 MHz + 0x00000002, 0x00090007, 0xffe9ffca, 0xfff00065, + 0x00a10003, 0xfee6feb6, 0x0053025b, 0x0213fed0, + 0xfbd3fd46, 0x02c70668, 0x02eafadb, 0xf74bfdae, + 0x08230a9c, 0x00c7f4a3, 0xf45b01a6, 0x0e480b7c, + 0xfb61efae, 0xf5ef079f, 0x110d0000, + }, { // 8.9 MHz + 0xffff0000, 0x0008000d, 0xfff5ffc8, 0xffd10043, + 0x00b20053, 0xff24fe7c, 0xffb9020c, 0x0295ffbb, + 0xfc17fc64, 0x019b0654, 0x042dfc1c, 0xf714fc2a, + 0x07020b21, 0x0251f575, 0xf3a7005e, 0x0dd80c24, + 0xfc2aefcd, 0xf599076e, 0x110d0000, + }, { // 9.0 MHz + 0xffffffff, 0x00060011, 0x0002ffcf, 0xffba0018, + 0x00ad009a, 0xff79fe68, 0xff260192, 0x02e500ab, + 0xfc99fbb6, 0x005b05f7, 0x0545fd81, 0xf723fabf, + 0x05b80b70, 0x03d2f669, 0xf313ff15, 0x0d550cbf, + 0xfcf6eff2, 0xf544073d, 0x110d0000, + }, { // 9.1 MHz + 0xfffffffe, 0x00030012, 0x000fffdd, 0xffacffea, + 0x009300cf, 0xffdcfe7c, 0xfea600f7, 0x02fd0190, + 0xfd51fb46, 0xff150554, 0x0627fefd, 0xf778f978, + 0x044d0b87, 0x0543f77d, 0xf2a0fdcf, 0x0cbe0d4e, + 0xfdc4f01d, 0xf4f2070b, 0x110d0000, + }, { // 9.2 MHz + 0x0000fffd, 0x00000010, 0x001afff0, 0xffaaffbf, + 0x006700ed, 0x0043feb6, 0xfe460047, 0x02db0258, + 0xfe35fb1b, 0xfddc0473, 0x06c90082, 0xf811f85e, + 0x02c90b66, 0x069ff8ad, 0xf250fc8d, 0x0c140dcf, + 0xfe93f04d, 0xf4a106d9, 0x110d0000, + }, { // 9.3 MHz + 0x0000fffd, 0xfffc000c, 0x00200006, 0xffb4ff9c, + 0x002f00ef, 0x00a4ff10, 0xfe0dff92, 0x028102f7, + 0xff36fb37, 0xfcbf035e, 0x07260202, 0xf8e8f778, + 0x01340b0d, 0x07e1f9f4, 0xf223fb51, 0x0b590e42, + 0xff64f083, 0xf45206a7, 0x110d0000, + }, { // 9.4 MHz + 0x0000fffd, 0xfff90005, 0x0022001a, 0xffc9ff86, + 0xfff000d7, 0x00f2ff82, 0xfe01fee5, 0x01f60362, + 0x0044fb99, 0xfbcc0222, 0x07380370, 0xf9f7f6cc, + 0xff990a7e, 0x0902fb50, 0xf21afa1f, 0x0a8d0ea6, + 0x0034f0bf, 0xf4050675, 0x110d0000, + }, { // 9.5 MHz + 0x0000fffe, 0xfff8fffe, 0x001e002b, 0xffe5ff81, + 0xffb400a5, 0x01280000, 0xfe24fe50, 0x01460390, + 0x014dfc3a, 0xfb1000ce, 0x070104bf, 0xfb37f65f, + 0xfe0009bc, 0x0a00fcbb, 0xf235f8f8, 0x09b20efc, + 0x0105f101, 0xf3ba0642, 0x110d0000, + }, { // 9.6 MHz + 0x0001ffff, 0xfff8fff7, 0x00150036, 0x0005ff8c, + 0xff810061, 0x013d007e, 0xfe71fddf, 0x007c0380, + 0x0241fd13, 0xfa94ff70, 0x068005e2, 0xfc9bf633, + 0xfc7308ca, 0x0ad5fe30, 0xf274f7e0, 0x08c90f43, + 0x01d4f147, 0xf371060f, 0x110d0000, + }, { // 9.7 MHz + 0x00010001, 0xfff9fff1, 0x00090038, 0x0025ffa7, + 0xff5e0012, 0x013200f0, 0xfee3fd9b, 0xffaa0331, + 0x0311fe15, 0xfa60fe18, 0x05bd06d1, 0xfe1bf64a, + 0xfafa07ae, 0x0b7effab, 0xf2d5f6d7, 0x07d30f7a, + 0x02a3f194, 0xf32905dc, 0x110d0000, + }, { // 9.8 MHz + 0x00010002, 0xfffcffee, 0xfffb0032, 0x003fffcd, + 0xff4effc1, 0x0106014a, 0xff6efd8a, 0xfedd02aa, + 0x03b0ff34, 0xfa74fcd7, 0x04bf0781, 0xffaaf6a3, + 0xf99e066b, 0x0bf90128, 0xf359f5e1, 0x06d20fa2, + 0x0370f1e5, 0xf2e405a8, 0x110d0000, + }, { // 9.9 MHz + 0x00000003, 0xffffffee, 0xffef0024, 0x0051fffa, + 0xff54ff77, 0x00be0184, 0x0006fdad, 0xfe2701f3, + 0x0413005e, 0xfad1fbba, 0x039007ee, 0x013bf73d, + 0xf868050a, 0x0c4302a1, 0xf3fdf4fe, 0x05c70fba, + 0x043bf23c, 0xf2a10575, 0x110d0000, + }, { // 10.0 MHz + 0x00000003, 0x0003fff1, 0xffe50011, 0x00570027, + 0xff70ff3c, 0x00620198, 0x009efe01, 0xfd95011a, + 0x04350183, 0xfb71fad0, 0x023c0812, 0x02c3f811, + 0xf75e0390, 0x0c5c0411, 0xf4c1f432, 0x04b30fc1, + 0x0503f297, 0xf2610541, 0x110d0000, + }, { // 10.1 MHz + 0x00000003, 0x0006fff7, 0xffdffffc, 0x00510050, + 0xff9dff18, 0xfffc0184, 0x0128fe80, 0xfd32002e, + 0x04130292, 0xfc4dfa21, 0x00d107ee, 0x0435f91c, + 0xf6850205, 0x0c430573, 0xf5a1f37d, 0x03990fba, + 0x05c7f2f8, 0xf222050d, 0x110d0000, + }, { // 10.2 MHz + 0x00000002, 0x0008fffe, 0xffdfffe7, 0x003f006e, + 0xffd6ff0f, 0xff96014a, 0x0197ff1f, 0xfd05ff3e, + 0x03b0037c, 0xfd59f9b7, 0xff5d0781, 0x0585fa56, + 0xf5e4006f, 0x0bf906c4, 0xf69df2e0, 0x02790fa2, + 0x0688f35d, 0xf1e604d8, 0x110d0000, + }, { // 10.3 MHz + 0xffff0001, 0x00090005, 0xffe4ffd6, 0x0025007e, + 0x0014ff20, 0xff3c00f0, 0x01e1ffd0, 0xfd12fe5c, + 0x03110433, 0xfe88f996, 0xfdf106d1, 0x06aafbb7, + 0xf57efed8, 0x0b7e07ff, 0xf7b0f25e, 0x01560f7a, + 0x0745f3c7, 0xf1ac04a4, 0x110d0000, + }, { // 10.4 MHz + 0xffffffff, 0x0008000c, 0xffedffcb, 0x0005007d, + 0x0050ff4c, 0xfef6007e, 0x01ff0086, 0xfd58fd97, + 0x024104ad, 0xffcaf9c0, 0xfc9905e2, 0x079afd35, + 0xf555fd46, 0x0ad50920, 0xf8d9f1f6, 0x00310f43, + 0x07fdf435, 0xf174046f, 0x110d0000, + }, { // 10.5 MHz + 0xfffffffe, 0x00050011, 0xfffaffc8, 0xffe5006b, + 0x0082ff8c, 0xfecc0000, 0x01f00130, 0xfdd2fcfc, + 0x014d04e3, 0x010efa32, 0xfb6404bf, 0x084efec5, + 0xf569fbc2, 0x0a000a23, 0xfa15f1ab, 0xff0b0efc, + 0x08b0f4a7, 0xf13f043a, 0x110d0000, + }, { // 10.6 MHz + 0x0000fffd, 0x00020012, 0x0007ffcd, 0xffc9004c, + 0x00a4ffd9, 0xfec3ff82, 0x01b401c1, 0xfe76fc97, + 0x004404d2, 0x0245fae8, 0xfa5f0370, 0x08c1005f, + 0xf5bcfa52, 0x09020b04, 0xfb60f17b, 0xfde70ea6, + 0x095df51e, 0xf10c0405, 0x110d0000, + }, { // 10.7 MHz + 0x0000fffd, 0xffff0011, 0x0014ffdb, 0xffb40023, + 0x00b2002a, 0xfedbff10, 0x0150022d, 0xff38fc6f, + 0xff36047b, 0x035efbda, 0xf9940202, 0x08ee01f5, + 0xf649f8fe, 0x07e10bc2, 0xfcb6f169, 0xfcc60e42, + 0x0a04f599, 0xf0db03d0, 0x110d0000, + }, { // 10.8 MHz + 0x0000fffd, 0xfffb000d, 0x001dffed, 0xffaafff5, + 0x00aa0077, 0xff13feb6, 0x00ce026b, 0x000afc85, + 0xfe3503e3, 0x044cfcfb, 0xf90c0082, 0x08d5037f, + 0xf710f7cc, 0x069f0c59, 0xfe16f173, 0xfbaa0dcf, + 0x0aa5f617, 0xf0ad039b, 0x110d0000, + }, { // 10.9 MHz + 0x0000fffe, 0xfff90006, 0x00210003, 0xffacffc8, + 0x008e00b6, 0xff63fe7c, 0x003a0275, 0x00dafcda, + 0xfd510313, 0x0501fe40, 0xf8cbfefd, 0x087604f0, + 0xf80af6c2, 0x05430cc8, 0xff7af19a, 0xfa940d4e, + 0x0b3ff699, 0xf0810365, 0x110d0000, + }, { // 11.0 MHz + 0x0001ffff, 0xfff8ffff, 0x00210018, 0xffbaffa3, + 0x006000e1, 0xffc4fe68, 0xffa0024b, 0x019afd66, + 0xfc990216, 0x0575ff99, 0xf8d4fd81, 0x07d40640, + 0xf932f5e6, 0x03d20d0d, 0x00dff1de, 0xf9860cbf, + 0x0bd1f71e, 0xf058032f, 0x110d0000, + }, { // 11.1 MHz + 0x00010000, 0xfff8fff8, 0x001b0029, 0xffd1ff8a, + 0x002600f2, 0x002cfe7c, 0xff0f01f0, 0x023bfe20, + 0xfc1700fa, 0x05a200f7, 0xf927fc1c, 0x06f40765, + 0xfa82f53b, 0x02510d27, 0x0243f23d, 0xf8810c24, + 0x0c5cf7a7, 0xf03102fa, 0x110d0000, + }, { // 11.2 MHz + 0x00010002, 0xfffafff2, 0x00110035, 0xfff0ff81, + 0xffe700e7, 0x008ffeb6, 0xfe94016d, 0x02b0fefb, + 0xfbd3ffd1, 0x05850249, 0xf9c1fadb, 0x05de0858, + 0xfbf2f4c4, 0x00c70d17, 0x03a0f2b8, 0xf7870b7c, + 0x0cdff833, 0xf00d02c4, 0x110d0000, + }, { // 11.3 MHz + 0x00000003, 0xfffdffee, 0x00040038, 0x0010ff88, + 0xffac00c2, 0x00e2ff10, 0xfe3900cb, 0x02f1ffe9, + 0xfbd3feaa, 0x05210381, 0xfa9cf9c8, 0x04990912, + 0xfd7af484, 0xff390cdb, 0x04f4f34d, 0xf69a0ac9, + 0x0d5af8c1, 0xefec028e, 0x110d0000, + }, { // 11.4 MHz + 0x00000003, 0x0000ffee, 0xfff60033, 0x002fff9f, + 0xff7b0087, 0x011eff82, 0xfe080018, 0x02f900d8, + 0xfc17fd96, 0x04790490, 0xfbadf8ed, 0x032f098e, + 0xff10f47d, 0xfdaf0c75, 0x063cf3fc, 0xf5ba0a0b, + 0x0dccf952, 0xefcd0258, 0x110d0000, + }, { // 11.5 MHz + 0x00000003, 0x0004fff1, 0xffea0026, 0x0046ffc3, + 0xff5a003c, 0x013b0000, 0xfe04ff63, 0x02c801b8, + 0xfc99fca6, 0x0397056a, 0xfcecf853, 0x01ad09c9, + 0x00acf4ad, 0xfc2e0be7, 0x0773f4c2, 0xf4e90943, + 0x0e35f9e6, 0xefb10221, 0x110d0000, + }, { // 11.6 MHz + 0x00000002, 0x0007fff6, 0xffe20014, 0x0054ffee, + 0xff4effeb, 0x0137007e, 0xfe2efebb, 0x0260027a, + 0xfd51fbe6, 0x02870605, 0xfe4af7fe, 0x001d09c1, + 0x0243f515, 0xfabd0b32, 0x0897f59e, 0xf4280871, + 0x0e95fa7c, 0xef9701eb, 0x110d0000, + }, { // 11.7 MHz + 0xffff0001, 0x0008fffd, 0xffdeffff, 0x0056001d, + 0xff57ff9c, 0x011300f0, 0xfe82fe2e, 0x01ca0310, + 0xfe35fb62, 0x0155065a, 0xffbaf7f2, 0xfe8c0977, + 0x03cef5b2, 0xf9610a58, 0x09a5f68f, 0xf3790797, + 0x0eebfb14, 0xef8001b5, 0x110d0000, + }, { // 11.8 MHz + 0xffff0000, 0x00080004, 0xffe0ffe9, 0x004c0047, + 0xff75ff58, 0x00d1014a, 0xfef9fdc8, 0x0111036f, + 0xff36fb21, 0x00120665, 0x012df82e, 0xfd0708ec, + 0x0542f682, 0xf81f095c, 0x0a9af792, 0xf2db06b5, + 0x0f38fbad, 0xef6c017e, 0x110d0000, + }, { // 11.9 MHz + 0xffffffff, 0x0007000b, 0xffe7ffd8, 0x00370068, + 0xffa4ff28, 0x00790184, 0xff87fd91, 0x00430392, + 0x0044fb26, 0xfece0626, 0x0294f8b2, 0xfb990825, + 0x0698f77f, 0xf6fe0842, 0x0b73f8a7, 0xf25105cd, + 0x0f7bfc48, 0xef5a0148, 0x110d0000, + }, { // 12.0 MHz + 0x0000fffe, 0x00050010, 0xfff2ffcc, 0x001b007b, + 0xffdfff10, 0x00140198, 0x0020fd8e, 0xff710375, + 0x014dfb73, 0xfd9a059f, 0x03e0f978, 0xfa4e0726, + 0x07c8f8a7, 0xf600070c, 0x0c2ff9c9, 0xf1db04de, + 0x0fb4fce5, 0xef4b0111, 0x110d0000, + }, { // 12.1 MHz + 0x0000fffd, 0x00010012, 0xffffffc8, 0xfffb007e, + 0x001dff14, 0xffad0184, 0x00b7fdbe, 0xfea9031b, + 0x0241fc01, 0xfc8504d6, 0x0504fa79, 0xf93005f6, + 0x08caf9f2, 0xf52b05c0, 0x0ccbfaf9, 0xf17903eb, + 0x0fe3fd83, 0xef3f00db, 0x110d0000, + }, { // 12.2 MHz + 0x0000fffd, 0xfffe0011, 0x000cffcc, 0xffdb0071, + 0x0058ff32, 0xff4f014a, 0x013cfe1f, 0xfdfb028a, + 0x0311fcc9, 0xfb9d03d6, 0x05f4fbad, 0xf848049d, + 0x0999fb5b, 0xf4820461, 0x0d46fc32, 0xf12d02f4, + 0x1007fe21, 0xef3600a4, 0x110d0000, + }, { // 12.3 MHz + 0x0000fffe, 0xfffa000e, 0x0017ffd9, 0xffc10055, + 0x0088ff68, 0xff0400f0, 0x01a6fea7, 0xfd7501cc, + 0x03b0fdc0, 0xfaef02a8, 0x06a7fd07, 0xf79d0326, + 0x0a31fcda, 0xf40702f3, 0x0d9ffd72, 0xf0f601fa, + 0x1021fec0, 0xef2f006d, 0x110d0000, + }, { // 12.4 MHz + 0x0001ffff, 0xfff80007, 0x001fffeb, 0xffaf002d, + 0x00a8ffb0, 0xfed3007e, 0x01e9ff4c, 0xfd2000ee, + 0x0413fed8, 0xfa82015c, 0x0715fe7d, 0xf7340198, + 0x0a8dfe69, 0xf3bd017c, 0x0dd5feb8, 0xf0d500fd, + 0x1031ff60, 0xef2b0037, 0x110d0000, + }, { // 12.5 MHz + 0x00010000, 0xfff70000, 0x00220000, 0xffa90000, + 0x00b30000, 0xfec20000, 0x02000000, 0xfd030000, + 0x04350000, 0xfa5e0000, 0x073b0000, 0xf7110000, + 0x0aac0000, 0xf3a40000, 0x0de70000, 0xf0c90000, + 0x10360000, 0xef290000, 0x110d0000, + }, { // 12.6 MHz + 0x00010001, 0xfff8fff9, 0x001f0015, 0xffafffd3, + 0x00a80050, 0xfed3ff82, 0x01e900b4, 0xfd20ff12, + 0x04130128, 0xfa82fea4, 0x07150183, 0xf734fe68, + 0x0a8d0197, 0xf3bdfe84, 0x0dd50148, 0xf0d5ff03, + 0x103100a0, 0xef2bffc9, 0x110d0000, + }, { // 12.7 MHz + 0x00000002, 0xfffafff2, 0x00170027, 0xffc1ffab, + 0x00880098, 0xff04ff10, 0x01a60159, 0xfd75fe34, + 0x03b00240, 0xfaeffd58, 0x06a702f9, 0xf79dfcda, + 0x0a310326, 0xf407fd0d, 0x0d9f028e, 0xf0f6fe06, + 0x10210140, 0xef2fff93, 0x110d0000, + }, { // 12.8 MHz + 0x00000003, 0xfffeffef, 0x000c0034, 0xffdbff8f, + 0x005800ce, 0xff4ffeb6, 0x013c01e1, 0xfdfbfd76, + 0x03110337, 0xfb9dfc2a, 0x05f40453, 0xf848fb63, + 0x099904a5, 0xf482fb9f, 0x0d4603ce, 0xf12dfd0c, + 0x100701df, 0xef36ff5c, 0x110d0000, + }, { // 12.9 MHz + 0x00000003, 0x0001ffee, 0xffff0038, 0xfffbff82, + 0x001d00ec, 0xffadfe7c, 0x00b70242, 0xfea9fce5, + 0x024103ff, 0xfc85fb2a, 0x05040587, 0xf930fa0a, + 0x08ca060e, 0xf52bfa40, 0x0ccb0507, 0xf179fc15, + 0x0fe3027d, 0xef3fff25, 0x110d0000, + }, { // 13.0 MHz + 0x00000002, 0x0005fff0, 0xfff20034, 0x001bff85, + 0xffdf00f0, 0x0014fe68, 0x00200272, 0xff71fc8b, + 0x014d048d, 0xfd9afa61, 0x03e00688, 0xfa4ef8da, + 0x07c80759, 0xf600f8f4, 0x0c2f0637, 0xf1dbfb22, + 0x0fb4031b, 0xef4bfeef, 0x110d0000, + }, { // 13.1 MHz + 0xffff0001, 0x0007fff5, 0xffe70028, 0x0037ff98, + 0xffa400d8, 0x0079fe7c, 0xff87026f, 0x0043fc6e, + 0x004404da, 0xfecef9da, 0x0294074e, 0xfb99f7db, + 0x06980881, 0xf6fef7be, 0x0b730759, 0xf251fa33, + 0x0f7b03b8, 0xef5afeb8, 0x110d0000, + }, { // 13.2 MHz + 0xffff0000, 0x0008fffc, 0xffe00017, 0x004cffb9, + 0xff7500a8, 0x00d1feb6, 0xfef90238, 0x0111fc91, + 0xff3604df, 0x0012f99b, 0x012d07d2, 0xfd07f714, + 0x0542097e, 0xf81ff6a4, 0x0a9a086e, 0xf2dbf94b, + 0x0f380453, 0xef6cfe82, 0x110d0000, + }, { // 13.3 MHz + 0xffffffff, 0x00080003, 0xffde0001, 0x0056ffe3, + 0xff570064, 0x0113ff10, 0xfe8201d2, 0x01cafcf0, + 0xfe35049e, 0x0155f9a6, 0xffba080e, 0xfe8cf689, + 0x03ce0a4e, 0xf961f5a8, 0x09a50971, 0xf379f869, + 0x0eeb04ec, 0xef80fe4b, 0x110d0000, + }, { // 13.4 MHz + 0x0000fffe, 0x0007000a, 0xffe2ffec, 0x00540012, + 0xff4e0015, 0x0137ff82, 0xfe2e0145, 0x0260fd86, + 0xfd51041a, 0x0287f9fb, 0xfe4a0802, 0x001df63f, + 0x02430aeb, 0xfabdf4ce, 0x08970a62, 0xf428f78f, + 0x0e950584, 0xef97fe15, 0x110d0000, + }, { // 13.5 MHz + 0x0000fffd, 0x0004000f, 0xffeaffda, 0x0046003d, + 0xff5affc4, 0x013b0000, 0xfe04009d, 0x02c8fe48, + 0xfc99035a, 0x0397fa96, 0xfcec07ad, 0x01adf637, + 0x00ac0b53, 0xfc2ef419, 0x07730b3e, 0xf4e9f6bd, + 0x0e35061a, 0xefb1fddf, 0x110d0000, + }, { // 13.6 MHz + 0x0000fffd, 0x00000012, 0xfff6ffcd, 0x002f0061, + 0xff7bff79, 0x011e007e, 0xfe08ffe8, 0x02f9ff28, + 0xfc17026a, 0x0479fb70, 0xfbad0713, 0x032ff672, + 0xff100b83, 0xfdaff38b, 0x063c0c04, 0xf5baf5f5, + 0x0dcc06ae, 0xefcdfda8, 0x110d0000, + }, { // 13.7 MHz + 0x0000fffd, 0xfffd0012, 0x0004ffc8, 0x00100078, + 0xffacff3e, 0x00e200f0, 0xfe39ff35, 0x02f10017, + 0xfbd30156, 0x0521fc7f, 0xfa9c0638, 0x0499f6ee, + 0xfd7a0b7c, 0xff39f325, 0x04f40cb3, 0xf69af537, + 0x0d5a073f, 0xefecfd72, 0x110d0000, + }, { // 13.8 MHz + 0x0001fffe, 0xfffa000e, 0x0011ffcb, 0xfff0007f, + 0xffe7ff19, 0x008f014a, 0xfe94fe93, 0x02b00105, + 0xfbd3002f, 0x0585fdb7, 0xf9c10525, 0x05def7a8, + 0xfbf20b3c, 0x00c7f2e9, 0x03a00d48, 0xf787f484, + 0x0cdf07cd, 0xf00dfd3c, 0x110d0000, + }, { // 13.9 MHz + 0x00010000, 0xfff80008, 0x001bffd7, 0xffd10076, + 0x0026ff0e, 0x002c0184, 0xff0ffe10, 0x023b01e0, + 0xfc17ff06, 0x05a2ff09, 0xf92703e4, 0x06f4f89b, + 0xfa820ac5, 0x0251f2d9, 0x02430dc3, 0xf881f3dc, + 0x0c5c0859, 0xf031fd06, 0x110d0000, + }, { // 14.0 MHz + 0x00010001, 0xfff80001, 0x0021ffe8, 0xffba005d, + 0x0060ff1f, 0xffc40198, 0xffa0fdb5, 0x019a029a, + 0xfc99fdea, 0x05750067, 0xf8d4027f, 0x07d4f9c0, + 0xf9320a1a, 0x03d2f2f3, 0x00df0e22, 0xf986f341, + 0x0bd108e2, 0xf058fcd1, 0x110d0000, + }, { // 14.1 MHz + 0x00000002, 0xfff9fffa, 0x0021fffd, 0xffac0038, + 0x008eff4a, 0xff630184, 0x003afd8b, 0x00da0326, + 0xfd51fced, 0x050101c0, 0xf8cb0103, 0x0876fb10, + 0xf80a093e, 0x0543f338, 0xff7a0e66, 0xfa94f2b2, + 0x0b3f0967, 0xf081fc9b, 0x110d0000, + }, { // 14.2 MHz + 0x00000003, 0xfffbfff3, 0x001d0013, 0xffaa000b, + 0x00aaff89, 0xff13014a, 0x00cefd95, 0x000a037b, + 0xfe35fc1d, 0x044c0305, 0xf90cff7e, 0x08d5fc81, + 0xf7100834, 0x069ff3a7, 0xfe160e8d, 0xfbaaf231, + 0x0aa509e9, 0xf0adfc65, 0x110d0000, + }, { // 14.3 MHz + 0x00000003, 0xffffffef, 0x00140025, 0xffb4ffdd, + 0x00b2ffd6, 0xfedb00f0, 0x0150fdd3, 0xff380391, + 0xff36fb85, 0x035e0426, 0xf994fdfe, 0x08eefe0b, + 0xf6490702, 0x07e1f43e, 0xfcb60e97, 0xfcc6f1be, + 0x0a040a67, 0xf0dbfc30, 0x110d0000, + }, { // 14.4 MHz + 0x00000003, 0x0002ffee, 0x00070033, 0xffc9ffb4, + 0x00a40027, 0xfec3007e, 0x01b4fe3f, 0xfe760369, + 0x0044fb2e, 0x02450518, 0xfa5ffc90, 0x08c1ffa1, + 0xf5bc05ae, 0x0902f4fc, 0xfb600e85, 0xfde7f15a, + 0x095d0ae2, 0xf10cfbfb, 0x110d0000, + }, { // 14.5 MHz + 0xffff0002, 0x0005ffef, 0xfffa0038, 0xffe5ff95, + 0x00820074, 0xfecc0000, 0x01f0fed0, 0xfdd20304, + 0x014dfb1d, 0x010e05ce, 0xfb64fb41, 0x084e013b, + 0xf569043e, 0x0a00f5dd, 0xfa150e55, 0xff0bf104, + 0x08b00b59, 0xf13ffbc6, 0x110d0000, + }, { // 14.6 MHz + 0xffff0001, 0x0008fff4, 0xffed0035, 0x0005ff83, + 0x005000b4, 0xfef6ff82, 0x01ffff7a, 0xfd580269, + 0x0241fb53, 0xffca0640, 0xfc99fa1e, 0x079a02cb, + 0xf55502ba, 0x0ad5f6e0, 0xf8d90e0a, 0x0031f0bd, + 0x07fd0bcb, 0xf174fb91, 0x110d0000, + }, { // 14.7 MHz + 0xffffffff, 0x0009fffb, 0xffe4002a, 0x0025ff82, + 0x001400e0, 0xff3cff10, 0x01e10030, 0xfd1201a4, + 0x0311fbcd, 0xfe88066a, 0xfdf1f92f, 0x06aa0449, + 0xf57e0128, 0x0b7ef801, 0xf7b00da2, 0x0156f086, + 0x07450c39, 0xf1acfb5c, 0x110d0000, + }, { // 14.8 MHz + 0x0000fffe, 0x00080002, 0xffdf0019, 0x003fff92, + 0xffd600f1, 0xff96feb6, 0x019700e1, 0xfd0500c2, + 0x03b0fc84, 0xfd590649, 0xff5df87f, 0x058505aa, + 0xf5e4ff91, 0x0bf9f93c, 0xf69d0d20, 0x0279f05e, + 0x06880ca3, 0xf1e6fb28, 0x110d0000, + }, { // 14.9 MHz + 0x0000fffd, 0x00060009, 0xffdf0004, 0x0051ffb0, + 0xff9d00e8, 0xfffcfe7c, 0x01280180, 0xfd32ffd2, + 0x0413fd6e, 0xfc4d05df, 0x00d1f812, 0x043506e4, + 0xf685fdfb, 0x0c43fa8d, 0xf5a10c83, 0x0399f046, + 0x05c70d08, 0xf222faf3, 0x110d0000, + }, { // 15.0 MHz + 0x0000fffd, 0x0003000f, 0xffe5ffef, 0x0057ffd9, + 0xff7000c4, 0x0062fe68, 0x009e01ff, 0xfd95fee6, + 0x0435fe7d, 0xfb710530, 0x023cf7ee, 0x02c307ef, + 0xf75efc70, 0x0c5cfbef, 0xf4c10bce, 0x04b3f03f, + 0x05030d69, 0xf261fabf, 0x110d0000, + }, { // 15.1 MHz + 0x0000fffd, 0xffff0012, 0xffefffdc, 0x00510006, + 0xff540089, 0x00befe7c, 0x00060253, 0xfe27fe0d, + 0x0413ffa2, 0xfad10446, 0x0390f812, 0x013b08c3, + 0xf868faf6, 0x0c43fd5f, 0xf3fd0b02, 0x05c7f046, + 0x043b0dc4, 0xf2a1fa8b, 0x110d0000, + }, { // 15.2 MHz + 0x0001fffe, 0xfffc0012, 0xfffbffce, 0x003f0033, + 0xff4e003f, 0x0106feb6, 0xff6e0276, 0xfeddfd56, + 0x03b000cc, 0xfa740329, 0x04bff87f, 0xffaa095d, + 0xf99ef995, 0x0bf9fed8, 0xf3590a1f, 0x06d2f05e, + 0x03700e1b, 0xf2e4fa58, 0x110d0000, + }, { // 15.3 MHz + 0x0001ffff, 0xfff9000f, 0x0009ffc8, 0x00250059, + 0xff5effee, 0x0132ff10, 0xfee30265, 0xffaafccf, + 0x031101eb, 0xfa6001e8, 0x05bdf92f, 0xfe1b09b6, + 0xfafaf852, 0x0b7e0055, 0xf2d50929, 0x07d3f086, + 0x02a30e6c, 0xf329fa24, 0x110d0000, + }, { // 15.4 MHz + 0x00010001, 0xfff80009, 0x0015ffca, 0x00050074, + 0xff81ff9f, 0x013dff82, 0xfe710221, 0x007cfc80, + 0x024102ed, 0xfa940090, 0x0680fa1e, 0xfc9b09cd, + 0xfc73f736, 0x0ad501d0, 0xf2740820, 0x08c9f0bd, + 0x01d40eb9, 0xf371f9f1, 0x110d0000, + }, { // 15.5 MHz + 0x00000002, 0xfff80002, 0x001effd5, 0xffe5007f, + 0xffb4ff5b, 0x01280000, 0xfe2401b0, 0x0146fc70, + 0x014d03c6, 0xfb10ff32, 0x0701fb41, 0xfb3709a1, + 0xfe00f644, 0x0a000345, 0xf2350708, 0x09b2f104, + 0x01050eff, 0xf3baf9be, 0x110d0000, + }, { // 15.6 MHz + 0x00000003, 0xfff9fffb, 0x0022ffe6, 0xffc9007a, + 0xfff0ff29, 0x00f2007e, 0xfe01011b, 0x01f6fc9e, + 0x00440467, 0xfbccfdde, 0x0738fc90, 0xf9f70934, + 0xff99f582, 0x090204b0, 0xf21a05e1, 0x0a8df15a, + 0x00340f41, 0xf405f98b, 0x110d0000, + }, { // 15.7 MHz + 0x00000003, 0xfffcfff4, 0x0020fffa, 0xffb40064, + 0x002fff11, 0x00a400f0, 0xfe0d006e, 0x0281fd09, + 0xff3604c9, 0xfcbffca2, 0x0726fdfe, 0xf8e80888, + 0x0134f4f3, 0x07e1060c, 0xf22304af, 0x0b59f1be, + 0xff640f7d, 0xf452f959, 0x110d0000, + }, { // 15.8 MHz + 0x00000003, 0x0000fff0, 0x001a0010, 0xffaa0041, + 0x0067ff13, 0x0043014a, 0xfe46ffb9, 0x02dbfda8, + 0xfe3504e5, 0xfddcfb8d, 0x06c9ff7e, 0xf81107a2, + 0x02c9f49a, 0x069f0753, 0xf2500373, 0x0c14f231, + 0xfe930fb3, 0xf4a1f927, 0x110d0000, + }, { // 15.9 MHz + 0xffff0002, 0x0003ffee, 0x000f0023, 0xffac0016, + 0x0093ff31, 0xffdc0184, 0xfea6ff09, 0x02fdfe70, + 0xfd5104ba, 0xff15faac, 0x06270103, 0xf7780688, + 0x044df479, 0x05430883, 0xf2a00231, 0x0cbef2b2, + 0xfdc40fe3, 0xf4f2f8f5, 0x110d0000, + }, { // 16.0 MHz + 0xffff0001, 0x0006ffef, 0x00020031, 0xffbaffe8, + 0x00adff66, 0xff790198, 0xff26fe6e, 0x02e5ff55, + 0xfc99044a, 0x005bfa09, 0x0545027f, 0xf7230541, + 0x05b8f490, 0x03d20997, 0xf31300eb, 0x0d55f341, + 0xfcf6100e, 0xf544f8c3, 0x110d0000, + } +}; + static void cx23885_dif_setup(struct i2c_client *client, u32 ifHz) { u64 pll_freq; u32 pll_freq_word; + const u32 *coeffs; v4l_dbg(1, cx25840_debug, client, "%s(%d)\n", __func__, ifHz); @@ -2763,2889 +3554,26 @@ static void cx23885_dif_setup(struct i2c_client *client, u32 ifHz) v4l_dbg(1, cx25840_debug, client, "%s(%d) again\n", __func__, ifHz); - switch (ifHz) { - case 3000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0024); - cx25840_write4(client, DIF_BPF_COEFF67, 0x001bfff8); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff50); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed8fe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe34); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfebaffc7); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d031f); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04f0065d); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x07010688); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x04c901d6); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f9d3); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f342); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f337); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf64efb22); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105070f); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0c460fce); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00220032); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00370026); - cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff91); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0efe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fdcc); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe0afedb); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440224); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0434060c); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738074e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x06090361); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99fb39); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef3b6); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21af2a5); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf573fa33); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034067d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bfb0fb9); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000e); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00200038); - cx25840_write4(client, DIF_BPF_COEFF67, 0x004c004f); - cx25840_write4(client, DIF_BPF_COEFF89, 0x002fffdf); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff5cfeb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dfd92); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7ffe03); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36010a); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x03410575); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x072607d2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x071804d5); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134fcb7); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff451); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223f22e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4a7f94b); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xff6405e8); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bae0fa4); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00000008); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0036); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0056006d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00670030); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffbdff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46fd8d); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd25fd4f); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35ffe0); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0224049f); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9080e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x07ef0627); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9fe45); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f513); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250f1d2); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3ecf869); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930552); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b5f0f8f); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0001); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000f002c); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0054007d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0093007c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0024ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6fdbb); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd03fcca); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51feb9); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x00eb0392); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270802); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08880750); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x044dffdb); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf5f8); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0f193); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf342f78f); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc404b9); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b0e0f78); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff9); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0002001b); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0046007d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad00ba); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00870000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe1a); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1bfc7e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fda4); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xffa5025c); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x054507ad); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08dd0847); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80172); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef6ff); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313f170); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2abf6bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6041f); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0abc0f61); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff3); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff50006); - cx25840_write4(client, DIF_BPF_COEFF67, 0x002f006c); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b200e3); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00dc007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9fea0); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd6bfc71); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fcb1); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe65010b); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x042d0713); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ec0906); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020302); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff823); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7f16a); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf228f5f5); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2a0384); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a670f4a); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7ffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9fff1); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0010004d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00a100f2); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x011a00f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053ff44); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdedfca2); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fbef); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd39ffae); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x02ea0638); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08b50987); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230483); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f960); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45bf180); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1b8f537); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb6102e7); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a110f32); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffdd); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00024); - cx25840_write4(client, DIF_BPF_COEFF89, 0x007c00e5); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013a014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e6fff8); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe98fd0f); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fb67); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc32fe54); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x01880525); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x083909c7); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x091505ee); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7fab3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52df1b4); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf15df484); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9b0249); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x09ba0f19); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 3900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff0); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffcf); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1fff6); - cx25840_write4(client, DIF_BPF_COEFF89, 0x004800be); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x01390184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x016300ac); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff5efdb1); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb23); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb5cfd0d); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x001703e4); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x077b09c4); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d2073c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251fc18); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61cf203); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf118f3dc); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d801aa); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x09600eff); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffefff4); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffc8); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffca); - cx25840_write4(client, DIF_BPF_COEFF89, 0x000b0082); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x01170198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10152); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0030fe7b); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb24); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfac3fbe9); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5027f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0683097f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a560867); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2fd89); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723f26f); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0e8f341); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919010a); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x09060ee5); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fffb); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8ffca); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffa4); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffcd0036); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d70184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f601dc); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ffff60); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb6d); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6efaf5); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd410103); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x055708f9); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e0969); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543ff02); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842f2f5); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cef2b2); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85e006b); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x08aa0ecb); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00050003); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff3ffd3); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaff8b); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ffe5); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0080014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe023f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ba0050); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fbf8); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa62fa3b); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9ff7e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x04010836); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa90a3d); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f007f); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf975f395); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cbf231); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ffcb); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x084c0eaf); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000a); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0000ffe4); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff81); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff96); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x001c00f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70271); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0254013b); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fcbd); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa9ff9c5); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbfdfe); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x028c073b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a750adf); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e101fa); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab8f44e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0ddf1be); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ff2b); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x07ed0e94); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000f); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000efff8); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff87); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff54); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffb5007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01860270); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c00210); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fdb2); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb22f997); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2fc90); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0102060f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a050b4c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902036e); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0af51e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf106f15a); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64efe8b); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x078d0e77); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0019000e); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff9e); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff25); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff560000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112023b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f702c0); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfec8); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbe5f9b3); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947fb41); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xff7004b9); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a0b81); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a0004d8); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd65f603); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf144f104); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aafdec); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x072b0e5a); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00060012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00200022); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ffc1); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ff10); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff09ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x008601d7); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f50340); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fff0); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcddfa19); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa1e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfde30343); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x08790b7f); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50631); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec7f6fc); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf198f0bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50dfd4e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x06c90e3d); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00220030); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffed); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff87ff15); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed6ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffed014c); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b90386); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110119); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfdfefac4); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6f92f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc6701b7); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x07670b44); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0776); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x002df807); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf200f086); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477fcb1); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x06650e1e); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0009); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0038); - cx25840_write4(client, DIF_BPF_COEFF67, 0x003f001b); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffbcff36); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec2feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff5600a5); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0248038d); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00232); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xff39fbab); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4f87f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb060020); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x062a0ad2); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf908a3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0192f922); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf27df05e); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8fc14); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x06000e00); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 4900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0002); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00160037); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00510046); - cx25840_write4(client, DIF_BPF_COEFF89, 0xfff9ff6d); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed0fe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefff0); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01aa0356); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413032b); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x007ffcc5); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cf812); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9cefe87); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c90a2c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4309b4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f3fa4a); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf30ef046); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361fb7a); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x059b0de0); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000a002d); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00570067); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0037ffb5); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfefffe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62ff3d); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ec02e3); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x043503f6); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x01befe05); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa27f7ee); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8c6fcf8); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x034c0954); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0aa4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x044cfb7e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3b1f03f); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2fae1); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x05340dc0); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff4); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfffd001e); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0051007b); - cx25840_write4(client, DIF_BPF_COEFF89, 0x006e0006); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff48fe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfe9a); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x001d023e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130488); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x02e6ff5b); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1ef812); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7f7fb7f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bc084e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430b72); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x059afcba); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf467f046); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cfa4a); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x04cd0da0); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff00009); - cx25840_write4(client, DIF_BPF_COEFF67, 0x003f007f); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00980056); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffa5feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe15); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff4b0170); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b004d7); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x03e800b9); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc48f87f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf768fa23); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022071f); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90c1b); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x06dafdfd); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf52df05e); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef9b5); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x04640d7f); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6fff3); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00250072); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00af009c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x000cff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13fdb8); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe870089); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104e1); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04b8020f); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd98f92f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf71df8f0); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe8805ce); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0c9c); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0808ff44); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf603f086); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af922); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x03fb0d5e); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe0); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00050056); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b000d1); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0071ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53fd8c); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfddfff99); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104a3); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x054a034d); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xff01fa1e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf717f7ed); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf50461); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50cf4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0921008d); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf6e7f0bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff891); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x03920d3b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffffff3); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffd1); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5002f); - cx25840_write4(client, DIF_BPF_COEFF89, 0x009c00ed); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00cb0000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfebafd94); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd61feb0); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d0422); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05970464); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0074fb41); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf759f721); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb7502de); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000d21); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a2201d4); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7d9f104); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf804); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x03280d19); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fffa); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3ffc9); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc90002); - cx25840_write4(client, DIF_BPF_COEFF89, 0x007500ef); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x010e007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3dfdcf); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd16fddd); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440365); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x059b0548); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3fc90); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7dff691); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0f014d); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020d23); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0318); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8d7f15a); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f779); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x02bd0cf6); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00060001); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffecffc9); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffd4); - cx25840_write4(client, DIF_BPF_COEFF89, 0x004000d5); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013600f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd3fe39); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd04fd31); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff360277); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x055605ef); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x033efdfe); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8a5f642); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbffb6); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10cfb); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50456); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9dff1be); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f6f2); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x02520cd2); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080009); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff8ffd2); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffac); - cx25840_write4(client, DIF_BPF_COEFF89, 0x000200a3); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013c014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x006dfec9); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2bfcb7); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe350165); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04cb0651); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477ff7e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9a5f635); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1fe20); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0ca8); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c81058b); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfaf0f231); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f66d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x01e60cae); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 5900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000e); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0005ffe1); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffacff90); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5005f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x01210184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fcff72); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd8afc77); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51003f); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04020669); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830103); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfad7f66b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8fc93); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430c2b); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d06b5); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfc08f2b2); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af5ec); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x017b0c89); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0012fff5); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaff82); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff8e000f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e80198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750028); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe18fc75); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99ff15); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x03050636); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0656027f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc32f6e2); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614fb17); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20b87); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d7707d2); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfd26f341); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf56f); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x010f0c64); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00050012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001c000b); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff84); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ffbe); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00960184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd00da); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeccfcb2); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fdf9); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x01e005bc); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e703e4); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfdabf798); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f9b3); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510abd); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf08df); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfe48f3dc); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f4f6); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x00a20c3e); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0002000f); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0021001f); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff97); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff74); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0034014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa0179); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff97fd2a); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fcfa); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x00a304fe); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310525); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xff37f886); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf86e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c709d0); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de209db); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xff6df484); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf481); - cx25840_write4(client, DIF_BPF_COEFF3435, 0x00360c18); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe000a); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0021002f); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ffb8); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff3b); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffcc00f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa01fa); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0069fdd4); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fc26); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xff5d0407); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310638); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x00c9f9a8); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf74e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xff3908c3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de20ac3); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0093f537); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf410); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xffca0bf2); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb0003); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001c0037); - cx25840_write4(client, DIF_BPF_COEFF67, 0x002fffe2); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ff17); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff6a007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd0251); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0134fea5); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb8b); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe2002e0); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e70713); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0255faf5); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f658); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0799); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf0b96); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x01b8f5f5); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f3a3); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xff5e0bca); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00120037); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00460010); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff8eff0f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff180000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750276); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01e8ff8d); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb31); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcfb0198); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x065607ad); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x03cefc64); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614f592); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0656); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d770c52); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x02daf6bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf33b); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfef10ba3); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff5); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0005002f); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0054003c); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5ff22); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedfff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fc0267); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0276007e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb1c); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbfe003e); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830802); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0529fdec); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8f4fe); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd04ff); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d0cf6); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x03f8f78f); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af2d7); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe850b7b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff80020); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00560060); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0002ff4e); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec4ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x006d0225); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02d50166); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb4e); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb35fee1); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477080e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x065bff82); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1f4a0); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610397); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c810d80); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0510f869); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f278); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe1a0b52); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffaffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffec000c); - cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0078); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0040ff8e); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecafeb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd301b6); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fc0235); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fbc5); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaaafd90); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x033e07d2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x075b011b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbf47a); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f0224); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50def); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0621f94b); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f21e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfdae0b29); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 6900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3fff6); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0037007f); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0075ffdc); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef2fe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3d0122); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02ea02dd); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fc79); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa65fc5d); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3074e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x082102ad); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0ff48c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe00a9); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0e43); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0729fa33); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f1c9); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfd430b00); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0001fff3); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe2); - cx25840_write4(client, DIF_BPF_COEFF67, 0x001b0076); - cx25840_write4(client, DIF_BPF_COEFF89, 0x009c002d); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff35fe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfeba0076); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x029f0352); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfd60); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa69fb53); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x00740688); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08a7042d); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb75f4d6); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600ff2d); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a220e7a); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0827fb22); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf17a); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfcd80ad6); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff9); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffd2); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb005e); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b0007a); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8ffe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53ffc1); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0221038c); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fe6e); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfab6fa80); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xff010587); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e90590); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf5f556); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfdb3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x09210e95); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0919fc15); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff12f); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc6e0aab); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00070000); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6ffc9); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0039); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00af00b8); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfff4feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13ff10); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01790388); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311ff92); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb48f9ed); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd980453); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e306cd); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe88f60a); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fc40); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x08080e93); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x09fdfd0c); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af0ea); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc050a81); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080008); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff0ffc9); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1000d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x009800e2); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x005bff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe74); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00b50345); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000bc); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc18f9a1); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc4802f9); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x089807dc); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022f6f0); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fada); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x06da0e74); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ad3fe06); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef0ab); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb9c0a55); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000e); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfffdffd0); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffdf); - cx25840_write4(client, DIF_BPF_COEFF89, 0x006e00f2); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00b8ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfdf8); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xffe302c8); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x041301dc); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd1af99e); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1e0183); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x080908b5); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bcf801); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf985); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x059a0e38); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b99ff03); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cf071); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb330a2a); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00070011); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000affdf); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffa9ffb5); - cx25840_write4(client, DIF_BPF_COEFF89, 0x003700e6); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x01010000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62fda8); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff140219); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x043502e1); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe42f9e6); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa270000); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x073a0953); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x034cf939); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a4f845); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x044c0de1); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c4f0000); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2f03c); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfacc09fe); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00040012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0016fff3); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffafff95); - cx25840_write4(client, DIF_BPF_COEFF89, 0xfff900c0); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0130007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefd89); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe560146); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x041303bc); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xff81fa76); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cfe7d); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x063209b1); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c9fa93); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf71e); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f30d6e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cf200fd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361f00e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa6509d1); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00010010); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0008); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ff84); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffbc0084); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013e00f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff56fd9f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdb8005c); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00460); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x00c7fb45); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4fd07); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x04fa09ce); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x062afc07); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407f614); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x01920ce0); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d8301fa); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8efe5); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa0009a4); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd000b); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001d); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff82); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff870039); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x012a014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffedfde7); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd47ff6b); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104c6); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0202fc4c); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6fbad); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x039909a7); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0767fd8e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482f52b); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x002d0c39); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e0002f4); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477efc2); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf99b0977); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 7900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa0004); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0020002d); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff91); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ffe8); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f70184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0086fe5c); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0bfe85); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104e5); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0323fd7d); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa79); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x021d093f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0879ff22); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bf465); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec70b79); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e6803eb); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50defa5); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf937094a); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffd); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00190036); - cx25840_write4(client, DIF_BPF_COEFF67, 0x001bffaf); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff99); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00aa0198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112fef3); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd09fdb9); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04be); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x041bfecc); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947f978); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x00900897); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a00b9); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f3c5); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd650aa3); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ebc04de); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aaef8e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf8d5091c); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff6); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000e0038); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ffd7); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff56); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x004b0184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0186ffa1); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd40fd16); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440452); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04de0029); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2f8b2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfefe07b5); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a05024d); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef34d); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0a09b8); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0efa05cd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64eef7d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf87308ed); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00000031); - cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0005); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff27); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffe4014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70057); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdacfca6); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3603a7); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05610184); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbf82e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd74069f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a7503d6); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff2ff); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab808b9); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f2306b5); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ef72); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf81308bf); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff30022); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00560032); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ff10); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8000f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe0106); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe46fc71); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3502c7); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x059e02ce); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9f7f2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfbff055b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa9054c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f2db); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf97507aa); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f350797); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ef6d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7b40890); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8000f); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00540058); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffcdff14); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff29007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f6019e); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff01fc7c); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5101bf); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x059203f6); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd41f7fe); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfaa903f3); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e06a9); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf2e2); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842068b); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f320871); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85eef6e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7560860); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fff2); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1fff9); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00460073); - cx25840_write4(client, DIF_BPF_COEFF89, 0x000bff34); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee90000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10215); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xffd0fcc5); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99009d); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x053d04f1); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5f853); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf97d0270); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a5607e4); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef314); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723055f); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f180943); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919ef75); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6fa0830); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff8); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe4); - cx25840_write4(client, DIF_BPF_COEFF67, 0x002f007f); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0048ff6b); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec7ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0163025f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00a2fd47); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff73); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04a405b2); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0017f8ed); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf88500dc); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d208f9); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff370); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61c0429); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ee80a0b); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d8ef82); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6a00800); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0007ffff); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffd4); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0010007a); - cx25840_write4(client, DIF_BPF_COEFF89, 0x007cffb2); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec6ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e60277); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0168fdf9); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fe50); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x03ce0631); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0188f9c8); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7c7ff43); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x091509e3); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f3f6); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52d02ea); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ea30ac9); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9bef95); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf64607d0); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00090007); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9ffca); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00065); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00a10003); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee6feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053025b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0213fed0); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fd46); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x02c70668); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x02eafadb); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf74bfdae); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230a9c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f4a3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45b01a6); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e480b7c); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb61efae); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf5ef079f); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 8900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000d); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff5ffc8); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10043); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b20053); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff24fe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9020c); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0295ffbb); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fc64); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x019b0654); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x042dfc1c); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf714fc2a); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020b21); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f575); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7005e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0dd80c24); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2aefcd); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf599076e); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00060011); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0002ffcf); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffba0018); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad009a); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff79fe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff260192); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e500ab); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fbb6); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x005b05f7); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545fd81); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf723fabf); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80b70); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f669); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313ff15); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d550cbf); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6eff2); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544073d); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00030012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000fffdd); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffea); - cx25840_write4(client, DIF_BPF_COEFF89, 0x009300cf); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdcfe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea600f7); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fd0190); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb46); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xff150554); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0627fefd); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf778f978); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x044d0b87); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f77d); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0fdcf); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbe0d4e); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc4f01d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2070b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00000010); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001afff0); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffbf); - cx25840_write4(client, DIF_BPF_COEFF89, 0x006700ed); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe460047); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02db0258); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb1b); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddc0473); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c90082); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf811f85e); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c90b66); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff8ad); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250fc8d); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c140dcf); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe93f04d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a106d9); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc000c); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00200006); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff9c); - cx25840_write4(client, DIF_BPF_COEFF89, 0x002f00ef); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a4ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dff92); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x028102f7); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb37); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbf035e); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x07260202); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e8f778); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x01340b0d); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f9f4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223fb51); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b590e42); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xff64f083); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf45206a7); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90005); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001a); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff86); - cx25840_write4(client, DIF_BPF_COEFF89, 0xfff000d7); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fee5); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f60362); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb99); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbcc0222); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x07380370); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f7f6cc); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xff990a7e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902fb50); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21afa1f); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8d0ea6); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034f0bf); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4050675); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffe); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001e002b); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff81); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffb400a5); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe50); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01460390); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfc3a); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb1000ce); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x070104bf); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb37f65f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe0009bc); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00fcbb); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f8f8); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b20efc); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105f101); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3ba0642); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff7); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00150036); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff8c); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff810061); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013d007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe71fddf); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x007c0380); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fd13); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa94ff70); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x068005e2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9bf633); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc7308ca); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5fe30); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf274f7e0); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c90f43); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d4f147); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371060f); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fff1); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00090038); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffa7); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff5e0012); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013200f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee3fd9b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaa0331); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fe15); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa60fe18); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bd06d1); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1bf64a); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafa07ae); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7effab); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d5f6d7); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d30f7a); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a3f194); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf32905dc); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfffb0032); - cx25840_write4(client, DIF_BPF_COEFF67, 0x003fffcd); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effc1); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6efd8a); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfedd02aa); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0ff34); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa74fcd7); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bf0781); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaaf6a3); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99e066b); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90128); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf359f5e1); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d20fa2); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0370f1e5); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e405a8); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 9900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffef0024); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0051fffa); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff54ff77); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00be0184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0006fdad); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe2701f3); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413005e); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad1fbba); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x039007ee); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x013bf73d); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868050a); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4302a1); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fdf4fe); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c70fba); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x043bf23c); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a10575); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fff1); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe50011); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00570027); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff70ff3c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00620198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x009efe01); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95011a); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350183); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb71fad0); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x023c0812); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c3f811); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75e0390); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0411); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c1f432); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b30fc1); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0503f297); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2610541); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0006fff7); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdffffc); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00510050); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff9dff18); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffc0184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0128fe80); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32002e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130292); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4dfa21); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d107ee); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0435f91c); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6850205); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430573); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a1f37d); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x03990fba); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c7f2f8); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222050d); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffe); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdfffe7); - cx25840_write4(client, DIF_BPF_COEFF67, 0x003f006e); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffd6ff0f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0197ff1f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd05ff3e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0037c); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd59f9b7); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5d0781); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0585fa56); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4006f); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf906c4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69df2e0); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x02790fa2); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0688f35d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e604d8); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00090005); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4ffd6); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0025007e); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0014ff20); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3c00f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e1ffd0); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd12fe5c); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110433); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88f996); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf106d1); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aafbb7); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57efed8); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e07ff); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b0f25e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x01560f7a); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0745f3c7); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1ac04a4); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000c); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffedffcb); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0005007d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0050ff4c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ff0086); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd58fd97); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104ad); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xffcaf9c0); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc9905e2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x079afd35); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf555fd46); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50920); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d9f1f6); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x00310f43); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fdf435); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174046f); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00050011); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfffaffc8); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5006b); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0082ff8c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f00130); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd2fcfc); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04e3); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x010efa32); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb6404bf); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x084efec5); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569fbc2); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000a23); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa15f1ab); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0b0efc); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b0f4a7); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13f043a); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00020012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0007ffcd); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9004c); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00a4ffd9); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b401c1); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe76fc97); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404d2); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0245fae8); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5f0370); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1005f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bcfa52); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020b04); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb60f17b); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde70ea6); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x095df51e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10c0405); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0011); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0014ffdb); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40023); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2002a); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedbff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150022d); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff38fc6f); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36047b); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x035efbda); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9940202); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ee01f5); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf649f8fe); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10bc2); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb6f169); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc60e42); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a04f599); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0db03d0); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb000d); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001dffed); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaafff5); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00aa0077); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00ce026b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x000afc85); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3503e3); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x044cfcfb); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90c0082); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5037f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf710f7cc); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0c59); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe16f173); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaa0dcf); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa5f617); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0ad039b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 10900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90006); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00210003); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffc8); - cx25840_write4(client, DIF_BPF_COEFF89, 0x008e00b6); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff63fe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x003a0275); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00dafcda); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd510313); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0501fe40); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cbfefd); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x087604f0); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80af6c2); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430cc8); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7af19a); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa940d4e); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3ff699); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0810365); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffff); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00210018); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffa3); - cx25840_write4(client, DIF_BPF_COEFF89, 0x006000e1); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc4fe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0024b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x019afd66); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc990216); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0575ff99); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4fd81); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d40640); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf932f5e6); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20d0d); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x00dff1de); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9860cbf); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd1f71e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058032f); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff8); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001b0029); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff8a); - cx25840_write4(client, DIF_BPF_COEFF89, 0x002600f2); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x002cfe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0f01f0); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x023bfe20); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc1700fa); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a200f7); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf927fc1c); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f40765); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa82f53b); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510d27); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0243f23d); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8810c24); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5cf7a7); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf03102fa); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00110035); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff81); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffe700e7); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x008ffeb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94016d); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b0fefb); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3ffd1); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05850249); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c1fadb); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x05de0858); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf2f4c4); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c70d17); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a0f2b8); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7870b7c); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdff833); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00d02c4); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00040038); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ff88); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffac00c2); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e2ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe3900cb); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f1ffe9); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3feaa); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05210381); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9cf9c8); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x04990912); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7af484); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xff390cdb); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f4f34d); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69a0ac9); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5af8c1); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xefec028e); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0000ffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff60033); - cx25840_write4(client, DIF_BPF_COEFF67, 0x002fff9f); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff7b0087); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x011eff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe080018); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f900d8); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fd96); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x04790490); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbadf8ed); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x032f098e); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xff10f47d); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0c75); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x063cf3fc); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5ba0a0b); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dccf952); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcd0258); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff1); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffea0026); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0046ffc3); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff5a003c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04ff63); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c801b8); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fca6); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397056a); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcecf853); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x01ad09c9); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x00acf4ad); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0be7); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0773f4c2); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e90943); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35f9e6); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb10221); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff6); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe20014); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0054ffee); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effeb); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2efebb); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260027a); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fbe6); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x02870605); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4af7fe); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x001d09c1); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0243f515); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd0b32); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0897f59e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4280871); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e95fa7c); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef9701eb); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffd); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffff); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0056001d); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff57ff9c); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x011300f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe82fe2e); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ca0310); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb62); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155065a); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xffbaf7f2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8c0977); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x03cef5b2); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610a58); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a5f68f); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3790797); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eebfb14); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef8001b5); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080004); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe9); - cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0047); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff75ff58); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef9fdc8); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111036f); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb21); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x00120665); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x012df82e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd0708ec); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542f682); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f095c); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9af792); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2db06b5); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f38fbad); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6c017e); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 11900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000b); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe7ffd8); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00370068); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffa4ff28); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00790184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87fd91); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00430392); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb26); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfece0626); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294f8b2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb990825); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0698f77f); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe0842); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b73f8a7); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf25105cd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7bfc48); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5a0148); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00050010); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff2ffcc); - cx25840_write4(client, DIF_BPF_COEFF67, 0x001b007b); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffdfff10); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00140198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0020fd8e); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff710375); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb73); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9a059f); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e0f978); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4e0726); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c8f8a7); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600070c); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2ff9c9); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1db04de); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4fce5); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4b0111); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00010012); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffffffc8); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb007e); - cx25840_write4(client, DIF_BPF_COEFF89, 0x001dff14); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffad0184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b7fdbe); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9031b); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fc01); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc8504d6); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0504fa79); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf93005f6); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x08caf9f2); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52b05c0); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccbfaf9); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf17903eb); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3fd83); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3f00db); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe0011); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000cffcc); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0071); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0058ff32); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4f014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x013cfe1f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfb028a); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fcc9); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9d03d6); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f4fbad); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848049d); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0999fb5b); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf4820461); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d46fc32); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12d02f4); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x1007fe21); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3600a4); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0017ffd9); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc10055); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0088ff68); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0400f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a6fea7); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7501cc); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fdc0); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaef02a8); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a7fd07); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79d0326); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a31fcda); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf40702f3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9ffd72); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f601fa); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x1021fec0); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2f006d); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80007); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001fffeb); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaf002d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00a8ffb0); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e9ff4c); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2000ee); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fed8); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82015c); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0715fe7d); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7340198); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8dfe69); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bd017c); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd5feb8); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d500fd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x1031ff60); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2b0037); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff70000); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00220000); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffa90000); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b30000); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec20000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x02000000); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd030000); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350000); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa5e0000); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x073b0000); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7110000); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aac0000); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a40000); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de70000); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0c90000); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x10360000); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef290000); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff9); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001f0015); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffd3); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00a80050); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e900b4); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd20ff12); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130128); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82fea4); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x07150183); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf734fe68); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8d0197); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdfe84); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd50148); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d5ff03); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x103100a0); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2bffc9); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00170027); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ffab); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00880098); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff04ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a60159); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd75fe34); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00240); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaeffd58); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a702f9); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79dfcda); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a310326); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fd0d); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9f028e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f6fe06); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x10210140); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2fff93); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000c0034); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff8f); - cx25840_write4(client, DIF_BPF_COEFF89, 0x005800ce); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4ffeb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x013c01e1); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfbfd76); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110337); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9dfc2a); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f40453); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848fb63); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x099904a5); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fb9f); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d4603ce); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12dfd0c); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x100701df); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef36ff5c); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 12900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0001ffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffff0038); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff82); - cx25840_write4(client, DIF_BPF_COEFF89, 0x001d00ec); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffadfe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b70242); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9fce5); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x024103ff); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc85fb2a); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05040587); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf930fa0a); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x08ca060e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfa40); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccb0507); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf179fc15); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3027d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3fff25); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff0); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff20034); - cx25840_write4(client, DIF_BPF_COEFF67, 0x001bff85); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffdf00f0); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0014fe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00200272); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff71fc8b); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d048d); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9afa61); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e00688); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4ef8da); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c80759); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f8f4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2f0637); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1dbfb22); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4031b); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4bfeef); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff5); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe70028); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ff98); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffa400d8); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0079fe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87026f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0043fc6e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404da); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfecef9da); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294074e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb99f7db); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x06980881); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef7be); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b730759); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf251fa33); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7b03b8); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5afeb8); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffc); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe00017); - cx25840_write4(client, DIF_BPF_COEFF67, 0x004cffb9); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff7500a8); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef90238); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111fc91); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604df); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0012f99b); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x012d07d2); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd07f714); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542097e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff6a4); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9a086e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2dbf94b); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f380453); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6cfe82); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080003); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffde0001); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0056ffe3); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff570064); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0113ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe8201d2); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01cafcf0); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35049e); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155f9a6); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xffba080e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8cf689); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x03ce0a4e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f5a8); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a50971); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf379f869); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eeb04ec); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef80fe4b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000a); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe2ffec); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00540012); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e0015); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2e0145); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260fd86); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51041a); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0287f9fb); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4a0802); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x001df63f); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x02430aeb); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf4ce); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x08970a62); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf428f78f); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e950584); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xef97fe15); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000f); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffeaffda); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0046003d); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff5affc4); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04009d); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c8fe48); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99035a); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397fa96); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcec07ad); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x01adf637); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x00ac0b53); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef419); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x07730b3e); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e9f6bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35061a); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb1fddf); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00000012); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfff6ffcd); - cx25840_write4(client, DIF_BPF_COEFF67, 0x002f0061); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff7bff79); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x011e007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe08ffe8); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f9ff28); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17026a); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0479fb70); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbad0713); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x032ff672); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xff100b83); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff38b); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x063c0c04); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5baf5f5); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dcc06ae); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcdfda8); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0012); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0004ffc8); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00100078); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffacff3e); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e200f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe39ff35); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f10017); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd30156); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0521fc7f); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9c0638); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0499f6ee); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7a0b7c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f325); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f40cb3); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69af537); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5a073f); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xefecfd72); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0011ffcb); - cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0007f); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffe7ff19); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x008f014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94fe93); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b00105); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3002f); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x0585fdb7); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c10525); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x05def7a8); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf20b3c); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f2e9); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a00d48); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf787f484); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdf07cd); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00dfd3c); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 13900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80008); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001bffd7); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10076); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0026ff0e); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x002c0184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0ffe10); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x023b01e0); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff06); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a2ff09); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf92703e4); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f4f89b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa820ac5); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f2d9); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x02430dc3); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf881f3dc); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5c0859); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf031fd06); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80001); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0021ffe8); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffba005d); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0060ff1f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc40198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0fdb5); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x019a029a); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fdea); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x05750067); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4027f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d4f9c0); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf9320a1a); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f2f3); - cx25840_write4(client, DIF_BPF_COEFF2829, 0x00df0e22); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xf986f341); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd108e2); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058fcd1); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0021fffd); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0038); - cx25840_write4(client, DIF_BPF_COEFF89, 0x008eff4a); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff630184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x003afd8b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x00da0326); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fced); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x050101c0); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cb0103); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x0876fb10); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80a093e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f338); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7a0e66); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa94f2b2); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3f0967); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf081fc9b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff3); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001d0013); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa000b); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00aaff89); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00cefd95); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x000a037b); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fc1d); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x044c0305); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90cff7e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5fc81); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7100834); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff3a7); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe160e8d); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaaf231); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa509e9); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0adfc65); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00140025); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffdd); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2ffd6); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedb00f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150fdd3); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xff380391); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb85); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x035e0426); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xf994fdfe); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08eefe0b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6490702); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f43e); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb60e97); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc6f1be); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a040a67); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0dbfc30); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0002ffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00070033); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ffb4); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00a40027); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b4fe3f); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe760369); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb2e); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x02450518); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5ffc90); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1ffa1); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bc05ae); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902f4fc); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb600e85); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde7f15a); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x095d0ae2); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10cfbfb); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0005ffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfffa0038); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff95); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00820074); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f0fed0); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd20304); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb1d); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x010e05ce); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb64fb41); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x084e013b); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569043e); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00f5dd); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa150e55); - cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0bf104); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b00b59); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13ffbc6); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fff4); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffed0035); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff83); - cx25840_write4(client, DIF_BPF_COEFF89, 0x005000b4); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6ff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ffff7a); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd580269); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fb53); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xffca0640); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc99fa1e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x079a02cb); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55502ba); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5f6e0); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d90e0a); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0031f0bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fd0bcb); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174fb91); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0009fffb); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4002a); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ff82); - cx25840_write4(client, DIF_BPF_COEFF89, 0x001400e0); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3cff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e10030); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1201a4); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fbcd); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88066a); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf1f92f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aa0449); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57e0128); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7ef801); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b00da2); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0156f086); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x07450c39); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1acfb5c); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00080002); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0019); - cx25840_write4(client, DIF_BPF_COEFF67, 0x003fff92); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffd600f1); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x019700e1); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0500c2); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fc84); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd590649); - cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5df87f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x058505aa); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4ff91); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9f93c); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69d0d20); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0279f05e); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x06880ca3); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e6fb28); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 14900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x00060009); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0004); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0051ffb0); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff9d00e8); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffcfe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x01280180); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32ffd2); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fd6e); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4d05df); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d1f812); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x043506e4); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf685fdfb); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fa8d); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a10c83); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0399f046); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c70d08); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222faf3); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffe5ffef); - cx25840_write4(client, DIF_BPF_COEFF67, 0x0057ffd9); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff7000c4); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0062fe68); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x009e01ff); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95fee6); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0435fe7d); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb710530); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x023cf7ee); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c307ef); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75efc70); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5cfbef); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c10bce); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b3f03f); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x05030d69); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf261fabf); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15100000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); - cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0012); - cx25840_write4(client, DIF_BPF_COEFF45, 0xffefffdc); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00510006); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff540089); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00befe7c); - cx25840_write4(client, DIF_BPF_COEFF1213, 0x00060253); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe27fe0d); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413ffa2); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad10446); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0390f812); - cx25840_write4(client, DIF_BPF_COEFF2223, 0x013b08c3); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868faf6); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fd5f); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fd0b02); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c7f046); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x043b0dc4); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a1fa8b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15200000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0012); - cx25840_write4(client, DIF_BPF_COEFF45, 0xfffbffce); - cx25840_write4(client, DIF_BPF_COEFF67, 0x003f0033); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e003f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106feb6); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6e0276); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeddfd56); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000cc); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa740329); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bff87f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaa095d); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99ef995); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9fed8); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3590a1f); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d2f05e); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x03700e1b); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e4fa58); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15300000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9000f); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0009ffc8); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00250059); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff5effee); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0132ff10); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee30265); - cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaafccf); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x031101eb); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6001e8); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bdf92f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1b09b6); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafaf852); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0055); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d50929); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d3f086); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a30e6c); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf329fa24); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15400000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80009); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0015ffca); - cx25840_write4(client, DIF_BPF_COEFF67, 0x00050074); - cx25840_write4(client, DIF_BPF_COEFF89, 0xff81ff9f); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x013dff82); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe710221); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x007cfc80); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x024102ed); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa940090); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0680fa1e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9b09cd); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc73f736); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad501d0); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2740820); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c9f0bd); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d40eb9); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371f9f1); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15500000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80002); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001effd5); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5007f); - cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff5b); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2401b0); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0146fc70); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d03c6); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb10ff32); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0701fb41); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb3709a1); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f644); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000345); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2350708); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b2f104); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x01050eff); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3baf9be); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15600000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0022ffe6); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9007a); - cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff29); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2007e); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01011b); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f6fc9e); - cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440467); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbccfdde); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738fc90); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f70934); - cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99f582); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x090204b0); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21a05e1); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8df15a); - cx25840_write4(client, DIF_BPF_COEFF3233, 0x00340f41); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf405f98b); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15700000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcfff4); - cx25840_write4(client, DIF_BPF_COEFF45, 0x0020fffa); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40064); - cx25840_write4(client, DIF_BPF_COEFF89, 0x002fff11); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a400f0); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0d006e); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x0281fd09); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604c9); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbffca2); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0726fdfe); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e80888); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134f4f3); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1060c); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf22304af); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b59f1be); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xff640f7d); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf452f959); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15800000: - cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0000fff0); - cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0010); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa0041); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0067ff13); - cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043014a); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46ffb9); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02dbfda8); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3504e5); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddcfb8d); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9ff7e); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf81107a2); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9f49a); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0753); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2500373); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c14f231); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930fb3); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a1f927); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 15900000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0003ffee); - cx25840_write4(client, DIF_BPF_COEFF45, 0x000f0023); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0016); - cx25840_write4(client, DIF_BPF_COEFF89, 0x0093ff31); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdc0184); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6ff09); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fdfe70); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5104ba); - cx25840_write4(client, DIF_BPF_COEFF1819, 0xff15faac); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270103); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7780688); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x044df479); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430883); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a00231); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbef2b2); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc40fe3); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2f8f5); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - - case 16000000: - cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); - cx25840_write4(client, DIF_BPF_COEFF23, 0x0006ffef); - cx25840_write4(client, DIF_BPF_COEFF45, 0x00020031); - cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffe8); - cx25840_write4(client, DIF_BPF_COEFF89, 0x00adff66); - cx25840_write4(client, DIF_BPF_COEFF1011, 0xff790198); - cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe6e); - cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e5ff55); - cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99044a); - cx25840_write4(client, DIF_BPF_COEFF1819, 0x005bfa09); - cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545027f); - cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7230541); - cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b8f490); - cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20997); - cx25840_write4(client, DIF_BPF_COEFF2829, 0xf31300eb); - cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d55f341); - cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6100e); - cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544f8c3); - cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); - break; - } + coeffs = ifhz_coeffs[(ifHz - 3000000) / 100000]; + cx25840_write4(client, DIF_BPF_COEFF01, coeffs[0]); + cx25840_write4(client, DIF_BPF_COEFF23, coeffs[1]); + cx25840_write4(client, DIF_BPF_COEFF45, coeffs[2]); + cx25840_write4(client, DIF_BPF_COEFF67, coeffs[3]); + cx25840_write4(client, DIF_BPF_COEFF89, coeffs[4]); + cx25840_write4(client, DIF_BPF_COEFF1011, coeffs[5]); + cx25840_write4(client, DIF_BPF_COEFF1213, coeffs[6]); + cx25840_write4(client, DIF_BPF_COEFF1415, coeffs[7]); + cx25840_write4(client, DIF_BPF_COEFF1617, coeffs[8]); + cx25840_write4(client, DIF_BPF_COEFF1819, coeffs[9]); + cx25840_write4(client, DIF_BPF_COEFF2021, coeffs[10]); + cx25840_write4(client, DIF_BPF_COEFF2223, coeffs[11]); + cx25840_write4(client, DIF_BPF_COEFF2425, coeffs[12]); + cx25840_write4(client, DIF_BPF_COEFF2627, coeffs[13]); + cx25840_write4(client, DIF_BPF_COEFF2829, coeffs[14]); + cx25840_write4(client, DIF_BPF_COEFF3031, coeffs[15]); + cx25840_write4(client, DIF_BPF_COEFF3233, coeffs[16]); + cx25840_write4(client, DIF_BPF_COEFF3435, coeffs[17]); + cx25840_write4(client, DIF_BPF_COEFF36, coeffs[18]); } static void cx23888_std_setup(struct i2c_client *client) diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c index 4bfa3b3cf6..8e9ebed09f 100644 --- a/drivers/media/i2c/ds90ub913.c +++ b/drivers/media/i2c/ds90ub913.c @@ -362,8 +362,6 @@ static int ub913_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, if (ret) return ret; - memset(fd, 0, sizeof(*fd)); - fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL; state = v4l2_subdev_lock_and_get_active_state(sd); diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index dc394e22a4..6440223128 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -499,8 +499,6 @@ static int ub953_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, if (ret) return ret; - memset(fd, 0, sizeof(*fd)); - fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; state = v4l2_subdev_lock_and_get_active_state(sd); diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index 8ba5750f5a..b8f3e5ca03 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -2786,8 +2786,6 @@ static int ub960_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, if (!ub960_pad_is_source(priv, pad)) return -EINVAL; - memset(fd, 0, sizeof(*fd)); - fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; state = v4l2_subdev_lock_and_get_active_state(&priv->sd); diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index fd56ba1387..f6ea9b7b97 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -477,6 +477,50 @@ static const struct hi556_reg mode_1296x972_regs[] = { {0x0958, 0xbb80}, }; +static const struct hi556_reg mode_1296x722_regs[] = { + {0x0a00, 0x0000}, + {0x0b0a, 0x8259}, + {0x0f30, 0x5b15}, + {0x0f32, 0x7167}, + {0x004a, 0x0100}, + {0x004c, 0x0000}, + {0x004e, 0x0100}, + {0x000c, 0x0122}, + {0x0008, 0x0b00}, + {0x005a, 0x0404}, + {0x0012, 0x000c}, + {0x0018, 0x0a33}, + {0x0022, 0x0008}, + {0x0028, 0x0017}, + {0x0024, 0x0022}, + {0x002a, 0x002b}, + {0x0026, 0x012a}, + {0x002c, 0x06cf}, + {0x002e, 0x3311}, + {0x0030, 0x3311}, + {0x0032, 0x3311}, + {0x0006, 0x0814}, + {0x0a22, 0x0000}, + {0x0a12, 0x0510}, + {0x0a14, 0x02d2}, + {0x003e, 0x0000}, + {0x0074, 0x0812}, + {0x0070, 0x0409}, + {0x0804, 0x0308}, + {0x0806, 0x0100}, + {0x0a04, 0x016a}, + {0x090c, 0x09c0}, + {0x090e, 0x0010}, + {0x0902, 0x4319}, + {0x0914, 0xc106}, + {0x0916, 0x040e}, + {0x0918, 0x0304}, + {0x091a, 0x0708}, + {0x091c, 0x0e06}, + {0x091e, 0x0300}, + {0x0958, 0xbb80}, +}; + static const char * const hi556_test_pattern_menu[] = { "Disabled", "Solid Colour", @@ -556,7 +600,25 @@ static const struct hi556_mode supported_modes[] = { .regs = mode_1296x972_regs, }, .link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX, - } + }, + { + .width = 1296, + .height = 722, + .crop = { + .left = HI556_PIXEL_ARRAY_LEFT, + .top = 250, + .width = HI556_PIXEL_ARRAY_WIDTH, + .height = 1444 + }, + .fll_def = HI556_FLL_30FPS, + .fll_min = HI556_FLL_30FPS_MIN, + .llp = 0x0b00, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1296x722_regs), + .regs = mode_1296x722_regs, + }, + .link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX, + }, }; struct hi556 { @@ -577,9 +639,6 @@ struct hi556 { /* To serialize asynchronus callbacks */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - /* True if the device has been identified */ bool identified; }; @@ -976,9 +1035,6 @@ static int hi556_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (hi556->streaming == enable) - return 0; - mutex_lock(&hi556->mutex); if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -998,47 +1054,8 @@ static int hi556_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - hi556->streaming = enable; - mutex_unlock(&hi556->mutex); - - return ret; -} - -static int __maybe_unused hi556_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct hi556 *hi556 = to_hi556(sd); - - mutex_lock(&hi556->mutex); - if (hi556->streaming) - hi556_stop_streaming(hi556); - - mutex_unlock(&hi556->mutex); - - return 0; -} - -static int __maybe_unused hi556_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct hi556 *hi556 = to_hi556(sd); - int ret; - - mutex_lock(&hi556->mutex); - if (hi556->streaming) { - ret = hi556_start_streaming(hi556); - if (ret) - goto error; - } - mutex_unlock(&hi556->mutex); - return 0; - -error: - hi556_stop_streaming(hi556); - hi556->streaming = 0; - mutex_unlock(&hi556->mutex); return ret; } @@ -1331,10 +1348,6 @@ probe_error_v4l2_ctrl_handler_free: return ret; } -static const struct dev_pm_ops hi556_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(hi556_suspend, hi556_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id hi556_acpi_ids[] = { {"INT3537"}, @@ -1347,7 +1360,6 @@ MODULE_DEVICE_TABLE(acpi, hi556_acpi_ids); static struct i2c_driver hi556_i2c_driver = { .driver = { .name = "hi556", - .pm = &hi556_pm_ops, .acpi_match_table = ACPI_PTR(hi556_acpi_ids), }, .probe = hi556_probe, diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c index fa0038749a..825fc8dc48 100644 --- a/drivers/media/i2c/hi846.c +++ b/drivers/media/i2c/hi846.c @@ -1607,17 +1607,12 @@ static int hi846_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (hi846->streaming == enable) - return 0; - mutex_lock(&hi846->mutex); if (enable) { - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_noidle(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) goto out; - } ret = hi846_start_streaming(hi846); } @@ -1680,9 +1675,6 @@ static int __maybe_unused hi846_suspend(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct hi846 *hi846 = to_hi846(sd); - if (hi846->streaming) - hi846_stop_streaming(hi846); - return hi846_power_off(hi846); } @@ -1691,26 +1683,8 @@ static int __maybe_unused hi846_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); struct hi846 *hi846 = to_hi846(sd); - int ret; - - ret = hi846_power_on(hi846); - if (ret) - return ret; - if (hi846->streaming) { - ret = hi846_start_streaming(hi846); - if (ret) { - dev_err(dev, "%s: start streaming failed: %d\n", - __func__, ret); - goto error; - } - } - - return 0; - -error: - hi846_power_off(hi846); - return ret; + return hi846_power_on(hi846); } static int hi846_set_format(struct v4l2_subdev *sd, @@ -2173,8 +2147,6 @@ static void hi846_remove(struct i2c_client *client) } static const struct dev_pm_ops hi846_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) SET_RUNTIME_PM_OPS(hi846_suspend, hi846_resume, NULL) }; diff --git a/drivers/media/i2c/hi847.c b/drivers/media/i2c/hi847.c index 32547d7a26..4075c38980 100644 --- a/drivers/media/i2c/hi847.c +++ b/drivers/media/i2c/hi847.c @@ -2184,9 +2184,6 @@ struct hi847 { /* To serialize asynchronus callbacks */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; static u64 to_pixel_rate(u32 f_index) @@ -2618,14 +2615,10 @@ static int hi847_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (hi847->streaming == enable) - return 0; - mutex_lock(&hi847->mutex); if (enable) { - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_noidle(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) { mutex_unlock(&hi847->mutex); return ret; } @@ -2641,49 +2634,8 @@ static int hi847_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - hi847->streaming = enable; - mutex_unlock(&hi847->mutex); - - return ret; -} - -static int __maybe_unused hi847_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct hi847 *hi847 = to_hi847(sd); - - mutex_lock(&hi847->mutex); - if (hi847->streaming) - hi847_stop_streaming(hi847); - - mutex_unlock(&hi847->mutex); - - return 0; -} - -static int __maybe_unused hi847_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct hi847 *hi847 = to_hi847(sd); - int ret; - - mutex_lock(&hi847->mutex); - if (hi847->streaming) { - ret = hi847_start_streaming(hi847); - if (ret) - goto error; - } - mutex_unlock(&hi847->mutex); - return 0; - -error: - hi847_stop_streaming(hi847); - hi847->streaming = 0; - mutex_unlock(&hi847->mutex); return ret; } @@ -2980,10 +2932,6 @@ probe_error_v4l2_ctrl_handler_free: return ret; } -static const struct dev_pm_ops hi847_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(hi847_suspend, hi847_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id hi847_acpi_ids[] = { {"HYV0847"}, @@ -2996,7 +2944,6 @@ MODULE_DEVICE_TABLE(acpi, hi847_acpi_ids); static struct i2c_driver hi847_i2c_driver = { .driver = { .name = "hi847", - .pm = &hi847_pm_ops, .acpi_match_table = ACPI_PTR(hi847_acpi_ids), }, .probe = hi847_probe, diff --git a/drivers/media/i2c/imx208.c b/drivers/media/i2c/imx208.c index ee5a286753..a9b0aea1ae 100644 --- a/drivers/media/i2c/imx208.c +++ b/drivers/media/i2c/imx208.c @@ -290,9 +290,6 @@ struct imx208 { */ struct mutex imx208_mx; - /* Streaming on/off */ - bool streaming; - /* OTP data */ bool otp_read; char otp_data[IMX208_OTP_SIZE]; @@ -714,15 +711,13 @@ static int imx208_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&imx208->imx208_mx); - if (imx208->streaming == enable) { - mutex_unlock(&imx208->imx208_mx); - return 0; - } if (enable) { - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) - goto err_rpm_put; + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) { + mutex_unlock(&imx208->imx208_mx); + return ret; + } /* * Apply default & customized values @@ -736,7 +731,6 @@ static int imx208_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - imx208->streaming = enable; mutex_unlock(&imx208->imx208_mx); /* vflip and hflip cannot change during streaming */ @@ -752,40 +746,6 @@ err_rpm_put: return ret; } -static int __maybe_unused imx208_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx208 *imx208 = to_imx208(sd); - - if (imx208->streaming) - imx208_stop_streaming(imx208); - - return 0; -} - -static int __maybe_unused imx208_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx208 *imx208 = to_imx208(sd); - int ret; - - if (imx208->streaming) { - ret = imx208_start_streaming(imx208); - if (ret) - goto error; - } - - return 0; - -error: - imx208_stop_streaming(imx208); - imx208->streaming = 0; - - return ret; -} - /* Verify chip ID */ static const struct v4l2_subdev_video_ops imx208_video_ops = { .s_stream = imx208_set_stream, @@ -819,11 +779,9 @@ static int imx208_read_otp(struct imx208 *imx208) if (imx208->otp_read) goto out_unlock; - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_noidle(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) goto out_unlock; - } ret = imx208_identify_module(imx208); if (ret) @@ -1081,10 +1039,6 @@ static void imx208_remove(struct i2c_client *client) mutex_destroy(&imx208->imx208_mx); } -static const struct dev_pm_ops imx208_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx208_suspend, imx208_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id imx208_acpi_ids[] = { { "INT3478" }, @@ -1097,7 +1051,6 @@ MODULE_DEVICE_TABLE(acpi, imx208_acpi_ids); static struct i2c_driver imx208_i2c_driver = { .driver = { .name = "imx208", - .pm = &imx208_pm_ops, .acpi_match_table = ACPI_PTR(imx208_acpi_ids), }, .probe = imx208_probe, diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index 2f9c8582f9..4f77ea02cc 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -58,8 +58,6 @@ struct imx214 { * and start streaming. */ struct mutex mutex; - - bool streaming; }; struct reg_8 { @@ -775,9 +773,6 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable) struct imx214 *imx214 = to_imx214(subdev); int ret; - if (imx214->streaming == enable) - return 0; - if (enable) { ret = pm_runtime_resume_and_get(imx214->dev); if (ret < 0) @@ -793,7 +788,6 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable) pm_runtime_put(imx214->dev); } - imx214->streaming = enable; return 0; err_rpm_put: @@ -909,39 +903,6 @@ done: return ret; } -static int __maybe_unused imx214_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx214 *imx214 = to_imx214(sd); - - if (imx214->streaming) - imx214_stop_streaming(imx214); - - return 0; -} - -static int __maybe_unused imx214_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx214 *imx214 = to_imx214(sd); - int ret; - - if (imx214->streaming) { - ret = imx214_start_streaming(imx214); - if (ret) - goto error; - } - - return 0; - -error: - imx214_stop_streaming(imx214); - imx214->streaming = 0; - return ret; -} - static int imx214_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -1102,7 +1063,6 @@ static const struct of_device_id imx214_of_match[] = { MODULE_DEVICE_TABLE(of, imx214_of_match); static const struct dev_pm_ops imx214_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx214_suspend, imx214_resume) SET_RUNTIME_PM_OPS(imx214_power_off, imx214_power_on, NULL) }; diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 3afa3f79c8..8436880dcf 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> +#include <linux/minmax.h> #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> @@ -71,20 +72,10 @@ /* V_TIMING internal */ #define IMX219_REG_VTS CCI_REG16(0x0160) -#define IMX219_VTS_15FPS 0x0dc6 -#define IMX219_VTS_30FPS_1080P 0x06e3 -#define IMX219_VTS_30FPS_BINNED 0x06e3 -#define IMX219_VTS_30FPS_640x480 0x06e3 #define IMX219_VTS_MAX 0xffff #define IMX219_VBLANK_MIN 4 -/*Frame Length Line*/ -#define IMX219_FLL_MIN 0x08a6 -#define IMX219_FLL_MAX 0xffff -#define IMX219_FLL_STEP 1 -#define IMX219_FLL_DEFAULT 0x0c98 - /* HBLANK control - read only */ #define IMX219_PPL_DEFAULT 3448 @@ -100,10 +91,11 @@ #define IMX219_REG_ORIENTATION CCI_REG8(0x0172) /* Binning Mode */ -#define IMX219_REG_BINNING_MODE CCI_REG16(0x0174) -#define IMX219_BINNING_NONE 0x0000 -#define IMX219_BINNING_2X2 0x0101 -#define IMX219_BINNING_2X2_ANALOG 0x0303 +#define IMX219_REG_BINNING_MODE_H CCI_REG8(0x0174) +#define IMX219_REG_BINNING_MODE_V CCI_REG8(0x0175) +#define IMX219_BINNING_NONE 0x00 +#define IMX219_BINNING_X2 0x01 +#define IMX219_BINNING_X2_ANALOG 0x03 #define IMX219_REG_CSI_DATA_FORMAT_A CCI_REG16(0x018c) @@ -133,10 +125,6 @@ #define IMX219_TESTP_COLOUR_MIN 0 #define IMX219_TESTP_COLOUR_MAX 0x03ff #define IMX219_TESTP_COLOUR_STEP 1 -#define IMX219_TESTP_RED_DEFAULT IMX219_TESTP_COLOUR_MAX -#define IMX219_TESTP_GREENR_DEFAULT 0 -#define IMX219_TESTP_BLUE_DEFAULT 0 -#define IMX219_TESTP_GREENB_DEFAULT 0 #define IMX219_REG_TP_WINDOW_WIDTH CCI_REG16(0x0624) #define IMX219_REG_TP_WINDOW_HEIGHT CCI_REG16(0x0626) @@ -159,11 +147,6 @@ #define IMX219_PIXEL_ARRAY_WIDTH 3280U #define IMX219_PIXEL_ARRAY_HEIGHT 2464U -struct imx219_reg_list { - unsigned int num_of_regs; - const struct cci_reg_sequence *regs; -}; - /* Mode : resolution and related config&values */ struct imx219_mode { /* Frame width */ @@ -171,17 +154,8 @@ struct imx219_mode { /* Frame height */ unsigned int height; - /* Analog crop rectangle. */ - struct v4l2_rect crop; - /* V-timing */ unsigned int vts_def; - - /* Default register values */ - struct imx219_reg_list reg_list; - - /* 2x2 binning is used */ - bool binning; }; static const struct cci_reg_sequence imx219_common_regs[] = { @@ -228,65 +202,6 @@ static const struct cci_reg_sequence imx219_common_regs[] = { { IMX219_REG_EXCK_FREQ, IMX219_EXCK_FREQ(IMX219_XCLK_FREQ / 1000000) }, }; -/* - * Register sets lifted off the i2C interface from the Raspberry Pi firmware - * driver. - * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. - */ -static const struct cci_reg_sequence mode_3280x2464_regs[] = { - { IMX219_REG_X_ADD_STA_A, 0 }, - { IMX219_REG_X_ADD_END_A, 3279 }, - { IMX219_REG_Y_ADD_STA_A, 0 }, - { IMX219_REG_Y_ADD_END_A, 2463 }, - { IMX219_REG_X_OUTPUT_SIZE, 3280 }, - { IMX219_REG_Y_OUTPUT_SIZE, 2464 }, - { IMX219_REG_TP_WINDOW_WIDTH, 3280 }, - { IMX219_REG_TP_WINDOW_HEIGHT, 2464 }, -}; - -static const struct cci_reg_sequence mode_1920_1080_regs[] = { - { IMX219_REG_X_ADD_STA_A, 680 }, - { IMX219_REG_X_ADD_END_A, 2599 }, - { IMX219_REG_Y_ADD_STA_A, 692 }, - { IMX219_REG_Y_ADD_END_A, 1771 }, - { IMX219_REG_X_OUTPUT_SIZE, 1920 }, - { IMX219_REG_Y_OUTPUT_SIZE, 1080 }, - { IMX219_REG_TP_WINDOW_WIDTH, 1920 }, - { IMX219_REG_TP_WINDOW_HEIGHT, 1080 }, -}; - -static const struct cci_reg_sequence mode_1640_1232_regs[] = { - { IMX219_REG_X_ADD_STA_A, 0 }, - { IMX219_REG_X_ADD_END_A, 3279 }, - { IMX219_REG_Y_ADD_STA_A, 0 }, - { IMX219_REG_Y_ADD_END_A, 2463 }, - { IMX219_REG_X_OUTPUT_SIZE, 1640 }, - { IMX219_REG_Y_OUTPUT_SIZE, 1232 }, - { IMX219_REG_TP_WINDOW_WIDTH, 1640 }, - { IMX219_REG_TP_WINDOW_HEIGHT, 1232 }, -}; - -static const struct cci_reg_sequence mode_640_480_regs[] = { - { IMX219_REG_X_ADD_STA_A, 1000 }, - { IMX219_REG_X_ADD_END_A, 2279 }, - { IMX219_REG_Y_ADD_STA_A, 752 }, - { IMX219_REG_Y_ADD_END_A, 1711 }, - { IMX219_REG_X_OUTPUT_SIZE, 640 }, - { IMX219_REG_Y_OUTPUT_SIZE, 480 }, - { IMX219_REG_TP_WINDOW_WIDTH, 1640 }, - { IMX219_REG_TP_WINDOW_HEIGHT, 1232 }, -}; - -static const struct cci_reg_sequence raw8_framefmt_regs[] = { - { IMX219_REG_CSI_DATA_FORMAT_A, 0x0808 }, - { IMX219_REG_OPPXCK_DIV, 8 }, -}; - -static const struct cci_reg_sequence raw10_framefmt_regs[] = { - { IMX219_REG_CSI_DATA_FORMAT_A, 0x0a0a }, - { IMX219_REG_OPPXCK_DIV, 10 }, -}; - static const s64 imx219_link_freq_menu[] = { IMX219_DEFAULT_LINK_FREQ, }; @@ -375,69 +290,25 @@ static const struct imx219_mode supported_modes[] = { /* 8MPix 15fps mode */ .width = 3280, .height = 2464, - .crop = { - .left = IMX219_PIXEL_ARRAY_LEFT, - .top = IMX219_PIXEL_ARRAY_TOP, - .width = 3280, - .height = 2464 - }, - .vts_def = IMX219_VTS_15FPS, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), - .regs = mode_3280x2464_regs, - }, - .binning = false, + .vts_def = 3526, }, { /* 1080P 30fps cropped */ .width = 1920, .height = 1080, - .crop = { - .left = 688, - .top = 700, - .width = 1920, - .height = 1080 - }, - .vts_def = IMX219_VTS_30FPS_1080P, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs), - .regs = mode_1920_1080_regs, - }, - .binning = false, + .vts_def = 1763, }, { /* 2x2 binned 30fps mode */ .width = 1640, .height = 1232, - .crop = { - .left = IMX219_PIXEL_ARRAY_LEFT, - .top = IMX219_PIXEL_ARRAY_TOP, - .width = 3280, - .height = 2464 - }, - .vts_def = IMX219_VTS_30FPS_BINNED, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs), - .regs = mode_1640_1232_regs, - }, - .binning = true, + .vts_def = 1763, }, { /* 640x480 30fps mode */ .width = 640, .height = 480, - .crop = { - .left = 1008, - .top = 760, - .width = 1280, - .height = 960 - }, - .vts_def = IMX219_VTS_30FPS_640x480, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_640_480_regs), - .regs = mode_640_480_regs, - }, - .binning = true, + .vts_def = 1763, }, }; @@ -462,12 +333,6 @@ struct imx219 { struct v4l2_ctrl *vblank; struct v4l2_ctrl *hblank; - /* Current mode */ - const struct imx219_mode *mode; - - /* Streaming on/off */ - bool streaming; - /* Two or Four lanes */ u8 lanes; }; @@ -495,18 +360,27 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code) return imx219_mbus_formats[i]; } +/* ----------------------------------------------------------------------------- + * Controls + */ + static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx219 *imx219 = container_of(ctrl->handler, struct imx219, ctrl_handler); struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; int ret = 0; + state = v4l2_subdev_get_locked_active_state(&imx219->sd); + format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0); + if (ctrl->id == V4L2_CID_VBLANK) { int exposure_max, exposure_def; /* Update max exposure while meeting expected vblanking */ - exposure_max = imx219->mode->height + ctrl->val - 4; + exposure_max = format->height + ctrl->val - 4; exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? exposure_max : IMX219_EXPOSURE_DEFAULT; __v4l2_ctrl_modify_range(imx219->exposure, @@ -546,7 +420,7 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_VBLANK: cci_write(imx219->regmap, IMX219_REG_VTS, - imx219->mode->height + ctrl->val, &ret); + format->height + ctrl->val, &ret); break; case V4L2_CID_TEST_PATTERN_RED: cci_write(imx219->regmap, IMX219_REG_TESTP_RED, @@ -581,207 +455,211 @@ static const struct v4l2_ctrl_ops imx219_ctrl_ops = { .s_ctrl = imx219_set_ctrl, }; -static void imx219_update_pad_format(struct imx219 *imx219, - const struct imx219_mode *mode, - struct v4l2_mbus_framefmt *fmt, u32 code) +static unsigned long imx219_get_pixel_rate(struct imx219 *imx219) { - /* Bayer order varies with flips */ - fmt->code = imx219_get_format_code(imx219, code); - fmt->width = mode->width; - fmt->height = mode->height; - fmt->field = V4L2_FIELD_NONE; - fmt->colorspace = V4L2_COLORSPACE_RAW; - fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - fmt->xfer_func = V4L2_XFER_FUNC_NONE; + return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE; } -static int imx219_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +/* Initialize control handlers */ +static int imx219_init_controls(struct imx219 *imx219) { - struct imx219 *imx219 = to_imx219(sd); - struct v4l2_mbus_framefmt *format; - struct v4l2_rect *crop; - - /* Initialize the format. */ - format = v4l2_subdev_get_pad_format(sd, state, 0); - imx219_update_pad_format(imx219, &supported_modes[0], format, - MEDIA_BUS_FMT_SRGGB10_1X10); - - /* Initialize the crop rectangle. */ - crop = v4l2_subdev_get_pad_crop(sd, state, 0); - crop->top = IMX219_PIXEL_ARRAY_TOP; - crop->left = IMX219_PIXEL_ARRAY_LEFT; - crop->width = IMX219_PIXEL_ARRAY_WIDTH; - crop->height = IMX219_PIXEL_ARRAY_HEIGHT; - - return 0; -} + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + const struct imx219_mode *mode = &supported_modes[0]; + struct v4l2_ctrl_handler *ctrl_hdlr; + struct v4l2_fwnode_device_properties props; + int exposure_max, exposure_def, hblank; + int i, ret; -static int imx219_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct imx219 *imx219 = to_imx219(sd); + ctrl_hdlr = &imx219->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12); + if (ret) + return ret; - if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4)) - return -EINVAL; + /* By default, PIXEL_RATE is read only */ + imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_PIXEL_RATE, + imx219_get_pixel_rate(imx219), + imx219_get_pixel_rate(imx219), 1, + imx219_get_pixel_rate(imx219)); - code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]); + imx219->link_freq = + v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(imx219_link_freq_menu) - 1, 0, + (imx219->lanes == 2) ? imx219_link_freq_menu : + imx219_link_freq_4lane_menu); + if (imx219->link_freq) + imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; - return 0; -} + /* Initial vblank/hblank/exposure parameters based on current mode */ + imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_VBLANK, IMX219_VBLANK_MIN, + IMX219_VTS_MAX - mode->height, 1, + mode->vts_def - mode->height); + hblank = IMX219_PPL_DEFAULT - mode->width; + imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_HBLANK, hblank, hblank, + 1, hblank); + if (imx219->hblank) + imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + exposure_max = mode->vts_def - 4; + exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? + exposure_max : IMX219_EXPOSURE_DEFAULT; + imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_EXPOSURE, + IMX219_EXPOSURE_MIN, exposure_max, + IMX219_EXPOSURE_STEP, + exposure_def); -static int imx219_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct imx219 *imx219 = to_imx219(sd); - u32 code; + v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX, + IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT); - if (fse->index >= ARRAY_SIZE(supported_modes)) - return -EINVAL; + v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX, + IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT); - code = imx219_get_format_code(imx219, fse->code); - if (fse->code != code) - return -EINVAL; + imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + if (imx219->hflip) + imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; - fse->min_width = supported_modes[fse->index].width; - fse->max_width = fse->min_width; - fse->min_height = supported_modes[fse->index].height; - fse->max_height = fse->min_height; + imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + if (imx219->vflip) + imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; - return 0; -} + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx219_test_pattern_menu) - 1, + 0, 0, imx219_test_pattern_menu); + for (i = 0; i < 4; i++) { + /* + * The assumption is that + * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1 + * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2 + * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3 + */ + v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, + V4L2_CID_TEST_PATTERN_RED + i, + IMX219_TESTP_COLOUR_MIN, + IMX219_TESTP_COLOUR_MAX, + IMX219_TESTP_COLOUR_STEP, + IMX219_TESTP_COLOUR_MAX); + /* The "Solid color" pattern is white by default */ + } -static int imx219_set_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct imx219 *imx219 = to_imx219(sd); - const struct imx219_mode *mode; - int exposure_max, exposure_def, hblank; - struct v4l2_mbus_framefmt *format; - struct v4l2_rect *crop; + if (ctrl_hdlr->error) { + ret = ctrl_hdlr->error; + dev_err(&client->dev, "%s control init failed (%d)\n", + __func__, ret); + goto error; + } - mode = v4l2_find_nearest_size(supported_modes, - ARRAY_SIZE(supported_modes), - width, height, - fmt->format.width, fmt->format.height); + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + goto error; - imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops, + &props); + if (ret) + goto error; - format = v4l2_subdev_get_pad_format(sd, sd_state, 0); - crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); + imx219->sd.ctrl_handler = ctrl_hdlr; - *format = fmt->format; - *crop = mode->crop; + return 0; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - imx219->mode = mode; - /* Update limits and set FPS to default */ - __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, - IMX219_VTS_MAX - mode->height, 1, - mode->vts_def - mode->height); - __v4l2_ctrl_s_ctrl(imx219->vblank, - mode->vts_def - mode->height); - /* Update max exposure while meeting expected vblanking */ - exposure_max = mode->vts_def - 4; - exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? - exposure_max : IMX219_EXPOSURE_DEFAULT; - __v4l2_ctrl_modify_range(imx219->exposure, - imx219->exposure->minimum, - exposure_max, imx219->exposure->step, - exposure_def); - /* - * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank - * depends on mode->width only, and is not changeble in any - * way other than changing the mode. - */ - hblank = IMX219_PPL_DEFAULT - mode->width; - __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1, - hblank); - } +error: + v4l2_ctrl_handler_free(ctrl_hdlr); - return 0; + return ret; } -static int imx219_set_framefmt(struct imx219 *imx219, - const struct v4l2_mbus_framefmt *format) +static void imx219_free_controls(struct imx219 *imx219) { - switch (format->code) { - case MEDIA_BUS_FMT_SRGGB8_1X8: - case MEDIA_BUS_FMT_SGRBG8_1X8: - case MEDIA_BUS_FMT_SGBRG8_1X8: - case MEDIA_BUS_FMT_SBGGR8_1X8: - return cci_multi_reg_write(imx219->regmap, raw8_framefmt_regs, - ARRAY_SIZE(raw8_framefmt_regs), NULL); - - case MEDIA_BUS_FMT_SRGGB10_1X10: - case MEDIA_BUS_FMT_SGRBG10_1X10: - case MEDIA_BUS_FMT_SGBRG10_1X10: - case MEDIA_BUS_FMT_SBGGR10_1X10: - return cci_multi_reg_write(imx219->regmap, raw10_framefmt_regs, - ARRAY_SIZE(raw10_framefmt_regs), NULL); - } - - return -EINVAL; + v4l2_ctrl_handler_free(imx219->sd.ctrl_handler); } -static int imx219_set_binning(struct imx219 *imx219, - const struct v4l2_mbus_framefmt *format) +/* ----------------------------------------------------------------------------- + * Subdev operations + */ + +static int imx219_set_framefmt(struct imx219 *imx219, + struct v4l2_subdev_state *state) { - if (!imx219->mode->binning) - return cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, - IMX219_BINNING_NONE, NULL); + const struct v4l2_mbus_framefmt *format; + const struct v4l2_rect *crop; + unsigned int bpp; + u64 bin_h, bin_v; + int ret = 0; + + format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0); + crop = v4l2_subdev_get_pad_crop(&imx219->sd, state, 0); switch (format->code) { case MEDIA_BUS_FMT_SRGGB8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SBGGR8_1X8: - return cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, - IMX219_BINNING_2X2_ANALOG, NULL); + bpp = 8; + break; case MEDIA_BUS_FMT_SRGGB10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SBGGR10_1X10: - return cci_write(imx219->regmap, IMX219_REG_BINNING_MODE, - IMX219_BINNING_2X2, NULL); + default: + bpp = 10; + break; } - return -EINVAL; -} + cci_write(imx219->regmap, IMX219_REG_X_ADD_STA_A, + crop->left - IMX219_PIXEL_ARRAY_LEFT, &ret); + cci_write(imx219->regmap, IMX219_REG_X_ADD_END_A, + crop->left - IMX219_PIXEL_ARRAY_LEFT + crop->width - 1, &ret); + cci_write(imx219->regmap, IMX219_REG_Y_ADD_STA_A, + crop->top - IMX219_PIXEL_ARRAY_TOP, &ret); + cci_write(imx219->regmap, IMX219_REG_Y_ADD_END_A, + crop->top - IMX219_PIXEL_ARRAY_TOP + crop->height - 1, &ret); + + switch (crop->width / format->width) { + case 1: + default: + bin_h = IMX219_BINNING_NONE; + break; + case 2: + bin_h = bpp == 8 ? IMX219_BINNING_X2_ANALOG : IMX219_BINNING_X2; + break; + } -static int imx219_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_selection *sel) -{ - switch (sel->target) { - case V4L2_SEL_TGT_CROP: { - sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0); - return 0; + switch (crop->height / format->height) { + case 1: + default: + bin_v = IMX219_BINNING_NONE; + break; + case 2: + bin_v = bpp == 8 ? IMX219_BINNING_X2_ANALOG : IMX219_BINNING_X2; + break; } - case V4L2_SEL_TGT_NATIVE_SIZE: - sel->r.top = 0; - sel->r.left = 0; - sel->r.width = IMX219_NATIVE_WIDTH; - sel->r.height = IMX219_NATIVE_HEIGHT; + cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_H, bin_h, &ret); + cci_write(imx219->regmap, IMX219_REG_BINNING_MODE_V, bin_v, &ret); - return 0; + cci_write(imx219->regmap, IMX219_REG_X_OUTPUT_SIZE, + format->width, &ret); + cci_write(imx219->regmap, IMX219_REG_Y_OUTPUT_SIZE, + format->height, &ret); - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.top = IMX219_PIXEL_ARRAY_TOP; - sel->r.left = IMX219_PIXEL_ARRAY_LEFT; - sel->r.width = IMX219_PIXEL_ARRAY_WIDTH; - sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT; + cci_write(imx219->regmap, IMX219_REG_TP_WINDOW_WIDTH, + format->width, &ret); + cci_write(imx219->regmap, IMX219_REG_TP_WINDOW_HEIGHT, + format->height, &ret); - return 0; - } + cci_write(imx219->regmap, IMX219_REG_CSI_DATA_FORMAT_A, + (bpp << 8) | bpp, &ret); + cci_write(imx219->regmap, IMX219_REG_OPPXCK_DIV, bpp, &ret); - return -EINVAL; + return ret; } static int imx219_configure_lanes(struct imx219 *imx219) @@ -795,8 +673,6 @@ static int imx219_start_streaming(struct imx219 *imx219, struct v4l2_subdev_state *state) { struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); - const struct v4l2_mbus_framefmt *format; - const struct imx219_reg_list *reg_list; int ret; ret = pm_runtime_resume_and_get(&client->dev); @@ -818,30 +694,14 @@ static int imx219_start_streaming(struct imx219 *imx219, goto err_rpm_put; } - /* Apply default values of current mode */ - reg_list = &imx219->mode->reg_list; - ret = cci_multi_reg_write(imx219->regmap, reg_list->regs, - reg_list->num_of_regs, NULL); - if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); - goto err_rpm_put; - } - - format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0); - ret = imx219_set_framefmt(imx219, format); + /* Apply format and crop settings. */ + ret = imx219_set_framefmt(imx219, state); if (ret) { dev_err(&client->dev, "%s failed to set frame format: %d\n", __func__, ret); goto err_rpm_put; } - ret = imx219_set_binning(imx219, format); - if (ret) { - dev_err(&client->dev, "%s failed to set binning: %d\n", - __func__, ret); - goto err_rpm_put; - } - /* Apply customized values from user */ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler); if (ret) @@ -889,141 +749,176 @@ static int imx219_set_stream(struct v4l2_subdev *sd, int enable) state = v4l2_subdev_lock_and_get_active_state(sd); - if (imx219->streaming == enable) - goto unlock; - - if (enable) { - /* - * Apply default & customized values - * and then start streaming. - */ + if (enable) ret = imx219_start_streaming(imx219, state); - if (ret) - goto unlock; - } else { + else imx219_stop_streaming(imx219); - } - - imx219->streaming = enable; -unlock: v4l2_subdev_unlock_state(state); return ret; } -/* Power/clock management functions */ -static int imx219_power_on(struct device *dev) +static void imx219_update_pad_format(struct imx219 *imx219, + const struct imx219_mode *mode, + struct v4l2_mbus_framefmt *fmt, u32 code) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx219 *imx219 = to_imx219(sd); - int ret; + /* Bayer order varies with flips */ + fmt->code = imx219_get_format_code(imx219, code); + fmt->width = mode->width; + fmt->height = mode->height; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_RAW; + fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_XFER_FUNC_NONE; +} - ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES, - imx219->supplies); - if (ret) { - dev_err(dev, "%s: failed to enable regulators\n", - __func__); - return ret; - } +static int imx219_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx219 *imx219 = to_imx219(sd); - ret = clk_prepare_enable(imx219->xclk); - if (ret) { - dev_err(dev, "%s: failed to enable clock\n", - __func__); - goto reg_off; - } + if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4)) + return -EINVAL; - gpiod_set_value_cansleep(imx219->reset_gpio, 1); - usleep_range(IMX219_XCLR_MIN_DELAY_US, - IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US); + code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]); return 0; - -reg_off: - regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); - - return ret; } -static int imx219_power_off(struct device *dev) +static int imx219_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx219 *imx219 = to_imx219(sd); + u32 code; - gpiod_set_value_cansleep(imx219->reset_gpio, 0); - regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); - clk_disable_unprepare(imx219->xclk); + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + code = imx219_get_format_code(imx219, fse->code); + if (fse->code != code) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; return 0; } -static int __maybe_unused imx219_suspend(struct device *dev) +static int imx219_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx219 *imx219 = to_imx219(sd); + const struct imx219_mode *mode; + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + unsigned int bin_h, bin_v; - if (imx219->streaming) - imx219_stop_streaming(imx219); + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, fmt->format.height); - return 0; -} + imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); -static int __maybe_unused imx219_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx219 *imx219 = to_imx219(sd); - struct v4l2_subdev_state *state; - int ret; + format = v4l2_subdev_get_pad_format(sd, state, 0); + *format = fmt->format; - if (imx219->streaming) { - state = v4l2_subdev_lock_and_get_active_state(sd); - ret = imx219_start_streaming(imx219, state); - v4l2_subdev_unlock_state(state); - if (ret) - goto error; - } + /* + * Use binning to maximize the crop rectangle size, and centre it in the + * sensor. + */ + bin_h = min(IMX219_PIXEL_ARRAY_WIDTH / format->width, 2U); + bin_v = min(IMX219_PIXEL_ARRAY_HEIGHT / format->height, 2U); - return 0; + crop = v4l2_subdev_get_pad_crop(sd, state, 0); + crop->width = format->width * bin_h; + crop->height = format->height * bin_v; + crop->left = (IMX219_NATIVE_WIDTH - crop->width) / 2; + crop->top = (IMX219_NATIVE_HEIGHT - crop->height) / 2; -error: - imx219_stop_streaming(imx219); - imx219->streaming = false; + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + int exposure_max; + int exposure_def; + int hblank; - return ret; + /* Update limits and set FPS to default */ + __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, + IMX219_VTS_MAX - mode->height, 1, + mode->vts_def - mode->height); + __v4l2_ctrl_s_ctrl(imx219->vblank, + mode->vts_def - mode->height); + /* Update max exposure while meeting expected vblanking */ + exposure_max = mode->vts_def - 4; + exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? + exposure_max : IMX219_EXPOSURE_DEFAULT; + __v4l2_ctrl_modify_range(imx219->exposure, + imx219->exposure->minimum, + exposure_max, imx219->exposure->step, + exposure_def); + /* + * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank + * depends on mode->width only, and is not changeble in any + * way other than changing the mode. + */ + hblank = IMX219_PPL_DEFAULT - mode->width; + __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1, + hblank); + } + + return 0; } -static int imx219_get_regulators(struct imx219 *imx219) +static int imx219_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) { - struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); - unsigned int i; + switch (sel->target) { + case V4L2_SEL_TGT_CROP: { + sel->r = *v4l2_subdev_get_pad_crop(sd, state, 0); + return 0; + } - for (i = 0; i < IMX219_NUM_SUPPLIES; i++) - imx219->supplies[i].supply = imx219_supply_name[i]; + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = IMX219_NATIVE_WIDTH; + sel->r.height = IMX219_NATIVE_HEIGHT; - return devm_regulator_bulk_get(&client->dev, - IMX219_NUM_SUPPLIES, - imx219->supplies); -} + return 0; -/* Verify chip ID */ -static int imx219_identify_module(struct imx219 *imx219) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); - int ret; - u64 val; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = IMX219_PIXEL_ARRAY_TOP; + sel->r.left = IMX219_PIXEL_ARRAY_LEFT; + sel->r.width = IMX219_PIXEL_ARRAY_WIDTH; + sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT; - ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL); - if (ret) { - dev_err(&client->dev, "failed to read chip id %x\n", - IMX219_CHIP_ID); - return ret; + return 0; } - if (val != IMX219_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", - IMX219_CHIP_ID, val); - return -EIO; - } + return -EINVAL; +} + +static int imx219_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .pad = 0, + .format = { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = supported_modes[0].width, + .height = supported_modes[0].height, + }, + }; + + imx219_set_pad_format(sd, state, &fmt); return 0; } @@ -1053,129 +948,93 @@ static const struct v4l2_subdev_ops imx219_subdev_ops = { }; -static unsigned long imx219_get_pixel_rate(struct imx219 *imx219) -{ - return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE; -} +/* ----------------------------------------------------------------------------- + * Power management + */ -/* Initialize control handlers */ -static int imx219_init_controls(struct imx219 *imx219) +static int imx219_power_on(struct device *dev) { - struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); - struct v4l2_ctrl_handler *ctrl_hdlr; - unsigned int height = imx219->mode->height; - struct v4l2_fwnode_device_properties props; - int exposure_max, exposure_def, hblank; - int i, ret; + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx219 *imx219 = to_imx219(sd); + int ret; - ctrl_hdlr = &imx219->ctrl_handler; - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12); - if (ret) + ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES, + imx219->supplies); + if (ret) { + dev_err(dev, "%s: failed to enable regulators\n", + __func__); return ret; + } - /* By default, PIXEL_RATE is read only */ - imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_PIXEL_RATE, - imx219_get_pixel_rate(imx219), - imx219_get_pixel_rate(imx219), 1, - imx219_get_pixel_rate(imx219)); + ret = clk_prepare_enable(imx219->xclk); + if (ret) { + dev_err(dev, "%s: failed to enable clock\n", + __func__); + goto reg_off; + } - imx219->link_freq = - v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_LINK_FREQ, - ARRAY_SIZE(imx219_link_freq_menu) - 1, 0, - (imx219->lanes == 2) ? imx219_link_freq_menu : - imx219_link_freq_4lane_menu); - if (imx219->link_freq) - imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + gpiod_set_value_cansleep(imx219->reset_gpio, 1); + usleep_range(IMX219_XCLR_MIN_DELAY_US, + IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US); - /* Initial vblank/hblank/exposure parameters based on current mode */ - imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_VBLANK, IMX219_VBLANK_MIN, - IMX219_VTS_MAX - height, 1, - imx219->mode->vts_def - height); - hblank = IMX219_PPL_DEFAULT - imx219->mode->width; - imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_HBLANK, hblank, hblank, - 1, hblank); - if (imx219->hblank) - imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; - exposure_max = imx219->mode->vts_def - 4; - exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? - exposure_max : IMX219_EXPOSURE_DEFAULT; - imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_EXPOSURE, - IMX219_EXPOSURE_MIN, exposure_max, - IMX219_EXPOSURE_STEP, - exposure_def); + return 0; - v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, - IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX, - IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT); +reg_off: + regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); - v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN, - IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX, - IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT); + return ret; +} - imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - if (imx219->hflip) - imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; +static int imx219_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx219 *imx219 = to_imx219(sd); - imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - if (imx219->vflip) - imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + gpiod_set_value_cansleep(imx219->reset_gpio, 0); + regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); + clk_disable_unprepare(imx219->xclk); - v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(imx219_test_pattern_menu) - 1, - 0, 0, imx219_test_pattern_menu); - for (i = 0; i < 4; i++) { - /* - * The assumption is that - * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1 - * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2 - * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3 - */ - v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, - V4L2_CID_TEST_PATTERN_RED + i, - IMX219_TESTP_COLOUR_MIN, - IMX219_TESTP_COLOUR_MAX, - IMX219_TESTP_COLOUR_STEP, - IMX219_TESTP_COLOUR_MAX); - /* The "Solid color" pattern is white by default */ - } + return 0; +} - if (ctrl_hdlr->error) { - ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", - __func__, ret); - goto error; - } +/* ----------------------------------------------------------------------------- + * Probe & remove + */ - ret = v4l2_fwnode_device_parse(&client->dev, &props); - if (ret) - goto error; +static int imx219_get_regulators(struct imx219 *imx219) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + unsigned int i; - ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops, - &props); - if (ret) - goto error; + for (i = 0; i < IMX219_NUM_SUPPLIES; i++) + imx219->supplies[i].supply = imx219_supply_name[i]; - imx219->sd.ctrl_handler = ctrl_hdlr; + return devm_regulator_bulk_get(&client->dev, + IMX219_NUM_SUPPLIES, + imx219->supplies); +} - return 0; +/* Verify chip ID */ +static int imx219_identify_module(struct imx219 *imx219) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + int ret; + u64 val; -error: - v4l2_ctrl_handler_free(ctrl_hdlr); + ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL); + if (ret) { + dev_err(&client->dev, "failed to read chip id %x\n", + IMX219_CHIP_ID); + return ret; + } - return ret; -} + if (val != IMX219_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", + IMX219_CHIP_ID, val); + return -EIO; + } -static void imx219_free_controls(struct imx219 *imx219) -{ - v4l2_ctrl_handler_free(imx219->sd.ctrl_handler); + return 0; } static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219) @@ -1287,10 +1146,8 @@ static int imx219_probe(struct i2c_client *client) if (ret) goto error_power_off; - /* Set default mode to max resolution */ - imx219->mode = &supported_modes[0]; - - /* sensor doesn't enter LP-11 state upon power up until and unless + /* + * Sensor doesn't enter LP-11 state upon power up until and unless * streaming is started, so upon power up switch the modes to: * streaming -> standby */ @@ -1385,7 +1242,6 @@ static const struct of_device_id imx219_dt_ids[] = { MODULE_DEVICE_TABLE(of, imx219_dt_ids); static const struct dev_pm_ops imx219_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx219_suspend, imx219_resume) SET_RUNTIME_PM_OPS(imx219_power_off, imx219_power_on, NULL) }; diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index e196565e84..b3827f4bc0 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -622,9 +622,6 @@ struct imx258 { */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - struct clk *clk; }; @@ -1035,10 +1032,6 @@ static int imx258_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&imx258->mutex); - if (imx258->streaming == enable) { - mutex_unlock(&imx258->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -1057,7 +1050,6 @@ static int imx258_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - imx258->streaming = enable; mutex_unlock(&imx258->mutex); return ret; @@ -1070,37 +1062,6 @@ err_unlock: return ret; } -static int __maybe_unused imx258_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx258 *imx258 = to_imx258(sd); - - if (imx258->streaming) - imx258_stop_streaming(imx258); - - return 0; -} - -static int __maybe_unused imx258_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx258 *imx258 = to_imx258(sd); - int ret; - - if (imx258->streaming) { - ret = imx258_start_streaming(imx258); - if (ret) - goto error; - } - - return 0; - -error: - imx258_stop_streaming(imx258); - imx258->streaming = 0; - return ret; -} - /* Verify chip ID */ static int imx258_identify_module(struct imx258 *imx258) { @@ -1369,7 +1330,6 @@ static void imx258_remove(struct i2c_client *client) } static const struct dev_pm_ops imx258_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx258_suspend, imx258_resume) SET_RUNTIME_PM_OPS(imx258_power_off, imx258_power_on, NULL) }; diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c index 3b4539b622..94aac9d273 100644 --- a/drivers/media/i2c/imx296.c +++ b/drivers/media/i2c/imx296.c @@ -201,8 +201,6 @@ struct imx296 { const struct imx296_clk_params *clk_params; bool mono; - bool streaming; - struct v4l2_subdev subdev; struct media_pad pad; @@ -321,7 +319,7 @@ static int imx296_s_ctrl(struct v4l2_ctrl *ctrl) unsigned int vmax; int ret = 0; - if (!sensor->streaming) + if (!pm_runtime_get_if_in_use(sensor->dev)) return 0; state = v4l2_subdev_get_locked_active_state(&sensor->subdev); @@ -376,6 +374,8 @@ static int imx296_s_ctrl(struct v4l2_ctrl *ctrl) break; } + pm_runtime_put(sensor->dev); + return ret; } @@ -607,8 +607,6 @@ static int imx296_s_stream(struct v4l2_subdev *sd, int enable) pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); - sensor->streaming = false; - goto unlock; } @@ -620,13 +618,6 @@ static int imx296_s_stream(struct v4l2_subdev *sd, int enable) if (ret < 0) goto err_pm; - /* - * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set - * the controls. The flag is reset to false further down if an error - * occurs. - */ - sensor->streaming = true; - ret = __v4l2_ctrl_handler_setup(&sensor->ctrls); if (ret < 0) goto err_pm; @@ -646,7 +637,6 @@ err_pm: * likely has no other chance to recover. */ pm_runtime_put_sync(sensor->dev); - sensor->streaming = false; goto unlock; } diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index 52ebb096e1..5378f607f3 100644 --- a/drivers/media/i2c/imx319.c +++ b/drivers/media/i2c/imx319.c @@ -138,8 +138,6 @@ struct imx319 { */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; /* True if the device has been identified */ bool identified; }; @@ -2166,10 +2164,6 @@ static int imx319_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&imx319->mutex); - if (imx319->streaming == enable) { - mutex_unlock(&imx319->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -2188,8 +2182,6 @@ static int imx319_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - imx319->streaming = enable; - /* vflip and hflip cannot change during streaming */ __v4l2_ctrl_grab(imx319->vflip, enable); __v4l2_ctrl_grab(imx319->hflip, enable); @@ -2206,37 +2198,6 @@ err_unlock: return ret; } -static int __maybe_unused imx319_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx319 *imx319 = to_imx319(sd); - - if (imx319->streaming) - imx319_stop_streaming(imx319); - - return 0; -} - -static int __maybe_unused imx319_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx319 *imx319 = to_imx319(sd); - int ret; - - if (imx319->streaming) { - ret = imx319_start_streaming(imx319); - if (ret) - goto error; - } - - return 0; - -error: - imx319_stop_streaming(imx319); - imx319->streaming = 0; - return ret; -} - static const struct v4l2_subdev_core_ops imx319_subdev_core_ops = { .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, @@ -2542,10 +2503,6 @@ static void imx319_remove(struct i2c_client *client) mutex_destroy(&imx319->mutex); } -static const struct dev_pm_ops imx319_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx319_suspend, imx319_resume) -}; - static const struct acpi_device_id imx319_acpi_ids[] __maybe_unused = { { "SONY319A" }, { /* sentinel */ } @@ -2555,7 +2512,6 @@ MODULE_DEVICE_TABLE(acpi, imx319_acpi_ids); static struct i2c_driver imx319_i2c_driver = { .driver = { .name = "imx319", - .pm = &imx319_pm_ops, .acpi_match_table = ACPI_PTR(imx319_acpi_ids), }, .probe = imx319_probe, diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c index d722c9b7cd..1196fe9350 100644 --- a/drivers/media/i2c/imx334.c +++ b/drivers/media/i2c/imx334.c @@ -56,6 +56,24 @@ #define IMX334_REG_MIN 0x00 #define IMX334_REG_MAX 0xfffff +/* Test Pattern Control */ +#define IMX334_REG_TP 0x329e +#define IMX334_TP_COLOR_HBARS 0xA +#define IMX334_TP_COLOR_VBARS 0xB + +#define IMX334_TPG_EN_DOUT 0x329c +#define IMX334_TP_ENABLE 0x1 +#define IMX334_TP_DISABLE 0x0 + +#define IMX334_TPG_COLORW 0x32a0 +#define IMX334_TPG_COLORW_120P 0x13 + +#define IMX334_TP_CLK_EN 0x3148 +#define IMX334_TP_CLK_EN_VAL 0x10 +#define IMX334_TP_CLK_DIS_VAL 0x0 + +#define IMX334_DIG_CLP_MODE 0x3280 + /** * struct imx334_reg - imx334 sensor register * @address: Register address @@ -120,7 +138,6 @@ struct imx334_mode { * @mutex: Mutex for serializing sensor controls * @menu_skip_mask: Menu skip mask for link_freq_ctrl * @cur_code: current selected format code - * @streaming: Flag indicating streaming state */ struct imx334 { struct device *dev; @@ -143,7 +160,6 @@ struct imx334 { struct mutex mutex; unsigned long menu_skip_mask; u32 cur_code; - bool streaming; }; static const s64 link_freq[] = { @@ -430,6 +446,18 @@ static const struct imx334_reg mode_3840x2160_regs[] = { {0x3a29, 0x00}, }; +static const char * const imx334_test_pattern_menu[] = { + "Disabled", + "Vertical Color Bars", + "Horizontal Color Bars", +}; + +static const int imx334_test_pattern_val[] = { + IMX334_TP_DISABLE, + IMX334_TP_COLOR_HBARS, + IMX334_TP_COLOR_VBARS, +}; + static const struct imx334_reg raw10_framefmt_regs[] = { {0x3050, 0x00}, {0x319d, 0x00}, @@ -716,6 +744,26 @@ static int imx334_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_HBLANK: ret = 0; break; + case V4L2_CID_TEST_PATTERN: + if (ctrl->val) { + imx334_write_reg(imx334, IMX334_TP_CLK_EN, 1, + IMX334_TP_CLK_EN_VAL); + imx334_write_reg(imx334, IMX334_DIG_CLP_MODE, 1, 0x0); + imx334_write_reg(imx334, IMX334_TPG_COLORW, 1, + IMX334_TPG_COLORW_120P); + imx334_write_reg(imx334, IMX334_REG_TP, 1, + imx334_test_pattern_val[ctrl->val]); + imx334_write_reg(imx334, IMX334_TPG_EN_DOUT, 1, + IMX334_TP_ENABLE); + } else { + imx334_write_reg(imx334, IMX334_DIG_CLP_MODE, 1, 0x1); + imx334_write_reg(imx334, IMX334_TP_CLK_EN, 1, + IMX334_TP_CLK_DIS_VAL); + imx334_write_reg(imx334, IMX334_TPG_EN_DOUT, 1, + IMX334_TP_DISABLE); + } + ret = 0; + break; default: dev_err(imx334->dev, "Invalid control %d", ctrl->id); ret = -EINVAL; @@ -1001,11 +1049,6 @@ static int imx334_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&imx334->mutex); - if (imx334->streaming == enable) { - mutex_unlock(&imx334->mutex); - return 0; - } - if (enable) { ret = pm_runtime_resume_and_get(imx334->dev); if (ret < 0) @@ -1019,8 +1062,6 @@ static int imx334_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(imx334->dev); } - imx334->streaming = enable; - mutex_unlock(&imx334->mutex); return 0; @@ -1222,7 +1263,7 @@ static int imx334_init_controls(struct imx334 *imx334) u32 lpfr; int ret; - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6); + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 7); if (ret) return ret; @@ -1282,6 +1323,11 @@ static int imx334_init_controls(struct imx334 *imx334) if (imx334->hblank_ctrl) imx334->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx334_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx334_test_pattern_menu) - 1, + 0, 0, imx334_test_pattern_menu); + if (ctrl_hdlr->error) { dev_err(imx334->dev, "control init failed: %d", ctrl_hdlr->error); diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c index 482a0b7f04..964a81bec5 100644 --- a/drivers/media/i2c/imx335.c +++ b/drivers/media/i2c/imx335.c @@ -119,7 +119,6 @@ struct imx335_mode { * @vblank: Vertical blanking in lines * @cur_mode: Pointer to current selected sensor mode * @mutex: Mutex for serializing sensor controls - * @streaming: Flag indicating streaming state */ struct imx335 { struct device *dev; @@ -140,7 +139,6 @@ struct imx335 { u32 vblank; const struct imx335_mode *cur_mode; struct mutex mutex; - bool streaming; }; static const s64 link_freq[] = { @@ -705,11 +703,6 @@ static int imx335_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&imx335->mutex); - if (imx335->streaming == enable) { - mutex_unlock(&imx335->mutex); - return 0; - } - if (enable) { ret = pm_runtime_resume_and_get(imx335->dev); if (ret) @@ -723,8 +716,6 @@ static int imx335_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(imx335->dev); } - imx335->streaming = enable; - mutex_unlock(&imx335->mutex); return 0; @@ -971,8 +962,8 @@ static int imx335_init_controls(struct imx335 *imx335) imx335->hblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &imx335_ctrl_ops, V4L2_CID_HBLANK, - IMX335_REG_MIN, - IMX335_REG_MAX, + mode->hblank, + mode->hblank, 1, mode->hblank); if (imx335->hblank_ctrl) imx335->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index 059a41b7ee..81bb61407b 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -123,9 +123,6 @@ struct imx355 { * Protect access to sensor v4l2 controls. */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; static const struct imx355_reg imx355_global_regs[] = { @@ -1436,10 +1433,6 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&imx355->mutex); - if (imx355->streaming == enable) { - mutex_unlock(&imx355->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -1458,8 +1451,6 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - imx355->streaming = enable; - /* vflip and hflip cannot change during streaming */ __v4l2_ctrl_grab(imx355->vflip, enable); __v4l2_ctrl_grab(imx355->hflip, enable); @@ -1476,37 +1467,6 @@ err_unlock: return ret; } -static int __maybe_unused imx355_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx355 *imx355 = to_imx355(sd); - - if (imx355->streaming) - imx355_stop_streaming(imx355); - - return 0; -} - -static int __maybe_unused imx355_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx355 *imx355 = to_imx355(sd); - int ret; - - if (imx355->streaming) { - ret = imx355_start_streaming(imx355); - if (ret) - goto error; - } - - return 0; - -error: - imx355_stop_streaming(imx355); - imx355->streaming = 0; - return ret; -} - /* Verify chip ID */ static int imx355_identify_module(struct imx355 *imx355) { @@ -1831,10 +1791,6 @@ static void imx355_remove(struct i2c_client *client) mutex_destroy(&imx355->mutex); } -static const struct dev_pm_ops imx355_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx355_suspend, imx355_resume) -}; - static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = { { "SONY355A" }, { /* sentinel */ } @@ -1844,7 +1800,6 @@ MODULE_DEVICE_TABLE(acpi, imx355_acpi_ids); static struct i2c_driver imx355_i2c_driver = { .driver = { .name = "imx355", - .pm = &imx355_pm_ops, .acpi_match_table = ACPI_PTR(imx355_acpi_ids), }, .probe = imx355_probe, diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index c7e862ae40..962b3136c3 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -127,7 +127,6 @@ static const char * const imx412_supply_names[] = { * @vblank: Vertical blanking in lines * @cur_mode: Pointer to current selected sensor mode * @mutex: Mutex for serializing sensor controls - * @streaming: Flag indicating streaming state */ struct imx412 { struct device *dev; @@ -149,7 +148,6 @@ struct imx412 { u32 vblank; const struct imx412_mode *cur_mode; struct mutex mutex; - bool streaming; }; static const s64 link_freq[] = { @@ -857,11 +855,6 @@ static int imx412_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&imx412->mutex); - if (imx412->streaming == enable) { - mutex_unlock(&imx412->mutex); - return 0; - } - if (enable) { ret = pm_runtime_resume_and_get(imx412->dev); if (ret) @@ -875,8 +868,6 @@ static int imx412_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(imx412->dev); } - imx412->streaming = enable; - mutex_unlock(&imx412->mutex); return 0; diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 3f00172df3..b3fa71a168 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -353,8 +353,6 @@ struct imx415 { const struct imx415_clk_params *clk_params; - bool streaming; - struct v4l2_subdev subdev; struct media_pad pad; @@ -542,8 +540,9 @@ static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) struct v4l2_subdev_state *state; unsigned int vmax; unsigned int flip; + int ret; - if (!sensor->streaming) + if (!pm_runtime_get_if_in_use(sensor->dev)) return 0; state = v4l2_subdev_get_locked_active_state(&sensor->subdev); @@ -554,24 +553,33 @@ static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) /* clamp the exposure value to VMAX. */ vmax = format->height + sensor->vblank->cur.val; ctrl->val = min_t(int, ctrl->val, vmax); - return imx415_write(sensor, IMX415_SHR0, vmax - ctrl->val); + ret = imx415_write(sensor, IMX415_SHR0, vmax - ctrl->val); + break; case V4L2_CID_ANALOGUE_GAIN: /* analogue gain in 0.3 dB step size */ - return imx415_write(sensor, IMX415_GAIN_PCG_0, ctrl->val); + ret = imx415_write(sensor, IMX415_GAIN_PCG_0, ctrl->val); + break; case V4L2_CID_HFLIP: case V4L2_CID_VFLIP: flip = (sensor->hflip->val << IMX415_HREVERSE_SHIFT) | (sensor->vflip->val << IMX415_VREVERSE_SHIFT); - return imx415_write(sensor, IMX415_REVERSE, flip); + ret = imx415_write(sensor, IMX415_REVERSE, flip); + break; case V4L2_CID_TEST_PATTERN: - return imx415_set_testpattern(sensor, ctrl->val); + ret = imx415_set_testpattern(sensor, ctrl->val); + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + + pm_runtime_put(sensor->dev); + + return ret; } static const struct v4l2_ctrl_ops imx415_ctrl_ops = { @@ -766,8 +774,6 @@ static int imx415_s_stream(struct v4l2_subdev *sd, int enable) pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); - sensor->streaming = false; - goto unlock; } @@ -779,13 +785,6 @@ static int imx415_s_stream(struct v4l2_subdev *sd, int enable) if (ret) goto err_pm; - /* - * Set streaming to true to ensure __v4l2_ctrl_handler_setup() will set - * the controls. The flag is reset to false further down if an error - * occurs. - */ - sensor->streaming = true; - ret = __v4l2_ctrl_handler_setup(&sensor->ctrls); if (ret < 0) goto err_pm; @@ -807,7 +806,6 @@ err_pm: * likely has no other chance to recover. */ pm_runtime_put_sync(sensor->dev); - sensor->streaming = false; goto unlock; } @@ -842,15 +840,6 @@ static int imx415_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int imx415_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state, - struct v4l2_subdev_format *fmt) -{ - fmt->format = *v4l2_subdev_get_pad_format(sd, state, fmt->pad); - - return 0; -} - static int imx415_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_format *fmt) @@ -913,7 +902,7 @@ static const struct v4l2_subdev_video_ops imx415_subdev_video_ops = { static const struct v4l2_subdev_pad_ops imx415_subdev_pad_ops = { .enum_mbus_code = imx415_enum_mbus_code, .enum_frame_size = imx415_enum_frame_size, - .get_fmt = imx415_get_format, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx415_set_format, .get_selection = imx415_get_selection, .init_cfg = imx415_init_cfg, diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index bec7680148..0ed8561edf 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -561,7 +561,7 @@ static int msp_log_status(struct v4l2_subdev *sd) struct msp_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); const char *p; - char prefix[V4L2_SUBDEV_NAME_SIZE + 20]; + char prefix[sizeof(sd->name) + 20]; if (state->opmode == OPMODE_AUTOSELECT) msp_detect_stereo(client); diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index ce9568e839..79192cf79d 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -93,7 +93,6 @@ struct mt9m001 { struct v4l2_ctrl *autoexposure; struct v4l2_ctrl *exposure; }; - bool streaming; struct mutex mutex; struct v4l2_rect rect; /* Sensor window */ struct clk *clk; @@ -213,9 +212,6 @@ static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&mt9m001->mutex); - if (mt9m001->streaming == enable) - goto done; - if (enable) { ret = pm_runtime_resume_and_get(&client->dev); if (ret < 0) @@ -239,8 +235,6 @@ static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - mt9m001->streaming = enable; -done: mutex_unlock(&mt9m001->mutex); return 0; diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index df8d9c9e6a..1f44b72e8a 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -244,9 +244,7 @@ struct mt9m111 { bool is_streaming; /* user point of view - 0: falling 1: rising edge */ unsigned int pclk_sample:1; -#ifdef CONFIG_MEDIA_CONTROLLER struct media_pad pad; -#endif }; static const struct mt9m111_mode_info mt9m111_mode_data[MT9M111_NUM_MODES] = { @@ -527,13 +525,9 @@ static int mt9m111_get_fmt(struct v4l2_subdev *sd, return -EINVAL; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mf = v4l2_subdev_get_try_format(sd, sd_state, format->pad); format->format = *mf; return 0; -#else - return -EINVAL; -#endif } mf->width = mt9m111->width; @@ -1120,7 +1114,6 @@ static int mt9m111_s_stream(struct v4l2_subdev *sd, int enable) static int mt9m111_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, sd_state, 0); @@ -1132,7 +1125,7 @@ static int mt9m111_init_cfg(struct v4l2_subdev *sd, format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; format->quantization = V4L2_QUANTIZATION_DEFAULT; format->xfer_func = V4L2_XFER_FUNC_DEFAULT; -#endif + return 0; } @@ -1315,13 +1308,11 @@ static int mt9m111_probe(struct i2c_client *client) return ret; } -#ifdef CONFIG_MEDIA_CONTROLLER mt9m111->pad.flags = MEDIA_PAD_FL_SOURCE; mt9m111->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&mt9m111->subdev.entity, 1, &mt9m111->pad); if (ret < 0) goto out_hdlfree; -#endif mt9m111->current_mode = &mt9m111_mode_data[MT9M111_MODE_SXGA_15FPS]; mt9m111->frame_interval.numerator = 1; @@ -1350,10 +1341,8 @@ static int mt9m111_probe(struct i2c_client *client) return 0; out_entityclean: -#ifdef CONFIG_MEDIA_CONTROLLER media_entity_cleanup(&mt9m111->subdev.entity); out_hdlfree: -#endif v4l2_ctrl_handler_free(&mt9m111->hdl); return ret; diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c new file mode 100644 index 0000000000..1a535c098d --- /dev/null +++ b/drivers/media/i2c/mt9m114.c @@ -0,0 +1,2481 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * mt9m114.c onsemi MT9M114 sensor driver + * + * Copyright (c) 2020-2023 Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * Copyright (c) 2012 Analog Devices Inc. + * + * Almost complete rewrite of work by Scott Jiang <Scott.Jiang.Linux@gmail.com> + * itself based on work from Andrew Chew <achew@nvidia.com>. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/types.h> +#include <linux/videodev2.h> + +#include <media/v4l2-async.h> +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mediabus.h> +#include <media/v4l2-subdev.h> + +/* Sysctl registers */ +#define MT9M114_CHIP_ID CCI_REG16(0x0000) +#define MT9M114_COMMAND_REGISTER CCI_REG16(0x0080) +#define MT9M114_COMMAND_REGISTER_APPLY_PATCH BIT(0) +#define MT9M114_COMMAND_REGISTER_SET_STATE BIT(1) +#define MT9M114_COMMAND_REGISTER_REFRESH BIT(2) +#define MT9M114_COMMAND_REGISTER_WAIT_FOR_EVENT BIT(3) +#define MT9M114_COMMAND_REGISTER_OK BIT(15) +#define MT9M114_RESET_AND_MISC_CONTROL CCI_REG16(0x001a) +#define MT9M114_RESET_SOC BIT(0) +#define MT9M114_PAD_SLEW CCI_REG16(0x001e) +#define MT9M114_PAD_CONTROL CCI_REG16(0x0032) + +/* XDMA registers */ +#define MT9M114_ACCESS_CTL_STAT CCI_REG16(0x0982) +#define MT9M114_PHYSICAL_ADDRESS_ACCESS CCI_REG16(0x098a) +#define MT9M114_LOGICAL_ADDRESS_ACCESS CCI_REG16(0x098e) + +/* Sensor Core registers */ +#define MT9M114_COARSE_INTEGRATION_TIME CCI_REG16(0x3012) +#define MT9M114_FINE_INTEGRATION_TIME CCI_REG16(0x3014) +#define MT9M114_RESET_REGISTER CCI_REG16(0x301a) +#define MT9M114_RESET_REGISTER_LOCK_REG BIT(3) +#define MT9M114_RESET_REGISTER_MASK_BAD BIT(9) +#define MT9M114_FLASH CCI_REG16(0x3046) +#define MT9M114_GREEN1_GAIN CCI_REG16(0x3056) +#define MT9M114_BLUE_GAIN CCI_REG16(0x3058) +#define MT9M114_RED_GAIN CCI_REG16(0x305a) +#define MT9M114_GREEN2_GAIN CCI_REG16(0x305c) +#define MT9M114_GLOBAL_GAIN CCI_REG16(0x305e) +#define MT9M114_GAIN_DIGITAL_GAIN(n) ((n) << 12) +#define MT9M114_GAIN_DIGITAL_GAIN_MASK (0xf << 12) +#define MT9M114_GAIN_ANALOG_GAIN(n) ((n) << 0) +#define MT9M114_GAIN_ANALOG_GAIN_MASK (0xff << 0) +#define MT9M114_CUSTOMER_REV CCI_REG16(0x31fe) + +/* Monitor registers */ +#define MT9M114_MON_MAJOR_VERSION CCI_REG16(0x8000) +#define MT9M114_MON_MINOR_VERSION CCI_REG16(0x8002) +#define MT9M114_MON_RELEASE_VERSION CCI_REG16(0x8004) + +/* Auto-Exposure Track registers */ +#define MT9M114_AE_TRACK_ALGO CCI_REG16(0xa804) +#define MT9M114_AE_TRACK_EXEC_AUTOMATIC_EXPOSURE BIT(0) +#define MT9M114_AE_TRACK_AE_TRACKING_DAMPENING_SPEED CCI_REG8(0xa80a) + +/* Color Correction Matrix registers */ +#define MT9M114_CCM_ALGO CCI_REG16(0xb404) +#define MT9M114_CCM_EXEC_CALC_CCM_MATRIX BIT(4) +#define MT9M114_CCM_DELTA_GAIN CCI_REG8(0xb42a) + +/* Camera Control registers */ +#define MT9M114_CAM_SENSOR_CFG_Y_ADDR_START CCI_REG16(0xc800) +#define MT9M114_CAM_SENSOR_CFG_X_ADDR_START CCI_REG16(0xc802) +#define MT9M114_CAM_SENSOR_CFG_Y_ADDR_END CCI_REG16(0xc804) +#define MT9M114_CAM_SENSOR_CFG_X_ADDR_END CCI_REG16(0xc806) +#define MT9M114_CAM_SENSOR_CFG_PIXCLK CCI_REG32(0xc808) +#define MT9M114_CAM_SENSOR_CFG_ROW_SPEED CCI_REG16(0xc80c) +#define MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MIN CCI_REG16(0xc80e) +#define MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MAX CCI_REG16(0xc810) +#define MT9M114_CAM_SENSOR_CFG_FRAME_LENGTH_LINES CCI_REG16(0xc812) +#define MT9M114_CAM_SENSOR_CFG_FRAME_LENGTH_LINES_MAX 65535 +#define MT9M114_CAM_SENSOR_CFG_LINE_LENGTH_PCK CCI_REG16(0xc814) +#define MT9M114_CAM_SENSOR_CFG_LINE_LENGTH_PCK_MAX 8191 +#define MT9M114_CAM_SENSOR_CFG_FINE_CORRECTION CCI_REG16(0xc816) +#define MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW CCI_REG16(0xc818) +#define MT9M114_CAM_SENSOR_CFG_REG_0_DATA CCI_REG16(0xc826) +#define MT9M114_CAM_SENSOR_CONTROL_READ_MODE CCI_REG16(0xc834) +#define MT9M114_CAM_SENSOR_CONTROL_HORZ_MIRROR_EN BIT(0) +#define MT9M114_CAM_SENSOR_CONTROL_VERT_FLIP_EN BIT(1) +#define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_NORMAL (0 << 4) +#define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_SKIPPING (1 << 4) +#define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_AVERAGE (2 << 4) +#define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_SUMMING (3 << 4) +#define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_MASK (3 << 4) +#define MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_NORMAL (0 << 8) +#define MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_SKIPPING (1 << 8) +#define MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_SUMMING (3 << 8) +#define MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_MASK (3 << 8) +#define MT9M114_CAM_SENSOR_CONTROL_ANALOG_GAIN CCI_REG16(0xc836) +#define MT9M114_CAM_SENSOR_CONTROL_COARSE_INTEGRATION_TIME CCI_REG16(0xc83c) +#define MT9M114_CAM_SENSOR_CONTROL_FINE_INTEGRATION_TIME CCI_REG16(0xc83e) +#define MT9M114_CAM_MODE_SELECT CCI_REG8(0xc84c) +#define MT9M114_CAM_MODE_SELECT_NORMAL (0 << 0) +#define MT9M114_CAM_MODE_SELECT_LENS_CALIBRATION (1 << 0) +#define MT9M114_CAM_MODE_SELECT_TEST_PATTERN (2 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT CCI_REG8(0xc84d) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_SOLID (1 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_SOLID_BARS (4 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_RANDOM (5 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_FADING_BARS (8 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_WALKING_1S_10B (10 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_WALKING_1S_8B (11 << 0) +#define MT9M114_CAM_MODE_TEST_PATTERN_RED CCI_REG16(0xc84e) +#define MT9M114_CAM_MODE_TEST_PATTERN_GREEN CCI_REG16(0xc850) +#define MT9M114_CAM_MODE_TEST_PATTERN_BLUE CCI_REG16(0xc852) +#define MT9M114_CAM_CROP_WINDOW_XOFFSET CCI_REG16(0xc854) +#define MT9M114_CAM_CROP_WINDOW_YOFFSET CCI_REG16(0xc856) +#define MT9M114_CAM_CROP_WINDOW_WIDTH CCI_REG16(0xc858) +#define MT9M114_CAM_CROP_WINDOW_HEIGHT CCI_REG16(0xc85a) +#define MT9M114_CAM_CROP_CROPMODE CCI_REG8(0xc85c) +#define MT9M114_CAM_CROP_MODE_AE_AUTO_CROP_EN BIT(0) +#define MT9M114_CAM_CROP_MODE_AWB_AUTO_CROP_EN BIT(1) +#define MT9M114_CAM_OUTPUT_WIDTH CCI_REG16(0xc868) +#define MT9M114_CAM_OUTPUT_HEIGHT CCI_REG16(0xc86a) +#define MT9M114_CAM_OUTPUT_FORMAT CCI_REG16(0xc86c) +#define MT9M114_CAM_OUTPUT_FORMAT_SWAP_RED_BLUE BIT(0) +#define MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES BIT(1) +#define MT9M114_CAM_OUTPUT_FORMAT_MONO_ENABLE BIT(2) +#define MT9M114_CAM_OUTPUT_FORMAT_BT656_ENABLE BIT(3) +#define MT9M114_CAM_OUTPUT_FORMAT_BT656_CROP_SCALE_DISABLE BIT(4) +#define MT9M114_CAM_OUTPUT_FORMAT_FVLV_DISABLE BIT(5) +#define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV (0 << 8) +#define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB (1 << 8) +#define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_BAYER (2 << 8) +#define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_NONE (3 << 8) +#define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_MASK (3 << 8) +#define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_RAWR10 (0 << 10) +#define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_PRELSC_8_2 (1 << 10) +#define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_POSTLSC_8_2 (2 << 10) +#define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_PROCESSED8 (3 << 10) +#define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_MASK (3 << 10) +#define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_565RGB (0 << 12) +#define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_555RGB (1 << 12) +#define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_444xRGB (2 << 12) +#define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_444RGBx (3 << 12) +#define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_MASK (3 << 12) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV CCI_REG16(0xc86e) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_CLIP BIT(5) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_AUV_OFFSET BIT(4) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_SELECT_601 BIT(3) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_NORMALISE BIT(2) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_SAMPLING_EVEN_UV (0 << 0) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_SAMPLING_ODD_UV (1 << 0) +#define MT9M114_CAM_OUTPUT_FORMAT_YUV_SAMPLING_EVENU_ODDV (2 << 0) +#define MT9M114_CAM_OUTPUT_Y_OFFSET CCI_REG8(0xc870) +#define MT9M114_CAM_AET_AEMODE CCI_REG8(0xc878) +#define MT9M114_CAM_AET_EXEC_SET_INDOOR BIT(0) +#define MT9M114_CAM_AET_DISCRETE_FRAMERATE BIT(1) +#define MT9M114_CAM_AET_ADAPTATIVE_TARGET_LUMA BIT(2) +#define MT9M114_CAM_AET_ADAPTATIVE_SKIP_FRAMES BIT(3) +#define MT9M114_CAM_AET_SKIP_FRAMES CCI_REG8(0xc879) +#define MT9M114_CAM_AET_TARGET_AVERAGE_LUMA CCI_REG8(0xc87a) +#define MT9M114_CAM_AET_TARGET_AVERAGE_LUMA_DARK CCI_REG8(0xc87b) +#define MT9M114_CAM_AET_BLACK_CLIPPING_TARGET CCI_REG16(0xc87c) +#define MT9M114_CAM_AET_AE_MIN_VIRT_INT_TIME_PCLK CCI_REG16(0xc87e) +#define MT9M114_CAM_AET_AE_MIN_VIRT_DGAIN CCI_REG16(0xc880) +#define MT9M114_CAM_AET_AE_MAX_VIRT_DGAIN CCI_REG16(0xc882) +#define MT9M114_CAM_AET_AE_MIN_VIRT_AGAIN CCI_REG16(0xc884) +#define MT9M114_CAM_AET_AE_MAX_VIRT_AGAIN CCI_REG16(0xc886) +#define MT9M114_CAM_AET_AE_VIRT_GAIN_TH_EG CCI_REG16(0xc888) +#define MT9M114_CAM_AET_AE_EG_GATE_PERCENTAGE CCI_REG8(0xc88a) +#define MT9M114_CAM_AET_FLICKER_FREQ_HZ CCI_REG8(0xc88b) +#define MT9M114_CAM_AET_MAX_FRAME_RATE CCI_REG16(0xc88c) +#define MT9M114_CAM_AET_MIN_FRAME_RATE CCI_REG16(0xc88e) +#define MT9M114_CAM_AET_TARGET_GAIN CCI_REG16(0xc890) +#define MT9M114_CAM_AWB_CCM_L(n) CCI_REG16(0xc892 + (n) * 2) +#define MT9M114_CAM_AWB_CCM_M(n) CCI_REG16(0xc8a4 + (n) * 2) +#define MT9M114_CAM_AWB_CCM_R(n) CCI_REG16(0xc8b6 + (n) * 2) +#define MT9M114_CAM_AWB_CCM_L_RG_GAIN CCI_REG16(0xc8c8) +#define MT9M114_CAM_AWB_CCM_L_BG_GAIN CCI_REG16(0xc8ca) +#define MT9M114_CAM_AWB_CCM_M_RG_GAIN CCI_REG16(0xc8cc) +#define MT9M114_CAM_AWB_CCM_M_BG_GAIN CCI_REG16(0xc8ce) +#define MT9M114_CAM_AWB_CCM_R_RG_GAIN CCI_REG16(0xc8d0) +#define MT9M114_CAM_AWB_CCM_R_BG_GAIN CCI_REG16(0xc8d2) +#define MT9M114_CAM_AWB_CCM_L_CTEMP CCI_REG16(0xc8d4) +#define MT9M114_CAM_AWB_CCM_M_CTEMP CCI_REG16(0xc8d6) +#define MT9M114_CAM_AWB_CCM_R_CTEMP CCI_REG16(0xc8d8) +#define MT9M114_CAM_AWB_AWB_XSCALE CCI_REG8(0xc8f2) +#define MT9M114_CAM_AWB_AWB_YSCALE CCI_REG8(0xc8f3) +#define MT9M114_CAM_AWB_AWB_WEIGHTS(n) CCI_REG16(0xc8f4 + (n) * 2) +#define MT9M114_CAM_AWB_AWB_XSHIFT_PRE_ADJ CCI_REG16(0xc904) +#define MT9M114_CAM_AWB_AWB_YSHIFT_PRE_ADJ CCI_REG16(0xc906) +#define MT9M114_CAM_AWB_AWBMODE CCI_REG8(0xc909) +#define MT9M114_CAM_AWB_MODE_AUTO BIT(1) +#define MT9M114_CAM_AWB_MODE_EXCLUSIVE_AE BIT(0) +#define MT9M114_CAM_AWB_K_R_L CCI_REG8(0xc90c) +#define MT9M114_CAM_AWB_K_G_L CCI_REG8(0xc90d) +#define MT9M114_CAM_AWB_K_B_L CCI_REG8(0xc90e) +#define MT9M114_CAM_AWB_K_R_R CCI_REG8(0xc90f) +#define MT9M114_CAM_AWB_K_G_R CCI_REG8(0xc910) +#define MT9M114_CAM_AWB_K_B_R CCI_REG8(0xc911) +#define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XSTART CCI_REG16(0xc914) +#define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YSTART CCI_REG16(0xc916) +#define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND CCI_REG16(0xc918) +#define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND CCI_REG16(0xc91a) +#define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XSTART CCI_REG16(0xc91c) +#define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YSTART CCI_REG16(0xc91e) +#define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND CCI_REG16(0xc920) +#define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND CCI_REG16(0xc922) +#define MT9M114_CAM_LL_LLMODE CCI_REG16(0xc924) +#define MT9M114_CAM_LL_START_BRIGHTNESS CCI_REG16(0xc926) +#define MT9M114_CAM_LL_STOP_BRIGHTNESS CCI_REG16(0xc928) +#define MT9M114_CAM_LL_START_SATURATION CCI_REG8(0xc92a) +#define MT9M114_CAM_LL_END_SATURATION CCI_REG8(0xc92b) +#define MT9M114_CAM_LL_START_DESATURATION CCI_REG8(0xc92c) +#define MT9M114_CAM_LL_END_DESATURATION CCI_REG8(0xc92d) +#define MT9M114_CAM_LL_START_DEMOSAICING CCI_REG8(0xc92e) +#define MT9M114_CAM_LL_START_AP_GAIN CCI_REG8(0xc92f) +#define MT9M114_CAM_LL_START_AP_THRESH CCI_REG8(0xc930) +#define MT9M114_CAM_LL_STOP_DEMOSAICING CCI_REG8(0xc931) +#define MT9M114_CAM_LL_STOP_AP_GAIN CCI_REG8(0xc932) +#define MT9M114_CAM_LL_STOP_AP_THRESH CCI_REG8(0xc933) +#define MT9M114_CAM_LL_START_NR_RED CCI_REG8(0xc934) +#define MT9M114_CAM_LL_START_NR_GREEN CCI_REG8(0xc935) +#define MT9M114_CAM_LL_START_NR_BLUE CCI_REG8(0xc936) +#define MT9M114_CAM_LL_START_NR_THRESH CCI_REG8(0xc937) +#define MT9M114_CAM_LL_STOP_NR_RED CCI_REG8(0xc938) +#define MT9M114_CAM_LL_STOP_NR_GREEN CCI_REG8(0xc939) +#define MT9M114_CAM_LL_STOP_NR_BLUE CCI_REG8(0xc93a) +#define MT9M114_CAM_LL_STOP_NR_THRESH CCI_REG8(0xc93b) +#define MT9M114_CAM_LL_START_CONTRAST_BM CCI_REG16(0xc93c) +#define MT9M114_CAM_LL_STOP_CONTRAST_BM CCI_REG16(0xc93e) +#define MT9M114_CAM_LL_GAMMA CCI_REG16(0xc940) +#define MT9M114_CAM_LL_START_CONTRAST_GRADIENT CCI_REG8(0xc942) +#define MT9M114_CAM_LL_STOP_CONTRAST_GRADIENT CCI_REG8(0xc943) +#define MT9M114_CAM_LL_START_CONTRAST_LUMA_PERCENTAGE CCI_REG8(0xc944) +#define MT9M114_CAM_LL_STOP_CONTRAST_LUMA_PERCENTAGE CCI_REG8(0xc945) +#define MT9M114_CAM_LL_START_GAIN_METRIC CCI_REG16(0xc946) +#define MT9M114_CAM_LL_STOP_GAIN_METRIC CCI_REG16(0xc948) +#define MT9M114_CAM_LL_START_FADE_TO_BLACK_LUMA CCI_REG16(0xc94a) +#define MT9M114_CAM_LL_STOP_FADE_TO_BLACK_LUMA CCI_REG16(0xc94c) +#define MT9M114_CAM_LL_CLUSTER_DC_TH_BM CCI_REG16(0xc94e) +#define MT9M114_CAM_LL_CLUSTER_DC_GATE_PERCENTAGE CCI_REG8(0xc950) +#define MT9M114_CAM_LL_SUMMING_SENSITIVITY_FACTOR CCI_REG8(0xc951) +#define MT9M114_CAM_LL_START_TARGET_LUMA_BM CCI_REG16(0xc952) +#define MT9M114_CAM_LL_STOP_TARGET_LUMA_BM CCI_REG16(0xc954) +#define MT9M114_CAM_PGA_PGA_CONTROL CCI_REG16(0xc95e) +#define MT9M114_CAM_SYSCTL_PLL_ENABLE CCI_REG8(0xc97e) +#define MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE BIT(0) +#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N CCI_REG16(0xc980) +#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(m, n) (((n) << 8) | (m)) +#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P CCI_REG16(0xc982) +#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(p) ((p) << 8) +#define MT9M114_CAM_PORT_OUTPUT_CONTROL CCI_REG16(0xc984) +#define MT9M114_CAM_PORT_PORT_SELECT_PARALLEL (0 << 0) +#define MT9M114_CAM_PORT_PORT_SELECT_MIPI (1 << 0) +#define MT9M114_CAM_PORT_CLOCK_SLOWDOWN BIT(3) +#define MT9M114_CAM_PORT_TRUNCATE_RAW_BAYER BIT(4) +#define MT9M114_CAM_PORT_PIXCLK_GATE BIT(5) +#define MT9M114_CAM_PORT_CONT_MIPI_CLK BIT(6) +#define MT9M114_CAM_PORT_CHAN_NUM(vc) ((vc) << 8) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_ZERO CCI_REG16(0xc988) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_ZERO_VALUE(n) ((n) << 8) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_EXIT_TRAIL CCI_REG16(0xc98a) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_EXIT_VALUE(n) ((n) << 8) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_TRAIL_VALUE(n) ((n) << 0) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_POST_PRE CCI_REG16(0xc98c) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_POST_VALUE(n) ((n) << 8) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_PRE_VALUE(n) ((n) << 0) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_TRAIL_ZERO CCI_REG16(0xc98e) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_TRAIL_VALUE(n) ((n) << 8) +#define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_ZERO_VALUE(n) ((n) << 0) + +/* System Manager registers */ +#define MT9M114_SYSMGR_NEXT_STATE CCI_REG8(0xdc00) +#define MT9M114_SYSMGR_CURRENT_STATE CCI_REG8(0xdc01) +#define MT9M114_SYSMGR_CMD_STATUS CCI_REG8(0xdc02) + +/* Patch Loader registers */ +#define MT9M114_PATCHLDR_LOADER_ADDRESS CCI_REG16(0xe000) +#define MT9M114_PATCHLDR_PATCH_ID CCI_REG16(0xe002) +#define MT9M114_PATCHLDR_FIRMWARE_ID CCI_REG32(0xe004) +#define MT9M114_PATCHLDR_APPLY_STATUS CCI_REG8(0xe008) +#define MT9M114_PATCHLDR_NUM_PATCHES CCI_REG8(0xe009) +#define MT9M114_PATCHLDR_PATCH_ID_0 CCI_REG16(0xe00a) +#define MT9M114_PATCHLDR_PATCH_ID_1 CCI_REG16(0xe00c) +#define MT9M114_PATCHLDR_PATCH_ID_2 CCI_REG16(0xe00e) +#define MT9M114_PATCHLDR_PATCH_ID_3 CCI_REG16(0xe010) +#define MT9M114_PATCHLDR_PATCH_ID_4 CCI_REG16(0xe012) +#define MT9M114_PATCHLDR_PATCH_ID_5 CCI_REG16(0xe014) +#define MT9M114_PATCHLDR_PATCH_ID_6 CCI_REG16(0xe016) +#define MT9M114_PATCHLDR_PATCH_ID_7 CCI_REG16(0xe018) + +/* SYS_STATE values (for SYSMGR_NEXT_STATE and SYSMGR_CURRENT_STATE) */ +#define MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE 0x28 +#define MT9M114_SYS_STATE_STREAMING 0x31 +#define MT9M114_SYS_STATE_START_STREAMING 0x34 +#define MT9M114_SYS_STATE_ENTER_SUSPEND 0x40 +#define MT9M114_SYS_STATE_SUSPENDED 0x41 +#define MT9M114_SYS_STATE_ENTER_STANDBY 0x50 +#define MT9M114_SYS_STATE_STANDBY 0x52 +#define MT9M114_SYS_STATE_LEAVE_STANDBY 0x54 + +/* Result status of last SET_STATE comamnd */ +#define MT9M114_SET_STATE_RESULT_ENOERR 0x00 +#define MT9M114_SET_STATE_RESULT_EINVAL 0x0c +#define MT9M114_SET_STATE_RESULT_ENOSPC 0x0d + +/* + * The minimum amount of horizontal and vertical blanking is undocumented. The + * minimum values that have been seen in register lists are 303 and 38, use + * them. + * + * Set the default to achieve 1280x960 at 30fps. + */ +#define MT9M114_MIN_HBLANK 303 +#define MT9M114_MIN_VBLANK 38 +#define MT9M114_DEF_HBLANK 323 +#define MT9M114_DEF_VBLANK 39 + +#define MT9M114_DEF_FRAME_RATE 30 +#define MT9M114_MAX_FRAME_RATE 120 + +#define MT9M114_PIXEL_ARRAY_WIDTH 1296U +#define MT9M114_PIXEL_ARRAY_HEIGHT 976U + +/* + * These values are not well documented and are semi-arbitrary. The pixel array + * minimum output size is 8 pixels larger than the minimum scaler cropped input + * width to account for the demosaicing. + */ +#define MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH (32U + 8U) +#define MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT (32U + 8U) +#define MT9M114_SCALER_CROPPED_INPUT_WIDTH 32U +#define MT9M114_SCALER_CROPPED_INPUT_HEIGHT 32U + +/* Indices into the mt9m114.ifp.tpg array. */ +#define MT9M114_TPG_PATTERN 0 +#define MT9M114_TPG_RED 1 +#define MT9M114_TPG_GREEN 2 +#define MT9M114_TPG_BLUE 3 + +/* ----------------------------------------------------------------------------- + * Data Structures + */ + +enum mt9m114_format_flag { + MT9M114_FMT_FLAG_PARALLEL = BIT(0), + MT9M114_FMT_FLAG_CSI2 = BIT(1), +}; + +struct mt9m114_format_info { + u32 code; + u32 output_format; + u32 flags; +}; + +struct mt9m114 { + struct i2c_client *client; + struct regmap *regmap; + + struct clk *clk; + struct gpio_desc *reset; + struct regulator_bulk_data supplies[3]; + struct v4l2_fwnode_endpoint bus_cfg; + + struct { + unsigned int m; + unsigned int n; + unsigned int p; + } pll; + + unsigned int pixrate; + bool streaming; + + /* Pixel Array */ + struct { + struct v4l2_subdev sd; + struct media_pad pad; + + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + } pa; + + /* Image Flow Processor */ + struct { + struct v4l2_subdev sd; + struct media_pad pads[2]; + + struct v4l2_ctrl_handler hdl; + unsigned int frame_rate; + + struct v4l2_ctrl *tpg[4]; + } ifp; +}; + +/* ----------------------------------------------------------------------------- + * Formats + */ + +static const struct mt9m114_format_info mt9m114_format_infos[] = { + { + /* + * The first two entries are used as defaults, for parallel and + * CSI-2 buses respectively. Keep them in that order. + */ + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .flags = MT9M114_FMT_FLAG_PARALLEL, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV, + }, { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .flags = MT9M114_FMT_FLAG_CSI2, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV, + }, { + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .flags = MT9M114_FMT_FLAG_PARALLEL, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV + | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES, + }, { + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .flags = MT9M114_FMT_FLAG_CSI2, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV + | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES, + }, { + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .flags = MT9M114_FMT_FLAG_PARALLEL, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_565RGB + | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB + | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES, + }, { + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .flags = MT9M114_FMT_FLAG_PARALLEL, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_565RGB + | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB, + }, { + .code = MEDIA_BUS_FMT_RGB565_1X16, + .flags = MT9M114_FMT_FLAG_CSI2, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_565RGB + | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB, + }, { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_PROCESSED8 + | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_BAYER, + .flags = MT9M114_FMT_FLAG_PARALLEL | MT9M114_FMT_FLAG_CSI2, + }, { + /* Keep the format compatible with the IFP sink pad last. */ + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .output_format = MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_RAWR10 + | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_BAYER, + .flags = MT9M114_FMT_FLAG_PARALLEL | MT9M114_FMT_FLAG_CSI2, + } +}; + +static const struct mt9m114_format_info * +mt9m114_default_format_info(struct mt9m114 *sensor) +{ + if (sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY) + return &mt9m114_format_infos[1]; + else + return &mt9m114_format_infos[0]; +} + +static const struct mt9m114_format_info * +mt9m114_format_info(struct mt9m114 *sensor, unsigned int pad, u32 code) +{ + const unsigned int num_formats = ARRAY_SIZE(mt9m114_format_infos); + unsigned int flag; + unsigned int i; + + switch (pad) { + case 0: + return &mt9m114_format_infos[num_formats - 1]; + + case 1: + if (sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY) + flag = MT9M114_FMT_FLAG_CSI2; + else + flag = MT9M114_FMT_FLAG_PARALLEL; + + for (i = 0; i < num_formats; ++i) { + const struct mt9m114_format_info *info = + &mt9m114_format_infos[i]; + + if (info->code == code && info->flags & flag) + return info; + } + + return mt9m114_default_format_info(sensor); + + default: + return NULL; + } +} + +/* ----------------------------------------------------------------------------- + * Initialization + */ + +static const struct cci_reg_sequence mt9m114_init[] = { + { MT9M114_RESET_REGISTER, MT9M114_RESET_REGISTER_MASK_BAD | + MT9M114_RESET_REGISTER_LOCK_REG | + 0x0010 }, + + /* Sensor optimization */ + { CCI_REG16(0x316a), 0x8270 }, + { CCI_REG16(0x316c), 0x8270 }, + { CCI_REG16(0x3ed0), 0x2305 }, + { CCI_REG16(0x3ed2), 0x77cf }, + { CCI_REG16(0x316e), 0x8202 }, + { CCI_REG16(0x3180), 0x87ff }, + { CCI_REG16(0x30d4), 0x6080 }, + { CCI_REG16(0xa802), 0x0008 }, + + { CCI_REG16(0x3e14), 0xff39 }, + + /* APGA */ + { MT9M114_CAM_PGA_PGA_CONTROL, 0x0000 }, + + /* Automatic White balance */ + { MT9M114_CAM_AWB_CCM_L(0), 0x0267 }, + { MT9M114_CAM_AWB_CCM_L(1), 0xff1a }, + { MT9M114_CAM_AWB_CCM_L(2), 0xffb3 }, + { MT9M114_CAM_AWB_CCM_L(3), 0xff80 }, + { MT9M114_CAM_AWB_CCM_L(4), 0x0166 }, + { MT9M114_CAM_AWB_CCM_L(5), 0x0003 }, + { MT9M114_CAM_AWB_CCM_L(6), 0xff9a }, + { MT9M114_CAM_AWB_CCM_L(7), 0xfeb4 }, + { MT9M114_CAM_AWB_CCM_L(8), 0x024d }, + { MT9M114_CAM_AWB_CCM_M(0), 0x01bf }, + { MT9M114_CAM_AWB_CCM_M(1), 0xff01 }, + { MT9M114_CAM_AWB_CCM_M(2), 0xfff3 }, + { MT9M114_CAM_AWB_CCM_M(3), 0xff75 }, + { MT9M114_CAM_AWB_CCM_M(4), 0x0198 }, + { MT9M114_CAM_AWB_CCM_M(5), 0xfffd }, + { MT9M114_CAM_AWB_CCM_M(6), 0xff9a }, + { MT9M114_CAM_AWB_CCM_M(7), 0xfee7 }, + { MT9M114_CAM_AWB_CCM_M(8), 0x02a8 }, + { MT9M114_CAM_AWB_CCM_R(0), 0x01d9 }, + { MT9M114_CAM_AWB_CCM_R(1), 0xff26 }, + { MT9M114_CAM_AWB_CCM_R(2), 0xfff3 }, + { MT9M114_CAM_AWB_CCM_R(3), 0xffb3 }, + { MT9M114_CAM_AWB_CCM_R(4), 0x0132 }, + { MT9M114_CAM_AWB_CCM_R(5), 0xffe8 }, + { MT9M114_CAM_AWB_CCM_R(6), 0xffda }, + { MT9M114_CAM_AWB_CCM_R(7), 0xfecd }, + { MT9M114_CAM_AWB_CCM_R(8), 0x02c2 }, + { MT9M114_CAM_AWB_CCM_L_RG_GAIN, 0x0075 }, + { MT9M114_CAM_AWB_CCM_L_BG_GAIN, 0x011c }, + { MT9M114_CAM_AWB_CCM_M_RG_GAIN, 0x009a }, + { MT9M114_CAM_AWB_CCM_M_BG_GAIN, 0x0105 }, + { MT9M114_CAM_AWB_CCM_R_RG_GAIN, 0x00a4 }, + { MT9M114_CAM_AWB_CCM_R_BG_GAIN, 0x00ac }, + { MT9M114_CAM_AWB_CCM_L_CTEMP, 0x0a8c }, + { MT9M114_CAM_AWB_CCM_M_CTEMP, 0x0f0a }, + { MT9M114_CAM_AWB_CCM_R_CTEMP, 0x1964 }, + { MT9M114_CAM_AWB_AWB_XSHIFT_PRE_ADJ, 51 }, + { MT9M114_CAM_AWB_AWB_YSHIFT_PRE_ADJ, 60 }, + { MT9M114_CAM_AWB_AWB_XSCALE, 3 }, + { MT9M114_CAM_AWB_AWB_YSCALE, 2 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(0), 0x0000 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(1), 0x0000 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(2), 0x0000 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(3), 0xe724 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(4), 0x1583 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(5), 0x2045 }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(6), 0x03ff }, + { MT9M114_CAM_AWB_AWB_WEIGHTS(7), 0x007c }, + { MT9M114_CAM_AWB_K_R_L, 0x80 }, + { MT9M114_CAM_AWB_K_G_L, 0x80 }, + { MT9M114_CAM_AWB_K_B_L, 0x80 }, + { MT9M114_CAM_AWB_K_R_R, 0x88 }, + { MT9M114_CAM_AWB_K_G_R, 0x80 }, + { MT9M114_CAM_AWB_K_B_R, 0x80 }, + + /* Low-Light Image Enhancements */ + { MT9M114_CAM_LL_START_BRIGHTNESS, 0x0020 }, + { MT9M114_CAM_LL_STOP_BRIGHTNESS, 0x009a }, + { MT9M114_CAM_LL_START_GAIN_METRIC, 0x0070 }, + { MT9M114_CAM_LL_STOP_GAIN_METRIC, 0x00f3 }, + { MT9M114_CAM_LL_START_CONTRAST_LUMA_PERCENTAGE, 0x20 }, + { MT9M114_CAM_LL_STOP_CONTRAST_LUMA_PERCENTAGE, 0x9a }, + { MT9M114_CAM_LL_START_SATURATION, 0x80 }, + { MT9M114_CAM_LL_END_SATURATION, 0x4b }, + { MT9M114_CAM_LL_START_DESATURATION, 0x00 }, + { MT9M114_CAM_LL_END_DESATURATION, 0xff }, + { MT9M114_CAM_LL_START_DEMOSAICING, 0x3c }, + { MT9M114_CAM_LL_START_AP_GAIN, 0x02 }, + { MT9M114_CAM_LL_START_AP_THRESH, 0x06 }, + { MT9M114_CAM_LL_STOP_DEMOSAICING, 0x64 }, + { MT9M114_CAM_LL_STOP_AP_GAIN, 0x01 }, + { MT9M114_CAM_LL_STOP_AP_THRESH, 0x0c }, + { MT9M114_CAM_LL_START_NR_RED, 0x3c }, + { MT9M114_CAM_LL_START_NR_GREEN, 0x3c }, + { MT9M114_CAM_LL_START_NR_BLUE, 0x3c }, + { MT9M114_CAM_LL_START_NR_THRESH, 0x0f }, + { MT9M114_CAM_LL_STOP_NR_RED, 0x64 }, + { MT9M114_CAM_LL_STOP_NR_GREEN, 0x64 }, + { MT9M114_CAM_LL_STOP_NR_BLUE, 0x64 }, + { MT9M114_CAM_LL_STOP_NR_THRESH, 0x32 }, + { MT9M114_CAM_LL_START_CONTRAST_BM, 0x0020 }, + { MT9M114_CAM_LL_STOP_CONTRAST_BM, 0x009a }, + { MT9M114_CAM_LL_GAMMA, 0x00dc }, + { MT9M114_CAM_LL_START_CONTRAST_GRADIENT, 0x38 }, + { MT9M114_CAM_LL_STOP_CONTRAST_GRADIENT, 0x30 }, + { MT9M114_CAM_LL_START_CONTRAST_LUMA_PERCENTAGE, 0x50 }, + { MT9M114_CAM_LL_STOP_CONTRAST_LUMA_PERCENTAGE, 0x19 }, + { MT9M114_CAM_LL_START_FADE_TO_BLACK_LUMA, 0x0230 }, + { MT9M114_CAM_LL_STOP_FADE_TO_BLACK_LUMA, 0x0010 }, + { MT9M114_CAM_LL_CLUSTER_DC_TH_BM, 0x01cd }, + { MT9M114_CAM_LL_CLUSTER_DC_GATE_PERCENTAGE, 0x05 }, + { MT9M114_CAM_LL_SUMMING_SENSITIVITY_FACTOR, 0x40 }, + + /* Auto-Exposure */ + { MT9M114_CAM_AET_TARGET_AVERAGE_LUMA_DARK, 0x1b }, + { MT9M114_CAM_AET_AEMODE, 0x00 }, + { MT9M114_CAM_AET_TARGET_GAIN, 0x0080 }, + { MT9M114_CAM_AET_AE_MAX_VIRT_AGAIN, 0x0100 }, + { MT9M114_CAM_AET_BLACK_CLIPPING_TARGET, 0x005a }, + + { MT9M114_CCM_DELTA_GAIN, 0x05 }, + { MT9M114_AE_TRACK_AE_TRACKING_DAMPENING_SPEED, 0x20 }, + + /* Pixel array timings and integration time */ + { MT9M114_CAM_SENSOR_CFG_ROW_SPEED, 1 }, + { MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MIN, 219 }, + { MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MAX, 1459 }, + { MT9M114_CAM_SENSOR_CFG_FINE_CORRECTION, 96 }, + { MT9M114_CAM_SENSOR_CFG_REG_0_DATA, 32 }, + + /* Miscellaneous settings */ + { MT9M114_PAD_SLEW, 0x0777 }, +}; + +/* ----------------------------------------------------------------------------- + * Hardware Configuration + */ + +/* Wait for a command to complete. */ +static int mt9m114_poll_command(struct mt9m114 *sensor, u32 command) +{ + unsigned int i; + u64 value; + int ret; + + for (i = 0; i < 100; ++i) { + ret = cci_read(sensor->regmap, MT9M114_COMMAND_REGISTER, &value, + NULL); + if (ret < 0) + return ret; + + if (!(value & command)) + break; + + usleep_range(5000, 6000); + } + + if (value & command) { + dev_err(&sensor->client->dev, "Command %u completion timeout\n", + command); + return -ETIMEDOUT; + } + + if (!(value & MT9M114_COMMAND_REGISTER_OK)) { + dev_err(&sensor->client->dev, "Command %u failed\n", command); + return -EIO; + } + + return 0; +} + +/* Wait for a state to be entered. */ +static int mt9m114_poll_state(struct mt9m114 *sensor, u32 state) +{ + unsigned int i; + u64 value; + int ret; + + for (i = 0; i < 100; ++i) { + ret = cci_read(sensor->regmap, MT9M114_SYSMGR_CURRENT_STATE, + &value, NULL); + if (ret < 0) + return ret; + + if (value == state) + return 0; + + usleep_range(1000, 1500); + } + + dev_err(&sensor->client->dev, "Timeout waiting for state 0x%02x\n", + state); + return -ETIMEDOUT; +} + +static int mt9m114_set_state(struct mt9m114 *sensor, u8 next_state) +{ + int ret = 0; + + /* Set the next desired state and start the state transition. */ + cci_write(sensor->regmap, MT9M114_SYSMGR_NEXT_STATE, next_state, &ret); + cci_write(sensor->regmap, MT9M114_COMMAND_REGISTER, + MT9M114_COMMAND_REGISTER_OK | + MT9M114_COMMAND_REGISTER_SET_STATE, &ret); + if (ret < 0) + return ret; + + /* Wait for the state transition to complete. */ + ret = mt9m114_poll_command(sensor, MT9M114_COMMAND_REGISTER_SET_STATE); + if (ret < 0) + return ret; + + return 0; +} + +static int mt9m114_initialize(struct mt9m114 *sensor) +{ + u32 value; + int ret; + + ret = cci_multi_reg_write(sensor->regmap, mt9m114_init, + ARRAY_SIZE(mt9m114_init), NULL); + if (ret < 0) { + dev_err(&sensor->client->dev, + "Failed to initialize the sensor\n"); + return ret; + } + + /* Configure the PLL. */ + cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_ENABLE, + MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE, &ret); + cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N, + MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(sensor->pll.m, + sensor->pll.n), + &ret); + cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_P, + MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(sensor->pll.p), &ret); + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_PIXCLK, + sensor->pixrate, &ret); + + /* Configure the output mode. */ + if (sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY) { + value = MT9M114_CAM_PORT_PORT_SELECT_MIPI + | MT9M114_CAM_PORT_CHAN_NUM(0) + | 0x8000; + if (!(sensor->bus_cfg.bus.mipi_csi2.flags & + V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) + value |= MT9M114_CAM_PORT_CONT_MIPI_CLK; + } else { + value = MT9M114_CAM_PORT_PORT_SELECT_PARALLEL + | 0x8000; + } + cci_write(sensor->regmap, MT9M114_CAM_PORT_OUTPUT_CONTROL, value, &ret); + if (ret < 0) + return ret; + + ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); + if (ret < 0) + return ret; + + ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_SUSPEND); + if (ret < 0) + return ret; + + return 0; +} + +static int mt9m114_configure(struct mt9m114 *sensor, + struct v4l2_subdev_state *pa_state, + struct v4l2_subdev_state *ifp_state) +{ + const struct v4l2_mbus_framefmt *pa_format; + const struct v4l2_rect *pa_crop; + const struct mt9m114_format_info *ifp_info; + const struct v4l2_mbus_framefmt *ifp_format; + const struct v4l2_rect *ifp_crop; + const struct v4l2_rect *ifp_compose; + unsigned int hratio, vratio; + u64 output_format; + u64 read_mode; + int ret = 0; + + pa_format = v4l2_subdev_get_pad_format(&sensor->pa.sd, pa_state, 0); + pa_crop = v4l2_subdev_get_pad_crop(&sensor->pa.sd, pa_state, 0); + + ifp_format = v4l2_subdev_get_pad_format(&sensor->ifp.sd, ifp_state, 1); + ifp_info = mt9m114_format_info(sensor, 1, ifp_format->code); + ifp_crop = v4l2_subdev_get_pad_crop(&sensor->ifp.sd, ifp_state, 0); + ifp_compose = v4l2_subdev_get_pad_compose(&sensor->ifp.sd, ifp_state, 0); + + ret = cci_read(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, + &read_mode, NULL); + if (ret < 0) + return ret; + + ret = cci_read(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT, + &output_format, NULL); + if (ret < 0) + return ret; + + hratio = pa_crop->width / pa_format->width; + vratio = pa_crop->height / pa_format->height; + + /* + * Pixel array crop and binning. The CAM_SENSOR_CFG_CPIPE_LAST_ROW + * register isn't clearly documented, but is always set to the number + * of active rows minus 4 divided by the vertical binning factor in all + * example sensor modes. + */ + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_START, + pa_crop->left, &ret); + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_START, + pa_crop->top, &ret); + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_END, + pa_crop->width + pa_crop->left - 1, &ret); + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_END, + pa_crop->height + pa_crop->top - 1, &ret); + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW, + (pa_crop->height - 4) / vratio - 1, &ret); + + read_mode &= ~(MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_MASK | + MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_MASK); + + if (hratio > 1) + read_mode |= MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_SUMMING; + if (vratio > 1) + read_mode |= MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_SUMMING; + + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, + read_mode, &ret); + + /* + * Color pipeline (IFP) cropping and scaling. Subtract 4 from the left + * and top coordinates to compensate for the lines and columns removed + * by demosaicing that are taken into account in the crop rectangle but + * not in the hardware. + */ + cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_XOFFSET, + ifp_crop->left - 4, &ret); + cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_YOFFSET, + ifp_crop->top - 4, &ret); + cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_WIDTH, + ifp_crop->width, &ret); + cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_HEIGHT, + ifp_crop->height, &ret); + + cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_WIDTH, + ifp_compose->width, &ret); + cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_HEIGHT, + ifp_compose->height, &ret); + + /* AWB and AE windows, use the full frame. */ + cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XSTART, + 0, &ret); + cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YSTART, + 0, &ret); + cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND, + ifp_compose->width - 1, &ret); + cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND, + ifp_compose->height - 1, &ret); + + cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XSTART, + 0, &ret); + cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YSTART, + 0, &ret); + cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND, + ifp_compose->width / 5 - 1, &ret); + cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND, + ifp_compose->height / 5 - 1, &ret); + + cci_write(sensor->regmap, MT9M114_CAM_CROP_CROPMODE, + MT9M114_CAM_CROP_MODE_AWB_AUTO_CROP_EN | + MT9M114_CAM_CROP_MODE_AE_AUTO_CROP_EN, &ret); + + /* Set the media bus code. */ + output_format &= ~(MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_MASK | + MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_MASK | + MT9M114_CAM_OUTPUT_FORMAT_FORMAT_MASK | + MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES | + MT9M114_CAM_OUTPUT_FORMAT_SWAP_RED_BLUE); + output_format |= ifp_info->output_format; + + cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT, + output_format, &ret); + + return ret; +} + +static int mt9m114_set_frame_rate(struct mt9m114 *sensor) +{ + u16 frame_rate = sensor->ifp.frame_rate << 8; + int ret = 0; + + cci_write(sensor->regmap, MT9M114_CAM_AET_MIN_FRAME_RATE, + frame_rate, &ret); + cci_write(sensor->regmap, MT9M114_CAM_AET_MAX_FRAME_RATE, + frame_rate, &ret); + + return ret; +} + +static int mt9m114_start_streaming(struct mt9m114 *sensor, + struct v4l2_subdev_state *pa_state, + struct v4l2_subdev_state *ifp_state) +{ + int ret; + + ret = pm_runtime_resume_and_get(&sensor->client->dev); + if (ret) + return ret; + + ret = mt9m114_configure(sensor, pa_state, ifp_state); + if (ret) + goto error; + + ret = mt9m114_set_frame_rate(sensor); + if (ret) + goto error; + + ret = __v4l2_ctrl_handler_setup(&sensor->pa.hdl); + if (ret) + goto error; + + ret = __v4l2_ctrl_handler_setup(&sensor->ifp.hdl); + if (ret) + goto error; + + /* + * The Change-Config state is transient and moves to the streaming + * state automatically. + */ + ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); + if (ret) + goto error; + + sensor->streaming = true; + + return 0; + +error: + pm_runtime_mark_last_busy(&sensor->client->dev); + pm_runtime_put_autosuspend(&sensor->client->dev); + + return ret; +} + +static int mt9m114_stop_streaming(struct mt9m114 *sensor) +{ + int ret; + + sensor->streaming = false; + + ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_SUSPEND); + + pm_runtime_mark_last_busy(&sensor->client->dev); + pm_runtime_put_autosuspend(&sensor->client->dev); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * Common Subdev Operations + */ + +static const struct media_entity_operations mt9m114_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* ----------------------------------------------------------------------------- + * Pixel Array Control Operations + */ + +static inline struct mt9m114 *pa_ctrl_to_mt9m114(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct mt9m114, pa.hdl); +} + +static int mt9m114_pa_g_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9m114 *sensor = pa_ctrl_to_mt9m114(ctrl); + u64 value; + int ret; + + if (!pm_runtime_get_if_in_use(&sensor->client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ret = cci_read(sensor->regmap, + MT9M114_CAM_SENSOR_CONTROL_COARSE_INTEGRATION_TIME, + &value, NULL); + if (ret) + break; + + ctrl->val = value; + break; + + case V4L2_CID_ANALOGUE_GAIN: + ret = cci_read(sensor->regmap, + MT9M114_CAM_SENSOR_CONTROL_ANALOG_GAIN, + &value, NULL); + if (ret) + break; + + ctrl->val = value; + break; + + default: + ret = -EINVAL; + break; + } + + pm_runtime_mark_last_busy(&sensor->client->dev); + pm_runtime_put_autosuspend(&sensor->client->dev); + + return ret; +} + +static int mt9m114_pa_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9m114 *sensor = pa_ctrl_to_mt9m114(ctrl); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + int ret = 0; + u64 mask; + + /* V4L2 controls values are applied only when power is up. */ + if (!pm_runtime_get_if_in_use(&sensor->client->dev)) + return 0; + + state = v4l2_subdev_get_locked_active_state(&sensor->pa.sd); + format = v4l2_subdev_get_pad_format(&sensor->pa.sd, state, 0); + + switch (ctrl->id) { + case V4L2_CID_HBLANK: + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_LINE_LENGTH_PCK, + ctrl->val + format->width, &ret); + break; + + case V4L2_CID_VBLANK: + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_FRAME_LENGTH_LINES, + ctrl->val + format->height, &ret); + break; + + case V4L2_CID_EXPOSURE: + cci_write(sensor->regmap, + MT9M114_CAM_SENSOR_CONTROL_COARSE_INTEGRATION_TIME, + ctrl->val, &ret); + break; + + case V4L2_CID_ANALOGUE_GAIN: + /* + * The CAM_SENSOR_CONTROL_ANALOG_GAIN contains linear analog + * gain values that are mapped to the GLOBAL_GAIN register + * values by the sensor firmware. + */ + cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_ANALOG_GAIN, + ctrl->val, &ret); + break; + + case V4L2_CID_HFLIP: + mask = MT9M114_CAM_SENSOR_CONTROL_HORZ_MIRROR_EN; + ret = cci_update_bits(sensor->regmap, + MT9M114_CAM_SENSOR_CONTROL_READ_MODE, + mask, ctrl->val ? mask : 0, NULL); + break; + + case V4L2_CID_VFLIP: + mask = MT9M114_CAM_SENSOR_CONTROL_VERT_FLIP_EN; + ret = cci_update_bits(sensor->regmap, + MT9M114_CAM_SENSOR_CONTROL_READ_MODE, + mask, ctrl->val ? mask : 0, NULL); + break; + + default: + ret = -EINVAL; + break; + } + + pm_runtime_mark_last_busy(&sensor->client->dev); + pm_runtime_put_autosuspend(&sensor->client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops mt9m114_pa_ctrl_ops = { + .g_volatile_ctrl = mt9m114_pa_g_ctrl, + .s_ctrl = mt9m114_pa_s_ctrl, +}; + +static void mt9m114_pa_ctrl_update_exposure(struct mt9m114 *sensor, bool manual) +{ + /* + * Update the volatile flag on the manual exposure and gain controls. + * If the controls have switched to manual, read their current value + * from the hardware to ensure that control read and write operations + * will behave correctly + */ + if (manual) { + mt9m114_pa_g_ctrl(sensor->pa.exposure); + sensor->pa.exposure->cur.val = sensor->pa.exposure->val; + sensor->pa.exposure->flags &= ~V4L2_CTRL_FLAG_VOLATILE; + + mt9m114_pa_g_ctrl(sensor->pa.gain); + sensor->pa.gain->cur.val = sensor->pa.gain->val; + sensor->pa.gain->flags &= ~V4L2_CTRL_FLAG_VOLATILE; + } else { + sensor->pa.exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; + sensor->pa.gain->flags |= V4L2_CTRL_FLAG_VOLATILE; + } +} + +static void mt9m114_pa_ctrl_update_blanking(struct mt9m114 *sensor, + const struct v4l2_mbus_framefmt *format) +{ + unsigned int max_blank; + + /* Update the blanking controls ranges based on the output size. */ + max_blank = MT9M114_CAM_SENSOR_CFG_LINE_LENGTH_PCK_MAX + - format->width; + __v4l2_ctrl_modify_range(sensor->pa.hblank, MT9M114_MIN_HBLANK, + max_blank, 1, MT9M114_DEF_HBLANK); + + max_blank = MT9M114_CAM_SENSOR_CFG_FRAME_LENGTH_LINES_MAX + - format->height; + __v4l2_ctrl_modify_range(sensor->pa.vblank, MT9M114_MIN_VBLANK, + max_blank, 1, MT9M114_DEF_VBLANK); +} + +/* ----------------------------------------------------------------------------- + * Pixel Array Subdev Operations + */ + +static inline struct mt9m114 *pa_to_mt9m114(struct v4l2_subdev *sd) +{ + return container_of(sd, struct mt9m114, pa.sd); +} + +static int mt9m114_pa_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + crop = v4l2_subdev_get_pad_crop(sd, state, 0); + + crop->left = 0; + crop->top = 0; + crop->width = MT9M114_PIXEL_ARRAY_WIDTH; + crop->height = MT9M114_PIXEL_ARRAY_HEIGHT; + + format = v4l2_subdev_get_pad_format(sd, state, 0); + + format->width = MT9M114_PIXEL_ARRAY_WIDTH; + format->height = MT9M114_PIXEL_ARRAY_HEIGHT; + format->code = MEDIA_BUS_FMT_SGRBG10_1X10; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_RAW; + format->ycbcr_enc = V4L2_YCBCR_ENC_601; + format->quantization = V4L2_QUANTIZATION_FULL_RANGE; + format->xfer_func = V4L2_XFER_FUNC_NONE; + + return 0; +} + +static int mt9m114_pa_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int mt9m114_pa_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index > 1) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + return -EINVAL; + + /* Report binning capability through frame size enumeration. */ + fse->min_width = MT9M114_PIXEL_ARRAY_WIDTH / (fse->index + 1); + fse->max_width = MT9M114_PIXEL_ARRAY_WIDTH / (fse->index + 1); + fse->min_height = MT9M114_PIXEL_ARRAY_HEIGHT / (fse->index + 1); + fse->max_height = MT9M114_PIXEL_ARRAY_HEIGHT / (fse->index + 1); + + return 0; +} + +static int mt9m114_pa_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct mt9m114 *sensor = pa_to_mt9m114(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + unsigned int hscale; + unsigned int vscale; + + crop = v4l2_subdev_get_pad_crop(sd, state, fmt->pad); + format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + + /* The sensor can bin horizontally and vertically. */ + hscale = DIV_ROUND_CLOSEST(crop->width, fmt->format.width ? : 1); + vscale = DIV_ROUND_CLOSEST(crop->height, fmt->format.height ? : 1); + format->width = crop->width / clamp(hscale, 1U, 2U); + format->height = crop->height / clamp(vscale, 1U, 2U); + + fmt->format = *format; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) + mt9m114_pa_ctrl_update_blanking(sensor, format); + + return 0; +} + +static int mt9m114_pa_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_get_pad_crop(sd, state, sel->pad); + return 0; + + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = MT9M114_PIXEL_ARRAY_WIDTH; + sel->r.height = MT9M114_PIXEL_ARRAY_HEIGHT; + return 0; + + default: + return -EINVAL; + } +} + +static int mt9m114_pa_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct mt9m114 *sensor = pa_to_mt9m114(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + crop = v4l2_subdev_get_pad_crop(sd, state, sel->pad); + format = v4l2_subdev_get_pad_format(sd, state, sel->pad); + + /* + * Clamp the crop rectangle. The vertical coordinates must be even, and + * the horizontal coordinates must be a multiple of 4. + * + * FIXME: The horizontal coordinates must be a multiple of 8 when + * binning, but binning is configured after setting the selection, so + * we can't know tell here if it will be used. + */ + crop->left = ALIGN(sel->r.left, 4); + crop->top = ALIGN(sel->r.top, 2); + crop->width = clamp_t(unsigned int, ALIGN(sel->r.width, 4), + MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH, + MT9M114_PIXEL_ARRAY_WIDTH - crop->left); + crop->height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), + MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT, + MT9M114_PIXEL_ARRAY_HEIGHT - crop->top); + + sel->r = *crop; + + /* Reset the format. */ + format->width = crop->width; + format->height = crop->height; + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) + mt9m114_pa_ctrl_update_blanking(sensor, format); + + return 0; +} + +static const struct v4l2_subdev_pad_ops mt9m114_pa_pad_ops = { + .init_cfg = mt9m114_pa_init_cfg, + .enum_mbus_code = mt9m114_pa_enum_mbus_code, + .enum_frame_size = mt9m114_pa_enum_framesizes, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = mt9m114_pa_set_fmt, + .get_selection = mt9m114_pa_get_selection, + .set_selection = mt9m114_pa_set_selection, +}; + +static const struct v4l2_subdev_ops mt9m114_pa_ops = { + .pad = &mt9m114_pa_pad_ops, +}; + +static int mt9m114_pa_init(struct mt9m114 *sensor) +{ + struct v4l2_ctrl_handler *hdl = &sensor->pa.hdl; + struct v4l2_subdev *sd = &sensor->pa.sd; + struct media_pad *pads = &sensor->pa.pad; + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + unsigned int max_exposure; + int ret; + + /* Initialize the subdev. */ + v4l2_subdev_init(sd, &mt9m114_pa_ops); + v4l2_i2c_subdev_set_name(sd, sensor->client, NULL, " pixel array"); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->owner = THIS_MODULE; + sd->dev = &sensor->client->dev; + v4l2_set_subdevdata(sd, sensor->client); + + /* Initialize the media entity. */ + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + sd->entity.ops = &mt9m114_entity_ops; + pads[0].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&sd->entity, 1, pads); + if (ret < 0) + return ret; + + /* Initialize the control handler. */ + v4l2_ctrl_handler_init(hdl, 7); + + /* The range of the HBLANK and VBLANK controls will be updated below. */ + sensor->pa.hblank = v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_HBLANK, + MT9M114_DEF_HBLANK, + MT9M114_DEF_HBLANK, 1, + MT9M114_DEF_HBLANK); + sensor->pa.vblank = v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_VBLANK, + MT9M114_DEF_VBLANK, + MT9M114_DEF_VBLANK, 1, + MT9M114_DEF_VBLANK); + + /* + * The maximum coarse integration time is the frame length in lines + * minus two. The default is taken directly from the datasheet, but + * makes little sense as auto-exposure is enabled by default. + */ + max_exposure = MT9M114_PIXEL_ARRAY_HEIGHT + MT9M114_MIN_VBLANK - 2; + sensor->pa.exposure = v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_EXPOSURE, 1, + max_exposure, 1, 16); + if (sensor->pa.exposure) + sensor->pa.exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; + + sensor->pa.gain = v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 1, + 511, 1, 32); + if (sensor->pa.gain) + sensor->pa.gain->flags |= V4L2_CTRL_FLAG_VOLATILE; + + v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_PIXEL_RATE, + sensor->pixrate, sensor->pixrate, 1, + sensor->pixrate); + + v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_HFLIP, + 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl, &mt9m114_pa_ctrl_ops, + V4L2_CID_VFLIP, + 0, 1, 1, 0); + + if (hdl->error) { + ret = hdl->error; + goto error; + } + + sd->state_lock = hdl->lock; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto error; + + /* Update the range of the blanking controls based on the format. */ + state = v4l2_subdev_lock_and_get_active_state(sd); + format = v4l2_subdev_get_pad_format(sd, state, 0); + mt9m114_pa_ctrl_update_blanking(sensor, format); + v4l2_subdev_unlock_state(state); + + sd->ctrl_handler = hdl; + + return 0; + +error: + v4l2_ctrl_handler_free(&sensor->pa.hdl); + media_entity_cleanup(&sensor->pa.sd.entity); + return ret; +} + +static void mt9m114_pa_cleanup(struct mt9m114 *sensor) +{ + v4l2_ctrl_handler_free(&sensor->pa.hdl); + media_entity_cleanup(&sensor->pa.sd.entity); +} + +/* ----------------------------------------------------------------------------- + * Image Flow Processor Control Operations + */ + +static const char * const mt9m114_test_pattern_menu[] = { + "Disabled", + "Solid Color", + "100% Color Bars", + "Pseudo-Random", + "Fade-to-Gray Color Bars", + "Walking Ones 10-bit", + "Walking Ones 8-bit", +}; + +/* Keep in sync with mt9m114_test_pattern_menu */ +static const unsigned int mt9m114_test_pattern_value[] = { + MT9M114_CAM_MODE_TEST_PATTERN_SELECT_SOLID, + MT9M114_CAM_MODE_TEST_PATTERN_SELECT_SOLID_BARS, + MT9M114_CAM_MODE_TEST_PATTERN_SELECT_RANDOM, + MT9M114_CAM_MODE_TEST_PATTERN_SELECT_FADING_BARS, + MT9M114_CAM_MODE_TEST_PATTERN_SELECT_WALKING_1S_10B, + MT9M114_CAM_MODE_TEST_PATTERN_SELECT_WALKING_1S_8B, +}; + +static inline struct mt9m114 *ifp_ctrl_to_mt9m114(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct mt9m114, ifp.hdl); +} + +static int mt9m114_ifp_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9m114 *sensor = ifp_ctrl_to_mt9m114(ctrl); + u32 value; + int ret = 0; + + if (ctrl->id == V4L2_CID_EXPOSURE_AUTO) + mt9m114_pa_ctrl_update_exposure(sensor, + ctrl->val != V4L2_EXPOSURE_AUTO); + + /* V4L2 controls values are applied only when power is up. */ + if (!pm_runtime_get_if_in_use(&sensor->client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + /* Control both the AWB mode and the CCM algorithm. */ + if (ctrl->val) + value = MT9M114_CAM_AWB_MODE_AUTO + | MT9M114_CAM_AWB_MODE_EXCLUSIVE_AE; + else + value = 0; + + cci_write(sensor->regmap, MT9M114_CAM_AWB_AWBMODE, value, &ret); + + if (ctrl->val) + value = MT9M114_CCM_EXEC_CALC_CCM_MATRIX | 0x22; + else + value = 0; + + cci_write(sensor->regmap, MT9M114_CCM_ALGO, value, &ret); + break; + + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->val == V4L2_EXPOSURE_AUTO) + value = MT9M114_AE_TRACK_EXEC_AUTOMATIC_EXPOSURE + | 0x00fe; + else + value = 0; + + cci_write(sensor->regmap, MT9M114_AE_TRACK_ALGO, value, &ret); + if (ret) + break; + + break; + + case V4L2_CID_TEST_PATTERN: + case V4L2_CID_TEST_PATTERN_RED: + case V4L2_CID_TEST_PATTERN_GREENR: + case V4L2_CID_TEST_PATTERN_BLUE: { + unsigned int pattern = sensor->ifp.tpg[MT9M114_TPG_PATTERN]->val; + + if (pattern) { + cci_write(sensor->regmap, MT9M114_CAM_MODE_SELECT, + MT9M114_CAM_MODE_SELECT_TEST_PATTERN, &ret); + cci_write(sensor->regmap, + MT9M114_CAM_MODE_TEST_PATTERN_SELECT, + mt9m114_test_pattern_value[pattern - 1], &ret); + cci_write(sensor->regmap, + MT9M114_CAM_MODE_TEST_PATTERN_RED, + sensor->ifp.tpg[MT9M114_TPG_RED]->val, &ret); + cci_write(sensor->regmap, + MT9M114_CAM_MODE_TEST_PATTERN_GREEN, + sensor->ifp.tpg[MT9M114_TPG_GREEN]->val, &ret); + cci_write(sensor->regmap, + MT9M114_CAM_MODE_TEST_PATTERN_BLUE, + sensor->ifp.tpg[MT9M114_TPG_BLUE]->val, &ret); + } else { + cci_write(sensor->regmap, MT9M114_CAM_MODE_SELECT, + MT9M114_CAM_MODE_SELECT_NORMAL, &ret); + } + + /* + * A Config-Change needs to be issued for the change to take + * effect. If we're not streaming ignore this, the change will + * be applied when the stream is started. + */ + if (ret || !sensor->streaming) + break; + + ret = mt9m114_set_state(sensor, + MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); + break; + } + + default: + ret = -EINVAL; + break; + } + + pm_runtime_mark_last_busy(&sensor->client->dev); + pm_runtime_put_autosuspend(&sensor->client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops mt9m114_ifp_ctrl_ops = { + .s_ctrl = mt9m114_ifp_s_ctrl, +}; + +/* ----------------------------------------------------------------------------- + * Image Flow Processor Subdev Operations + */ + +static inline struct mt9m114 *ifp_to_mt9m114(struct v4l2_subdev *sd) +{ + return container_of(sd, struct mt9m114, ifp.sd); +} + +static int mt9m114_ifp_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + struct v4l2_subdev_state *pa_state; + struct v4l2_subdev_state *ifp_state; + int ret; + + if (!enable) + return mt9m114_stop_streaming(sensor); + + ifp_state = v4l2_subdev_lock_and_get_active_state(&sensor->ifp.sd); + pa_state = v4l2_subdev_lock_and_get_active_state(&sensor->pa.sd); + + ret = mt9m114_start_streaming(sensor, pa_state, ifp_state); + + v4l2_subdev_unlock_state(pa_state); + v4l2_subdev_unlock_state(ifp_state); + + return ret; +} + +static int mt9m114_ifp_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct v4l2_fract *ival = &interval->interval; + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + + mutex_lock(sensor->ifp.hdl.lock); + + ival->numerator = 1; + ival->denominator = sensor->ifp.frame_rate; + + mutex_unlock(sensor->ifp.hdl.lock); + + return 0; +} + +static int mt9m114_ifp_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct v4l2_fract *ival = &interval->interval; + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + int ret = 0; + + mutex_lock(sensor->ifp.hdl.lock); + + if (ival->numerator != 0 && ival->denominator != 0) + sensor->ifp.frame_rate = min_t(unsigned int, + ival->denominator / ival->numerator, + MT9M114_MAX_FRAME_RATE); + else + sensor->ifp.frame_rate = MT9M114_MAX_FRAME_RATE; + + ival->numerator = 1; + ival->denominator = sensor->ifp.frame_rate; + + if (sensor->streaming) + ret = mt9m114_set_frame_rate(sensor); + + mutex_unlock(sensor->ifp.hdl.lock); + + return ret; +} + +static int mt9m114_ifp_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + struct v4l2_rect *compose; + + format = v4l2_subdev_get_pad_format(sd, state, 0); + + format->width = MT9M114_PIXEL_ARRAY_WIDTH; + format->height = MT9M114_PIXEL_ARRAY_HEIGHT; + format->code = MEDIA_BUS_FMT_SGRBG10_1X10; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_RAW; + format->ycbcr_enc = V4L2_YCBCR_ENC_601; + format->quantization = V4L2_QUANTIZATION_FULL_RANGE; + format->xfer_func = V4L2_XFER_FUNC_NONE; + + crop = v4l2_subdev_get_pad_crop(sd, state, 0); + + crop->left = 4; + crop->top = 4; + crop->width = format->width - 8; + crop->height = format->height - 8; + + compose = v4l2_subdev_get_pad_compose(sd, state, 0); + + compose->left = 0; + compose->top = 0; + compose->width = crop->width; + compose->height = crop->height; + + format = v4l2_subdev_get_pad_format(sd, state, 1); + + format->width = compose->width; + format->height = compose->height; + format->code = mt9m114_default_format_info(sensor)->code; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + format->quantization = V4L2_QUANTIZATION_DEFAULT; + format->xfer_func = V4L2_XFER_FUNC_DEFAULT; + + return 0; +} + +static int mt9m114_ifp_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + const unsigned int num_formats = ARRAY_SIZE(mt9m114_format_infos); + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + unsigned int index = 0; + unsigned int flag; + unsigned int i; + + switch (code->pad) { + case 0: + if (code->index != 0) + return -EINVAL; + + code->code = mt9m114_format_infos[num_formats - 1].code; + return 0; + + case 1: + if (sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY) + flag = MT9M114_FMT_FLAG_CSI2; + else + flag = MT9M114_FMT_FLAG_PARALLEL; + + for (i = 0; i < num_formats; ++i) { + const struct mt9m114_format_info *info = + &mt9m114_format_infos[i]; + + if (info->flags & flag) { + if (index == code->index) { + code->code = info->code; + return 0; + } + + index++; + } + } + + return -EINVAL; + + default: + return -EINVAL; + } +} + +static int mt9m114_ifp_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + const struct mt9m114_format_info *info; + + if (fse->index > 0) + return -EINVAL; + + info = mt9m114_format_info(sensor, fse->pad, fse->code); + if (!info || info->code != fse->code) + return -EINVAL; + + if (fse->pad == 0) { + fse->min_width = MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH; + fse->max_width = MT9M114_PIXEL_ARRAY_WIDTH; + fse->min_height = MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT; + fse->max_height = MT9M114_PIXEL_ARRAY_HEIGHT; + } else { + const struct v4l2_rect *crop; + + crop = v4l2_subdev_get_pad_crop(sd, state, 0); + + fse->max_width = crop->width; + fse->max_height = crop->height; + + fse->min_width = fse->max_width / 4; + fse->min_height = fse->max_height / 4; + } + + return 0; +} + +static int mt9m114_ifp_enum_frameintervals(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_interval_enum *fie) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + const struct mt9m114_format_info *info; + + if (fie->index > 0) + return -EINVAL; + + info = mt9m114_format_info(sensor, fie->pad, fie->code); + if (!info || info->code != fie->code) + return -EINVAL; + + fie->interval.numerator = 1; + fie->interval.denominator = MT9M114_MAX_FRAME_RATE; + + return 0; +} + +static int mt9m114_ifp_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_pad_format(sd, state, fmt->pad); + + if (fmt->pad == 0) { + /* Only the size can be changed on the sink pad. */ + format->width = clamp(ALIGN(fmt->format.width, 8), + MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH, + MT9M114_PIXEL_ARRAY_WIDTH); + format->height = clamp(ALIGN(fmt->format.height, 8), + MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT, + MT9M114_PIXEL_ARRAY_HEIGHT); + } else { + const struct mt9m114_format_info *info; + + /* Only the media bus code can be changed on the source pad. */ + info = mt9m114_format_info(sensor, 1, fmt->format.code); + + format->code = info->code; + + /* If the output format is RAW10, bypass the scaler. */ + if (format->code == MEDIA_BUS_FMT_SGRBG10_1X10) + *format = *v4l2_subdev_get_pad_format(sd, state, 0); + } + + fmt->format = *format; + + return 0; +} + +static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + const struct v4l2_mbus_framefmt *format; + const struct v4l2_rect *crop; + int ret = 0; + + /* Crop and compose are only supported on the sink pad. */ + if (sel->pad != 0) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_get_pad_crop(sd, state, 0); + break; + + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + /* + * The crop default and bounds are equal to the sink + * format size minus 4 pixels on each side for demosaicing. + */ + format = v4l2_subdev_get_pad_format(sd, state, 0); + + sel->r.left = 4; + sel->r.top = 4; + sel->r.width = format->width - 8; + sel->r.height = format->height - 8; + break; + + case V4L2_SEL_TGT_COMPOSE: + sel->r = *v4l2_subdev_get_pad_compose(sd, state, 0); + break; + + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + /* + * The compose default and bounds sizes are equal to the sink + * crop rectangle size. + */ + crop = v4l2_subdev_get_pad_crop(sd, state, 0); + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = crop->width; + sel->r.height = crop->height; + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int mt9m114_ifp_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + struct v4l2_rect *compose; + + if (sel->target != V4L2_SEL_TGT_CROP && + sel->target != V4L2_SEL_TGT_COMPOSE) + return -EINVAL; + + /* Crop and compose are only supported on the sink pad. */ + if (sel->pad != 0) + return -EINVAL; + + format = v4l2_subdev_get_pad_format(sd, state, 0); + crop = v4l2_subdev_get_pad_crop(sd, state, 0); + compose = v4l2_subdev_get_pad_compose(sd, state, 0); + + if (sel->target == V4L2_SEL_TGT_CROP) { + /* + * Clamp the crop rectangle. Demosaicing removes 4 pixels on + * each side of the image. + */ + crop->left = clamp_t(unsigned int, ALIGN(sel->r.left, 2), 4, + format->width - 4 - + MT9M114_SCALER_CROPPED_INPUT_WIDTH); + crop->top = clamp_t(unsigned int, ALIGN(sel->r.top, 2), 4, + format->height - 4 - + MT9M114_SCALER_CROPPED_INPUT_HEIGHT); + crop->width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), + MT9M114_SCALER_CROPPED_INPUT_WIDTH, + format->width - 4 - crop->left); + crop->height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), + MT9M114_SCALER_CROPPED_INPUT_HEIGHT, + format->height - 4 - crop->top); + + sel->r = *crop; + + /* Propagate to the compose rectangle. */ + compose->width = crop->width; + compose->height = crop->height; + } else { + /* + * Clamp the compose rectangle. The scaler can only downscale. + */ + compose->left = 0; + compose->top = 0; + compose->width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), + MT9M114_SCALER_CROPPED_INPUT_WIDTH, + crop->width); + compose->height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), + MT9M114_SCALER_CROPPED_INPUT_HEIGHT, + crop->height); + + sel->r = *compose; + } + + /* Propagate the compose rectangle to the source format. */ + format = v4l2_subdev_get_pad_format(sd, state, 1); + format->width = compose->width; + format->height = compose->height; + + return 0; +} + +static void mt9m114_ifp_unregistered(struct v4l2_subdev *sd) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + + v4l2_device_unregister_subdev(&sensor->pa.sd); +} + +static int mt9m114_ifp_registered(struct v4l2_subdev *sd) +{ + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + int ret; + + ret = v4l2_device_register_subdev(sd->v4l2_dev, &sensor->pa.sd); + if (ret < 0) { + dev_err(&sensor->client->dev, + "Failed to register pixel array subdev\n"); + return ret; + } + + ret = media_create_pad_link(&sensor->pa.sd.entity, 0, + &sensor->ifp.sd.entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret < 0) { + dev_err(&sensor->client->dev, + "Failed to link pixel array to ifp\n"); + v4l2_device_unregister_subdev(&sensor->pa.sd); + return ret; + } + + return 0; +} + +static const struct v4l2_subdev_video_ops mt9m114_ifp_video_ops = { + .s_stream = mt9m114_ifp_s_stream, + .g_frame_interval = mt9m114_ifp_g_frame_interval, + .s_frame_interval = mt9m114_ifp_s_frame_interval, +}; + +static const struct v4l2_subdev_pad_ops mt9m114_ifp_pad_ops = { + .init_cfg = mt9m114_ifp_init_cfg, + .enum_mbus_code = mt9m114_ifp_enum_mbus_code, + .enum_frame_size = mt9m114_ifp_enum_framesizes, + .enum_frame_interval = mt9m114_ifp_enum_frameintervals, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = mt9m114_ifp_set_fmt, + .get_selection = mt9m114_ifp_get_selection, + .set_selection = mt9m114_ifp_set_selection, +}; + +static const struct v4l2_subdev_ops mt9m114_ifp_ops = { + .video = &mt9m114_ifp_video_ops, + .pad = &mt9m114_ifp_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops mt9m114_ifp_internal_ops = { + .registered = mt9m114_ifp_registered, + .unregistered = mt9m114_ifp_unregistered, +}; + +static int mt9m114_ifp_init(struct mt9m114 *sensor) +{ + struct v4l2_subdev *sd = &sensor->ifp.sd; + struct media_pad *pads = sensor->ifp.pads; + struct v4l2_ctrl_handler *hdl = &sensor->ifp.hdl; + struct v4l2_ctrl *link_freq; + int ret; + + /* Initialize the subdev. */ + v4l2_i2c_subdev_init(sd, sensor->client, &mt9m114_ifp_ops); + v4l2_i2c_subdev_set_name(sd, sensor->client, NULL, " ifp"); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->internal_ops = &mt9m114_ifp_internal_ops; + + /* Initialize the media entity. */ + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_ISP; + sd->entity.ops = &mt9m114_entity_ops; + pads[0].flags = MEDIA_PAD_FL_SINK; + pads[1].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&sd->entity, 2, pads); + if (ret < 0) + return ret; + + sensor->ifp.frame_rate = MT9M114_DEF_FRAME_RATE; + + /* Initialize the control handler. */ + v4l2_ctrl_handler_init(hdl, 8); + v4l2_ctrl_new_std(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 1); + v4l2_ctrl_new_std_menu(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_EXPOSURE_AUTO, + V4L2_EXPOSURE_MANUAL, 0, + V4L2_EXPOSURE_AUTO); + + link_freq = v4l2_ctrl_new_int_menu(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_LINK_FREQ, + sensor->bus_cfg.nr_of_link_frequencies - 1, + 0, sensor->bus_cfg.link_frequencies); + if (link_freq) + link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_PIXEL_RATE, + sensor->pixrate, sensor->pixrate, 1, + sensor->pixrate); + + sensor->ifp.tpg[MT9M114_TPG_PATTERN] = + v4l2_ctrl_new_std_menu_items(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mt9m114_test_pattern_menu) - 1, + 0, 0, mt9m114_test_pattern_menu); + sensor->ifp.tpg[MT9M114_TPG_RED] = + v4l2_ctrl_new_std(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_TEST_PATTERN_RED, + 0, 1023, 1, 1023); + sensor->ifp.tpg[MT9M114_TPG_GREEN] = + v4l2_ctrl_new_std(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_TEST_PATTERN_GREENR, + 0, 1023, 1, 1023); + sensor->ifp.tpg[MT9M114_TPG_BLUE] = + v4l2_ctrl_new_std(hdl, &mt9m114_ifp_ctrl_ops, + V4L2_CID_TEST_PATTERN_BLUE, + 0, 1023, 1, 1023); + + v4l2_ctrl_cluster(ARRAY_SIZE(sensor->ifp.tpg), sensor->ifp.tpg); + + if (hdl->error) { + ret = hdl->error; + goto error; + } + + sd->ctrl_handler = hdl; + sd->state_lock = hdl->lock; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto error; + + return 0; + +error: + v4l2_ctrl_handler_free(&sensor->ifp.hdl); + media_entity_cleanup(&sensor->ifp.sd.entity); + return ret; +} + +static void mt9m114_ifp_cleanup(struct mt9m114 *sensor) +{ + v4l2_ctrl_handler_free(&sensor->ifp.hdl); + media_entity_cleanup(&sensor->ifp.sd.entity); +} + +/* ----------------------------------------------------------------------------- + * Power Management + */ + +static int mt9m114_power_on(struct mt9m114 *sensor) +{ + int ret; + + /* Enable power and clocks. */ + ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies), + sensor->supplies); + if (ret < 0) + return ret; + + ret = clk_prepare_enable(sensor->clk); + if (ret < 0) + goto error_regulator; + + /* Perform a hard reset if available, or a soft reset otherwise. */ + if (sensor->reset) { + long freq = clk_get_rate(sensor->clk); + unsigned int duration; + + /* + * The minimum duration is 50 clock cycles, thus typically + * around 2µs. Double it to be safe. + */ + duration = DIV_ROUND_UP(2 * 50 * 1000000, freq); + + gpiod_set_value(sensor->reset, 1); + fsleep(duration); + gpiod_set_value(sensor->reset, 0); + } else { + /* + * The power may have just been turned on, we need to wait for + * the sensor to be ready to accept I2C commands. + */ + usleep_range(44500, 50000); + + cci_write(sensor->regmap, MT9M114_RESET_AND_MISC_CONTROL, + MT9M114_RESET_SOC, &ret); + cci_write(sensor->regmap, MT9M114_RESET_AND_MISC_CONTROL, 0, + &ret); + + if (ret < 0) { + dev_err(&sensor->client->dev, "Soft reset failed\n"); + goto error_clock; + } + } + + /* + * Wait for the sensor to be ready to accept I2C commands by polling the + * command register to wait for initialization to complete. + */ + usleep_range(44500, 50000); + + ret = mt9m114_poll_command(sensor, MT9M114_COMMAND_REGISTER_SET_STATE); + if (ret < 0) + goto error_clock; + + if (sensor->bus_cfg.bus_type == V4L2_MBUS_PARALLEL) { + /* + * In parallel mode (OE set to low), the sensor will enter the + * streaming state after initialization. Enter the standby + * manually to stop streaming. + */ + ret = mt9m114_set_state(sensor, + MT9M114_SYS_STATE_ENTER_STANDBY); + if (ret < 0) + goto error_clock; + } + + /* + * Before issuing any Set-State command, we must ensure that the sensor + * reaches the standby mode (either initiated manually above in + * parallel mode, or automatically after reset in MIPI mode). + */ + ret = mt9m114_poll_state(sensor, MT9M114_SYS_STATE_STANDBY); + if (ret < 0) + goto error_clock; + + return 0; + +error_clock: + clk_disable_unprepare(sensor->clk); +error_regulator: + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); + return ret; +} + +static void mt9m114_power_off(struct mt9m114 *sensor) +{ + clk_disable_unprepare(sensor->clk); + regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies); +} + +static int __maybe_unused mt9m114_runtime_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + int ret; + + ret = mt9m114_power_on(sensor); + if (ret) + return ret; + + ret = mt9m114_initialize(sensor); + if (ret) { + mt9m114_power_off(sensor); + return ret; + } + + return 0; +} + +static int __maybe_unused mt9m114_runtime_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + + mt9m114_power_off(sensor); + + return 0; +} + +static const struct dev_pm_ops mt9m114_pm_ops = { + SET_RUNTIME_PM_OPS(mt9m114_runtime_suspend, mt9m114_runtime_resume, NULL) +}; + +/* ----------------------------------------------------------------------------- + * Probe & Remove + */ + +static int mt9m114_clk_init(struct mt9m114 *sensor) +{ + unsigned int link_freq; + + /* Hardcode the PLL multiplier and dividers to default settings. */ + sensor->pll.m = 32; + sensor->pll.n = 1; + sensor->pll.p = 7; + + /* + * Calculate the pixel rate and link frequency. The CSI-2 bus is clocked + * for 16-bit per pixel, transmitted in DDR over a single lane. For + * parallel mode, the sensor ouputs one pixel in two PIXCLK cycles. + */ + sensor->pixrate = clk_get_rate(sensor->clk) * sensor->pll.m + / ((sensor->pll.n + 1) * (sensor->pll.p + 1)); + + link_freq = sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY + ? sensor->pixrate * 8 : sensor->pixrate * 2; + + if (sensor->bus_cfg.nr_of_link_frequencies != 1 || + sensor->bus_cfg.link_frequencies[0] != link_freq) { + dev_err(&sensor->client->dev, "Unsupported DT link-frequencies\n"); + return -EINVAL; + } + + return 0; +} + +static int mt9m114_identify(struct mt9m114 *sensor) +{ + u64 major, minor, release, customer; + u64 value; + int ret; + + ret = cci_read(sensor->regmap, MT9M114_CHIP_ID, &value, NULL); + if (ret) { + dev_err(&sensor->client->dev, "Failed to read chip ID\n"); + return -ENXIO; + } + + if (value != 0x2481) { + dev_err(&sensor->client->dev, "Invalid chip ID 0x%04llx\n", + value); + return -ENXIO; + } + + cci_read(sensor->regmap, MT9M114_MON_MAJOR_VERSION, &major, &ret); + cci_read(sensor->regmap, MT9M114_MON_MINOR_VERSION, &minor, &ret); + cci_read(sensor->regmap, MT9M114_MON_RELEASE_VERSION, &release, &ret); + cci_read(sensor->regmap, MT9M114_CUSTOMER_REV, &customer, &ret); + if (ret) { + dev_err(&sensor->client->dev, "Failed to read version\n"); + return -ENXIO; + } + + dev_dbg(&sensor->client->dev, + "monitor v%llu.%llu.%04llx customer rev 0x%04llx\n", + major, minor, release, customer); + + return 0; +} + +static int mt9m114_parse_dt(struct mt9m114 *sensor) +{ + struct fwnode_handle *fwnode = dev_fwnode(&sensor->client->dev); + struct fwnode_handle *ep; + int ret; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) { + dev_err(&sensor->client->dev, "No endpoint found\n"); + return -EINVAL; + } + + sensor->bus_cfg.bus_type = V4L2_MBUS_UNKNOWN; + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &sensor->bus_cfg); + fwnode_handle_put(ep); + if (ret < 0) { + dev_err(&sensor->client->dev, "Failed to parse endpoint\n"); + goto error; + } + + switch (sensor->bus_cfg.bus_type) { + case V4L2_MBUS_CSI2_DPHY: + case V4L2_MBUS_PARALLEL: + break; + + default: + dev_err(&sensor->client->dev, "unsupported bus type %u\n", + sensor->bus_cfg.bus_type); + ret = -EINVAL; + goto error; + } + + return 0; + +error: + v4l2_fwnode_endpoint_free(&sensor->bus_cfg); + return ret; +} + +static int mt9m114_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct mt9m114 *sensor; + int ret; + + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + sensor->client = client; + + sensor->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(sensor->regmap)) { + dev_err(dev, "Unable to initialize I2C\n"); + return -ENODEV; + } + + ret = mt9m114_parse_dt(sensor); + if (ret < 0) + return ret; + + /* Acquire clocks, GPIOs and regulators. */ + sensor->clk = devm_clk_get(dev, NULL); + if (IS_ERR(sensor->clk)) { + ret = PTR_ERR(sensor->clk); + dev_err_probe(dev, ret, "Failed to get clock\n"); + goto error_ep_free; + } + + sensor->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(sensor->reset)) { + ret = PTR_ERR(sensor->reset); + dev_err_probe(dev, ret, "Failed to get reset GPIO\n"); + goto error_ep_free; + } + + sensor->supplies[0].supply = "vddio"; + sensor->supplies[1].supply = "vdd"; + sensor->supplies[2].supply = "vaa"; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sensor->supplies), + sensor->supplies); + if (ret < 0) { + dev_err_probe(dev, ret, "Failed to get regulators\n"); + goto error_ep_free; + } + + ret = mt9m114_clk_init(sensor); + if (ret) + goto error_ep_free; + + /* + * Identify the sensor. The driver supports runtime PM, but needs to + * work when runtime PM is disabled in the kernel. To that end, power + * the sensor on manually here, and initialize it after identification + * to reach the same state as if resumed through runtime PM. + */ + ret = mt9m114_power_on(sensor); + if (ret < 0) { + dev_err_probe(dev, ret, "Could not power on the device\n"); + goto error_ep_free; + } + + ret = mt9m114_identify(sensor); + if (ret < 0) + goto error_power_off; + + ret = mt9m114_initialize(sensor); + if (ret < 0) + goto error_power_off; + + /* + * Enable runtime PM with autosuspend. As the device has been powered + * manually, mark it as active, and increase the usage count without + * resuming the device. + */ + pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + + /* Initialize the subdevices. */ + ret = mt9m114_pa_init(sensor); + if (ret < 0) + goto error_pm_cleanup; + + ret = mt9m114_ifp_init(sensor); + if (ret < 0) + goto error_pa_cleanup; + + ret = v4l2_async_register_subdev(&sensor->ifp.sd); + if (ret < 0) + goto error_ifp_cleanup; + + /* + * Decrease the PM usage count. The device will get suspended after the + * autosuspend delay, turning the power off. + */ + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; + +error_ifp_cleanup: + mt9m114_ifp_cleanup(sensor); +error_pa_cleanup: + mt9m114_pa_cleanup(sensor); +error_pm_cleanup: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); +error_power_off: + mt9m114_power_off(sensor); +error_ep_free: + v4l2_fwnode_endpoint_free(&sensor->bus_cfg); + return ret; +} + +static void mt9m114_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct mt9m114 *sensor = ifp_to_mt9m114(sd); + struct device *dev = &client->dev; + + v4l2_async_unregister_subdev(&sensor->ifp.sd); + + mt9m114_ifp_cleanup(sensor); + mt9m114_pa_cleanup(sensor); + v4l2_fwnode_endpoint_free(&sensor->bus_cfg); + + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ + pm_runtime_disable(dev); + if (!pm_runtime_status_suspended(dev)) + mt9m114_power_off(sensor); + pm_runtime_set_suspended(dev); +} + +static const struct of_device_id mt9m114_of_ids[] = { + { .compatible = "onnn,mt9m114" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, mt9m114_of_ids); + +static struct i2c_driver mt9m114_driver = { + .driver = { + .name = "mt9m114", + .pm = &mt9m114_pm_ops, + .of_match_table = mt9m114_of_ids, + }, + .probe = mt9m114_probe, + .remove = mt9m114_remove, +}; + +module_i2c_driver(mt9m114_driver); + +MODULE_DESCRIPTION("onsemi MT9M114 Sensor Driver"); +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 774861ba77..37a634b92c 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -49,9 +49,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); struct mt9v011 { struct v4l2_subdev sd; -#ifdef CONFIG_MEDIA_CONTROLLER struct media_pad pad; -#endif struct v4l2_ctrl_handler ctrls; unsigned width, height; unsigned xtal; @@ -483,9 +481,7 @@ static int mt9v011_probe(struct i2c_client *c) u16 version; struct mt9v011 *core; struct v4l2_subdev *sd; -#ifdef CONFIG_MEDIA_CONTROLLER int ret; -#endif /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(c->adapter, @@ -499,14 +495,12 @@ static int mt9v011_probe(struct i2c_client *c) sd = &core->sd; v4l2_i2c_subdev_init(sd, c, &mt9v011_ops); -#ifdef CONFIG_MEDIA_CONTROLLER core->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &core->pad); if (ret < 0) return ret; -#endif /* Check if the sensor is really a MT9V011 */ version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION); diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 00e7bc6e32..1c6f6cea12 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -14,6 +14,7 @@ #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/log2.h> +#include <linux/mod_devicetable.h> #include <linux/mutex.h> #include <linux/of.h> #include <linux/of_graph.h> @@ -1046,7 +1047,6 @@ done: static int mt9v032_probe(struct i2c_client *client) { - const struct i2c_device_id *did = i2c_client_get_device_id(client); struct mt9v032_platform_data *pdata = mt9v032_get_pdata(client); struct mt9v032 *mt9v032; unsigned int i; @@ -1076,7 +1076,7 @@ static int mt9v032_probe(struct i2c_client *client) mutex_init(&mt9v032->power_lock); mt9v032->pdata = pdata; - mt9v032->model = (const void *)did->driver_data; + mt9v032->model = i2c_get_match_data(client); v4l2_ctrl_handler_init(&mt9v032->ctrls, 11 + ARRAY_SIZE(mt9v032_aegc_controls)); @@ -1272,29 +1272,27 @@ static const struct i2c_device_id mt9v032_id[] = { { "mt9v032m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_MONO] }, { "mt9v034", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_COLOR] }, { "mt9v034m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_MONO] }, - { } + { /* Sentinel */ } }; MODULE_DEVICE_TABLE(i2c, mt9v032_id); -#if IS_ENABLED(CONFIG_OF) static const struct of_device_id mt9v032_of_match[] = { - { .compatible = "aptina,mt9v022" }, - { .compatible = "aptina,mt9v022m" }, - { .compatible = "aptina,mt9v024" }, - { .compatible = "aptina,mt9v024m" }, - { .compatible = "aptina,mt9v032" }, - { .compatible = "aptina,mt9v032m" }, - { .compatible = "aptina,mt9v034" }, - { .compatible = "aptina,mt9v034m" }, + { .compatible = "aptina,mt9v022", .data = &mt9v032_models[MT9V032_MODEL_V022_COLOR] }, + { .compatible = "aptina,mt9v022m", .data = &mt9v032_models[MT9V032_MODEL_V022_MONO] }, + { .compatible = "aptina,mt9v024", .data = &mt9v032_models[MT9V032_MODEL_V024_COLOR] }, + { .compatible = "aptina,mt9v024m", .data = &mt9v032_models[MT9V032_MODEL_V024_MONO] }, + { .compatible = "aptina,mt9v032", .data = &mt9v032_models[MT9V032_MODEL_V032_COLOR] }, + { .compatible = "aptina,mt9v032m", .data = &mt9v032_models[MT9V032_MODEL_V032_MONO] }, + { .compatible = "aptina,mt9v034", .data = &mt9v032_models[MT9V032_MODEL_V034_COLOR] }, + { .compatible = "aptina,mt9v034m", .data = &mt9v032_models[MT9V032_MODEL_V034_MONO] }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, mt9v032_of_match); -#endif static struct i2c_driver mt9v032_driver = { .driver = { .name = "mt9v032", - .of_match_table = of_match_ptr(mt9v032_of_match), + .of_match_table = mt9v032_of_match, }, .probe = mt9v032_probe, .remove = mt9v032_remove, diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c index 1f7edc0f5b..f859b49e13 100644 --- a/drivers/media/i2c/mt9v111.c +++ b/drivers/media/i2c/mt9v111.c @@ -121,9 +121,7 @@ struct mt9v111_dev { u8 addr_space; struct v4l2_subdev sd; -#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER) struct media_pad pad; -#endif struct v4l2_ctrl *auto_awb; struct v4l2_ctrl *auto_exp; @@ -797,11 +795,7 @@ static struct v4l2_mbus_framefmt *__mt9v111_get_pad_format( { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: -#if IS_ENABLED(CONFIG_VIDEO_V4L2_SUBDEV_API) return v4l2_subdev_get_try_format(&mt9v111->sd, sd_state, pad); -#else - return &sd_state->pads->try_fmt; -#endif case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9v111->fmt; default: @@ -987,11 +981,9 @@ static const struct v4l2_subdev_ops mt9v111_ops = { .pad = &mt9v111_pad_ops, }; -#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER) static const struct media_entity_operations mt9v111_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; -#endif /* --- V4L2 ctrl --- */ static int mt9v111_s_ctrl(struct v4l2_ctrl *ctrl) @@ -1203,7 +1195,6 @@ static int mt9v111_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&mt9v111->sd, client, &mt9v111_ops); -#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER) mt9v111->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; mt9v111->sd.entity.ops = &mt9v111_subdev_entity_ops; mt9v111->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; @@ -1212,7 +1203,6 @@ static int mt9v111_probe(struct i2c_client *client) ret = media_entity_pads_init(&mt9v111->sd.entity, 1, &mt9v111->pad); if (ret) goto error_free_entity; -#endif ret = mt9v111_chip_probe(mt9v111); if (ret) @@ -1225,9 +1215,7 @@ static int mt9v111_probe(struct i2c_client *client) return 0; error_free_entity: -#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&mt9v111->sd.entity); -#endif error_free_ctrls: v4l2_ctrl_handler_free(&mt9v111->ctrls); @@ -1245,9 +1233,7 @@ static void mt9v111_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); -#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&sd->entity); -#endif v4l2_ctrl_handler_free(&mt9v111->ctrls); diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c index 365ce56845..51378ba16a 100644 --- a/drivers/media/i2c/og01a1b.c +++ b/drivers/media/i2c/og01a1b.c @@ -434,9 +434,6 @@ struct og01a1b { /* To serialize asynchronus callbacks */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; static u64 to_pixel_rate(u32 f_index) @@ -732,14 +729,10 @@ static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (og01a1b->streaming == enable) - return 0; - mutex_lock(&og01a1b->mutex); if (enable) { - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_noidle(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) { mutex_unlock(&og01a1b->mutex); return ret; } @@ -755,50 +748,11 @@ static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - og01a1b->streaming = enable; mutex_unlock(&og01a1b->mutex); return ret; } -static int __maybe_unused og01a1b_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct og01a1b *og01a1b = to_og01a1b(sd); - - mutex_lock(&og01a1b->mutex); - if (og01a1b->streaming) - og01a1b_stop_streaming(og01a1b); - - mutex_unlock(&og01a1b->mutex); - - return 0; -} - -static int __maybe_unused og01a1b_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct og01a1b *og01a1b = to_og01a1b(sd); - int ret; - - mutex_lock(&og01a1b->mutex); - if (og01a1b->streaming) { - ret = og01a1b_start_streaming(og01a1b); - if (ret) { - og01a1b->streaming = false; - og01a1b_stop_streaming(og01a1b); - mutex_unlock(&og01a1b->mutex); - return ret; - } - } - - mutex_unlock(&og01a1b->mutex); - - return 0; -} - static int og01a1b_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -1096,10 +1050,6 @@ probe_error_v4l2_ctrl_handler_free: return ret; } -static const struct dev_pm_ops og01a1b_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(og01a1b_suspend, og01a1b_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id og01a1b_acpi_ids[] = { {"OVTI01AC"}, @@ -1112,7 +1062,6 @@ MODULE_DEVICE_TABLE(acpi, og01a1b_acpi_ids); static struct i2c_driver og01a1b_i2c_driver = { .driver = { .name = "og01a1b", - .pm = &og01a1b_pm_ops, .acpi_match_table = ACPI_PTR(og01a1b_acpi_ids), }, .probe = og01a1b_probe, diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c index 9afe9bf503..02de09edc3 100644 --- a/drivers/media/i2c/ov01a10.c +++ b/drivers/media/i2c/ov01a10.c @@ -287,9 +287,6 @@ struct ov01a10 { struct v4l2_ctrl *exposure; const struct ov01a10_mode *cur_mode; - - /* streaming state */ - bool streaming; }; static inline struct ov01a10 *to_ov01a10(struct v4l2_subdev *subdev) @@ -672,8 +669,6 @@ static int ov01a10_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; state = v4l2_subdev_lock_and_get_active_state(sd); - if (ov01a10->streaming == enable) - goto unlock; if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -685,55 +680,12 @@ static int ov01a10_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); goto unlock; } - - goto done; - } - - ov01a10_stop_streaming(ov01a10); - pm_runtime_put(&client->dev); -done: - ov01a10->streaming = enable; -unlock: - v4l2_subdev_unlock_state(state); - - return ret; -} - -static int __maybe_unused ov01a10_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov01a10 *ov01a10 = to_ov01a10(sd); - struct v4l2_subdev_state *state; - - state = v4l2_subdev_lock_and_get_active_state(sd); - if (ov01a10->streaming) - ov01a10_stop_streaming(ov01a10); - - v4l2_subdev_unlock_state(state); - - return 0; -} - -static int __maybe_unused ov01a10_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov01a10 *ov01a10 = to_ov01a10(sd); - struct v4l2_subdev_state *state; - int ret = 0; - - state = v4l2_subdev_lock_and_get_active_state(sd); - if (!ov01a10->streaming) - goto exit; - - ret = ov01a10_start_streaming(ov01a10); - if (ret) { - ov01a10->streaming = false; + } else { ov01a10_stop_streaming(ov01a10); + pm_runtime_put(&client->dev); } -exit: +unlock: v4l2_subdev_unlock_state(state); return ret; @@ -983,10 +935,6 @@ err_handler_free: return ret; } -static const struct dev_pm_ops ov01a10_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov01a10_suspend, ov01a10_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id ov01a10_acpi_ids[] = { { "OVTI01A0" }, @@ -999,7 +947,6 @@ MODULE_DEVICE_TABLE(acpi, ov01a10_acpi_ids); static struct i2c_driver ov01a10_i2c_driver = { .driver = { .name = "ov01a10", - .pm = &ov01a10_pm_ops, .acpi_match_table = ACPI_PTR(ov01a10_acpi_ids), }, .probe = ov01a10_probe, diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c index 741d977a76..848e47a464 100644 --- a/drivers/media/i2c/ov02a10.c +++ b/drivers/media/i2c/ov02a10.c @@ -570,8 +570,6 @@ unlock_and_return: } static const struct dev_pm_ops ov02a10_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) SET_RUNTIME_PM_OPS(ov02a10_power_off, ov02a10_power_on, NULL) }; diff --git a/drivers/media/i2c/ov08d10.c b/drivers/media/i2c/ov08d10.c index 7d55d4ca24..3d49e3fa8e 100644 --- a/drivers/media/i2c/ov08d10.c +++ b/drivers/media/i2c/ov08d10.c @@ -536,9 +536,6 @@ struct ov08d10 { /* To serialize asynchronus callbacks */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - /* lanes index */ u8 nlanes; @@ -1103,9 +1100,6 @@ static int ov08d10_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (ov08d10->streaming == enable) - return 0; - mutex_lock(&ov08d10->mutex); if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -1125,8 +1119,6 @@ static int ov08d10_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov08d10->streaming = enable; - /* vflip and hflip cannot change during streaming */ __v4l2_ctrl_grab(ov08d10->vflip, enable); __v4l2_ctrl_grab(ov08d10->hflip, enable); @@ -1136,45 +1128,6 @@ static int ov08d10_set_stream(struct v4l2_subdev *sd, int enable) return ret; } -static int __maybe_unused ov08d10_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov08d10 *ov08d10 = to_ov08d10(sd); - - mutex_lock(&ov08d10->mutex); - if (ov08d10->streaming) - ov08d10_stop_streaming(ov08d10); - - mutex_unlock(&ov08d10->mutex); - - return 0; -} - -static int __maybe_unused ov08d10_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov08d10 *ov08d10 = to_ov08d10(sd); - int ret; - - mutex_lock(&ov08d10->mutex); - - if (ov08d10->streaming) { - ret = ov08d10_start_streaming(ov08d10); - if (ret) { - ov08d10->streaming = false; - ov08d10_stop_streaming(ov08d10); - mutex_unlock(&ov08d10->mutex); - return ret; - } - } - - mutex_unlock(&ov08d10->mutex); - - return 0; -} - static int ov08d10_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -1501,10 +1454,6 @@ probe_error_v4l2_ctrl_handler_free: return ret; } -static const struct dev_pm_ops ov08d10_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov08d10_suspend, ov08d10_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id ov08d10_acpi_ids[] = { { "OVTI08D1" }, @@ -1517,7 +1466,6 @@ MODULE_DEVICE_TABLE(acpi, ov08d10_acpi_ids); static struct i2c_driver ov08d10_i2c_driver = { .driver = { .name = "ov08d10", - .pm = &ov08d10_pm_ops, .acpi_match_table = ACPI_PTR(ov08d10_acpi_ids), }, .probe = ov08d10_probe, diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c index 637da4df69..b41b6866a0 100644 --- a/drivers/media/i2c/ov08x40.c +++ b/drivers/media/i2c/ov08x40.c @@ -2432,9 +2432,6 @@ struct ov08x40 { /* Mutex for serialized access */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; #define to_ov08x40(_sd) container_of(_sd, struct ov08x40, sd) @@ -2915,10 +2912,6 @@ static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&ov08x->mutex); - if (ov08x->streaming == enable) { - mutex_unlock(&ov08x->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -2937,7 +2930,6 @@ static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov08x->streaming = enable; mutex_unlock(&ov08x->mutex); return ret; @@ -2950,37 +2942,6 @@ err_unlock: return ret; } -static int __maybe_unused ov08x40_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov08x40 *ov08x = to_ov08x40(sd); - - if (ov08x->streaming) - ov08x40_stop_streaming(ov08x); - - return 0; -} - -static int __maybe_unused ov08x40_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov08x40 *ov08x = to_ov08x40(sd); - int ret; - - if (ov08x->streaming) { - ret = ov08x40_start_streaming(ov08x); - if (ret) - goto error; - } - - return 0; - -error: - ov08x40_stop_streaming(ov08x); - ov08x->streaming = false; - return ret; -} - /* Verify chip ID */ static int ov08x40_identify_module(struct ov08x40 *ov08x) { @@ -3294,10 +3255,6 @@ static void ov08x40_remove(struct i2c_client *client) pm_runtime_set_suspended(&client->dev); } -static const struct dev_pm_ops ov08x40_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov08x40_suspend, ov08x40_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id ov08x40_acpi_ids[] = { {"OVTI08F4"}, @@ -3310,7 +3267,6 @@ MODULE_DEVICE_TABLE(acpi, ov08x40_acpi_ids); static struct i2c_driver ov08x40_i2c_driver = { .driver = { .name = "ov08x40", - .pm = &ov08x40_pm_ops, .acpi_match_table = ACPI_PTR(ov08x40_acpi_ids), }, .probe = ov08x40_probe, diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 35652b3623..4c419014dd 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1044,9 +1044,6 @@ struct ov13858 { /* Mutex for serialized access */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; #define to_ov13858(_sd) container_of(_sd, struct ov13858, sd) @@ -1467,10 +1464,6 @@ static int ov13858_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&ov13858->mutex); - if (ov13858->streaming == enable) { - mutex_unlock(&ov13858->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -1489,7 +1482,6 @@ static int ov13858_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov13858->streaming = enable; mutex_unlock(&ov13858->mutex); return ret; @@ -1502,37 +1494,6 @@ err_unlock: return ret; } -static int __maybe_unused ov13858_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov13858 *ov13858 = to_ov13858(sd); - - if (ov13858->streaming) - ov13858_stop_streaming(ov13858); - - return 0; -} - -static int __maybe_unused ov13858_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov13858 *ov13858 = to_ov13858(sd); - int ret; - - if (ov13858->streaming) { - ret = ov13858_start_streaming(ov13858); - if (ret) - goto error; - } - - return 0; - -error: - ov13858_stop_streaming(ov13858); - ov13858->streaming = false; - return ret; -} - /* Verify chip ID */ static int ov13858_identify_module(struct ov13858 *ov13858) { @@ -1787,10 +1748,6 @@ static const struct i2c_device_id ov13858_id_table[] = { MODULE_DEVICE_TABLE(i2c, ov13858_id_table); -static const struct dev_pm_ops ov13858_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov13858_suspend, ov13858_resume) -}; - #ifdef CONFIG_ACPI static const struct acpi_device_id ov13858_acpi_ids[] = { {"OVTID858"}, @@ -1803,7 +1760,6 @@ MODULE_DEVICE_TABLE(acpi, ov13858_acpi_ids); static struct i2c_driver ov13858_i2c_driver = { .driver = { .name = "ov13858", - .pm = &ov13858_pm_ops, .acpi_match_table = ACPI_PTR(ov13858_acpi_ids), }, .probe = ov13858_probe, diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c index 124eaa4f9e..2793e4675c 100644 --- a/drivers/media/i2c/ov13b10.c +++ b/drivers/media/i2c/ov13b10.c @@ -31,6 +31,7 @@ #define OV13B10_REG_VTS 0x380e #define OV13B10_VTS_30FPS 0x0c7c #define OV13B10_VTS_60FPS 0x063e +#define OV13B10_VTS_120FPS 0x0320 #define OV13B10_VTS_MAX 0x7fff /* HBLANK control - read only */ @@ -468,6 +469,50 @@ static const struct ov13b10_reg mode_2080x1170_regs[] = { {0x5001, 0x0d}, }; +static const struct ov13b10_reg mode_1364x768_120fps_regs[] = { + {0x0305, 0xaf}, + {0x3011, 0x7c}, + {0x3501, 0x03}, + {0x3502, 0x00}, + {0x3662, 0x88}, + {0x3714, 0x28}, + {0x3739, 0x10}, + {0x37c2, 0x14}, + {0x37d9, 0x06}, + {0x37e2, 0x0c}, + {0x37e4, 0x00}, + {0x3800, 0x02}, + {0x3801, 0xe4}, + {0x3802, 0x03}, + {0x3803, 0x48}, + {0x3804, 0x0d}, + {0x3805, 0xab}, + {0x3806, 0x09}, + {0x3807, 0x60}, + {0x3808, 0x05}, + {0x3809, 0x54}, + {0x380a, 0x03}, + {0x380b, 0x00}, + {0x380c, 0x04}, + {0x380d, 0x8e}, + {0x380e, 0x03}, + {0x380f, 0x20}, + {0x3811, 0x07}, + {0x3813, 0x07}, + {0x3814, 0x03}, + {0x3816, 0x03}, + {0x3820, 0x8b}, + {0x3c8c, 0x18}, + {0x4008, 0x00}, + {0x4009, 0x05}, + {0x4050, 0x00}, + {0x4051, 0x05}, + {0x4501, 0x08}, + {0x4505, 0x04}, + {0x5000, 0xfd}, + {0x5001, 0x0d}, +}; + static const char * const ov13b10_test_pattern_menu[] = { "Disabled", "Vertical Color Bar Type 1", @@ -568,7 +613,18 @@ static const struct ov13b10_mode supported_modes[] = { .regs = mode_2080x1170_regs, }, .link_freq_index = OV13B10_LINK_FREQ_INDEX_0, - } + }, + { + .width = 1364, + .height = 768, + .vts_def = OV13B10_VTS_120FPS, + .vts_min = OV13B10_VTS_120FPS, + .link_freq_index = OV13B10_LINK_FREQ_INDEX_0, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1364x768_120fps_regs), + .regs = mode_1364x768_120fps_regs, + }, + }, }; struct ov13b10 { @@ -594,9 +650,6 @@ struct ov13b10 { /* Mutex for serialized access */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - /* True if the device has been identified */ bool identified; }; @@ -1161,10 +1214,6 @@ static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&ov13b->mutex); - if (ov13b->streaming == enable) { - mutex_unlock(&ov13b->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -1183,7 +1232,6 @@ static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov13b->streaming = enable; mutex_unlock(&ov13b->mutex); return ret; @@ -1198,12 +1246,6 @@ err_unlock: static int ov13b10_suspend(struct device *dev) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov13b10 *ov13b = to_ov13b10(sd); - - if (ov13b->streaming) - ov13b10_stop_streaming(ov13b); - ov13b10_power_off(dev); return 0; @@ -1211,29 +1253,7 @@ static int ov13b10_suspend(struct device *dev) static int ov13b10_resume(struct device *dev) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov13b10 *ov13b = to_ov13b10(sd); - int ret; - - ret = ov13b10_power_on(dev); - if (ret) - goto pm_fail; - - if (ov13b->streaming) { - ret = ov13b10_start_streaming(ov13b); - if (ret) - goto stop_streaming; - } - - return 0; - -stop_streaming: - ov13b10_stop_streaming(ov13b); - ov13b10_power_off(dev); -pm_fail: - ov13b->streaming = false; - - return ret; + return ov13b10_power_on(dev); } static const struct v4l2_subdev_video_ops ov13b10_video_ops = { diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index bb6c9863a5..28a01c6eff 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -293,9 +293,7 @@ struct ov2640_win_size { struct ov2640_priv { struct v4l2_subdev subdev; -#if defined(CONFIG_MEDIA_CONTROLLER) struct media_pad pad; -#endif struct v4l2_ctrl_handler hdl; u32 cfmt_code; struct clk *clk; @@ -922,13 +920,9 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, return -EINVAL; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mf = v4l2_subdev_get_try_format(sd, sd_state, 0); format->format = *mf; return 0; -#else - return -EINVAL; -#endif } mf->width = priv->win->width; @@ -1005,7 +999,6 @@ out: static int ov2640_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); const struct ov2640_win_size *win = @@ -1019,7 +1012,7 @@ static int ov2640_init_cfg(struct v4l2_subdev *sd, try_fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; try_fmt->quantization = V4L2_QUANTIZATION_DEFAULT; try_fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; -#endif + return 0; } @@ -1205,17 +1198,14 @@ static int ov2640_probe(struct i2c_client *client) return -ENOMEM; if (client->dev.of_node) { - priv->clk = devm_clk_get(&client->dev, "xvclk"); + priv->clk = devm_clk_get_enabled(&client->dev, "xvclk"); if (IS_ERR(priv->clk)) return PTR_ERR(priv->clk); - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; } ret = ov2640_probe_dt(client, priv); if (ret) - goto err_clk; + return ret; priv->win = ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT); priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; @@ -1239,13 +1229,11 @@ static int ov2640_probe(struct i2c_client *client) ret = priv->hdl.error; goto err_hdl; } -#if defined(CONFIG_MEDIA_CONTROLLER) priv->pad.flags = MEDIA_PAD_FL_SOURCE; priv->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&priv->subdev.entity, 1, &priv->pad); if (ret < 0) goto err_hdl; -#endif ret = ov2640_video_probe(client); if (ret < 0) @@ -1264,8 +1252,6 @@ err_videoprobe: err_hdl: v4l2_ctrl_handler_free(&priv->hdl); mutex_destroy(&priv->lock); -err_clk: - clk_disable_unprepare(priv->clk); return ret; } @@ -1278,7 +1264,6 @@ static void ov2640_remove(struct i2c_client *client) mutex_destroy(&priv->lock); media_entity_cleanup(&priv->subdev.entity); v4l2_device_unregister_subdev(&priv->subdev); - clk_disable_unprepare(priv->clk); } static const struct i2c_device_id ov2640_id[] = { diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 5429bd2eb0..2c3dbe164e 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1031,7 +1031,6 @@ static int ov2659_get_fmt(struct v4l2_subdev *sd, dev_dbg(&client->dev, "ov2659_get_fmt\n"); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *mf; mf = v4l2_subdev_get_try_format(sd, sd_state, 0); @@ -1039,9 +1038,6 @@ static int ov2659_get_fmt(struct v4l2_subdev *sd, fmt->format = *mf; mutex_unlock(&ov2659->lock); return 0; -#else - return -EINVAL; -#endif } mutex_lock(&ov2659->lock); @@ -1113,10 +1109,8 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, mutex_lock(&ov2659->lock); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); *mf = fmt->format; -#endif } else { s64 val; @@ -1306,7 +1300,6 @@ static int ov2659_power_on(struct device *dev) * V4L2 subdev internal operations */ -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1319,7 +1312,6 @@ static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return 0; } -#endif static const struct v4l2_subdev_core_ops ov2659_subdev_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, @@ -1338,7 +1330,6 @@ static const struct v4l2_subdev_pad_ops ov2659_subdev_pad_ops = { .set_fmt = ov2659_set_fmt, }; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static const struct v4l2_subdev_ops ov2659_subdev_ops = { .core = &ov2659_subdev_core_ops, .video = &ov2659_subdev_video_ops, @@ -1348,7 +1339,6 @@ static const struct v4l2_subdev_ops ov2659_subdev_ops = { static const struct v4l2_subdev_internal_ops ov2659_subdev_internal_ops = { .open = ov2659_open, }; -#endif static int ov2659_detect(struct v4l2_subdev *sd) { @@ -1489,15 +1479,12 @@ static int ov2659_probe(struct i2c_client *client) sd = &ov2659->sd; client->flags |= I2C_CLIENT_SCCB; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API - v4l2_i2c_subdev_init(sd, client, &ov2659_subdev_ops); + v4l2_i2c_subdev_init(sd, client, &ov2659_subdev_ops); sd->internal_ops = &ov2659_subdev_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; -#endif -#if defined(CONFIG_MEDIA_CONTROLLER) ov2659->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &ov2659->pad); @@ -1505,7 +1492,6 @@ static int ov2659_probe(struct i2c_client *client) v4l2_ctrl_handler_free(&ov2659->ctrls); return ret; } -#endif mutex_init(&ov2659->lock); diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index 303793e1f9..396583826a 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -91,7 +91,6 @@ struct ov2685 { 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; @@ -513,10 +512,6 @@ static int ov2685_s_stream(struct v4l2_subdev *sd, int on) mutex_lock(&ov2685->mutex); - on = !!on; - if (on == ov2685->streaming) - goto unlock_and_return; - if (on) { ret = pm_runtime_resume_and_get(&ov2685->client->dev); if (ret < 0) @@ -539,15 +534,12 @@ static int ov2685_s_stream(struct v4l2_subdev *sd, int on) 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); @@ -563,7 +555,6 @@ static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return 0; } -#endif static int __maybe_unused ov2685_runtime_resume(struct device *dev) { @@ -660,11 +651,9 @@ static const struct v4l2_subdev_ops ov2685_subdev_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, @@ -833,17 +822,13 @@ static int ov2685_probe(struct i2c_client *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) { @@ -858,9 +843,7 @@ static int ov2685_probe(struct i2c_client *client) 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: @@ -877,9 +860,7 @@ static void ov2685_remove(struct i2c_client *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); diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 41d4f85470..6be22586c3 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -310,7 +310,7 @@ static const struct ov2740_mode supported_modes[] = { { .width = 1932, .height = 1092, - .hts = 1080, + .hts = 2160, .vts_def = OV2740_VTS_DEF, .vts_min = OV2740_VTS_MIN, .reg_list = { @@ -336,12 +336,6 @@ struct ov2740 { /* Current mode */ const struct ov2740_mode *cur_mode; - /* To serialize asynchronus callbacks */ - struct mutex mutex; - - /* Streaming on/off */ - bool streaming; - /* NVM data inforamtion */ struct nvm_data *nvm; @@ -363,15 +357,6 @@ static u64 to_pixel_rate(u32 f_index) return pixel_rate; } -static u64 to_pixels_per_line(u32 hts, u32 f_index) -{ - u64 ppl = hts * to_pixel_rate(f_index); - - do_div(ppl, OV2740_SCLK); - - return ppl; -} - static int ov2740_read_reg(struct ov2740 *ov2740, u16 reg, u16 len, u32 *val) { struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); @@ -582,7 +567,6 @@ static int ov2740_init_controls(struct ov2740 *ov2740) if (ret) return ret; - ctrl_hdlr->lock = &ov2740->mutex; cur_mode = ov2740->cur_mode; size = ARRAY_SIZE(link_freq_menu_items); @@ -605,8 +589,7 @@ static int ov2740_init_controls(struct ov2740 *ov2740) V4L2_CID_VBLANK, vblank_min, vblank_max, 1, vblank_default); - h_blank = to_pixels_per_line(cur_mode->hts, cur_mode->link_freq_index); - h_blank -= cur_mode->width; + h_blank = cur_mode->hts - cur_mode->width; ov2740->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, V4L2_CID_HBLANK, h_blank, h_blank, 1, h_blank); @@ -792,18 +775,15 @@ static int ov2740_set_stream(struct v4l2_subdev *sd, int enable) { struct ov2740 *ov2740 = to_ov2740(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); + struct v4l2_subdev_state *sd_state; int ret = 0; - if (ov2740->streaming == enable) - return 0; + sd_state = v4l2_subdev_lock_and_get_active_state(&ov2740->sd); - mutex_lock(&ov2740->mutex); if (enable) { ret = pm_runtime_resume_and_get(&client->dev); - if (ret < 0) { - mutex_unlock(&ov2740->mutex); - return ret; - } + if (ret < 0) + goto out_unlock; ret = ov2740_start_streaming(ov2740); if (ret) { @@ -816,47 +796,12 @@ static int ov2740_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov2740->streaming = enable; - mutex_unlock(&ov2740->mutex); +out_unlock: + v4l2_subdev_unlock_state(sd_state); return ret; } -static int ov2740_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov2740 *ov2740 = to_ov2740(sd); - - mutex_lock(&ov2740->mutex); - if (ov2740->streaming) - ov2740_stop_streaming(ov2740); - - mutex_unlock(&ov2740->mutex); - - return 0; -} - -static int ov2740_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov2740 *ov2740 = to_ov2740(sd); - int ret = 0; - - mutex_lock(&ov2740->mutex); - if (!ov2740->streaming) - goto exit; - - ret = ov2740_start_streaming(ov2740); - if (ret) { - ov2740->streaming = false; - ov2740_stop_streaming(ov2740); - } - -exit: - mutex_unlock(&ov2740->mutex); - return ret; -} - static int ov2740_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -870,48 +815,25 @@ static int ov2740_set_format(struct v4l2_subdev *sd, height, fmt->format.width, fmt->format.height); - mutex_lock(&ov2740->mutex); ov2740_update_pad_format(mode, &fmt->format); - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format; - } else { - ov2740->cur_mode = mode; - __v4l2_ctrl_s_ctrl(ov2740->link_freq, mode->link_freq_index); - __v4l2_ctrl_s_ctrl_int64(ov2740->pixel_rate, - to_pixel_rate(mode->link_freq_index)); - - /* Update limits and set FPS to default */ - vblank_def = mode->vts_def - mode->height; - __v4l2_ctrl_modify_range(ov2740->vblank, - mode->vts_min - mode->height, - OV2740_VTS_MAX - mode->height, 1, - vblank_def); - __v4l2_ctrl_s_ctrl(ov2740->vblank, vblank_def); - h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) - - mode->width; - __v4l2_ctrl_modify_range(ov2740->hblank, h_blank, h_blank, 1, - h_blank); - } - mutex_unlock(&ov2740->mutex); + *v4l2_subdev_get_pad_format(sd, sd_state, fmt->pad) = fmt->format; - return 0; -} - -static int ov2740_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct ov2740 *ov2740 = to_ov2740(sd); - - mutex_lock(&ov2740->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - fmt->format = *v4l2_subdev_get_try_format(&ov2740->sd, - sd_state, - fmt->pad); - else - ov2740_update_pad_format(ov2740->cur_mode, &fmt->format); + return 0; - mutex_unlock(&ov2740->mutex); + ov2740->cur_mode = mode; + __v4l2_ctrl_s_ctrl(ov2740->link_freq, mode->link_freq_index); + __v4l2_ctrl_s_ctrl_int64(ov2740->pixel_rate, + to_pixel_rate(mode->link_freq_index)); + + /* Update limits and set FPS to default */ + vblank_def = mode->vts_def - mode->height; + __v4l2_ctrl_modify_range(ov2740->vblank, + mode->vts_min - mode->height, + OV2740_VTS_MAX - mode->height, 1, vblank_def); + __v4l2_ctrl_s_ctrl(ov2740->vblank, vblank_def); + h_blank = mode->hts - mode->width; + __v4l2_ctrl_modify_range(ov2740->hblank, h_blank, h_blank, 1, h_blank); return 0; } @@ -946,14 +868,11 @@ static int ov2740_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int ov2740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +static int ov2740_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { - struct ov2740 *ov2740 = to_ov2740(sd); - - mutex_lock(&ov2740->mutex); ov2740_update_pad_format(&supported_modes[0], - v4l2_subdev_get_try_format(sd, fh->state, 0)); - mutex_unlock(&ov2740->mutex); + v4l2_subdev_get_pad_format(sd, sd_state, 0)); return 0; } @@ -963,10 +882,11 @@ static const struct v4l2_subdev_video_ops ov2740_video_ops = { }; static const struct v4l2_subdev_pad_ops ov2740_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = ov2740_set_format, - .get_fmt = ov2740_get_format, .enum_mbus_code = ov2740_enum_mbus_code, .enum_frame_size = ov2740_enum_frame_size, + .init_cfg = ov2740_init_cfg, }; static const struct v4l2_subdev_ops ov2740_subdev_ops = { @@ -978,10 +898,6 @@ static const struct media_entity_operations ov2740_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; -static const struct v4l2_subdev_internal_ops ov2740_internal_ops = { - .open = ov2740_open, -}; - static int ov2740_check_hwcfg(struct device *dev) { struct fwnode_handle *ep; @@ -1004,7 +920,7 @@ static int ov2740_check_hwcfg(struct device *dev) ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) - return -ENXIO; + return -EPROBE_DEFER; ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); fwnode_handle_put(ep); @@ -1047,13 +963,12 @@ check_hwcfg_error: static void ov2740_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2740 *ov2740 = to_ov2740(sd); v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); + v4l2_subdev_cleanup(sd); v4l2_ctrl_handler_free(sd->ctrl_handler); pm_runtime_disable(&client->dev); - mutex_destroy(&ov2740->mutex); } static int ov2740_nvmem_read(void *priv, unsigned int off, void *val, @@ -1062,9 +977,11 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val, struct nvm_data *nvm = priv; struct device *dev = regmap_get_device(nvm->regmap); struct ov2740 *ov2740 = to_ov2740(dev_get_drvdata(dev)); + struct v4l2_subdev_state *sd_state; int ret = 0; - mutex_lock(&ov2740->mutex); + /* Serialise sensor access */ + sd_state = v4l2_subdev_lock_and_get_active_state(&ov2740->sd); if (nvm->nvm_buffer) { memcpy(val, nvm->nvm_buffer + off, count); @@ -1082,7 +999,7 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val, pm_runtime_put(dev); exit: - mutex_unlock(&ov2740->mutex); + v4l2_subdev_unlock_state(sd_state); return ret; } @@ -1153,7 +1070,6 @@ static int ov2740_probe(struct i2c_client *client) return dev_err_probe(dev, ret, "failed to find sensor\n"); } - mutex_init(&ov2740->mutex); ov2740->cur_mode = &supported_modes[0]; ret = ov2740_init_controls(ov2740); if (ret) { @@ -1161,7 +1077,7 @@ static int ov2740_probe(struct i2c_client *client) goto probe_error_v4l2_ctrl_handler_free; } - ov2740->sd.internal_ops = &ov2740_internal_ops; + ov2740->sd.state_lock = ov2740->ctrl_handler.lock; ov2740->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov2740->sd.entity.ops = &ov2740_subdev_entity_ops; ov2740->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; @@ -1172,36 +1088,42 @@ static int ov2740_probe(struct i2c_client *client) goto probe_error_v4l2_ctrl_handler_free; } + ret = v4l2_subdev_init_finalize(&ov2740->sd); + if (ret) + goto probe_error_media_entity_cleanup; + + /* Set the device's state to active if it's in D0 state. */ + if (full_power) + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + ret = v4l2_async_register_subdev_sensor(&ov2740->sd); if (ret < 0) { dev_err_probe(dev, ret, "failed to register V4L2 subdev\n"); - goto probe_error_media_entity_cleanup; + goto probe_error_v4l2_subdev_cleanup; } ret = ov2740_register_nvmem(client, ov2740); if (ret) dev_warn(&client->dev, "register nvmem failed, ret %d\n", ret); - /* Set the device's state to active if it's in D0 state. */ - if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); - return 0; +probe_error_v4l2_subdev_cleanup: + v4l2_subdev_cleanup(&ov2740->sd); + probe_error_media_entity_cleanup: media_entity_cleanup(&ov2740->sd.entity); + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); probe_error_v4l2_ctrl_handler_free: v4l2_ctrl_handler_free(ov2740->sd.ctrl_handler); - mutex_destroy(&ov2740->mutex); return ret; } -static DEFINE_SIMPLE_DEV_PM_OPS(ov2740_pm_ops, ov2740_suspend, ov2740_resume); - static const struct acpi_device_id ov2740_acpi_ids[] = { {"INT3474"}, {} @@ -1212,7 +1134,6 @@ MODULE_DEVICE_TABLE(acpi, ov2740_acpi_ids); static struct i2c_driver ov2740_i2c_driver = { .driver = { .name = "ov2740", - .pm = pm_sleep_ptr(&ov2740_pm_ops), .acpi_match_table = ov2740_acpi_ids, }, .probe = ov2740_probe, diff --git a/drivers/media/i2c/ov4689.c b/drivers/media/i2c/ov4689.c index fda217d2cb..3bd972a822 100644 --- a/drivers/media/i2c/ov4689.c +++ b/drivers/media/i2c/ov4689.c @@ -99,8 +99,7 @@ struct ov4689 { u32 clock_rate; - struct mutex mutex; /* lock to protect streaming, ctrls and cur_mode */ - bool streaming; + struct mutex mutex; /* lock to protect ctrls and cur_mode */ struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl *exposure; @@ -468,10 +467,6 @@ static int ov4689_s_stream(struct v4l2_subdev *sd, int on) mutex_lock(&ov4689->mutex); - on = !!on; - if (on == ov4689->streaming) - goto unlock_and_return; - if (on) { ret = pm_runtime_resume_and_get(&client->dev); if (ret < 0) @@ -504,8 +499,6 @@ static int ov4689_s_stream(struct v4l2_subdev *sd, int on) pm_runtime_put(&client->dev); } - ov4689->streaming = on; - unlock_and_return: mutex_unlock(&ov4689->mutex); diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index 8de398423b..dcfe3129c6 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -109,7 +109,6 @@ struct ov5647 { struct v4l2_ctrl *hblank; struct v4l2_ctrl *vblank; struct v4l2_ctrl *exposure; - bool streaming; }; static inline struct ov5647 *to_sensor(struct v4l2_subdev *sd) @@ -898,10 +897,6 @@ static int ov5647_s_stream(struct v4l2_subdev *sd, int enable) int ret; mutex_lock(&sensor->lock); - if (sensor->streaming == enable) { - mutex_unlock(&sensor->lock); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -922,7 +917,6 @@ static int ov5647_s_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - sensor->streaming = enable; mutex_unlock(&sensor->lock); return 0; diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 29e773a997..e80db3ecd4 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -1882,8 +1882,6 @@ struct ov5670 { /* To serialize asynchronus callbacks */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; /* True if the device has been identified */ bool identified; }; @@ -2471,8 +2469,6 @@ static int ov5670_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&ov5670->mutex); - if (ov5670->streaming == enable) - goto unlock_and_return; if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -2486,7 +2482,6 @@ static int ov5670_set_stream(struct v4l2_subdev *sd, int enable) ret = ov5670_stop_streaming(ov5670); pm_runtime_put(&client->dev); } - ov5670->streaming = enable; goto unlock_and_return; error: @@ -2541,34 +2536,6 @@ static int __maybe_unused ov5670_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused ov5670_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov5670 *ov5670 = to_ov5670(sd); - - if (ov5670->streaming) - ov5670_stop_streaming(ov5670); - - return 0; -} - -static int __maybe_unused ov5670_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov5670 *ov5670 = to_ov5670(sd); - int ret; - - if (ov5670->streaming) { - ret = ov5670_start_streaming(ov5670); - if (ret) { - ov5670_stop_streaming(ov5670); - return ret; - } - } - - return 0; -} - static const struct v4l2_subdev_core_ops ov5670_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, @@ -2771,8 +2738,6 @@ static int ov5670_probe(struct i2c_client *client) goto error_handler_free; } - ov5670->streaming = false; - /* Set the device's state to active if it's in D0 state. */ if (full_power) pm_runtime_set_active(&client->dev); @@ -2827,7 +2792,6 @@ static void ov5670_remove(struct i2c_client *client) } static const struct dev_pm_ops ov5670_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov5670_suspend, ov5670_resume) SET_RUNTIME_PM_OPS(ov5670_runtime_suspend, ov5670_runtime_resume, NULL) }; diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index d5a2a5f823..e63d9d402d 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -513,9 +513,6 @@ struct ov5675 { /* To serialize asynchronus callbacks */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - /* True if the device has been identified */ bool identified; }; @@ -949,9 +946,6 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (ov5675->streaming == enable) - return 0; - mutex_lock(&ov5675->mutex); if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -971,7 +965,6 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov5675->streaming = enable; mutex_unlock(&ov5675->mutex); return ret; @@ -1027,42 +1020,6 @@ static int ov5675_power_on(struct device *dev) return 0; } -static int __maybe_unused ov5675_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov5675 *ov5675 = to_ov5675(sd); - - mutex_lock(&ov5675->mutex); - if (ov5675->streaming) - ov5675_stop_streaming(ov5675); - - mutex_unlock(&ov5675->mutex); - - return 0; -} - -static int __maybe_unused ov5675_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov5675 *ov5675 = to_ov5675(sd); - int ret; - - mutex_lock(&ov5675->mutex); - if (ov5675->streaming) { - ret = ov5675_start_streaming(ov5675); - if (ret) { - ov5675->streaming = false; - ov5675_stop_streaming(ov5675); - mutex_unlock(&ov5675->mutex); - return ret; - } - } - - mutex_unlock(&ov5675->mutex); - - return 0; -} - static int ov5675_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -1409,7 +1366,6 @@ probe_power_off: } static const struct dev_pm_ops ov5675_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov5675_suspend, ov5675_resume) SET_RUNTIME_PM_OPS(ov5675_power_off, ov5675_power_on, NULL) }; diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c index 488ee6d9d3..819425e213 100644 --- a/drivers/media/i2c/ov5693.c +++ b/drivers/media/i2c/ov5693.c @@ -154,7 +154,6 @@ struct ov5693_device { unsigned int inc_y_odd; unsigned int vts; } mode; - bool streaming; struct v4l2_subdev sd; struct media_pad pad; @@ -975,9 +974,9 @@ static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) int ret; if (enable) { - ret = pm_runtime_get_sync(ov5693->dev); - if (ret < 0) - goto err_power_down; + ret = pm_runtime_resume_and_get(ov5693->dev); + if (ret) + return ret; mutex_lock(&ov5693->lock); ret = __v4l2_ctrl_handler_setup(&ov5693->ctrls.handler); @@ -996,8 +995,6 @@ static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) if (ret) goto err_power_down; - ov5693->streaming = !!enable; - if (!enable) pm_runtime_put(ov5693->dev); diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index 3023b72541..c8f57ce157 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -108,7 +108,6 @@ struct ov5695 { struct v4l2_ctrl *vblank; struct v4l2_ctrl *test_pattern; struct mutex mutex; - bool streaming; const struct ov5695_mode *cur_mode; }; @@ -821,9 +820,7 @@ static int ov5695_set_fmt(struct v4l2_subdev *sd, fmt->format.height = mode->height; fmt->format.field = V4L2_FIELD_NONE; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format; -#endif } else { ov5695->cur_mode = mode; h_blank = mode->hts_def - mode->width; @@ -849,13 +846,8 @@ static int ov5695_get_fmt(struct v4l2_subdev *sd, mutex_lock(&ov5695->mutex); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API fmt->format = *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); -#else - mutex_unlock(&ov5695->mutex); - return -EINVAL; -#endif } else { fmt->format.width = mode->width; fmt->format.height = mode->height; @@ -942,9 +934,6 @@ static int ov5695_s_stream(struct v4l2_subdev *sd, int on) int ret = 0; mutex_lock(&ov5695->mutex); - on = !!on; - if (on == ov5695->streaming) - goto unlock_and_return; if (on) { ret = pm_runtime_resume_and_get(&client->dev); @@ -962,8 +951,6 @@ static int ov5695_s_stream(struct v4l2_subdev *sd, int on) pm_runtime_put(&client->dev); } - ov5695->streaming = on; - unlock_and_return: mutex_unlock(&ov5695->mutex); @@ -1048,7 +1035,6 @@ static int __maybe_unused ov5695_runtime_suspend(struct device *dev) return 0; } -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static int ov5695_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct ov5695 *ov5695 = to_ov5695(sd); @@ -1068,18 +1054,15 @@ static int ov5695_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return 0; } -#endif static const struct dev_pm_ops ov5695_pm_ops = { SET_RUNTIME_PM_OPS(ov5695_runtime_suspend, ov5695_runtime_resume, NULL) }; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static const struct v4l2_subdev_internal_ops ov5695_internal_ops = { .open = ov5695_open, }; -#endif static const struct v4l2_subdev_video_ops ov5695_video_ops = { .s_stream = ov5695_s_stream, @@ -1322,17 +1305,13 @@ static int ov5695_probe(struct i2c_client *client) if (ret) goto err_power_off; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API sd->internal_ops = &ov5695_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -#endif -#if defined(CONFIG_MEDIA_CONTROLLER) ov5695->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &ov5695->pad); if (ret < 0) goto err_power_off; -#endif ret = v4l2_async_register_subdev_sensor(sd); if (ret) { @@ -1347,9 +1326,7 @@ static int ov5695_probe(struct i2c_client *client) return 0; err_clean_entity: -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&sd->entity); -#endif err_power_off: __ov5695_power_off(ov5695); err_free_handler: @@ -1366,9 +1343,7 @@ static void ov5695_remove(struct i2c_client *client) struct ov5695 *ov5695 = to_ov5695(sd); v4l2_async_unregister_subdev(sd); -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&sd->entity); -#endif v4l2_ctrl_handler_free(&ov5695->ctrl_handler); mutex_destroy(&ov5695->mutex); diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c index 675fb37a6f..6582cc0e23 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1340,9 +1340,11 @@ static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable) mutex_lock(&ov7251->lock); if (enable) { - ret = pm_runtime_get_sync(ov7251->dev); - if (ret < 0) - goto err_power_down; + ret = pm_runtime_resume_and_get(ov7251->dev); + if (ret) { + mutex_unlock(&ov7251->lock); + return ret; + } ret = ov7251_pll_configure(ov7251); if (ret) { diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 2f55491ef5..172483597c 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -10,6 +10,7 @@ */ #include <linux/clk.h> #include <linux/init.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/i2c.h> @@ -186,11 +187,6 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); #define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ #define REG_BD60MAX 0xab /* 60hz banding step limit */ -enum ov7670_model { - MODEL_OV7670 = 0, - MODEL_OV7675, -}; - struct ov7670_win_size { int width; int height; @@ -217,9 +213,7 @@ struct ov7670_devtype { struct ov7670_format_struct; /* coming later */ struct ov7670_info { struct v4l2_subdev sd; -#if defined(CONFIG_MEDIA_CONTROLLER) struct media_pad pad; -#endif struct v4l2_ctrl_handler hdl; struct { /* gain cluster */ @@ -1108,9 +1102,7 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *format) { struct ov7670_info *info = to_state(sd); -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *mbus_fmt; -#endif int ret; if (format->pad) @@ -1120,11 +1112,9 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL); if (ret) return ret; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); *mbus_fmt = format->format; -#endif return 0; } @@ -1148,18 +1138,12 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *format) { struct ov7670_info *info = to_state(sd); -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *mbus_fmt; -#endif if (format->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); format->format = *mbus_fmt; return 0; -#else - return -EINVAL; -#endif } else { format->format = info->format; } @@ -1720,7 +1704,6 @@ static void ov7670_get_default_format(struct v4l2_subdev *sd, format->field = V4L2_FIELD_NONE; } -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *format = @@ -1730,7 +1713,6 @@ static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return 0; } -#endif /* ----------------------------------------------------------------------- */ @@ -1766,29 +1748,12 @@ static const struct v4l2_subdev_ops ov7670_ops = { .pad = &ov7670_pad_ops, }; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static const struct v4l2_subdev_internal_ops ov7670_subdev_internal_ops = { .open = ov7670_open, }; -#endif /* ----------------------------------------------------------------------- */ -static const struct ov7670_devtype ov7670_devdata[] = { - [MODEL_OV7670] = { - .win_sizes = ov7670_win_sizes, - .n_win_sizes = ARRAY_SIZE(ov7670_win_sizes), - .set_framerate = ov7670_set_framerate_legacy, - .get_framerate = ov7670_get_framerate_legacy, - }, - [MODEL_OV7675] = { - .win_sizes = ov7675_win_sizes, - .n_win_sizes = ARRAY_SIZE(ov7675_win_sizes), - .set_framerate = ov7675_set_framerate, - .get_framerate = ov7675_get_framerate, - }, -}; - static int ov7670_init_gpio(struct i2c_client *client, struct ov7670_info *info) { info->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", @@ -1849,7 +1814,6 @@ static int ov7670_parse_dt(struct device *dev, static int ov7670_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct v4l2_fract tpf; struct v4l2_subdev *sd; struct ov7670_info *info; @@ -1861,10 +1825,8 @@ static int ov7670_probe(struct i2c_client *client) sd = &info->sd; v4l2_i2c_subdev_init(sd, client, &ov7670_ops); -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API sd->internal_ops = &ov7670_subdev_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; -#endif info->clock_speed = 30; /* default: a guess */ @@ -1923,7 +1885,7 @@ static int ov7670_probe(struct i2c_client *client) v4l_info(client, "chip found @ 0x%02x (%s)\n", client->addr << 1, client->adapter->name); - info->devtype = &ov7670_devdata[id->driver_data]; + info->devtype = i2c_get_match_data(client); info->fmt = &ov7670_formats[0]; info->wsize = &info->devtype->win_sizes[0]; @@ -1977,13 +1939,11 @@ static int ov7670_probe(struct i2c_client *client) V4L2_EXPOSURE_MANUAL, false); v4l2_ctrl_cluster(2, &info->saturation); -#if defined(CONFIG_MEDIA_CONTROLLER) info->pad.flags = MEDIA_PAD_FL_SOURCE; info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); if (ret < 0) goto hdl_free; -#endif v4l2_ctrl_handler_setup(&info->hdl); @@ -2013,25 +1973,37 @@ static void ov7670_remove(struct i2c_client *client) media_entity_cleanup(&info->sd.entity); } +static const struct ov7670_devtype ov7670_devdata = { + .win_sizes = ov7670_win_sizes, + .n_win_sizes = ARRAY_SIZE(ov7670_win_sizes), + .set_framerate = ov7670_set_framerate_legacy, + .get_framerate = ov7670_get_framerate_legacy, +}; + +static const struct ov7670_devtype ov7675_devdata = { + .win_sizes = ov7675_win_sizes, + .n_win_sizes = ARRAY_SIZE(ov7675_win_sizes), + .set_framerate = ov7675_set_framerate, + .get_framerate = ov7675_get_framerate, +}; + static const struct i2c_device_id ov7670_id[] = { - { "ov7670", MODEL_OV7670 }, - { "ov7675", MODEL_OV7675 }, - { } + { "ov7670", (kernel_ulong_t)&ov7670_devdata }, + { "ov7675", (kernel_ulong_t)&ov7675_devdata }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, ov7670_id); -#if IS_ENABLED(CONFIG_OF) static const struct of_device_id ov7670_of_match[] = { - { .compatible = "ovti,ov7670", }, - { /* sentinel */ }, + { .compatible = "ovti,ov7670", &ov7670_devdata }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ov7670_of_match); -#endif static struct i2c_driver ov7670_driver = { .driver = { .name = "ov7670", - .of_match_table = of_match_ptr(ov7670_of_match), + .of_match_table = ov7670_of_match, }, .probe = ov7670_probe, .remove = ov7670_remove, diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 386d69c8e0..7618b58a7a 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -433,9 +433,7 @@ struct ov772x_priv { struct mutex lock; int power_count; int streaming; -#ifdef CONFIG_MEDIA_CONTROLLER struct media_pad pad; -#endif enum v4l2_mbus_type bus_type; }; @@ -1488,13 +1486,11 @@ static int ov772x_probe(struct i2c_client *client) if (ret < 0) goto error_gpio_put; -#ifdef CONFIG_MEDIA_CONTROLLER priv->pad.flags = MEDIA_PAD_FL_SOURCE; priv->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&priv->subdev.entity, 1, &priv->pad); if (ret < 0) goto error_gpio_put; -#endif priv->cfmt = &ov772x_cfmts[0]; priv->win = &ov772x_win_sizes[0]; diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index dffdb475e4..356a45e65b 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -83,9 +83,7 @@ struct ov7740 { struct v4l2_subdev subdev; -#if defined(CONFIG_MEDIA_CONTROLLER) struct media_pad pad; -#endif struct v4l2_mbus_framefmt format; const struct ov7740_pixfmt *fmt; /* Current format */ const struct ov7740_framesize *frmsize; @@ -120,7 +118,6 @@ struct ov7740 { struct v4l2_ctrl *contrast; struct mutex mutex; /* To serialize asynchronus callbacks */ - bool streaming; /* Streaming on/off */ struct gpio_desc *resetb_gpio; struct gpio_desc *pwdn_gpio; @@ -618,10 +615,6 @@ static int ov7740_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&ov7740->mutex); - if (ov7740->streaming == enable) { - mutex_unlock(&ov7740->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -635,8 +628,6 @@ static int ov7740_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov7740->streaming = enable; - mutex_unlock(&ov7740->mutex); return ret; @@ -807,9 +798,7 @@ static int ov7740_set_fmt(struct v4l2_subdev *sd, struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); const struct ov7740_pixfmt *ovfmt; const struct ov7740_framesize *fsize; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *mbus_fmt; -#endif int ret; mutex_lock(&ov7740->mutex); @@ -822,11 +811,10 @@ static int ov7740_set_fmt(struct v4l2_subdev *sd, ret = ov7740_try_fmt_internal(sd, &format->format, NULL, NULL); if (ret) goto error; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); *mbus_fmt = format->format; -#endif mutex_unlock(&ov7740->mutex); return 0; } @@ -851,26 +839,18 @@ static int ov7740_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *format) { struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API struct v4l2_mbus_framefmt *mbus_fmt; -#endif - int ret = 0; mutex_lock(&ov7740->mutex); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); format->format = *mbus_fmt; - ret = 0; -#else - ret = -EINVAL; -#endif } else { format->format = ov7740->format; } mutex_unlock(&ov7740->mutex); - return ret; + return 0; } static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = { @@ -899,7 +879,6 @@ static void ov7740_get_default_format(struct v4l2_subdev *sd, format->field = V4L2_FIELD_NONE; } -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); @@ -916,7 +895,6 @@ static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static const struct v4l2_subdev_internal_ops ov7740_subdev_internal_ops = { .open = ov7740_open, }; -#endif static int ov7740_probe_dt(struct i2c_client *client, struct ov7740 *ov7740) @@ -1094,18 +1072,14 @@ static int ov7740_probe(struct i2c_client *client) sd = &ov7740->subdev; v4l2_i2c_subdev_init(sd, client, &ov7740_subdev_ops); -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API sd->internal_ops = &ov7740_subdev_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; -#endif -#if defined(CONFIG_MEDIA_CONTROLLER) ov7740->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &ov7740->pad); if (ret) return ret; -#endif ret = ov7740_set_power(ov7740, 1); if (ret) diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index f053c3a767..a0f673a24e 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -1438,9 +1438,6 @@ struct ov8856 { /* To serialize asynchronus callbacks */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; - /* lanes index */ u8 nlanes; @@ -2042,9 +2039,6 @@ static int ov8856_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (ov8856->streaming == enable) - return 0; - mutex_lock(&ov8856->mutex); if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -2064,7 +2058,6 @@ static int ov8856_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov8856->streaming = enable; mutex_unlock(&ov8856->mutex); return ret; @@ -2125,45 +2118,6 @@ static int ov8856_power_off(struct device *dev) return 0; } -static int __maybe_unused ov8856_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov8856 *ov8856 = to_ov8856(sd); - - mutex_lock(&ov8856->mutex); - if (ov8856->streaming) - ov8856_stop_streaming(ov8856); - - ov8856_power_off(dev); - mutex_unlock(&ov8856->mutex); - - return 0; -} - -static int __maybe_unused ov8856_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov8856 *ov8856 = to_ov8856(sd); - int ret; - - mutex_lock(&ov8856->mutex); - - ov8856_power_on(dev); - if (ov8856->streaming) { - ret = ov8856_start_streaming(ov8856); - if (ret) { - ov8856->streaming = false; - ov8856_stop_streaming(ov8856); - mutex_unlock(&ov8856->mutex); - return ret; - } - } - - mutex_unlock(&ov8856->mutex); - - return 0; -} - static int ov8856_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) @@ -2501,7 +2455,6 @@ probe_power_off: } static const struct dev_pm_ops ov8856_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov8856_suspend, ov8856_resume) SET_RUNTIME_PM_OPS(ov8856_power_off, ov8856_power_on, NULL) }; diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index 068c7449f5..bf6dfce1b5 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -165,7 +165,6 @@ struct ov9282_mode { * @cur_mode: Pointer to current selected sensor mode * @code: Mbus code currently selected * @mutex: Mutex for serializing sensor controls - * @streaming: Flag indicating streaming state */ struct ov9282 { struct device *dev; @@ -188,7 +187,6 @@ struct ov9282 { const struct ov9282_mode *cur_mode; u32 code; struct mutex mutex; - bool streaming; }; static const s64 link_freq[] = { @@ -1037,11 +1035,6 @@ static int ov9282_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&ov9282->mutex); - if (ov9282->streaming == enable) { - mutex_unlock(&ov9282->mutex); - return 0; - } - if (enable) { ret = pm_runtime_resume_and_get(ov9282->dev); if (ret) @@ -1055,8 +1048,6 @@ static int ov9282_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(ov9282->dev); } - ov9282->streaming = enable; - mutex_unlock(&ov9282->mutex); return 0; diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index b36fc0feda..f1377c305b 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -337,9 +337,6 @@ struct ov9734 { /* To serialize asynchronus callbacks */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; static inline struct ov9734 *to_ov9734(struct v4l2_subdev *subdev) @@ -660,10 +657,6 @@ static int ov9734_set_stream(struct v4l2_subdev *sd, int enable) int ret = 0; mutex_lock(&ov9734->mutex); - if (ov9734->streaming == enable) { - mutex_unlock(&ov9734->mutex); - return 0; - } if (enable) { ret = pm_runtime_resume_and_get(&client->dev); @@ -683,46 +676,8 @@ static int ov9734_set_stream(struct v4l2_subdev *sd, int enable) pm_runtime_put(&client->dev); } - ov9734->streaming = enable; - mutex_unlock(&ov9734->mutex); - - return ret; -} - -static int __maybe_unused ov9734_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov9734 *ov9734 = to_ov9734(sd); - - mutex_lock(&ov9734->mutex); - if (ov9734->streaming) - ov9734_stop_streaming(ov9734); - mutex_unlock(&ov9734->mutex); - return 0; -} - -static int __maybe_unused ov9734_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov9734 *ov9734 = to_ov9734(sd); - int ret = 0; - - mutex_lock(&ov9734->mutex); - if (!ov9734->streaming) - goto exit; - - ret = ov9734_start_streaming(ov9734); - if (ret) { - ov9734->streaming = false; - ov9734_stop_streaming(ov9734); - } - -exit: - mutex_unlock(&ov9734->mutex); return ret; } @@ -1014,10 +969,6 @@ probe_error_v4l2_ctrl_handler_free: return ret; } -static const struct dev_pm_ops ov9734_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ov9734_suspend, ov9734_resume) -}; - static const struct acpi_device_id ov9734_acpi_ids[] = { { "OVTI9734", }, {} @@ -1028,7 +979,6 @@ MODULE_DEVICE_TABLE(acpi, ov9734_acpi_ids); static struct i2c_driver ov9734_i2c_driver = { .driver = { .name = "ov9734", - .pm = &ov9734_pm_ops, .acpi_match_table = ov9734_acpi_ids, }, .probe = ov9734_probe, diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c index f4e2e2f397..b4647bda8c 100644 --- a/drivers/media/i2c/rdacm20.c +++ b/drivers/media/i2c/rdacm20.c @@ -625,8 +625,7 @@ error_free_ctrls: v4l2_ctrl_handler_free(&dev->ctrls); error: media_entity_cleanup(&dev->sd.entity); - if (dev->sensor) - i2c_unregister_device(dev->sensor); + i2c_unregister_device(dev->sensor); dev_err(&client->dev, "probe failed\n"); diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c index 30f82ca344..5dbfb04b31 100644 --- a/drivers/media/i2c/st-vgxy61.c +++ b/drivers/media/i2c/st-vgxy61.c @@ -1170,14 +1170,9 @@ static int vgxy61_stream_enable(struct vgxy61_dev *sensor) if (ret) return ret; - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(&client->dev); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) return ret; - } - - /* pm_runtime_get_sync() can return 1 as a valid return code */ - ret = 0; vgxy61_write_reg(sensor, VGXY61_REG_FORMAT_CTRL, get_bpp_by_code(sensor->fmt.code), &ret); diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c index 566f5eaddd..ce612a47ba 100644 --- a/drivers/media/i2c/tc358746.c +++ b/drivers/media/i2c/tc358746.c @@ -784,8 +784,12 @@ static int tc358746_set_fmt(struct v4l2_subdev *sd, sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, TC358746_SINK); fmt = tc358746_get_format_by_code(format->pad, format->format.code); - if (IS_ERR(fmt)) + if (IS_ERR(fmt)) { fmt = tc358746_get_format_by_code(format->pad, tc358746_def_fmt.code); + // Can't happen, but just in case... + if (WARN_ON(IS_ERR(fmt))) + return -EINVAL; + } format->format.code = fmt->code; format->format.field = V4L2_FIELD_NONE; diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index aa6d4b67b6..c37f605cb7 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -16,23 +16,24 @@ * Prabhakar Lad <prabhakar.lad@ti.com> */ -#include <linux/i2c.h> -#include <linux/slab.h> #include <linux/delay.h> -#include <linux/videodev2.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/v4l2-mediabus.h> #include <linux/of.h> #include <linux/of_graph.h> +#include <linux/slab.h> +#include <linux/v4l2-mediabus.h> +#include <linux/videodev2.h> +#include <media/i2c/tvp514x.h> +#include <media/media-entity.h> #include <media/v4l2-async.h> -#include <media/v4l2-device.h> #include <media/v4l2-common.h> -#include <media/v4l2-mediabus.h> -#include <media/v4l2-fwnode.h> #include <media/v4l2-ctrls.h> -#include <media/i2c/tvp514x.h> -#include <media/media-entity.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mediabus.h> #include "tvp514x_regs.h" @@ -118,7 +119,7 @@ struct tvp514x_decoder { struct media_pad pad; struct v4l2_mbus_framefmt format; - struct tvp514x_reg *int_seq; + const struct tvp514x_reg *int_seq; }; /* TVP514x default register values */ @@ -1024,7 +1025,6 @@ done: static int tvp514x_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct tvp514x_platform_data *pdata = tvp514x_get_pdata(client); struct tvp514x_decoder *decoder; struct v4l2_subdev *sd; @@ -1049,7 +1049,7 @@ tvp514x_probe(struct i2c_client *client) memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default, sizeof(tvp514x_reg_list_default)); - decoder->int_seq = (struct tvp514x_reg *)id->driver_data; + decoder->int_seq = i2c_get_match_data(client); /* Copy board specific information here */ decoder->pdata = pdata; @@ -1183,29 +1183,26 @@ static const struct tvp514x_reg tvp514xm_init_reg_seq[] = { * driver_data - Driver data */ static const struct i2c_device_id tvp514x_id[] = { - {"tvp5146", (unsigned long)tvp5146_init_reg_seq}, - {"tvp5146m2", (unsigned long)tvp514xm_init_reg_seq}, - {"tvp5147", (unsigned long)tvp5147_init_reg_seq}, - {"tvp5147m1", (unsigned long)tvp514xm_init_reg_seq}, - {}, + {"tvp5146", (kernel_ulong_t)tvp5146_init_reg_seq }, + {"tvp5146m2", (kernel_ulong_t)tvp514xm_init_reg_seq }, + {"tvp5147", (kernel_ulong_t)tvp5147_init_reg_seq }, + {"tvp5147m1", (kernel_ulong_t)tvp514xm_init_reg_seq }, + { /* sentinel */ } }; - MODULE_DEVICE_TABLE(i2c, tvp514x_id); -#if IS_ENABLED(CONFIG_OF) static const struct of_device_id tvp514x_of_match[] = { - { .compatible = "ti,tvp5146", }, - { .compatible = "ti,tvp5146m2", }, - { .compatible = "ti,tvp5147", }, - { .compatible = "ti,tvp5147m1", }, - { /* sentinel */ }, + { .compatible = "ti,tvp5146", .data = tvp5146_init_reg_seq }, + { .compatible = "ti,tvp5146m2", .data = tvp514xm_init_reg_seq }, + { .compatible = "ti,tvp5147", .data = tvp5147_init_reg_seq }, + { .compatible = "ti,tvp5147m1", .data = tvp514xm_init_reg_seq }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, tvp514x_of_match); -#endif static struct i2c_driver tvp514x_driver = { .driver = { - .of_match_table = of_match_ptr(tvp514x_of_match), + .of_match_table = tvp514x_of_match, .name = TVP514X_MODULE_NAME, }, .probe = tvp514x_probe, diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 537ebd9fa8..178bd06cc2 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -759,7 +759,6 @@ static void video_i2c_release(struct video_device *vdev) static int video_i2c_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct video_i2c_data *data; struct v4l2_device *v4l2_dev; struct vb2_queue *queue; @@ -769,11 +768,8 @@ static int video_i2c_probe(struct i2c_client *client) if (!data) return -ENOMEM; - if (dev_fwnode(&client->dev)) - data->chip = device_get_match_data(&client->dev); - else if (id) - data->chip = &video_i2c_chip[id->driver_data]; - else + data->chip = i2c_get_match_data(client); + if (!data->chip) goto error_free_device; data->regmap = regmap_init_i2c(client, data->chip->regmap_config); @@ -940,8 +936,8 @@ static const struct dev_pm_ops video_i2c_pm_ops = { }; static const struct i2c_device_id video_i2c_id_table[] = { - { "amg88xx", AMG88XX }, - { "mlx90640", MLX90640 }, + { "amg88xx", (kernel_ulong_t)&video_i2c_chip[AMG88XX] }, + { "mlx90640", (kernel_ulong_t)&video_i2c_chip[MLX90640] }, {} }; MODULE_DEVICE_TABLE(i2c, video_i2c_id_table); diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 83468d4a44..543a392f86 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -197,6 +197,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads, struct media_device *mdev = entity->graph_obj.mdev; struct media_pad *iter; unsigned int i = 0; + int ret = 0; if (num_pads >= MEDIA_ENTITY_MAX_PADS) return -E2BIG; @@ -210,15 +211,27 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads, media_entity_for_each_pad(entity, iter) { iter->entity = entity; iter->index = i++; + + if (hweight32(iter->flags & (MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_SOURCE)) != 1) { + ret = -EINVAL; + break; + } + if (mdev) media_gobj_create(mdev, MEDIA_GRAPH_PAD, &iter->graph_obj); } + if (ret && mdev) { + media_entity_for_each_pad(entity, iter) + media_gobj_destroy(&iter->graph_obj); + } + if (mdev) mutex_unlock(&mdev->graph_mutex); - return 0; + return ret; } EXPORT_SYMBOL_GPL(media_entity_pads_init); diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index ee095bde0b..7f65aa6093 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -13,6 +13,7 @@ if MEDIA_PCI_SUPPORT if MEDIA_CAMERA_SUPPORT comment "Media capture support" +source "drivers/media/pci/mgb4/Kconfig" source "drivers/media/pci/solo6x10/Kconfig" source "drivers/media/pci/sta2x11/Kconfig" source "drivers/media/pci/tw5864/Kconfig" diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index 8bed619b71..f18c7e15ab 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_VIDEO_CX25821) += cx25821/ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_DT3155) += dt3155/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ +obj-$(CONFIG_VIDEO_MGB4) += mgb4/ obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index ec78f7fc5e..867c1308de 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -126,6 +126,7 @@ MODULE_PARM_DESC(audiodev, "specify audio device:\n" "\t\t 3 = tvaudio"); MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition."); +MODULE_FIRMWARE("hcwamc.rbf"); /* I2C addresses list */ #define I2C_ADDR_TDA7432 0x8a diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c index 4cb890b949..390cbba6c0 100644 --- a/drivers/media/pci/bt8xx/dvb-bt8xx.c +++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c @@ -190,11 +190,15 @@ static int cx24108_tuner_set_params(struct dvb_frontend *fe) u32 freq = c->frequency; int i, a, n, pump; u32 band, pll; - u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, - 1576000,1718000,1856000,2036000,2150000}; - u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, - 0x00102000,0x00104000,0x00108000,0x00110000, - 0x00120000,0x00140000}; + static const u32 osci[] = { + 950000, 1019000, 1075000, 1178000, 1296000, 1432000, + 1576000, 1718000, 1856000, 2036000, 2150000 + }; + static const u32 bandsel[] = { + 0, 0x00020000, 0x00040000, 0x00100800, 0x00101000, + 0x00102000, 0x00104000, 0x00108000, 0x00110000, + 0x00120000, 0x00140000 + }; #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq); diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index 4bfbcca14f..26bf58d17a 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -107,11 +107,9 @@ static void chain_all_buffers(struct cobalt_stream *s) { struct sg_dma_desc_info *desc[NR_BUFS]; struct cobalt_buffer *cb; - struct list_head *p; int i = 0; - list_for_each(p, &s->bufs) { - cb = list_entry(p, struct cobalt_buffer, list); + list_for_each_entry(cb, &s->bufs, list) { desc[i] = &s->dma_desc_info[cb->vb.vb2_buf.index]; if (i > 0) descriptor_list_chain(desc[i-1], desc[i]); @@ -348,7 +346,6 @@ static void cobalt_dma_stop_streaming(struct cobalt_stream *s) struct cobalt *cobalt = s->cobalt; struct sg_dma_desc_info *desc; struct cobalt_buffer *cb; - struct list_head *p; unsigned long flags; int timeout_msec = 100; int rx = s->video_channel; @@ -367,8 +364,7 @@ static void cobalt_dma_stop_streaming(struct cobalt_stream *s) /* Try to stop the DMA engine gracefully */ spin_lock_irqsave(&s->irqlock, flags); - list_for_each(p, &s->bufs) { - cb = list_entry(p, struct cobalt_buffer, list); + list_for_each_entry(cb, &s->bufs, list) { desc = &s->dma_desc_info[cb->vb.vb2_buf.index]; /* Stop DMA after this descriptor chain */ descriptor_list_end_of_chain(desc); diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h index 887d2aa364..af05bde758 100644 --- a/drivers/media/pci/cx18/cx18-driver.h +++ b/drivers/media/pci/cx18/cx18-driver.h @@ -631,7 +631,7 @@ struct cx18 { u32 hw2_irq_mask; struct workqueue_struct *in_work_queue; - char in_workq_name[11]; /* "cx18-NN-in" */ + char in_workq_name[39]; /* "cx18-NN-in" */ struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS]; char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ diff --git a/drivers/media/pci/cx18/cx18-mailbox.c b/drivers/media/pci/cx18/cx18-mailbox.c index 3b283f3c67..a6457c23d1 100644 --- a/drivers/media/pci/cx18/cx18-mailbox.c +++ b/drivers/media/pci/cx18/cx18-mailbox.c @@ -831,7 +831,7 @@ int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...) int i; if (cx == NULL) { - CX18_ERR("cx == NULL (cmd=%x)\n", cmd); + pr_err("cx == NULL (cmd=%x)\n", cmd); return 0; } if (args > MAX_MB_ARGUMENTS) { diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c index 91733ab9f5..363badab7c 100644 --- a/drivers/media/pci/ddbridge/ddbridge-main.c +++ b/drivers/media/pci/ddbridge/ddbridge-main.c @@ -238,7 +238,7 @@ fail: ddb_unmap(dev); pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); - return -1; + return stat; } /****************************************************************************/ diff --git a/drivers/media/pci/intel/ivsc/Kconfig b/drivers/media/pci/intel/ivsc/Kconfig index a8cb981544..407a800c81 100644 --- a/drivers/media/pci/intel/ivsc/Kconfig +++ b/drivers/media/pci/intel/ivsc/Kconfig @@ -10,6 +10,12 @@ config INTEL_VSC help This adds support for Intel Visual Sensing Controller (IVSC). - Enables the IVSC firmware services required for controlling - camera sensor ownership and CSI-2 link through Image Processing - Unit(IPU) driver of Intel. + The IVSC support is split into two devices, ACE (Algorithm + Context Engine) and CSI (Camera Serial Interface), each of which + have their own drivers. The ACE is used to select the ownership + of the sensor between the IVSC and the host CPU while the CSI is + used to both select the routing destination for the data the + sensor transmits over the CSI-2 bus between the IVSC and the + host CPU and to configure the CSI-2 bus itself. + + The modules will be called ivsc-ace and ivsc-csi. diff --git a/drivers/media/pci/intel/ivsc/mei_ace.c b/drivers/media/pci/intel/ivsc/mei_ace.c index a0491f3078..3622271c71 100644 --- a/drivers/media/pci/intel/ivsc/mei_ace.c +++ b/drivers/media/pci/intel/ivsc/mei_ace.c @@ -30,8 +30,6 @@ #include <linux/uuid.h> #include <linux/workqueue.h> -#define MEI_ACE_DRIVER_NAME "ivsc_ace" - /* indicating driver message */ #define ACE_DRV_MSG 1 /* indicating set command */ @@ -408,6 +406,9 @@ static int mei_ace_setup_dev_link(struct mei_ace *ace) if (!csi_dev) { ret = -EPROBE_DEFER; goto err; + } else if (!dev_fwnode(csi_dev)) { + ret = -EPROBE_DEFER; + goto err_put; } /* setup link between mei_ace and mei_csi */ @@ -554,14 +555,14 @@ static const struct dev_pm_ops mei_ace_pm_ops = { 0x9B, 0x78, 0x03, 0x61, 0x63, 0x5E, 0x24, 0x47) static const struct mei_cl_device_id mei_ace_tbl[] = { - { MEI_ACE_DRIVER_NAME, MEI_ACE_UUID, MEI_CL_VERSION_ANY }, + { .uuid = MEI_ACE_UUID, .version = MEI_CL_VERSION_ANY }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(mei, mei_ace_tbl); static struct mei_cl_driver mei_ace_driver = { .id_table = mei_ace_tbl, - .name = MEI_ACE_DRIVER_NAME, + .name = KBUILD_MODNAME, .probe = mei_ace_probe, .remove = mei_ace_remove, diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c index 00ba611e0f..2a6b828fd8 100644 --- a/drivers/media/pci/intel/ivsc/mei_csi.c +++ b/drivers/media/pci/intel/ivsc/mei_csi.c @@ -30,7 +30,6 @@ #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> -#define MEI_CSI_DRIVER_NAME "ivsc_csi" #define MEI_CSI_ENTITY_NAME "Intel IVSC CSI" #define MEI_CSI_LINK_FREQ_400MHZ 400000000ULL @@ -804,14 +803,14 @@ static void mei_csi_remove(struct mei_cl_device *cldev) 0xAF, 0x93, 0x7b, 0x44, 0x53, 0xAC, 0x29, 0xDA) static const struct mei_cl_device_id mei_csi_tbl[] = { - { MEI_CSI_DRIVER_NAME, MEI_CSI_UUID, MEI_CL_VERSION_ANY }, + { .uuid = MEI_CSI_UUID, .version = MEI_CL_VERSION_ANY }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(mei, mei_csi_tbl); static struct mei_cl_driver mei_csi_driver = { .id_table = mei_csi_tbl, - .name = MEI_CSI_DRIVER_NAME, + .name = KBUILD_MODNAME, .probe = mei_csi_probe, .remove = mei_csi_remove, diff --git a/drivers/media/pci/mgb4/Kconfig b/drivers/media/pci/mgb4/Kconfig new file mode 100644 index 0000000000..f2a05a1c8f --- /dev/null +++ b/drivers/media/pci/mgb4/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_MGB4 + tristate "Digiteq Automotive MGB4 support" + depends on VIDEO_DEV && PCI && I2C && DMADEVICES && SPI && MTD && IIO + depends on COMMON_CLK + select VIDEOBUF2_DMA_SG + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select I2C_XILINX + select SPI_XILINX + select MTD_SPI_NOR + select XILINX_XDMA + help + This is a video4linux driver for Digiteq Automotive MGB4 grabber + cards. + + To compile this driver as a module, choose M here: the + module will be called mgb4. diff --git a/drivers/media/pci/mgb4/Makefile b/drivers/media/pci/mgb4/Makefile new file mode 100644 index 0000000000..e92ead18be --- /dev/null +++ b/drivers/media/pci/mgb4/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +mgb4-objs := mgb4_regs.o mgb4_core.o mgb4_vin.o mgb4_vout.o \ + mgb4_sysfs_pci.o mgb4_sysfs_in.o mgb4_sysfs_out.o \ + mgb4_i2c.o mgb4_cmt.o mgb4_trigger.o mgb4_dma.o + +obj-$(CONFIG_VIDEO_MGB4) += mgb4.o diff --git a/drivers/media/pci/mgb4/mgb4_cmt.c b/drivers/media/pci/mgb4/mgb4_cmt.c new file mode 100644 index 0000000000..70dc78ef19 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_cmt.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + * + * The CMT module configures the FPGA Clock Management Tile (CMT) registers. For + * different video signal frequencies (FPGA input signal frequencies), the FPGA + * CMT registers need to be adjusted for the FPGA to work properly. The values + * are precomputed based on formulas given by Xilinx in their FPGA documentation + * (which are in turn full of some magic values/tables...). + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include "mgb4_core.h" +#include "mgb4_cmt.h" + +static const u16 cmt_vals_out[][15] = { + {0x1208, 0x0000, 0x171C, 0x0000, 0x1E38, 0x0000, 0x11C7, 0x0000, 0x1041, 0x01BC, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x11C7, 0x0000, 0x1619, 0x0080, 0x1C71, 0x0000, 0x130D, 0x0080, 0x0041, 0x0090, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x9000, }, + {0x11C7, 0x0000, 0x1619, 0x0080, 0x1C71, 0x0000, 0x165A, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x11C7, 0x0000, 0x1619, 0x0080, 0x1C71, 0x0000, 0x1187, 0x0080, 0x1041, 0x01EE, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x1186, 0x0000, 0x1555, 0x0000, 0x1AAA, 0x0000, 0x1451, 0x0000, 0x0042, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x11C7, 0x0000, 0x1619, 0x0080, 0x1C71, 0x0000, 0x134E, 0x0080, 0x0041, 0x005E, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x1619, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x179E, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x179F, 0x0080, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x17DF, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x8800, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x128B, 0x0080, 0x0041, 0x00DB, 0x7C01, 0x7DE9, 0xFFFF, 0x9000, 0x0100, }, + {0x1186, 0x0000, 0x1555, 0x0000, 0x1AAA, 0x0000, 0x1820, 0x0000, 0x0083, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1186, 0x0000, 0x1555, 0x0000, 0x1AAA, 0x0000, 0x1187, 0x0080, 0x1041, 0x01EE, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x169B, 0x0080, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x171C, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x1186, 0x0000, 0x1555, 0x0000, 0x1AAA, 0x0000, 0x1515, 0x0080, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x1493, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x15D8, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1900, 0x0100, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x124A, 0x0080, 0x0041, 0x010D, 0x7C01, 0x7DE9, 0xFFFF, 0x9000, 0x0100, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x175D, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x1619, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x17DF, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x8800, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x17E0, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x9000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x1820, 0x0000, 0x0083, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x13D0, 0x0080, 0x0042, 0x002C, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x128B, 0x0080, 0x0041, 0x00DB, 0x7C01, 0x7DE9, 0xFFFF, 0x9000, 0x0100, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x1820, 0x0000, 0x00C3, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x134E, 0x0080, 0x0041, 0x005E, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x1515, 0x0080, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x175D, 0x0000, 0x00C4, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1145, 0x0000, 0x1452, 0x0080, 0x18E3, 0x0000, 0x11C7, 0x0000, 0x1041, 0x01BC, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1209, 0x0080, 0x0041, 0x013F, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x1100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1556, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x8000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x179F, 0x0080, 0x00C4, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x15D8, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1900, 0x0100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1105, 0x0080, 0x1041, 0x01E8, 0x6401, 0x65E9, 0xFFFF, 0x9800, 0x1100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1820, 0x0000, 0x00C4, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x1493, 0x0080, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x138E, 0x0000, 0x0042, 0x005E, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x17E0, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x9000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x165A, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x175D, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x1187, 0x0080, 0x1041, 0x01EE, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x175E, 0x0080, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x179E, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x134E, 0x0080, 0x0041, 0x005E, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x165A, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x16DC, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x169A, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x11C7, 0x0000, 0x1041, 0x01BC, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x169B, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, + {0x1104, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x171D, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x16DB, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1146, 0x0080, 0x1041, 0x0184, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x171C, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1451, 0x0000, 0x0042, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x171D, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x175D, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1452, 0x0080, 0x0042, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x15D8, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1900, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1104, 0x0000, 0x1041, 0x01E8, 0x5801, 0x59E9, 0xFFFF, 0x9900, 0x0900, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x179F, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1515, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x17DF, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x8800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1659, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1555, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x8000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x14D3, 0x0000, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1820, 0x0000, 0x0083, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1556, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x8000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1187, 0x0080, 0x1041, 0x01EE, 0x7C01, 0x7DE9, 0xFFFF, 0x9900, 0x8100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1452, 0x0080, 0x0082, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x169B, 0x0080, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1514, 0x0000, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x17E0, 0x0080, 0x00C4, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x9000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x1515, 0x0080, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x10C3, 0x0000, 0x128B, 0x0080, 0x1555, 0x0000, 0x16DC, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1493, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x15D8, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1900, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x171D, 0x0080, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1618, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1900, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x175D, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x14D4, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1619, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x179E, 0x0000, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x179F, 0x0080, 0x00C3, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1515, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x13D0, 0x0080, 0x0042, 0x002C, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x169A, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x128B, 0x0080, 0x0041, 0x00DB, 0x7C01, 0x7DE9, 0xFFFF, 0x9000, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x169B, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1820, 0x0000, 0x00C3, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1556, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x8000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x16DB, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1411, 0x0080, 0x0042, 0x002C, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x171C, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1597, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x8000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1451, 0x0000, 0x0042, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x171D, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x1800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x12CC, 0x0080, 0x0041, 0x00A9, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x175D, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1452, 0x0080, 0x0042, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x15D8, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1900, 0x0100, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x175E, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1492, 0x0000, 0x0042, 0x0013, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x179F, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0800, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1619, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1493, 0x0080, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x17DF, 0x0000, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x8800, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x130D, 0x0080, 0x0041, 0x0090, 0x7C01, 0x7DE9, 0xFFFF, 0x1100, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x17E0, 0x0080, 0x0083, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x14D3, 0x0000, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x165A, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1000, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x1820, 0x0000, 0x0083, 0x00FA, 0x7DE9, 0x7DE8, 0xFFFF, 0x0900, 0x9000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x14D4, 0x0080, 0x0042, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x0900, 0x1000, }, + {0x1082, 0x0000, 0x11C7, 0x0000, 0x138E, 0x0000, 0x169B, 0x0080, 0x0082, 0x00FA, 0x7C01, 0x7DE9, 0xFFFF, 0x1800, 0x0100, }, +}; + +static const u16 cmt_vals_in[][13] = { + {0x1082, 0x0000, 0x5104, 0x0000, 0x11C7, 0x0000, 0x1041, 0x02BC, 0x7C01, 0xFFE9, 0x9900, 0x9908, 0x8100}, + {0x1104, 0x0000, 0x9208, 0x0000, 0x138E, 0x0000, 0x1041, 0x015E, 0x7C01, 0xFFE9, 0x0100, 0x0908, 0x1000}, +}; + +static const u32 cmt_addrs_out[][15] = { + {0x420, 0x424, 0x428, 0x42C, 0x430, 0x434, 0x450, 0x454, 0x458, 0x460, 0x464, 0x468, 0x4A0, 0x538, 0x53C}, + {0x620, 0x624, 0x628, 0x62C, 0x630, 0x634, 0x650, 0x654, 0x658, 0x660, 0x664, 0x668, 0x6A0, 0x738, 0x73C}, +}; + +static const u32 cmt_addrs_in[][13] = { + {0x020, 0x024, 0x028, 0x02C, 0x050, 0x054, 0x058, 0x060, 0x064, 0x068, 0x0A0, 0x138, 0x13C}, + {0x220, 0x224, 0x228, 0x22C, 0x250, 0x254, 0x258, 0x260, 0x264, 0x268, 0x2A0, 0x338, 0x33C}, +}; + +static const u32 cmt_freq[] = { + 25000, 25510, 26020, 26530, 26983, 27551, 28000, 28570, + 29046, 29522, 30000, 30476, 30952, 31546, 32000, 32539, + 33035, 33571, 33928, 34522, 35000, 35428, 36000, 36571, + 36904, 37500, 38093, 38571, 39047, 39453, 40000, 40476, + 40952, 41494, 41964, 42857, 43535, 44047, 44444, 45000, + 45535, 46029, 46428, 46823, 47617, 48214, 48571, 49107, + 49523, 50000, 50476, 50892, 51428, 52380, 53333, 53967, + 54285, 55238, 55555, 55952, 57142, 58095, 58571, 59047, + 59521, 60000, 60316, 60952, 61428, 61904, 62500, 63092, + 63491, 64282, 65078, 65476, 66071, 66664, 67142, 67854, + 68571, 69044, 69642, 70000, 71425, 72616, 73214, 73808, + 74285, 75000, 75714, 76187, 76785, 77142, 78570, 80000, + 80357, 80951, 81428, 82142, 82857, 83332, 83928, 84285, + 85713, 87142, 87500, 88094, 88571, 89285, 90000, 90475, + 91071, 91428, 92856, 94642, +}; + +static size_t freq_srch(u32 key, const u32 *array, size_t size) +{ + int l = 0; + int r = size - 1; + int m = 0; + + while (l <= r) { + m = (l + r) / 2; + if (array[m] < key) + l = m + 1; + else if (array[m] > key) + r = m - 1; + else + return m; + } + + if (r < 0 || l > size - 1) + return m; + else + return (abs(key - array[l]) < abs(key - array[r])) ? l : r; +} + +u32 mgb4_cmt_set_vout_freq(struct mgb4_vout_dev *voutdev, unsigned int freq) +{ + struct mgb4_regs *video = &voutdev->mgbdev->video; + const struct mgb4_vout_regs *regs = &voutdev->config->regs; + const u16 *reg_set; + const u32 *addr; + u32 config; + size_t i, index; + + index = freq_srch(freq, cmt_freq, ARRAY_SIZE(cmt_freq)); + addr = cmt_addrs_out[voutdev->config->id]; + reg_set = cmt_vals_out[index]; + + config = mgb4_read_reg(video, regs->config); + + mgb4_write_reg(video, regs->config, 0x1 | (config & ~0x3)); + + for (i = 0; i < ARRAY_SIZE(cmt_addrs_out[0]); i++) + mgb4_write_reg(&voutdev->mgbdev->cmt, addr[i], reg_set[i]); + + mgb4_mask_reg(video, regs->config, 0x100, 0x100); + mgb4_mask_reg(video, regs->config, 0x100, 0x0); + + mgb4_write_reg(video, regs->config, config & ~0x1); + + return cmt_freq[index]; +} + +void mgb4_cmt_set_vin_freq_range(struct mgb4_vin_dev *vindev, + unsigned int freq_range) +{ + struct mgb4_regs *video = &vindev->mgbdev->video; + const struct mgb4_vin_regs *regs = &vindev->config->regs; + const u16 *reg_set; + const u32 *addr; + u32 config; + size_t i; + + addr = cmt_addrs_in[vindev->config->id]; + reg_set = cmt_vals_in[freq_range]; + + config = mgb4_read_reg(video, regs->config); + + mgb4_write_reg(video, regs->config, 0x1 | (config & ~0x3)); + + for (i = 0; i < ARRAY_SIZE(cmt_addrs_in[0]); i++) + mgb4_write_reg(&vindev->mgbdev->cmt, addr[i], reg_set[i]); + + mgb4_mask_reg(video, regs->config, 0x1000, 0x1000); + mgb4_mask_reg(video, regs->config, 0x1000, 0x0); + + mgb4_write_reg(video, regs->config, config & ~0x1); +} diff --git a/drivers/media/pci/mgb4/mgb4_cmt.h b/drivers/media/pci/mgb4/mgb4_cmt.h new file mode 100644 index 0000000000..b15df56ca0 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_cmt.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + */ + +#ifndef __MGB4_CMT_H__ +#define __MGB4_CMT_H__ + +#include "mgb4_vout.h" +#include "mgb4_vin.h" + +u32 mgb4_cmt_set_vout_freq(struct mgb4_vout_dev *voutdev, unsigned int freq); +void mgb4_cmt_set_vin_freq_range(struct mgb4_vin_dev *vindev, + unsigned int freq_range); + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_core.c b/drivers/media/pci/mgb4/mgb4_core.c new file mode 100644 index 0000000000..5bfb8a0620 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_core.c @@ -0,0 +1,696 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This is the driver for the MGB4 video grabber card by Digiteq Automotive. + * + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + * + * This is the main driver module. The DMA, I2C and SPI sub-drivers are + * initialized here and the input/output v4l2 devices are created. + * + * The mgb4 card uses different expansion modules for different video sources + * (GMSL and FPDL3 for now) so in probe() we detect the module type based on + * what we see on the I2C bus and check if it matches the FPGA bitstream (there + * are different bitstreams for different expansion modules). When no expansion + * module is present, we still let the driver initialize to allow flashing of + * the FPGA firmware using the SPI FLASH device. No v4l2 video devices are + * created in this case. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/dma/amd_xdma.h> +#include <linux/platform_data/amd_xdma.h> +#include <linux/spi/xilinx_spi.h> +#include <linux/mtd/mtd.h> +#include <linux/hwmon.h> +#include <linux/debugfs.h> +#include "mgb4_dma.h" +#include "mgb4_i2c.h" +#include "mgb4_sysfs.h" +#include "mgb4_vout.h" +#include "mgb4_vin.h" +#include "mgb4_trigger.h" +#include "mgb4_core.h" + +#define MGB4_USER_IRQS 16 + +#define DIGITEQ_VID 0x1ed8 +#define T100_DID 0x0101 +#define T200_DID 0x0201 + +ATTRIBUTE_GROUPS(mgb4_pci); + +static int flashid; + +static struct xdma_chan_info h2c_chan_info = { + .dir = DMA_MEM_TO_DEV, +}; + +static struct xdma_chan_info c2h_chan_info = { + .dir = DMA_DEV_TO_MEM, +}; + +static struct xspi_platform_data spi_platform_data = { + .num_chipselect = 1, + .bits_per_word = 8 +}; + +static const struct i2c_board_info extender_info = { + I2C_BOARD_INFO("extender", 0x21) +}; + +#if IS_REACHABLE(CONFIG_HWMON) +static umode_t temp_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (type == hwmon_temp && + (attr == hwmon_temp_input || attr == hwmon_temp_label)) + return 0444; + else + return 0; +} + +static int temp_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long *val) +{ + struct mgb4_dev *mgbdev = dev_get_drvdata(dev); + u32 val10, raw; + + if (type != hwmon_temp || attr != hwmon_temp_input) + return -EOPNOTSUPP; + + raw = mgb4_read_reg(&mgbdev->video, 0xD0); + /* register value -> Celsius degrees formula given by Xilinx */ + val10 = ((((raw >> 20) & 0xFFF) * 503975) - 1118822400) / 409600; + *val = val10 * 100; + + return 0; +} + +static int temp_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + if (type != hwmon_temp || attr != hwmon_temp_label) + return -EOPNOTSUPP; + + *str = "FPGA Temperature"; + + return 0; +} + +static const struct hwmon_ops temp_ops = { + .is_visible = temp_is_visible, + .read = temp_read, + .read_string = temp_read_string +}; + +static const struct hwmon_channel_info *temp_channel_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL), + NULL +}; + +static const struct hwmon_chip_info temp_chip_info = { + .ops = &temp_ops, + .info = temp_channel_info, +}; +#endif + +static int match_i2c_adap(struct device *dev, void *data) +{ + return i2c_verify_adapter(dev) ? 1 : 0; +} + +static struct i2c_adapter *get_i2c_adap(struct platform_device *pdev) +{ + struct device *dev; + + mutex_lock(&pdev->dev.mutex); + dev = device_find_child(&pdev->dev, NULL, match_i2c_adap); + mutex_unlock(&pdev->dev.mutex); + + return dev ? to_i2c_adapter(dev) : NULL; +} + +static int match_spi_adap(struct device *dev, void *data) +{ + return to_spi_device(dev) ? 1 : 0; +} + +static struct spi_master *get_spi_adap(struct platform_device *pdev) +{ + struct device *dev; + + mutex_lock(&pdev->dev.mutex); + dev = device_find_child(&pdev->dev, NULL, match_spi_adap); + mutex_unlock(&pdev->dev.mutex); + + return dev ? container_of(dev, struct spi_master, dev) : NULL; +} + +static int init_spi(struct mgb4_dev *mgbdev, u32 devid) +{ + struct resource spi_resources[] = { + { + .start = 0x400, + .end = 0x47f, + .flags = IORESOURCE_MEM, + .name = "io-memory", + }, + { + .start = 14, + .end = 14, + .flags = IORESOURCE_IRQ, + .name = "irq", + }, + }; + struct spi_board_info spi_info = { + .max_speed_hz = 10000000, + .modalias = "m25p80", + .chip_select = 0, + .mode = SPI_MODE_3, + }; + struct pci_dev *pdev = mgbdev->pdev; + struct device *dev = &pdev->dev; + struct spi_master *master; + struct spi_device *spi_dev; + u32 irq; + int rv, id; + resource_size_t mapbase = pci_resource_start(pdev, MGB4_MGB4_BAR_ID); + + request_module("platform:xilinx_spi"); + + irq = xdma_get_user_irq(mgbdev->xdev, 14); + xdma_enable_user_irq(mgbdev->xdev, irq); + + spi_resources[0].parent = &pdev->resource[MGB4_MGB4_BAR_ID]; + spi_resources[0].start += mapbase; + spi_resources[0].end += mapbase; + spi_resources[1].start = irq; + spi_resources[1].end = irq; + + id = pci_dev_id(pdev); + mgbdev->spi_pdev = platform_device_register_resndata(dev, "xilinx_spi", + id, spi_resources, + ARRAY_SIZE(spi_resources), + &spi_platform_data, + sizeof(spi_platform_data)); + if (IS_ERR(mgbdev->spi_pdev)) { + dev_err(dev, "failed to register SPI device\n"); + return PTR_ERR(mgbdev->spi_pdev); + } + + master = get_spi_adap(mgbdev->spi_pdev); + if (!master) { + dev_err(dev, "failed to get SPI adapter\n"); + rv = -EINVAL; + goto err_pdev; + } + + snprintf(mgbdev->fw_part_name, sizeof(mgbdev->fw_part_name), + "mgb4-fw.%d", flashid); + mgbdev->partitions[0].name = mgbdev->fw_part_name; + if (devid == T200_DID) { + mgbdev->partitions[0].size = 0x950000; + mgbdev->partitions[0].offset = 0x1000000; + } else { + mgbdev->partitions[0].size = 0x400000; + mgbdev->partitions[0].offset = 0x400000; + } + mgbdev->partitions[0].mask_flags = 0; + + snprintf(mgbdev->data_part_name, sizeof(mgbdev->data_part_name), + "mgb4-data.%d", flashid); + mgbdev->partitions[1].name = mgbdev->data_part_name; + mgbdev->partitions[1].size = 0x10000; + mgbdev->partitions[1].offset = 0xFF0000; + mgbdev->partitions[1].mask_flags = MTD_CAP_NORFLASH; + + snprintf(mgbdev->flash_name, sizeof(mgbdev->flash_name), + "mgb4-flash.%d", flashid); + mgbdev->flash_data.name = mgbdev->flash_name; + mgbdev->flash_data.parts = mgbdev->partitions; + mgbdev->flash_data.nr_parts = ARRAY_SIZE(mgbdev->partitions); + mgbdev->flash_data.type = "spi-nor"; + + spi_info.platform_data = &mgbdev->flash_data; + + spi_dev = spi_new_device(master, &spi_info); + put_device(&master->dev); + if (!spi_dev) { + dev_err(dev, "failed to create MTD device\n"); + rv = -EINVAL; + goto err_pdev; + } + + return 0; + +err_pdev: + platform_device_unregister(mgbdev->spi_pdev); + + return rv; +} + +static void free_spi(struct mgb4_dev *mgbdev) +{ + platform_device_unregister(mgbdev->spi_pdev); +} + +static int init_i2c(struct mgb4_dev *mgbdev) +{ + struct resource i2c_resources[] = { + { + .start = 0x200, + .end = 0x3ff, + .flags = IORESOURCE_MEM, + .name = "io-memory", + }, + { + .start = 15, + .end = 15, + .flags = IORESOURCE_IRQ, + .name = "irq", + }, + }; + struct pci_dev *pdev = mgbdev->pdev; + struct device *dev = &pdev->dev; + char clk_name[16]; + u32 irq; + int rv, id; + resource_size_t mapbase = pci_resource_start(pdev, MGB4_MGB4_BAR_ID); + + request_module("platform:xiic-i2c"); + + irq = xdma_get_user_irq(mgbdev->xdev, 15); + xdma_enable_user_irq(mgbdev->xdev, irq); + + i2c_resources[0].parent = &pdev->resource[MGB4_MGB4_BAR_ID]; + i2c_resources[0].start += mapbase; + i2c_resources[0].end += mapbase; + i2c_resources[1].start = irq; + i2c_resources[1].end = irq; + + id = pci_dev_id(pdev); + + /* create dummy clock required by the xiic-i2c adapter */ + snprintf(clk_name, sizeof(clk_name), "xiic-i2c.%d", id); + mgbdev->i2c_clk = clk_hw_register_fixed_rate(NULL, clk_name, NULL, + 0, 125000000); + if (IS_ERR(mgbdev->i2c_clk)) { + dev_err(dev, "failed to register I2C clock\n"); + return PTR_ERR(mgbdev->i2c_clk); + } + mgbdev->i2c_cl = clkdev_hw_create(mgbdev->i2c_clk, NULL, "xiic-i2c.%d", + id); + if (!mgbdev->i2c_cl) { + dev_err(dev, "failed to register I2C clockdev\n"); + rv = -ENOMEM; + goto err_clk; + } + + mgbdev->i2c_pdev = platform_device_register_resndata(dev, "xiic-i2c", + id, i2c_resources, + ARRAY_SIZE(i2c_resources), + NULL, 0); + if (IS_ERR(mgbdev->i2c_pdev)) { + dev_err(dev, "failed to register I2C device\n"); + rv = PTR_ERR(mgbdev->i2c_pdev); + goto err_clkdev; + } + + mgbdev->i2c_adap = get_i2c_adap(mgbdev->i2c_pdev); + if (!mgbdev->i2c_adap) { + dev_err(dev, "failed to get I2C adapter\n"); + rv = -EINVAL; + goto err_pdev; + } + + mutex_init(&mgbdev->i2c_lock); + + return 0; + +err_pdev: + platform_device_unregister(mgbdev->i2c_pdev); +err_clkdev: + clkdev_drop(mgbdev->i2c_cl); +err_clk: + clk_hw_unregister(mgbdev->i2c_clk); + + return rv; +} + +static void free_i2c(struct mgb4_dev *mgbdev) +{ + put_device(&mgbdev->i2c_adap->dev); + platform_device_unregister(mgbdev->i2c_pdev); + clkdev_drop(mgbdev->i2c_cl); + clk_hw_unregister(mgbdev->i2c_clk); +} + +static int get_serial_number(struct mgb4_dev *mgbdev) +{ + struct device *dev = &mgbdev->pdev->dev; + struct mtd_info *mtd; + size_t rs; + int rv; + + mgbdev->serial_number = 0; + + mtd = get_mtd_device_nm(mgbdev->data_part_name); + if (IS_ERR(mtd)) { + dev_warn(dev, "failed to get data MTD device\n"); + return -ENOENT; + } + rv = mtd_read(mtd, 0, sizeof(mgbdev->serial_number), &rs, + (u_char *)&mgbdev->serial_number); + put_mtd_device(mtd); + if (rv < 0 || rs != sizeof(mgbdev->serial_number)) { + dev_warn(dev, "error reading MTD device\n"); + return -EIO; + } + + return 0; +} + +static int get_module_version(struct mgb4_dev *mgbdev) +{ + struct device *dev = &mgbdev->pdev->dev; + struct mgb4_i2c_client extender; + s32 version; + u32 fw_version; + int rv; + + rv = mgb4_i2c_init(&extender, mgbdev->i2c_adap, &extender_info, 8); + if (rv < 0) { + dev_err(dev, "failed to create extender I2C device\n"); + return rv; + } + version = mgb4_i2c_read_byte(&extender, 0x00); + mgb4_i2c_free(&extender); + if (version < 0) { + dev_err(dev, "error reading module version\n"); + return -EIO; + } + + mgbdev->module_version = ~((u32)version) & 0xff; + if (!(MGB4_IS_FPDL3(mgbdev) || MGB4_IS_GMSL(mgbdev))) { + dev_err(dev, "unknown module type\n"); + return -EINVAL; + } + fw_version = mgb4_read_reg(&mgbdev->video, 0xC4); + if (fw_version >> 24 != mgbdev->module_version >> 4) { + dev_err(dev, "module/firmware type mismatch\n"); + return -EINVAL; + } + + dev_info(dev, "%s module detected\n", + MGB4_IS_FPDL3(mgbdev) ? "FPDL3" : "GMSL"); + + return 0; +} + +static int map_regs(struct pci_dev *pdev, struct resource *res, + struct mgb4_regs *regs) +{ + int rv; + resource_size_t mapbase = pci_resource_start(pdev, MGB4_MGB4_BAR_ID); + + res->start += mapbase; + res->end += mapbase; + + rv = mgb4_regs_map(res, regs); + if (rv < 0) { + dev_err(&pdev->dev, "failed to map %s registers\n", res->name); + return rv; + } + + return 0; +} + +static int init_xdma(struct mgb4_dev *mgbdev) +{ + struct xdma_platdata data; + struct resource res[2] = { 0 }; + struct dma_slave_map *map; + struct pci_dev *pdev = mgbdev->pdev; + struct device *dev = &pdev->dev; + int i; + + res[0].start = pci_resource_start(pdev, MGB4_XDMA_BAR_ID); + res[0].end = pci_resource_end(pdev, MGB4_XDMA_BAR_ID); + res[0].flags = IORESOURCE_MEM; + res[0].parent = &pdev->resource[MGB4_XDMA_BAR_ID]; + res[1].start = pci_irq_vector(pdev, 0); + res[1].end = res[1].start + MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES + + MGB4_USER_IRQS - 1; + res[1].flags = IORESOURCE_IRQ; + + data.max_dma_channels = MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES; + data.device_map = mgbdev->slave_map; + data.device_map_cnt = MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES; + + for (i = 0; i < MGB4_VIN_DEVICES; i++) { + sprintf(mgbdev->channel_names[i], "c2h%d", i); + map = &data.device_map[i]; + map->slave = mgbdev->channel_names[i]; + map->devname = dev_name(dev); + map->param = XDMA_FILTER_PARAM(&c2h_chan_info); + } + for (i = 0; i < MGB4_VOUT_DEVICES; i++) { + sprintf(mgbdev->channel_names[i + MGB4_VIN_DEVICES], "h2c%d", i); + map = &data.device_map[i + MGB4_VIN_DEVICES]; + map->slave = mgbdev->channel_names[i + MGB4_VIN_DEVICES]; + map->devname = dev_name(dev); + map->param = XDMA_FILTER_PARAM(&h2c_chan_info); + } + + mgbdev->xdev = platform_device_register_resndata(dev, "xdma", + PLATFORM_DEVID_AUTO, res, + 2, &data, sizeof(data)); + if (IS_ERR(mgbdev->xdev)) { + dev_err(dev, "failed to register XDMA device\n"); + return PTR_ERR(mgbdev->xdev); + } + + return 0; +} + +static void free_xdma(struct mgb4_dev *mgbdev) +{ + platform_device_unregister(mgbdev->xdev); +} + +static int mgb4_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int i, rv; + struct mgb4_dev *mgbdev; + struct resource video = { + .start = 0x0, + .end = 0x100, + .flags = IORESOURCE_MEM, + .name = "mgb4-video", + }; + struct resource cmt = { + .start = 0x1000, + .end = 0x1800, + .flags = IORESOURCE_MEM, + .name = "mgb4-cmt", + }; + int irqs = pci_msix_vec_count(pdev); + + mgbdev = kzalloc(sizeof(*mgbdev), GFP_KERNEL); + if (!mgbdev) + return -ENOMEM; + + mgbdev->pdev = pdev; + pci_set_drvdata(pdev, mgbdev); + + /* PCIe related stuff */ + rv = pci_enable_device(pdev); + if (rv) { + dev_err(&pdev->dev, "error enabling PCI device\n"); + goto err_mgbdev; + } + + rv = pcie_capability_set_word(pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN); + if (rv) + dev_warn(&pdev->dev, "error enabling PCIe relaxed ordering\n"); + rv = pcie_capability_set_word(pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_EXT_TAG); + if (rv) + dev_warn(&pdev->dev, "error enabling PCIe extended tag field\n"); + rv = pcie_set_readrq(pdev, 512); + if (rv) + dev_warn(&pdev->dev, "error setting PCIe max. memory read size\n"); + pci_set_master(pdev); + + rv = pci_alloc_irq_vectors(pdev, irqs, irqs, PCI_IRQ_MSIX); + if (rv < 0) { + dev_err(&pdev->dev, "error allocating MSI-X IRQs\n"); + goto err_enable_pci; + } + + rv = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (rv) { + dev_err(&pdev->dev, "error setting DMA mask\n"); + goto err_enable_pci; + } + + /* DMA + IRQ engine */ + rv = init_xdma(mgbdev); + if (rv) + goto err_alloc_irq; + rv = mgb4_dma_channel_init(mgbdev); + if (rv) + goto err_dma_chan; + + /* mgb4 video registers */ + rv = map_regs(pdev, &video, &mgbdev->video); + if (rv < 0) + goto err_dma_chan; + /* mgb4 cmt registers */ + rv = map_regs(pdev, &cmt, &mgbdev->cmt); + if (rv < 0) + goto err_video_regs; + + /* SPI FLASH */ + rv = init_spi(mgbdev, id->device); + if (rv < 0) + goto err_cmt_regs; + + /* I2C controller */ + rv = init_i2c(mgbdev); + if (rv < 0) + goto err_spi; + + /* PCI card related sysfs attributes */ + rv = device_add_groups(&pdev->dev, mgb4_pci_groups); + if (rv < 0) + goto err_i2c; + +#if IS_REACHABLE(CONFIG_HWMON) + /* HWmon (card temperature) */ + mgbdev->hwmon_dev = hwmon_device_register_with_info(&pdev->dev, "mgb4", + mgbdev, + &temp_chip_info, + NULL); +#endif + +#ifdef CONFIG_DEBUG_FS + mgbdev->debugfs = debugfs_create_dir(dev_name(&pdev->dev), NULL); +#endif + + /* Get card serial number. On systems without MTD flash support we may + * get an error thus ignore the return value. An invalid serial number + * should not break anything... + */ + if (get_serial_number(mgbdev) < 0) + dev_warn(&pdev->dev, "error reading card serial number\n"); + + /* Get module type. If no valid module is found, skip the video device + * creation part but do not exit with error to allow flashing the card. + */ + rv = get_module_version(mgbdev); + if (rv < 0) + goto exit; + + /* Video input v4l2 devices */ + for (i = 0; i < MGB4_VIN_DEVICES; i++) + mgbdev->vin[i] = mgb4_vin_create(mgbdev, i); + + /* Video output v4l2 devices */ + for (i = 0; i < MGB4_VOUT_DEVICES; i++) + mgbdev->vout[i] = mgb4_vout_create(mgbdev, i); + + /* Triggers */ + mgbdev->indio_dev = mgb4_trigger_create(mgbdev); + +exit: + flashid++; + + return 0; + +err_i2c: + free_i2c(mgbdev); +err_spi: + free_spi(mgbdev); +err_cmt_regs: + mgb4_regs_free(&mgbdev->cmt); +err_video_regs: + mgb4_regs_free(&mgbdev->video); +err_dma_chan: + mgb4_dma_channel_free(mgbdev); + free_xdma(mgbdev); +err_alloc_irq: + pci_disable_msix(pdev); +err_enable_pci: + pci_disable_device(pdev); +err_mgbdev: + kfree(mgbdev); + + return rv; +} + +static void mgb4_remove(struct pci_dev *pdev) +{ + struct mgb4_dev *mgbdev = pci_get_drvdata(pdev); + int i; + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(mgbdev->debugfs); +#endif +#if IS_REACHABLE(CONFIG_HWMON) + hwmon_device_unregister(mgbdev->hwmon_dev); +#endif + + if (mgbdev->indio_dev) + mgb4_trigger_free(mgbdev->indio_dev); + + for (i = 0; i < MGB4_VOUT_DEVICES; i++) + if (mgbdev->vout[i]) + mgb4_vout_free(mgbdev->vout[i]); + for (i = 0; i < MGB4_VIN_DEVICES; i++) + if (mgbdev->vin[i]) + mgb4_vin_free(mgbdev->vin[i]); + + device_remove_groups(&mgbdev->pdev->dev, mgb4_pci_groups); + free_spi(mgbdev); + free_i2c(mgbdev); + mgb4_regs_free(&mgbdev->video); + mgb4_regs_free(&mgbdev->cmt); + + mgb4_dma_channel_free(mgbdev); + free_xdma(mgbdev); + + pci_disable_msix(mgbdev->pdev); + pci_disable_device(mgbdev->pdev); + + kfree(mgbdev); +} + +static const struct pci_device_id mgb4_pci_ids[] = { + { PCI_DEVICE(DIGITEQ_VID, T100_DID), }, + { PCI_DEVICE(DIGITEQ_VID, T200_DID), }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, mgb4_pci_ids); + +static struct pci_driver mgb4_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = mgb4_pci_ids, + .probe = mgb4_probe, + .remove = mgb4_remove, +}; + +module_pci_driver(mgb4_pci_driver); + +MODULE_AUTHOR("Digiteq Automotive s.r.o."); +MODULE_DESCRIPTION("Digiteq Automotive MGB4 Driver"); +MODULE_LICENSE("GPL"); +MODULE_SOFTDEP("pre: platform:xiic-i2c platform:xilinx_spi spi-nor"); diff --git a/drivers/media/pci/mgb4/mgb4_core.h b/drivers/media/pci/mgb4/mgb4_core.h new file mode 100644 index 0000000000..2a946e46ae --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_core.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + */ + +#ifndef __MGB4_CORE_H__ +#define __MGB4_CORE_H__ + +#include <linux/spi/flash.h> +#include <linux/mtd/partitions.h> +#include <linux/mutex.h> +#include <linux/dmaengine.h> +#include "mgb4_regs.h" + +#define MGB4_VIN_DEVICES 2 +#define MGB4_VOUT_DEVICES 2 + +#define MGB4_MGB4_BAR_ID 0 +#define MGB4_XDMA_BAR_ID 1 + +#define MGB4_IS_GMSL(mgbdev) \ + ((mgbdev)->module_version >> 4 == 2) +#define MGB4_IS_FPDL3(mgbdev) \ + ((mgbdev)->module_version >> 4 == 1) + +struct mgb4_dma_channel { + struct dma_chan *chan; + struct completion req_compl; +}; + +struct mgb4_dev { + struct pci_dev *pdev; + struct platform_device *xdev; + struct mgb4_vin_dev *vin[MGB4_VIN_DEVICES]; + struct mgb4_vout_dev *vout[MGB4_VOUT_DEVICES]; + + struct mgb4_dma_channel c2h_chan[MGB4_VIN_DEVICES]; + struct mgb4_dma_channel h2c_chan[MGB4_VOUT_DEVICES]; + struct dma_slave_map slave_map[MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES]; + + struct mgb4_regs video; + struct mgb4_regs cmt; + + struct clk_hw *i2c_clk; + struct clk_lookup *i2c_cl; + struct platform_device *i2c_pdev; + struct i2c_adapter *i2c_adap; + struct mutex i2c_lock; /* I2C bus access lock */ + + struct platform_device *spi_pdev; + struct flash_platform_data flash_data; + struct mtd_partition partitions[2]; + char flash_name[16]; + char fw_part_name[16]; + char data_part_name[16]; + char channel_names[MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES][16]; + + struct iio_dev *indio_dev; +#if IS_REACHABLE(CONFIG_HWMON) + struct device *hwmon_dev; +#endif + + unsigned long io_reconfig; + + u8 module_version; + u32 serial_number; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs; +#endif +}; + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_dma.c b/drivers/media/pci/mgb4/mgb4_dma.c new file mode 100644 index 0000000000..cae888e650 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_dma.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + * + * This module handles the DMA transfers. A standard dmaengine API as provided + * by the XDMA module is used. + */ + +#include <linux/pci.h> +#include <linux/dma-direction.h> +#include "mgb4_core.h" +#include "mgb4_dma.h" + +static void chan_irq(void *param) +{ + struct mgb4_dma_channel *chan = param; + + complete(&chan->req_compl); +} + +int mgb4_dma_transfer(struct mgb4_dev *mgbdev, u32 channel, bool write, + u64 paddr, struct sg_table *sgt) +{ + struct dma_slave_config cfg; + struct mgb4_dma_channel *chan; + struct dma_async_tx_descriptor *tx; + struct pci_dev *pdev = mgbdev->pdev; + int ret; + + memset(&cfg, 0, sizeof(cfg)); + + if (write) { + cfg.direction = DMA_MEM_TO_DEV; + cfg.dst_addr = paddr; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + chan = &mgbdev->h2c_chan[channel]; + } else { + cfg.direction = DMA_DEV_TO_MEM; + cfg.src_addr = paddr; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + chan = &mgbdev->c2h_chan[channel]; + } + + ret = dmaengine_slave_config(chan->chan, &cfg); + if (ret) { + dev_err(&pdev->dev, "failed to config dma: %d\n", ret); + return ret; + } + + tx = dmaengine_prep_slave_sg(chan->chan, sgt->sgl, sgt->nents, + cfg.direction, 0); + if (!tx) { + dev_err(&pdev->dev, "failed to prep slave sg\n"); + return -EIO; + } + + tx->callback = chan_irq; + tx->callback_param = chan; + + ret = dma_submit_error(dmaengine_submit(tx)); + if (ret) { + dev_err(&pdev->dev, "failed to submit sg\n"); + return -EIO; + } + + dma_async_issue_pending(chan->chan); + + if (!wait_for_completion_timeout(&chan->req_compl, + msecs_to_jiffies(10000))) { + dev_err(&pdev->dev, "dma timeout\n"); + dmaengine_terminate_sync(chan->chan); + return -EIO; + } + + return 0; +} + +int mgb4_dma_channel_init(struct mgb4_dev *mgbdev) +{ + int i, ret; + char name[16]; + struct pci_dev *pdev = mgbdev->pdev; + + for (i = 0; i < MGB4_VIN_DEVICES; i++) { + sprintf(name, "c2h%d", i); + mgbdev->c2h_chan[i].chan = dma_request_chan(&pdev->dev, name); + if (IS_ERR(mgbdev->c2h_chan[i].chan)) { + dev_err(&pdev->dev, "failed to initialize %s", name); + ret = PTR_ERR(mgbdev->c2h_chan[i].chan); + mgbdev->c2h_chan[i].chan = NULL; + return ret; + } + init_completion(&mgbdev->c2h_chan[i].req_compl); + } + for (i = 0; i < MGB4_VOUT_DEVICES; i++) { + sprintf(name, "h2c%d", i); + mgbdev->h2c_chan[i].chan = dma_request_chan(&pdev->dev, name); + if (IS_ERR(mgbdev->h2c_chan[i].chan)) { + dev_err(&pdev->dev, "failed to initialize %s", name); + ret = PTR_ERR(mgbdev->h2c_chan[i].chan); + mgbdev->h2c_chan[i].chan = NULL; + return ret; + } + init_completion(&mgbdev->h2c_chan[i].req_compl); + } + + return 0; +} + +void mgb4_dma_channel_free(struct mgb4_dev *mgbdev) +{ + int i; + + for (i = 0; i < MGB4_VIN_DEVICES; i++) { + if (mgbdev->c2h_chan[i].chan) + dma_release_channel(mgbdev->c2h_chan[i].chan); + } + for (i = 0; i < MGB4_VOUT_DEVICES; i++) { + if (mgbdev->h2c_chan[i].chan) + dma_release_channel(mgbdev->h2c_chan[i].chan); + } +} diff --git a/drivers/media/pci/mgb4/mgb4_dma.h b/drivers/media/pci/mgb4/mgb4_dma.h new file mode 100644 index 0000000000..4ebc2b1ce9 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_dma.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + */ + +#ifndef __MGB4_DMA_H__ +#define __MGB4_DMA_H__ + +#include "mgb4_core.h" + +int mgb4_dma_channel_init(struct mgb4_dev *mgbdev); +void mgb4_dma_channel_free(struct mgb4_dev *mgbdev); + +int mgb4_dma_transfer(struct mgb4_dev *mgbdev, u32 channel, bool write, + u64 paddr, struct sg_table *sgt); + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_i2c.c b/drivers/media/pci/mgb4/mgb4_i2c.c new file mode 100644 index 0000000000..2697b67e29 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_i2c.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + * + * The i2c module unifies the I2C access to the serializes/deserializes. The I2C + * chips on the GMSL module use 16b addressing, the FPDL3 chips use standard + * 8b addressing. + */ + +#include "mgb4_i2c.h" + +static int read_r16(struct i2c_client *client, u16 reg, u8 *val, int len) +{ + int ret; + u8 buf[2]; + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = buf, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = val, + } + }; + + buf[0] = (reg >> 8) & 0xff; + buf[1] = (reg >> 0) & 0xff; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) + return ret; + else if (ret != 2) + return -EREMOTEIO; + else + return 0; +} + +static int write_r16(struct i2c_client *client, u16 reg, const u8 *val, int len) +{ + int ret; + u8 buf[4]; + struct i2c_msg msg[1] = { + { + .addr = client->addr, + .flags = 0, + .len = 2 + len, + .buf = buf, + } + }; + + if (2 + len > sizeof(buf)) + return -EINVAL; + + buf[0] = (reg >> 8) & 0xff; + buf[1] = (reg >> 0) & 0xff; + memcpy(&buf[2], val, len); + + ret = i2c_transfer(client->adapter, msg, 1); + if (ret < 0) + return ret; + else if (ret != 1) + return -EREMOTEIO; + else + return 0; +} + +int mgb4_i2c_init(struct mgb4_i2c_client *client, struct i2c_adapter *adap, + struct i2c_board_info const *info, int addr_size) +{ + client->client = i2c_new_client_device(adap, info); + if (IS_ERR(client->client)) + return PTR_ERR(client->client); + + client->addr_size = addr_size; + + return 0; +} + +void mgb4_i2c_free(struct mgb4_i2c_client *client) +{ + i2c_unregister_device(client->client); +} + +s32 mgb4_i2c_read_byte(struct mgb4_i2c_client *client, u16 reg) +{ + int ret; + u8 b; + + if (client->addr_size == 8) + return i2c_smbus_read_byte_data(client->client, reg); + + ret = read_r16(client->client, reg, &b, 1); + if (ret < 0) + return ret; + + return (s32)b; +} + +s32 mgb4_i2c_write_byte(struct mgb4_i2c_client *client, u16 reg, u8 val) +{ + if (client->addr_size == 8) + return i2c_smbus_write_byte_data(client->client, reg, val); + else + return write_r16(client->client, reg, &val, 1); +} + +s32 mgb4_i2c_mask_byte(struct mgb4_i2c_client *client, u16 reg, u8 mask, u8 val) +{ + s32 ret; + + if (mask != 0xFF) { + ret = mgb4_i2c_read_byte(client, reg); + if (ret < 0) + return ret; + val |= (u8)ret & ~mask; + } + + return mgb4_i2c_write_byte(client, reg, val); +} + +int mgb4_i2c_configure(struct mgb4_i2c_client *client, + const struct mgb4_i2c_kv *values, size_t count) +{ + size_t i; + s32 res; + + for (i = 0; i < count; i++) { + res = mgb4_i2c_mask_byte(client, values[i].reg, values[i].mask, + values[i].val); + if (res < 0) + return res; + } + + return 0; +} diff --git a/drivers/media/pci/mgb4/mgb4_i2c.h b/drivers/media/pci/mgb4/mgb4_i2c.h new file mode 100644 index 0000000000..fac6a16344 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_i2c.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + */ + +#ifndef __MGB4_I2C_H__ +#define __MGB4_I2C_H__ + +#include <linux/i2c.h> + +struct mgb4_i2c_client { + struct i2c_client *client; + int addr_size; +}; + +struct mgb4_i2c_kv { + u16 reg; + u8 mask; + u8 val; +}; + +int mgb4_i2c_init(struct mgb4_i2c_client *client, struct i2c_adapter *adap, + struct i2c_board_info const *info, int addr_size); +void mgb4_i2c_free(struct mgb4_i2c_client *client); + +s32 mgb4_i2c_read_byte(struct mgb4_i2c_client *client, u16 reg); +s32 mgb4_i2c_write_byte(struct mgb4_i2c_client *client, u16 reg, u8 val); +s32 mgb4_i2c_mask_byte(struct mgb4_i2c_client *client, u16 reg, u8 mask, + u8 val); + +int mgb4_i2c_configure(struct mgb4_i2c_client *client, + const struct mgb4_i2c_kv *values, size_t count); + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_io.h b/drivers/media/pci/mgb4/mgb4_io.h new file mode 100644 index 0000000000..8698db1be4 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_io.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + */ + +#ifndef __MGB4_IO_H__ +#define __MGB4_IO_H__ + +#include <media/v4l2-dev.h> + +#define MGB4_DEFAULT_WIDTH 1280 +#define MGB4_DEFAULT_HEIGHT 640 +#define MGB4_DEFAULT_PERIOD (125000000 / 60) + +/* Register access error indication */ +#define MGB4_ERR_NO_REG 0xFFFFFFFE +/* Frame buffer addresses greater than 0xFFFFFFFA indicate HW errors */ +#define MGB4_ERR_QUEUE_TIMEOUT 0xFFFFFFFD +#define MGB4_ERR_QUEUE_EMPTY 0xFFFFFFFC +#define MGB4_ERR_QUEUE_FULL 0xFFFFFFFB + +struct mgb4_frame_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; +}; + +static inline struct mgb4_frame_buffer *to_frame_buffer(struct vb2_v4l2_buffer *vbuf) +{ + return container_of(vbuf, struct mgb4_frame_buffer, vb); +} + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_regs.c b/drivers/media/pci/mgb4/mgb4_regs.c new file mode 100644 index 0000000000..53d4e4503a --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_regs.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + */ + +#include <linux/ioport.h> +#include "mgb4_regs.h" + +int mgb4_regs_map(struct resource *res, struct mgb4_regs *regs) +{ + regs->mapbase = res->start; + regs->mapsize = res->end - res->start; + + if (!request_mem_region(regs->mapbase, regs->mapsize, res->name)) + return -EINVAL; + regs->membase = ioremap(regs->mapbase, regs->mapsize); + if (!regs->membase) { + release_mem_region(regs->mapbase, regs->mapsize); + return -EINVAL; + } + + return 0; +} + +void mgb4_regs_free(struct mgb4_regs *regs) +{ + iounmap(regs->membase); + release_mem_region(regs->mapbase, regs->mapsize); +} diff --git a/drivers/media/pci/mgb4/mgb4_regs.h b/drivers/media/pci/mgb4/mgb4_regs.h new file mode 100644 index 0000000000..c451808907 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_regs.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + */ + +#ifndef __MGB4_REGS_H__ +#define __MGB4_REGS_H__ + +#include <linux/io.h> + +struct mgb4_regs { + resource_size_t mapbase; + resource_size_t mapsize; + void __iomem *membase; +}; + +#define mgb4_write_reg(regs, offset, val) \ + iowrite32(val, (regs)->membase + (offset)) +#define mgb4_read_reg(regs, offset) \ + ioread32((regs)->membase + (offset)) + +static inline void mgb4_mask_reg(struct mgb4_regs *regs, u32 reg, u32 mask, + u32 val) +{ + u32 ret = mgb4_read_reg(regs, reg); + + val |= ret & ~mask; + mgb4_write_reg(regs, reg, val); +} + +int mgb4_regs_map(struct resource *res, struct mgb4_regs *regs); +void mgb4_regs_free(struct mgb4_regs *regs); + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_sysfs.h b/drivers/media/pci/mgb4/mgb4_sysfs.h new file mode 100644 index 0000000000..017d82c062 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_sysfs.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + */ + +#ifndef __MGB4_SYSFS_H__ +#define __MGB4_SYSFS_H__ + +#include <linux/sysfs.h> + +extern struct attribute *mgb4_pci_attrs[]; +extern struct attribute *mgb4_fpdl3_in_attrs[]; +extern struct attribute *mgb4_gmsl_in_attrs[]; +extern struct attribute *mgb4_fpdl3_out_attrs[]; +extern struct attribute *mgb4_gmsl_out_attrs[]; + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_in.c b/drivers/media/pci/mgb4/mgb4_sysfs_in.c new file mode 100644 index 0000000000..0ba66a2cf1 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_sysfs_in.c @@ -0,0 +1,772 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + * + * This module handles all the sysfs info/configuration that is related to the + * v4l2 input devices. + */ + +#include <linux/device.h> +#include "mgb4_core.h" +#include "mgb4_i2c.h" +#include "mgb4_vin.h" +#include "mgb4_cmt.h" +#include "mgb4_sysfs.h" + +/* Common for both FPDL3 and GMSL */ + +static ssize_t input_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + + return sprintf(buf, "%d\n", vindev->config->id); +} + +static ssize_t oldi_lane_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + struct mgb4_dev *mgbdev = vindev->mgbdev; + u16 i2c_reg; + u8 i2c_mask, i2c_single_val, i2c_dual_val; + u32 config; + int ret; + + i2c_reg = MGB4_IS_GMSL(mgbdev) ? 0x1CE : 0x49; + i2c_mask = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x03; + i2c_single_val = MGB4_IS_GMSL(mgbdev) ? 0x00 : 0x02; + i2c_dual_val = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x00; + + mutex_lock(&mgbdev->i2c_lock); + ret = mgb4_i2c_read_byte(&vindev->deser, i2c_reg); + mutex_unlock(&mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + config = mgb4_read_reg(&mgbdev->video, vindev->config->regs.config); + + if (((config & (1U << 9)) && ((ret & i2c_mask) != i2c_dual_val)) || + (!(config & (1U << 9)) && ((ret & i2c_mask) != i2c_single_val))) { + dev_err(dev, "I2C/FPGA register value mismatch\n"); + return -EINVAL; + } + + return sprintf(buf, "%s\n", config & (1U << 9) ? "1" : "0"); +} + +/* + * OLDI lane width change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t oldi_lane_width_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + struct mgb4_dev *mgbdev = vindev->mgbdev; + u32 fpga_data; + u16 i2c_reg; + u8 i2c_mask, i2c_data; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + switch (val) { + case 0: /* single */ + fpga_data = 0; + i2c_data = MGB4_IS_GMSL(mgbdev) ? 0x00 : 0x02; + break; + case 1: /* dual */ + fpga_data = 1U << 9; + i2c_data = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x00; + break; + default: + return -EINVAL; + } + + i2c_reg = MGB4_IS_GMSL(mgbdev) ? 0x1CE : 0x49; + i2c_mask = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x03; + + mutex_lock(&mgbdev->i2c_lock); + ret = mgb4_i2c_mask_byte(&vindev->deser, i2c_reg, i2c_mask, i2c_data); + mutex_unlock(&mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + mgb4_mask_reg(&mgbdev->video, vindev->config->regs.config, 1U << 9, + fpga_data); + if (MGB4_IS_GMSL(mgbdev)) { + /* reset input link */ + mutex_lock(&mgbdev->i2c_lock); + ret = mgb4_i2c_mask_byte(&vindev->deser, 0x10, 1U << 5, 1U << 5); + mutex_unlock(&mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + } + + return count; +} + +static ssize_t color_mapping_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.config); + + return sprintf(buf, "%s\n", config & (1U << 8) ? "0" : "1"); +} + +/* + * Color mapping change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t color_mapping_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 fpga_data; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + switch (val) { + case 0: /* OLDI/JEIDA */ + fpga_data = (1U << 8); + break; + case 1: /* SPWG/VESA */ + fpga_data = 0; + break; + default: + return -EINVAL; + } + + mgb4_mask_reg(&vindev->mgbdev->video, vindev->config->regs.config, + 1U << 8, fpga_data); + + return count; +} + +static ssize_t link_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 status = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.status); + + return sprintf(buf, "%s\n", status & (1U << 2) ? "1" : "0"); +} + +static ssize_t stream_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 status = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.status); + + return sprintf(buf, "%s\n", ((status & (1 << 14)) && + (status & (1 << 2)) && (status & (3 << 9))) ? "1" : "0"); +} + +static ssize_t video_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.resolution); + + return sprintf(buf, "%u\n", config >> 16); +} + +static ssize_t video_height_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.resolution); + + return sprintf(buf, "%u\n", config & 0xFFFF); +} + +static ssize_t hsync_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 status = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.status); + u32 res; + + if (!(status & (1U << 11))) + res = 0x02; // not available + else if (status & (1U << 12)) + res = 0x01; // active high + else + res = 0x00; // active low + + return sprintf(buf, "%u\n", res); +} + +static ssize_t vsync_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 status = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.status); + u32 res; + + if (!(status & (1U << 11))) + res = 0x02; // not available + else if (status & (1U << 13)) + res = 0x01; // active high + else + res = 0x00; // active low + + return sprintf(buf, "%u\n", res); +} + +static ssize_t hsync_gap_length_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sync = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.sync); + + return sprintf(buf, "%u\n", sync >> 16); +} + +/* + * HSYNC gap length change is expected to be called on live streams. Video + * device locking/queue check is not needed. + */ +static ssize_t hsync_gap_length_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFFFF) + return -EINVAL; + + mgb4_mask_reg(&vindev->mgbdev->video, vindev->config->regs.sync, + 0xFFFF0000, val << 16); + + return count; +} + +static ssize_t vsync_gap_length_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sync = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.sync); + + return sprintf(buf, "%u\n", sync & 0xFFFF); +} + +/* + * VSYNC gap length change is expected to be called on live streams. Video + * device locking/queue check is not needed. + */ +static ssize_t vsync_gap_length_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFFFF) + return -EINVAL; + + mgb4_mask_reg(&vindev->mgbdev->video, vindev->config->regs.sync, 0xFFFF, + val); + + return count; +} + +static ssize_t pclk_frequency_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 freq = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.pclk); + + return sprintf(buf, "%u\n", freq); +} + +static ssize_t hsync_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.signal); + + return sprintf(buf, "%u\n", (sig & 0x00FF0000) >> 16); +} + +static ssize_t vsync_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.signal2); + + return sprintf(buf, "%u\n", (sig & 0x00FF0000) >> 16); +} + +static ssize_t hback_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.signal); + + return sprintf(buf, "%u\n", (sig & 0x0000FF00) >> 8); +} + +static ssize_t hfront_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.signal); + + return sprintf(buf, "%u\n", (sig & 0x000000FF)); +} + +static ssize_t vback_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.signal2); + + return sprintf(buf, "%u\n", (sig & 0x0000FF00) >> 8); +} + +static ssize_t vfront_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&vindev->mgbdev->video, + vindev->config->regs.signal2); + + return sprintf(buf, "%u\n", (sig & 0x000000FF)); +} + +static ssize_t frequency_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + + return sprintf(buf, "%d\n", vindev->freq_range); +} + +static ssize_t frequency_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 1) + return -EINVAL; + + mutex_lock(vindev->vdev.lock); + if (vb2_is_busy(vindev->vdev.queue)) { + mutex_unlock(vindev->vdev.lock); + return -EBUSY; + } + + mgb4_cmt_set_vin_freq_range(vindev, val); + vindev->freq_range = val; + + mutex_unlock(vindev->vdev.lock); + + return count; +} + +/* FPDL3 only */ + +static ssize_t fpdl3_input_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + s32 ret; + + mutex_lock(&vindev->mgbdev->i2c_lock); + ret = mgb4_i2c_read_byte(&vindev->deser, 0x34); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + switch ((u8)ret & 0x18) { + case 0: + return sprintf(buf, "0\n"); + case 0x10: + return sprintf(buf, "1\n"); + case 0x08: + return sprintf(buf, "2\n"); + default: + return -EINVAL; + } +} + +/* + * FPD-Link width change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t fpdl3_input_width_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + u8 i2c_data; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + switch (val) { + case 0: /* auto */ + i2c_data = 0x00; + break; + case 1: /* single */ + i2c_data = 0x10; + break; + case 2: /* dual */ + i2c_data = 0x08; + break; + default: + return -EINVAL; + } + + mutex_lock(&vindev->mgbdev->i2c_lock); + ret = mgb4_i2c_mask_byte(&vindev->deser, 0x34, 0x18, i2c_data); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + return count; +} + +/* GMSL only */ + +static ssize_t gmsl_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + s32 r1, r300, r3; + + mutex_lock(&vindev->mgbdev->i2c_lock); + r1 = mgb4_i2c_read_byte(&vindev->deser, 0x01); + r300 = mgb4_i2c_read_byte(&vindev->deser, 0x300); + r3 = mgb4_i2c_read_byte(&vindev->deser, 0x03); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (r1 < 0 || r300 < 0 || r3 < 0) + return -EIO; + + if ((r1 & 0x03) == 0x03 && (r300 & 0x0C) == 0x0C && (r3 & 0xC0) == 0xC0) + return sprintf(buf, "0\n"); + else if ((r1 & 0x03) == 0x02 && (r300 & 0x0C) == 0x08 && (r3 & 0xC0) == 0x00) + return sprintf(buf, "1\n"); + else if ((r1 & 0x03) == 0x01 && (r300 & 0x0C) == 0x04 && (r3 & 0xC0) == 0x00) + return sprintf(buf, "2\n"); + else if ((r1 & 0x03) == 0x00 && (r300 & 0x0C) == 0x00 && (r3 & 0xC0) == 0x00) + return sprintf(buf, "3\n"); + else + return -EINVAL; +} + +/* + * GMSL mode change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t gmsl_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + static const struct mgb4_i2c_kv G12[] = { + {0x01, 0x03, 0x03}, {0x300, 0x0C, 0x0C}, {0x03, 0xC0, 0xC0}}; + static const struct mgb4_i2c_kv G6[] = { + {0x01, 0x03, 0x02}, {0x300, 0x0C, 0x08}, {0x03, 0xC0, 0x00}}; + static const struct mgb4_i2c_kv G3[] = { + {0x01, 0x03, 0x01}, {0x300, 0x0C, 0x04}, {0x03, 0xC0, 0x00}}; + static const struct mgb4_i2c_kv G1[] = { + {0x01, 0x03, 0x00}, {0x300, 0x0C, 0x00}, {0x03, 0xC0, 0x00}}; + static const struct mgb4_i2c_kv reset[] = { + {0x10, 1U << 5, 1U << 5}, {0x300, 1U << 6, 1U << 6}}; + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + const struct mgb4_i2c_kv *values; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + switch (val) { + case 0: /* 12Gb/s */ + values = G12; + break; + case 1: /* 6Gb/s */ + values = G6; + break; + case 2: /* 3Gb/s */ + values = G3; + break; + case 3: /* 1.5Gb/s */ + values = G1; + break; + default: + return -EINVAL; + } + + mutex_lock(&vindev->mgbdev->i2c_lock); + ret = mgb4_i2c_configure(&vindev->deser, values, 3); + ret |= mgb4_i2c_configure(&vindev->deser, reset, 2); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + return count; +} + +static ssize_t gmsl_stream_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + s32 ret; + + mutex_lock(&vindev->mgbdev->i2c_lock); + ret = mgb4_i2c_read_byte(&vindev->deser, 0xA0); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + return sprintf(buf, "%d\n", ret & 0x03); +} + +static ssize_t gmsl_stream_id_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 3) + return -EINVAL; + + mutex_lock(vindev->vdev.lock); + if (vb2_is_busy(vindev->vdev.queue)) { + mutex_unlock(vindev->vdev.lock); + return -EBUSY; + } + + mutex_lock(&vindev->mgbdev->i2c_lock); + ret = mgb4_i2c_mask_byte(&vindev->deser, 0xA0, 0x03, (u8)val); + mutex_unlock(&vindev->mgbdev->i2c_lock); + + mutex_unlock(vindev->vdev.lock); + + return (ret < 0) ? -EIO : count; +} + +static ssize_t gmsl_fec_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + s32 r3e0, r308; + + mutex_lock(&vindev->mgbdev->i2c_lock); + r3e0 = mgb4_i2c_read_byte(&vindev->deser, 0x3E0); + r308 = mgb4_i2c_read_byte(&vindev->deser, 0x308); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (r3e0 < 0 || r308 < 0) + return -EIO; + + if ((r3e0 & 0x07) == 0x00 && (r308 & 0x01) == 0x00) + return sprintf(buf, "0\n"); + else if ((r3e0 & 0x07) == 0x07 && (r308 & 0x01) == 0x01) + return sprintf(buf, "1\n"); + else + return -EINVAL; +} + +/* + * GMSL FEC change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t gmsl_fec_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vin_dev *vindev = video_get_drvdata(vdev); + static const struct mgb4_i2c_kv enable[] = { + {0x3E0, 0x07, 0x07}, {0x308, 0x01, 0x01}}; + static const struct mgb4_i2c_kv disable[] = { + {0x3E0, 0x07, 0x00}, {0x308, 0x01, 0x00}}; + static const struct mgb4_i2c_kv reset[] = { + {0x10, 1U << 5, 1U << 5}, {0x300, 1U << 6, 1U << 6}}; + const struct mgb4_i2c_kv *values; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + switch (val) { + case 0: /* disabled */ + values = disable; + break; + case 1: /* enabled */ + values = enable; + break; + default: + return -EINVAL; + } + + mutex_lock(&vindev->mgbdev->i2c_lock); + ret = mgb4_i2c_configure(&vindev->deser, values, 2); + ret |= mgb4_i2c_configure(&vindev->deser, reset, 2); + mutex_unlock(&vindev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + return count; +} + +static DEVICE_ATTR_RO(input_id); +static DEVICE_ATTR_RW(oldi_lane_width); +static DEVICE_ATTR_RW(color_mapping); +static DEVICE_ATTR_RO(link_status); +static DEVICE_ATTR_RO(stream_status); +static DEVICE_ATTR_RO(video_width); +static DEVICE_ATTR_RO(video_height); +static DEVICE_ATTR_RO(hsync_status); +static DEVICE_ATTR_RO(vsync_status); +static DEVICE_ATTR_RW(hsync_gap_length); +static DEVICE_ATTR_RW(vsync_gap_length); +static DEVICE_ATTR_RO(pclk_frequency); +static DEVICE_ATTR_RO(hsync_width); +static DEVICE_ATTR_RO(vsync_width); +static DEVICE_ATTR_RO(hback_porch); +static DEVICE_ATTR_RO(hfront_porch); +static DEVICE_ATTR_RO(vback_porch); +static DEVICE_ATTR_RO(vfront_porch); +static DEVICE_ATTR_RW(frequency_range); + +static DEVICE_ATTR_RW(fpdl3_input_width); + +static DEVICE_ATTR_RW(gmsl_mode); +static DEVICE_ATTR_RW(gmsl_stream_id); +static DEVICE_ATTR_RW(gmsl_fec); + +struct attribute *mgb4_fpdl3_in_attrs[] = { + &dev_attr_input_id.attr, + &dev_attr_link_status.attr, + &dev_attr_stream_status.attr, + &dev_attr_video_width.attr, + &dev_attr_video_height.attr, + &dev_attr_hsync_status.attr, + &dev_attr_vsync_status.attr, + &dev_attr_oldi_lane_width.attr, + &dev_attr_color_mapping.attr, + &dev_attr_hsync_gap_length.attr, + &dev_attr_vsync_gap_length.attr, + &dev_attr_pclk_frequency.attr, + &dev_attr_hsync_width.attr, + &dev_attr_vsync_width.attr, + &dev_attr_hback_porch.attr, + &dev_attr_hfront_porch.attr, + &dev_attr_vback_porch.attr, + &dev_attr_vfront_porch.attr, + &dev_attr_frequency_range.attr, + &dev_attr_fpdl3_input_width.attr, + NULL +}; + +struct attribute *mgb4_gmsl_in_attrs[] = { + &dev_attr_input_id.attr, + &dev_attr_link_status.attr, + &dev_attr_stream_status.attr, + &dev_attr_video_width.attr, + &dev_attr_video_height.attr, + &dev_attr_hsync_status.attr, + &dev_attr_vsync_status.attr, + &dev_attr_oldi_lane_width.attr, + &dev_attr_color_mapping.attr, + &dev_attr_hsync_gap_length.attr, + &dev_attr_vsync_gap_length.attr, + &dev_attr_pclk_frequency.attr, + &dev_attr_hsync_width.attr, + &dev_attr_vsync_width.attr, + &dev_attr_hback_porch.attr, + &dev_attr_hfront_porch.attr, + &dev_attr_vback_porch.attr, + &dev_attr_vfront_porch.attr, + &dev_attr_frequency_range.attr, + &dev_attr_gmsl_mode.attr, + &dev_attr_gmsl_stream_id.attr, + &dev_attr_gmsl_fec.attr, + NULL +}; diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_out.c b/drivers/media/pci/mgb4/mgb4_sysfs_out.c new file mode 100644 index 0000000000..9f6e81c577 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_sysfs_out.c @@ -0,0 +1,740 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + * + * This module handles all the sysfs info/configuration that is related to the + * v4l2 output devices. + */ + +#include <linux/device.h> +#include <linux/nospec.h> +#include "mgb4_core.h" +#include "mgb4_i2c.h" +#include "mgb4_vout.h" +#include "mgb4_vin.h" +#include "mgb4_cmt.h" +#include "mgb4_sysfs.h" + +static int loopin_cnt(struct mgb4_vin_dev *vindev) +{ + struct mgb4_vout_dev *voutdev; + u32 config; + int i, cnt = 0; + + for (i = 0; i < MGB4_VOUT_DEVICES; i++) { + voutdev = vindev->mgbdev->vout[i]; + if (!voutdev) + continue; + + config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.config); + if ((config & 0xc) >> 2 == vindev->config->id) + cnt++; + } + + return cnt; +} + +static bool is_busy(struct video_device *dev) +{ + bool ret; + + mutex_lock(dev->lock); + ret = vb2_is_busy(dev->queue); + mutex_unlock(dev->lock); + + return ret; +} + +/* Common for both FPDL3 and GMSL */ + +static ssize_t output_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + + return sprintf(buf, "%d\n", voutdev->config->id); +} + +static ssize_t video_source_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.config); + + return sprintf(buf, "%u\n", (config & 0xc) >> 2); +} + +/* + * Video source change may affect the buffer queue of ANY video input/output on + * the card thus if any of the inputs/outputs is in use, we do not allow + * the change. + * + * As we do not want to lock all the video devices at the same time, a two-stage + * locking strategy is used. In addition to the video device locking there is + * a global (PCI device) variable "io_reconfig" atomically checked/set when + * the reconfiguration is running. All the video devices check the variable in + * their queue_setup() functions and do not allow to start the queue when + * the reconfiguration has started. + */ +static ssize_t video_source_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + struct mgb4_dev *mgbdev = voutdev->mgbdev; + struct mgb4_vin_dev *loopin_new = NULL, *loopin_old = NULL; + unsigned long val; + ssize_t ret; + u32 config; + int i; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 3) + return -EINVAL; + + if (test_and_set_bit(0, &mgbdev->io_reconfig)) + return -EBUSY; + + ret = -EBUSY; + for (i = 0; i < MGB4_VIN_DEVICES; i++) + if (mgbdev->vin[i] && is_busy(&mgbdev->vin[i]->vdev)) + goto end; + for (i = 0; i < MGB4_VOUT_DEVICES; i++) + if (mgbdev->vout[i] && is_busy(&mgbdev->vout[i]->vdev)) + goto end; + + config = mgb4_read_reg(&mgbdev->video, voutdev->config->regs.config); + + if (((config & 0xc) >> 2) < MGB4_VIN_DEVICES) + loopin_old = mgbdev->vin[(config & 0xc) >> 2]; + if (val < MGB4_VIN_DEVICES) { + val = array_index_nospec(val, MGB4_VIN_DEVICES); + loopin_new = mgbdev->vin[val]; + } + if (loopin_old && loopin_cnt(loopin_old) == 1) + mgb4_mask_reg(&mgbdev->video, loopin_old->config->regs.config, + 0x2, 0x0); + if (loopin_new) + mgb4_mask_reg(&mgbdev->video, loopin_new->config->regs.config, + 0x2, 0x2); + + if (val == voutdev->config->id + MGB4_VIN_DEVICES) + mgb4_write_reg(&mgbdev->video, voutdev->config->regs.config, + config & ~(1 << 1)); + else + mgb4_write_reg(&mgbdev->video, voutdev->config->regs.config, + config | (1U << 1)); + + mgb4_mask_reg(&mgbdev->video, voutdev->config->regs.config, 0xc, + val << 2); + + ret = count; +end: + clear_bit(0, &mgbdev->io_reconfig); + + return ret; +} + +static ssize_t display_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.resolution); + + return sprintf(buf, "%u\n", config >> 16); +} + +static ssize_t display_width_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFFFF) + return -EINVAL; + + mutex_lock(voutdev->vdev.lock); + if (vb2_is_busy(voutdev->vdev.queue)) { + mutex_unlock(voutdev->vdev.lock); + return -EBUSY; + } + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.resolution, + 0xFFFF0000, val << 16); + + mutex_unlock(voutdev->vdev.lock); + + return count; +} + +static ssize_t display_height_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.resolution); + + return sprintf(buf, "%u\n", config & 0xFFFF); +} + +static ssize_t display_height_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFFFF) + return -EINVAL; + + mutex_lock(voutdev->vdev.lock); + if (vb2_is_busy(voutdev->vdev.queue)) { + mutex_unlock(voutdev->vdev.lock); + return -EBUSY; + } + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.resolution, + 0xFFFF, val); + + mutex_unlock(voutdev->vdev.lock); + + return count; +} + +static ssize_t frame_rate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 period = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.frame_period); + + return sprintf(buf, "%u\n", 125000000 / period); +} + +/* + * Frame rate change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t frame_rate_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + mgb4_write_reg(&voutdev->mgbdev->video, + voutdev->config->regs.frame_period, 125000000 / val); + + return count; +} + +static ssize_t hsync_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.hsync); + + return sprintf(buf, "%u\n", (sig & 0x00FF0000) >> 16); +} + +/* + * HSYNC width change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t hsync_width_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFF) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync, + 0x00FF0000, val << 16); + + return count; +} + +static ssize_t vsync_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.vsync); + + return sprintf(buf, "%u\n", (sig & 0x00FF0000) >> 16); +} + +/* + * VSYNC vidth change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t vsync_width_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFF) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, + 0x00FF0000, val << 16); + + return count; +} + +static ssize_t hback_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.hsync); + + return sprintf(buf, "%u\n", (sig & 0x0000FF00) >> 8); +} + +/* + * hback porch change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t hback_porch_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFF) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync, + 0x0000FF00, val << 8); + + return count; +} + +static ssize_t vback_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.vsync); + + return sprintf(buf, "%u\n", (sig & 0x0000FF00) >> 8); +} + +/* + * vback porch change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t vback_porch_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFF) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, + 0x0000FF00, val << 8); + + return count; +} + +static ssize_t hfront_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.hsync); + + return sprintf(buf, "%u\n", (sig & 0x000000FF)); +} + +/* + * hfront porch change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t hfront_porch_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFF) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync, + 0x000000FF, val); + + return count; +} + +static ssize_t vfront_porch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.vsync); + + return sprintf(buf, "%u\n", (sig & 0x000000FF)); +} + +/* + * vfront porch change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t vfront_porch_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 0xFF) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, + 0x000000FF, val); + + return count; +} + +/* FPDL3 only */ + +static ssize_t hsync_polarity_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.hsync); + + return sprintf(buf, "%u\n", (config & (1U << 31)) >> 31); +} + +/* + * HSYNC polarity change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t hsync_polarity_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 1) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync, + (1U << 31), val << 31); + + return count; +} + +static ssize_t vsync_polarity_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.vsync); + + return sprintf(buf, "%u\n", (config & (1U << 31)) >> 31); +} + +/* + * VSYNC polarity change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t vsync_polarity_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 1) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, + (1U << 31), val << 31); + + return count; +} + +static ssize_t de_polarity_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u32 config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.vsync); + + return sprintf(buf, "%u\n", (config & (1U << 30)) >> 30); +} + +/* + * DE polarity change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t de_polarity_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val > 1) + return -EINVAL; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, + (1U << 30), val << 30); + + return count; +} + +static ssize_t fpdl3_output_width_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + s32 ret; + + mutex_lock(&voutdev->mgbdev->i2c_lock); + ret = mgb4_i2c_read_byte(&voutdev->ser, 0x5B); + mutex_unlock(&voutdev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + switch ((u8)ret & 0x03) { + case 0: + return sprintf(buf, "0\n"); + case 1: + return sprintf(buf, "1\n"); + case 3: + return sprintf(buf, "2\n"); + default: + return -EINVAL; + } +} + +/* + * FPD-Link width change is expected to be called on live streams. Video device + * locking/queue check is not needed. + */ +static ssize_t fpdl3_output_width_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + u8 i2c_data; + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + switch (val) { + case 0: /* auto */ + i2c_data = 0x00; + break; + case 1: /* single */ + i2c_data = 0x01; + break; + case 2: /* dual */ + i2c_data = 0x03; + break; + default: + return -EINVAL; + } + + mutex_lock(&voutdev->mgbdev->i2c_lock); + ret = mgb4_i2c_mask_byte(&voutdev->ser, 0x5B, 0x03, i2c_data); + mutex_unlock(&voutdev->mgbdev->i2c_lock); + if (ret < 0) + return -EIO; + + return count; +} + +static ssize_t pclk_frequency_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + + return sprintf(buf, "%u\n", voutdev->freq); +} + +static ssize_t pclk_frequency_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(dev); + struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); + unsigned long val; + int ret; + unsigned int dp; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(voutdev->vdev.lock); + if (vb2_is_busy(voutdev->vdev.queue)) { + mutex_unlock(voutdev->vdev.lock); + return -EBUSY; + } + + dp = (val > 50000) ? 1 : 0; + voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, val >> dp) << dp; + + mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.config, + 0x10, dp << 4); + mutex_lock(&voutdev->mgbdev->i2c_lock); + ret = mgb4_i2c_mask_byte(&voutdev->ser, 0x4F, 1 << 6, ((~dp) & 1) << 6); + mutex_unlock(&voutdev->mgbdev->i2c_lock); + + mutex_unlock(voutdev->vdev.lock); + + return (ret < 0) ? -EIO : count; +} + +static DEVICE_ATTR_RO(output_id); +static DEVICE_ATTR_RW(video_source); +static DEVICE_ATTR_RW(display_width); +static DEVICE_ATTR_RW(display_height); +static DEVICE_ATTR_RW(frame_rate); +static DEVICE_ATTR_RW(hsync_polarity); +static DEVICE_ATTR_RW(vsync_polarity); +static DEVICE_ATTR_RW(de_polarity); +static DEVICE_ATTR_RW(pclk_frequency); +static DEVICE_ATTR_RW(hsync_width); +static DEVICE_ATTR_RW(vsync_width); +static DEVICE_ATTR_RW(hback_porch); +static DEVICE_ATTR_RW(hfront_porch); +static DEVICE_ATTR_RW(vback_porch); +static DEVICE_ATTR_RW(vfront_porch); + +static DEVICE_ATTR_RW(fpdl3_output_width); + +struct attribute *mgb4_fpdl3_out_attrs[] = { + &dev_attr_output_id.attr, + &dev_attr_video_source.attr, + &dev_attr_display_width.attr, + &dev_attr_display_height.attr, + &dev_attr_frame_rate.attr, + &dev_attr_hsync_polarity.attr, + &dev_attr_vsync_polarity.attr, + &dev_attr_de_polarity.attr, + &dev_attr_pclk_frequency.attr, + &dev_attr_hsync_width.attr, + &dev_attr_vsync_width.attr, + &dev_attr_hback_porch.attr, + &dev_attr_hfront_porch.attr, + &dev_attr_vback_porch.attr, + &dev_attr_vfront_porch.attr, + &dev_attr_fpdl3_output_width.attr, + NULL +}; + +struct attribute *mgb4_gmsl_out_attrs[] = { + &dev_attr_output_id.attr, + &dev_attr_video_source.attr, + &dev_attr_display_width.attr, + &dev_attr_display_height.attr, + &dev_attr_frame_rate.attr, + NULL +}; diff --git a/drivers/media/pci/mgb4/mgb4_sysfs_pci.c b/drivers/media/pci/mgb4/mgb4_sysfs_pci.c new file mode 100644 index 0000000000..d26935ff95 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_sysfs_pci.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + * + * This module handles all the sysfs info/configuration that is related to the + * PCI card device. + */ + +#include <linux/device.h> +#include "mgb4_core.h" +#include "mgb4_sysfs.h" + +static ssize_t module_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mgb4_dev *mgbdev = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", mgbdev->module_version & 0x0F); +} + +static ssize_t module_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mgb4_dev *mgbdev = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", mgbdev->module_version >> 4); +} + +static ssize_t fw_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mgb4_dev *mgbdev = dev_get_drvdata(dev); + u32 config = mgb4_read_reg(&mgbdev->video, 0xC4); + + return sprintf(buf, "%u\n", config & 0xFFFF); +} + +static ssize_t fw_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mgb4_dev *mgbdev = dev_get_drvdata(dev); + u32 config = mgb4_read_reg(&mgbdev->video, 0xC4); + + return sprintf(buf, "%u\n", config >> 24); +} + +static ssize_t serial_number_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mgb4_dev *mgbdev = dev_get_drvdata(dev); + u32 sn = mgbdev->serial_number; + + return sprintf(buf, "%03d-%03d-%03d-%03d\n", sn >> 24, (sn >> 16) & 0xFF, + (sn >> 8) & 0xFF, sn & 0xFF); +} + +static DEVICE_ATTR_RO(module_version); +static DEVICE_ATTR_RO(module_type); +static DEVICE_ATTR_RO(fw_version); +static DEVICE_ATTR_RO(fw_type); +static DEVICE_ATTR_RO(serial_number); + +struct attribute *mgb4_pci_attrs[] = { + &dev_attr_module_type.attr, + &dev_attr_module_version.attr, + &dev_attr_fw_type.attr, + &dev_attr_fw_version.attr, + &dev_attr_serial_number.attr, + NULL +}; diff --git a/drivers/media/pci/mgb4/mgb4_trigger.c b/drivers/media/pci/mgb4/mgb4_trigger.c new file mode 100644 index 0000000000..923650d53d --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_trigger.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + * + * This module handles the IIO trigger device. The card has two signal inputs + * for event triggers that can be used to record events related to the video + * stream. A standard linux IIO device with triggered buffer capability is + * created and configured that can be used to fetch the events with the same + * clock source as the video frames. + */ + +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/pci.h> +#include <linux/dma/amd_xdma.h> +#include "mgb4_core.h" +#include "mgb4_trigger.h" + +struct trigger_data { + struct mgb4_dev *mgbdev; + struct iio_trigger *trig; +}; + +static int trigger_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct trigger_data *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + *val = mgb4_read_reg(&st->mgbdev->video, 0xA0); + + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int trigger_set_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct trigger_data *st = iio_priv(indio_dev); + int irq = xdma_get_user_irq(st->mgbdev->xdev, 11); + + if (state) + xdma_enable_user_irq(st->mgbdev->xdev, irq); + else + xdma_disable_user_irq(st->mgbdev->xdev, irq); + + return 0; +} + +static const struct iio_trigger_ops trigger_ops = { + .set_trigger_state = &trigger_set_state, +}; + +static const struct iio_info trigger_info = { + .read_raw = trigger_read_raw, +}; + +#define TRIGGER_CHANNEL(_si) { \ + .type = IIO_ACTIVITY, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .scan_index = _si, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 32, \ + .storagebits = 32, \ + .shift = 0, \ + .endianness = IIO_CPU \ + }, \ +} + +static const struct iio_chan_spec trigger_channels[] = { + TRIGGER_CHANNEL(0), + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static irqreturn_t trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct trigger_data *st = iio_priv(indio_dev); + struct { + u32 data; + s64 ts __aligned(8); + } scan; + + scan.data = mgb4_read_reg(&st->mgbdev->video, 0xA0); + mgb4_write_reg(&st->mgbdev->video, 0xA0, scan.data); + + iio_push_to_buffers_with_timestamp(indio_dev, &scan, pf->timestamp); + iio_trigger_notify_done(indio_dev->trig); + + mgb4_write_reg(&st->mgbdev->video, 0xB4, 1U << 11); + + return IRQ_HANDLED; +} + +static int probe_trigger(struct iio_dev *indio_dev, int irq) +{ + int ret; + struct trigger_data *st = iio_priv(indio_dev); + + st->trig = iio_trigger_alloc(&st->mgbdev->pdev->dev, "%s-dev%d", + indio_dev->name, iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + ret = request_irq(irq, &iio_trigger_generic_data_rdy_poll, 0, + "mgb4-trigger", st->trig); + if (ret) + goto error_free_trig; + + st->trig->ops = &trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = iio_trigger_register(st->trig); + if (ret) + goto error_free_irq; + + indio_dev->trig = iio_trigger_get(st->trig); + + return 0; + +error_free_irq: + free_irq(irq, st->trig); +error_free_trig: + iio_trigger_free(st->trig); + + return ret; +} + +static void remove_trigger(struct iio_dev *indio_dev, int irq) +{ + struct trigger_data *st = iio_priv(indio_dev); + + iio_trigger_unregister(st->trig); + free_irq(irq, st->trig); + iio_trigger_free(st->trig); +} + +struct iio_dev *mgb4_trigger_create(struct mgb4_dev *mgbdev) +{ + struct iio_dev *indio_dev; + struct trigger_data *data; + struct pci_dev *pdev = mgbdev->pdev; + struct device *dev = &pdev->dev; + int rv, irq; + + indio_dev = iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return NULL; + + indio_dev->info = &trigger_info; + indio_dev->name = "mgb4"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = trigger_channels; + indio_dev->num_channels = ARRAY_SIZE(trigger_channels); + + data = iio_priv(indio_dev); + data->mgbdev = mgbdev; + + irq = xdma_get_user_irq(mgbdev->xdev, 11); + rv = probe_trigger(indio_dev, irq); + if (rv < 0) { + dev_err(dev, "iio triggered setup failed\n"); + goto error_alloc; + } + rv = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + trigger_handler, NULL); + if (rv < 0) { + dev_err(dev, "iio triggered buffer setup failed\n"); + goto error_trigger; + } + rv = iio_device_register(indio_dev); + if (rv < 0) { + dev_err(dev, "iio device register failed\n"); + goto error_buffer; + } + + return indio_dev; + +error_buffer: + iio_triggered_buffer_cleanup(indio_dev); +error_trigger: + remove_trigger(indio_dev, irq); +error_alloc: + iio_device_free(indio_dev); + + return NULL; +} + +void mgb4_trigger_free(struct iio_dev *indio_dev) +{ + struct trigger_data *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + remove_trigger(indio_dev, xdma_get_user_irq(st->mgbdev->xdev, 11)); + iio_device_free(indio_dev); +} diff --git a/drivers/media/pci/mgb4/mgb4_trigger.h b/drivers/media/pci/mgb4/mgb4_trigger.h new file mode 100644 index 0000000000..6c25bc4576 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_trigger.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2022 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + */ + +struct iio_dev *mgb4_trigger_create(struct mgb4_dev *mgbdev); +void mgb4_trigger_free(struct iio_dev *indio_dev); diff --git a/drivers/media/pci/mgb4/mgb4_vin.c b/drivers/media/pci/mgb4/mgb4_vin.c new file mode 100644 index 0000000000..d72b07b87c --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_vin.c @@ -0,0 +1,939 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + * + * This is the v4l2 input device module. It initializes the signal deserializers + * and creates the v4l2 video devices. The input signal can change at any time + * which is handled by the "timings" callbacks and an IRQ based watcher, that + * emits the V4L2_EVENT_SOURCE_CHANGE event in case of a signal source change. + * + * When the device is in loopback mode (a direct, in HW, in->out frame passing + * mode) the card's frame queue must be running regardless of whether a v4l2 + * stream is running and the output parameters like frame buffers padding must + * be in sync with the input parameters. + */ + +#include <linux/pci.h> +#include <linux/workqueue.h> +#include <linux/align.h> +#include <linux/dma/amd_xdma.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-v4l2.h> +#include <media/videobuf2-dma-sg.h> +#include <media/v4l2-dv-timings.h> +#include <media/v4l2-event.h> +#include "mgb4_core.h" +#include "mgb4_dma.h" +#include "mgb4_sysfs.h" +#include "mgb4_io.h" +#include "mgb4_vout.h" +#include "mgb4_vin.h" + +ATTRIBUTE_GROUPS(mgb4_fpdl3_in); +ATTRIBUTE_GROUPS(mgb4_gmsl_in); + +static const struct mgb4_vin_config vin_cfg[] = { + {0, 0, 0, 6, {0x10, 0x00, 0x04, 0x08, 0x1C, 0x14, 0x18, 0x20, 0x24, 0x28}}, + {1, 1, 1, 7, {0x40, 0x30, 0x34, 0x38, 0x4C, 0x44, 0x48, 0x50, 0x54, 0x58}} +}; + +static const struct i2c_board_info fpdl3_deser_info[] = { + {I2C_BOARD_INFO("deserializer1", 0x38)}, + {I2C_BOARD_INFO("deserializer2", 0x36)}, +}; + +static const struct i2c_board_info gmsl_deser_info[] = { + {I2C_BOARD_INFO("deserializer1", 0x4C)}, + {I2C_BOARD_INFO("deserializer2", 0x2A)}, +}; + +static const struct mgb4_i2c_kv fpdl3_i2c[] = { + {0x06, 0xFF, 0x04}, {0x07, 0xFF, 0x01}, {0x45, 0xFF, 0xE8}, + {0x49, 0xFF, 0x00}, {0x34, 0xFF, 0x00}, {0x23, 0xFF, 0x00} +}; + +static const struct mgb4_i2c_kv gmsl_i2c[] = { + {0x01, 0x03, 0x03}, {0x300, 0x0C, 0x0C}, {0x03, 0xC0, 0xC0}, + {0x1CE, 0x0E, 0x0E}, {0x11, 0x05, 0x00}, {0x05, 0xC0, 0x40}, + {0x307, 0x0F, 0x00}, {0xA0, 0x03, 0x00}, {0x3E0, 0x07, 0x07}, + {0x308, 0x01, 0x01}, {0x10, 0x20, 0x20}, {0x300, 0x40, 0x40} +}; + +static const struct v4l2_dv_timings_cap video_timings_cap = { + .type = V4L2_DV_BT_656_1120, + .bt = { + .min_width = 320, + .max_width = 4096, + .min_height = 240, + .max_height = 2160, + .min_pixelclock = 1843200, /* 320 x 240 x 24Hz */ + .max_pixelclock = 530841600, /* 4096 x 2160 x 60Hz */ + .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF, + .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | + V4L2_DV_BT_CAP_CUSTOM, + }, +}; + +/* + * Returns the video output connected with the given video input if the input + * is in loopback mode. + */ +static struct mgb4_vout_dev *loopback_dev(struct mgb4_vin_dev *vindev, int i) +{ + struct mgb4_vout_dev *voutdev; + u32 config; + + voutdev = vindev->mgbdev->vout[i]; + if (!voutdev) + return NULL; + + config = mgb4_read_reg(&voutdev->mgbdev->video, + voutdev->config->regs.config); + if ((config & 0xc) >> 2 == vindev->config->id) + return voutdev; + + return NULL; +} + +/* + * Check, whether the loopback mode - a HW INPUT->OUTPUT transmission - is + * enabled on the given input. + */ +static int loopback_active(struct mgb4_vin_dev *vindev) +{ + int i; + + for (i = 0; i < MGB4_VOUT_DEVICES; i++) + if (loopback_dev(vindev, i)) + return 1; + + return 0; +} + +/* + * Set the output frame buffer padding of all outputs connected with the given + * input when the video input is set to loopback mode. The paddings must be + * the same for the loopback to work properly. + */ +static void set_loopback_padding(struct mgb4_vin_dev *vindev, u32 padding) +{ + struct mgb4_regs *video = &vindev->mgbdev->video; + struct mgb4_vout_dev *voutdev; + int i; + + for (i = 0; i < MGB4_VOUT_DEVICES; i++) { + voutdev = loopback_dev(vindev, i); + if (voutdev) + mgb4_write_reg(video, voutdev->config->regs.padding, + padding); + } +} + +static int get_timings(struct mgb4_vin_dev *vindev, + struct v4l2_dv_timings *timings) +{ + struct mgb4_regs *video = &vindev->mgbdev->video; + const struct mgb4_vin_regs *regs = &vindev->config->regs; + + u32 status = mgb4_read_reg(video, regs->status); + u32 pclk = mgb4_read_reg(video, regs->pclk); + u32 signal = mgb4_read_reg(video, regs->signal); + u32 signal2 = mgb4_read_reg(video, regs->signal2); + u32 resolution = mgb4_read_reg(video, regs->resolution); + + if (!(status & (1U << 2))) + return -ENOLCK; + if (!(status & (3 << 9))) + return -ENOLINK; + + memset(timings, 0, sizeof(*timings)); + timings->type = V4L2_DV_BT_656_1120; + timings->bt.width = resolution >> 16; + timings->bt.height = resolution & 0xFFFF; + if (status & (1U << 12)) + timings->bt.polarities |= V4L2_DV_HSYNC_POS_POL; + if (status & (1U << 13)) + timings->bt.polarities |= V4L2_DV_VSYNC_POS_POL; + timings->bt.pixelclock = pclk * 1000; + timings->bt.hsync = (signal & 0x00FF0000) >> 16; + timings->bt.vsync = (signal2 & 0x00FF0000) >> 16; + timings->bt.hbackporch = (signal & 0x0000FF00) >> 8; + timings->bt.hfrontporch = signal & 0x000000FF; + timings->bt.vbackporch = (signal2 & 0x0000FF00) >> 8; + timings->bt.vfrontporch = signal2 & 0x000000FF; + + return 0; +} + +static void return_all_buffers(struct mgb4_vin_dev *vindev, + enum vb2_buffer_state state) +{ + struct mgb4_frame_buffer *buf, *node; + unsigned long flags; + + spin_lock_irqsave(&vindev->qlock, flags); + list_for_each_entry_safe(buf, node, &vindev->buf_list, list) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->list); + } + spin_unlock_irqrestore(&vindev->qlock, flags); +} + +static int queue_setup(struct vb2_queue *q, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct mgb4_vin_dev *vindev = vb2_get_drv_priv(q); + unsigned int size = (vindev->timings.bt.width + vindev->padding) + * vindev->timings.bt.height * 4; + + /* + * If I/O reconfiguration is in process, do not allow to start + * the queue. See video_source_store() in mgb4_sysfs_out.c for + * details. + */ + if (test_bit(0, &vindev->mgbdev->io_reconfig)) + return -EBUSY; + + if (!size) + return -EINVAL; + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int buffer_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mgb4_frame_buffer *buf = to_frame_buffer(vbuf); + + INIT_LIST_HEAD(&buf->list); + + return 0; +} + +static int buffer_prepare(struct vb2_buffer *vb) +{ + struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vb->vb2_queue); + struct device *dev = &vindev->mgbdev->pdev->dev; + unsigned int size = (vindev->timings.bt.width + vindev->padding) + * vindev->timings.bt.height * 4; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(dev, "buffer too small (%lu < %u)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void buffer_queue(struct vb2_buffer *vb) +{ + struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mgb4_frame_buffer *buf = to_frame_buffer(vbuf); + unsigned long flags; + + spin_lock_irqsave(&vindev->qlock, flags); + list_add_tail(&buf->list, &vindev->buf_list); + spin_unlock_irqrestore(&vindev->qlock, flags); +} + +static void stop_streaming(struct vb2_queue *vq) +{ + struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vq); + const struct mgb4_vin_config *config = vindev->config; + int irq = xdma_get_user_irq(vindev->mgbdev->xdev, config->vin_irq); + + xdma_disable_user_irq(vindev->mgbdev->xdev, irq); + + /* + * In loopback mode, the HW frame queue must be left running for + * the IN->OUT transmission to work! + */ + if (!loopback_active(vindev)) + mgb4_mask_reg(&vindev->mgbdev->video, config->regs.config, 0x2, + 0x0); + + cancel_work_sync(&vindev->dma_work); + return_all_buffers(vindev, VB2_BUF_STATE_ERROR); +} + +static int start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vq); + const struct mgb4_vin_config *config = vindev->config; + int irq = xdma_get_user_irq(vindev->mgbdev->xdev, config->vin_irq); + + vindev->sequence = 0; + + /* + * In loopback mode, the HW frame queue is already running. + */ + if (!loopback_active(vindev)) + mgb4_mask_reg(&vindev->mgbdev->video, config->regs.config, 0x2, + 0x2); + + xdma_enable_user_irq(vindev->mgbdev->xdev, irq); + + return 0; +} + +static const struct vb2_ops queue_ops = { + .queue_setup = queue_setup, + .buf_init = buffer_init, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish +}; + +static int fh_open(struct file *file) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + int rv; + + mutex_lock(&vindev->lock); + + rv = v4l2_fh_open(file); + if (rv) + goto out; + + if (!v4l2_fh_is_singular_file(file)) + goto out; + + get_timings(vindev, &vindev->timings); + set_loopback_padding(vindev, vindev->padding); + +out: + mutex_unlock(&vindev->lock); + return rv; +} + +static int fh_release(struct file *file) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + int rv; + + mutex_lock(&vindev->lock); + + if (v4l2_fh_is_singular_file(file)) + set_loopback_padding(vindev, 0); + + rv = _vb2_fop_release(file, NULL); + + mutex_unlock(&vindev->lock); + + return rv; +} + +static const struct v4l2_file_operations video_fops = { + .owner = THIS_MODULE, + .open = fh_open, + .release = fh_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strscpy(cap->card, "MGB4 PCIe Card", sizeof(cap->card)); + + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; + + f->pixelformat = V4L2_PIX_FMT_ABGR32; + + return 0; +} + +static int vidioc_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *ival) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + + if (ival->index != 0) + return -EINVAL; + if (ival->pixel_format != V4L2_PIX_FMT_ABGR32) + return -EINVAL; + if (ival->width != vindev->timings.bt.width || + ival->height != vindev->timings.bt.height) + return -EINVAL; + + ival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; + ival->stepwise.min.denominator = 60; + ival->stepwise.min.numerator = 1; + ival->stepwise.max.denominator = 1; + ival->stepwise.max.numerator = 1; + ival->stepwise.step = ival->stepwise.max; + + return 0; +} + +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32; + f->fmt.pix.width = vindev->timings.bt.width; + f->fmt.pix.height = vindev->timings.bt.height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; + f->fmt.pix.bytesperline = (f->fmt.pix.width + vindev->padding) * 4; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32; + f->fmt.pix.width = vindev->timings.bt.width; + f->fmt.pix.height = vindev->timings.bt.height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; + f->fmt.pix.bytesperline = max(f->fmt.pix.width * 4, + ALIGN_DOWN(f->fmt.pix.bytesperline, 4)); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + + return 0; +} + +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + struct mgb4_regs *video = &vindev->mgbdev->video; + + if (vb2_is_busy(&vindev->queue)) + return -EBUSY; + + vidioc_try_fmt(file, priv, f); + + vindev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width * 4)) / 4; + mgb4_write_reg(video, vindev->config->regs.padding, vindev->padding); + set_loopback_padding(vindev, vindev->padding); + + return 0; +} + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + struct mgb4_regs *video = &vindev->mgbdev->video; + u32 status; + + if (i->index != 0) + return -EINVAL; + + strscpy(i->name, "MGB4", sizeof(i->name)); + i->type = V4L2_INPUT_TYPE_CAMERA; + i->capabilities = V4L2_IN_CAP_DV_TIMINGS; + i->status = 0; + + status = mgb4_read_reg(video, vindev->config->regs.status); + if (!(status & (1U << 2))) + i->status |= V4L2_IN_ST_NO_SYNC; + if (!(status & (3 << 9))) + i->status |= V4L2_IN_ST_NO_SIGNAL; + + return 0; +} + +static int vidioc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + + if (fsize->index != 0 || fsize->pixel_format != V4L2_PIX_FMT_ABGR32) + return -EINVAL; + + fsize->discrete.width = vindev->timings.bt.width; + fsize->discrete.height = vindev->timings.bt.height; + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + return (i == 0) ? 0 : -EINVAL; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + struct mgb4_regs *video = &vindev->mgbdev->video; + const struct mgb4_vin_regs *regs = &vindev->config->regs; + struct v4l2_fract timeperframe = { + .numerator = mgb4_read_reg(video, regs->frame_period), + .denominator = 125000000, + }; + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + parm->parm.capture.readbuffers = 2; + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.timeperframe = timeperframe; + + return 0; +} + +static int vidioc_s_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + + if (timings->bt.width < video_timings_cap.bt.min_width || + timings->bt.width > video_timings_cap.bt.max_width || + timings->bt.height < video_timings_cap.bt.min_height || + timings->bt.height > video_timings_cap.bt.max_height) + return -EINVAL; + if (timings->bt.width == vindev->timings.bt.width && + timings->bt.height == vindev->timings.bt.height) + return 0; + if (vb2_is_busy(&vindev->queue)) + return -EBUSY; + + vindev->timings = *timings; + + return 0; +} + +static int vidioc_g_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + *timings = vindev->timings; + + return 0; +} + +static int vidioc_query_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct mgb4_vin_dev *vindev = video_drvdata(file); + + return get_timings(vindev, timings); +} + +static int vidioc_enum_dv_timings(struct file *file, void *fh, + struct v4l2_enum_dv_timings *timings) +{ + return v4l2_enum_dv_timings_cap(timings, &video_timings_cap, NULL, NULL); +} + +static int vidioc_dv_timings_cap(struct file *file, void *fh, + struct v4l2_dv_timings_cap *cap) +{ + *cap = video_timings_cap; + + return 0; +} + +static int vidioc_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + } + + return v4l2_ctrl_subscribe_event(fh, sub); +} + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt, + .vidioc_enum_framesizes = vidioc_enum_framesizes, + .vidioc_enum_frameintervals = vidioc_enum_frameintervals, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_g_parm = vidioc_parm, + .vidioc_s_parm = vidioc_parm, + .vidioc_dv_timings_cap = vidioc_dv_timings_cap, + .vidioc_enum_dv_timings = vidioc_enum_dv_timings, + .vidioc_g_dv_timings = vidioc_g_dv_timings, + .vidioc_s_dv_timings = vidioc_s_dv_timings, + .vidioc_query_dv_timings = vidioc_query_dv_timings, + .vidioc_subscribe_event = vidioc_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static void dma_transfer(struct work_struct *work) +{ + struct mgb4_vin_dev *vindev = container_of(work, struct mgb4_vin_dev, + dma_work); + struct mgb4_regs *video = &vindev->mgbdev->video; + struct device *dev = &vindev->mgbdev->pdev->dev; + struct mgb4_frame_buffer *buf = NULL; + unsigned long flags; + u32 addr; + int rv; + + spin_lock_irqsave(&vindev->qlock, flags); + if (!list_empty(&vindev->buf_list)) { + buf = list_first_entry(&vindev->buf_list, + struct mgb4_frame_buffer, list); + list_del_init(vindev->buf_list.next); + } + spin_unlock_irqrestore(&vindev->qlock, flags); + + if (!buf) + return; + + addr = mgb4_read_reg(video, vindev->config->regs.address); + if (addr >= MGB4_ERR_QUEUE_FULL) { + dev_dbg(dev, "frame queue error (%d)\n", (int)addr); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + return; + } + + rv = mgb4_dma_transfer(vindev->mgbdev, vindev->config->dma_channel, + false, addr, + vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0)); + if (rv < 0) { + dev_warn(dev, "DMA transfer error\n"); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } else { + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.sequence = vindev->sequence++; + buf->vb.field = V4L2_FIELD_NONE; + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } +} + +static void signal_change(struct work_struct *work) +{ + struct mgb4_vin_dev *vindev = container_of(work, struct mgb4_vin_dev, + err_work); + struct mgb4_regs *video = &vindev->mgbdev->video; + struct v4l2_bt_timings *timings = &vindev->timings.bt; + struct device *dev = &vindev->mgbdev->pdev->dev; + + u32 resolution = mgb4_read_reg(video, vindev->config->regs.resolution); + u32 width = resolution >> 16; + u32 height = resolution & 0xFFFF; + + if (timings->width != width || timings->height != height) { + static const struct v4l2_event ev = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + v4l2_event_queue(&vindev->vdev, &ev); + + if (vb2_is_streaming(&vindev->queue)) + vb2_queue_error(&vindev->queue); + } + + dev_dbg(dev, "stream changed to %ux%u\n", width, height); +} + +static irqreturn_t vin_handler(int irq, void *ctx) +{ + struct mgb4_vin_dev *vindev = (struct mgb4_vin_dev *)ctx; + struct mgb4_regs *video = &vindev->mgbdev->video; + + schedule_work(&vindev->dma_work); + + mgb4_write_reg(video, 0xB4, 1U << vindev->config->vin_irq); + + return IRQ_HANDLED; +} + +static irqreturn_t err_handler(int irq, void *ctx) +{ + struct mgb4_vin_dev *vindev = (struct mgb4_vin_dev *)ctx; + struct mgb4_regs *video = &vindev->mgbdev->video; + + schedule_work(&vindev->err_work); + + mgb4_write_reg(video, 0xB4, 1U << vindev->config->err_irq); + + return IRQ_HANDLED; +} + +static int deser_init(struct mgb4_vin_dev *vindev, int id) +{ + int rv, addr_size; + size_t values_count; + const struct mgb4_i2c_kv *values; + const struct i2c_board_info *info; + struct device *dev = &vindev->mgbdev->pdev->dev; + + if (MGB4_IS_GMSL(vindev->mgbdev)) { + info = &gmsl_deser_info[id]; + addr_size = 16; + values = gmsl_i2c; + values_count = ARRAY_SIZE(gmsl_i2c); + } else { + info = &fpdl3_deser_info[id]; + addr_size = 8; + values = fpdl3_i2c; + values_count = ARRAY_SIZE(fpdl3_i2c); + } + + rv = mgb4_i2c_init(&vindev->deser, vindev->mgbdev->i2c_adap, info, + addr_size); + if (rv < 0) { + dev_err(dev, "failed to create deserializer\n"); + return rv; + } + rv = mgb4_i2c_configure(&vindev->deser, values, values_count); + if (rv < 0) { + dev_err(dev, "failed to configure deserializer\n"); + goto err_i2c_dev; + } + + return 0; + +err_i2c_dev: + mgb4_i2c_free(&vindev->deser); + + return rv; +} + +static void fpga_init(struct mgb4_vin_dev *vindev) +{ + struct mgb4_regs *video = &vindev->mgbdev->video; + const struct mgb4_vin_regs *regs = &vindev->config->regs; + + mgb4_write_reg(video, regs->config, 0x00000001); + mgb4_write_reg(video, regs->sync, 0x03E80002); + mgb4_write_reg(video, regs->padding, 0x00000000); + mgb4_write_reg(video, regs->config, 1U << 9); +} + +#ifdef CONFIG_DEBUG_FS +static void debugfs_init(struct mgb4_vin_dev *vindev) +{ + struct mgb4_regs *video = &vindev->mgbdev->video; + + vindev->debugfs = debugfs_create_dir(vindev->vdev.name, + vindev->mgbdev->debugfs); + if (!vindev->debugfs) + return; + + vindev->regs[0].name = "CONFIG"; + vindev->regs[0].offset = vindev->config->regs.config; + vindev->regs[1].name = "STATUS"; + vindev->regs[1].offset = vindev->config->regs.status; + vindev->regs[2].name = "RESOLUTION"; + vindev->regs[2].offset = vindev->config->regs.resolution; + vindev->regs[3].name = "FRAME_PERIOD"; + vindev->regs[3].offset = vindev->config->regs.frame_period; + vindev->regs[4].name = "HS_VS_GENER_SETTINGS"; + vindev->regs[4].offset = vindev->config->regs.sync; + vindev->regs[5].name = "PCLK_FREQUENCY"; + vindev->regs[5].offset = vindev->config->regs.pclk; + vindev->regs[6].name = "VIDEO_PARAMS_1"; + vindev->regs[6].offset = vindev->config->regs.signal; + vindev->regs[7].name = "VIDEO_PARAMS_2"; + vindev->regs[7].offset = vindev->config->regs.signal2; + vindev->regs[8].name = "PADDING_PIXELS"; + vindev->regs[8].offset = vindev->config->regs.padding; + + vindev->regset.base = video->membase; + vindev->regset.regs = vindev->regs; + vindev->regset.nregs = ARRAY_SIZE(vindev->regs); + + debugfs_create_regset32("registers", 0444, vindev->debugfs, + &vindev->regset); +} +#endif + +struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id) +{ + int rv; + const struct attribute_group **groups; + struct mgb4_vin_dev *vindev; + struct pci_dev *pdev = mgbdev->pdev; + struct device *dev = &pdev->dev; + int vin_irq, err_irq; + + vindev = kzalloc(sizeof(*vindev), GFP_KERNEL); + if (!vindev) + return NULL; + + vindev->mgbdev = mgbdev; + vindev->config = &vin_cfg[id]; + + /* Frame queue*/ + INIT_LIST_HEAD(&vindev->buf_list); + spin_lock_init(&vindev->qlock); + + /* Work queues */ + INIT_WORK(&vindev->dma_work, dma_transfer); + INIT_WORK(&vindev->err_work, signal_change); + + /* IRQ callback */ + vin_irq = xdma_get_user_irq(mgbdev->xdev, vindev->config->vin_irq); + rv = request_irq(vin_irq, vin_handler, 0, "mgb4-vin", vindev); + if (rv) { + dev_err(dev, "failed to register vin irq handler\n"); + goto err_alloc; + } + /* Error IRQ callback */ + err_irq = xdma_get_user_irq(mgbdev->xdev, vindev->config->err_irq); + rv = request_irq(err_irq, err_handler, 0, "mgb4-err", vindev); + if (rv) { + dev_err(dev, "failed to register err irq handler\n"); + goto err_vin_irq; + } + + /* Set the FPGA registers default values */ + fpga_init(vindev); + + /* Set the deserializer default values */ + rv = deser_init(vindev, id); + if (rv) + goto err_err_irq; + + /* V4L2 stuff init */ + rv = v4l2_device_register(dev, &vindev->v4l2dev); + if (rv) { + dev_err(dev, "failed to register v4l2 device\n"); + goto err_err_irq; + } + + mutex_init(&vindev->lock); + + vindev->queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vindev->queue.io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + vindev->queue.buf_struct_size = sizeof(struct mgb4_frame_buffer); + vindev->queue.ops = &queue_ops; + vindev->queue.mem_ops = &vb2_dma_sg_memops; + vindev->queue.gfp_flags = GFP_DMA32; + vindev->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vindev->queue.min_buffers_needed = 2; + vindev->queue.drv_priv = vindev; + vindev->queue.lock = &vindev->lock; + vindev->queue.dev = dev; + rv = vb2_queue_init(&vindev->queue); + if (rv) { + dev_err(dev, "failed to initialize vb2 queue\n"); + goto err_v4l2_dev; + } + + snprintf(vindev->vdev.name, sizeof(vindev->vdev.name), "mgb4-in%d", + id + 1); + vindev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE + | V4L2_CAP_STREAMING; + vindev->vdev.fops = &video_fops; + vindev->vdev.ioctl_ops = &video_ioctl_ops; + vindev->vdev.release = video_device_release_empty; + vindev->vdev.v4l2_dev = &vindev->v4l2dev; + vindev->vdev.lock = &vindev->lock; + vindev->vdev.queue = &vindev->queue; + video_set_drvdata(&vindev->vdev, vindev); + + /* Enable the video signal change watcher */ + xdma_enable_user_irq(vindev->mgbdev->xdev, err_irq); + + /* Register the video device */ + rv = video_register_device(&vindev->vdev, VFL_TYPE_VIDEO, -1); + if (rv) { + dev_err(dev, "failed to register video device\n"); + goto err_v4l2_dev; + } + + /* Module sysfs attributes */ + groups = MGB4_IS_GMSL(mgbdev) + ? mgb4_gmsl_in_groups : mgb4_fpdl3_in_groups; + rv = device_add_groups(&vindev->vdev.dev, groups); + if (rv) { + dev_err(dev, "failed to create sysfs attributes\n"); + goto err_video_dev; + } + +#ifdef CONFIG_DEBUG_FS + debugfs_init(vindev); +#endif + + return vindev; + +err_video_dev: + video_unregister_device(&vindev->vdev); +err_v4l2_dev: + v4l2_device_unregister(&vindev->v4l2dev); +err_err_irq: + free_irq(err_irq, vindev); +err_vin_irq: + free_irq(vin_irq, vindev); +err_alloc: + kfree(vindev); + + return NULL; +} + +void mgb4_vin_free(struct mgb4_vin_dev *vindev) +{ + const struct attribute_group **groups; + int vin_irq = xdma_get_user_irq(vindev->mgbdev->xdev, + vindev->config->vin_irq); + int err_irq = xdma_get_user_irq(vindev->mgbdev->xdev, + vindev->config->err_irq); + + xdma_disable_user_irq(vindev->mgbdev->xdev, err_irq); + + free_irq(vin_irq, vindev); + free_irq(err_irq, vindev); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(vindev->debugfs); +#endif + + groups = MGB4_IS_GMSL(vindev->mgbdev) + ? mgb4_gmsl_in_groups : mgb4_fpdl3_in_groups; + device_remove_groups(&vindev->vdev.dev, groups); + + mgb4_i2c_free(&vindev->deser); + video_unregister_device(&vindev->vdev); + v4l2_device_unregister(&vindev->v4l2dev); + + kfree(vindev); +} diff --git a/drivers/media/pci/mgb4/mgb4_vin.h b/drivers/media/pci/mgb4/mgb4_vin.h new file mode 100644 index 0000000000..0249b400ad --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_vin.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + */ + +#ifndef __MGB4_VIN_H__ +#define __MGB4_VIN_H__ + +#include <media/v4l2-device.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-ctrls.h> +#include <media/videobuf2-core.h> +#include <linux/debugfs.h> +#include "mgb4_i2c.h" + +struct mgb4_vin_regs { + u32 address; + u32 config; + u32 status; + u32 resolution; + u32 frame_period; + u32 sync; + u32 pclk; + u32 signal; + u32 signal2; + u32 padding; +}; + +struct mgb4_vin_config { + int id; + int dma_channel; + int vin_irq; + int err_irq; + struct mgb4_vin_regs regs; +}; + +struct mgb4_vin_dev { + struct mgb4_dev *mgbdev; + struct v4l2_device v4l2dev; + struct video_device vdev; + struct vb2_queue queue; + struct mutex lock; /* vdev lock */ + + spinlock_t qlock; /* video buffer queue lock */ + struct list_head buf_list; + struct work_struct dma_work, err_work; + + unsigned int sequence; + + struct v4l2_dv_timings timings; + u32 freq_range; + u32 padding; + + struct mgb4_i2c_client deser; + + const struct mgb4_vin_config *config; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs; + struct debugfs_regset32 regset; + struct debugfs_reg32 regs[9]; +#endif +}; + +struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id); +void mgb4_vin_free(struct mgb4_vin_dev *vindev); + +#endif diff --git a/drivers/media/pci/mgb4/mgb4_vout.c b/drivers/media/pci/mgb4/mgb4_vout.c new file mode 100644 index 0000000000..857fc7bbd2 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_vout.c @@ -0,0 +1,602 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + * + * This is the v4l2 output device module. It initializes the signal serializers + * and creates the v4l2 video devices. + * + * When the device is in loopback mode (a direct, in HW, in->out frame passing + * mode) we disable the v4l2 output by returning EBUSY in the open() syscall. + */ + +#include <linux/pci.h> +#include <linux/align.h> +#include <linux/dma/amd_xdma.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-v4l2.h> +#include <media/videobuf2-dma-sg.h> +#include "mgb4_core.h" +#include "mgb4_dma.h" +#include "mgb4_sysfs.h" +#include "mgb4_io.h" +#include "mgb4_cmt.h" +#include "mgb4_vout.h" + +ATTRIBUTE_GROUPS(mgb4_fpdl3_out); +ATTRIBUTE_GROUPS(mgb4_gmsl_out); + +static const struct mgb4_vout_config vout_cfg[] = { + {0, 0, 8, {0x78, 0x60, 0x64, 0x68, 0x74, 0x6C, 0x70, 0x7c}}, + {1, 1, 9, {0x98, 0x80, 0x84, 0x88, 0x94, 0x8c, 0x90, 0x9c}} +}; + +static const struct i2c_board_info fpdl3_ser_info[] = { + {I2C_BOARD_INFO("serializer1", 0x14)}, + {I2C_BOARD_INFO("serializer2", 0x16)}, +}; + +static const struct mgb4_i2c_kv fpdl3_i2c[] = { + {0x05, 0xFF, 0x04}, {0x06, 0xFF, 0x01}, {0xC2, 0xFF, 0x80} +}; + +static void return_all_buffers(struct mgb4_vout_dev *voutdev, + enum vb2_buffer_state state) +{ + struct mgb4_frame_buffer *buf, *node; + unsigned long flags; + + spin_lock_irqsave(&voutdev->qlock, flags); + list_for_each_entry_safe(buf, node, &voutdev->buf_list, list) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->list); + } + spin_unlock_irqrestore(&voutdev->qlock, flags); +} + +static int queue_setup(struct vb2_queue *q, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct mgb4_vout_dev *voutdev = vb2_get_drv_priv(q); + unsigned int size; + + /* + * If I/O reconfiguration is in process, do not allow to start + * the queue. See video_source_store() in mgb4_sysfs_out.c for + * details. + */ + if (test_bit(0, &voutdev->mgbdev->io_reconfig)) + return -EBUSY; + + size = (voutdev->width + voutdev->padding) * voutdev->height * 4; + + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int buffer_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mgb4_frame_buffer *buf = to_frame_buffer(vbuf); + + INIT_LIST_HEAD(&buf->list); + + return 0; +} + +static int buffer_prepare(struct vb2_buffer *vb) +{ + struct mgb4_vout_dev *voutdev = vb2_get_drv_priv(vb->vb2_queue); + struct device *dev = &voutdev->mgbdev->pdev->dev; + unsigned int size; + + size = (voutdev->width + voutdev->padding) * voutdev->height * 4; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(dev, "buffer too small (%lu < %u)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void buffer_queue(struct vb2_buffer *vb) +{ + struct mgb4_vout_dev *vindev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mgb4_frame_buffer *buf = to_frame_buffer(vbuf); + unsigned long flags; + + spin_lock_irqsave(&vindev->qlock, flags); + list_add_tail(&buf->list, &vindev->buf_list); + spin_unlock_irqrestore(&vindev->qlock, flags); +} + +static void stop_streaming(struct vb2_queue *vq) +{ + struct mgb4_vout_dev *voutdev = vb2_get_drv_priv(vq); + struct mgb4_dev *mgbdev = voutdev->mgbdev; + int irq = xdma_get_user_irq(mgbdev->xdev, voutdev->config->irq); + + xdma_disable_user_irq(mgbdev->xdev, irq); + cancel_work_sync(&voutdev->dma_work); + mgb4_mask_reg(&mgbdev->video, voutdev->config->regs.config, 0x2, 0x0); + return_all_buffers(voutdev, VB2_BUF_STATE_ERROR); +} + +static int start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct mgb4_vout_dev *voutdev = vb2_get_drv_priv(vq); + struct mgb4_dev *mgbdev = voutdev->mgbdev; + struct device *dev = &mgbdev->pdev->dev; + struct mgb4_frame_buffer *buf; + struct mgb4_regs *video = &mgbdev->video; + const struct mgb4_vout_config *config = voutdev->config; + int irq = xdma_get_user_irq(mgbdev->xdev, config->irq); + int rv; + u32 addr; + + mgb4_mask_reg(video, config->regs.config, 0x2, 0x2); + + addr = mgb4_read_reg(video, config->regs.address); + if (addr >= MGB4_ERR_QUEUE_FULL) { + dev_dbg(dev, "frame queue error (%d)\n", (int)addr); + return_all_buffers(voutdev, VB2_BUF_STATE_QUEUED); + return -EBUSY; + } + + buf = list_first_entry(&voutdev->buf_list, struct mgb4_frame_buffer, + list); + list_del_init(voutdev->buf_list.next); + + rv = mgb4_dma_transfer(mgbdev, config->dma_channel, true, addr, + vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0)); + if (rv < 0) { + dev_warn(dev, "DMA transfer error\n"); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } else { + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } + + xdma_enable_user_irq(mgbdev->xdev, irq); + + return 0; +} + +static const struct vb2_ops queue_ops = { + .queue_setup = queue_setup, + .buf_init = buffer_init, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish +}; + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strscpy(cap->card, "MGB4 PCIe Card", sizeof(cap->card)); + + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; + + f->pixelformat = V4L2_PIX_FMT_ABGR32; + + return 0; +} + +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct mgb4_vout_dev *voutdev = video_drvdata(file); + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32; + f->fmt.pix.width = voutdev->width; + f->fmt.pix.height = voutdev->height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; + f->fmt.pix.bytesperline = (f->fmt.pix.width + voutdev->padding) * 4; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct mgb4_vout_dev *voutdev = video_drvdata(file); + + f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32; + f->fmt.pix.width = voutdev->width; + f->fmt.pix.height = voutdev->height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; + f->fmt.pix.bytesperline = max(f->fmt.pix.width * 4, + ALIGN_DOWN(f->fmt.pix.bytesperline, 4)); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + + return 0; +} + +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct mgb4_vout_dev *voutdev = video_drvdata(file); + struct mgb4_regs *video = &voutdev->mgbdev->video; + + if (vb2_is_busy(&voutdev->queue)) + return -EBUSY; + + vidioc_try_fmt(file, priv, f); + + voutdev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width * 4)) / 4; + mgb4_write_reg(video, voutdev->config->regs.padding, voutdev->padding); + + return 0; +} + +static int vidioc_g_output(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_output(struct file *file, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int vidioc_enum_output(struct file *file, void *priv, + struct v4l2_output *out) +{ + if (out->index != 0) + return -EINVAL; + + out->type = V4L2_OUTPUT_TYPE_ANALOG; + strscpy(out->name, "MGB4", sizeof(out->name)); + + return 0; +} + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt, + .vidioc_try_fmt_vid_out = vidioc_try_fmt, + .vidioc_s_fmt_vid_out = vidioc_s_fmt, + .vidioc_g_fmt_vid_out = vidioc_g_fmt, + .vidioc_enum_output = vidioc_enum_output, + .vidioc_g_output = vidioc_g_output, + .vidioc_s_output = vidioc_s_output, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static int fh_open(struct file *file) +{ + struct mgb4_vout_dev *voutdev = video_drvdata(file); + struct mgb4_regs *video = &voutdev->mgbdev->video; + struct device *dev = &voutdev->mgbdev->pdev->dev; + u32 config, resolution; + int rv; + + /* Return EBUSY when the device is in loopback mode */ + config = mgb4_read_reg(video, voutdev->config->regs.config); + if ((config & 0xc) >> 2 != voutdev->config->id + MGB4_VIN_DEVICES) { + dev_dbg(dev, "can not open - device in loopback mode"); + return -EBUSY; + } + + mutex_lock(&voutdev->lock); + + rv = v4l2_fh_open(file); + if (rv) + goto out; + + if (!v4l2_fh_is_singular_file(file)) + goto out; + + resolution = mgb4_read_reg(video, voutdev->config->regs.resolution); + voutdev->width = resolution >> 16; + voutdev->height = resolution & 0xFFFF; + +out: + mutex_unlock(&voutdev->lock); + return rv; +} + +static const struct v4l2_file_operations video_fops = { + .owner = THIS_MODULE, + .open = fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .write = vb2_fop_write, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +static void dma_transfer(struct work_struct *work) +{ + struct mgb4_vout_dev *voutdev = container_of(work, struct mgb4_vout_dev, + dma_work); + struct device *dev = &voutdev->mgbdev->pdev->dev; + struct mgb4_regs *video = &voutdev->mgbdev->video; + struct mgb4_frame_buffer *buf = NULL; + unsigned long flags; + u32 addr; + int rv; + + spin_lock_irqsave(&voutdev->qlock, flags); + if (!list_empty(&voutdev->buf_list)) { + buf = list_first_entry(&voutdev->buf_list, + struct mgb4_frame_buffer, list); + list_del_init(voutdev->buf_list.next); + } + spin_unlock_irqrestore(&voutdev->qlock, flags); + + if (!buf) + return; + + addr = mgb4_read_reg(video, voutdev->config->regs.address); + if (addr >= MGB4_ERR_QUEUE_FULL) { + dev_dbg(dev, "frame queue error (%d)\n", (int)addr); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + return; + } + + rv = mgb4_dma_transfer(voutdev->mgbdev, voutdev->config->dma_channel, + true, addr, + vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0)); + if (rv < 0) { + dev_warn(dev, "DMA transfer error\n"); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } else { + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } +} + +static irqreturn_t handler(int irq, void *ctx) +{ + struct mgb4_vout_dev *voutdev = (struct mgb4_vout_dev *)ctx; + struct mgb4_regs *video = &voutdev->mgbdev->video; + + schedule_work(&voutdev->dma_work); + + mgb4_write_reg(video, 0xB4, 1U << voutdev->config->irq); + + return IRQ_HANDLED; +} + +static int ser_init(struct mgb4_vout_dev *voutdev, int id) +{ + int rv; + const struct i2c_board_info *info = &fpdl3_ser_info[id]; + struct mgb4_i2c_client *ser = &voutdev->ser; + struct device *dev = &voutdev->mgbdev->pdev->dev; + + if (MGB4_IS_GMSL(voutdev->mgbdev)) + return 0; + + rv = mgb4_i2c_init(ser, voutdev->mgbdev->i2c_adap, info, 8); + if (rv < 0) { + dev_err(dev, "failed to create serializer\n"); + return rv; + } + rv = mgb4_i2c_configure(ser, fpdl3_i2c, ARRAY_SIZE(fpdl3_i2c)); + if (rv < 0) { + dev_err(dev, "failed to configure serializer\n"); + goto err_i2c_dev; + } + + return 0; + +err_i2c_dev: + mgb4_i2c_free(ser); + + return rv; +} + +static void fpga_init(struct mgb4_vout_dev *voutdev) +{ + struct mgb4_regs *video = &voutdev->mgbdev->video; + const struct mgb4_vout_regs *regs = &voutdev->config->regs; + + mgb4_write_reg(video, regs->config, 0x00000011); + mgb4_write_reg(video, regs->resolution, + (MGB4_DEFAULT_WIDTH << 16) | MGB4_DEFAULT_HEIGHT); + mgb4_write_reg(video, regs->hsync, 0x00102020); + mgb4_write_reg(video, regs->vsync, 0x40020202); + mgb4_write_reg(video, regs->frame_period, MGB4_DEFAULT_PERIOD); + mgb4_write_reg(video, regs->padding, 0x00000000); + + voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, 70000 >> 1) << 1; + + mgb4_write_reg(video, regs->config, + (voutdev->config->id + MGB4_VIN_DEVICES) << 2 | 1 << 4); +} + +#ifdef CONFIG_DEBUG_FS +static void debugfs_init(struct mgb4_vout_dev *voutdev) +{ + struct mgb4_regs *video = &voutdev->mgbdev->video; + + voutdev->debugfs = debugfs_create_dir(voutdev->vdev.name, + voutdev->mgbdev->debugfs); + if (!voutdev->debugfs) + return; + + voutdev->regs[0].name = "CONFIG"; + voutdev->regs[0].offset = voutdev->config->regs.config; + voutdev->regs[1].name = "STATUS"; + voutdev->regs[1].offset = voutdev->config->regs.status; + voutdev->regs[2].name = "RESOLUTION"; + voutdev->regs[2].offset = voutdev->config->regs.resolution; + voutdev->regs[3].name = "VIDEO_PARAMS_1"; + voutdev->regs[3].offset = voutdev->config->regs.hsync; + voutdev->regs[4].name = "VIDEO_PARAMS_2"; + voutdev->regs[4].offset = voutdev->config->regs.vsync; + voutdev->regs[5].name = "FRAME_PERIOD"; + voutdev->regs[5].offset = voutdev->config->regs.frame_period; + voutdev->regs[6].name = "PADDING"; + voutdev->regs[6].offset = voutdev->config->regs.padding; + + voutdev->regset.base = video->membase; + voutdev->regset.regs = voutdev->regs; + voutdev->regset.nregs = ARRAY_SIZE(voutdev->regs); + + debugfs_create_regset32("registers", 0444, voutdev->debugfs, + &voutdev->regset); +} +#endif + +struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id) +{ + int rv, irq; + const struct attribute_group **groups; + struct mgb4_vout_dev *voutdev; + struct pci_dev *pdev = mgbdev->pdev; + struct device *dev = &pdev->dev; + + voutdev = kzalloc(sizeof(*voutdev), GFP_KERNEL); + if (!voutdev) + return NULL; + + voutdev->mgbdev = mgbdev; + voutdev->config = &vout_cfg[id]; + + /* Frame queue */ + INIT_LIST_HEAD(&voutdev->buf_list); + spin_lock_init(&voutdev->qlock); + + /* DMA transfer stuff */ + INIT_WORK(&voutdev->dma_work, dma_transfer); + + /* IRQ callback */ + irq = xdma_get_user_irq(mgbdev->xdev, voutdev->config->irq); + rv = request_irq(irq, handler, 0, "mgb4-vout", voutdev); + if (rv) { + dev_err(dev, "failed to register irq handler\n"); + goto err_alloc; + } + + /* Set the FPGA registers default values */ + fpga_init(voutdev); + + /* Set the serializer default values */ + rv = ser_init(voutdev, id); + if (rv) + goto err_irq; + + /* V4L2 stuff init */ + rv = v4l2_device_register(dev, &voutdev->v4l2dev); + if (rv) { + dev_err(dev, "failed to register v4l2 device\n"); + goto err_irq; + } + + mutex_init(&voutdev->lock); + + voutdev->queue.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + voutdev->queue.io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; + voutdev->queue.buf_struct_size = sizeof(struct mgb4_frame_buffer); + voutdev->queue.ops = &queue_ops; + voutdev->queue.mem_ops = &vb2_dma_sg_memops; + voutdev->queue.gfp_flags = GFP_DMA32; + voutdev->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + voutdev->queue.min_buffers_needed = 2; + voutdev->queue.drv_priv = voutdev; + voutdev->queue.lock = &voutdev->lock; + voutdev->queue.dev = dev; + rv = vb2_queue_init(&voutdev->queue); + if (rv) { + dev_err(dev, "failed to initialize vb2 queue\n"); + goto err_v4l2_dev; + } + + snprintf(voutdev->vdev.name, sizeof(voutdev->vdev.name), "mgb4-out%d", + id + 1); + voutdev->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE + | V4L2_CAP_STREAMING; + voutdev->vdev.vfl_dir = VFL_DIR_TX; + voutdev->vdev.fops = &video_fops; + voutdev->vdev.ioctl_ops = &video_ioctl_ops; + voutdev->vdev.release = video_device_release_empty; + voutdev->vdev.v4l2_dev = &voutdev->v4l2dev; + voutdev->vdev.lock = &voutdev->lock; + voutdev->vdev.queue = &voutdev->queue; + video_set_drvdata(&voutdev->vdev, voutdev); + + rv = video_register_device(&voutdev->vdev, VFL_TYPE_VIDEO, -1); + if (rv) { + dev_err(dev, "failed to register video device\n"); + goto err_v4l2_dev; + } + + /* Module sysfs attributes */ + groups = MGB4_IS_GMSL(mgbdev) + ? mgb4_gmsl_out_groups : mgb4_fpdl3_out_groups; + rv = device_add_groups(&voutdev->vdev.dev, groups); + if (rv) { + dev_err(dev, "failed to create sysfs attributes\n"); + goto err_video_dev; + } + +#ifdef CONFIG_DEBUG_FS + debugfs_init(voutdev); +#endif + + return voutdev; + +err_video_dev: + video_unregister_device(&voutdev->vdev); +err_v4l2_dev: + v4l2_device_unregister(&voutdev->v4l2dev); +err_irq: + free_irq(irq, voutdev); +err_alloc: + kfree(voutdev); + + return NULL; +} + +void mgb4_vout_free(struct mgb4_vout_dev *voutdev) +{ + const struct attribute_group **groups; + int irq = xdma_get_user_irq(voutdev->mgbdev->xdev, voutdev->config->irq); + + free_irq(irq, voutdev); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(voutdev->debugfs); +#endif + + groups = MGB4_IS_GMSL(voutdev->mgbdev) + ? mgb4_gmsl_out_groups : mgb4_fpdl3_out_groups; + device_remove_groups(&voutdev->vdev.dev, groups); + + mgb4_i2c_free(&voutdev->ser); + video_unregister_device(&voutdev->vdev); + v4l2_device_unregister(&voutdev->v4l2dev); + + kfree(voutdev); +} diff --git a/drivers/media/pci/mgb4/mgb4_vout.h b/drivers/media/pci/mgb4/mgb4_vout.h new file mode 100644 index 0000000000..b163dee711 --- /dev/null +++ b/drivers/media/pci/mgb4/mgb4_vout.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021-2023 Digiteq Automotive + * author: Martin Tuma <martin.tuma@digiteqautomotive.com> + */ + +#ifndef __MGB4_VOUT_H__ +#define __MGB4_VOUT_H__ + +#include <media/v4l2-device.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-ctrls.h> +#include <media/videobuf2-core.h> +#include <linux/debugfs.h> +#include "mgb4_i2c.h" + +struct mgb4_vout_regs { + u32 address; + u32 config; + u32 status; + u32 resolution; + u32 frame_period; + u32 hsync; + u32 vsync; + u32 padding; +}; + +struct mgb4_vout_config { + int id; + int dma_channel; + int irq; + struct mgb4_vout_regs regs; +}; + +struct mgb4_vout_dev { + struct mgb4_dev *mgbdev; + struct v4l2_device v4l2dev; + struct video_device vdev; + struct vb2_queue queue; + struct mutex lock; /* vdev lock */ + + spinlock_t qlock; /* buffer queue lock */ + struct list_head buf_list; + struct work_struct dma_work; + + u32 width; + u32 height; + u32 freq; + u32 padding; + + struct mgb4_i2c_client ser; + + const struct mgb4_vout_config *config; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs; + struct debugfs_regset32 regset; + struct debugfs_reg32 regs[7]; +#endif +}; + +struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id); +void mgb4_vout_free(struct mgb4_vout_dev *voutdev); + +#endif diff --git a/drivers/media/pci/solo6x10/solo6x10-offsets.h b/drivers/media/pci/solo6x10/solo6x10-offsets.h index f414ee1316..fdbb817e63 100644 --- a/drivers/media/pci/solo6x10/solo6x10-offsets.h +++ b/drivers/media/pci/solo6x10/solo6x10-offsets.h @@ -57,16 +57,16 @@ #define SOLO_MP4E_EXT_ADDR(__solo) \ (SOLO_EREF_EXT_ADDR(__solo) + SOLO_EREF_EXT_AREA(__solo)) #define SOLO_MP4E_EXT_SIZE(__solo) \ - max((__solo->nr_chans * 0x00080000), \ - min(((__solo->sdram_size - SOLO_MP4E_EXT_ADDR(__solo)) - \ - __SOLO_JPEG_MIN_SIZE(__solo)), 0x00ff0000)) + clamp(__solo->sdram_size - SOLO_MP4E_EXT_ADDR(__solo) - \ + __SOLO_JPEG_MIN_SIZE(__solo), \ + __solo->nr_chans * 0x00080000, 0x00ff0000) #define __SOLO_JPEG_MIN_SIZE(__solo) (__solo->nr_chans * 0x00080000) #define SOLO_JPEG_EXT_ADDR(__solo) \ (SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo)) #define SOLO_JPEG_EXT_SIZE(__solo) \ - max(__SOLO_JPEG_MIN_SIZE(__solo), \ - min((__solo->sdram_size - SOLO_JPEG_EXT_ADDR(__solo)), 0x00ff0000)) + clamp(__solo->sdram_size - SOLO_JPEG_EXT_ADDR(__solo), \ + __SOLO_JPEG_MIN_SIZE(__solo), 0x00ff0000) #define SOLO_SDRAM_END(__solo) \ (SOLO_JPEG_EXT_ADDR(__solo) + SOLO_JPEG_EXT_SIZE(__solo)) diff --git a/drivers/media/pci/zoran/zoran.h b/drivers/media/pci/zoran/zoran.h index 56340553b2..1cd990468d 100644 --- a/drivers/media/pci/zoran/zoran.h +++ b/drivers/media/pci/zoran/zoran.h @@ -219,7 +219,7 @@ struct zoran { const struct tvnorm *timing; unsigned short id; /* number of this device */ - char name[32]; /* name of this device */ + char name[40]; /* name of this device */ struct pci_dev *pci_dev; /* PCI device */ unsigned char revision; /* revision of zr36057 */ unsigned char __iomem *zr36057_mem;/* pointer to mapped IO memory */ diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index ee579916f8..91e54215de 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -73,6 +73,7 @@ source "drivers/media/platform/intel/Kconfig" source "drivers/media/platform/marvell/Kconfig" source "drivers/media/platform/mediatek/Kconfig" source "drivers/media/platform/microchip/Kconfig" +source "drivers/media/platform/nuvoton/Kconfig" source "drivers/media/platform/nvidia/Kconfig" source "drivers/media/platform/nxp/Kconfig" source "drivers/media/platform/qcom/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 5453bb868e..3296ec1ebe 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -16,6 +16,7 @@ obj-y += intel/ obj-y += marvell/ obj-y += mediatek/ obj-y += microchip/ +obj-y += nuvoton/ obj-y += nvidia/ obj-y += nxp/ obj-y += qcom/ diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.c b/drivers/media/platform/allegro-dvt/allegro-mail.c index 16effad107..aadc947a77 100644 --- a/drivers/media/platform/allegro-dvt/allegro-mail.c +++ b/drivers/media/platform/allegro-dvt/allegro-mail.c @@ -16,7 +16,7 @@ const char *msg_type_name(enum mcu_msg_type type) { - static char buf[9]; + static char buf[13]; switch (type) { case MCU_MSG_TYPE_INIT: diff --git a/drivers/media/platform/allegro-dvt/allegro-mail.h b/drivers/media/platform/allegro-dvt/allegro-mail.h index a5686058d7..c0c9013f1a 100644 --- a/drivers/media/platform/allegro-dvt/allegro-mail.h +++ b/drivers/media/platform/allegro-dvt/allegro-mail.h @@ -184,7 +184,7 @@ struct mcu_msg_push_buffers_internal { struct mcu_msg_header header; u32 channel_id; size_t num_buffers; - struct mcu_msg_push_buffers_internal_buffer buffer[]; + struct mcu_msg_push_buffers_internal_buffer buffer[] __counted_by(num_buffers); }; struct mcu_msg_put_stream_buffer { diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h index 5a701f6428..0246cf0ac3 100644 --- a/drivers/media/platform/amphion/vpu.h +++ b/drivers/media/platform/amphion/vpu.h @@ -154,7 +154,6 @@ struct vpu_core { struct vpu_mbox tx_type; struct vpu_mbox tx_data; struct vpu_mbox rx; - unsigned long cmd_seq; wait_queue_head_t ack_wq; struct completion cmp; @@ -253,6 +252,8 @@ struct vpu_inst { struct list_head cmd_q; void *pending; + unsigned long cmd_seq; + atomic_long_t last_response_cmd; struct vpu_inst_ops *ops; const struct vpu_format *formats; diff --git a/drivers/media/platform/amphion/vpu_cmds.c b/drivers/media/platform/amphion/vpu_cmds.c index c233781257..5695f5c1cb 100644 --- a/drivers/media/platform/amphion/vpu_cmds.c +++ b/drivers/media/platform/amphion/vpu_cmds.c @@ -32,6 +32,7 @@ struct vpu_cmd_t { struct vpu_cmd_request *request; struct vpu_rpc_event *pkt; unsigned long key; + atomic_long_t *last_response_cmd; }; static struct vpu_cmd_request vpu_cmd_requests[] = { @@ -115,6 +116,8 @@ static void vpu_free_cmd(struct vpu_cmd_t *cmd) { if (!cmd) return; + if (cmd->last_response_cmd) + atomic_long_set(cmd->last_response_cmd, cmd->key); vfree(cmd->pkt); vfree(cmd); } @@ -172,7 +175,8 @@ static int vpu_request_cmd(struct vpu_inst *inst, u32 id, void *data, return -ENOMEM; mutex_lock(&core->cmd_lock); - cmd->key = core->cmd_seq++; + cmd->key = ++inst->cmd_seq; + cmd->last_response_cmd = &inst->last_response_cmd; if (key) *key = cmd->key; if (sync) @@ -246,26 +250,12 @@ void vpu_clear_request(struct vpu_inst *inst) static bool check_is_responsed(struct vpu_inst *inst, unsigned long key) { - struct vpu_core *core = inst->core; - struct vpu_cmd_t *cmd; - bool flag = true; + unsigned long last_response = atomic_long_read(&inst->last_response_cmd); - mutex_lock(&core->cmd_lock); - cmd = inst->pending; - if (cmd && key == cmd->key) { - flag = false; - goto exit; - } - list_for_each_entry(cmd, &inst->cmd_q, list) { - if (key == cmd->key) { - flag = false; - break; - } - } -exit: - mutex_unlock(&core->cmd_lock); + if (key <= last_response && (last_response - key) < (ULONG_MAX >> 1)) + return true; - return flag; + return false; } static int sync_session_response(struct vpu_inst *inst, unsigned long key, long timeout, int try) diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 0f6e4c6664..d7e0de49b3 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -716,6 +716,7 @@ int vpu_v4l2_open(struct file *file, struct vpu_inst *inst) func = &vpu->decoder; atomic_set(&inst->ref_count, 0); + atomic_long_set(&inst->last_response_cmd, 0); vpu_inst_get(inst); inst->vpu = vpu; inst->core = vpu_request_core(vpu, inst->type); diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c index a9c2c69b2e..d08aa7f73d 100644 --- a/drivers/media/platform/aspeed/aspeed-video.c +++ b/drivers/media/platform/aspeed/aspeed-video.c @@ -1970,22 +1970,15 @@ static void aspeed_video_debugfs_remove(struct aspeed_video *video) debugfs_entry = NULL; } -static int aspeed_video_debugfs_create(struct aspeed_video *video) +static void aspeed_video_debugfs_create(struct aspeed_video *video) { debugfs_entry = debugfs_create_file(DEVICE_NAME, 0444, NULL, video, &aspeed_video_debugfs_fops); - if (!debugfs_entry) - aspeed_video_debugfs_remove(video); - - return !debugfs_entry ? -EIO : 0; } #else static void aspeed_video_debugfs_remove(struct aspeed_video *video) { } -static int aspeed_video_debugfs_create(struct aspeed_video *video) -{ - return 0; -} +static void aspeed_video_debugfs_create(struct aspeed_video *video) { } #endif /* CONFIG_DEBUG_FS */ static int aspeed_video_setup_video(struct aspeed_video *video) @@ -2198,9 +2191,7 @@ static int aspeed_video_probe(struct platform_device *pdev) return rc; } - rc = aspeed_video_debugfs_create(video); - if (rc) - dev_err(video->dev, "debugfs create failed\n"); + aspeed_video_debugfs_create(video); return 0; } diff --git a/drivers/media/platform/cadence/Kconfig b/drivers/media/platform/cadence/Kconfig index 480325d053..1aa608c00d 100644 --- a/drivers/media/platform/cadence/Kconfig +++ b/drivers/media/platform/cadence/Kconfig @@ -8,6 +8,8 @@ config VIDEO_CADENCE_CSI2RX select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE + select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY help Support for the Cadence MIPI CSI2 Receiver controller. diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 9231ee7e9b..889f4fbbaf 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -8,6 +8,7 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_graph.h> @@ -40,10 +41,14 @@ #define CSI2RX_STREAM_BASE(n) (((n) + 1) * 0x100) #define CSI2RX_STREAM_CTRL_REG(n) (CSI2RX_STREAM_BASE(n) + 0x000) +#define CSI2RX_STREAM_CTRL_SOFT_RST BIT(4) +#define CSI2RX_STREAM_CTRL_STOP BIT(1) #define CSI2RX_STREAM_CTRL_START BIT(0) +#define CSI2RX_STREAM_STATUS_REG(n) (CSI2RX_STREAM_BASE(n) + 0x004) +#define CSI2RX_STREAM_STATUS_RDY BIT(31) + #define CSI2RX_STREAM_DATA_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x008) -#define CSI2RX_STREAM_DATA_CFG_EN_VC_SELECT BIT(31) #define CSI2RX_STREAM_DATA_CFG_VC_SELECT(n) BIT((n) + 16) #define CSI2RX_STREAM_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x00c) @@ -61,6 +66,11 @@ enum csi2rx_pads { CSI2RX_PAD_MAX, }; +struct csi2rx_fmt { + u32 code; + u8 bpp; +}; + struct csi2rx_priv { struct device *dev; unsigned int count; @@ -95,6 +105,32 @@ struct csi2rx_priv { int source_pad; }; +static const struct csi2rx_fmt formats[] = { + { .code = MEDIA_BUS_FMT_YUYV8_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_YVYU8_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_VYUY8_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10, }, +}; + +static const struct csi2rx_fmt *csi2rx_get_fmt_by_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); i++) + if (formats[i].code == code) + return &formats[i]; + + return NULL; +} + static inline struct csi2rx_priv *v4l2_subdev_to_csi2rx(struct v4l2_subdev *subdev) { @@ -103,19 +139,54 @@ struct csi2rx_priv *v4l2_subdev_to_csi2rx(struct v4l2_subdev *subdev) static void csi2rx_reset(struct csi2rx_priv *csi2rx) { + unsigned int i; + + /* Reset module */ writel(CSI2RX_SOFT_RESET_PROTOCOL | CSI2RX_SOFT_RESET_FRONT, csi2rx->base + CSI2RX_SOFT_RESET_REG); + /* Reset individual streams. */ + for (i = 0; i < csi2rx->max_streams; i++) { + writel(CSI2RX_STREAM_CTRL_SOFT_RST, + csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); + } - udelay(10); + usleep_range(10, 20); + /* Clear resets */ writel(0, csi2rx->base + CSI2RX_SOFT_RESET_REG); + for (i = 0; i < csi2rx->max_streams; i++) + writel(0, csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); } static int csi2rx_configure_ext_dphy(struct csi2rx_priv *csi2rx) { union phy_configure_opts opts = { }; + struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .pad = CSI2RX_PAD_SINK, + }; + const struct csi2rx_fmt *fmt; + s64 link_freq; int ret; + ret = v4l2_subdev_call_state_active(&csi2rx->subdev, pad, get_fmt, + &sd_fmt); + if (ret < 0) + return ret; + + fmt = csi2rx_get_fmt_by_code(sd_fmt.format.code); + + link_freq = v4l2_get_link_freq(csi2rx->source_subdev->ctrl_handler, + fmt->bpp, 2 * csi2rx->num_lanes); + if (link_freq < 0) + return link_freq; + + ret = phy_mipi_dphy_get_default_config_for_hsclk(link_freq, + csi2rx->num_lanes, cfg); + if (ret) + return ret; + ret = phy_power_on(csi2rx->dphy); if (ret) return ret; @@ -199,8 +270,11 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) writel(CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF, csi2rx->base + CSI2RX_STREAM_CFG_REG(i)); - writel(CSI2RX_STREAM_DATA_CFG_EN_VC_SELECT | - CSI2RX_STREAM_DATA_CFG_VC_SELECT(i), + /* + * Enable one virtual channel. When multiple virtual channels + * are supported this will have to be changed. + */ + writel(CSI2RX_STREAM_DATA_CFG_VC_SELECT(0), csi2rx->base + CSI2RX_STREAM_DATA_CFG_REG(i)); writel(CSI2RX_STREAM_CTRL_START, @@ -243,13 +317,25 @@ err_disable_pclk: static void csi2rx_stop(struct csi2rx_priv *csi2rx) { unsigned int i; + u32 val; + int ret; clk_prepare_enable(csi2rx->p_clk); reset_control_assert(csi2rx->sys_rst); clk_disable_unprepare(csi2rx->sys_clk); for (i = 0; i < csi2rx->max_streams; i++) { - writel(0, csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); + writel(CSI2RX_STREAM_CTRL_STOP, + csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); + + ret = readl_relaxed_poll_timeout(csi2rx->base + + CSI2RX_STREAM_STATUS_REG(i), + val, + !(val & CSI2RX_STREAM_STATUS_RDY), + 10, 10000); + if (ret) + dev_warn(csi2rx->dev, + "Failed to stop streaming on pad%u\n", i); reset_control_assert(csi2rx->pixel_rst[i]); clk_disable_unprepare(csi2rx->pixel_clk[i]); @@ -303,12 +389,72 @@ out: return ret; } +static int csi2rx_set_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt; + unsigned int i; + + /* No transcoding, source and sink formats must match. */ + if (format->pad != CSI2RX_PAD_SINK) + return v4l2_subdev_get_fmt(subdev, state, format); + + if (!csi2rx_get_fmt_by_code(format->format.code)) + format->format.code = formats[0].code; + + format->format.field = V4L2_FIELD_NONE; + + /* Set sink format */ + fmt = v4l2_subdev_get_pad_format(subdev, state, format->pad); + *fmt = format->format; + + /* Propagate to source formats */ + for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) { + fmt = v4l2_subdev_get_pad_format(subdev, state, i); + *fmt = format->format; + } + + return 0; +} + +static int csi2rx_init_cfg(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format format = { + .pad = CSI2RX_PAD_SINK, + .format = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, + }, + }; + + return csi2rx_set_fmt(subdev, state, &format); +} + +static const struct v4l2_subdev_pad_ops csi2rx_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = csi2rx_set_fmt, + .init_cfg = csi2rx_init_cfg, +}; + static const struct v4l2_subdev_video_ops csi2rx_video_ops = { .s_stream = csi2rx_s_stream, }; static const struct v4l2_subdev_ops csi2rx_subdev_ops = { .video = &csi2rx_video_ops, + .pad = &csi2rx_pad_ops, +}; + +static const struct media_entity_operations csi2rx_media_ops = { + .link_validate = v4l2_subdev_link_validate, }; static int csi2rx_async_bound(struct v4l2_async_notifier *notifier, @@ -518,23 +664,29 @@ static int csi2rx_probe(struct platform_device *pdev) csi2rx->subdev.dev = &pdev->dev; v4l2_subdev_init(&csi2rx->subdev, &csi2rx_subdev_ops); v4l2_set_subdevdata(&csi2rx->subdev, &pdev->dev); - snprintf(csi2rx->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.%s", - KBUILD_MODNAME, dev_name(&pdev->dev)); + snprintf(csi2rx->subdev.name, sizeof(csi2rx->subdev.name), + "%s.%s", KBUILD_MODNAME, dev_name(&pdev->dev)); /* Create our media pads */ csi2rx->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; csi2rx->pads[CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) csi2rx->pads[i].flags = MEDIA_PAD_FL_SOURCE; + csi2rx->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + csi2rx->subdev.entity.ops = &csi2rx_media_ops; ret = media_entity_pads_init(&csi2rx->subdev.entity, CSI2RX_PAD_MAX, csi2rx->pads); if (ret) goto err_cleanup; + ret = v4l2_subdev_init_finalize(&csi2rx->subdev); + if (ret) + goto err_cleanup; + ret = v4l2_async_register_subdev(&csi2rx->subdev); if (ret < 0) - goto err_cleanup; + goto err_free_state; dev_info(&pdev->dev, "Probed CSI2RX with %u/%u lanes, %u streams, %s D-PHY\n", @@ -544,9 +696,12 @@ static int csi2rx_probe(struct platform_device *pdev) return 0; +err_free_state: + v4l2_subdev_cleanup(&csi2rx->subdev); err_cleanup: v4l2_async_nf_unregister(&csi2rx->notifier); v4l2_async_nf_cleanup(&csi2rx->notifier); + media_entity_cleanup(&csi2rx->subdev.entity); err_free_priv: kfree(csi2rx); return ret; @@ -559,6 +714,8 @@ static void csi2rx_remove(struct platform_device *pdev) v4l2_async_nf_unregister(&csi2rx->notifier); v4l2_async_nf_cleanup(&csi2rx->notifier); v4l2_async_unregister_subdev(&csi2rx->subdev); + v4l2_subdev_cleanup(&csi2rx->subdev); + media_entity_cleanup(&csi2rx->subdev.entity); kfree(csi2rx); } diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c index 1e0400b780..c115742f34 100644 --- a/drivers/media/platform/cadence/cdns-csi2tx.c +++ b/drivers/media/platform/cadence/cdns-csi2tx.c @@ -480,7 +480,7 @@ static int csi2tx_get_resources(struct csi2tx_priv *csi2tx, csi2tx->has_internal_dphy = !!(dev_cfg & CSI2TX_DEVICE_CONFIG_HAS_DPHY); for (i = 0; i < csi2tx->max_streams; i++) { - char clk_name[16]; + char clk_name[23]; snprintf(clk_name, sizeof(clk_name), "pixel_if%u_clk", i); csi2tx->pixel_clk[i] = devm_clk_get(&pdev->dev, clk_name); @@ -592,8 +592,8 @@ static int csi2tx_probe(struct platform_device *pdev) csi2tx->subdev.owner = THIS_MODULE; csi2tx->subdev.dev = &pdev->dev; csi2tx->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(csi2tx->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.%s", - KBUILD_MODNAME, dev_name(&pdev->dev)); + snprintf(csi2tx->subdev.name, sizeof(csi2tx->subdev.name), + "%s.%s", KBUILD_MODNAME, dev_name(&pdev->dev)); ret = csi2tx_check_lanes(csi2tx); if (ret) diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c index 667933ea15..575c8d52ac 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c @@ -1137,6 +1137,7 @@ int mdp_comp_config(struct mdp_dev *mdp) comp = mdp_comp_create(mdp, node, id); if (IS_ERR(comp)) { ret = PTR_ERR(comp); + of_node_put(node); goto err_init_comps; } diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c index 9e744d07a1..6bbe55de6c 100644 --- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c +++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_scp.c @@ -68,7 +68,7 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_scp_init(void *priv, enum mtk_vcodec_fw_use plat_dev = dec_dev->plat_dev; } else { - pr_err("Invalid fw_use %d (use a resonable fw id here)\n", fw_use); + pr_err("Invalid fw_use %d (use a reasonable fw id here)\n", fw_use); return ERR_PTR(-EINVAL); } diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c index 5e03b08865..9f6e4b5945 100644 --- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c +++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c @@ -109,7 +109,7 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(void *priv, enum mtk_vcodec_fw_use plat_dev = dec_dev->plat_dev; rst_id = VPU_RST_DEC; } else { - pr_err("Invalid fw_use %d (use a resonable fw id here)\n", fw_use); + pr_err("Invalid fw_use %d (use a reasonable fw id here)\n", fw_use); return ERR_PTR(-EINVAL); } diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c index 04948d3eb0..eb381fa6e7 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c @@ -866,7 +866,7 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) { struct mtk_vcodec_enc_ctx *ctx = vb2_get_drv_priv(q); struct venc_enc_param param; - int ret, pm_ret; + int ret; int i; /* Once state turn into MTK_STATE_ABORT, we need stop_streaming @@ -886,18 +886,12 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) return 0; } - ret = pm_runtime_resume_and_get(&ctx->dev->plat_dev->dev); - if (ret < 0) { - mtk_v4l2_venc_err(ctx, "pm_runtime_resume_and_get fail %d", ret); - goto err_start_stream; - } - mtk_venc_set_param(ctx, ¶m); ret = venc_if_set_param(ctx, VENC_SET_PARAM_ENC, ¶m); if (ret) { mtk_v4l2_venc_err(ctx, "venc_if_set_param failed=%d", ret); ctx->state = MTK_STATE_ABORT; - goto err_set_param; + goto err_start_stream; } ctx->param_change = MTK_ENCODE_PARAM_NONE; @@ -910,18 +904,13 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) if (ret) { mtk_v4l2_venc_err(ctx, "venc_if_set_param failed=%d", ret); ctx->state = MTK_STATE_ABORT; - goto err_set_param; + goto err_start_stream; } ctx->state = MTK_STATE_HEADER; } return 0; -err_set_param: - pm_ret = pm_runtime_put(&ctx->dev->plat_dev->dev); - if (pm_ret < 0) - mtk_v4l2_venc_err(ctx, "pm_runtime_put fail %d", pm_ret); - err_start_stream: for (i = 0; i < q->num_buffers; ++i) { struct vb2_buffer *buf = vb2_get_buffer(q, i); @@ -1004,10 +993,6 @@ static void vb2ops_venc_stop_streaming(struct vb2_queue *q) if (ret) mtk_v4l2_venc_err(ctx, "venc_if_deinit failed=%d", ret); - ret = pm_runtime_put(&ctx->dev->plat_dev->dev); - if (ret < 0) - mtk_v4l2_venc_err(ctx, "pm_runtime_put fail %d", ret); - ctx->state = MTK_STATE_FREE; } diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c index 3fce936e61..a22b7dfc65 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.c @@ -58,6 +58,24 @@ int mtk_vcodec_init_enc_clk(struct mtk_vcodec_enc_dev *mtkdev) return 0; } +void mtk_vcodec_enc_pw_on(struct mtk_vcodec_pm *pm) +{ + int ret; + + ret = pm_runtime_resume_and_get(pm->dev); + if (ret) + dev_err(pm->dev, "pm_runtime_resume_and_get fail: %d", ret); +} + +void mtk_vcodec_enc_pw_off(struct mtk_vcodec_pm *pm) +{ + int ret; + + ret = pm_runtime_put(pm->dev); + if (ret && ret != -EAGAIN) + dev_err(pm->dev, "pm_runtime_put fail %d", ret); +} + void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm) { struct mtk_vcodec_clk *enc_clk = &pm->venc_clk; diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h index e50be05751..157ea08ba9 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_pm.h @@ -10,7 +10,8 @@ #include "mtk_vcodec_enc_drv.h" int mtk_vcodec_init_enc_clk(struct mtk_vcodec_enc_dev *dev); - +void mtk_vcodec_enc_pw_on(struct mtk_vcodec_pm *pm); +void mtk_vcodec_enc_pw_off(struct mtk_vcodec_pm *pm); void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm); void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm); diff --git a/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c b/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c index 1bdaecdd64..c402a686f3 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/venc_drv_if.c @@ -32,9 +32,7 @@ int venc_if_init(struct mtk_vcodec_enc_ctx *ctx, unsigned int fourcc) } mtk_venc_lock(ctx); - mtk_vcodec_enc_clock_on(&ctx->dev->pm); ret = ctx->enc_if->init(ctx); - mtk_vcodec_enc_clock_off(&ctx->dev->pm); mtk_venc_unlock(ctx); return ret; @@ -46,9 +44,7 @@ int venc_if_set_param(struct mtk_vcodec_enc_ctx *ctx, int ret = 0; mtk_venc_lock(ctx); - mtk_vcodec_enc_clock_on(&ctx->dev->pm); ret = ctx->enc_if->set_param(ctx->drv_handle, type, in); - mtk_vcodec_enc_clock_off(&ctx->dev->pm); mtk_venc_unlock(ctx); return ret; @@ -68,10 +64,12 @@ int venc_if_encode(struct mtk_vcodec_enc_ctx *ctx, ctx->dev->curr_ctx = ctx; spin_unlock_irqrestore(&ctx->dev->irqlock, flags); + mtk_vcodec_enc_pw_on(&ctx->dev->pm); mtk_vcodec_enc_clock_on(&ctx->dev->pm); ret = ctx->enc_if->encode(ctx->drv_handle, opt, frm_buf, bs_buf, result); mtk_vcodec_enc_clock_off(&ctx->dev->pm); + mtk_vcodec_enc_pw_off(&ctx->dev->pm); spin_lock_irqsave(&ctx->dev->irqlock, flags); ctx->dev->curr_ctx = NULL; @@ -89,9 +87,7 @@ int venc_if_deinit(struct mtk_vcodec_enc_ctx *ctx) return 0; mtk_venc_lock(ctx); - mtk_vcodec_enc_clock_on(&ctx->dev->pm); ret = ctx->enc_if->deinit(ctx->drv_handle); - mtk_vcodec_enc_clock_off(&ctx->dev->pm); mtk_venc_unlock(ctx); ctx->drv_handle = NULL; diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c index 8dbf7bc1e8..1f85288444 100644 --- a/drivers/media/platform/microchip/microchip-isc-base.c +++ b/drivers/media/platform/microchip/microchip-isc-base.c @@ -478,12 +478,8 @@ static const struct vb2_ops isc_vb2_ops = { static int isc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct isc_device *isc = video_drvdata(file); - strscpy(cap->driver, "microchip-isc", sizeof(cap->driver)); strscpy(cap->card, "Microchip Image Sensor Controller", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", isc->v4l2_dev.name); return 0; } @@ -1993,8 +1989,6 @@ int isc_mc_init(struct isc_device *isc, u32 ver) strscpy(isc->mdev.driver_name, KBUILD_MODNAME, sizeof(isc->mdev.driver_name)); strscpy(isc->mdev.model, match->compatible, sizeof(isc->mdev.model)); - snprintf(isc->mdev.bus_info, sizeof(isc->mdev.bus_info), "platform:%s", - isc->v4l2_dev.name); isc->mdev.hw_revision = ver; media_device_init(&isc->mdev); diff --git a/drivers/media/platform/nuvoton/Kconfig b/drivers/media/platform/nuvoton/Kconfig new file mode 100644 index 0000000000..40b36d1be8 --- /dev/null +++ b/drivers/media/platform/nuvoton/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +comment "Nuvoton media platform drivers" + +config VIDEO_NPCM_VCD_ECE + tristate "Nuvoton NPCM Video Capture/Encode Engine driver" + depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV + depends on ARCH_NPCM || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + help + Support for the Video Capture/Differentiation Engine (VCD) and + Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. + The VCD can capture a frame from digital video input and compare + two frames in memory, and then the ECE can compress the frame + data into HEXTILE format. diff --git a/drivers/media/platform/nuvoton/Makefile b/drivers/media/platform/nuvoton/Makefile new file mode 100644 index 0000000000..74a4e3fc85 --- /dev/null +++ b/drivers/media/platform/nuvoton/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_VIDEO_NPCM_VCD_ECE) += npcm-video.o diff --git a/drivers/media/platform/nuvoton/npcm-regs.h b/drivers/media/platform/nuvoton/npcm-regs.h new file mode 100644 index 0000000000..4a44f47f02 --- /dev/null +++ b/drivers/media/platform/nuvoton/npcm-regs.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Register definition header for NPCM video driver + * + * Copyright (C) 2022 Nuvoton Technologies + */ + +#ifndef _NPCM_REGS_H +#define _NPCM_REGS_H + +/* VCD Registers */ +#define VCD_DIFF_TBL 0x0000 +#define VCD_FBA_ADR 0x8000 +#define VCD_FBB_ADR 0x8004 + +#define VCD_FB_LP 0x8008 +#define VCD_FBA_LP GENMASK(15, 0) +#define VCD_FBB_LP GENMASK(31, 16) + +#define VCD_CAP_RES 0x800c +#define VCD_CAP_RES_VERT_RES GENMASK(10, 0) +#define VCD_CAP_RES_HOR_RES GENMASK(26, 16) + +#define VCD_MODE 0x8014 +#define VCD_MODE_VCDE BIT(0) +#define VCD_MODE_CM565 BIT(1) +#define VCD_MODE_IDBC BIT(3) +#define VCD_MODE_KVM_BW_SET BIT(16) + +#define VCD_CMD 0x8018 +#define VCD_CMD_GO BIT(0) +#define VCD_CMD_RST BIT(1) +#define VCD_CMD_OPERATION GENMASK(6, 4) +#define VCD_CMD_OPERATION_CAPTURE 0 +#define VCD_CMD_OPERATION_COMPARE 2 + +#define VCD_STAT 0x801c +#define VCD_STAT_DONE BIT(0) +#define VCD_STAT_IFOT BIT(2) +#define VCD_STAT_IFOR BIT(3) +#define VCD_STAT_VHT_CHG BIT(5) +#define VCD_STAT_HAC_CHG BIT(8) +#define VCD_STAT_BUSY BIT(30) +#define VCD_STAT_CLEAR 0x3fff + +#define VCD_INTE 0x8020 +#define VCD_INTE_DONE_IE BIT(0) +#define VCD_INTE_IFOT_IE BIT(2) +#define VCD_INTE_IFOR_IE BIT(3) +#define VCD_INTE_VHT_IE BIT(5) +#define VCD_INTE_HAC_IE BIT(8) + +#define VCD_RCHG 0x8028 +#define VCD_RCHG_IG_CHG0 GENMASK(2, 0) +#define VCD_RCHG_TIM_PRSCL GENMASK(12, 9) + +#define VCD_VER_HI_TIM 0x8044 +#define VCD_VER_HI_TIME GENMASK(23, 0) + +#define VCD_VER_HI_LST 0x8048 +#define VCD_VER_HI_LAST GENMASK(23, 0) + +#define VCD_HOR_AC_TIM 0x804c +#define VCD_HOR_AC_TIME GENMASK(13, 0) + +#define VCD_HOR_AC_LST 0x8050 +#define VCD_HOR_AC_LAST GENMASK(13, 0) + +#define VCD_FIFO 0x805c +#define VCD_FIFO_TH 0x100350ff + +#define VCD_FB_SIZE 0x500000 /* support up to 1920 x 1200 */ +#define VCD_KVM_BW_PCLK 120000000UL +#define VCD_TIMEOUT_US 300000 + +/* ECE Registers */ +#define ECE_DDA_CTRL 0x0000 +#define ECE_DDA_CTRL_ECEEN BIT(0) +#define ECE_DDA_CTRL_INTEN BIT(8) + +#define ECE_DDA_STS 0x0004 +#define ECE_DDA_STS_CDREADY BIT(8) +#define ECE_DDA_STS_ACDRDY BIT(10) + +#define ECE_FBR_BA 0x0008 +#define ECE_ED_BA 0x000c +#define ECE_RECT_XY 0x0010 + +#define ECE_RECT_DIMEN 0x0014 +#define ECE_RECT_DIMEN_WR GENMASK(10, 0) +#define ECE_RECT_DIMEN_WLTR GENMASK(14, 11) +#define ECE_RECT_DIMEN_HR GENMASK(26, 16) +#define ECE_RECT_DIMEN_HLTR GENMASK(30, 27) + +#define ECE_RESOL 0x001c +#define ECE_RESOL_FB_LP_512 0 +#define ECE_RESOL_FB_LP_1024 1 +#define ECE_RESOL_FB_LP_2048 2 +#define ECE_RESOL_FB_LP_2560 3 +#define ECE_RESOL_FB_LP_4096 4 + +#define ECE_HEX_CTRL 0x0040 +#define ECE_HEX_CTRL_ENCDIS BIT(0) +#define ECE_HEX_CTRL_ENC_GAP GENMASK(12, 8) + +#define ECE_HEX_RECT_OFFSET 0x0048 +#define ECE_HEX_RECT_OFFSET_MASK GENMASK(22, 0) + +#define ECE_TILE_W 16 +#define ECE_TILE_H 16 +#define ECE_POLL_TIMEOUT_US 300000 + +/* GCR Registers */ +#define INTCR 0x3c +#define INTCR_GFXIFDIS GENMASK(9, 8) +#define INTCR_DEHS BIT(27) + +#define INTCR2 0x60 +#define INTCR2_GIRST2 BIT(2) +#define INTCR2_GIHCRST BIT(5) +#define INTCR2_GIVCRST BIT(6) + +/* GFXI Register */ +#define DISPST 0x00 +#define DISPST_HSCROFF BIT(1) +#define DISPST_MGAMODE BIT(7) + +#define HVCNTL 0x10 +#define HVCNTL_MASK GENMASK(7, 0) + +#define HVCNTH 0x14 +#define HVCNTH_MASK GENMASK(2, 0) + +#define VVCNTL 0x20 +#define VVCNTL_MASK GENMASK(7, 0) + +#define VVCNTH 0x24 +#define VVCNTH_MASK GENMASK(2, 0) + +#define GPLLINDIV 0x40 +#define GPLLINDIV_MASK GENMASK(5, 0) +#define GPLLINDIV_GPLLFBDV8 BIT(7) + +#define GPLLFBDIV 0x44 +#define GPLLFBDIV_MASK GENMASK(7, 0) + +#define GPLLST 0x48 +#define GPLLST_PLLOTDIV1 GENMASK(2, 0) +#define GPLLST_PLLOTDIV2 GENMASK(5, 3) +#define GPLLST_GPLLFBDV109 GENMASK(7, 6) + +#endif /* _NPCM_REGS_H */ diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c new file mode 100644 index 0000000000..b9e6782f59 --- /dev/null +++ b/drivers/media/platform/nuvoton/npcm-video.c @@ -0,0 +1,1831 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for Video Capture/Differentiation Engine (VCD) and Encoding + * Compression Engine (ECE) present on Nuvoton NPCM SoCs. + * + * Copyright (C) 2022 Nuvoton Technologies + */ + +#include <linux/atomic.h> +#include <linux/bitfield.h> +#include <linux/bitmap.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/of_reserved_mem.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/v4l2-controls.h> +#include <linux/videodev2.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> +#include <media/v4l2-dv-timings.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-dma-contig.h> +#include <uapi/linux/npcm-video.h> +#include "npcm-regs.h" + +#define DEVICE_NAME "npcm-video" +#define MAX_WIDTH 1920 +#define MAX_HEIGHT 1200 +#define MIN_WIDTH 320 +#define MIN_HEIGHT 240 +#define MIN_LP 512 +#define MAX_LP 4096 +#define RECT_W 16 +#define RECT_H 16 +#define BITMAP_SIZE 32 + +struct npcm_video_addr { + size_t size; + dma_addr_t dma; + void *virt; +}; + +struct npcm_video_buffer { + struct vb2_v4l2_buffer vb; + struct list_head link; +}; + +#define to_npcm_video_buffer(x) \ + container_of((x), struct npcm_video_buffer, vb) + +/* + * VIDEO_STREAMING: a flag indicating if the video has started streaming + * VIDEO_CAPTURING: a flag indicating if the VCD is capturing a frame + * VIDEO_RES_CHANGING: a flag indicating if the resolution is changing + * VIDEO_STOPPED: a flag indicating if the video has stopped streaming + */ +enum { + VIDEO_STREAMING, + VIDEO_CAPTURING, + VIDEO_RES_CHANGING, + VIDEO_STOPPED, +}; + +struct rect_list { + struct v4l2_clip clip; + struct list_head list; +}; + +struct rect_list_info { + struct rect_list *list; + struct rect_list *first; + struct list_head *head; + unsigned int index; + unsigned int tile_perline; + unsigned int tile_perrow; + unsigned int offset_perline; + unsigned int tile_size; + unsigned int tile_cnt; +}; + +struct npcm_ece { + struct regmap *regmap; + atomic_t clients; + struct reset_control *reset; + bool enable; +}; + +struct npcm_video { + struct regmap *gcr_regmap; + struct regmap *gfx_regmap; + struct regmap *vcd_regmap; + + struct device *dev; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *rect_cnt_ctrl; + struct v4l2_device v4l2_dev; + struct v4l2_pix_format pix_fmt; + struct v4l2_bt_timings active_timings; + struct v4l2_bt_timings detected_timings; + unsigned int v4l2_input_status; + struct vb2_queue queue; + struct video_device vdev; + struct mutex video_lock; /* v4l2 and videobuf2 lock */ + + struct list_head buffers; + spinlock_t lock; /* buffer list lock */ + unsigned long flags; + unsigned int sequence; + + struct npcm_video_addr src; + struct reset_control *reset; + struct npcm_ece ece; + + unsigned int bytesperline; + unsigned int bytesperpixel; + unsigned int rect_cnt; + struct list_head list[VIDEO_MAX_FRAME]; + unsigned int rect[VIDEO_MAX_FRAME]; + unsigned int ctrl_cmd; + unsigned int op_cmd; +}; + +#define to_npcm_video(x) container_of((x), struct npcm_video, v4l2_dev) + +struct npcm_fmt { + unsigned int fourcc; + unsigned int bpp; /* bytes per pixel */ +}; + +static const struct npcm_fmt npcm_fmt_list[] = { + { + .fourcc = V4L2_PIX_FMT_RGB565, + .bpp = 2, + }, + { + .fourcc = V4L2_PIX_FMT_HEXTILE, + .bpp = 2, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(npcm_fmt_list) + +static const struct v4l2_dv_timings_cap npcm_video_timings_cap = { + .type = V4L2_DV_BT_656_1120, + .bt = { + .min_width = MIN_WIDTH, + .max_width = MAX_WIDTH, + .min_height = MIN_HEIGHT, + .max_height = MAX_HEIGHT, + .min_pixelclock = 6574080, /* 640 x 480 x 24Hz */ + .max_pixelclock = 138240000, /* 1920 x 1200 x 60Hz */ + .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF, + .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | + V4L2_DV_BT_CAP_REDUCED_BLANKING | + V4L2_DV_BT_CAP_CUSTOM, + }, +}; + +static DECLARE_BITMAP(bitmap, BITMAP_SIZE); + +static const struct npcm_fmt *npcm_video_find_format(struct v4l2_format *f) +{ + const struct npcm_fmt *fmt; + unsigned int k; + + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &npcm_fmt_list[k]; + if (fmt->fourcc == f->fmt.pix.pixelformat) + break; + } + + if (k == NUM_FORMATS) + return NULL; + + return &npcm_fmt_list[k]; +} + +static void npcm_video_ece_prepend_rect_header(void *addr, u16 x, u16 y, u16 w, u16 h) +{ + __be16 x_pos = cpu_to_be16(x); + __be16 y_pos = cpu_to_be16(y); + __be16 width = cpu_to_be16(w); + __be16 height = cpu_to_be16(h); + __be32 encoding = cpu_to_be32(5); /* Hextile encoding */ + + memcpy(addr, &x_pos, 2); + memcpy(addr + 2, &y_pos, 2); + memcpy(addr + 4, &width, 2); + memcpy(addr + 6, &height, 2); + memcpy(addr + 8, &encoding, 4); +} + +static unsigned int npcm_video_ece_get_ed_size(struct npcm_video *video, + unsigned int offset, void *addr) +{ + struct regmap *ece = video->ece.regmap; + unsigned int size, gap, val; + int ret; + + ret = regmap_read_poll_timeout(ece, ECE_DDA_STS, val, + (val & ECE_DDA_STS_CDREADY), 0, + ECE_POLL_TIMEOUT_US); + + if (ret) { + dev_warn(video->dev, "Wait for ECE_DDA_STS_CDREADY timeout\n"); + return 0; + } + + size = readl((void __iomem *)addr + offset); + regmap_read(ece, ECE_HEX_CTRL, &val); + gap = FIELD_GET(ECE_HEX_CTRL_ENC_GAP, val); + + dev_dbg(video->dev, "offset = %u, ed_size = %u, gap = %u\n", offset, + size, gap); + + return size + gap; +} + +static void npcm_video_ece_enc_rect(struct npcm_video *video, + unsigned int r_off_x, unsigned int r_off_y, + unsigned int r_w, unsigned int r_h) +{ + struct regmap *ece = video->ece.regmap; + unsigned int rect_offset = (r_off_y * video->bytesperline) + (r_off_x * 2); + unsigned int w_size = ECE_TILE_W, h_size = ECE_TILE_H; + unsigned int temp, w_tile, h_tile; + + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, 0); + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, ECE_DDA_CTRL_ECEEN); + regmap_write(ece, ECE_DDA_STS, ECE_DDA_STS_CDREADY | ECE_DDA_STS_ACDRDY); + regmap_write(ece, ECE_RECT_XY, rect_offset); + + w_tile = r_w / ECE_TILE_W; + h_tile = r_h / ECE_TILE_H; + + if (r_w % ECE_TILE_W) { + w_tile += 1; + w_size = r_w % ECE_TILE_W; + } + if (r_h % ECE_TILE_H || !h_tile) { + h_tile += 1; + h_size = r_h % ECE_TILE_H; + } + + temp = FIELD_PREP(ECE_RECT_DIMEN_WLTR, w_size - 1) | + FIELD_PREP(ECE_RECT_DIMEN_HLTR, h_size - 1) | + FIELD_PREP(ECE_RECT_DIMEN_WR, w_tile - 1) | + FIELD_PREP(ECE_RECT_DIMEN_HR, h_tile - 1); + + regmap_write(ece, ECE_RECT_DIMEN, temp); +} + +static unsigned int npcm_video_ece_read_rect_offset(struct npcm_video *video) +{ + struct regmap *ece = video->ece.regmap; + unsigned int offset; + + regmap_read(ece, ECE_HEX_RECT_OFFSET, &offset); + return FIELD_GET(ECE_HEX_RECT_OFFSET_MASK, offset); +} + +/* + * Set the line pitch (in bytes) for the frame buffers. + * Can be on of those values: 512, 1024, 2048, 2560 or 4096 bytes. + */ +static void npcm_video_ece_set_lp(struct npcm_video *video, unsigned int pitch) +{ + struct regmap *ece = video->ece.regmap; + unsigned int lp; + + switch (pitch) { + case 512: + lp = ECE_RESOL_FB_LP_512; + break; + case 1024: + lp = ECE_RESOL_FB_LP_1024; + break; + case 2048: + lp = ECE_RESOL_FB_LP_2048; + break; + case 2560: + lp = ECE_RESOL_FB_LP_2560; + break; + case 4096: + lp = ECE_RESOL_FB_LP_4096; + break; + default: + return; + } + + regmap_write(ece, ECE_RESOL, lp); +} + +static inline void npcm_video_ece_set_fb_addr(struct npcm_video *video, + unsigned int buffer) +{ + struct regmap *ece = video->ece.regmap; + + regmap_write(ece, ECE_FBR_BA, buffer); +} + +static inline void npcm_video_ece_set_enc_dba(struct npcm_video *video, + unsigned int addr) +{ + struct regmap *ece = video->ece.regmap; + + regmap_write(ece, ECE_ED_BA, addr); +} + +static inline void npcm_video_ece_clear_rect_offset(struct npcm_video *video) +{ + struct regmap *ece = video->ece.regmap; + + regmap_write(ece, ECE_HEX_RECT_OFFSET, 0); +} + +static void npcm_video_ece_ctrl_reset(struct npcm_video *video) +{ + struct regmap *ece = video->ece.regmap; + + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, 0); + regmap_update_bits(ece, ECE_HEX_CTRL, ECE_HEX_CTRL_ENCDIS, ECE_HEX_CTRL_ENCDIS); + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, ECE_DDA_CTRL_ECEEN); + regmap_update_bits(ece, ECE_HEX_CTRL, ECE_HEX_CTRL_ENCDIS, 0); + + npcm_video_ece_clear_rect_offset(video); +} + +static void npcm_video_ece_ip_reset(struct npcm_video *video) +{ + /* + * After resetting a module and clearing the reset bit, it should wait + * at least 10 us before accessing the module. + */ + reset_control_assert(video->ece.reset); + usleep_range(10, 20); + reset_control_deassert(video->ece.reset); + usleep_range(10, 20); +} + +static void npcm_video_ece_stop(struct npcm_video *video) +{ + struct regmap *ece = video->ece.regmap; + + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, 0); + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_INTEN, 0); + regmap_update_bits(ece, ECE_HEX_CTRL, ECE_HEX_CTRL_ENCDIS, ECE_HEX_CTRL_ENCDIS); + npcm_video_ece_clear_rect_offset(video); +} + +static bool npcm_video_alloc_fb(struct npcm_video *video, + struct npcm_video_addr *addr) +{ + addr->virt = dma_alloc_coherent(video->dev, VCD_FB_SIZE, &addr->dma, + GFP_KERNEL); + if (!addr->virt) + return false; + + addr->size = VCD_FB_SIZE; + return true; +} + +static void npcm_video_free_fb(struct npcm_video *video, + struct npcm_video_addr *addr) +{ + dma_free_coherent(video->dev, addr->size, addr->virt, addr->dma); + addr->size = 0; + addr->dma = 0ULL; + addr->virt = NULL; +} + +static void npcm_video_free_diff_table(struct npcm_video *video) +{ + struct list_head *head, *pos, *nx; + struct rect_list *tmp; + unsigned int i; + + for (i = 0; i < video->queue.num_buffers; i++) { + head = &video->list[i]; + list_for_each_safe(pos, nx, head) { + tmp = list_entry(pos, struct rect_list, list); + list_del(&tmp->list); + kfree(tmp); + } + } +} + +static unsigned int npcm_video_add_rect(struct npcm_video *video, + unsigned int index, + unsigned int x, unsigned int y, + unsigned int w, unsigned int h) +{ + struct list_head *head = &video->list[index]; + struct rect_list *list = NULL; + struct v4l2_rect *r; + + list = kzalloc(sizeof(*list), GFP_KERNEL); + if (!list) + return 0; + + r = &list->clip.c; + r->left = x; + r->top = y; + r->width = w; + r->height = h; + + list_add_tail(&list->list, head); + return 1; +} + +static void npcm_video_merge_rect(struct npcm_video *video, + struct rect_list_info *info) +{ + struct list_head *head = info->head; + struct rect_list *list = info->list, *first = info->first; + struct v4l2_rect *r = &list->clip.c, *f = &first->clip.c; + + if (!first) { + first = list; + info->first = first; + list_add_tail(&list->list, head); + video->rect_cnt++; + } else { + if ((r->left == (f->left + f->width)) && r->top == f->top) { + f->width += r->width; + kfree(list); + } else if ((r->top == (f->top + f->height)) && + (r->left == f->left)) { + f->height += r->height; + kfree(list); + } else if (((r->top > f->top) && + (r->top < (f->top + f->height))) && + ((r->left > f->left) && + (r->left < (f->left + f->width)))) { + kfree(list); + } else { + list_add_tail(&list->list, head); + video->rect_cnt++; + info->first = list; + } + } +} + +static struct rect_list *npcm_video_new_rect(struct npcm_video *video, + unsigned int offset, + unsigned int index) +{ + struct v4l2_bt_timings *act = &video->active_timings; + struct rect_list *list = NULL; + struct v4l2_rect *r; + + list = kzalloc(sizeof(*list), GFP_KERNEL); + if (!list) + return NULL; + + r = &list->clip.c; + + r->left = (offset << 4); + r->top = (index >> 2); + r->width = RECT_W; + r->height = RECT_H; + if ((r->left + RECT_W) > act->width) + r->width = act->width - r->left; + if ((r->top + RECT_H) > act->height) + r->height = act->height - r->top; + + return list; +} + +static int npcm_video_find_rect(struct npcm_video *video, + struct rect_list_info *info, + unsigned int offset) +{ + if (offset < info->tile_perline) { + info->list = npcm_video_new_rect(video, offset, info->index); + if (!info->list) { + dev_err(video->dev, "Failed to allocate rect_list\n"); + return -ENOMEM; + } + + npcm_video_merge_rect(video, info); + } + return 0; +} + +static int npcm_video_build_table(struct npcm_video *video, + struct rect_list_info *info) +{ + struct regmap *vcd = video->vcd_regmap; + unsigned int j, bit, value; + int ret; + + for (j = 0; j < info->offset_perline; j += 4) { + regmap_read(vcd, VCD_DIFF_TBL + (j + info->index), &value); + + bitmap_from_arr32(bitmap, &value, BITMAP_SIZE); + + for_each_set_bit(bit, bitmap, BITMAP_SIZE) { + ret = npcm_video_find_rect(video, info, bit + (j << 3)); + if (ret) + return ret; + } + } + info->index += 64; + return info->tile_perline; +} + +static void npcm_video_get_rect_list(struct npcm_video *video, unsigned int index) +{ + struct v4l2_bt_timings *act = &video->active_timings; + struct rect_list_info info; + unsigned int tile_cnt = 0, mod; + int ret = 0; + + memset(&info, 0, sizeof(struct rect_list_info)); + info.head = &video->list[index]; + + info.tile_perline = act->width >> 4; + mod = act->width % RECT_W; + if (mod != 0) + info.tile_perline += 1; + + info.tile_perrow = act->height >> 4; + mod = act->height % RECT_H; + if (mod != 0) + info.tile_perrow += 1; + + info.tile_size = info.tile_perrow * info.tile_perline; + + info.offset_perline = info.tile_perline >> 5; + mod = info.tile_perline % 32; + if (mod != 0) + info.offset_perline += 1; + + info.offset_perline *= 4; + + do { + ret = npcm_video_build_table(video, &info); + if (ret < 0) + return; + + tile_cnt += ret; + } while (tile_cnt < info.tile_size); +} + +static unsigned int npcm_video_is_mga(struct npcm_video *video) +{ + struct regmap *gfxi = video->gfx_regmap; + unsigned int dispst; + + regmap_read(gfxi, DISPST, &dispst); + return ((dispst & DISPST_MGAMODE) == DISPST_MGAMODE); +} + +static unsigned int npcm_video_hres(struct npcm_video *video) +{ + struct regmap *gfxi = video->gfx_regmap; + unsigned int hvcnth, hvcntl, apb_hor_res; + + regmap_read(gfxi, HVCNTH, &hvcnth); + regmap_read(gfxi, HVCNTL, &hvcntl); + apb_hor_res = (((hvcnth & HVCNTH_MASK) << 8) + (hvcntl & HVCNTL_MASK) + 1); + + return apb_hor_res; +} + +static unsigned int npcm_video_vres(struct npcm_video *video) +{ + struct regmap *gfxi = video->gfx_regmap; + unsigned int vvcnth, vvcntl, apb_ver_res; + + regmap_read(gfxi, VVCNTH, &vvcnth); + regmap_read(gfxi, VVCNTL, &vvcntl); + + apb_ver_res = (((vvcnth & VVCNTH_MASK) << 8) + (vvcntl & VVCNTL_MASK)); + + return apb_ver_res; +} + +static int npcm_video_capres(struct npcm_video *video, unsigned int hor_res, + unsigned int vert_res) +{ + struct regmap *vcd = video->vcd_regmap; + unsigned int res, cap_res; + + if (hor_res > MAX_WIDTH || vert_res > MAX_HEIGHT) + return -EINVAL; + + res = FIELD_PREP(VCD_CAP_RES_VERT_RES, vert_res) | + FIELD_PREP(VCD_CAP_RES_HOR_RES, hor_res); + + regmap_write(vcd, VCD_CAP_RES, res); + regmap_read(vcd, VCD_CAP_RES, &cap_res); + + if (cap_res != res) + return -EINVAL; + + return 0; +} + +static void npcm_video_vcd_ip_reset(struct npcm_video *video) +{ + /* + * After resetting a module and clearing the reset bit, it should wait + * at least 10 us before accessing the module. + */ + reset_control_assert(video->reset); + usleep_range(10, 20); + reset_control_deassert(video->reset); + usleep_range(10, 20); +} + +static void npcm_video_vcd_state_machine_reset(struct npcm_video *video) +{ + struct regmap *vcd = video->vcd_regmap; + + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_VCDE, 0); + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_IDBC, 0); + regmap_update_bits(vcd, VCD_CMD, VCD_CMD_RST, VCD_CMD_RST); + + /* + * VCD_CMD_RST will reset VCD internal state machines and clear FIFOs, + * it should wait at least 800 us for the reset operations completed. + */ + usleep_range(800, 1000); + + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_VCDE, VCD_MODE_VCDE); + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_IDBC, VCD_MODE_IDBC); +} + +static void npcm_video_gfx_reset(struct npcm_video *video) +{ + struct regmap *gcr = video->gcr_regmap; + + regmap_update_bits(gcr, INTCR2, INTCR2_GIRST2, INTCR2_GIRST2); + npcm_video_vcd_state_machine_reset(video); + regmap_update_bits(gcr, INTCR2, INTCR2_GIRST2, 0); +} + +static void npcm_video_kvm_bw(struct npcm_video *video, bool set_bw) +{ + struct regmap *vcd = video->vcd_regmap; + + if (set_bw || !npcm_video_is_mga(video)) + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_KVM_BW_SET, + VCD_MODE_KVM_BW_SET); + else + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_KVM_BW_SET, 0); +} + +static unsigned int npcm_video_pclk(struct npcm_video *video) +{ + struct regmap *gfxi = video->gfx_regmap; + unsigned int tmp, pllfbdiv, pllinotdiv, gpllfbdiv; + unsigned int gpllfbdv109, gpllfbdv8, gpllindiv; + unsigned int gpllst_pllotdiv1, gpllst_pllotdiv2; + + regmap_read(gfxi, GPLLST, &tmp); + gpllfbdv109 = FIELD_GET(GPLLST_GPLLFBDV109, tmp); + gpllst_pllotdiv1 = FIELD_GET(GPLLST_PLLOTDIV1, tmp); + gpllst_pllotdiv2 = FIELD_GET(GPLLST_PLLOTDIV2, tmp); + + regmap_read(gfxi, GPLLINDIV, &tmp); + gpllfbdv8 = FIELD_GET(GPLLINDIV_GPLLFBDV8, tmp); + gpllindiv = FIELD_GET(GPLLINDIV_MASK, tmp); + + regmap_read(gfxi, GPLLFBDIV, &tmp); + gpllfbdiv = FIELD_GET(GPLLFBDIV_MASK, tmp); + + pllfbdiv = (512 * gpllfbdv109 + 256 * gpllfbdv8 + gpllfbdiv); + pllinotdiv = (gpllindiv * gpllst_pllotdiv1 * gpllst_pllotdiv2); + if (pllfbdiv == 0 || pllinotdiv == 0) + return 0; + + return ((pllfbdiv * 25000) / pllinotdiv) * 1000; +} + +static unsigned int npcm_video_get_bpp(struct npcm_video *video) +{ + const struct npcm_fmt *fmt; + unsigned int k; + + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &npcm_fmt_list[k]; + if (fmt->fourcc == video->pix_fmt.pixelformat) + break; + } + + return fmt->bpp; +} + +/* + * Pitch must be a power of 2, >= linebytes, + * at least 512, and no more than 4096. + */ +static void npcm_video_set_linepitch(struct npcm_video *video, + unsigned int linebytes) +{ + struct regmap *vcd = video->vcd_regmap; + unsigned int pitch = MIN_LP; + + while ((pitch < linebytes) && (pitch < MAX_LP)) + pitch *= 2; + + regmap_write(vcd, VCD_FB_LP, FIELD_PREP(VCD_FBA_LP, pitch) | + FIELD_PREP(VCD_FBB_LP, pitch)); +} + +static unsigned int npcm_video_get_linepitch(struct npcm_video *video) +{ + struct regmap *vcd = video->vcd_regmap; + unsigned int linepitch; + + regmap_read(vcd, VCD_FB_LP, &linepitch); + return FIELD_GET(VCD_FBA_LP, linepitch); +} + +static void npcm_video_command(struct npcm_video *video, unsigned int value) +{ + struct regmap *vcd = video->vcd_regmap; + unsigned int cmd; + + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + regmap_read(vcd, VCD_CMD, &cmd); + cmd |= FIELD_PREP(VCD_CMD_OPERATION, value); + + regmap_write(vcd, VCD_CMD, cmd); + regmap_update_bits(vcd, VCD_CMD, VCD_CMD_GO, VCD_CMD_GO); + video->op_cmd = value; +} + +static void npcm_video_init_reg(struct npcm_video *video) +{ + struct regmap *gcr = video->gcr_regmap, *vcd = video->vcd_regmap; + + /* Selects Data Enable */ + regmap_update_bits(gcr, INTCR, INTCR_DEHS, 0); + + /* Enable display of KVM GFX and access to memory */ + regmap_update_bits(gcr, INTCR, INTCR_GFXIFDIS, 0); + + /* Active Vertical/Horizontal Counters Reset */ + regmap_update_bits(gcr, INTCR2, INTCR2_GIHCRST | INTCR2_GIVCRST, + INTCR2_GIHCRST | INTCR2_GIVCRST); + + /* Reset video modules */ + npcm_video_vcd_ip_reset(video); + npcm_video_gfx_reset(video); + + /* Set the FIFO thresholds */ + regmap_write(vcd, VCD_FIFO, VCD_FIFO_TH); + + /* Set RCHG timer */ + regmap_write(vcd, VCD_RCHG, FIELD_PREP(VCD_RCHG_TIM_PRSCL, 0xf) | + FIELD_PREP(VCD_RCHG_IG_CHG0, 0x3)); + + /* Set video mode */ + regmap_write(vcd, VCD_MODE, VCD_MODE_VCDE | VCD_MODE_CM565 | + VCD_MODE_IDBC | VCD_MODE_KVM_BW_SET); +} + +static int npcm_video_start_frame(struct npcm_video *video) +{ + struct npcm_video_buffer *buf; + struct regmap *vcd = video->vcd_regmap; + unsigned long flags; + unsigned int val; + int ret; + + if (video->v4l2_input_status) { + dev_dbg(video->dev, "No video signal; skip capture frame\n"); + return 0; + } + + ret = regmap_read_poll_timeout(vcd, VCD_STAT, val, !(val & VCD_STAT_BUSY), + 1000, VCD_TIMEOUT_US); + if (ret) { + dev_err(video->dev, "Wait for VCD_STAT_BUSY timeout\n"); + return -EBUSY; + } + + spin_lock_irqsave(&video->lock, flags); + buf = list_first_entry_or_null(&video->buffers, + struct npcm_video_buffer, link); + if (!buf) { + spin_unlock_irqrestore(&video->lock, flags); + dev_dbg(video->dev, "No empty buffers; skip capture frame\n"); + return 0; + } + + set_bit(VIDEO_CAPTURING, &video->flags); + spin_unlock_irqrestore(&video->lock, flags); + + npcm_video_vcd_state_machine_reset(video); + + regmap_read(vcd, VCD_HOR_AC_TIM, &val); + regmap_update_bits(vcd, VCD_HOR_AC_LST, VCD_HOR_AC_LAST, + FIELD_GET(VCD_HOR_AC_TIME, val)); + + regmap_read(vcd, VCD_VER_HI_TIM, &val); + regmap_update_bits(vcd, VCD_VER_HI_LST, VCD_VER_HI_LAST, + FIELD_GET(VCD_VER_HI_TIME, val)); + + regmap_update_bits(vcd, VCD_INTE, VCD_INTE_DONE_IE | VCD_INTE_IFOT_IE | + VCD_INTE_IFOR_IE | VCD_INTE_HAC_IE | VCD_INTE_VHT_IE, + VCD_INTE_DONE_IE | VCD_INTE_IFOT_IE | VCD_INTE_IFOR_IE | + VCD_INTE_HAC_IE | VCD_INTE_VHT_IE); + + npcm_video_command(video, video->ctrl_cmd); + + return 0; +} + +static void npcm_video_bufs_done(struct npcm_video *video, + enum vb2_buffer_state state) +{ + struct npcm_video_buffer *buf; + unsigned long flags; + + spin_lock_irqsave(&video->lock, flags); + list_for_each_entry(buf, &video->buffers, link) + vb2_buffer_done(&buf->vb.vb2_buf, state); + + INIT_LIST_HEAD(&video->buffers); + spin_unlock_irqrestore(&video->lock, flags); +} + +static void npcm_video_get_diff_rect(struct npcm_video *video, unsigned int index) +{ + unsigned int width = video->active_timings.width; + unsigned int height = video->active_timings.height; + + if (video->op_cmd != VCD_CMD_OPERATION_CAPTURE) { + video->rect_cnt = 0; + npcm_video_get_rect_list(video, index); + video->rect[index] = video->rect_cnt; + } else { + video->rect[index] = npcm_video_add_rect(video, index, 0, 0, + width, height); + } +} + +static void npcm_video_detect_resolution(struct npcm_video *video) +{ + struct v4l2_bt_timings *act = &video->active_timings; + struct v4l2_bt_timings *det = &video->detected_timings; + struct regmap *gfxi = video->gfx_regmap; + unsigned int dispst; + + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + det->width = npcm_video_hres(video); + det->height = npcm_video_vres(video); + + if (act->width != det->width || act->height != det->height) { + dev_dbg(video->dev, "Resolution changed\n"); + + if (npcm_video_hres(video) > 0 && npcm_video_vres(video) > 0) { + if (test_bit(VIDEO_STREAMING, &video->flags)) { + /* + * Wait for resolution is available, + * and it is also captured by host. + */ + do { + mdelay(100); + regmap_read(gfxi, DISPST, &dispst); + } while (npcm_video_vres(video) < 100 || + npcm_video_pclk(video) == 0 || + (dispst & DISPST_HSCROFF)); + } + + det->width = npcm_video_hres(video); + det->height = npcm_video_vres(video); + det->pixelclock = npcm_video_pclk(video); + } + + clear_bit(VIDEO_RES_CHANGING, &video->flags); + } + + if (det->width && det->height) + video->v4l2_input_status = 0; + + dev_dbg(video->dev, "Got resolution[%dx%d] -> [%dx%d], status %d\n", + act->width, act->height, det->width, det->height, + video->v4l2_input_status); +} + +static int npcm_video_set_resolution(struct npcm_video *video, + struct v4l2_bt_timings *timing) +{ + struct regmap *vcd = video->vcd_regmap; + unsigned int mode; + + if (npcm_video_capres(video, timing->width, timing->height)) { + dev_err(video->dev, "Failed to set VCD_CAP_RES\n"); + return -EINVAL; + } + + video->active_timings = *timing; + video->bytesperpixel = npcm_video_get_bpp(video); + npcm_video_set_linepitch(video, timing->width * video->bytesperpixel); + video->bytesperline = npcm_video_get_linepitch(video); + video->pix_fmt.width = timing->width ? timing->width : MIN_WIDTH; + video->pix_fmt.height = timing->height ? timing->height : MIN_HEIGHT; + video->pix_fmt.sizeimage = video->pix_fmt.width * video->pix_fmt.height * + video->bytesperpixel; + video->pix_fmt.bytesperline = video->bytesperline; + + npcm_video_kvm_bw(video, timing->pixelclock > VCD_KVM_BW_PCLK); + npcm_video_gfx_reset(video); + regmap_read(vcd, VCD_MODE, &mode); + + dev_dbg(video->dev, "VCD mode = 0x%x, %s mode\n", mode, + npcm_video_is_mga(video) ? "Hi Res" : "VGA"); + + dev_dbg(video->dev, + "Digital mode: %d x %d x %d, pixelclock %lld, bytesperline %d\n", + timing->width, timing->height, video->bytesperpixel, + timing->pixelclock, video->bytesperline); + + return 0; +} + +static void npcm_video_start(struct npcm_video *video) +{ + npcm_video_init_reg(video); + + if (!npcm_video_alloc_fb(video, &video->src)) { + dev_err(video->dev, "Failed to allocate VCD frame buffer\n"); + return; + } + + npcm_video_detect_resolution(video); + if (npcm_video_set_resolution(video, &video->detected_timings)) { + dev_err(video->dev, "Failed to set resolution\n"); + return; + } + + /* Set frame buffer physical address */ + regmap_write(video->vcd_regmap, VCD_FBA_ADR, video->src.dma); + regmap_write(video->vcd_regmap, VCD_FBB_ADR, video->src.dma); + + if (video->ece.enable && atomic_inc_return(&video->ece.clients) == 1) { + npcm_video_ece_ip_reset(video); + npcm_video_ece_ctrl_reset(video); + npcm_video_ece_set_fb_addr(video, video->src.dma); + npcm_video_ece_set_lp(video, video->bytesperline); + + dev_dbg(video->dev, "ECE open: client %d\n", + atomic_read(&video->ece.clients)); + } +} + +static void npcm_video_stop(struct npcm_video *video) +{ + struct regmap *vcd = video->vcd_regmap; + + set_bit(VIDEO_STOPPED, &video->flags); + + regmap_write(vcd, VCD_INTE, 0); + regmap_write(vcd, VCD_MODE, 0); + regmap_write(vcd, VCD_RCHG, 0); + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + + if (video->src.size) + npcm_video_free_fb(video, &video->src); + + npcm_video_free_diff_table(video); + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + video->flags = 0; + video->ctrl_cmd = VCD_CMD_OPERATION_CAPTURE; + + if (video->ece.enable && atomic_dec_return(&video->ece.clients) == 0) { + npcm_video_ece_stop(video); + dev_dbg(video->dev, "ECE close: client %d\n", + atomic_read(&video->ece.clients)); + } +} + +static unsigned int npcm_video_raw(struct npcm_video *video, int index, void *addr) +{ + unsigned int width = video->active_timings.width; + unsigned int height = video->active_timings.height; + unsigned int i, len, offset, bytes = 0; + + video->rect[index] = npcm_video_add_rect(video, index, 0, 0, width, height); + + for (i = 0; i < height; i++) { + len = width * video->bytesperpixel; + offset = i * video->bytesperline; + + memcpy(addr + bytes, video->src.virt + offset, len); + bytes += len; + } + + return bytes; +} + +static unsigned int npcm_video_hextile(struct npcm_video *video, unsigned int index, + unsigned int dma_addr, void *vaddr) +{ + struct rect_list *rect_list; + struct v4l2_rect *rect; + unsigned int offset, len, bytes = 0; + + npcm_video_ece_ctrl_reset(video); + npcm_video_ece_clear_rect_offset(video); + npcm_video_ece_set_fb_addr(video, video->src.dma); + + /* Set base address of encoded data to video buffer */ + npcm_video_ece_set_enc_dba(video, dma_addr); + + npcm_video_ece_set_lp(video, video->bytesperline); + npcm_video_get_diff_rect(video, index); + + list_for_each_entry(rect_list, &video->list[index], list) { + rect = &rect_list->clip.c; + offset = npcm_video_ece_read_rect_offset(video); + npcm_video_ece_enc_rect(video, rect->left, rect->top, + rect->width, rect->height); + + len = npcm_video_ece_get_ed_size(video, offset, vaddr); + npcm_video_ece_prepend_rect_header(vaddr + offset, + rect->left, rect->top, + rect->width, rect->height); + bytes += len; + } + + return bytes; +} + +static irqreturn_t npcm_video_irq(int irq, void *arg) +{ + struct npcm_video *video = arg; + struct regmap *vcd = video->vcd_regmap; + struct npcm_video_buffer *buf; + unsigned int index, size, status, fmt; + dma_addr_t dma_addr; + void *addr; + static const struct v4l2_event ev = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + regmap_read(vcd, VCD_STAT, &status); + dev_dbg(video->dev, "VCD irq status 0x%x\n", status); + + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + + if (test_bit(VIDEO_STOPPED, &video->flags) || + !test_bit(VIDEO_STREAMING, &video->flags)) + return IRQ_NONE; + + if (status & VCD_STAT_DONE) { + regmap_write(vcd, VCD_INTE, 0); + spin_lock(&video->lock); + clear_bit(VIDEO_CAPTURING, &video->flags); + buf = list_first_entry_or_null(&video->buffers, + struct npcm_video_buffer, link); + if (!buf) { + spin_unlock(&video->lock); + return IRQ_NONE; + } + + addr = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + index = buf->vb.vb2_buf.index; + fmt = video->pix_fmt.pixelformat; + + switch (fmt) { + case V4L2_PIX_FMT_RGB565: + size = npcm_video_raw(video, index, addr); + break; + case V4L2_PIX_FMT_HEXTILE: + dma_addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + size = npcm_video_hextile(video, index, dma_addr, addr); + break; + default: + spin_unlock(&video->lock); + return IRQ_NONE; + } + + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.sequence = video->sequence++; + buf->vb.field = V4L2_FIELD_NONE; + + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + list_del(&buf->link); + spin_unlock(&video->lock); + + if (npcm_video_start_frame(video)) + dev_err(video->dev, "Failed to capture next frame\n"); + } + + /* Resolution changed */ + if (status & VCD_STAT_VHT_CHG || status & VCD_STAT_HAC_CHG) { + if (!test_bit(VIDEO_RES_CHANGING, &video->flags)) { + set_bit(VIDEO_RES_CHANGING, &video->flags); + + vb2_queue_error(&video->queue); + v4l2_event_queue(&video->vdev, &ev); + } + } + + if (status & VCD_STAT_IFOR || status & VCD_STAT_IFOT) { + dev_warn(video->dev, "VCD FIFO overrun or over thresholds\n"); + if (npcm_video_start_frame(video)) + dev_err(video->dev, "Failed to recover from FIFO overrun\n"); + } + + return IRQ_HANDLED; +} + +static int npcm_video_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, DEVICE_NAME, sizeof(cap->driver)); + strscpy(cap->card, "NPCM Video Engine", sizeof(cap->card)); + + return 0; +} + +static int npcm_video_enum_format(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + struct npcm_video *video = video_drvdata(file); + const struct npcm_fmt *fmt; + + if (f->index >= NUM_FORMATS) + return -EINVAL; + + fmt = &npcm_fmt_list[f->index]; + if (fmt->fourcc == V4L2_PIX_FMT_HEXTILE && !video->ece.enable) + return -EINVAL; + + f->pixelformat = fmt->fourcc; + return 0; +} + +static int npcm_video_try_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct npcm_video *video = video_drvdata(file); + const struct npcm_fmt *fmt; + + fmt = npcm_video_find_format(f); + + /* If format not found or HEXTILE not supported, use RGB565 as default */ + if (!fmt || (fmt->fourcc == V4L2_PIX_FMT_HEXTILE && !video->ece.enable)) + f->fmt.pix.pixelformat = npcm_fmt_list[0].fourcc; + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + f->fmt.pix.quantization = V4L2_QUANTIZATION_FULL_RANGE; + f->fmt.pix.width = video->pix_fmt.width; + f->fmt.pix.height = video->pix_fmt.height; + f->fmt.pix.bytesperline = video->bytesperline; + f->fmt.pix.sizeimage = video->pix_fmt.sizeimage; + + return 0; +} + +static int npcm_video_get_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct npcm_video *video = video_drvdata(file); + + f->fmt.pix = video->pix_fmt; + return 0; +} + +static int npcm_video_set_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct npcm_video *video = video_drvdata(file); + int ret; + + ret = npcm_video_try_format(file, fh, f); + if (ret) + return ret; + + if (vb2_is_busy(&video->queue)) { + dev_err(video->dev, "%s device busy\n", __func__); + return -EBUSY; + } + + video->pix_fmt.pixelformat = f->fmt.pix.pixelformat; + return 0; +} + +static int npcm_video_enum_input(struct file *file, void *fh, + struct v4l2_input *inp) +{ + struct npcm_video *video = video_drvdata(file); + + if (inp->index) + return -EINVAL; + + strscpy(inp->name, "Host VGA capture", sizeof(inp->name)); + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; + inp->status = video->v4l2_input_status; + + return 0; +} + +static int npcm_video_get_input(struct file *file, void *fh, unsigned int *i) +{ + *i = 0; + + return 0; +} + +static int npcm_video_set_input(struct file *file, void *fh, unsigned int i) +{ + if (i) + return -EINVAL; + + return 0; +} + +static int npcm_video_set_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct npcm_video *video = video_drvdata(file); + int rc; + + if (timings->bt.width == video->active_timings.width && + timings->bt.height == video->active_timings.height) + return 0; + + if (vb2_is_busy(&video->queue)) { + dev_err(video->dev, "%s device busy\n", __func__); + return -EBUSY; + } + + rc = npcm_video_set_resolution(video, &timings->bt); + if (rc) + return rc; + + timings->type = V4L2_DV_BT_656_1120; + + return 0; +} + +static int npcm_video_get_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct npcm_video *video = video_drvdata(file); + + timings->type = V4L2_DV_BT_656_1120; + timings->bt = video->active_timings; + + return 0; +} + +static int npcm_video_query_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct npcm_video *video = video_drvdata(file); + + npcm_video_detect_resolution(video); + timings->type = V4L2_DV_BT_656_1120; + timings->bt = video->detected_timings; + + return video->v4l2_input_status ? -ENOLINK : 0; +} + +static int npcm_video_enum_dv_timings(struct file *file, void *fh, + struct v4l2_enum_dv_timings *timings) +{ + return v4l2_enum_dv_timings_cap(timings, &npcm_video_timings_cap, + NULL, NULL); +} + +static int npcm_video_dv_timings_cap(struct file *file, void *fh, + struct v4l2_dv_timings_cap *cap) +{ + *cap = npcm_video_timings_cap; + + return 0; +} + +static int npcm_video_sub_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + } + + return v4l2_ctrl_subscribe_event(fh, sub); +} + +static const struct v4l2_ioctl_ops npcm_video_ioctls = { + .vidioc_querycap = npcm_video_querycap, + + .vidioc_enum_fmt_vid_cap = npcm_video_enum_format, + .vidioc_g_fmt_vid_cap = npcm_video_get_format, + .vidioc_s_fmt_vid_cap = npcm_video_set_format, + .vidioc_try_fmt_vid_cap = npcm_video_try_format, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_enum_input = npcm_video_enum_input, + .vidioc_g_input = npcm_video_get_input, + .vidioc_s_input = npcm_video_set_input, + + .vidioc_s_dv_timings = npcm_video_set_dv_timings, + .vidioc_g_dv_timings = npcm_video_get_dv_timings, + .vidioc_query_dv_timings = npcm_video_query_dv_timings, + .vidioc_enum_dv_timings = npcm_video_enum_dv_timings, + .vidioc_dv_timings_cap = npcm_video_dv_timings_cap, + + .vidioc_subscribe_event = npcm_video_sub_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int npcm_video_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct npcm_video *video = container_of(ctrl->handler, struct npcm_video, + ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_NPCM_CAPTURE_MODE: + if (ctrl->val == V4L2_NPCM_CAPTURE_MODE_COMPLETE) + video->ctrl_cmd = VCD_CMD_OPERATION_CAPTURE; + else if (ctrl->val == V4L2_NPCM_CAPTURE_MODE_DIFF) + video->ctrl_cmd = VCD_CMD_OPERATION_COMPARE; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops npcm_video_ctrl_ops = { + .s_ctrl = npcm_video_set_ctrl, +}; + +static const char * const npcm_ctrl_capture_mode_menu[] = { + "COMPLETE", + "DIFF", + NULL, +}; + +static const struct v4l2_ctrl_config npcm_ctrl_capture_mode = { + .ops = &npcm_video_ctrl_ops, + .id = V4L2_CID_NPCM_CAPTURE_MODE, + .name = "NPCM Video Capture Mode", + .type = V4L2_CTRL_TYPE_MENU, + .min = 0, + .max = V4L2_NPCM_CAPTURE_MODE_DIFF, + .def = 0, + .qmenu = npcm_ctrl_capture_mode_menu, +}; + +/* + * This control value is set when a buffer is dequeued by userspace, i.e. in + * npcm_video_buf_finish function. + */ +static const struct v4l2_ctrl_config npcm_ctrl_rect_count = { + .id = V4L2_CID_NPCM_RECT_COUNT, + .name = "NPCM Hextile Rectangle Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (MAX_WIDTH / RECT_W) * (MAX_HEIGHT / RECT_H), + .step = 1, + .def = 0, +}; + +static int npcm_video_open(struct file *file) +{ + struct npcm_video *video = video_drvdata(file); + int rc; + + mutex_lock(&video->video_lock); + rc = v4l2_fh_open(file); + if (rc) { + mutex_unlock(&video->video_lock); + return rc; + } + + if (v4l2_fh_is_singular_file(file)) + npcm_video_start(video); + + mutex_unlock(&video->video_lock); + return 0; +} + +static int npcm_video_release(struct file *file) +{ + struct npcm_video *video = video_drvdata(file); + int rc; + + mutex_lock(&video->video_lock); + if (v4l2_fh_is_singular_file(file)) + npcm_video_stop(video); + + rc = _vb2_fop_release(file, NULL); + + mutex_unlock(&video->video_lock); + return rc; +} + +static const struct v4l2_file_operations npcm_video_v4l2_fops = { + .owner = THIS_MODULE, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, + .open = npcm_video_open, + .release = npcm_video_release, +}; + +static int npcm_video_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct npcm_video *video = vb2_get_drv_priv(q); + unsigned int i; + + if (*num_planes) { + if (sizes[0] < video->pix_fmt.sizeimage) + return -EINVAL; + + return 0; + } + + *num_planes = 1; + sizes[0] = video->pix_fmt.sizeimage; + + for (i = 0; i < VIDEO_MAX_FRAME; i++) + INIT_LIST_HEAD(&video->list[i]); + + return 0; +} + +static int npcm_video_buf_prepare(struct vb2_buffer *vb) +{ + struct npcm_video *video = vb2_get_drv_priv(vb->vb2_queue); + + if (vb2_plane_size(vb, 0) < video->pix_fmt.sizeimage) + return -EINVAL; + + return 0; +} + +static int npcm_video_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct npcm_video *video = vb2_get_drv_priv(q); + int rc; + + video->sequence = 0; + rc = npcm_video_start_frame(video); + if (rc) { + npcm_video_bufs_done(video, VB2_BUF_STATE_QUEUED); + return rc; + } + + set_bit(VIDEO_STREAMING, &video->flags); + return 0; +} + +static void npcm_video_stop_streaming(struct vb2_queue *q) +{ + struct npcm_video *video = vb2_get_drv_priv(q); + struct regmap *vcd = video->vcd_regmap; + + clear_bit(VIDEO_STREAMING, &video->flags); + regmap_write(vcd, VCD_INTE, 0); + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + npcm_video_gfx_reset(video); + npcm_video_bufs_done(video, VB2_BUF_STATE_ERROR); + video->ctrl_cmd = VCD_CMD_OPERATION_CAPTURE; + v4l2_ctrl_s_ctrl(video->rect_cnt_ctrl, 0); +} + +static void npcm_video_buf_queue(struct vb2_buffer *vb) +{ + struct npcm_video *video = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct npcm_video_buffer *nvb = to_npcm_video_buffer(vbuf); + unsigned long flags; + bool empty; + + spin_lock_irqsave(&video->lock, flags); + empty = list_empty(&video->buffers); + list_add_tail(&nvb->link, &video->buffers); + spin_unlock_irqrestore(&video->lock, flags); + + if (test_bit(VIDEO_STREAMING, &video->flags) && + !test_bit(VIDEO_CAPTURING, &video->flags) && empty) { + if (npcm_video_start_frame(video)) + dev_err(video->dev, "Failed to capture next frame\n"); + } +} + +static void npcm_video_buf_finish(struct vb2_buffer *vb) +{ + struct npcm_video *video = vb2_get_drv_priv(vb->vb2_queue); + struct list_head *head, *pos, *nx; + struct rect_list *tmp; + + /* + * This callback is called when the buffer is dequeued, so update + * V4L2_CID_NPCM_RECT_COUNT control value with the number of rectangles + * in this buffer and free associated rect_list. + */ + if (test_bit(VIDEO_STREAMING, &video->flags)) { + v4l2_ctrl_s_ctrl(video->rect_cnt_ctrl, video->rect[vb->index]); + + head = &video->list[vb->index]; + list_for_each_safe(pos, nx, head) { + tmp = list_entry(pos, struct rect_list, list); + list_del(&tmp->list); + kfree(tmp); + } + } +} + +static const struct regmap_config npcm_video_regmap_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = VCD_FIFO, +}; + +static const struct regmap_config npcm_video_ece_regmap_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = ECE_HEX_RECT_OFFSET, +}; + +static const struct vb2_ops npcm_video_vb2_ops = { + .queue_setup = npcm_video_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_prepare = npcm_video_buf_prepare, + .buf_finish = npcm_video_buf_finish, + .start_streaming = npcm_video_start_streaming, + .stop_streaming = npcm_video_stop_streaming, + .buf_queue = npcm_video_buf_queue, +}; + +static int npcm_video_setup_video(struct npcm_video *video) +{ + struct v4l2_device *v4l2_dev = &video->v4l2_dev; + struct video_device *vdev = &video->vdev; + struct vb2_queue *vbq = &video->queue; + int rc; + + if (video->ece.enable) + video->pix_fmt.pixelformat = V4L2_PIX_FMT_HEXTILE; + else + video->pix_fmt.pixelformat = V4L2_PIX_FMT_RGB565; + + video->pix_fmt.field = V4L2_FIELD_NONE; + video->pix_fmt.colorspace = V4L2_COLORSPACE_SRGB; + video->pix_fmt.quantization = V4L2_QUANTIZATION_FULL_RANGE; + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + + rc = v4l2_device_register(video->dev, v4l2_dev); + if (rc) { + dev_err(video->dev, "Failed to register v4l2 device\n"); + return rc; + } + + v4l2_ctrl_handler_init(&video->ctrl_handler, 2); + v4l2_ctrl_new_custom(&video->ctrl_handler, &npcm_ctrl_capture_mode, NULL); + video->rect_cnt_ctrl = v4l2_ctrl_new_custom(&video->ctrl_handler, + &npcm_ctrl_rect_count, NULL); + if (video->ctrl_handler.error) { + dev_err(video->dev, "Failed to init controls: %d\n", + video->ctrl_handler.error); + + rc = video->ctrl_handler.error; + goto rel_ctrl_handler; + } + v4l2_dev->ctrl_handler = &video->ctrl_handler; + + vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vbq->io_modes = VB2_MMAP | VB2_DMABUF; + vbq->dev = v4l2_dev->dev; + vbq->lock = &video->video_lock; + vbq->ops = &npcm_video_vb2_ops; + vbq->mem_ops = &vb2_dma_contig_memops; + vbq->drv_priv = video; + vbq->buf_struct_size = sizeof(struct npcm_video_buffer); + vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vbq->min_buffers_needed = 3; + + rc = vb2_queue_init(vbq); + if (rc) { + dev_err(video->dev, "Failed to init vb2 queue\n"); + goto rel_ctrl_handler; + } + vdev->queue = vbq; + vdev->fops = &npcm_video_v4l2_fops; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + vdev->v4l2_dev = v4l2_dev; + strscpy(vdev->name, DEVICE_NAME, sizeof(vdev->name)); + vdev->vfl_type = VFL_TYPE_VIDEO; + vdev->vfl_dir = VFL_DIR_RX; + vdev->release = video_device_release_empty; + vdev->ioctl_ops = &npcm_video_ioctls; + vdev->lock = &video->video_lock; + + video_set_drvdata(vdev, video); + rc = video_register_device(vdev, VFL_TYPE_VIDEO, 0); + if (rc) { + dev_err(video->dev, "Failed to register video device\n"); + goto rel_vb_queue; + } + + return 0; + +rel_vb_queue: + vb2_queue_release(vbq); +rel_ctrl_handler: + v4l2_ctrl_handler_free(&video->ctrl_handler); + v4l2_device_unregister(v4l2_dev); + + return rc; +} + +static int npcm_video_ece_init(struct npcm_video *video) +{ + struct device *dev = video->dev; + struct device_node *ece_node; + struct platform_device *ece_pdev; + void __iomem *regs; + + ece_node = of_parse_phandle(video->dev->of_node, "nuvoton,ece", 0); + if (!ece_node) { + dev_err(dev, "Failed to get ECE phandle in DTS\n"); + return -ENODEV; + } + + video->ece.enable = of_device_is_available(ece_node); + + if (video->ece.enable) { + dev_info(dev, "Support HEXTILE pixel format\n"); + + ece_pdev = of_find_device_by_node(ece_node); + if (IS_ERR(ece_pdev)) { + dev_err(dev, "Failed to find ECE device\n"); + return PTR_ERR(ece_pdev); + } + of_node_put(ece_node); + + regs = devm_platform_ioremap_resource(ece_pdev, 0); + if (IS_ERR(regs)) { + dev_err(dev, "Failed to parse ECE reg in DTS\n"); + return PTR_ERR(regs); + } + + video->ece.regmap = devm_regmap_init_mmio(dev, regs, + &npcm_video_ece_regmap_cfg); + if (IS_ERR(video->ece.regmap)) { + dev_err(dev, "Failed to initialize ECE regmap\n"); + return PTR_ERR(video->ece.regmap); + } + + video->ece.reset = devm_reset_control_get(&ece_pdev->dev, NULL); + if (IS_ERR(video->ece.reset)) { + dev_err(dev, "Failed to get ECE reset control in DTS\n"); + return PTR_ERR(video->ece.reset); + } + } + + return 0; +} + +static int npcm_video_init(struct npcm_video *video) +{ + struct device *dev = video->dev; + int irq, rc; + + irq = irq_of_parse_and_map(dev->of_node, 0); + if (!irq) { + dev_err(dev, "Failed to find VCD IRQ\n"); + return -ENODEV; + } + + rc = devm_request_threaded_irq(dev, irq, NULL, npcm_video_irq, + IRQF_ONESHOT, DEVICE_NAME, video); + if (rc < 0) { + dev_err(dev, "Failed to request IRQ %d\n", irq); + return rc; + } + + of_reserved_mem_device_init(dev); + rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (rc) { + dev_err(dev, "Failed to set DMA mask\n"); + of_reserved_mem_device_release(dev); + } + + rc = npcm_video_ece_init(video); + if (rc) { + dev_err(dev, "Failed to initialize ECE\n"); + return rc; + } + + return 0; +} + +static int npcm_video_probe(struct platform_device *pdev) +{ + struct npcm_video *video = kzalloc(sizeof(*video), GFP_KERNEL); + int rc; + void __iomem *regs; + + if (!video) + return -ENOMEM; + + video->dev = &pdev->dev; + spin_lock_init(&video->lock); + mutex_init(&video->video_lock); + INIT_LIST_HEAD(&video->buffers); + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) { + dev_err(&pdev->dev, "Failed to parse VCD reg in DTS\n"); + return PTR_ERR(regs); + } + + video->vcd_regmap = devm_regmap_init_mmio(&pdev->dev, regs, + &npcm_video_regmap_cfg); + if (IS_ERR(video->vcd_regmap)) { + dev_err(&pdev->dev, "Failed to initialize VCD regmap\n"); + return PTR_ERR(video->vcd_regmap); + } + + video->reset = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(video->reset)) { + dev_err(&pdev->dev, "Failed to get VCD reset control in DTS\n"); + return PTR_ERR(video->reset); + } + + video->gcr_regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "nuvoton,sysgcr"); + if (IS_ERR(video->gcr_regmap)) + return PTR_ERR(video->gcr_regmap); + + video->gfx_regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "nuvoton,sysgfxi"); + if (IS_ERR(video->gfx_regmap)) + return PTR_ERR(video->gfx_regmap); + + rc = npcm_video_init(video); + if (rc) + return rc; + + rc = npcm_video_setup_video(video); + if (rc) + return rc; + + dev_info(video->dev, "NPCM video driver probed\n"); + return 0; +} + +static int npcm_video_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); + struct npcm_video *video = to_npcm_video(v4l2_dev); + + video_unregister_device(&video->vdev); + vb2_queue_release(&video->queue); + v4l2_ctrl_handler_free(&video->ctrl_handler); + v4l2_device_unregister(v4l2_dev); + if (video->ece.enable) + npcm_video_ece_stop(video); + of_reserved_mem_device_release(dev); + + return 0; +} + +static const struct of_device_id npcm_video_match[] = { + { .compatible = "nuvoton,npcm750-vcd" }, + { .compatible = "nuvoton,npcm845-vcd" }, + {}, +}; + +MODULE_DEVICE_TABLE(of, npcm_video_match); + +static struct platform_driver npcm_video_driver = { + .driver = { + .name = DEVICE_NAME, + .of_match_table = npcm_video_match, + }, + .probe = npcm_video_probe, + .remove = npcm_video_remove, +}; + +module_platform_driver(npcm_video_driver); + +MODULE_AUTHOR("Joseph Liu <kwliu@nuvoton.com>"); +MODULE_AUTHOR("Marvin Lin <kflin@nuvoton.com>"); +MODULE_DESCRIPTION("Driver for Nuvoton NPCM Video Capture/Encode Engine"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h index a2b4fb9e29..d579c804b0 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h @@ -115,28 +115,17 @@ void print_cast_status(struct device *dev, void __iomem *reg, void print_wrapper_info(struct device *dev, void __iomem *reg); void mxc_jpeg_sw_reset(void __iomem *reg); int mxc_jpeg_enable(void __iomem *reg); -void wait_frmdone(struct device *dev, void __iomem *reg); void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg, u8 extseq); void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg, u8 extseq); void mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg, u8 quality); void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg); -int mxc_jpeg_get_slot(void __iomem *reg); -u32 mxc_jpeg_get_offset(void __iomem *reg, int slot); void mxc_jpeg_enable_slot(void __iomem *reg, int slot); void mxc_jpeg_set_l_endian(void __iomem *reg, int le); void mxc_jpeg_enable_irq(void __iomem *reg, int slot); void mxc_jpeg_disable_irq(void __iomem *reg, int slot); -int mxc_jpeg_set_input(void __iomem *reg, u32 in_buf, u32 bufsize); -int mxc_jpeg_set_output(void __iomem *reg, u16 out_pitch, u32 out_buf, - u16 w, u16 h); -void mxc_jpeg_set_config_mode(void __iomem *reg, int config_mode); -int mxc_jpeg_set_params(struct mxc_jpeg_desc *desc, u32 bufsize, u16 - out_pitch, u32 format); void mxc_jpeg_set_bufsize(struct mxc_jpeg_desc *desc, u32 bufsize); void mxc_jpeg_set_res(struct mxc_jpeg_desc *desc, u16 w, u16 h); void mxc_jpeg_set_line_pitch(struct mxc_jpeg_desc *desc, u32 line_pitch); void mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot); void mxc_jpeg_clr_desc(void __iomem *reg, int slot); -void mxc_jpeg_set_regs_from_desc(struct mxc_jpeg_desc *desc, - void __iomem *reg); #endif diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 0c8b204535..64112b6329 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -2794,7 +2794,7 @@ static int mxc_jpeg_probe(struct platform_device *pdev) ret = mxc_jpeg_attach_pm_domains(jpeg); if (ret < 0) { dev_err(dev, "failed to attach power domains %d\n", ret); - return ret; + goto err_clk; } /* v4l2 */ diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 142ac7b73e..b08f6d2e75 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -1114,8 +1114,6 @@ static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL; fd->num_entries = 1; - memset(entry, 0, sizeof(*entry)); - entry->flags = 0; entry->pixelcode = csis_fmt->code; entry->bus.csi2.vc = 0; diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c index 81be744e9f..f73facb97d 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c @@ -406,12 +406,10 @@ static int mxc_isi_clk_get(struct mxc_isi_dev *isi) * sizeof(*isi->clks); int ret; - isi->clks = devm_kmalloc(isi->dev, size, GFP_KERNEL); + isi->clks = devm_kmemdup(isi->dev, isi->pdata->clks, size, GFP_KERNEL); if (!isi->clks) return -ENOMEM; - memcpy(isi->clks, isi->pdata->clks, size); - ret = devm_clk_bulk_get(isi->dev, isi->pdata->num_clks, isi->clks); if (ret < 0) { diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-1.c b/drivers/media/platform/qcom/camss/camss-csid-4-1.c index d2aec0679d..dd49a40e6a 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-csid-4-1.c @@ -47,28 +47,28 @@ static const struct csid_format csid_formats[] = { { - MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_VYUY8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_YVYU8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-7.c b/drivers/media/platform/qcom/camss/camss-csid-4-7.c index e7436ec6d0..6b26e03629 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-csid-4-7.c @@ -46,28 +46,28 @@ static const struct csid_format csid_formats[] = { { - MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_VYUY8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_YVYU8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.c b/drivers/media/platform/qcom/camss/camss-csid-gen2.c index 0147cc062e..05ff5fa809 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c +++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c @@ -179,28 +179,28 @@ static const struct csid_format csid_formats[] = { { - MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_VYUY8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, 2, }, { - MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_YVYU8_1X16, DATA_TYPE_YUV422_8BIT, DECODE_FORMAT_UNCOMPRESSED_8_BIT, 8, diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 6360314f04..95873f988f 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -159,15 +159,17 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) struct camss *camss = csid->camss; struct device *dev = camss->dev; struct vfe_device *vfe = &camss->vfe[csid->id]; - u32 version = camss->version; int ret = 0; if (on) { - if (version == CAMSS_8250 || version == CAMSS_845) { - ret = vfe_get(vfe); - if (ret < 0) - return ret; - } + /* + * From SDM845 onwards, the VFE needs to be powered on before + * switching on the CSID. Do so unconditionally, as there is no + * drawback in following the same powering order on older SoCs. + */ + ret = vfe_get(vfe); + if (ret < 0) + return ret; ret = pm_runtime_resume_and_get(dev); if (ret < 0) @@ -217,8 +219,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) regulator_bulk_disable(csid->num_supplies, csid->supplies); pm_runtime_put_sync(dev); - if (version == CAMSS_8250 || version == CAMSS_845) - vfe_put(vfe); + vfe_put(vfe); } return ret; @@ -307,7 +308,7 @@ static void csid_try_format(struct csid_device *csid, /* If not found, use UYVY as default */ if (i >= csid->nformats) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt->width = clamp_t(u32, fmt->width, 1, 8191); fmt->height = clamp_t(u32, fmt->height, 1, 8191); @@ -336,7 +337,7 @@ static void csid_try_format(struct csid_device *csid, /* If not found, use UYVY as default */ if (i >= csid->nformats) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt->width = clamp_t(u32, fmt->width, 1, 8191); fmt->height = clamp_t(u32, fmt->height, 1, 8191); @@ -503,7 +504,7 @@ static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) .which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE, .format = { - .code = MEDIA_BUS_FMT_UYVY8_2X8, + .code = MEDIA_BUS_FMT_UYVY8_1X16, .width = 1920, .height = 1080 } @@ -566,7 +567,7 @@ static const struct v4l2_ctrl_ops csid_ctrl_ops = { * Return 0 on success or a negative error code otherwise */ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, - const struct resources *res, u8 id) + const struct camss_subdev_resources *res, u8 id) { struct device *dev = camss->dev; struct platform_device *pdev = to_platform_device(dev); @@ -575,23 +576,13 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, csid->camss = camss; csid->id = id; + csid->ops = res->ops; - if (camss->version == CAMSS_8x16) { - csid->ops = &csid_ops_4_1; - } else if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) { - csid->ops = &csid_ops_4_7; - } else if (camss->version == CAMSS_845 || - camss->version == CAMSS_8250) { - csid->ops = &csid_ops_gen2; - } else { - return -EINVAL; - } csid->ops->subdev_init(csid); /* Memory */ - if (camss->version == CAMSS_8250) { + if (camss->res->version == CAMSS_8250) { /* for titan 480, CSID registers are inside the VFE region, * between the VFE "top" and "bus" registers. this requires * VFE to be initialized before CSID diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h index d4b48432a0..30d94eb2eb 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.h +++ b/drivers/media/platform/qcom/camss/camss-csid.h @@ -172,7 +172,7 @@ struct csid_device { const struct csid_hw_ops *ops; }; -struct resources; +struct camss_subdev_resources; /* * csid_find_code - Find a format code in an array using array index or format code @@ -200,7 +200,7 @@ const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats, u32 code); int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, - const struct resources *res, u8 id); + const struct camss_subdev_resources *res, u8 id); int msm_csid_register_entity(struct csid_device *csid, struct v4l2_device *v4l2_dev); diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 4dba61b8d3..f50e2235c3 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -402,7 +402,7 @@ static void csiphy_gen1_config_lanes(struct csiphy_device *csiphy, val = CSIPHY_3PH_LNn_CFG1_SWI_REC_DLY_PRG; writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG1(l)); - if (csiphy->camss->version == CAMSS_660) + if (csiphy->camss->res->version == CAMSS_660) val = CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS_660; else val = CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS; @@ -419,7 +419,7 @@ static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy, int i, l, array_size; u32 val; - switch (csiphy->camss->version) { + switch (csiphy->camss->res->version) { case CAMSS_845: r = &lane_regs_sdm845[0][0]; array_size = ARRAY_SIZE(lane_regs_sdm845[0]); @@ -468,8 +468,8 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy, s64 link_freq, u8 lane_mask) { struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg; - bool is_gen2 = (csiphy->camss->version == CAMSS_845 || - csiphy->camss->version == CAMSS_8250); + bool is_gen2 = (csiphy->camss->res->version == CAMSS_845 || + csiphy->camss->res->version == CAMSS_8250); u8 settle_cnt; u8 val; int i; diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 3f726a7237..edd573606a 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -30,10 +30,10 @@ struct csiphy_format { }; static const struct csiphy_format csiphy_formats_8x16[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, @@ -50,10 +50,10 @@ static const struct csiphy_format csiphy_formats_8x16[] = { }; static const struct csiphy_format csiphy_formats_8x96[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, @@ -74,10 +74,10 @@ static const struct csiphy_format csiphy_formats_8x96[] = { }; static const struct csiphy_format csiphy_formats_sdm845[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, @@ -357,7 +357,7 @@ static void csiphy_try_format(struct csiphy_device *csiphy, /* If not found, use UYVY as default */ if (i >= csiphy->nformats) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt->width = clamp_t(u32, fmt->width, 1, 8191); fmt->height = clamp_t(u32, fmt->height, 1, 8191); @@ -527,7 +527,7 @@ static int csiphy_init_formats(struct v4l2_subdev *sd, .which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE, .format = { - .code = MEDIA_BUS_FMT_UYVY8_2X8, + .code = MEDIA_BUS_FMT_UYVY8_1X16, .width = 1920, .height = 1080 } @@ -536,6 +536,15 @@ static int csiphy_init_formats(struct v4l2_subdev *sd, return csiphy_set_format(sd, fh ? fh->state : NULL, &format); } +static bool csiphy_match_clock_name(const char *clock_name, const char *format, + int index) +{ + char name[16]; /* csiphyXXX_timer\0 */ + + snprintf(name, sizeof(name), format, index); + return !strcmp(clock_name, name); +} + /* * msm_csiphy_subdev_init - Initialize CSIPHY device structure and resources * @csiphy: CSIPHY device @@ -546,33 +555,33 @@ static int csiphy_init_formats(struct v4l2_subdev *sd, */ int msm_csiphy_subdev_init(struct camss *camss, struct csiphy_device *csiphy, - const struct resources *res, u8 id) + const struct camss_subdev_resources *res, u8 id) { struct device *dev = camss->dev; struct platform_device *pdev = to_platform_device(dev); - int i, j; + int i, j, k; int ret; csiphy->camss = camss; csiphy->id = id; csiphy->cfg.combo_mode = 0; + csiphy->ops = res->ops; - if (camss->version == CAMSS_8x16) { - csiphy->ops = &csiphy_ops_2ph_1_0; + switch (camss->res->version) { + case CAMSS_8x16: csiphy->formats = csiphy_formats_8x16; csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x16); - } else if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) { - csiphy->ops = &csiphy_ops_3ph_1_0; + break; + case CAMSS_8x96: + case CAMSS_660: csiphy->formats = csiphy_formats_8x96; csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96); - } else if (camss->version == CAMSS_845 || - camss->version == CAMSS_8250) { - csiphy->ops = &csiphy_ops_3ph_1_0; + break; + case CAMSS_845: + case CAMSS_8250: csiphy->formats = csiphy_formats_sdm845; csiphy->nformats = ARRAY_SIZE(csiphy_formats_sdm845); - } else { - return -EINVAL; + break; } /* Memory */ @@ -581,8 +590,8 @@ int msm_csiphy_subdev_init(struct camss *camss, if (IS_ERR(csiphy->base)) return PTR_ERR(csiphy->base); - if (camss->version == CAMSS_8x16 || - camss->version == CAMSS_8x96) { + if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x96) { csiphy->base_clk_mux = devm_platform_ioremap_resource_byname(pdev, res->reg[1]); if (IS_ERR(csiphy->base_clk_mux)) @@ -656,19 +665,23 @@ int msm_csiphy_subdev_init(struct camss *camss, for (j = 0; j < clock->nfreqs; j++) clock->freq[j] = res->clock_rate[i][j]; - if (!strcmp(clock->name, "csiphy0_timer") || - !strcmp(clock->name, "csiphy1_timer") || - !strcmp(clock->name, "csiphy2_timer") || - !strcmp(clock->name, "csiphy3_timer") || - !strcmp(clock->name, "csiphy4_timer") || - !strcmp(clock->name, "csiphy5_timer")) - csiphy->rate_set[i] = true; - - if (camss->version == CAMSS_660 && - (!strcmp(clock->name, "csi0_phy") || - !strcmp(clock->name, "csi1_phy") || - !strcmp(clock->name, "csi2_phy"))) - csiphy->rate_set[i] = true; + for (k = 0; k < camss->res->csiphy_num; k++) { + csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, + "csiphy%d_timer", k); + if (csiphy->rate_set[i]) + break; + + if (camss->res->version == CAMSS_660) { + csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, + "csi%d_phy", k); + if (csiphy->rate_set[i]) + break; + } + + csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, "csiphy%d", k); + if (csiphy->rate_set[i]) + break; + } } return 0; diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index 1c14947f92..c9b7fe82b1 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -83,11 +83,11 @@ struct csiphy_device { unsigned int nformats; }; -struct resources; +struct camss_subdev_resources; int msm_csiphy_subdev_init(struct camss *camss, struct csiphy_device *csiphy, - const struct resources *res, u8 id); + const struct camss_subdev_resources *res, u8 id); int msm_csiphy_register_entity(struct csiphy_device *csiphy, struct v4l2_device *v4l2_dev); diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index b713f5b86a..be9d2f0a10 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -106,10 +106,10 @@ enum ispif_intf_cmd { }; static const u32 ispif_formats_8x16[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, @@ -126,10 +126,10 @@ static const u32 ispif_formats_8x16[] = { }; static const u32 ispif_formats_8x96[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, @@ -270,7 +270,7 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id) unsigned long time; u32 val; - if (vfe_id > (camss->vfe_num - 1)) { + if (vfe_id > camss->res->vfe_num - 1) { dev_err(camss->dev, "Error: asked reset for invalid VFE%d\n", vfe_id); return -ENOENT; @@ -829,8 +829,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) ispif_select_csid(ispif, intf, csid, vfe, 1); ispif_select_cid(ispif, intf, cid, vfe, 1); ispif_config_irq(ispif, intf, vfe, 1); - if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) + if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) ispif_config_pack(ispif, line->fmt[MSM_ISPIF_PAD_SINK].code, intf, cid, vfe, 1); @@ -847,8 +847,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) return ret; mutex_lock(&ispif->config_lock); - if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) + if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) ispif_config_pack(ispif, line->fmt[MSM_ISPIF_PAD_SINK].code, intf, cid, vfe, 0); @@ -911,7 +911,7 @@ static void ispif_try_format(struct ispif_line *line, /* If not found, use UYVY as default */ if (i >= line->nformats) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt->width = clamp_t(u32, fmt->width, 1, 8191); fmt->height = clamp_t(u32, fmt->height, 1, 8191); @@ -1078,7 +1078,7 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) .which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE, .format = { - .code = MEDIA_BUS_FMT_UYVY8_2X8, + .code = MEDIA_BUS_FMT_UYVY8_1X16, .width = 1920, .height = 1080 } @@ -1095,7 +1095,7 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) * Return 0 on success or a negative error code otherwise */ int msm_ispif_subdev_init(struct camss *camss, - const struct resources_ispif *res) + const struct camss_subdev_resources *res) { struct device *dev = camss->dev; struct ispif_device *ispif = camss->ispif; @@ -1109,10 +1109,10 @@ int msm_ispif_subdev_init(struct camss *camss, ispif->camss = camss; /* Number of ISPIF lines - same as number of CSID hardware modules */ - if (camss->version == CAMSS_8x16) + if (camss->res->version == CAMSS_8x16) ispif->line_num = 2; - else if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) + else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) ispif->line_num = 4; else return -EINVAL; @@ -1126,12 +1126,12 @@ int msm_ispif_subdev_init(struct camss *camss, ispif->line[i].ispif = ispif; ispif->line[i].id = i; - if (camss->version == CAMSS_8x16) { + if (camss->res->version == CAMSS_8x16) { ispif->line[i].formats = ispif_formats_8x16; ispif->line[i].nformats = ARRAY_SIZE(ispif_formats_8x16); - } else if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) { + } else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) { ispif->line[i].formats = ispif_formats_8x96; ispif->line[i].nformats = ARRAY_SIZE(ispif_formats_8x96); @@ -1152,18 +1152,18 @@ int msm_ispif_subdev_init(struct camss *camss, /* Interrupt */ - ret = platform_get_irq_byname(pdev, res->interrupt); + ret = platform_get_irq_byname(pdev, res->interrupt[0]); if (ret < 0) return ret; ispif->irq = ret; snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s", dev_name(dev), MSM_ISPIF_NAME); - if (camss->version == CAMSS_8x16) + if (camss->res->version == CAMSS_8x16) ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); - else if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) + else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_660) ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); else diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h index fdf28e68cc..dff6d5b35c 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.h +++ b/drivers/media/platform/qcom/camss/camss-ispif.h @@ -66,10 +66,10 @@ struct ispif_device { struct camss *camss; }; -struct resources_ispif; +struct camss_subdev_resources; int msm_ispif_subdev_init(struct camss *camss, - const struct resources_ispif *res); + const struct camss_subdev_resources *res); int msm_ispif_register_entities(struct ispif_device *ispif, struct v4l2_device *v4l2_dev); diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c index 168baaa80d..0b211fed12 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -209,7 +209,8 @@ static void vfe_global_reset(struct vfe_device *vfe) GLOBAL_RESET_CMD_IDLE_CGC | GLOBAL_RESET_CMD_RDI0 | GLOBAL_RESET_CMD_RDI1 | - GLOBAL_RESET_CMD_RDI2; + GLOBAL_RESET_CMD_RDI2 | + GLOBAL_RESET_CMD_RDI3; writel_relaxed(BIT(31), vfe->base + VFE_IRQ_MASK_0); @@ -343,7 +344,7 @@ static void vfe_violation_read(struct vfe_device *vfe) static irqreturn_t vfe_isr(int irq, void *dev) { struct vfe_device *vfe = dev; - u32 status0, status1, vfe_bus_status[3]; + u32 status0, status1, vfe_bus_status[VFE_LINE_NUM_MAX]; int i, wm; status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0); @@ -352,7 +353,7 @@ static irqreturn_t vfe_isr(int irq, void *dev) writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0); writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1); - for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) { + for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) { vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i)); writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i)); } @@ -366,11 +367,11 @@ static irqreturn_t vfe_isr(int irq, void *dev) if (status0 & STATUS_0_RESET_ACK) vfe->isr_ops.reset_ack(vfe); - for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) + for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) if (status0 & STATUS_0_RDI_REG_UPDATE(i)) vfe->isr_ops.reg_update(vfe, i); - for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) + for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) if (status0 & STATUS_1_RDI_SOF(i)) vfe->isr_ops.sof(vfe, i); @@ -493,22 +494,6 @@ static int vfe_enable_output(struct vfe_line *line) return 0; } -static void vfe_disable_output(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - struct vfe_output *output = &line->output; - unsigned long flags; - unsigned int i; - - spin_lock_irqsave(&vfe->output_lock, flags); - for (i = 0; i < output->wm_num; i++) - vfe_wm_stop(vfe, output->wm_idx[i]); - output->gen2.active_num = 0; - spin_unlock_irqrestore(&vfe->output_lock, flags); - - vfe_reset(vfe); -} - /* * vfe_enable - Enable streaming on VFE line * @line: VFE line @@ -555,29 +540,6 @@ error_get_output: } /* - * vfe_disable - Disable streaming on VFE line - * @line: VFE line - * - * Return 0 on success or a negative error code otherwise - */ -static int vfe_disable(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - - vfe_disable_output(line); - - vfe_put_output(line); - - mutex_lock(&vfe->stream_lock); - - vfe->stream_count--; - - mutex_unlock(&vfe->stream_lock); - - return 0; -} - -/* * vfe_isr_sof - Process start of frame interrupt * @vfe: VFE Device * @line_id: VFE line @@ -673,7 +635,7 @@ static void vfe_pm_domain_off(struct vfe_device *vfe) { struct camss *camss = vfe->camss; - if (vfe->id >= camss->vfe_num) + if (vfe->id >= camss->res->vfe_num) return; device_link_del(camss->genpd_link[vfe->id]); @@ -688,7 +650,7 @@ static int vfe_pm_domain_on(struct vfe_device *vfe) struct camss *camss = vfe->camss; enum vfe_line_id id = vfe->id; - if (id >= camss->vfe_num) + if (id >= camss->res->vfe_num) return 0; camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], @@ -753,8 +715,6 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) { vfe->isr_ops = vfe_isr_ops_170; vfe->video_ops = vfe_video_ops_170; - - vfe->line_num = VFE_LINE_NUM_GEN2; } const struct vfe_hw_ops vfe_ops_170 = { @@ -771,4 +731,5 @@ const struct vfe_hw_ops vfe_ops_170 = { .vfe_enable = vfe_enable, .vfe_halt = vfe_halt, .violation_read = vfe_violation_read, + .vfe_wm_stop = vfe_wm_stop, }; diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c index 42047b11ba..2911e4126e 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -614,20 +614,20 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line) writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1); switch (line->fmt[MSM_VFE_PAD_SINK].code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV; break; - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU; break; - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: default: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY; break; - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY; break; @@ -775,17 +775,17 @@ static void vfe_set_camif_cfg(struct vfe_device *vfe, struct vfe_line *line) u32 val; switch (line->fmt[MSM_VFE_PAD_SINK].code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR; break; - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB; break; - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: default: val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY; break; - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY; break; } @@ -992,8 +992,6 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) vfe->isr_ops = vfe_isr_ops_gen1; vfe->ops_gen1 = &vfe_ops_gen1_4_1; vfe->video_ops = vfe_video_ops_gen1; - - vfe->line_num = VFE_LINE_NUM_GEN1; } const struct vfe_hw_ops vfe_ops_4_1 = { diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index ab2d57bdf5..b65ed0fef5 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -768,20 +768,20 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line) writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1); switch (line->fmt[MSM_VFE_PAD_SINK].code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV; break; - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU; break; - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: default: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY; break; - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY; break; @@ -941,17 +941,17 @@ static void vfe_set_camif_cfg(struct vfe_device *vfe, struct vfe_line *line) u32 val; switch (line->fmt[MSM_VFE_PAD_SINK].code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR; break; - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB; break; - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: default: val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY; break; - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY; break; } @@ -1188,8 +1188,6 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) vfe->isr_ops = vfe_isr_ops_gen1; vfe->ops_gen1 = &vfe_ops_gen1_4_7; vfe->video_ops = vfe_video_ops_gen1; - - vfe->line_num = VFE_LINE_NUM_GEN1; } const struct vfe_hw_ops vfe_ops_4_7 = { diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c index 7e6b62c930..7b3805177f 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c @@ -739,20 +739,20 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line) writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1); switch (line->fmt[MSM_VFE_PAD_SINK].code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV; break; - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU; break; - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: default: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY; break; - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY; odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY; break; @@ -873,17 +873,17 @@ static void vfe_set_camif_cfg(struct vfe_device *vfe, struct vfe_line *line) u32 val; switch (line->fmt[MSM_VFE_PAD_SINK].code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR; break; - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB; break; - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: default: val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY; break; - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY; break; } @@ -1173,8 +1173,6 @@ static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) vfe->isr_ops = vfe_isr_ops_gen1; vfe->ops_gen1 = &vfe_ops_gen1_4_8; vfe->video_ops = vfe_video_ops_gen1; - - vfe->line_num = VFE_LINE_NUM_GEN1; } const struct vfe_hw_ops vfe_ops_4_8 = { diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c index 8ddb801643..f2368b77fc 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-480.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c @@ -327,22 +327,6 @@ static int vfe_enable_output(struct vfe_line *line) return 0; } -static void vfe_disable_output(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - struct vfe_output *output = &line->output; - unsigned long flags; - unsigned int i; - - spin_lock_irqsave(&vfe->output_lock, flags); - for (i = 0; i < output->wm_num; i++) - vfe_wm_stop(vfe, output->wm_idx[i]); - output->gen2.active_num = 0; - spin_unlock_irqrestore(&vfe->output_lock, flags); - - vfe_reset(vfe); -} - /* * vfe_enable - Enable streaming on VFE line * @line: VFE line @@ -391,29 +375,6 @@ error_get_output: } /* - * vfe_disable - Disable streaming on VFE line - * @line: VFE line - * - * Return 0 on success or a negative error code otherwise - */ -static int vfe_disable(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - - vfe_disable_output(line); - - vfe_put_output(line); - - mutex_lock(&vfe->stream_lock); - - vfe->stream_count--; - - mutex_unlock(&vfe->stream_lock); - - return 0; -} - -/* * vfe_isr_reg_update - Process reg update interrupt * @vfe: VFE Device * @line_id: VFE line @@ -499,7 +460,7 @@ static void vfe_pm_domain_off(struct vfe_device *vfe) { struct camss *camss = vfe->camss; - if (vfe->id >= camss->vfe_num) + if (vfe->id >= camss->res->vfe_num) return; device_link_del(camss->genpd_link[vfe->id]); @@ -514,7 +475,7 @@ static int vfe_pm_domain_on(struct vfe_device *vfe) struct camss *camss = vfe->camss; enum vfe_line_id id = vfe->id; - if (id >= camss->vfe_num) + if (id >= camss->res->vfe_num) return 0; camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], @@ -569,7 +530,6 @@ static const struct camss_video_ops vfe_video_ops_480 = { static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) { vfe->video_ops = vfe_video_ops_480; - vfe->line_num = MAX_VFE_OUTPUT_LINES; } const struct vfe_hw_ops vfe_ops_480 = { @@ -582,4 +542,5 @@ const struct vfe_hw_ops vfe_ops_480 = { .vfe_disable = vfe_disable, .vfe_enable = vfe_enable, .vfe_halt = vfe_halt, + .vfe_wm_stop = vfe_wm_stop, }; diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 965500b83d..4839e2cedf 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -37,10 +37,10 @@ struct vfe_format { }; static const struct vfe_format formats_rdi_8x16[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, @@ -57,17 +57,17 @@ static const struct vfe_format formats_rdi_8x16[] = { }; static const struct vfe_format formats_pix_8x16[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, }; static const struct vfe_format formats_rdi_8x96[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, @@ -90,17 +90,17 @@ static const struct vfe_format formats_rdi_8x96[] = { }; static const struct vfe_format formats_pix_8x96[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, }; static const struct vfe_format formats_rdi_845[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, - { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, - { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, - { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, + { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, + { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, + { MEDIA_BUS_FMT_YVYU8_1X16, 8 }, { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, @@ -170,42 +170,43 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, { struct vfe_device *vfe = to_vfe(line); - if (vfe->camss->version == CAMSS_8x16) + switch (vfe->camss->res->version) { + case CAMSS_8x16: switch (sink_code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1_5X8, }; return vfe_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_YVYU8_1X16, MEDIA_BUS_FMT_YVYU8_1_5X8, }; return vfe_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1_5X8, }; return vfe_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_VYUY8_1X16, MEDIA_BUS_FMT_VYUY8_1_5X8, }; @@ -218,57 +219,58 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, return sink_code; } - else if (vfe->camss->version == CAMSS_8x96 || - vfe->camss->version == CAMSS_660 || - vfe->camss->version == CAMSS_845 || - vfe->camss->version == CAMSS_8250) + break; + case CAMSS_8x96: + case CAMSS_660: + case CAMSS_845: + case CAMSS_8250: switch (sink_code) { - case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, MEDIA_BUS_FMT_YUYV8_1_5X8, }; return vfe_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } - case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YVYU8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_YVYU8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, MEDIA_BUS_FMT_YVYU8_1_5X8, }; return vfe_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } - case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, MEDIA_BUS_FMT_UYVY8_1_5X8, }; return vfe_find_code(src_code, ARRAY_SIZE(src_code), index, src_req_code); } - case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: { u32 src_code[] = { - MEDIA_BUS_FMT_VYUY8_2X8, - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_VYUY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, + MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_VYUY8_1_5X8, }; @@ -281,8 +283,9 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, return sink_code; } - else - return 0; + break; + } + return 0; } int vfe_reset(struct vfe_device *vfe) @@ -407,6 +410,49 @@ int vfe_put_output(struct vfe_line *line) return 0; } +static int vfe_disable_output(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + struct vfe_output *output = &line->output; + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&vfe->output_lock, flags); + for (i = 0; i < output->wm_num; i++) + vfe->ops->vfe_wm_stop(vfe, output->wm_idx[i]); + output->gen2.active_num = 0; + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return vfe_reset(vfe); +} + +/* + * vfe_disable - Disable streaming on VFE line + * @line: VFE line + * + * Return 0 on success or a negative error code otherwise + */ +int vfe_disable(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + int ret; + + ret = vfe_disable_output(line); + if (ret) + goto error; + + vfe_put_output(line); + + mutex_lock(&vfe->stream_lock); + + vfe->stream_count--; + + mutex_unlock(&vfe->stream_lock); + +error: + return ret; +} + /** * vfe_isr_comp_done() - Process composite image done interrupt * @vfe: VFE Device @@ -428,6 +474,20 @@ void vfe_isr_reset_ack(struct vfe_device *vfe) complete(&vfe->reset_complete); } +static int vfe_match_clock_names(struct vfe_device *vfe, + struct camss_clock *clock) +{ + char vfe_name[7]; /* vfeXXX\0 */ + char vfe_lite_name[12]; /* vfe_liteXXX\0 */ + + snprintf(vfe_name, sizeof(vfe_name), "vfe%d", vfe->id); + snprintf(vfe_lite_name, sizeof(vfe_lite_name), "vfe_lite%d", vfe->id); + + return (!strcmp(clock->name, vfe_name) || + !strcmp(clock->name, vfe_lite_name) || + !strcmp(clock->name, "vfe_lite")); +} + /* * vfe_set_clock_rates - Calculate and set clock rates on VFE module * @vfe: VFE device @@ -451,9 +511,7 @@ static int vfe_set_clock_rates(struct vfe_device *vfe) for (i = 0; i < vfe->nclocks; i++) { struct camss_clock *clock = &vfe->clock[i]; - if (!strcmp(clock->name, "vfe0") || - !strcmp(clock->name, "vfe1") || - !strcmp(clock->name, "vfe_lite")) { + if (vfe_match_clock_names(vfe, clock)) { u64 min_rate = 0; long rate; @@ -534,9 +592,7 @@ static int vfe_check_clock_rates(struct vfe_device *vfe) for (i = 0; i < vfe->nclocks; i++) { struct camss_clock *clock = &vfe->clock[i]; - if (!strcmp(clock->name, "vfe0") || - !strcmp(clock->name, "vfe1") || - !strcmp(clock->name, "vfe_lite")) { + if (vfe_match_clock_names(vfe, clock)) { u64 min_rate = 0; unsigned long rate; @@ -845,7 +901,7 @@ static void vfe_try_format(struct vfe_line *line, /* If not found, use UYVY as default */ if (i >= line->nformats) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt->width = clamp_t(u32, fmt->width, 1, 8191); fmt->height = clamp_t(u32, fmt->height, 1, 8191); @@ -1262,7 +1318,7 @@ static int vfe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) .which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE, .format = { - .code = MEDIA_BUS_FMT_UYVY8_2X8, + .code = MEDIA_BUS_FMT_UYVY8_1X16, .width = 1920, .height = 1080 } @@ -1279,32 +1335,19 @@ static int vfe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) * Return 0 on success or a negative error code otherwise */ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, - const struct resources *res, u8 id) + const struct camss_subdev_resources *res, u8 id) { struct device *dev = camss->dev; struct platform_device *pdev = to_platform_device(dev); int i, j; int ret; - switch (camss->version) { - case CAMSS_8x16: - vfe->ops = &vfe_ops_4_1; - break; - case CAMSS_8x96: - vfe->ops = &vfe_ops_4_7; - break; - case CAMSS_660: - vfe->ops = &vfe_ops_4_8; - break; - case CAMSS_845: - vfe->ops = &vfe_ops_170; - break; - case CAMSS_8250: - vfe->ops = &vfe_ops_480; - break; - default: + vfe->ops = res->ops; + + if (!res->line_num) return -EINVAL; - } + + vfe->line_num = res->line_num; vfe->ops->subdev_init(dev, vfe); /* Memory */ @@ -1392,7 +1435,8 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, init_completion(&l->output.sof); init_completion(&l->output.reg_update); - if (camss->version == CAMSS_8x16) { + switch (camss->res->version) { + case CAMSS_8x16: if (i == VFE_LINE_PIX) { l->formats = formats_pix_8x16; l->nformats = ARRAY_SIZE(formats_pix_8x16); @@ -1400,8 +1444,9 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, l->formats = formats_rdi_8x16; l->nformats = ARRAY_SIZE(formats_rdi_8x16); } - } else if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) { + break; + case CAMSS_8x96: + case CAMSS_660: if (i == VFE_LINE_PIX) { l->formats = formats_pix_8x96; l->nformats = ARRAY_SIZE(formats_pix_8x96); @@ -1409,12 +1454,12 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, l->formats = formats_rdi_8x96; l->nformats = ARRAY_SIZE(formats_rdi_8x96); } - } else if (camss->version == CAMSS_845 || - camss->version == CAMSS_8250) { + break; + case CAMSS_845: + case CAMSS_8250: l->formats = formats_rdi_845; l->nformats = ARRAY_SIZE(formats_rdi_845); - } else { - return -EINVAL; + break; } } @@ -1542,8 +1587,8 @@ int msm_vfe_register_entities(struct vfe_device *vfe, } video_out->ops = &vfe->video_ops; - if (vfe->camss->version == CAMSS_845 || - vfe->camss->version == CAMSS_8250) + if (vfe->camss->res->version == CAMSS_845 || + vfe->camss->res->version == CAMSS_8250) video_out->bpl_alignment = 16; else video_out->bpl_alignment = 8; diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index cbc314c4e2..09baded0dc 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -52,9 +52,7 @@ enum vfe_line_id { VFE_LINE_RDI0 = 0, VFE_LINE_RDI1 = 1, VFE_LINE_RDI2 = 2, - VFE_LINE_NUM_GEN2 = 3, VFE_LINE_PIX = 3, - VFE_LINE_NUM_GEN1 = 4, VFE_LINE_NUM_MAX = 4 }; @@ -116,6 +114,7 @@ struct vfe_hw_ops { int (*vfe_enable)(struct vfe_line *line); int (*vfe_halt)(struct vfe_device *vfe); void (*violation_read)(struct vfe_device *vfe); + void (*vfe_wm_stop)(struct vfe_device *vfe, u8 wm); }; struct vfe_isr_ops { @@ -153,10 +152,10 @@ struct vfe_device { struct camss_video_ops video_ops; }; -struct resources; +struct camss_subdev_resources; int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, - const struct resources *res, u8 id); + const struct camss_subdev_resources *res, u8 id); int msm_vfe_register_entities(struct vfe_device *vfe, struct v4l2_device *v4l2_dev); @@ -194,6 +193,14 @@ int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id); */ int vfe_reset(struct vfe_device *vfe); +/* + * vfe_disable - Disable streaming on VFE line + * @line: VFE line + * + * Return 0 on success or a negative error code otherwise + */ +int vfe_disable(struct vfe_line *line); + extern const struct vfe_hw_ops vfe_ops_4_1; extern const struct vfe_hw_ops vfe_ops_4_7; extern const struct vfe_hw_ops vfe_ops_4_8; diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 8640db3060..a89da5ef47 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -48,13 +48,13 @@ struct camss_format_info { }; static const struct camss_format_info formats_rdi_8x16[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, { { 1, 1 } }, { { 1, 1 } }, { 8 } }, @@ -85,13 +85,13 @@ static const struct camss_format_info formats_rdi_8x16[] = { }; static const struct camss_format_info formats_rdi_8x96[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, { { 1, 1 } }, { { 1, 1 } }, { 8 } }, @@ -134,13 +134,13 @@ static const struct camss_format_info formats_rdi_8x96[] = { }; static const struct camss_format_info formats_rdi_845[] = { - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, { { 1, 1 } }, { { 1, 1 } }, { 8 } }, @@ -201,21 +201,21 @@ static const struct camss_format_info formats_pix_8x16[] = { { { 1, 1 } }, { { 2, 3 } }, { 8 } }, { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1, { { 1, 1 } }, { { 2, 3 } }, { 8 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, }; @@ -236,29 +236,29 @@ static const struct camss_format_info formats_pix_8x96[] = { { { 1, 1 } }, { { 2, 3 } }, { 8 } }, { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1, { { 1, 1 } }, { { 2, 3 } }, { 8 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV16, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV61, 1, { { 1, 1 } }, { { 1, 2 } }, { 8 } }, - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, - { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, + { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1, { { 1, 1 } }, { { 1, 1 } }, { 16 } }, }; @@ -1006,7 +1006,8 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, mutex_init(&video->lock); - if (video->camss->version == CAMSS_8x16) { + switch (video->camss->res->version) { + case CAMSS_8x16: if (is_pix) { video->formats = formats_pix_8x16; video->nformats = ARRAY_SIZE(formats_pix_8x16); @@ -1014,8 +1015,9 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, video->formats = formats_rdi_8x16; video->nformats = ARRAY_SIZE(formats_rdi_8x16); } - } else if (video->camss->version == CAMSS_8x96 || - video->camss->version == CAMSS_660) { + break; + case CAMSS_8x96: + case CAMSS_660: if (is_pix) { video->formats = formats_pix_8x96; video->nformats = ARRAY_SIZE(formats_pix_8x96); @@ -1023,13 +1025,12 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, video->formats = formats_rdi_8x96; video->nformats = ARRAY_SIZE(formats_rdi_8x96); } - } else if (video->camss->version == CAMSS_845 || - video->camss->version == CAMSS_8250) { + break; + case CAMSS_845: + case CAMSS_8250: video->formats = formats_rdi_845; video->nformats = ARRAY_SIZE(formats_rdi_845); - } else { - ret = -EINVAL; - goto error_video_register; + break; } ret = msm_video_init_format(video); diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index c6df862c79..8e78dd8d59 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_graph.h> #include <linux/pm_runtime.h> #include <linux/pm_domain.h> @@ -31,7 +32,7 @@ #define CAMSS_CLOCK_MARGIN_NUMERATOR 105 #define CAMSS_CLOCK_MARGIN_DENOMINATOR 100 -static const struct resources csiphy_res_8x16[] = { +static const struct camss_subdev_resources csiphy_res_8x16[] = { /* CSIPHY0 */ { .regulators = {}, @@ -41,7 +42,8 @@ static const struct resources csiphy_res_8x16[] = { { 0 }, { 100000000, 200000000 } }, .reg = { "csiphy0", "csiphy0_clk_mux" }, - .interrupt = { "csiphy0" } + .interrupt = { "csiphy0" }, + .ops = &csiphy_ops_2ph_1_0 }, /* CSIPHY1 */ @@ -53,11 +55,12 @@ static const struct resources csiphy_res_8x16[] = { { 0 }, { 100000000, 200000000 } }, .reg = { "csiphy1", "csiphy1_clk_mux" }, - .interrupt = { "csiphy1" } + .interrupt = { "csiphy1" }, + .ops = &csiphy_ops_2ph_1_0 } }; -static const struct resources csid_res_8x16[] = { +static const struct camss_subdev_resources csid_res_8x16[] = { /* CSID0 */ { .regulators = { "vdda" }, @@ -72,7 +75,8 @@ static const struct resources csid_res_8x16[] = { { 0 }, { 0 } }, .reg = { "csid0" }, - .interrupt = { "csid0" } + .interrupt = { "csid0" }, + .ops = &csid_ops_4_1, }, /* CSID1 */ @@ -89,22 +93,23 @@ static const struct resources csid_res_8x16[] = { { 0 }, { 0 } }, .reg = { "csid1" }, - .interrupt = { "csid1" } + .interrupt = { "csid1" }, + .ops = &csid_ops_4_1, }, }; -static const struct resources_ispif ispif_res_8x16 = { +static const struct camss_subdev_resources ispif_res_8x16 = { /* ISPIF */ .clock = { "top_ahb", "ahb", "ispif_ahb", "csi0", "csi0_pix", "csi0_rdi", "csi1", "csi1_pix", "csi1_rdi" }, .clock_for_reset = { "vfe0", "csi_vfe0" }, .reg = { "ispif", "csi_clk_mux" }, - .interrupt = "ispif" + .interrupt = { "ispif" } }; -static const struct resources vfe_res_8x16[] = { +static const struct camss_subdev_resources vfe_res_8x16[] = { /* VFE0 */ { .regulators = {}, @@ -122,11 +127,13 @@ static const struct resources vfe_res_8x16[] = { { 0 }, { 0 } }, .reg = { "vfe0" }, - .interrupt = { "vfe0" } + .interrupt = { "vfe0" }, + .line_num = 3, + .ops = &vfe_ops_4_1 } }; -static const struct resources csiphy_res_8x96[] = { +static const struct camss_subdev_resources csiphy_res_8x96[] = { /* CSIPHY0 */ { .regulators = {}, @@ -136,7 +143,8 @@ static const struct resources csiphy_res_8x96[] = { { 0 }, { 100000000, 200000000, 266666667 } }, .reg = { "csiphy0", "csiphy0_clk_mux" }, - .interrupt = { "csiphy0" } + .interrupt = { "csiphy0" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY1 */ @@ -148,7 +156,8 @@ static const struct resources csiphy_res_8x96[] = { { 0 }, { 100000000, 200000000, 266666667 } }, .reg = { "csiphy1", "csiphy1_clk_mux" }, - .interrupt = { "csiphy1" } + .interrupt = { "csiphy1" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY2 */ @@ -160,11 +169,12 @@ static const struct resources csiphy_res_8x96[] = { { 0 }, { 100000000, 200000000, 266666667 } }, .reg = { "csiphy2", "csiphy2_clk_mux" }, - .interrupt = { "csiphy2" } + .interrupt = { "csiphy2" }, + .ops = &csiphy_ops_3ph_1_0 } }; -static const struct resources csid_res_8x96[] = { +static const struct camss_subdev_resources csid_res_8x96[] = { /* CSID0 */ { .regulators = { "vdda" }, @@ -179,7 +189,8 @@ static const struct resources csid_res_8x96[] = { { 0 }, { 0 } }, .reg = { "csid0" }, - .interrupt = { "csid0" } + .interrupt = { "csid0" }, + .ops = &csid_ops_4_7, }, /* CSID1 */ @@ -196,7 +207,8 @@ static const struct resources csid_res_8x96[] = { { 0 }, { 0 } }, .reg = { "csid1" }, - .interrupt = { "csid1" } + .interrupt = { "csid1" }, + .ops = &csid_ops_4_7, }, /* CSID2 */ @@ -213,7 +225,8 @@ static const struct resources csid_res_8x96[] = { { 0 }, { 0 } }, .reg = { "csid2" }, - .interrupt = { "csid2" } + .interrupt = { "csid2" }, + .ops = &csid_ops_4_7, }, /* CSID3 */ @@ -230,11 +243,12 @@ static const struct resources csid_res_8x96[] = { { 0 }, { 0 } }, .reg = { "csid3" }, - .interrupt = { "csid3" } + .interrupt = { "csid3" }, + .ops = &csid_ops_4_7, } }; -static const struct resources_ispif ispif_res_8x96 = { +static const struct camss_subdev_resources ispif_res_8x96 = { /* ISPIF */ .clock = { "top_ahb", "ahb", "ispif_ahb", "csi0", "csi0_pix", "csi0_rdi", @@ -243,10 +257,10 @@ static const struct resources_ispif ispif_res_8x96 = { "csi3", "csi3_pix", "csi3_rdi" }, .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" }, .reg = { "ispif", "csi_clk_mux" }, - .interrupt = "ispif" + .interrupt = { "ispif" } }; -static const struct resources vfe_res_8x96[] = { +static const struct camss_subdev_resources vfe_res_8x96[] = { /* VFE0 */ { .regulators = {}, @@ -262,7 +276,9 @@ static const struct resources vfe_res_8x96[] = { { 0 }, { 0 } }, .reg = { "vfe0" }, - .interrupt = { "vfe0" } + .interrupt = { "vfe0" }, + .line_num = 3, + .ops = &vfe_ops_4_7 }, /* VFE1 */ @@ -280,11 +296,13 @@ static const struct resources vfe_res_8x96[] = { { 0 }, { 0 } }, .reg = { "vfe1" }, - .interrupt = { "vfe1" } + .interrupt = { "vfe1" }, + .line_num = 3, + .ops = &vfe_ops_4_7 } }; -static const struct resources csiphy_res_660[] = { +static const struct camss_subdev_resources csiphy_res_660[] = { /* CSIPHY0 */ { .regulators = {}, @@ -296,7 +314,8 @@ static const struct resources csiphy_res_660[] = { { 100000000, 200000000, 269333333 }, { 0 } }, .reg = { "csiphy0", "csiphy0_clk_mux" }, - .interrupt = { "csiphy0" } + .interrupt = { "csiphy0" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY1 */ @@ -310,7 +329,8 @@ static const struct resources csiphy_res_660[] = { { 100000000, 200000000, 269333333 }, { 0 } }, .reg = { "csiphy1", "csiphy1_clk_mux" }, - .interrupt = { "csiphy1" } + .interrupt = { "csiphy1" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY2 */ @@ -324,11 +344,12 @@ static const struct resources csiphy_res_660[] = { { 100000000, 200000000, 269333333 }, { 0 } }, .reg = { "csiphy2", "csiphy2_clk_mux" }, - .interrupt = { "csiphy2" } + .interrupt = { "csiphy2" }, + .ops = &csiphy_ops_3ph_1_0 } }; -static const struct resources csid_res_660[] = { +static const struct camss_subdev_resources csid_res_660[] = { /* CSID0 */ { .regulators = { "vdda", "vdd_sec" }, @@ -346,7 +367,8 @@ static const struct resources csid_res_660[] = { { 0 }, { 0 } }, .reg = { "csid0" }, - .interrupt = { "csid0" } + .interrupt = { "csid0" }, + .ops = &csid_ops_4_7, }, /* CSID1 */ @@ -366,7 +388,8 @@ static const struct resources csid_res_660[] = { { 0 }, { 0 } }, .reg = { "csid1" }, - .interrupt = { "csid1" } + .interrupt = { "csid1" }, + .ops = &csid_ops_4_7, }, /* CSID2 */ @@ -386,7 +409,8 @@ static const struct resources csid_res_660[] = { { 0 }, { 0 } }, .reg = { "csid2" }, - .interrupt = { "csid2" } + .interrupt = { "csid2" }, + .ops = &csid_ops_4_7, }, /* CSID3 */ @@ -406,11 +430,12 @@ static const struct resources csid_res_660[] = { { 0 }, { 0 } }, .reg = { "csid3" }, - .interrupt = { "csid3" } + .interrupt = { "csid3" }, + .ops = &csid_ops_4_7, } }; -static const struct resources_ispif ispif_res_660 = { +static const struct camss_subdev_resources ispif_res_660 = { /* ISPIF */ .clock = { "top_ahb", "ahb", "ispif_ahb", "csi0", "csi0_pix", "csi0_rdi", @@ -419,10 +444,10 @@ static const struct resources_ispif ispif_res_660 = { "csi3", "csi3_pix", "csi3_rdi" }, .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" }, .reg = { "ispif", "csi_clk_mux" }, - .interrupt = "ispif" + .interrupt = { "ispif" } }; -static const struct resources vfe_res_660[] = { +static const struct camss_subdev_resources vfe_res_660[] = { /* VFE0 */ { .regulators = {}, @@ -441,7 +466,9 @@ static const struct resources vfe_res_660[] = { { 0 }, { 0 } }, .reg = { "vfe0" }, - .interrupt = { "vfe0" } + .interrupt = { "vfe0" }, + .line_num = 3, + .ops = &vfe_ops_4_8 }, /* VFE1 */ @@ -462,11 +489,13 @@ static const struct resources vfe_res_660[] = { { 0 }, { 0 } }, .reg = { "vfe1" }, - .interrupt = { "vfe1" } + .interrupt = { "vfe1" }, + .line_num = 3, + .ops = &vfe_ops_4_8 } }; -static const struct resources csiphy_res_845[] = { +static const struct camss_subdev_resources csiphy_res_845[] = { /* CSIPHY0 */ { .regulators = {}, @@ -482,7 +511,8 @@ static const struct resources csiphy_res_845[] = { { 0 }, { 19200000, 240000000, 269333333 } }, .reg = { "csiphy0" }, - .interrupt = { "csiphy0" } + .interrupt = { "csiphy0" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY1 */ @@ -500,7 +530,8 @@ static const struct resources csiphy_res_845[] = { { 0 }, { 19200000, 240000000, 269333333 } }, .reg = { "csiphy1" }, - .interrupt = { "csiphy1" } + .interrupt = { "csiphy1" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY2 */ @@ -518,7 +549,8 @@ static const struct resources csiphy_res_845[] = { { 0 }, { 19200000, 240000000, 269333333 } }, .reg = { "csiphy2" }, - .interrupt = { "csiphy2" } + .interrupt = { "csiphy2" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY3 */ @@ -536,11 +568,12 @@ static const struct resources csiphy_res_845[] = { { 0 }, { 19200000, 240000000, 269333333 } }, .reg = { "csiphy3" }, - .interrupt = { "csiphy3" } + .interrupt = { "csiphy3" }, + .ops = &csiphy_ops_3ph_1_0 } }; -static const struct resources csid_res_845[] = { +static const struct camss_subdev_resources csid_res_845[] = { /* CSID0 */ { .regulators = { "vdda-phy", "vdda-pll" }, @@ -558,7 +591,8 @@ static const struct resources csid_res_845[] = { { 19200000, 75000000, 384000000, 538666667 }, { 384000000 } }, .reg = { "csid0" }, - .interrupt = { "csid0" } + .interrupt = { "csid0" }, + .ops = &csid_ops_gen2 }, /* CSID1 */ @@ -578,7 +612,8 @@ static const struct resources csid_res_845[] = { { 19200000, 75000000, 384000000, 538666667 }, { 384000000 } }, .reg = { "csid1" }, - .interrupt = { "csid1" } + .interrupt = { "csid1" }, + .ops = &csid_ops_gen2 }, /* CSID2 */ @@ -598,11 +633,12 @@ static const struct resources csid_res_845[] = { { 19200000, 75000000, 384000000, 538666667 }, { 384000000 } }, .reg = { "csid2" }, - .interrupt = { "csid2" } + .interrupt = { "csid2" }, + .ops = &csid_ops_gen2 } }; -static const struct resources vfe_res_845[] = { +static const struct camss_subdev_resources vfe_res_845[] = { /* VFE0 */ { .regulators = {}, @@ -620,7 +656,9 @@ static const struct resources vfe_res_845[] = { { 19200000, 75000000, 384000000, 538666667 }, { 384000000 } }, .reg = { "vfe0" }, - .interrupt = { "vfe0" } + .interrupt = { "vfe0" }, + .line_num = 4, + .ops = &vfe_ops_170 }, /* VFE1 */ @@ -640,7 +678,9 @@ static const struct resources vfe_res_845[] = { { 19200000, 75000000, 384000000, 538666667 }, { 384000000 } }, .reg = { "vfe1" }, - .interrupt = { "vfe1" } + .interrupt = { "vfe1" }, + .line_num = 4, + .ops = &vfe_ops_170 }, /* VFE-lite */ @@ -659,11 +699,13 @@ static const struct resources vfe_res_845[] = { { 19200000, 75000000, 384000000, 538666667 }, { 384000000 } }, .reg = { "vfe_lite" }, - .interrupt = { "vfe_lite" } + .interrupt = { "vfe_lite" }, + .line_num = 4, + .ops = &vfe_ops_170 } }; -static const struct resources csiphy_res_8250[] = { +static const struct camss_subdev_resources csiphy_res_8250[] = { /* CSIPHY0 */ { .regulators = {}, @@ -671,7 +713,8 @@ static const struct resources csiphy_res_8250[] = { .clock_rate = { { 400000000 }, { 300000000 } }, .reg = { "csiphy0" }, - .interrupt = { "csiphy0" } + .interrupt = { "csiphy0" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY1 */ { @@ -680,7 +723,8 @@ static const struct resources csiphy_res_8250[] = { .clock_rate = { { 400000000 }, { 300000000 } }, .reg = { "csiphy1" }, - .interrupt = { "csiphy1" } + .interrupt = { "csiphy1" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY2 */ { @@ -689,7 +733,8 @@ static const struct resources csiphy_res_8250[] = { .clock_rate = { { 400000000 }, { 300000000 } }, .reg = { "csiphy2" }, - .interrupt = { "csiphy2" } + .interrupt = { "csiphy2" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY3 */ { @@ -698,7 +743,8 @@ static const struct resources csiphy_res_8250[] = { .clock_rate = { { 400000000 }, { 300000000 } }, .reg = { "csiphy3" }, - .interrupt = { "csiphy3" } + .interrupt = { "csiphy3" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY4 */ { @@ -707,7 +753,8 @@ static const struct resources csiphy_res_8250[] = { .clock_rate = { { 400000000 }, { 300000000 } }, .reg = { "csiphy4" }, - .interrupt = { "csiphy4" } + .interrupt = { "csiphy4" }, + .ops = &csiphy_ops_3ph_1_0 }, /* CSIPHY5 */ { @@ -716,11 +763,12 @@ static const struct resources csiphy_res_8250[] = { .clock_rate = { { 400000000 }, { 300000000 } }, .reg = { "csiphy5" }, - .interrupt = { "csiphy5" } + .interrupt = { "csiphy5" }, + .ops = &csiphy_ops_3ph_1_0 } }; -static const struct resources csid_res_8250[] = { +static const struct camss_subdev_resources csid_res_8250[] = { /* CSID0 */ { .regulators = { "vdda-phy", "vdda-pll" }, @@ -731,7 +779,8 @@ static const struct resources csid_res_8250[] = { { 100000000, 200000000, 300000000, 400000000 }, { 0 } }, .reg = { "csid0" }, - .interrupt = { "csid0" } + .interrupt = { "csid0" }, + .ops = &csid_ops_gen2 }, /* CSID1 */ { @@ -743,7 +792,8 @@ static const struct resources csid_res_8250[] = { { 100000000, 200000000, 300000000, 400000000 }, { 0 } }, .reg = { "csid1" }, - .interrupt = { "csid1" } + .interrupt = { "csid1" }, + .ops = &csid_ops_gen2 }, /* CSID2 */ { @@ -754,7 +804,8 @@ static const struct resources csid_res_8250[] = { { 400000000, 480000000 }, { 0 } }, .reg = { "csid2" }, - .interrupt = { "csid2" } + .interrupt = { "csid2" }, + .ops = &csid_ops_gen2 }, /* CSID3 */ { @@ -765,11 +816,12 @@ static const struct resources csid_res_8250[] = { { 400000000, 480000000 }, { 0 } }, .reg = { "csid3" }, - .interrupt = { "csid3" } + .interrupt = { "csid3" }, + .ops = &csid_ops_gen2 } }; -static const struct resources vfe_res_8250[] = { +static const struct camss_subdev_resources vfe_res_8250[] = { /* VFE0 */ { .regulators = {}, @@ -786,7 +838,9 @@ static const struct resources vfe_res_8250[] = { { 0 }, { 0 } }, .reg = { "vfe0" }, - .interrupt = { "vfe0" } + .interrupt = { "vfe0" }, + .line_num = 3, + .ops = &vfe_ops_480 }, /* VFE1 */ { @@ -804,7 +858,9 @@ static const struct resources vfe_res_8250[] = { { 0 }, { 0 } }, .reg = { "vfe1" }, - .interrupt = { "vfe1" } + .interrupt = { "vfe1" }, + .line_num = 3, + .ops = &vfe_ops_480 }, /* VFE2 (lite) */ { @@ -821,7 +877,9 @@ static const struct resources vfe_res_8250[] = { { 400000000, 480000000 }, { 0 } }, .reg = { "vfe_lite0" }, - .interrupt = { "vfe_lite0" } + .interrupt = { "vfe_lite0" }, + .line_num = 4, + .ops = &vfe_ops_480 }, /* VFE3 (lite) */ { @@ -838,7 +896,9 @@ static const struct resources vfe_res_8250[] = { { 400000000, 480000000 }, { 0 } }, .reg = { "vfe_lite1" }, - .interrupt = { "vfe_lite1" } + .interrupt = { "vfe_lite1" }, + .line_num = 4, + .ops = &vfe_ops_480 }, }; @@ -1004,7 +1064,7 @@ int camss_pm_domain_on(struct camss *camss, int id) { int ret = 0; - if (id < camss->vfe_num) { + if (id < camss->res->vfe_num) { struct vfe_device *vfe = &camss->vfe[id]; ret = vfe->ops->pm_domain_on(vfe); @@ -1015,7 +1075,7 @@ int camss_pm_domain_on(struct camss *camss, int id) void camss_pm_domain_off(struct camss *camss, int id) { - if (id < camss->vfe_num) { + if (id < camss->res->vfe_num) { struct vfe_device *vfe = &camss->vfe[id]; vfe->ops->pm_domain_off(vfe); @@ -1120,47 +1180,13 @@ err_cleanup: */ static int camss_init_subdevices(struct camss *camss) { - const struct resources *csiphy_res; - const struct resources *csid_res; - const struct resources_ispif *ispif_res; - const struct resources *vfe_res; + const struct camss_resources *res = camss->res; unsigned int i; int ret; - if (camss->version == CAMSS_8x16) { - csiphy_res = csiphy_res_8x16; - csid_res = csid_res_8x16; - ispif_res = &ispif_res_8x16; - vfe_res = vfe_res_8x16; - } else if (camss->version == CAMSS_8x96) { - csiphy_res = csiphy_res_8x96; - csid_res = csid_res_8x96; - ispif_res = &ispif_res_8x96; - vfe_res = vfe_res_8x96; - } else if (camss->version == CAMSS_660) { - csiphy_res = csiphy_res_660; - csid_res = csid_res_660; - ispif_res = &ispif_res_660; - vfe_res = vfe_res_660; - } else if (camss->version == CAMSS_845) { - csiphy_res = csiphy_res_845; - csid_res = csid_res_845; - /* Titan VFEs don't have an ISPIF */ - ispif_res = NULL; - vfe_res = vfe_res_845; - } else if (camss->version == CAMSS_8250) { - csiphy_res = csiphy_res_8250; - csid_res = csid_res_8250; - /* Titan VFEs don't have an ISPIF */ - ispif_res = NULL; - vfe_res = vfe_res_8250; - } else { - return -EINVAL; - } - - for (i = 0; i < camss->csiphy_num; i++) { + for (i = 0; i < camss->res->csiphy_num; i++) { ret = msm_csiphy_subdev_init(camss, &camss->csiphy[i], - &csiphy_res[i], i); + &res->csiphy_res[i], i); if (ret < 0) { dev_err(camss->dev, "Failed to init csiphy%d sub-device: %d\n", @@ -1170,9 +1196,9 @@ static int camss_init_subdevices(struct camss *camss) } /* note: SM8250 requires VFE to be initialized before CSID */ - for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) { + for (i = 0; i < camss->vfe_total_num; i++) { ret = msm_vfe_subdev_init(camss, &camss->vfe[i], - &vfe_res[i], i); + &res->vfe_res[i], i); if (ret < 0) { dev_err(camss->dev, "Fail to init vfe%d sub-device: %d\n", i, ret); @@ -1180,9 +1206,9 @@ static int camss_init_subdevices(struct camss *camss) } } - for (i = 0; i < camss->csid_num; i++) { + for (i = 0; i < camss->res->csid_num; i++) { ret = msm_csid_subdev_init(camss, &camss->csid[i], - &csid_res[i], i); + &res->csid_res[i], i); if (ret < 0) { dev_err(camss->dev, "Failed to init csid%d sub-device: %d\n", @@ -1191,7 +1217,7 @@ static int camss_init_subdevices(struct camss *camss) } } - ret = msm_ispif_subdev_init(camss, ispif_res); + ret = msm_ispif_subdev_init(camss, res->ispif_res); if (ret < 0) { dev_err(camss->dev, "Failed to init ispif sub-device: %d\n", ret); @@ -1212,7 +1238,7 @@ static int camss_register_entities(struct camss *camss) int i, j, k; int ret; - for (i = 0; i < camss->csiphy_num; i++) { + for (i = 0; i < camss->res->csiphy_num; i++) { ret = msm_csiphy_register_entity(&camss->csiphy[i], &camss->v4l2_dev); if (ret < 0) { @@ -1223,7 +1249,7 @@ static int camss_register_entities(struct camss *camss) } } - for (i = 0; i < camss->csid_num; i++) { + for (i = 0; i < camss->res->csid_num; i++) { ret = msm_csid_register_entity(&camss->csid[i], &camss->v4l2_dev); if (ret < 0) { @@ -1242,7 +1268,7 @@ static int camss_register_entities(struct camss *camss) goto err_reg_ispif; } - for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) { + for (i = 0; i < camss->vfe_total_num; i++) { ret = msm_vfe_register_entities(&camss->vfe[i], &camss->v4l2_dev); if (ret < 0) { @@ -1253,8 +1279,8 @@ static int camss_register_entities(struct camss *camss) } } - for (i = 0; i < camss->csiphy_num; i++) { - for (j = 0; j < camss->csid_num; j++) { + for (i = 0; i < camss->res->csiphy_num; i++) { + for (j = 0; j < camss->res->csid_num; j++) { ret = media_create_pad_link( &camss->csiphy[i].subdev.entity, MSM_CSIPHY_PAD_SRC, @@ -1273,7 +1299,7 @@ static int camss_register_entities(struct camss *camss) } if (camss->ispif) { - for (i = 0; i < camss->csid_num; i++) { + for (i = 0; i < camss->res->csid_num; i++) { for (j = 0; j < camss->ispif->line_num; j++) { ret = media_create_pad_link( &camss->csid[i].subdev.entity, @@ -1293,7 +1319,7 @@ static int camss_register_entities(struct camss *camss) } for (i = 0; i < camss->ispif->line_num; i++) - for (k = 0; k < camss->vfe_num; k++) + for (k = 0; k < camss->res->vfe_num; k++) for (j = 0; j < camss->vfe[k].line_num; j++) { struct v4l2_subdev *ispif = &camss->ispif->line[i].subdev; struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev; @@ -1313,8 +1339,8 @@ static int camss_register_entities(struct camss *camss) } } } else { - for (i = 0; i < camss->csid_num; i++) - for (k = 0; k < camss->vfe_num + camss->vfe_lite_num; k++) + for (i = 0; i < camss->res->csid_num; i++) + for (k = 0; k < camss->vfe_total_num; k++) for (j = 0; j < camss->vfe[k].line_num; j++) { struct v4l2_subdev *csid = &camss->csid[i].subdev; struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev; @@ -1338,7 +1364,7 @@ static int camss_register_entities(struct camss *camss) return 0; err_link: - i = camss->vfe_num + camss->vfe_lite_num; + i = camss->vfe_total_num; err_reg_vfe: for (i--; i >= 0; i--) msm_vfe_unregister_entities(&camss->vfe[i]); @@ -1346,12 +1372,12 @@ err_reg_vfe: err_reg_ispif: msm_ispif_unregister_entities(camss->ispif); - i = camss->csid_num; + i = camss->res->csid_num; err_reg_csid: for (i--; i >= 0; i--) msm_csid_unregister_entity(&camss->csid[i]); - i = camss->csiphy_num; + i = camss->res->csiphy_num; err_reg_csiphy: for (i--; i >= 0; i--) msm_csiphy_unregister_entity(&camss->csiphy[i]); @@ -1369,15 +1395,15 @@ static void camss_unregister_entities(struct camss *camss) { unsigned int i; - for (i = 0; i < camss->csiphy_num; i++) + for (i = 0; i < camss->res->csiphy_num; i++) msm_csiphy_unregister_entity(&camss->csiphy[i]); - for (i = 0; i < camss->csid_num; i++) + for (i = 0; i < camss->res->csid_num; i++) msm_csid_unregister_entity(&camss->csid[i]); msm_ispif_unregister_entities(camss->ispif); - for (i = 0; i < camss->vfe_num + camss->vfe_lite_num; i++) + for (i = 0; i < camss->vfe_total_num; i++) msm_vfe_unregister_entities(&camss->vfe[i]); } @@ -1496,7 +1522,7 @@ static int camss_configure_pd(struct camss *camss) } } - if (i > camss->vfe_num) { + if (i > camss->res->vfe_num) { camss->genpd_link[i - 1] = device_link_add(camss->dev, camss->genpd[i - 1], DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); @@ -1518,21 +1544,15 @@ fail_pm: static int camss_icc_get(struct camss *camss) { const struct resources_icc *icc_res; - int nbr_icc_paths = 0; int i; - if (camss->version == CAMSS_8250) { - icc_res = &icc_res_sm8250[0]; - nbr_icc_paths = ICC_SM8250_COUNT; - } + icc_res = camss->res->icc_res; - for (i = 0; i < nbr_icc_paths; i++) { + for (i = 0; i < camss->res->icc_path_num; i++) { camss->icc_path[i] = devm_of_icc_get(camss->dev, icc_res[i].name); if (IS_ERR(camss->icc_path[i])) return PTR_ERR(camss->icc_path[i]); - - camss->icc_bw_tbl[i] = icc_res[i].icc_bw_tbl; } return 0; @@ -1545,7 +1565,7 @@ static void camss_genpd_cleanup(struct camss *camss) if (camss->genpd_num == 1) return; - if (camss->genpd_num > camss->vfe_num) + if (camss->genpd_num > camss->res->vfe_num) device_link_del(camss->genpd_link[camss->genpd_num - 1]); for (i = 0; i < camss->genpd_num; i++) @@ -1562,69 +1582,38 @@ static int camss_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct camss *camss; - int num_subdevs, ret; + int num_subdevs; + int ret; camss = devm_kzalloc(dev, sizeof(*camss), GFP_KERNEL); if (!camss) return -ENOMEM; + camss->res = of_device_get_match_data(dev); + atomic_set(&camss->ref_count, 0); camss->dev = dev; platform_set_drvdata(pdev, camss); - if (of_device_is_compatible(dev->of_node, "qcom,msm8916-camss")) { - camss->version = CAMSS_8x16; - camss->csiphy_num = 2; - camss->csid_num = 2; - camss->vfe_num = 1; - } else if (of_device_is_compatible(dev->of_node, - "qcom,msm8996-camss")) { - camss->version = CAMSS_8x96; - camss->csiphy_num = 3; - camss->csid_num = 4; - camss->vfe_num = 2; - } else if (of_device_is_compatible(dev->of_node, - "qcom,sdm660-camss")) { - camss->version = CAMSS_660; - camss->csiphy_num = 3; - camss->csid_num = 4; - camss->vfe_num = 2; - } else if (of_device_is_compatible(dev->of_node, - "qcom,sdm845-camss")) { - camss->version = CAMSS_845; - camss->csiphy_num = 4; - camss->csid_num = 3; - camss->vfe_num = 2; - camss->vfe_lite_num = 1; - } else if (of_device_is_compatible(dev->of_node, - "qcom,sm8250-camss")) { - camss->version = CAMSS_8250; - camss->csiphy_num = 6; - camss->csid_num = 4; - camss->vfe_num = 2; - camss->vfe_lite_num = 2; - } else { - return -EINVAL; - } - - camss->csiphy = devm_kcalloc(dev, camss->csiphy_num, + camss->csiphy = devm_kcalloc(dev, camss->res->csiphy_num, sizeof(*camss->csiphy), GFP_KERNEL); if (!camss->csiphy) return -ENOMEM; - camss->csid = devm_kcalloc(dev, camss->csid_num, sizeof(*camss->csid), + camss->csid = devm_kcalloc(dev, camss->res->csid_num, sizeof(*camss->csid), GFP_KERNEL); if (!camss->csid) return -ENOMEM; - if (camss->version == CAMSS_8x16 || - camss->version == CAMSS_8x96) { + if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x96) { camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL); if (!camss->ispif) return -ENOMEM; } - camss->vfe = devm_kcalloc(dev, camss->vfe_num + camss->vfe_lite_num, + camss->vfe_total_num = camss->res->vfe_num + camss->res->vfe_lite_num; + camss->vfe = devm_kcalloc(dev, camss->vfe_total_num, sizeof(*camss->vfe), GFP_KERNEL); if (!camss->vfe) return -ENOMEM; @@ -1742,12 +1731,69 @@ static void camss_remove(struct platform_device *pdev) camss_genpd_cleanup(camss); } +static const struct camss_resources msm8916_resources = { + .version = CAMSS_8x16, + .csiphy_res = csiphy_res_8x16, + .csid_res = csid_res_8x16, + .ispif_res = &ispif_res_8x16, + .vfe_res = vfe_res_8x16, + .csiphy_num = ARRAY_SIZE(csiphy_res_8x16), + .csid_num = ARRAY_SIZE(csid_res_8x16), + .vfe_num = ARRAY_SIZE(vfe_res_8x16), +}; + +static const struct camss_resources msm8996_resources = { + .version = CAMSS_8x96, + .csiphy_res = csiphy_res_8x96, + .csid_res = csid_res_8x96, + .ispif_res = &ispif_res_8x96, + .vfe_res = vfe_res_8x96, + .csiphy_num = ARRAY_SIZE(csiphy_res_8x96), + .csid_num = ARRAY_SIZE(csid_res_8x96), + .vfe_num = ARRAY_SIZE(vfe_res_8x96), +}; + +static const struct camss_resources sdm660_resources = { + .version = CAMSS_660, + .csiphy_res = csiphy_res_660, + .csid_res = csid_res_660, + .ispif_res = &ispif_res_660, + .vfe_res = vfe_res_660, + .csiphy_num = ARRAY_SIZE(csiphy_res_660), + .csid_num = ARRAY_SIZE(csid_res_660), + .vfe_num = ARRAY_SIZE(vfe_res_660), +}; + +static const struct camss_resources sdm845_resources = { + .version = CAMSS_845, + .csiphy_res = csiphy_res_845, + .csid_res = csid_res_845, + .vfe_res = vfe_res_845, + .csiphy_num = ARRAY_SIZE(csiphy_res_845), + .csid_num = ARRAY_SIZE(csid_res_845), + .vfe_num = 2, + .vfe_lite_num = 1, +}; + +static const struct camss_resources sm8250_resources = { + .version = CAMSS_8250, + .csiphy_res = csiphy_res_8250, + .csid_res = csid_res_8250, + .vfe_res = vfe_res_8250, + .icc_res = icc_res_sm8250, + .icc_path_num = ARRAY_SIZE(icc_res_sm8250), + .csiphy_num = ARRAY_SIZE(csiphy_res_8250), + .csid_num = ARRAY_SIZE(csid_res_8250), + .vfe_num = 2, + .vfe_lite_num = 2, +}; + static const struct of_device_id camss_dt_match[] = { - { .compatible = "qcom,msm8916-camss" }, - { .compatible = "qcom,msm8996-camss" }, - { .compatible = "qcom,sdm660-camss" }, - { .compatible = "qcom,sdm845-camss" }, - { .compatible = "qcom,sm8250-camss" }, + { .compatible = "qcom,msm8916-camss", .data = &msm8916_resources }, + { .compatible = "qcom,msm8996-camss", .data = &msm8996_resources }, + { .compatible = "qcom,sdm660-camss", .data = &sdm660_resources }, + { .compatible = "qcom,sdm845-camss", .data = &sdm845_resources }, + { .compatible = "qcom,sm8250-camss", .data = &sm8250_resources }, { } }; @@ -1756,14 +1802,10 @@ MODULE_DEVICE_TABLE(of, camss_dt_match); static int __maybe_unused camss_runtime_suspend(struct device *dev) { struct camss *camss = dev_get_drvdata(dev); - int nbr_icc_paths = 0; int i; int ret; - if (camss->version == CAMSS_8250) - nbr_icc_paths = ICC_SM8250_COUNT; - - for (i = 0; i < nbr_icc_paths; i++) { + for (i = 0; i < camss->res->icc_path_num; i++) { ret = icc_set_bw(camss->icc_path[i], 0, 0); if (ret) return ret; @@ -1775,17 +1817,14 @@ static int __maybe_unused camss_runtime_suspend(struct device *dev) static int __maybe_unused camss_runtime_resume(struct device *dev) { struct camss *camss = dev_get_drvdata(dev); - int nbr_icc_paths = 0; + const struct resources_icc *icc_res = camss->res->icc_res; int i; int ret; - if (camss->version == CAMSS_8250) - nbr_icc_paths = ICC_SM8250_COUNT; - - for (i = 0; i < nbr_icc_paths; i++) { + for (i = 0; i < camss->res->icc_path_num; i++) { ret = icc_set_bw(camss->icc_path[i], - camss->icc_bw_tbl[i].avg, - camss->icc_bw_tbl[i].peak); + icc_res[i].icc_bw_tbl.avg, + icc_res[i].icc_bw_tbl.peak); if (ret) return ret; } diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index f6c326cb85..8acad7321c 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -41,19 +41,15 @@ #define CAMSS_RES_MAX 17 -struct resources { +struct camss_subdev_resources { char *regulators[CAMSS_RES_MAX]; char *clock[CAMSS_RES_MAX]; + char *clock_for_reset[CAMSS_RES_MAX]; u32 clock_rate[CAMSS_RES_MAX][CAMSS_RES_MAX]; char *reg[CAMSS_RES_MAX]; char *interrupt[CAMSS_RES_MAX]; -}; - -struct resources_ispif { - char *clock[CAMSS_RES_MAX]; - char *clock_for_reset[CAMSS_RES_MAX]; - char *reg[CAMSS_RES_MAX]; - char *interrupt; + u8 line_num; + const void *ops; }; struct icc_bw_tbl { @@ -85,26 +81,36 @@ enum icc_count { ICC_SM8250_COUNT = 4, }; -struct camss { +struct camss_resources { enum camss_version version; + const struct camss_subdev_resources *csiphy_res; + const struct camss_subdev_resources *csid_res; + const struct camss_subdev_resources *ispif_res; + const struct camss_subdev_resources *vfe_res; + const struct resources_icc *icc_res; + const unsigned int icc_path_num; + const unsigned int csiphy_num; + const unsigned int csid_num; + const unsigned int vfe_num; + const unsigned int vfe_lite_num; +}; + +struct camss { struct v4l2_device v4l2_dev; struct v4l2_async_notifier notifier; struct media_device media_dev; struct device *dev; - int csiphy_num; struct csiphy_device *csiphy; - int csid_num; struct csid_device *csid; struct ispif_device *ispif; - int vfe_num; - int vfe_lite_num; struct vfe_device *vfe; atomic_t ref_count; int genpd_num; struct device **genpd; struct device_link **genpd_link; struct icc_path *icc_path[ICC_SM8250_COUNT]; - struct icc_bw_tbl icc_bw_tbl[ICC_SM8250_COUNT]; + const struct camss_resources *res; + unsigned int vfe_total_num; }; struct camss_camera_interface { diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 054b8e74ba..9cffe97558 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -549,7 +549,7 @@ static const struct venus_resources msm8916_res = { .vmem_size = 0, .vmem_addr = 0, .dma_mask = 0xddc00000 - 1, - .fwname = "qcom/venus-1.8/venus.mdt", + .fwname = "qcom/venus-1.8/venus.mbn", }; static const struct freq_tbl msm8996_freq_table[] = { @@ -582,7 +582,7 @@ static const struct venus_resources msm8996_res = { .vmem_size = 0, .vmem_addr = 0, .dma_mask = 0xddc00000 - 1, - .fwname = "qcom/venus-4.2/venus.mdt", + .fwname = "qcom/venus-4.2/venus.mbn", }; static const struct freq_tbl sdm660_freq_table[] = { @@ -690,7 +690,7 @@ static const struct venus_resources sdm845_res = { .vmem_size = 0, .vmem_addr = 0, .dma_mask = 0xe0000000 - 1, - .fwname = "qcom/venus-5.2/venus.mdt", + .fwname = "qcom/venus-5.2/venus.mbn", }; static const struct venus_resources sdm845_res_v2 = { @@ -720,7 +720,7 @@ static const struct venus_resources sdm845_res_v2 = { .cp_size = 0x70800000, .cp_nonpixel_start = 0x1000000, .cp_nonpixel_size = 0x24800000, - .fwname = "qcom/venus-5.2/venus.mdt", + .fwname = "qcom/venus-5.2/venus.mbn", }; static const struct freq_tbl sc7180_freq_table[] = { @@ -768,7 +768,7 @@ static const struct venus_resources sc7180_res = { .cp_size = 0x70800000, .cp_nonpixel_start = 0x1000000, .cp_nonpixel_size = 0x24800000, - .fwname = "qcom/venus-5.4/venus.mdt", + .fwname = "qcom/venus-5.4/venus.mbn", }; static const struct freq_tbl sm8250_freq_table[] = { diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.h b/drivers/media/platform/qcom/venus/hfi_cmds.h index dd9c506644..20acd412ee 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.h +++ b/drivers/media/platform/qcom/venus/hfi_cmds.h @@ -242,7 +242,7 @@ struct hfi_session_parse_sequence_header_pkt { struct hfi_sfr { u32 buf_size; - u8 data[1]; + u8 data[] __counted_by(buf_size); }; struct hfi_sys_test_ssr_pkt { diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 48c9084bb4..a1b127caa9 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -870,7 +870,7 @@ static int vcodec_domains_get(struct venus_core *core) pd = dev_pm_domain_attach_by_name(dev, res->vcodec_pmdomains[i]); if (IS_ERR_OR_NULL(pd)) - return PTR_ERR(pd) ? : -ENODATA; + return pd ? PTR_ERR(pd) : -ENODATA; core->pmdomains[i] = pd; } diff --git a/drivers/media/platform/renesas/rcar-isp.c b/drivers/media/platform/renesas/rcar-isp.c index 7360cf3863..19a005d837 100644 --- a/drivers/media/platform/renesas/rcar-isp.c +++ b/drivers/media/platform/renesas/rcar-isp.c @@ -467,7 +467,7 @@ static int risp_probe(struct platform_device *pdev) isp->subdev.dev = &pdev->dev; v4l2_subdev_init(&isp->subdev, &rcar_isp_subdev_ops); v4l2_set_subdevdata(&isp->subdev, &pdev->dev); - snprintf(isp->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s %s", + snprintf(isp->subdev.name, sizeof(isp->subdev.name), "%s %s", KBUILD_MODNAME, dev_name(&pdev->dev)); isp->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c index f6326df0b0..66fe553a00 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c @@ -1889,7 +1889,7 @@ static int rcsi2_probe(struct platform_device *pdev) priv->subdev.dev = &pdev->dev; v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops); v4l2_set_subdevdata(&priv->subdev, &pdev->dev); - snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s %s", + snprintf(priv->subdev.name, sizeof(priv->subdev.name), "%s %s", KBUILD_MODNAME, dev_name(&pdev->dev)); priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c index 163a4ba61c..292c5bf9e5 100644 --- a/drivers/media/platform/renesas/rcar_drif.c +++ b/drivers/media/platform/renesas/rcar_drif.c @@ -871,8 +871,7 @@ static int rcar_drif_querycap(struct file *file, void *fh, strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, sdr->vdev->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - sdr->vdev->name); + strscpy(cap->bus_info, "platform:R-Car DRIF", sizeof(cap->bus_info)); return 0; } diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c index ec631c6e2a..2562b30acf 100644 --- a/drivers/media/platform/renesas/renesas-ceu.c +++ b/drivers/media/platform/renesas/renesas-ceu.c @@ -1183,17 +1183,13 @@ static int ceu_enum_input(struct file *file, void *priv, struct v4l2_input *inp) { struct ceu_device *ceudev = video_drvdata(file); - struct ceu_subdev *ceusd; if (inp->index >= ceudev->num_sd) return -EINVAL; - ceusd = ceudev->subdevs[inp->index]; - inp->type = V4L2_INPUT_TYPE_CAMERA; inp->std = 0; - snprintf(inp->name, sizeof(inp->name), "Camera%u: %s", - inp->index, ceusd->v4l2_sd->name); + snprintf(inp->name, sizeof(inp->name), "Camera %u", inp->index); return 0; } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c index f8093ba953..68d05243c3 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c @@ -373,7 +373,7 @@ int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) (7 << VI6_DPR_SMPPT_TGW_SHIFT) | (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); - v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 0); + vsp1_wpf_stop(pipe->output); return ret; } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c index 3b17f5fa40..ea12c3f12c 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c @@ -44,14 +44,6 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, } /* ----------------------------------------------------------------------------- - * V4L2 Subdevice Operations - */ - -static const struct v4l2_subdev_ops rpf_ops = { - .pad = &vsp1_rwpf_pad_ops, -}; - -/* ----------------------------------------------------------------------------- * VSP1 Entity Operations */ @@ -411,7 +403,7 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) rpf->entity.index = index; sprintf(name, "rpf.%u", index); - ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops, + ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &vsp1_rwpf_subdev_ops, MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); if (ret < 0) return ERR_PTR(ret); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c index 22a82d2181..e0f87c8103 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c @@ -24,7 +24,7 @@ struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, } /* ----------------------------------------------------------------------------- - * V4L2 Subdevice Pad Operations + * V4L2 Subdevice Operations */ static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, @@ -243,7 +243,7 @@ done: return ret; } -const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = { +static const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = { .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = vsp1_rwpf_enum_mbus_code, .enum_frame_size = vsp1_rwpf_enum_frame_size, @@ -253,6 +253,10 @@ const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = { .set_selection = vsp1_rwpf_set_selection, }; +const struct v4l2_subdev_ops vsp1_rwpf_subdev_ops = { + .pad = &vsp1_rwpf_pad_ops, +}; + /* ----------------------------------------------------------------------------- * Controls */ diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h index eac5c04c22..e0d212c70b 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h @@ -79,9 +79,11 @@ static inline struct vsp1_rwpf *entity_to_rwpf(struct vsp1_entity *entity) struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); +void vsp1_wpf_stop(struct vsp1_rwpf *wpf); + int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols); -extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops; +extern const struct v4l2_subdev_ops vsp1_rwpf_subdev_ops; struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_state *sd_state); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c index d0074ca009..cab4445eca 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c @@ -186,17 +186,13 @@ static int wpf_init_controls(struct vsp1_rwpf *wpf) } /* ----------------------------------------------------------------------------- - * V4L2 Subdevice Core Operations + * VSP1 Entity Operations */ -static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) +void vsp1_wpf_stop(struct vsp1_rwpf *wpf) { - struct vsp1_rwpf *wpf = to_rwpf(subdev); struct vsp1_device *vsp1 = wpf->entity.vsp1; - if (enable) - return 0; - /* * Write to registers directly when stopping the stream as there will be * no pipeline run to apply the display list. @@ -204,27 +200,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0); vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET + VI6_WPF_SRCRPF, 0); - - return 0; } -/* ----------------------------------------------------------------------------- - * V4L2 Subdevice Operations - */ - -static const struct v4l2_subdev_video_ops wpf_video_ops = { - .s_stream = wpf_s_stream, -}; - -static const struct v4l2_subdev_ops wpf_ops = { - .video = &wpf_video_ops, - .pad = &vsp1_rwpf_pad_ops, -}; - -/* ----------------------------------------------------------------------------- - * VSP1 Entity Operations - */ - static void vsp1_wpf_destroy(struct vsp1_entity *entity) { struct vsp1_rwpf *wpf = entity_to_rwpf(entity); @@ -583,7 +560,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) wpf->entity.index = index; sprintf(name, "wpf.%u", index); - ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops, + ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &vsp1_rwpf_subdev_ops, MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); if (ret < 0) return ERR_PTR(ret); diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index f1c532a580..25f5b5eebf 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -184,7 +184,7 @@ static int rga_setup_ctrls(struct rga_ctx *ctx) static struct rga_fmt formats[] = { { .fourcc = V4L2_PIX_FMT_ARGB32, - .color_swap = RGA_COLOR_RB_SWAP, + .color_swap = RGA_COLOR_ALPHA_SWAP, .hw_format = RGA_COLOR_FMT_ABGR8888, .depth = 32, .uv_factor = 1, @@ -192,17 +192,8 @@ static struct rga_fmt formats[] = { .x_div = 1, }, { - .fourcc = V4L2_PIX_FMT_XRGB32, - .color_swap = RGA_COLOR_RB_SWAP, - .hw_format = RGA_COLOR_FMT_XBGR8888, - .depth = 32, - .uv_factor = 1, - .y_div = 1, - .x_div = 1, - }, - { .fourcc = V4L2_PIX_FMT_ABGR32, - .color_swap = RGA_COLOR_ALPHA_SWAP, + .color_swap = RGA_COLOR_RB_SWAP, .hw_format = RGA_COLOR_FMT_ABGR8888, .depth = 32, .uv_factor = 1, @@ -211,7 +202,7 @@ static struct rga_fmt formats[] = { }, { .fourcc = V4L2_PIX_FMT_XBGR32, - .color_swap = RGA_COLOR_ALPHA_SWAP, + .color_swap = RGA_COLOR_RB_SWAP, .hw_format = RGA_COLOR_FMT_XBGR8888, .depth = 32, .uv_factor = 1, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index 8f3cba3197..c6d7e01c89 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -479,9 +479,11 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap) rkisp1_write(rkisp1, cap->config->mi.cr_size_init, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR)); + rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->sp_y_stride); rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_WIDTH, pixm->width); rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT, pixm->height); - rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->sp_y_stride); + rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_SIZE, + cap->sp_y_stride * pixm->height); rkisp1_irq_frame_end_enable(cap); @@ -1101,14 +1103,20 @@ rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane *pixm, memset(pixm->plane_fmt, 0, sizeof(pixm->plane_fmt)); info = v4l2_format_info(pixm->pixelformat); pixm->num_planes = info->mem_planes; - stride = info->bpp[0] * pixm->width; - /* Self path supports custom stride but Main path doesn't */ - if (id == RKISP1_MAINPATH || plane_y->bytesperline < stride) - plane_y->bytesperline = stride; - plane_y->sizeimage = plane_y->bytesperline * pixm->height; - /* normalize stride to pixels per line */ - stride = DIV_ROUND_UP(plane_y->bytesperline, info->bpp[0]); + /* + * The SP supports custom strides, expressed as a number of pixels for + * the Y plane. Clamp the stride to a reasonable value to avoid integer + * overflows when calculating the bytesperline and sizeimage values. + */ + if (id == RKISP1_SELFPATH) + stride = clamp(DIV_ROUND_UP(plane_y->bytesperline, info->bpp[0]), + pixm->width, 65536U); + else + stride = pixm->width; + + plane_y->bytesperline = stride * info->bpp[0]; + plane_y->sizeimage = plane_y->bytesperline * pixm->height; for (i = 1; i < info->comp_planes; i++) { struct v4l2_plane_pix_format *plane = &pixm->plane_fmt[i]; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index d30f0ecb1b..2d7f06281c 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -61,6 +61,14 @@ struct dentry; RKISP1_CIF_ISP_EXP_END | \ RKISP1_CIF_ISP_HIST_MEASURE_RDY) +/* IRQ lines */ +enum rkisp1_irq_line { + RKISP1_IRQ_ISP = 0, + RKISP1_IRQ_MI, + RKISP1_IRQ_MIPI, + RKISP1_NUM_IRQS, +}; + /* enum for the resizer pads */ enum rkisp1_rsz_pad { RKISP1_RSZ_PAD_SINK, @@ -167,9 +175,6 @@ struct rkisp1_sensor_async { * @is_dphy_errctrl_disabled: if dphy errctrl is disabled (avoid endless interrupt) * @sd: v4l2_subdev variable * @pads: media pads - * @pad_cfg: configurations for the pads - * @sink_fmt: input format - * @lock: protects pad_cfg and sink_fmt * @source: source in-use, set when starting streaming */ struct rkisp1_csi { @@ -178,9 +183,6 @@ struct rkisp1_csi { bool is_dphy_errctrl_disabled; struct v4l2_subdev sd; struct media_pad pads[RKISP1_CSI_PAD_NUM]; - struct v4l2_subdev_pad_config pad_cfg[RKISP1_CSI_PAD_NUM]; - const struct rkisp1_mbus_info *sink_fmt; - struct mutex lock; struct v4l2_subdev *source; }; @@ -190,20 +192,14 @@ struct rkisp1_csi { * @sd: v4l2_subdev variable * @rkisp1: pointer to rkisp1_device * @pads: media pads - * @pad_cfg: pads configurations * @sink_fmt: input format - * @src_fmt: output format - * @ops_lock: ops serialization * @frame_sequence: used to synchronize frame_id between video devices. */ struct rkisp1_isp { struct v4l2_subdev sd; struct rkisp1_device *rkisp1; struct media_pad pads[RKISP1_ISP_PAD_MAX]; - struct v4l2_subdev_pad_config pad_cfg[RKISP1_ISP_PAD_MAX]; const struct rkisp1_mbus_info *sink_fmt; - const struct rkisp1_mbus_info *src_fmt; - struct mutex ops_lock; /* serialize the subdevice ops */ __u32 frame_sequence; }; @@ -390,10 +386,7 @@ struct rkisp1_params { * @id: id of the resizer, one of RKISP1_SELFPATH, RKISP1_MAINPATH * @rkisp1: pointer to the rkisp1 device * @pads: media pads - * @pad_cfg: configurations for the pads * @config: the set of registers to configure the resizer - * @pixel_enc: pixel encoding of the resizer - * @ops_lock: a lock for the subdev ops */ struct rkisp1_resizer { struct v4l2_subdev sd; @@ -401,10 +394,7 @@ struct rkisp1_resizer { enum rkisp1_stream_id id; struct rkisp1_device *rkisp1; struct media_pad pads[RKISP1_RSZ_PAD_MAX]; - struct v4l2_subdev_pad_config pad_cfg[RKISP1_RSZ_PAD_MAX]; const struct rkisp1_rsz_config *config; - enum v4l2_pixel_encoding pixel_enc; - struct mutex ops_lock; /* serialize the subdevice ops */ }; /* @@ -441,7 +431,6 @@ struct rkisp1_debug { * struct rkisp1_device - ISP platform device * * @base_addr: base register address - * @irq: the irq number * @dev: a pointer to the struct device * @clk_size: number of clocks * @clks: array of clocks @@ -459,6 +448,7 @@ struct rkisp1_debug { * @stream_lock: serializes {start/stop}_streaming callbacks between the capture devices. * @debug: debug params to be exposed on debugfs * @info: version-specific ISP information + * @irqs: IRQ line numbers */ struct rkisp1_device { void __iomem *base_addr; @@ -479,6 +469,7 @@ struct rkisp1_device { struct mutex stream_lock; /* serialize {start/stop}_streaming cb between capture devices */ struct rkisp1_debug debug; const struct rkisp1_info *info; + int irqs[RKISP1_NUM_IRQS]; }; /* diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c index fdff3d0da4..702adee833 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c @@ -30,23 +30,6 @@ static inline struct rkisp1_csi *to_rkisp1_csi(struct v4l2_subdev *sd) return container_of(sd, struct rkisp1_csi, sd); } -static struct v4l2_mbus_framefmt * -rkisp1_csi_get_pad_fmt(struct rkisp1_csi *csi, - struct v4l2_subdev_state *sd_state, - unsigned int pad, u32 which) -{ - struct v4l2_subdev_state state = { - .pads = csi->pad_cfg - }; - - lockdep_assert_held(&csi->lock); - - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad); - else - return v4l2_subdev_get_try_format(&csi->sd, &state, pad); -} - int rkisp1_csi_link_sensor(struct rkisp1_device *rkisp1, struct v4l2_subdev *sd, struct rkisp1_sensor_async *s_asd, unsigned int source_pad) @@ -76,7 +59,8 @@ int rkisp1_csi_link_sensor(struct rkisp1_device *rkisp1, struct v4l2_subdev *sd, } static int rkisp1_csi_config(struct rkisp1_csi *csi, - const struct rkisp1_sensor_async *sensor) + const struct rkisp1_sensor_async *sensor, + const struct rkisp1_mbus_info *format) { struct rkisp1_device *rkisp1 = csi->rkisp1; unsigned int lanes = sensor->lanes; @@ -98,7 +82,7 @@ static int rkisp1_csi_config(struct rkisp1_csi *csi, /* Configure Data Type and Virtual Channel */ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL, - RKISP1_CIF_MIPI_DATA_SEL_DT(csi->sink_fmt->mipi_dt) | + RKISP1_CIF_MIPI_DATA_SEL_DT(format->mipi_dt) | RKISP1_CIF_MIPI_DATA_SEL_VC(0)); /* Clear MIPI interrupts */ @@ -141,8 +125,20 @@ static void rkisp1_csi_disable(struct rkisp1_csi *csi) struct rkisp1_device *rkisp1 = csi->rkisp1; u32 val; - /* Mask and clear interrupts. */ + /* Mask MIPI interrupts. */ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, 0); + + /* Flush posted writes */ + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); + + /* + * Wait until the IRQ handler has ended. The IRQ handler may get called + * even after this, but it will return immediately as the MIPI + * interrupts have been masked. + */ + synchronize_irq(rkisp1->irqs[RKISP1_IRQ_MIPI]); + + /* Clear MIPI interrupt status */ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, ~0); val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); @@ -151,7 +147,8 @@ static void rkisp1_csi_disable(struct rkisp1_csi *csi) } static int rkisp1_csi_start(struct rkisp1_csi *csi, - const struct rkisp1_sensor_async *sensor) + const struct rkisp1_sensor_async *sensor, + const struct rkisp1_mbus_info *format) { struct rkisp1_device *rkisp1 = csi->rkisp1; union phy_configure_opts opts; @@ -159,7 +156,7 @@ static int rkisp1_csi_start(struct rkisp1_csi *csi, s64 pixel_clock; int ret; - ret = rkisp1_csi_config(csi, sensor); + ret = rkisp1_csi_config(csi, sensor, format); if (ret) return ret; @@ -169,7 +166,7 @@ static int rkisp1_csi_start(struct rkisp1_csi *csi, return -EINVAL; } - phy_mipi_dphy_get_default_config(pixel_clock, csi->sink_fmt->bus_width, + phy_mipi_dphy_get_default_config(pixel_clock, format->bus_width, sensor->lanes, cfg); phy_set_mode(csi->dphy, PHY_MODE_MIPI_DPHY); phy_configure(csi->dphy, &opts); @@ -248,7 +245,6 @@ static int rkisp1_csi_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - struct rkisp1_csi *csi = to_rkisp1_csi(sd); unsigned int i; int pos = 0; @@ -258,15 +254,10 @@ static int rkisp1_csi_enum_mbus_code(struct v4l2_subdev *sd, if (code->index) return -EINVAL; - mutex_lock(&csi->lock); - - sink_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, - RKISP1_CSI_PAD_SINK, - code->which); + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, + RKISP1_CSI_PAD_SINK); code->code = sink_fmt->code; - mutex_unlock(&csi->lock); - return 0; } @@ -296,9 +287,9 @@ static int rkisp1_csi_init_config(struct v4l2_subdev *sd, { struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SINK); - src_fmt = v4l2_subdev_get_try_format(sd, sd_state, + src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SRC); sink_fmt->width = RKISP1_DEFAULT_WIDTH; @@ -311,36 +302,18 @@ static int rkisp1_csi_init_config(struct v4l2_subdev *sd, return 0; } -static int rkisp1_csi_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct rkisp1_csi *csi = to_rkisp1_csi(sd); - - mutex_lock(&csi->lock); - fmt->format = *rkisp1_csi_get_pad_fmt(csi, sd_state, fmt->pad, - fmt->which); - mutex_unlock(&csi->lock); - - return 0; -} - static int rkisp1_csi_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - struct rkisp1_csi *csi = to_rkisp1_csi(sd); const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; /* The format on the source pad always matches the sink pad. */ if (fmt->pad == RKISP1_CSI_PAD_SRC) - return rkisp1_csi_get_fmt(sd, sd_state, fmt); - - mutex_lock(&csi->lock); + return v4l2_subdev_get_fmt(sd, sd_state, fmt); - sink_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, RKISP1_CSI_PAD_SINK, - fmt->which); + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SINK); sink_fmt->code = fmt->format.code; @@ -359,16 +332,10 @@ static int rkisp1_csi_set_fmt(struct v4l2_subdev *sd, fmt->format = *sink_fmt; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - csi->sink_fmt = mbus_info; - /* Propagate the format to the source pad. */ - src_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, RKISP1_CSI_PAD_SRC, - fmt->which); + src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SRC); *src_fmt = *sink_fmt; - mutex_unlock(&csi->lock); - return 0; } @@ -380,8 +347,11 @@ static int rkisp1_csi_s_stream(struct v4l2_subdev *sd, int enable) { struct rkisp1_csi *csi = to_rkisp1_csi(sd); struct rkisp1_device *rkisp1 = csi->rkisp1; + const struct v4l2_mbus_framefmt *sink_fmt; + const struct rkisp1_mbus_info *format; struct rkisp1_sensor_async *source_asd; struct v4l2_async_connection *asc; + struct v4l2_subdev_state *sd_state; struct media_pad *source_pad; struct v4l2_subdev *source; int ret; @@ -415,9 +385,12 @@ static int rkisp1_csi_s_stream(struct v4l2_subdev *sd, int enable) if (source_asd->mbus_type != V4L2_MBUS_CSI2_DPHY) return -EINVAL; - mutex_lock(&csi->lock); - ret = rkisp1_csi_start(csi, source_asd); - mutex_unlock(&csi->lock); + sd_state = v4l2_subdev_lock_and_get_active_state(sd); + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SINK); + format = rkisp1_mbus_info_get_by_code(sink_fmt->code); + v4l2_subdev_unlock_state(sd_state); + + ret = rkisp1_csi_start(csi, source_asd, format); if (ret) return ret; @@ -447,7 +420,7 @@ static const struct v4l2_subdev_video_ops rkisp1_csi_video_ops = { static const struct v4l2_subdev_pad_ops rkisp1_csi_pad_ops = { .enum_mbus_code = rkisp1_csi_enum_mbus_code, .init_cfg = rkisp1_csi_init_config, - .get_fmt = rkisp1_csi_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = rkisp1_csi_set_fmt, }; @@ -459,13 +432,11 @@ static const struct v4l2_subdev_ops rkisp1_csi_ops = { int rkisp1_csi_register(struct rkisp1_device *rkisp1) { struct rkisp1_csi *csi = &rkisp1->csi; - struct v4l2_subdev_state state = {}; struct media_pad *pads; struct v4l2_subdev *sd; int ret; csi->rkisp1 = rkisp1; - mutex_init(&csi->lock); sd = &csi->sd; v4l2_subdev_init(sd, &rkisp1_csi_ops); @@ -481,26 +452,26 @@ int rkisp1_csi_register(struct rkisp1_device *rkisp1) pads[RKISP1_CSI_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT; - csi->sink_fmt = rkisp1_mbus_info_get_by_code(RKISP1_CSI_DEF_FMT); - ret = media_entity_pads_init(&sd->entity, RKISP1_CSI_PAD_NUM, pads); if (ret) - goto error; + goto err_entity_cleanup; - state.pads = csi->pad_cfg; - rkisp1_csi_init_config(sd, &state); + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto err_entity_cleanup; ret = v4l2_device_register_subdev(&csi->rkisp1->v4l2_dev, sd); if (ret) { dev_err(sd->dev, "Failed to register csi receiver subdev\n"); - goto error; + goto err_subdev_cleanup; } return 0; -error: +err_subdev_cleanup: + v4l2_subdev_cleanup(sd); +err_entity_cleanup: media_entity_cleanup(&sd->entity); - mutex_destroy(&csi->lock); csi->rkisp1 = NULL; return ret; } @@ -513,8 +484,8 @@ void rkisp1_csi_unregister(struct rkisp1_device *rkisp1) return; v4l2_device_unregister_subdev(&csi->sd); + v4l2_subdev_cleanup(&csi->sd); media_entity_cleanup(&csi->sd.entity); - mutex_destroy(&csi->lock); } int rkisp1_csi_init(struct rkisp1_device *rkisp1) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index 894d5afaff..acc559652d 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -114,6 +114,7 @@ struct rkisp1_isr_data { const char *name; irqreturn_t (*isr)(int irq, void *ctx); + u32 line_mask; }; /* ---------------------------------------------------------------------------- @@ -442,17 +443,25 @@ error: static irqreturn_t rkisp1_isr(int irq, void *ctx) { + irqreturn_t ret = IRQ_NONE; + /* * Call rkisp1_capture_isr() first to handle the frame that * potentially completed using the current frame_sequence number before * it is potentially incremented by rkisp1_isp_isr() in the vertical * sync. */ - rkisp1_capture_isr(irq, ctx); - rkisp1_isp_isr(irq, ctx); - rkisp1_csi_isr(irq, ctx); - return IRQ_HANDLED; + if (rkisp1_capture_isr(irq, ctx) == IRQ_HANDLED) + ret = IRQ_HANDLED; + + if (rkisp1_isp_isr(irq, ctx) == IRQ_HANDLED) + ret = IRQ_HANDLED; + + if (rkisp1_csi_isr(irq, ctx) == IRQ_HANDLED) + ret = IRQ_HANDLED; + + return ret; } static const char * const px30_isp_clks[] = { @@ -463,9 +472,9 @@ static const char * const px30_isp_clks[] = { }; static const struct rkisp1_isr_data px30_isp_isrs[] = { - { "isp", rkisp1_isp_isr }, - { "mi", rkisp1_capture_isr }, - { "mipi", rkisp1_csi_isr }, + { "isp", rkisp1_isp_isr, BIT(RKISP1_IRQ_ISP) }, + { "mi", rkisp1_capture_isr, BIT(RKISP1_IRQ_MI) }, + { "mipi", rkisp1_csi_isr, BIT(RKISP1_IRQ_MIPI) }, }; static const struct rkisp1_info px30_isp_info = { @@ -484,7 +493,7 @@ static const char * const rk3399_isp_clks[] = { }; static const struct rkisp1_isr_data rk3399_isp_isrs[] = { - { NULL, rkisp1_isr }, + { NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) | BIT(RKISP1_IRQ_MIPI) }, }; static const struct rkisp1_info rk3399_isp_info = { @@ -535,6 +544,9 @@ static int rkisp1_probe(struct platform_device *pdev) if (IS_ERR(rkisp1->base_addr)) return PTR_ERR(rkisp1->base_addr); + for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) + rkisp1->irqs[il] = -1; + for (i = 0; i < info->isr_size; i++) { irq = info->isrs[i].name ? platform_get_irq_byname(pdev, info->isrs[i].name) @@ -542,6 +554,11 @@ static int rkisp1_probe(struct platform_device *pdev) if (irq < 0) return irq; + for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) { + if (info->isrs[i].line_mask & BIT(il)) + rkisp1->irqs[il] = irq; + } + ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED, dev_driver_string(dev), dev); if (ret) { diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 07fbb77ce2..5fbc47bda6 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -54,40 +54,6 @@ */ /* ---------------------------------------------------------------------------- - * Helpers - */ - -static struct v4l2_mbus_framefmt * -rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp, - struct v4l2_subdev_state *sd_state, - unsigned int pad, u32 which) -{ - struct v4l2_subdev_state state = { - .pads = isp->pad_cfg - }; - - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&isp->sd, sd_state, pad); - else - return v4l2_subdev_get_try_format(&isp->sd, &state, pad); -} - -static struct v4l2_rect * -rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp, - struct v4l2_subdev_state *sd_state, - unsigned int pad, u32 which) -{ - struct v4l2_subdev_state state = { - .pads = isp->pad_cfg - }; - - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&isp->sd, sd_state, pad); - else - return v4l2_subdev_get_try_crop(&isp->sd, &state, pad); -} - -/* ---------------------------------------------------------------------------- * Camera Interface registers configurations */ @@ -96,12 +62,12 @@ rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp, * This should only be called when configuring CIF * or at the frame end interrupt */ -static void rkisp1_config_ism(struct rkisp1_isp *isp) +static void rkisp1_config_ism(struct rkisp1_isp *isp, + struct v4l2_subdev_state *sd_state) { const struct v4l2_rect *src_crop = - rkisp1_isp_get_pad_crop(isp, NULL, - RKISP1_ISP_PAD_SOURCE_VIDEO, - V4L2_SUBDEV_FORMAT_ACTIVE); + v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); struct rkisp1_device *rkisp1 = isp->rkisp1; u32 val; @@ -125,21 +91,26 @@ static void rkisp1_config_ism(struct rkisp1_isp *isp) * configure ISP blocks with input format, size...... */ static int rkisp1_config_isp(struct rkisp1_isp *isp, + struct v4l2_subdev_state *sd_state, enum v4l2_mbus_type mbus_type, u32 mbus_flags) { struct rkisp1_device *rkisp1 = isp->rkisp1; u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, acq_prop = 0; - const struct rkisp1_mbus_info *sink_fmt = isp->sink_fmt; - const struct rkisp1_mbus_info *src_fmt = isp->src_fmt; + const struct rkisp1_mbus_info *sink_fmt; + const struct rkisp1_mbus_info *src_fmt; + const struct v4l2_mbus_framefmt *src_frm; const struct v4l2_mbus_framefmt *sink_frm; const struct v4l2_rect *sink_crop; - sink_frm = rkisp1_isp_get_pad_fmt(isp, NULL, - RKISP1_ISP_PAD_SINK_VIDEO, - V4L2_SUBDEV_FORMAT_ACTIVE); - sink_crop = rkisp1_isp_get_pad_crop(isp, NULL, - RKISP1_ISP_PAD_SINK_VIDEO, - V4L2_SUBDEV_FORMAT_ACTIVE); + sink_frm = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + src_frm = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + + sink_fmt = rkisp1_mbus_info_get_by_code(sink_frm->code); + src_fmt = rkisp1_mbus_info_get_by_code(src_frm->code); if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { acq_mult = 1; @@ -230,14 +201,15 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp, } else { struct v4l2_mbus_framefmt *src_frm; - src_frm = rkisp1_isp_get_pad_fmt(isp, NULL, - RKISP1_ISP_PAD_SOURCE_VIDEO, - V4L2_SUBDEV_FORMAT_ACTIVE); + src_frm = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); rkisp1_params_pre_configure(&rkisp1->params, sink_fmt->bayer_pat, src_frm->quantization, src_frm->ycbcr_enc); } + isp->sink_fmt = sink_fmt; + return 0; } @@ -258,16 +230,17 @@ static void rkisp1_config_path(struct rkisp1_isp *isp, /* Hardware configure Entry */ static int rkisp1_config_cif(struct rkisp1_isp *isp, + struct v4l2_subdev_state *sd_state, enum v4l2_mbus_type mbus_type, u32 mbus_flags) { int ret; - ret = rkisp1_config_isp(isp, mbus_type, mbus_flags); + ret = rkisp1_config_isp(isp, sd_state, mbus_type, mbus_flags); if (ret) return ret; rkisp1_config_path(isp, mbus_type); - rkisp1_config_ism(isp); + rkisp1_config_ism(isp, sd_state); return 0; } @@ -281,11 +254,25 @@ static void rkisp1_isp_stop(struct rkisp1_isp *isp) * ISP(mi) stop in mi frame end -> Stop ISP(mipi) -> * Stop ISP(isp) ->wait for ISP isp off */ - /* stop and clear MI and ISP interrupts */ - rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, 0); - rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, ~0); + /* Mask MI and ISP interrupts */ + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, 0); rkisp1_write(rkisp1, RKISP1_CIF_MI_IMSC, 0); + + /* Flush posted writes */ + rkisp1_read(rkisp1, RKISP1_CIF_MI_IMSC); + + /* + * Wait until the IRQ handler has ended. The IRQ handler may get called + * even after this, but it will return immediately as the MI and ISP + * interrupts have been masked. + */ + synchronize_irq(rkisp1->irqs[RKISP1_IRQ_ISP]); + if (rkisp1->irqs[RKISP1_IRQ_ISP] != rkisp1->irqs[RKISP1_IRQ_MI]) + synchronize_irq(rkisp1->irqs[RKISP1_IRQ_MI]); + + /* Clear MI and ISP interrupt status */ + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, ~0); rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, ~0); /* stop ISP */ @@ -328,9 +315,12 @@ static void rkisp1_config_clk(struct rkisp1_isp *isp) } } -static void rkisp1_isp_start(struct rkisp1_isp *isp) +static void rkisp1_isp_start(struct rkisp1_isp *isp, + struct v4l2_subdev_state *sd_state) { struct rkisp1_device *rkisp1 = isp->rkisp1; + const struct v4l2_mbus_framefmt *src_fmt; + const struct rkisp1_mbus_info *src_info; u32 val; rkisp1_config_clk(isp); @@ -342,7 +332,11 @@ static void rkisp1_isp_start(struct rkisp1_isp *isp) RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE; rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val); - if (isp->src_fmt->pixel_enc != V4L2_PIXEL_ENC_BAYER) + src_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + src_info = rkisp1_mbus_info_get_by_code(src_fmt->code); + + if (src_info->pixel_enc != V4L2_PIXEL_ENC_BAYER) rkisp1_params_post_configure(&rkisp1->params); } @@ -436,7 +430,7 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, struct v4l2_rect *sink_crop, *src_crop; /* Video. */ - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_ISP_PAD_SINK_VIDEO); sink_fmt->width = RKISP1_DEFAULT_WIDTH; sink_fmt->height = RKISP1_DEFAULT_HEIGHT; @@ -447,14 +441,14 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - sink_crop = v4l2_subdev_get_try_crop(sd, sd_state, + sink_crop = v4l2_subdev_get_pad_crop(sd, sd_state, RKISP1_ISP_PAD_SINK_VIDEO); sink_crop->width = RKISP1_DEFAULT_WIDTH; sink_crop->height = RKISP1_DEFAULT_HEIGHT; sink_crop->left = 0; sink_crop->top = 0; - src_fmt = v4l2_subdev_get_try_format(sd, sd_state, + src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_ISP_PAD_SOURCE_VIDEO); *src_fmt = *sink_fmt; src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; @@ -463,14 +457,14 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, src_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; - src_crop = v4l2_subdev_get_try_crop(sd, sd_state, + src_crop = v4l2_subdev_get_pad_crop(sd, sd_state, RKISP1_ISP_PAD_SOURCE_VIDEO); *src_crop = *sink_crop; /* Parameters and statistics. */ - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_ISP_PAD_SINK_PARAMS); - src_fmt = v4l2_subdev_get_try_format(sd, sd_state, + src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_ISP_PAD_SOURCE_STATS); sink_fmt->width = 0; sink_fmt->height = 0; @@ -483,8 +477,7 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, struct v4l2_subdev_state *sd_state, - struct v4l2_mbus_framefmt *format, - unsigned int which) + struct v4l2_mbus_framefmt *format) { const struct rkisp1_mbus_info *sink_info; const struct rkisp1_mbus_info *src_info; @@ -493,12 +486,12 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, const struct v4l2_rect *src_crop; bool set_csc; - sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, which); - src_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO, which); - src_crop = rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO, which); + sink_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + src_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + src_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); /* * Media bus code. The ISP can operate in pass-through mode (Bayer in, @@ -581,26 +574,20 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, */ if (set_csc) format->flags |= V4L2_MBUS_FRAMEFMT_SET_CSC; - - /* Store the source format info when setting the active format. */ - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - isp->src_fmt = src_info; } static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp, struct v4l2_subdev_state *sd_state, - struct v4l2_rect *r, unsigned int which) + struct v4l2_rect *r) { struct v4l2_mbus_framefmt *src_fmt; const struct v4l2_rect *sink_crop; struct v4l2_rect *src_crop; - src_crop = rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO, - which); - sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, - which); + src_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); src_crop->left = ALIGN(r->left, 2); src_crop->width = ALIGN(r->width, 2); @@ -611,24 +598,22 @@ static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp, *r = *src_crop; /* Propagate to out format */ - src_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO, which); - rkisp1_isp_set_src_fmt(isp, sd_state, src_fmt, which); + src_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + rkisp1_isp_set_src_fmt(isp, sd_state, src_fmt); } static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp, struct v4l2_subdev_state *sd_state, - struct v4l2_rect *r, unsigned int which) + struct v4l2_rect *r) { struct v4l2_rect *sink_crop, *src_crop; const struct v4l2_mbus_framefmt *sink_fmt; - sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, - which); - sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, - which); + sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + sink_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); sink_crop->left = ALIGN(r->left, 2); sink_crop->width = ALIGN(r->width, 2); @@ -639,32 +624,28 @@ static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp, *r = *sink_crop; /* Propagate to out crop */ - src_crop = rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SOURCE_VIDEO, which); - rkisp1_isp_set_src_crop(isp, sd_state, src_crop, which); + src_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SOURCE_VIDEO); + rkisp1_isp_set_src_crop(isp, sd_state, src_crop); } static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, struct v4l2_subdev_state *sd_state, - struct v4l2_mbus_framefmt *format, - unsigned int which) + struct v4l2_mbus_framefmt *format) { const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; bool is_yuv; - sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, - which); + sink_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); sink_fmt->code = format->code; mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) { sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT; mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); } - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - isp->sink_fmt = mbus_info; sink_fmt->width = clamp_t(u32, format->width, RKISP1_ISP_MIN_WIDTH, @@ -706,23 +687,9 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, *format = *sink_fmt; /* Propagate to in crop */ - sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, - which); - rkisp1_isp_set_sink_crop(isp, sd_state, sink_crop, which); -} - -static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct rkisp1_isp *isp = to_rkisp1_isp(sd); - - mutex_lock(&isp->ops_lock); - fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad, - fmt->which); - mutex_unlock(&isp->ops_lock); - return 0; + sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); + rkisp1_isp_set_sink_crop(isp, sd_state, sink_crop); } static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd, @@ -731,18 +698,13 @@ static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd, { struct rkisp1_isp *isp = to_rkisp1_isp(sd); - mutex_lock(&isp->ops_lock); if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO) - rkisp1_isp_set_sink_fmt(isp, sd_state, &fmt->format, - fmt->which); + rkisp1_isp_set_sink_fmt(isp, sd_state, &fmt->format); else if (fmt->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) - rkisp1_isp_set_src_fmt(isp, sd_state, &fmt->format, - fmt->which); + rkisp1_isp_set_src_fmt(isp, sd_state, &fmt->format); else - fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad, - fmt->which); + fmt->format = *v4l2_subdev_get_pad_format(sd, sd_state, fmt->pad); - mutex_unlock(&isp->ops_lock); return 0; } @@ -750,39 +712,37 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct rkisp1_isp *isp = to_rkisp1_isp(sd); int ret = 0; if (sel->pad != RKISP1_ISP_PAD_SOURCE_VIDEO && sel->pad != RKISP1_ISP_PAD_SINK_VIDEO) return -EINVAL; - mutex_lock(&isp->ops_lock); switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) { struct v4l2_mbus_framefmt *fmt; - fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, sel->pad, - sel->which); + fmt = v4l2_subdev_get_pad_format(sd, sd_state, sel->pad); sel->r.height = fmt->height; sel->r.width = fmt->width; sel->r.left = 0; sel->r.top = 0; } else { - sel->r = *rkisp1_isp_get_pad_crop(isp, sd_state, - RKISP1_ISP_PAD_SINK_VIDEO, - sel->which); + sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO); } break; + case V4L2_SEL_TGT_CROP: - sel->r = *rkisp1_isp_get_pad_crop(isp, sd_state, sel->pad, - sel->which); + sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, sel->pad); break; + default: ret = -EINVAL; + break; } - mutex_unlock(&isp->ops_lock); + return ret; } @@ -798,15 +758,14 @@ static int rkisp1_isp_set_selection(struct v4l2_subdev *sd, dev_dbg(isp->rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); - mutex_lock(&isp->ops_lock); + if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) - rkisp1_isp_set_sink_crop(isp, sd_state, &sel->r, sel->which); + rkisp1_isp_set_sink_crop(isp, sd_state, &sel->r); else if (sel->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) - rkisp1_isp_set_src_crop(isp, sd_state, &sel->r, sel->which); + rkisp1_isp_set_src_crop(isp, sd_state, &sel->r); else ret = -EINVAL; - mutex_unlock(&isp->ops_lock); return ret; } @@ -824,7 +783,7 @@ static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = { .get_selection = rkisp1_isp_get_selection, .set_selection = rkisp1_isp_set_selection, .init_cfg = rkisp1_isp_init_config, - .get_fmt = rkisp1_isp_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = rkisp1_isp_set_fmt, .link_validate = v4l2_subdev_link_validate_default, }; @@ -837,6 +796,7 @@ static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable) { struct rkisp1_isp *isp = to_rkisp1_isp(sd); struct rkisp1_device *rkisp1 = isp->rkisp1; + struct v4l2_subdev_state *sd_state; struct media_pad *source_pad; struct media_pad *sink_pad; enum v4l2_mbus_type mbus_type; @@ -881,21 +841,23 @@ static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable) } isp->frame_sequence = -1; - mutex_lock(&isp->ops_lock); - ret = rkisp1_config_cif(isp, mbus_type, mbus_flags); + + sd_state = v4l2_subdev_lock_and_get_active_state(sd); + + ret = rkisp1_config_cif(isp, sd_state, mbus_type, mbus_flags); if (ret) - goto mutex_unlock; + goto out_unlock; - rkisp1_isp_start(isp); + rkisp1_isp_start(isp, sd_state); ret = v4l2_subdev_call(rkisp1->source, video, s_stream, true); if (ret) { rkisp1_isp_stop(isp); - goto mutex_unlock; + goto out_unlock; } -mutex_unlock: - mutex_unlock(&isp->ops_lock); +out_unlock: + v4l2_subdev_unlock_state(sd_state); return ret; } @@ -933,9 +895,6 @@ static const struct v4l2_subdev_ops rkisp1_isp_ops = { int rkisp1_isp_register(struct rkisp1_device *rkisp1) { - struct v4l2_subdev_state state = { - .pads = rkisp1->isp.pad_cfg - }; struct rkisp1_isp *isp = &rkisp1->isp; struct media_pad *pads = isp->pads; struct v4l2_subdev *sd = &isp->sd; @@ -956,27 +915,26 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1) pads[RKISP1_ISP_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE; pads[RKISP1_ISP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE; - isp->sink_fmt = rkisp1_mbus_info_get_by_code(RKISP1_DEF_SINK_PAD_FMT); - isp->src_fmt = rkisp1_mbus_info_get_by_code(RKISP1_DEF_SRC_PAD_FMT); - - mutex_init(&isp->ops_lock); ret = media_entity_pads_init(&sd->entity, RKISP1_ISP_PAD_MAX, pads); if (ret) - goto error; + goto err_entity_cleanup; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto err_subdev_cleanup; ret = v4l2_device_register_subdev(&rkisp1->v4l2_dev, sd); if (ret) { dev_err(rkisp1->dev, "Failed to register isp subdev\n"); - goto error; + goto err_subdev_cleanup; } - rkisp1_isp_init_config(sd, &state); - return 0; -error: +err_subdev_cleanup: + v4l2_subdev_cleanup(sd); +err_entity_cleanup: media_entity_cleanup(&sd->entity); - mutex_destroy(&isp->ops_lock); isp->sd.v4l2_dev = NULL; return ret; } @@ -989,8 +947,8 @@ void rkisp1_isp_unregister(struct rkisp1_device *rkisp1) return; v4l2_device_unregister_subdev(&isp->sd); + v4l2_subdev_cleanup(&isp->sd); media_entity_cleanup(&isp->sd.entity); - mutex_destroy(&isp->ops_lock); } /* ---------------------------------------------------------------------------- diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 3482f7d707..173d1ea418 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -812,7 +812,7 @@ static void rkisp1_hst_config_v10(struct rkisp1_params *params, weight[2], weight[3])); rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_WEIGHT_44_V10, - weight[0] & 0x1F); + weight[0] & 0x1f); } static void rkisp1_hst_config_v12(struct rkisp1_params *params, @@ -1726,7 +1726,7 @@ static const struct rkisp1_params_ops rkisp1_v10_params_ops = { .afm_config = rkisp1_afm_config_v10, }; -static struct rkisp1_params_ops rkisp1_v12_params_ops = { +static const struct rkisp1_params_ops rkisp1_v12_params_ops = { .lsc_matrix_config = rkisp1_lsc_matrix_config_v12, .goc_config = rkisp1_goc_config_v12, .awb_meas_config = rkisp1_awb_meas_config_v12, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index 421cc73355..350f452e67 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -273,13 +273,13 @@ #define RKISP1_CIF_C_PROC_YOUT_FULL BIT(1) #define RKISP1_CIF_C_PROC_YIN_FULL BIT(2) #define RKISP1_CIF_C_PROC_COUT_FULL BIT(3) -#define RKISP1_CIF_C_PROC_CTRL_RESERVED 0xFFFFFFFE -#define RKISP1_CIF_C_PROC_CONTRAST_RESERVED 0xFFFFFF00 -#define RKISP1_CIF_C_PROC_BRIGHTNESS_RESERVED 0xFFFFFF00 -#define RKISP1_CIF_C_PROC_HUE_RESERVED 0xFFFFFF00 -#define RKISP1_CIF_C_PROC_SATURATION_RESERVED 0xFFFFFF00 -#define RKISP1_CIF_C_PROC_MACC_RESERVED 0xE000E000 -#define RKISP1_CIF_C_PROC_TONE_RESERVED 0xF000 +#define RKISP1_CIF_C_PROC_CTRL_RESERVED 0xfffffffe +#define RKISP1_CIF_C_PROC_CONTRAST_RESERVED 0xffffff00 +#define RKISP1_CIF_C_PROC_BRIGHTNESS_RESERVED 0xffffff00 +#define RKISP1_CIF_C_PROC_HUE_RESERVED 0xffffff00 +#define RKISP1_CIF_C_PROC_SATURATION_RESERVED 0xffffff00 +#define RKISP1_CIF_C_PROC_MACC_RESERVED 0xe000e000 +#define RKISP1_CIF_C_PROC_TONE_RESERVED 0xf000 /* DUAL_CROP_CTRL */ #define RKISP1_CIF_DUAL_CROP_MP_MODE_BYPASS (0 << 0) #define RKISP1_CIF_DUAL_CROP_MP_MODE_YUV (1 << 0) @@ -310,7 +310,7 @@ #define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS_SHIFT 4 #define RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH_SHIFT 5 #define RKISP1_CIF_IMG_EFF_CTRL_MODE_SHARPEN_SHIFT 6 -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_MASK 0xE +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_MASK 0xe /* IMG_EFF_COLOR_SEL */ #define RKISP1_CIF_IMG_EFF_COLOR_RGB 0 @@ -324,7 +324,7 @@ /* MIPI_CTRL */ #define RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA BIT(0) -#define RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(a) (((a) & 0xF) << 8) +#define RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(a) (((a) & 0xf) << 8) #define RKISP1_CIF_MIPI_CTRL_NUM_LANES(a) (((a) & 0x3) << 12) #define RKISP1_CIF_MIPI_CTRL_ERR_SOT_HS_SKIP BIT(16) #define RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP BIT(17) @@ -332,14 +332,14 @@ /* MIPI_DATA_SEL */ #define RKISP1_CIF_MIPI_DATA_SEL_VC(a) (((a) & 0x3) << 6) -#define RKISP1_CIF_MIPI_DATA_SEL_DT(a) (((a) & 0x3F) << 0) +#define RKISP1_CIF_MIPI_DATA_SEL_DT(a) (((a) & 0x3f) << 0) /* MIPI_IMSC, MIPI_RIS, MIPI_MIS, MIPI_ICR, MIPI_ISR */ -#define RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(a) (((a) & 0xF) << 0) -#define RKISP1_CIF_MIPI_ERR_SOT(a) (((a) & 0xF) << 4) -#define RKISP1_CIF_MIPI_ERR_SOT_SYNC(a) (((a) & 0xF) << 8) -#define RKISP1_CIF_MIPI_ERR_EOT_SYNC(a) (((a) & 0xF) << 12) -#define RKISP1_CIF_MIPI_ERR_CTRL(a) (((a) & 0xF) << 16) +#define RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(a) (((a) & 0xf) << 0) +#define RKISP1_CIF_MIPI_ERR_SOT(a) (((a) & 0xf) << 4) +#define RKISP1_CIF_MIPI_ERR_SOT_SYNC(a) (((a) & 0xf) << 8) +#define RKISP1_CIF_MIPI_ERR_EOT_SYNC(a) (((a) & 0xf) << 12) +#define RKISP1_CIF_MIPI_ERR_CTRL(a) (((a) & 0xf) << 16) #define RKISP1_CIF_MIPI_ERR_PROTOCOL BIT(20) #define RKISP1_CIF_MIPI_ERR_ECC1 BIT(21) #define RKISP1_CIF_MIPI_ERR_ECC2 BIT(22) @@ -371,28 +371,28 @@ #define RKISP1_CIF_ISP_HIST_PROP_MODE_BLUE_V10 (4 << 0) #define RKISP1_CIF_ISP_HIST_PROP_MODE_LUM_V10 (5 << 0) #define RKISP1_CIF_ISP_HIST_PROP_MODE_MASK_V10 0x7 -#define RKISP1_CIF_ISP_HIST_PREDIV_SET_V10(x) (((x) & 0x7F) << 3) +#define RKISP1_CIF_ISP_HIST_PREDIV_SET_V10(x) (((x) & 0x7f) << 3) #define RKISP1_CIF_ISP_HIST_WEIGHT_SET_V10(v0, v1, v2, v3) \ - (((v0) & 0x1F) | (((v1) & 0x1F) << 8) |\ - (((v2) & 0x1F) << 16) | \ - (((v3) & 0x1F) << 24)) - -#define RKISP1_CIF_ISP_HIST_WINDOW_OFFSET_RESERVED_V10 0xFFFFF000 -#define RKISP1_CIF_ISP_HIST_WINDOW_SIZE_RESERVED_V10 0xFFFFF800 -#define RKISP1_CIF_ISP_HIST_WEIGHT_RESERVED_V10 0xE0E0E0E0 -#define RKISP1_CIF_ISP_MAX_HIST_PREDIVIDER_V10 0x0000007F + (((v0) & 0x1f) | (((v1) & 0x1f) << 8) |\ + (((v2) & 0x1f) << 16) | \ + (((v3) & 0x1f) << 24)) + +#define RKISP1_CIF_ISP_HIST_WINDOW_OFFSET_RESERVED_V10 0xfffff000 +#define RKISP1_CIF_ISP_HIST_WINDOW_SIZE_RESERVED_V10 0xfffff800 +#define RKISP1_CIF_ISP_HIST_WEIGHT_RESERVED_V10 0xe0e0e0e0 +#define RKISP1_CIF_ISP_MAX_HIST_PREDIVIDER_V10 0x0000007f #define RKISP1_CIF_ISP_HIST_ROW_NUM_V10 5 #define RKISP1_CIF_ISP_HIST_COLUMN_NUM_V10 5 -#define RKISP1_CIF_ISP_HIST_GET_BIN_V10(x) ((x) & 0x000FFFFF) +#define RKISP1_CIF_ISP_HIST_GET_BIN_V10(x) ((x) & 0x000fffff) /* ISP HISTOGRAM CALCULATION : CIF_ISP_HIST */ #define RKISP1_CIF_ISP_HIST_CTRL_EN_SET_V12(x) (((x) & 0x01) << 0) #define RKISP1_CIF_ISP_HIST_CTRL_EN_MASK_V12 RKISP1_CIF_ISP_HIST_CTRL_EN_SET_V12(0x01) -#define RKISP1_CIF_ISP_HIST_CTRL_STEPSIZE_SET_V12(x) (((x) & 0x7F) << 1) +#define RKISP1_CIF_ISP_HIST_CTRL_STEPSIZE_SET_V12(x) (((x) & 0x7f) << 1) #define RKISP1_CIF_ISP_HIST_CTRL_MODE_SET_V12(x) (((x) & 0x07) << 8) #define RKISP1_CIF_ISP_HIST_CTRL_MODE_MASK_V12 RKISP1_CIF_ISP_HIST_CTRL_MODE_SET_V12(0x07) #define RKISP1_CIF_ISP_HIST_CTRL_AUTOSTOP_SET_V12(x) (((x) & 0x01) << 11) -#define RKISP1_CIF_ISP_HIST_CTRL_WATERLINE_SET_V12(x) (((x) & 0xFFF) << 12) +#define RKISP1_CIF_ISP_HIST_CTRL_WATERLINE_SET_V12(x) (((x) & 0xfff) << 12) #define RKISP1_CIF_ISP_HIST_CTRL_DATASEL_SET_V12(x) (((x) & 0x07) << 24) #define RKISP1_CIF_ISP_HIST_CTRL_INTRSEL_SET_V12(x) (((x) & 0x01) << 27) #define RKISP1_CIF_ISP_HIST_CTRL_WNDNUM_SET_V12(x) (((x) & 0x03) << 28) @@ -403,19 +403,19 @@ (RKISP1_CIF_ISP_HIST_ROW_NUM_V12 * RKISP1_CIF_ISP_HIST_COLUMN_NUM_V12) #define RKISP1_CIF_ISP_HIST_WEIGHT_SET_V12(v0, v1, v2, v3) \ - (((v0) & 0x3F) | (((v1) & 0x3F) << 8) |\ - (((v2) & 0x3F) << 16) |\ - (((v3) & 0x3F) << 24)) + (((v0) & 0x3f) | (((v1) & 0x3f) << 8) |\ + (((v2) & 0x3f) << 16) |\ + (((v3) & 0x3f) << 24)) #define RKISP1_CIF_ISP_HIST_OFFS_SET_V12(v0, v1) \ - (((v0) & 0x1FFF) | (((v1) & 0x1FFF) << 16)) + (((v0) & 0x1fff) | (((v1) & 0x1fff) << 16)) #define RKISP1_CIF_ISP_HIST_SIZE_SET_V12(v0, v1) \ - (((v0) & 0x7FF) | (((v1) & 0x7FF) << 16)) + (((v0) & 0x7ff) | (((v1) & 0x7ff) << 16)) #define RKISP1_CIF_ISP_HIST_GET_BIN0_V12(x) \ - ((x) & 0xFFFF) + ((x) & 0xffff) #define RKISP1_CIF_ISP_HIST_GET_BIN1_V12(x) \ - (((x) >> 16) & 0xFFFF) + (((x) >> 16) & 0xffff) /* AUTO FOCUS MEASUREMENT: ISP_AFM_CTRL */ #define RKISP1_ISP_AFM_CTRL_ENABLE BIT(0) @@ -437,11 +437,11 @@ #define RKISP1_CIFFLASH_CONFIG_VSYNC_POS BIT(1) #define RKISP1_CIFFLASH_CONFIG_PRELIGHT_LOW BIT(2) #define RKISP1_CIFFLASH_CONFIG_SRC_FL_TRIG BIT(3) -#define RKISP1_CIFFLASH_CONFIG_DELAY(a) (((a) & 0xF) << 4) +#define RKISP1_CIFFLASH_CONFIG_DELAY(a) (((a) & 0xf) << 4) /* Demosaic: ISP_DEMOSAIC */ #define RKISP1_CIF_ISP_DEMOSAIC_BYPASS BIT(10) -#define RKISP1_CIF_ISP_DEMOSAIC_TH(x) ((x) & 0xFF) +#define RKISP1_CIF_ISP_DEMOSAIC_TH(x) ((x) & 0xff) /* ISP_FLAGS_SHD */ #define RKISP1_CIF_ISP_FLAGS_SHD_ISP_ENABLE_SHD BIT(0) @@ -458,39 +458,39 @@ #define RKISP1_CIF_ISP_AWB_YMAX_READ(x) (((x) >> 2) & 1) #define RKISP1_CIF_ISP_AWB_MODE_RGB_EN ((1 << 31) | (0x2 << 0)) #define RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN ((0 << 31) | (0x2 << 0)) -#define RKISP1_CIF_ISP_AWB_MODE_MASK_NONE 0xFFFFFFFC +#define RKISP1_CIF_ISP_AWB_MODE_MASK_NONE 0xfffffffc #define RKISP1_CIF_ISP_AWB_MODE_READ(x) ((x) & 3) #define RKISP1_CIF_ISP_AWB_SET_FRAMES_V12(x) (((x) & 0x07) << 28) #define RKISP1_CIF_ISP_AWB_SET_FRAMES_MASK_V12 RKISP1_CIF_ISP_AWB_SET_FRAMES_V12(0x07) /* ISP_AWB_GAIN_RB, ISP_AWB_GAIN_G */ -#define RKISP1_CIF_ISP_AWB_GAIN_R_SET(x) (((x) & 0x3FF) << 16) -#define RKISP1_CIF_ISP_AWB_GAIN_R_READ(x) (((x) >> 16) & 0x3FF) -#define RKISP1_CIF_ISP_AWB_GAIN_B_SET(x) ((x) & 0x3FFF) -#define RKISP1_CIF_ISP_AWB_GAIN_B_READ(x) ((x) & 0x3FFF) +#define RKISP1_CIF_ISP_AWB_GAIN_R_SET(x) (((x) & 0x3ff) << 16) +#define RKISP1_CIF_ISP_AWB_GAIN_R_READ(x) (((x) >> 16) & 0x3ff) +#define RKISP1_CIF_ISP_AWB_GAIN_B_SET(x) ((x) & 0x3fff) +#define RKISP1_CIF_ISP_AWB_GAIN_B_READ(x) ((x) & 0x3fff) /* ISP_AWB_REF */ -#define RKISP1_CIF_ISP_AWB_REF_CR_SET(x) (((x) & 0xFF) << 8) -#define RKISP1_CIF_ISP_AWB_REF_CR_READ(x) (((x) >> 8) & 0xFF) -#define RKISP1_CIF_ISP_AWB_REF_CB_READ(x) ((x) & 0xFF) +#define RKISP1_CIF_ISP_AWB_REF_CR_SET(x) (((x) & 0xff) << 8) +#define RKISP1_CIF_ISP_AWB_REF_CR_READ(x) (((x) >> 8) & 0xff) +#define RKISP1_CIF_ISP_AWB_REF_CB_READ(x) ((x) & 0xff) /* ISP_AWB_THRESH */ -#define RKISP1_CIF_ISP_AWB_MAX_CS_SET(x) (((x) & 0xFF) << 8) -#define RKISP1_CIF_ISP_AWB_MAX_CS_READ(x) (((x) >> 8) & 0xFF) -#define RKISP1_CIF_ISP_AWB_MIN_C_READ(x) ((x) & 0xFF) -#define RKISP1_CIF_ISP_AWB_MIN_Y_SET(x) (((x) & 0xFF) << 16) -#define RKISP1_CIF_ISP_AWB_MIN_Y_READ(x) (((x) >> 16) & 0xFF) -#define RKISP1_CIF_ISP_AWB_MAX_Y_SET(x) (((x) & 0xFF) << 24) -#define RKISP1_CIF_ISP_AWB_MAX_Y_READ(x) (((x) >> 24) & 0xFF) +#define RKISP1_CIF_ISP_AWB_MAX_CS_SET(x) (((x) & 0xff) << 8) +#define RKISP1_CIF_ISP_AWB_MAX_CS_READ(x) (((x) >> 8) & 0xff) +#define RKISP1_CIF_ISP_AWB_MIN_C_READ(x) ((x) & 0xff) +#define RKISP1_CIF_ISP_AWB_MIN_Y_SET(x) (((x) & 0xff) << 16) +#define RKISP1_CIF_ISP_AWB_MIN_Y_READ(x) (((x) >> 16) & 0xff) +#define RKISP1_CIF_ISP_AWB_MAX_Y_SET(x) (((x) & 0xff) << 24) +#define RKISP1_CIF_ISP_AWB_MAX_Y_READ(x) (((x) >> 24) & 0xff) /* ISP_AWB_MEAN */ -#define RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(x) ((x) & 0xFF) -#define RKISP1_CIF_ISP_AWB_GET_MEAN_CB_B(x) (((x) >> 8) & 0xFF) -#define RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(x) (((x) >> 16) & 0xFF) +#define RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(x) ((x) & 0xff) +#define RKISP1_CIF_ISP_AWB_GET_MEAN_CB_B(x) (((x) >> 8) & 0xff) +#define RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(x) (((x) >> 16) & 0xff) /* ISP_AWB_WHITE_CNT */ -#define RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(x) ((x) & 0x3FFFFFF) +#define RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(x) ((x) & 0x3ffffff) -#define RKISP1_CIF_ISP_AWB_GAINS_MAX_VAL 0x000003FF -#define RKISP1_CIF_ISP_AWB_WINDOW_OFFSET_MAX 0x00000FFF -#define RKISP1_CIF_ISP_AWB_WINDOW_MAX_SIZE 0x00001FFF -#define RKISP1_CIF_ISP_AWB_CBCR_MAX_REF 0x000000FF -#define RKISP1_CIF_ISP_AWB_THRES_MAX_YC 0x000000FF +#define RKISP1_CIF_ISP_AWB_GAINS_MAX_VAL 0x000003ff +#define RKISP1_CIF_ISP_AWB_WINDOW_OFFSET_MAX 0x00000fff +#define RKISP1_CIF_ISP_AWB_WINDOW_MAX_SIZE 0x00001fff +#define RKISP1_CIF_ISP_AWB_CBCR_MAX_REF 0x000000ff +#define RKISP1_CIF_ISP_AWB_THRES_MAX_YC 0x000000ff /* AE */ /* ISP_EXP_CTRL */ @@ -504,24 +504,24 @@ #define RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1 BIT(31) /* ISP_EXP_H_SIZE */ -#define RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(x) ((x) & 0x7FF) -#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK_V10 0x000007FF -#define RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(x) ((x) & 0x7FF) -#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK_V12 0x000007FF +#define RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(x) ((x) & 0x7ff) +#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK_V10 0x000007ff +#define RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(x) ((x) & 0x7ff) +#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK_V12 0x000007ff /* ISP_EXP_V_SIZE : vertical size must be a multiple of 2). */ -#define RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(x) ((x) & 0x7FE) -#define RKISP1_CIF_ISP_EXP_V_SIZE_SET_V12(x) (((x) & 0x7FE) << 16) +#define RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(x) ((x) & 0x7fe) +#define RKISP1_CIF_ISP_EXP_V_SIZE_SET_V12(x) (((x) & 0x7fe) << 16) /* ISP_EXP_H_OFFSET */ -#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V10(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V10(x) ((x) & 0x1fff) #define RKISP1_CIF_ISP_EXP_MAX_HOFFS_V10 2424 -#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(x) ((x) & 0x1FFF) -#define RKISP1_CIF_ISP_EXP_MAX_HOFFS_V12 0x1FFF +#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(x) ((x) & 0x1fff) +#define RKISP1_CIF_ISP_EXP_MAX_HOFFS_V12 0x1fff /* ISP_EXP_V_OFFSET */ -#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V10(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V10(x) ((x) & 0x1fff) #define RKISP1_CIF_ISP_EXP_MAX_VOFFS_V10 1806 -#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V12(x) (((x) & 0x1FFF) << 16) -#define RKISP1_CIF_ISP_EXP_MAX_VOFFS_V12 0x1FFF +#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V12(x) (((x) & 0x1fff) << 16) +#define RKISP1_CIF_ISP_EXP_MAX_VOFFS_V12 0x1fff #define RKISP1_CIF_ISP_EXP_ROW_NUM_V10 5 #define RKISP1_CIF_ISP_EXP_COLUMN_NUM_V10 5 @@ -545,10 +545,10 @@ #define RKISP1_CIF_ISP_EXP_NUM_LUMA_REGS_V12 \ (RKISP1_CIF_ISP_EXP_ROW_NUM_V12 * RKISP1_CIF_ISP_EXP_COLUMN_NUM_V12) -#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE_V12 0x7FF -#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE_V12 0xE -#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE_V12 0x7FE -#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE_V12 0xE +#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE_V12 0x7ff +#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE_V12 0xe +#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE_V12 0x7fe +#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE_V12 0xe #define RKISP1_CIF_ISP_EXP_MAX_HSIZE_V12 \ (RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE_V12 * RKISP1_CIF_ISP_EXP_COLUMN_NUM_V12 + 1) #define RKISP1_CIF_ISP_EXP_MIN_HSIZE_V12 \ @@ -558,26 +558,26 @@ #define RKISP1_CIF_ISP_EXP_MIN_VSIZE_V12 \ (RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE_V12 * RKISP1_CIF_ISP_EXP_ROW_NUM_V12 + 1) -#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy0_V12(x) ((x) & 0xFF) -#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy1_V12(x) (((x) >> 8) & 0xFF) -#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy2_V12(x) (((x) >> 16) & 0xFF) -#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy3_V12(x) (((x) >> 24) & 0xFF) +#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy0_V12(x) ((x) & 0xff) +#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy1_V12(x) (((x) >> 8) & 0xff) +#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy2_V12(x) (((x) >> 16) & 0xff) +#define RKISP1_CIF_ISP_EXP_GET_MEAN_xy3_V12(x) (((x) >> 24) & 0xff) /* LSC: ISP_LSC_CTRL */ #define RKISP1_CIF_ISP_LSC_CTRL_ENA BIT(0) -#define RKISP1_CIF_ISP_LSC_SECT_SIZE_RESERVED 0xFC00FC00 -#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED_V10 0xF000F000 -#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED_V10 0xF000F000 -#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED_V12 0xE000E000 -#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED_V12 0xE000E000 +#define RKISP1_CIF_ISP_LSC_SECT_SIZE_RESERVED 0xfc00fc00 +#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED_V10 0xf000f000 +#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED_V10 0xf000f000 +#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED_V12 0xe000e000 +#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED_V12 0xe000e000 #define RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(v0, v1) \ - (((v0) & 0xFFF) | (((v1) & 0xFFF) << 12)) + (((v0) & 0xfff) | (((v1) & 0xfff) << 12)) #define RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(v0, v1) \ - (((v0) & 0x1FFF) | (((v1) & 0x1FFF) << 13)) + (((v0) & 0x1fff) | (((v1) & 0x1fff) << 13)) #define RKISP1_CIF_ISP_LSC_SECT_SIZE(v0, v1) \ - (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) + (((v0) & 0xfff) | (((v1) & 0xfff) << 16)) #define RKISP1_CIF_ISP_LSC_SECT_GRAD(v0, v1) \ - (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) + (((v0) & 0xfff) | (((v1) & 0xfff) << 16)) /* LSC: ISP_LSC_TABLE_SEL */ #define RKISP1_CIF_ISP_LSC_TABLE_0 0 @@ -601,19 +601,19 @@ #define RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(x) (((x) & 0x3) << 4) #define RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(x) (((x) & 0x3) << 6) #define RKISP1_CIF_ISP_FLT_CHROMA_MODE_MAX 3 -#define RKISP1_CIF_ISP_FLT_GREEN_STAGE1(x) (((x) & 0xF) << 8) +#define RKISP1_CIF_ISP_FLT_GREEN_STAGE1(x) (((x) & 0xf) << 8) #define RKISP1_CIF_ISP_FLT_GREEN_STAGE1_MAX 8 -#define RKISP1_CIF_ISP_FLT_THREAD_RESERVED 0xFFFFFC00 -#define RKISP1_CIF_ISP_FLT_FAC_RESERVED 0xFFFFFFC0 -#define RKISP1_CIF_ISP_FLT_LUM_WEIGHT_RESERVED 0xFFF80000 +#define RKISP1_CIF_ISP_FLT_THREAD_RESERVED 0xfffffc00 +#define RKISP1_CIF_ISP_FLT_FAC_RESERVED 0xffffffc0 +#define RKISP1_CIF_ISP_FLT_LUM_WEIGHT_RESERVED 0xfff80000 -#define RKISP1_CIF_ISP_CTK_COEFF_RESERVED 0xFFFFF800 -#define RKISP1_CIF_ISP_XTALK_OFFSET_RESERVED 0xFFFFF000 +#define RKISP1_CIF_ISP_CTK_COEFF_RESERVED 0xfffff800 +#define RKISP1_CIF_ISP_XTALK_OFFSET_RESERVED 0xfffff000 /* GOC */ #define RKISP1_CIF_ISP_GAMMA_OUT_MODE_EQU BIT(0) #define RKISP1_CIF_ISP_GOC_MODE_MAX 1 -#define RKISP1_CIF_ISP_GOC_RESERVED 0xFFFFF800 +#define RKISP1_CIF_ISP_GOC_RESERVED 0xfffff800 /* ISP_CTRL BIT 11*/ #define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA_READ(x) (((x) >> 11) & 1) @@ -643,22 +643,22 @@ #define RKISP1_CIFISP_DEGAMMA_X_RESERVED \ ((1 << 31) | (1 << 27) | (1 << 23) | (1 << 19) |\ (1 << 15) | (1 << 11) | (1 << 7) | (1 << 3)) -#define RKISP1_CIFISP_DEGAMMA_Y_RESERVED 0xFFFFF000 +#define RKISP1_CIFISP_DEGAMMA_Y_RESERVED 0xfffff000 /* GAMMA-OUT */ #define RKISP1_CIF_ISP_GAMMA_VALUE_V12(x, y) \ - (((x) & 0xFFF) << 16 | ((y) & 0xFFF) << 0) + (((x) & 0xfff) << 16 | ((y) & 0xfff) << 0) /* AFM */ #define RKISP1_CIF_ISP_AFM_ENA BIT(0) -#define RKISP1_CIF_ISP_AFM_THRES_RESERVED 0xFFFF0000 -#define RKISP1_CIF_ISP_AFM_VAR_SHIFT_RESERVED 0xFFF8FFF8 -#define RKISP1_CIF_ISP_AFM_WINDOW_X_RESERVED 0xE000 -#define RKISP1_CIF_ISP_AFM_WINDOW_Y_RESERVED 0xF000 +#define RKISP1_CIF_ISP_AFM_THRES_RESERVED 0xffff0000 +#define RKISP1_CIF_ISP_AFM_VAR_SHIFT_RESERVED 0xfff8fff8 +#define RKISP1_CIF_ISP_AFM_WINDOW_X_RESERVED 0xe000 +#define RKISP1_CIF_ISP_AFM_WINDOW_Y_RESERVED 0xf000 #define RKISP1_CIF_ISP_AFM_WINDOW_X_MIN 0x5 #define RKISP1_CIF_ISP_AFM_WINDOW_Y_MIN 0x2 -#define RKISP1_CIF_ISP_AFM_WINDOW_X(x) (((x) & 0x1FFF) << 16) -#define RKISP1_CIF_ISP_AFM_WINDOW_Y(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_AFM_WINDOW_X(x) (((x) & 0x1fff) << 16) +#define RKISP1_CIF_ISP_AFM_WINDOW_Y(x) ((x) & 0x1fff) #define RKISP1_CIF_ISP_AFM_SET_SHIFT_a_V12(x, y) (((x) & 0x7) << 16 | ((y) & 0x7) << 0) #define RKISP1_CIF_ISP_AFM_SET_SHIFT_b_V12(x, y) (((x) & 0x7) << 20 | ((y) & 0x7) << 4) #define RKISP1_CIF_ISP_AFM_SET_SHIFT_c_V12(x, y) (((x) & 0x7) << 24 | ((y) & 0x7) << 8) @@ -676,9 +676,9 @@ #define RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP BIT(7) #define RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP BIT(8) #define RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN BIT(9) -#define RKISP1_CIF_ISP_DPF_NF_GAIN_RESERVED 0xFFFFF000 -#define RKISP1_CIF_ISP_DPF_SPATIAL_COEFF_MAX 0x1F -#define RKISP1_CIF_ISP_DPF_NLL_COEFF_N_MAX 0x3FF +#define RKISP1_CIF_ISP_DPF_NF_GAIN_RESERVED 0xfffff000 +#define RKISP1_CIF_ISP_DPF_SPATIAL_COEFF_MAX 0x1f +#define RKISP1_CIF_ISP_DPF_NLL_COEFF_N_MAX 0x3ff /* =================================================================== */ /* CIF Registers */ @@ -686,7 +686,7 @@ #define RKISP1_CIF_CTRL_BASE 0x00000000 #define RKISP1_CIF_VI_CCL (RKISP1_CIF_CTRL_BASE + 0x00000000) #define RKISP1_CIF_VI_ID (RKISP1_CIF_CTRL_BASE + 0x00000008) -#define RKISP1_CIF_VI_ISP_CLK_CTRL_V12 (RKISP1_CIF_CTRL_BASE + 0x0000000C) +#define RKISP1_CIF_VI_ISP_CLK_CTRL_V12 (RKISP1_CIF_CTRL_BASE + 0x0000000c) #define RKISP1_CIF_VI_ICCL (RKISP1_CIF_CTRL_BASE + 0x00000010) #define RKISP1_CIF_VI_IRCL (RKISP1_CIF_CTRL_BASE + 0x00000014) #define RKISP1_CIF_VI_DPCL (RKISP1_CIF_CTRL_BASE + 0x00000018) @@ -695,11 +695,11 @@ #define RKISP1_CIF_IMG_EFF_CTRL (RKISP1_CIF_IMG_EFF_BASE + 0x00000000) #define RKISP1_CIF_IMG_EFF_COLOR_SEL (RKISP1_CIF_IMG_EFF_BASE + 0x00000004) #define RKISP1_CIF_IMG_EFF_MAT_1 (RKISP1_CIF_IMG_EFF_BASE + 0x00000008) -#define RKISP1_CIF_IMG_EFF_MAT_2 (RKISP1_CIF_IMG_EFF_BASE + 0x0000000C) +#define RKISP1_CIF_IMG_EFF_MAT_2 (RKISP1_CIF_IMG_EFF_BASE + 0x0000000c) #define RKISP1_CIF_IMG_EFF_MAT_3 (RKISP1_CIF_IMG_EFF_BASE + 0x00000010) #define RKISP1_CIF_IMG_EFF_MAT_4 (RKISP1_CIF_IMG_EFF_BASE + 0x00000014) #define RKISP1_CIF_IMG_EFF_MAT_5 (RKISP1_CIF_IMG_EFF_BASE + 0x00000018) -#define RKISP1_CIF_IMG_EFF_TINT (RKISP1_CIF_IMG_EFF_BASE + 0x0000001C) +#define RKISP1_CIF_IMG_EFF_TINT (RKISP1_CIF_IMG_EFF_BASE + 0x0000001c) #define RKISP1_CIF_IMG_EFF_CTRL_SHD (RKISP1_CIF_IMG_EFF_BASE + 0x00000020) #define RKISP1_CIF_IMG_EFF_SHARPEN (RKISP1_CIF_IMG_EFF_BASE + 0x00000024) @@ -707,7 +707,7 @@ #define RKISP1_CIF_SUPER_IMP_CTRL (RKISP1_CIF_SUPER_IMP_BASE + 0x00000000) #define RKISP1_CIF_SUPER_IMP_OFFSET_X (RKISP1_CIF_SUPER_IMP_BASE + 0x00000004) #define RKISP1_CIF_SUPER_IMP_OFFSET_Y (RKISP1_CIF_SUPER_IMP_BASE + 0x00000008) -#define RKISP1_CIF_SUPER_IMP_COLOR_Y (RKISP1_CIF_SUPER_IMP_BASE + 0x0000000C) +#define RKISP1_CIF_SUPER_IMP_COLOR_Y (RKISP1_CIF_SUPER_IMP_BASE + 0x0000000c) #define RKISP1_CIF_SUPER_IMP_COLOR_CB (RKISP1_CIF_SUPER_IMP_BASE + 0x00000010) #define RKISP1_CIF_SUPER_IMP_COLOR_CR (RKISP1_CIF_SUPER_IMP_BASE + 0x00000014) @@ -715,148 +715,148 @@ #define RKISP1_CIF_ISP_CTRL (RKISP1_CIF_ISP_BASE + 0x00000000) #define RKISP1_CIF_ISP_ACQ_PROP (RKISP1_CIF_ISP_BASE + 0x00000004) #define RKISP1_CIF_ISP_ACQ_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000008) -#define RKISP1_CIF_ISP_ACQ_V_OFFS (RKISP1_CIF_ISP_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_ACQ_V_OFFS (RKISP1_CIF_ISP_BASE + 0x0000000c) #define RKISP1_CIF_ISP_ACQ_H_SIZE (RKISP1_CIF_ISP_BASE + 0x00000010) #define RKISP1_CIF_ISP_ACQ_V_SIZE (RKISP1_CIF_ISP_BASE + 0x00000014) #define RKISP1_CIF_ISP_ACQ_NR_FRAMES (RKISP1_CIF_ISP_BASE + 0x00000018) -#define RKISP1_CIF_ISP_GAMMA_DX_LO (RKISP1_CIF_ISP_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_GAMMA_DX_LO (RKISP1_CIF_ISP_BASE + 0x0000001c) #define RKISP1_CIF_ISP_GAMMA_DX_HI (RKISP1_CIF_ISP_BASE + 0x00000020) #define RKISP1_CIF_ISP_GAMMA_R_Y0 (RKISP1_CIF_ISP_BASE + 0x00000024) #define RKISP1_CIF_ISP_GAMMA_R_Y1 (RKISP1_CIF_ISP_BASE + 0x00000028) -#define RKISP1_CIF_ISP_GAMMA_R_Y2 (RKISP1_CIF_ISP_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_GAMMA_R_Y2 (RKISP1_CIF_ISP_BASE + 0x0000002c) #define RKISP1_CIF_ISP_GAMMA_R_Y3 (RKISP1_CIF_ISP_BASE + 0x00000030) #define RKISP1_CIF_ISP_GAMMA_R_Y4 (RKISP1_CIF_ISP_BASE + 0x00000034) #define RKISP1_CIF_ISP_GAMMA_R_Y5 (RKISP1_CIF_ISP_BASE + 0x00000038) -#define RKISP1_CIF_ISP_GAMMA_R_Y6 (RKISP1_CIF_ISP_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_GAMMA_R_Y6 (RKISP1_CIF_ISP_BASE + 0x0000003c) #define RKISP1_CIF_ISP_GAMMA_R_Y7 (RKISP1_CIF_ISP_BASE + 0x00000040) #define RKISP1_CIF_ISP_GAMMA_R_Y8 (RKISP1_CIF_ISP_BASE + 0x00000044) #define RKISP1_CIF_ISP_GAMMA_R_Y9 (RKISP1_CIF_ISP_BASE + 0x00000048) -#define RKISP1_CIF_ISP_GAMMA_R_Y10 (RKISP1_CIF_ISP_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_GAMMA_R_Y10 (RKISP1_CIF_ISP_BASE + 0x0000004c) #define RKISP1_CIF_ISP_GAMMA_R_Y11 (RKISP1_CIF_ISP_BASE + 0x00000050) #define RKISP1_CIF_ISP_GAMMA_R_Y12 (RKISP1_CIF_ISP_BASE + 0x00000054) #define RKISP1_CIF_ISP_GAMMA_R_Y13 (RKISP1_CIF_ISP_BASE + 0x00000058) -#define RKISP1_CIF_ISP_GAMMA_R_Y14 (RKISP1_CIF_ISP_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_GAMMA_R_Y14 (RKISP1_CIF_ISP_BASE + 0x0000005c) #define RKISP1_CIF_ISP_GAMMA_R_Y15 (RKISP1_CIF_ISP_BASE + 0x00000060) #define RKISP1_CIF_ISP_GAMMA_R_Y16 (RKISP1_CIF_ISP_BASE + 0x00000064) #define RKISP1_CIF_ISP_GAMMA_G_Y0 (RKISP1_CIF_ISP_BASE + 0x00000068) -#define RKISP1_CIF_ISP_GAMMA_G_Y1 (RKISP1_CIF_ISP_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_GAMMA_G_Y1 (RKISP1_CIF_ISP_BASE + 0x0000006c) #define RKISP1_CIF_ISP_GAMMA_G_Y2 (RKISP1_CIF_ISP_BASE + 0x00000070) #define RKISP1_CIF_ISP_GAMMA_G_Y3 (RKISP1_CIF_ISP_BASE + 0x00000074) #define RKISP1_CIF_ISP_GAMMA_G_Y4 (RKISP1_CIF_ISP_BASE + 0x00000078) -#define RKISP1_CIF_ISP_GAMMA_G_Y5 (RKISP1_CIF_ISP_BASE + 0x0000007C) +#define RKISP1_CIF_ISP_GAMMA_G_Y5 (RKISP1_CIF_ISP_BASE + 0x0000007c) #define RKISP1_CIF_ISP_GAMMA_G_Y6 (RKISP1_CIF_ISP_BASE + 0x00000080) #define RKISP1_CIF_ISP_GAMMA_G_Y7 (RKISP1_CIF_ISP_BASE + 0x00000084) #define RKISP1_CIF_ISP_GAMMA_G_Y8 (RKISP1_CIF_ISP_BASE + 0x00000088) -#define RKISP1_CIF_ISP_GAMMA_G_Y9 (RKISP1_CIF_ISP_BASE + 0x0000008C) +#define RKISP1_CIF_ISP_GAMMA_G_Y9 (RKISP1_CIF_ISP_BASE + 0x0000008c) #define RKISP1_CIF_ISP_GAMMA_G_Y10 (RKISP1_CIF_ISP_BASE + 0x00000090) #define RKISP1_CIF_ISP_GAMMA_G_Y11 (RKISP1_CIF_ISP_BASE + 0x00000094) #define RKISP1_CIF_ISP_GAMMA_G_Y12 (RKISP1_CIF_ISP_BASE + 0x00000098) -#define RKISP1_CIF_ISP_GAMMA_G_Y13 (RKISP1_CIF_ISP_BASE + 0x0000009C) -#define RKISP1_CIF_ISP_GAMMA_G_Y14 (RKISP1_CIF_ISP_BASE + 0x000000A0) -#define RKISP1_CIF_ISP_GAMMA_G_Y15 (RKISP1_CIF_ISP_BASE + 0x000000A4) -#define RKISP1_CIF_ISP_GAMMA_G_Y16 (RKISP1_CIF_ISP_BASE + 0x000000A8) -#define RKISP1_CIF_ISP_GAMMA_B_Y0 (RKISP1_CIF_ISP_BASE + 0x000000AC) -#define RKISP1_CIF_ISP_GAMMA_B_Y1 (RKISP1_CIF_ISP_BASE + 0x000000B0) -#define RKISP1_CIF_ISP_GAMMA_B_Y2 (RKISP1_CIF_ISP_BASE + 0x000000B4) -#define RKISP1_CIF_ISP_GAMMA_B_Y3 (RKISP1_CIF_ISP_BASE + 0x000000B8) -#define RKISP1_CIF_ISP_GAMMA_B_Y4 (RKISP1_CIF_ISP_BASE + 0x000000BC) -#define RKISP1_CIF_ISP_GAMMA_B_Y5 (RKISP1_CIF_ISP_BASE + 0x000000C0) -#define RKISP1_CIF_ISP_GAMMA_B_Y6 (RKISP1_CIF_ISP_BASE + 0x000000C4) -#define RKISP1_CIF_ISP_GAMMA_B_Y7 (RKISP1_CIF_ISP_BASE + 0x000000C8) -#define RKISP1_CIF_ISP_GAMMA_B_Y8 (RKISP1_CIF_ISP_BASE + 0x000000CC) -#define RKISP1_CIF_ISP_GAMMA_B_Y9 (RKISP1_CIF_ISP_BASE + 0x000000D0) -#define RKISP1_CIF_ISP_GAMMA_B_Y10 (RKISP1_CIF_ISP_BASE + 0x000000D4) -#define RKISP1_CIF_ISP_GAMMA_B_Y11 (RKISP1_CIF_ISP_BASE + 0x000000D8) -#define RKISP1_CIF_ISP_GAMMA_B_Y12 (RKISP1_CIF_ISP_BASE + 0x000000DC) -#define RKISP1_CIF_ISP_GAMMA_B_Y13 (RKISP1_CIF_ISP_BASE + 0x000000E0) -#define RKISP1_CIF_ISP_GAMMA_B_Y14 (RKISP1_CIF_ISP_BASE + 0x000000E4) -#define RKISP1_CIF_ISP_GAMMA_B_Y15 (RKISP1_CIF_ISP_BASE + 0x000000E8) -#define RKISP1_CIF_ISP_GAMMA_B_Y16 (RKISP1_CIF_ISP_BASE + 0x000000EC) +#define RKISP1_CIF_ISP_GAMMA_G_Y13 (RKISP1_CIF_ISP_BASE + 0x0000009c) +#define RKISP1_CIF_ISP_GAMMA_G_Y14 (RKISP1_CIF_ISP_BASE + 0x000000a0) +#define RKISP1_CIF_ISP_GAMMA_G_Y15 (RKISP1_CIF_ISP_BASE + 0x000000a4) +#define RKISP1_CIF_ISP_GAMMA_G_Y16 (RKISP1_CIF_ISP_BASE + 0x000000a8) +#define RKISP1_CIF_ISP_GAMMA_B_Y0 (RKISP1_CIF_ISP_BASE + 0x000000ac) +#define RKISP1_CIF_ISP_GAMMA_B_Y1 (RKISP1_CIF_ISP_BASE + 0x000000b0) +#define RKISP1_CIF_ISP_GAMMA_B_Y2 (RKISP1_CIF_ISP_BASE + 0x000000b4) +#define RKISP1_CIF_ISP_GAMMA_B_Y3 (RKISP1_CIF_ISP_BASE + 0x000000b8) +#define RKISP1_CIF_ISP_GAMMA_B_Y4 (RKISP1_CIF_ISP_BASE + 0x000000bc) +#define RKISP1_CIF_ISP_GAMMA_B_Y5 (RKISP1_CIF_ISP_BASE + 0x000000c0) +#define RKISP1_CIF_ISP_GAMMA_B_Y6 (RKISP1_CIF_ISP_BASE + 0x000000c4) +#define RKISP1_CIF_ISP_GAMMA_B_Y7 (RKISP1_CIF_ISP_BASE + 0x000000c8) +#define RKISP1_CIF_ISP_GAMMA_B_Y8 (RKISP1_CIF_ISP_BASE + 0x000000cc) +#define RKISP1_CIF_ISP_GAMMA_B_Y9 (RKISP1_CIF_ISP_BASE + 0x000000d0) +#define RKISP1_CIF_ISP_GAMMA_B_Y10 (RKISP1_CIF_ISP_BASE + 0x000000d4) +#define RKISP1_CIF_ISP_GAMMA_B_Y11 (RKISP1_CIF_ISP_BASE + 0x000000d8) +#define RKISP1_CIF_ISP_GAMMA_B_Y12 (RKISP1_CIF_ISP_BASE + 0x000000dc) +#define RKISP1_CIF_ISP_GAMMA_B_Y13 (RKISP1_CIF_ISP_BASE + 0x000000e0) +#define RKISP1_CIF_ISP_GAMMA_B_Y14 (RKISP1_CIF_ISP_BASE + 0x000000e4) +#define RKISP1_CIF_ISP_GAMMA_B_Y15 (RKISP1_CIF_ISP_BASE + 0x000000e8) +#define RKISP1_CIF_ISP_GAMMA_B_Y16 (RKISP1_CIF_ISP_BASE + 0x000000ec) #define RKISP1_CIF_ISP_AWB_PROP_V10 (RKISP1_CIF_ISP_BASE + 0x00000110) #define RKISP1_CIF_ISP_AWB_WND_H_OFFS_V10 (RKISP1_CIF_ISP_BASE + 0x00000114) #define RKISP1_CIF_ISP_AWB_WND_V_OFFS_V10 (RKISP1_CIF_ISP_BASE + 0x00000118) -#define RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10 (RKISP1_CIF_ISP_BASE + 0x0000011C) +#define RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10 (RKISP1_CIF_ISP_BASE + 0x0000011c) #define RKISP1_CIF_ISP_AWB_WND_V_SIZE_V10 (RKISP1_CIF_ISP_BASE + 0x00000120) #define RKISP1_CIF_ISP_AWB_FRAMES_V10 (RKISP1_CIF_ISP_BASE + 0x00000124) #define RKISP1_CIF_ISP_AWB_REF_V10 (RKISP1_CIF_ISP_BASE + 0x00000128) -#define RKISP1_CIF_ISP_AWB_THRESH_V10 (RKISP1_CIF_ISP_BASE + 0x0000012C) +#define RKISP1_CIF_ISP_AWB_THRESH_V10 (RKISP1_CIF_ISP_BASE + 0x0000012c) #define RKISP1_CIF_ISP_AWB_GAIN_G_V10 (RKISP1_CIF_ISP_BASE + 0x00000138) -#define RKISP1_CIF_ISP_AWB_GAIN_RB_V10 (RKISP1_CIF_ISP_BASE + 0x0000013C) +#define RKISP1_CIF_ISP_AWB_GAIN_RB_V10 (RKISP1_CIF_ISP_BASE + 0x0000013c) #define RKISP1_CIF_ISP_AWB_WHITE_CNT_V10 (RKISP1_CIF_ISP_BASE + 0x00000140) #define RKISP1_CIF_ISP_AWB_MEAN_V10 (RKISP1_CIF_ISP_BASE + 0x00000144) #define RKISP1_CIF_ISP_AWB_PROP_V12 (RKISP1_CIF_ISP_BASE + 0x00000110) #define RKISP1_CIF_ISP_AWB_SIZE_V12 (RKISP1_CIF_ISP_BASE + 0x00000114) #define RKISP1_CIF_ISP_AWB_OFFS_V12 (RKISP1_CIF_ISP_BASE + 0x00000118) -#define RKISP1_CIF_ISP_AWB_REF_V12 (RKISP1_CIF_ISP_BASE + 0x0000011C) +#define RKISP1_CIF_ISP_AWB_REF_V12 (RKISP1_CIF_ISP_BASE + 0x0000011c) #define RKISP1_CIF_ISP_AWB_THRESH_V12 (RKISP1_CIF_ISP_BASE + 0x00000120) #define RKISP1_CIF_ISP_X_COOR12_V12 (RKISP1_CIF_ISP_BASE + 0x00000124) #define RKISP1_CIF_ISP_X_COOR34_V12 (RKISP1_CIF_ISP_BASE + 0x00000128) -#define RKISP1_CIF_ISP_AWB_WHITE_CNT_V12 (RKISP1_CIF_ISP_BASE + 0x0000012C) +#define RKISP1_CIF_ISP_AWB_WHITE_CNT_V12 (RKISP1_CIF_ISP_BASE + 0x0000012c) #define RKISP1_CIF_ISP_AWB_MEAN_V12 (RKISP1_CIF_ISP_BASE + 0x00000130) #define RKISP1_CIF_ISP_DEGAIN_V12 (RKISP1_CIF_ISP_BASE + 0x00000134) #define RKISP1_CIF_ISP_AWB_GAIN_G_V12 (RKISP1_CIF_ISP_BASE + 0x00000138) -#define RKISP1_CIF_ISP_AWB_GAIN_RB_V12 (RKISP1_CIF_ISP_BASE + 0x0000013C) +#define RKISP1_CIF_ISP_AWB_GAIN_RB_V12 (RKISP1_CIF_ISP_BASE + 0x0000013c) #define RKISP1_CIF_ISP_REGION_LINE_V12 (RKISP1_CIF_ISP_BASE + 0x00000140) #define RKISP1_CIF_ISP_WP_CNT_REGION0_V12 (RKISP1_CIF_ISP_BASE + 0x00000160) #define RKISP1_CIF_ISP_WP_CNT_REGION1_V12 (RKISP1_CIF_ISP_BASE + 0x00000164) #define RKISP1_CIF_ISP_WP_CNT_REGION2_V12 (RKISP1_CIF_ISP_BASE + 0x00000168) -#define RKISP1_CIF_ISP_WP_CNT_REGION3_V12 (RKISP1_CIF_ISP_BASE + 0x0000016C) +#define RKISP1_CIF_ISP_WP_CNT_REGION3_V12 (RKISP1_CIF_ISP_BASE + 0x0000016c) #define RKISP1_CIF_ISP_CC_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x00000170) #define RKISP1_CIF_ISP_CC_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x00000174) #define RKISP1_CIF_ISP_CC_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x00000178) -#define RKISP1_CIF_ISP_CC_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x0000017C) +#define RKISP1_CIF_ISP_CC_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x0000017c) #define RKISP1_CIF_ISP_CC_COEFF_4 (RKISP1_CIF_ISP_BASE + 0x00000180) #define RKISP1_CIF_ISP_CC_COEFF_5 (RKISP1_CIF_ISP_BASE + 0x00000184) #define RKISP1_CIF_ISP_CC_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x00000188) -#define RKISP1_CIF_ISP_CC_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x0000018C) +#define RKISP1_CIF_ISP_CC_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x0000018c) #define RKISP1_CIF_ISP_CC_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x00000190) #define RKISP1_CIF_ISP_OUT_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000194) #define RKISP1_CIF_ISP_OUT_V_OFFS (RKISP1_CIF_ISP_BASE + 0x00000198) -#define RKISP1_CIF_ISP_OUT_H_SIZE (RKISP1_CIF_ISP_BASE + 0x0000019C) -#define RKISP1_CIF_ISP_OUT_V_SIZE (RKISP1_CIF_ISP_BASE + 0x000001A0) -#define RKISP1_CIF_ISP_DEMOSAIC (RKISP1_CIF_ISP_BASE + 0x000001A4) -#define RKISP1_CIF_ISP_FLAGS_SHD (RKISP1_CIF_ISP_BASE + 0x000001A8) -#define RKISP1_CIF_ISP_OUT_H_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001AC) -#define RKISP1_CIF_ISP_OUT_V_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001B0) -#define RKISP1_CIF_ISP_OUT_H_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001B4) -#define RKISP1_CIF_ISP_OUT_V_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001B8) -#define RKISP1_CIF_ISP_IMSC (RKISP1_CIF_ISP_BASE + 0x000001BC) -#define RKISP1_CIF_ISP_RIS (RKISP1_CIF_ISP_BASE + 0x000001C0) -#define RKISP1_CIF_ISP_MIS (RKISP1_CIF_ISP_BASE + 0x000001C4) -#define RKISP1_CIF_ISP_ICR (RKISP1_CIF_ISP_BASE + 0x000001C8) -#define RKISP1_CIF_ISP_ISR (RKISP1_CIF_ISP_BASE + 0x000001CC) -#define RKISP1_CIF_ISP_CT_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x000001D0) -#define RKISP1_CIF_ISP_CT_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x000001D4) -#define RKISP1_CIF_ISP_CT_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x000001D8) -#define RKISP1_CIF_ISP_CT_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x000001DC) -#define RKISP1_CIF_ISP_CT_COEFF_4 (RKISP1_CIF_ISP_BASE + 0x000001E0) -#define RKISP1_CIF_ISP_CT_COEFF_5 (RKISP1_CIF_ISP_BASE + 0x000001E4) -#define RKISP1_CIF_ISP_CT_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x000001E8) -#define RKISP1_CIF_ISP_CT_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x000001EC) -#define RKISP1_CIF_ISP_CT_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x000001F0) -#define RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10 (RKISP1_CIF_ISP_BASE + 0x000001F4) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 (RKISP1_CIF_ISP_BASE + 0x000001F8) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_1_V10 (RKISP1_CIF_ISP_BASE + 0x000001FC) +#define RKISP1_CIF_ISP_OUT_H_SIZE (RKISP1_CIF_ISP_BASE + 0x0000019c) +#define RKISP1_CIF_ISP_OUT_V_SIZE (RKISP1_CIF_ISP_BASE + 0x000001a0) +#define RKISP1_CIF_ISP_DEMOSAIC (RKISP1_CIF_ISP_BASE + 0x000001a4) +#define RKISP1_CIF_ISP_FLAGS_SHD (RKISP1_CIF_ISP_BASE + 0x000001a8) +#define RKISP1_CIF_ISP_OUT_H_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001ac) +#define RKISP1_CIF_ISP_OUT_V_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001b0) +#define RKISP1_CIF_ISP_OUT_H_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001b4) +#define RKISP1_CIF_ISP_OUT_V_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001b8) +#define RKISP1_CIF_ISP_IMSC (RKISP1_CIF_ISP_BASE + 0x000001bc) +#define RKISP1_CIF_ISP_RIS (RKISP1_CIF_ISP_BASE + 0x000001c0) +#define RKISP1_CIF_ISP_MIS (RKISP1_CIF_ISP_BASE + 0x000001c4) +#define RKISP1_CIF_ISP_ICR (RKISP1_CIF_ISP_BASE + 0x000001c8) +#define RKISP1_CIF_ISP_ISR (RKISP1_CIF_ISP_BASE + 0x000001cc) +#define RKISP1_CIF_ISP_CT_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x000001d0) +#define RKISP1_CIF_ISP_CT_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x000001d4) +#define RKISP1_CIF_ISP_CT_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x000001d8) +#define RKISP1_CIF_ISP_CT_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x000001dc) +#define RKISP1_CIF_ISP_CT_COEFF_4 (RKISP1_CIF_ISP_BASE + 0x000001e0) +#define RKISP1_CIF_ISP_CT_COEFF_5 (RKISP1_CIF_ISP_BASE + 0x000001e4) +#define RKISP1_CIF_ISP_CT_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x000001e8) +#define RKISP1_CIF_ISP_CT_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x000001ec) +#define RKISP1_CIF_ISP_CT_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x000001f0) +#define RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10 (RKISP1_CIF_ISP_BASE + 0x000001f4) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 (RKISP1_CIF_ISP_BASE + 0x000001f8) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_1_V10 (RKISP1_CIF_ISP_BASE + 0x000001fc) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_2_V10 (RKISP1_CIF_ISP_BASE + 0x00000200) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_3_V10 (RKISP1_CIF_ISP_BASE + 0x00000204) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_4_V10 (RKISP1_CIF_ISP_BASE + 0x00000208) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_5_V10 (RKISP1_CIF_ISP_BASE + 0x0000020C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_5_V10 (RKISP1_CIF_ISP_BASE + 0x0000020c) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_6_V10 (RKISP1_CIF_ISP_BASE + 0x00000210) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_7_V10 (RKISP1_CIF_ISP_BASE + 0x00000214) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_8_V10 (RKISP1_CIF_ISP_BASE + 0x00000218) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_9_V10 (RKISP1_CIF_ISP_BASE + 0x0000021C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_9_V10 (RKISP1_CIF_ISP_BASE + 0x0000021c) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_10_V10 (RKISP1_CIF_ISP_BASE + 0x00000220) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_11_V10 (RKISP1_CIF_ISP_BASE + 0x00000224) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_12_V10 (RKISP1_CIF_ISP_BASE + 0x00000228) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_13_V10 (RKISP1_CIF_ISP_BASE + 0x0000022C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_13_V10 (RKISP1_CIF_ISP_BASE + 0x0000022c) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_14_V10 (RKISP1_CIF_ISP_BASE + 0x00000230) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_15_V10 (RKISP1_CIF_ISP_BASE + 0x00000234) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_16_V10 (RKISP1_CIF_ISP_BASE + 0x00000238) -#define RKISP1_CIF_ISP_ERR (RKISP1_CIF_ISP_BASE + 0x0000023C) +#define RKISP1_CIF_ISP_ERR (RKISP1_CIF_ISP_BASE + 0x0000023c) #define RKISP1_CIF_ISP_ERR_CLR (RKISP1_CIF_ISP_BASE + 0x00000240) #define RKISP1_CIF_ISP_FRAME_COUNT (RKISP1_CIF_ISP_BASE + 0x00000244) #define RKISP1_CIF_ISP_CT_OFFSET_R (RKISP1_CIF_ISP_BASE + 0x00000248) -#define RKISP1_CIF_ISP_CT_OFFSET_G (RKISP1_CIF_ISP_BASE + 0x0000024C) +#define RKISP1_CIF_ISP_CT_OFFSET_G (RKISP1_CIF_ISP_BASE + 0x0000024c) #define RKISP1_CIF_ISP_CT_OFFSET_B (RKISP1_CIF_ISP_BASE + 0x00000250) #define RKISP1_CIF_ISP_GAMMA_OUT_MODE_V12 (RKISP1_CIF_ISP_BASE + 0x00000300) #define RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V12 (RKISP1_CIF_ISP_BASE + 0x00000304) @@ -865,7 +865,7 @@ #define RKISP1_CIF_ISP_FLASH_CMD (RKISP1_CIF_ISP_FLASH_BASE + 0x00000000) #define RKISP1_CIF_ISP_FLASH_CONFIG (RKISP1_CIF_ISP_FLASH_BASE + 0x00000004) #define RKISP1_CIF_ISP_FLASH_PREDIV (RKISP1_CIF_ISP_FLASH_BASE + 0x00000008) -#define RKISP1_CIF_ISP_FLASH_DELAY (RKISP1_CIF_ISP_FLASH_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_FLASH_DELAY (RKISP1_CIF_ISP_FLASH_BASE + 0x0000000c) #define RKISP1_CIF_ISP_FLASH_TIME (RKISP1_CIF_ISP_FLASH_BASE + 0x00000010) #define RKISP1_CIF_ISP_FLASH_MAXP (RKISP1_CIF_ISP_FLASH_BASE + 0x00000014) @@ -873,56 +873,56 @@ #define RKISP1_CIF_ISP_SH_CTRL (RKISP1_CIF_ISP_SH_BASE + 0x00000000) #define RKISP1_CIF_ISP_SH_PREDIV (RKISP1_CIF_ISP_SH_BASE + 0x00000004) #define RKISP1_CIF_ISP_SH_DELAY (RKISP1_CIF_ISP_SH_BASE + 0x00000008) -#define RKISP1_CIF_ISP_SH_TIME (RKISP1_CIF_ISP_SH_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_SH_TIME (RKISP1_CIF_ISP_SH_BASE + 0x0000000c) #define RKISP1_CIF_C_PROC_BASE 0x00000800 #define RKISP1_CIF_C_PROC_CTRL (RKISP1_CIF_C_PROC_BASE + 0x00000000) #define RKISP1_CIF_C_PROC_CONTRAST (RKISP1_CIF_C_PROC_BASE + 0x00000004) #define RKISP1_CIF_C_PROC_BRIGHTNESS (RKISP1_CIF_C_PROC_BASE + 0x00000008) -#define RKISP1_CIF_C_PROC_SATURATION (RKISP1_CIF_C_PROC_BASE + 0x0000000C) +#define RKISP1_CIF_C_PROC_SATURATION (RKISP1_CIF_C_PROC_BASE + 0x0000000c) #define RKISP1_CIF_C_PROC_HUE (RKISP1_CIF_C_PROC_BASE + 0x00000010) #define RKISP1_CIF_DUAL_CROP_BASE 0x00000880 #define RKISP1_CIF_DUAL_CROP_CTRL (RKISP1_CIF_DUAL_CROP_BASE + 0x00000000) #define RKISP1_CIF_DUAL_CROP_M_H_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000004) #define RKISP1_CIF_DUAL_CROP_M_V_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000008) -#define RKISP1_CIF_DUAL_CROP_M_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000000C) +#define RKISP1_CIF_DUAL_CROP_M_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000000c) #define RKISP1_CIF_DUAL_CROP_M_V_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x00000010) #define RKISP1_CIF_DUAL_CROP_S_H_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000014) #define RKISP1_CIF_DUAL_CROP_S_V_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000018) -#define RKISP1_CIF_DUAL_CROP_S_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000001C) +#define RKISP1_CIF_DUAL_CROP_S_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000001c) #define RKISP1_CIF_DUAL_CROP_S_V_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x00000020) #define RKISP1_CIF_DUAL_CROP_M_H_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000024) #define RKISP1_CIF_DUAL_CROP_M_V_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000028) -#define RKISP1_CIF_DUAL_CROP_M_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000002C) +#define RKISP1_CIF_DUAL_CROP_M_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000002c) #define RKISP1_CIF_DUAL_CROP_M_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000030) #define RKISP1_CIF_DUAL_CROP_S_H_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000034) #define RKISP1_CIF_DUAL_CROP_S_V_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000038) -#define RKISP1_CIF_DUAL_CROP_S_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000003C) +#define RKISP1_CIF_DUAL_CROP_S_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000003c) #define RKISP1_CIF_DUAL_CROP_S_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000040) -#define RKISP1_CIF_MRSZ_BASE 0x00000C00 +#define RKISP1_CIF_MRSZ_BASE 0x00000c00 #define RKISP1_CIF_SRSZ_BASE 0x00001000 #define RKISP1_CIF_RSZ_CTRL 0x0000 #define RKISP1_CIF_RSZ_SCALE_HY 0x0004 #define RKISP1_CIF_RSZ_SCALE_HCB 0x0008 -#define RKISP1_CIF_RSZ_SCALE_HCR 0x000C +#define RKISP1_CIF_RSZ_SCALE_HCR 0x000c #define RKISP1_CIF_RSZ_SCALE_VY 0x0010 #define RKISP1_CIF_RSZ_SCALE_VC 0x0014 #define RKISP1_CIF_RSZ_PHASE_HY 0x0018 -#define RKISP1_CIF_RSZ_PHASE_HC 0x001C +#define RKISP1_CIF_RSZ_PHASE_HC 0x001c #define RKISP1_CIF_RSZ_PHASE_VY 0x0020 #define RKISP1_CIF_RSZ_PHASE_VC 0x0024 #define RKISP1_CIF_RSZ_SCALE_LUT_ADDR 0x0028 -#define RKISP1_CIF_RSZ_SCALE_LUT 0x002C +#define RKISP1_CIF_RSZ_SCALE_LUT 0x002c #define RKISP1_CIF_RSZ_CTRL_SHD 0x0030 #define RKISP1_CIF_RSZ_SCALE_HY_SHD 0x0034 #define RKISP1_CIF_RSZ_SCALE_HCB_SHD 0x0038 -#define RKISP1_CIF_RSZ_SCALE_HCR_SHD 0x003C +#define RKISP1_CIF_RSZ_SCALE_HCR_SHD 0x003c #define RKISP1_CIF_RSZ_SCALE_VY_SHD 0x0040 #define RKISP1_CIF_RSZ_SCALE_VC_SHD 0x0044 #define RKISP1_CIF_RSZ_PHASE_HY_SHD 0x0048 -#define RKISP1_CIF_RSZ_PHASE_HC_SHD 0x004C +#define RKISP1_CIF_RSZ_PHASE_HC_SHD 0x004c #define RKISP1_CIF_RSZ_PHASE_VY_SHD 0x0050 #define RKISP1_CIF_RSZ_PHASE_VC_SHD 0x0054 @@ -930,89 +930,89 @@ #define RKISP1_CIF_MI_CTRL (RKISP1_CIF_MI_BASE + 0x00000000) #define RKISP1_CIF_MI_INIT (RKISP1_CIF_MI_BASE + 0x00000004) #define RKISP1_CIF_MI_MP_Y_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000008) -#define RKISP1_CIF_MI_MP_Y_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x0000000C) +#define RKISP1_CIF_MI_MP_Y_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x0000000c) #define RKISP1_CIF_MI_MP_Y_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000010) #define RKISP1_CIF_MI_MP_Y_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000014) #define RKISP1_CIF_MI_MP_Y_IRQ_OFFS_INIT (RKISP1_CIF_MI_BASE + 0x00000018) -#define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000001C) +#define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000001c) #define RKISP1_CIF_MI_MP_CB_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000020) #define RKISP1_CIF_MI_MP_CB_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000024) #define RKISP1_CIF_MI_MP_CB_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000028) -#define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000002C) +#define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000002c) #define RKISP1_CIF_MI_MP_CR_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000030) #define RKISP1_CIF_MI_MP_CR_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000034) #define RKISP1_CIF_MI_MP_CR_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000038) -#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000003C) +#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000003c) #define RKISP1_CIF_MI_SP_Y_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000040) #define RKISP1_CIF_MI_SP_Y_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000044) #define RKISP1_CIF_MI_SP_Y_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000048) -#define RKISP1_CIF_MI_SP_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x0000004C) +#define RKISP1_CIF_MI_SP_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x0000004c) #define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000050) #define RKISP1_CIF_MI_SP_CB_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000054) #define RKISP1_CIF_MI_SP_CB_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000058) -#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000005C) +#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000005c) #define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000060) #define RKISP1_CIF_MI_SP_CR_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000064) #define RKISP1_CIF_MI_SP_CR_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000068) -#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000006C) +#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000006c) #define RKISP1_CIF_MI_BYTE_CNT (RKISP1_CIF_MI_BASE + 0x00000070) #define RKISP1_CIF_MI_CTRL_SHD (RKISP1_CIF_MI_BASE + 0x00000074) #define RKISP1_CIF_MI_MP_Y_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000078) -#define RKISP1_CIF_MI_MP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000007C) +#define RKISP1_CIF_MI_MP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000007c) #define RKISP1_CIF_MI_MP_Y_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x00000080) #define RKISP1_CIF_MI_MP_Y_IRQ_OFFS_SHD (RKISP1_CIF_MI_BASE + 0x00000084) #define RKISP1_CIF_MI_MP_CB_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000088) -#define RKISP1_CIF_MI_MP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000008C) +#define RKISP1_CIF_MI_MP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000008c) #define RKISP1_CIF_MI_MP_CB_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x00000090) #define RKISP1_CIF_MI_MP_CR_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000094) #define RKISP1_CIF_MI_MP_CR_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x00000098) -#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x0000009C) -#define RKISP1_CIF_MI_SP_Y_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000A0) -#define RKISP1_CIF_MI_SP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000A4) -#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000A8) -#define RKISP1_CIF_MI_SP_CB_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000B0) -#define RKISP1_CIF_MI_SP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000B4) -#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000B8) -#define RKISP1_CIF_MI_SP_CR_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000BC) -#define RKISP1_CIF_MI_SP_CR_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000C0) -#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000C4) -#define RKISP1_CIF_MI_DMA_Y_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000C8) -#define RKISP1_CIF_MI_DMA_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x000000CC) -#define RKISP1_CIF_MI_DMA_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x000000D0) -#define RKISP1_CIF_MI_DMA_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x000000D4) -#define RKISP1_CIF_MI_DMA_CB_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000D8) -#define RKISP1_CIF_MI_DMA_CR_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000E8) -#define RKISP1_CIF_MI_IMSC (RKISP1_CIF_MI_BASE + 0x000000F8) -#define RKISP1_CIF_MI_RIS (RKISP1_CIF_MI_BASE + 0x000000FC) +#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x0000009c) +#define RKISP1_CIF_MI_SP_Y_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000a0) +#define RKISP1_CIF_MI_SP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000a4) +#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000a8) +#define RKISP1_CIF_MI_SP_CB_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000b0) +#define RKISP1_CIF_MI_SP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000b4) +#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000b8) +#define RKISP1_CIF_MI_SP_CR_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000bc) +#define RKISP1_CIF_MI_SP_CR_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000c0) +#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000c4) +#define RKISP1_CIF_MI_DMA_Y_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000c8) +#define RKISP1_CIF_MI_DMA_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x000000cc) +#define RKISP1_CIF_MI_DMA_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x000000d0) +#define RKISP1_CIF_MI_DMA_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x000000d4) +#define RKISP1_CIF_MI_DMA_CB_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000d8) +#define RKISP1_CIF_MI_DMA_CR_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000e8) +#define RKISP1_CIF_MI_IMSC (RKISP1_CIF_MI_BASE + 0x000000f8) +#define RKISP1_CIF_MI_RIS (RKISP1_CIF_MI_BASE + 0x000000fc) #define RKISP1_CIF_MI_MIS (RKISP1_CIF_MI_BASE + 0x00000100) #define RKISP1_CIF_MI_ICR (RKISP1_CIF_MI_BASE + 0x00000104) #define RKISP1_CIF_MI_ISR (RKISP1_CIF_MI_BASE + 0x00000108) -#define RKISP1_CIF_MI_STATUS (RKISP1_CIF_MI_BASE + 0x0000010C) +#define RKISP1_CIF_MI_STATUS (RKISP1_CIF_MI_BASE + 0x0000010c) #define RKISP1_CIF_MI_STATUS_CLR (RKISP1_CIF_MI_BASE + 0x00000110) #define RKISP1_CIF_MI_SP_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x00000114) #define RKISP1_CIF_MI_SP_Y_PIC_HEIGHT (RKISP1_CIF_MI_BASE + 0x00000118) -#define RKISP1_CIF_MI_SP_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x0000011C) +#define RKISP1_CIF_MI_SP_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x0000011c) #define RKISP1_CIF_MI_DMA_CTRL (RKISP1_CIF_MI_BASE + 0x00000120) #define RKISP1_CIF_MI_DMA_START (RKISP1_CIF_MI_BASE + 0x00000124) #define RKISP1_CIF_MI_DMA_STATUS (RKISP1_CIF_MI_BASE + 0x00000128) -#define RKISP1_CIF_MI_PIXEL_COUNT (RKISP1_CIF_MI_BASE + 0x0000012C) +#define RKISP1_CIF_MI_PIXEL_COUNT (RKISP1_CIF_MI_BASE + 0x0000012c) #define RKISP1_CIF_MI_MP_Y_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000130) #define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000134) #define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000138) -#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x0000013C) +#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x0000013c) #define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000140) #define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000144) #define RKISP1_CIF_MI_XTD_FORMAT_CTRL (RKISP1_CIF_MI_BASE + 0x00000148) -#define RKISP1_CIF_SMIA_BASE 0x00001A00 +#define RKISP1_CIF_SMIA_BASE 0x00001a00 #define RKISP1_CIF_SMIA_CTRL (RKISP1_CIF_SMIA_BASE + 0x00000000) #define RKISP1_CIF_SMIA_STATUS (RKISP1_CIF_SMIA_BASE + 0x00000004) #define RKISP1_CIF_SMIA_IMSC (RKISP1_CIF_SMIA_BASE + 0x00000008) -#define RKISP1_CIF_SMIA_RIS (RKISP1_CIF_SMIA_BASE + 0x0000000C) +#define RKISP1_CIF_SMIA_RIS (RKISP1_CIF_SMIA_BASE + 0x0000000c) #define RKISP1_CIF_SMIA_MIS (RKISP1_CIF_SMIA_BASE + 0x00000010) #define RKISP1_CIF_SMIA_ICR (RKISP1_CIF_SMIA_BASE + 0x00000014) #define RKISP1_CIF_SMIA_ISR (RKISP1_CIF_SMIA_BASE + 0x00000018) -#define RKISP1_CIF_SMIA_DATA_FORMAT_SEL (RKISP1_CIF_SMIA_BASE + 0x0000001C) +#define RKISP1_CIF_SMIA_DATA_FORMAT_SEL (RKISP1_CIF_SMIA_BASE + 0x0000001c) #define RKISP1_CIF_SMIA_SOF_EMB_DATA_LINES (RKISP1_CIF_SMIA_BASE + 0x00000020) #define RKISP1_CIF_SMIA_EMB_HSTART (RKISP1_CIF_SMIA_BASE + 0x00000024) #define RKISP1_CIF_SMIA_EMB_HSIZE (RKISP1_CIF_SMIA_BASE + 0x00000028) @@ -1021,27 +1021,27 @@ #define RKISP1_CIF_SMIA_EMB_DATA_FIFO (RKISP1_CIF_SMIA_BASE + 0x00000034) #define RKISP1_CIF_SMIA_EMB_DATA_WATERMARK (RKISP1_CIF_SMIA_BASE + 0x00000038) -#define RKISP1_CIF_MIPI_BASE 0x00001C00 +#define RKISP1_CIF_MIPI_BASE 0x00001c00 #define RKISP1_CIF_MIPI_CTRL (RKISP1_CIF_MIPI_BASE + 0x00000000) #define RKISP1_CIF_MIPI_STATUS (RKISP1_CIF_MIPI_BASE + 0x00000004) #define RKISP1_CIF_MIPI_IMSC (RKISP1_CIF_MIPI_BASE + 0x00000008) -#define RKISP1_CIF_MIPI_RIS (RKISP1_CIF_MIPI_BASE + 0x0000000C) +#define RKISP1_CIF_MIPI_RIS (RKISP1_CIF_MIPI_BASE + 0x0000000c) #define RKISP1_CIF_MIPI_MIS (RKISP1_CIF_MIPI_BASE + 0x00000010) #define RKISP1_CIF_MIPI_ICR (RKISP1_CIF_MIPI_BASE + 0x00000014) #define RKISP1_CIF_MIPI_ISR (RKISP1_CIF_MIPI_BASE + 0x00000018) -#define RKISP1_CIF_MIPI_CUR_DATA_ID (RKISP1_CIF_MIPI_BASE + 0x0000001C) +#define RKISP1_CIF_MIPI_CUR_DATA_ID (RKISP1_CIF_MIPI_BASE + 0x0000001c) #define RKISP1_CIF_MIPI_IMG_DATA_SEL (RKISP1_CIF_MIPI_BASE + 0x00000020) #define RKISP1_CIF_MIPI_ADD_DATA_SEL_1 (RKISP1_CIF_MIPI_BASE + 0x00000024) #define RKISP1_CIF_MIPI_ADD_DATA_SEL_2 (RKISP1_CIF_MIPI_BASE + 0x00000028) -#define RKISP1_CIF_MIPI_ADD_DATA_SEL_3 (RKISP1_CIF_MIPI_BASE + 0x0000002C) +#define RKISP1_CIF_MIPI_ADD_DATA_SEL_3 (RKISP1_CIF_MIPI_BASE + 0x0000002c) #define RKISP1_CIF_MIPI_ADD_DATA_SEL_4 (RKISP1_CIF_MIPI_BASE + 0x00000030) #define RKISP1_CIF_MIPI_ADD_DATA_FIFO (RKISP1_CIF_MIPI_BASE + 0x00000034) #define RKISP1_CIF_MIPI_FIFO_FILL_LEVEL (RKISP1_CIF_MIPI_BASE + 0x00000038) -#define RKISP1_CIF_MIPI_COMPRESSED_MODE (RKISP1_CIF_MIPI_BASE + 0x0000003C) +#define RKISP1_CIF_MIPI_COMPRESSED_MODE (RKISP1_CIF_MIPI_BASE + 0x0000003c) #define RKISP1_CIF_MIPI_FRAME (RKISP1_CIF_MIPI_BASE + 0x00000040) #define RKISP1_CIF_MIPI_GEN_SHORT_DT (RKISP1_CIF_MIPI_BASE + 0x00000044) #define RKISP1_CIF_MIPI_GEN_SHORT_8_9 (RKISP1_CIF_MIPI_BASE + 0x00000048) -#define RKISP1_CIF_MIPI_GEN_SHORT_A_B (RKISP1_CIF_MIPI_BASE + 0x0000004C) +#define RKISP1_CIF_MIPI_GEN_SHORT_A_B (RKISP1_CIF_MIPI_BASE + 0x0000004c) #define RKISP1_CIF_MIPI_GEN_SHORT_C_D (RKISP1_CIF_MIPI_BASE + 0x00000050) #define RKISP1_CIF_MIPI_GEN_SHORT_E_F (RKISP1_CIF_MIPI_BASE + 0x00000054) @@ -1049,15 +1049,15 @@ #define RKISP1_CIF_ISP_AFM_CTRL (RKISP1_CIF_ISP_AFM_BASE + 0x00000000) #define RKISP1_CIF_ISP_AFM_LT_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000004) #define RKISP1_CIF_ISP_AFM_RB_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000008) -#define RKISP1_CIF_ISP_AFM_LT_B (RKISP1_CIF_ISP_AFM_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_AFM_LT_B (RKISP1_CIF_ISP_AFM_BASE + 0x0000000c) #define RKISP1_CIF_ISP_AFM_RB_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000010) #define RKISP1_CIF_ISP_AFM_LT_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000014) #define RKISP1_CIF_ISP_AFM_RB_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000018) -#define RKISP1_CIF_ISP_AFM_THRES (RKISP1_CIF_ISP_AFM_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_AFM_THRES (RKISP1_CIF_ISP_AFM_BASE + 0x0000001c) #define RKISP1_CIF_ISP_AFM_VAR_SHIFT (RKISP1_CIF_ISP_AFM_BASE + 0x00000020) #define RKISP1_CIF_ISP_AFM_SUM_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000024) #define RKISP1_CIF_ISP_AFM_SUM_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000028) -#define RKISP1_CIF_ISP_AFM_SUM_C (RKISP1_CIF_ISP_AFM_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_AFM_SUM_C (RKISP1_CIF_ISP_AFM_BASE + 0x0000002c) #define RKISP1_CIF_ISP_AFM_LUM_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000030) #define RKISP1_CIF_ISP_AFM_LUM_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000034) #define RKISP1_CIF_ISP_AFM_LUM_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000038) @@ -1066,11 +1066,11 @@ #define RKISP1_CIF_ISP_LSC_CTRL (RKISP1_CIF_ISP_LSC_BASE + 0x00000000) #define RKISP1_CIF_ISP_LSC_R_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000004) #define RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000008) -#define RKISP1_CIF_ISP_LSC_B_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_LSC_B_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x0000000c) #define RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000010) #define RKISP1_CIF_ISP_LSC_R_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000014) #define RKISP1_CIF_ISP_LSC_GR_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000018) -#define RKISP1_CIF_ISP_LSC_B_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_LSC_B_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x0000001c) #define RKISP1_CIF_ISP_LSC_GB_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000020) #define RKISP1_CIF_ISP_LSC_XGRAD(n) (RKISP1_CIF_ISP_LSC_BASE + 0x00000024 + (n) * 4) #define RKISP1_CIF_ISP_LSC_YGRAD(n) (RKISP1_CIF_ISP_LSC_BASE + 0x00000034 + (n) * 4) @@ -1083,46 +1083,46 @@ #define RKISP1_CIF_ISP_IS_CTRL (RKISP1_CIF_ISP_IS_BASE + 0x00000000) #define RKISP1_CIF_ISP_IS_RECENTER (RKISP1_CIF_ISP_IS_BASE + 0x00000004) #define RKISP1_CIF_ISP_IS_H_OFFS (RKISP1_CIF_ISP_IS_BASE + 0x00000008) -#define RKISP1_CIF_ISP_IS_V_OFFS (RKISP1_CIF_ISP_IS_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_IS_V_OFFS (RKISP1_CIF_ISP_IS_BASE + 0x0000000c) #define RKISP1_CIF_ISP_IS_H_SIZE (RKISP1_CIF_ISP_IS_BASE + 0x00000010) #define RKISP1_CIF_ISP_IS_V_SIZE (RKISP1_CIF_ISP_IS_BASE + 0x00000014) #define RKISP1_CIF_ISP_IS_MAX_DX (RKISP1_CIF_ISP_IS_BASE + 0x00000018) -#define RKISP1_CIF_ISP_IS_MAX_DY (RKISP1_CIF_ISP_IS_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_IS_MAX_DY (RKISP1_CIF_ISP_IS_BASE + 0x0000001c) #define RKISP1_CIF_ISP_IS_DISPLACE (RKISP1_CIF_ISP_IS_BASE + 0x00000020) #define RKISP1_CIF_ISP_IS_H_OFFS_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000024) #define RKISP1_CIF_ISP_IS_V_OFFS_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000028) -#define RKISP1_CIF_ISP_IS_H_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_IS_H_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x0000002c) #define RKISP1_CIF_ISP_IS_V_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000030) #define RKISP1_CIF_ISP_HIST_BASE_V10 0x00002400 #define RKISP1_CIF_ISP_HIST_PROP_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000000) #define RKISP1_CIF_ISP_HIST_H_OFFS_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000004) #define RKISP1_CIF_ISP_HIST_V_OFFS_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000008) -#define RKISP1_CIF_ISP_HIST_H_SIZE_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000000C) +#define RKISP1_CIF_ISP_HIST_H_SIZE_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000000c) #define RKISP1_CIF_ISP_HIST_V_SIZE_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000010) #define RKISP1_CIF_ISP_HIST_BIN_0_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000014) #define RKISP1_CIF_ISP_HIST_BIN_1_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000018) -#define RKISP1_CIF_ISP_HIST_BIN_2_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000001C) +#define RKISP1_CIF_ISP_HIST_BIN_2_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000001c) #define RKISP1_CIF_ISP_HIST_BIN_3_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000020) #define RKISP1_CIF_ISP_HIST_BIN_4_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000024) #define RKISP1_CIF_ISP_HIST_BIN_5_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000028) -#define RKISP1_CIF_ISP_HIST_BIN_6_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000002C) +#define RKISP1_CIF_ISP_HIST_BIN_6_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000002c) #define RKISP1_CIF_ISP_HIST_BIN_7_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000030) #define RKISP1_CIF_ISP_HIST_BIN_8_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000034) #define RKISP1_CIF_ISP_HIST_BIN_9_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000038) -#define RKISP1_CIF_ISP_HIST_BIN_10_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000003C) +#define RKISP1_CIF_ISP_HIST_BIN_10_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000003c) #define RKISP1_CIF_ISP_HIST_BIN_11_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000040) #define RKISP1_CIF_ISP_HIST_BIN_12_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000044) #define RKISP1_CIF_ISP_HIST_BIN_13_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000048) -#define RKISP1_CIF_ISP_HIST_BIN_14_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000004C) +#define RKISP1_CIF_ISP_HIST_BIN_14_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000004c) #define RKISP1_CIF_ISP_HIST_BIN_15_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000050) #define RKISP1_CIF_ISP_HIST_WEIGHT_00TO30_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000054) #define RKISP1_CIF_ISP_HIST_WEIGHT_40TO21_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000058) -#define RKISP1_CIF_ISP_HIST_WEIGHT_31TO12_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000005C) +#define RKISP1_CIF_ISP_HIST_WEIGHT_31TO12_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000005c) #define RKISP1_CIF_ISP_HIST_WEIGHT_22TO03_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000060) #define RKISP1_CIF_ISP_HIST_WEIGHT_13TO43_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000064) #define RKISP1_CIF_ISP_HIST_WEIGHT_04TO34_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x00000068) -#define RKISP1_CIF_ISP_HIST_WEIGHT_44_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000006C) +#define RKISP1_CIF_ISP_HIST_WEIGHT_44_V10 (RKISP1_CIF_ISP_HIST_BASE_V10 + 0x0000006c) #define RKISP1_CIF_ISP_FILT_BASE 0x00002500 #define RKISP1_CIF_ISP_FILT_MODE (RKISP1_CIF_ISP_FILT_BASE + 0x00000000) @@ -1135,13 +1135,13 @@ #define RKISP1_CIF_ISP_FILT_FAC_SH0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000040) #define RKISP1_CIF_ISP_FILT_FAC_MID (RKISP1_CIF_ISP_FILT_BASE + 0x00000044) #define RKISP1_CIF_ISP_FILT_FAC_BL0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000048) -#define RKISP1_CIF_ISP_FILT_FAC_BL1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_FILT_FAC_BL1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000004c) #define RKISP1_CIF_ISP_CAC_BASE 0x00002580 #define RKISP1_CIF_ISP_CAC_CTRL (RKISP1_CIF_ISP_CAC_BASE + 0x00000000) #define RKISP1_CIF_ISP_CAC_COUNT_START (RKISP1_CIF_ISP_CAC_BASE + 0x00000004) #define RKISP1_CIF_ISP_CAC_A (RKISP1_CIF_ISP_CAC_BASE + 0x00000008) -#define RKISP1_CIF_ISP_CAC_B (RKISP1_CIF_ISP_CAC_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_CAC_B (RKISP1_CIF_ISP_CAC_BASE + 0x0000000c) #define RKISP1_CIF_ISP_CAC_C (RKISP1_CIF_ISP_CAC_BASE + 0x00000010) #define RKISP1_CIF_ISP_X_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000014) #define RKISP1_CIF_ISP_Y_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000018) @@ -1150,7 +1150,7 @@ #define RKISP1_CIF_ISP_EXP_CTRL (RKISP1_CIF_ISP_EXP_BASE + 0x00000000) #define RKISP1_CIF_ISP_EXP_H_OFFSET_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000004) #define RKISP1_CIF_ISP_EXP_V_OFFSET_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000008) -#define RKISP1_CIF_ISP_EXP_H_SIZE_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_EXP_H_SIZE_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x0000000c) #define RKISP1_CIF_ISP_EXP_V_SIZE_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000010) #define RKISP1_CIF_ISP_EXP_MEAN_00_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000014) #define RKISP1_CIF_ISP_EXP_MEAN_10_V10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000018) @@ -1205,160 +1205,160 @@ #define RKISP1_CIF_ISP_DPF_MODE (RKISP1_CIF_ISP_DPF_BASE + 0x00000000) #define RKISP1_CIF_ISP_DPF_STRENGTH_R (RKISP1_CIF_ISP_DPF_BASE + 0x00000004) #define RKISP1_CIF_ISP_DPF_STRENGTH_G (RKISP1_CIF_ISP_DPF_BASE + 0x00000008) -#define RKISP1_CIF_ISP_DPF_STRENGTH_B (RKISP1_CIF_ISP_DPF_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_DPF_STRENGTH_B (RKISP1_CIF_ISP_DPF_BASE + 0x0000000c) #define RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000010) #define RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6 (RKISP1_CIF_ISP_DPF_BASE + 0x00000014) #define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000018) -#define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6 (RKISP1_CIF_ISP_DPF_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6 (RKISP1_CIF_ISP_DPF_BASE + 0x0000001c) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_0 (RKISP1_CIF_ISP_DPF_BASE + 0x00000020) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_1 (RKISP1_CIF_ISP_DPF_BASE + 0x00000024) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_2 (RKISP1_CIF_ISP_DPF_BASE + 0x00000028) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_3 (RKISP1_CIF_ISP_DPF_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_3 (RKISP1_CIF_ISP_DPF_BASE + 0x0000002c) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000030) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_5 (RKISP1_CIF_ISP_DPF_BASE + 0x00000034) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_6 (RKISP1_CIF_ISP_DPF_BASE + 0x00000038) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_7 (RKISP1_CIF_ISP_DPF_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_7 (RKISP1_CIF_ISP_DPF_BASE + 0x0000003c) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_8 (RKISP1_CIF_ISP_DPF_BASE + 0x00000040) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_9 (RKISP1_CIF_ISP_DPF_BASE + 0x00000044) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_10 (RKISP1_CIF_ISP_DPF_BASE + 0x00000048) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_11 (RKISP1_CIF_ISP_DPF_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_11 (RKISP1_CIF_ISP_DPF_BASE + 0x0000004c) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_12 (RKISP1_CIF_ISP_DPF_BASE + 0x00000050) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_13 (RKISP1_CIF_ISP_DPF_BASE + 0x00000054) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_14 (RKISP1_CIF_ISP_DPF_BASE + 0x00000058) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_15 (RKISP1_CIF_ISP_DPF_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_15 (RKISP1_CIF_ISP_DPF_BASE + 0x0000005c) #define RKISP1_CIF_ISP_DPF_NULL_COEFF_16 (RKISP1_CIF_ISP_DPF_BASE + 0x00000060) #define RKISP1_CIF_ISP_DPF_NF_GAIN_R (RKISP1_CIF_ISP_DPF_BASE + 0x00000064) #define RKISP1_CIF_ISP_DPF_NF_GAIN_GR (RKISP1_CIF_ISP_DPF_BASE + 0x00000068) -#define RKISP1_CIF_ISP_DPF_NF_GAIN_GB (RKISP1_CIF_ISP_DPF_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_DPF_NF_GAIN_GB (RKISP1_CIF_ISP_DPF_BASE + 0x0000006c) #define RKISP1_CIF_ISP_DPF_NF_GAIN_B (RKISP1_CIF_ISP_DPF_BASE + 0x00000070) #define RKISP1_CIF_ISP_DPCC_BASE 0x00002900 #define RKISP1_CIF_ISP_DPCC_MODE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000000) #define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000004) #define RKISP1_CIF_ISP_DPCC_SET_USE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000008) -#define RKISP1_CIF_ISP_DPCC_METHODS_SET_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000000c) #define RKISP1_CIF_ISP_DPCC_METHODS_SET_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000010) #define RKISP1_CIF_ISP_DPCC_METHODS_SET_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000014) #define RKISP1_CIF_ISP_DPCC_LINE_THRESH_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000018) -#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000001c) #define RKISP1_CIF_ISP_DPCC_PG_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000020) #define RKISP1_CIF_ISP_DPCC_RND_THRESH_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000024) #define RKISP1_CIF_ISP_DPCC_RG_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000028) -#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000002c) #define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000030) #define RKISP1_CIF_ISP_DPCC_PG_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000034) #define RKISP1_CIF_ISP_DPCC_RND_THRESH_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000038) -#define RKISP1_CIF_ISP_DPCC_RG_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_DPCC_RG_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000003c) #define RKISP1_CIF_ISP_DPCC_LINE_THRESH_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000040) #define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000044) #define RKISP1_CIF_ISP_DPCC_PG_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000048) -#define RKISP1_CIF_ISP_DPCC_RND_THRESH_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000004c) #define RKISP1_CIF_ISP_DPCC_RG_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000050) #define RKISP1_CIF_ISP_DPCC_RO_LIMITS (RKISP1_CIF_ISP_DPCC_BASE + 0x00000054) #define RKISP1_CIF_ISP_DPCC_RND_OFFS (RKISP1_CIF_ISP_DPCC_BASE + 0x00000058) -#define RKISP1_CIF_ISP_DPCC_BPT_CTRL (RKISP1_CIF_ISP_DPCC_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_DPCC_BPT_CTRL (RKISP1_CIF_ISP_DPCC_BASE + 0x0000005c) #define RKISP1_CIF_ISP_DPCC_BPT_NUMBER (RKISP1_CIF_ISP_DPCC_BASE + 0x00000060) #define RKISP1_CIF_ISP_DPCC_BPT_ADDR (RKISP1_CIF_ISP_DPCC_BASE + 0x00000064) #define RKISP1_CIF_ISP_DPCC_BPT_DATA (RKISP1_CIF_ISP_DPCC_BASE + 0x00000068) -#define RKISP1_CIF_ISP_WDR_BASE 0x00002A00 +#define RKISP1_CIF_ISP_WDR_BASE 0x00002a00 #define RKISP1_CIF_ISP_WDR_CTRL (RKISP1_CIF_ISP_WDR_BASE + 0x00000000) #define RKISP1_CIF_ISP_WDR_TONECURVE_1 (RKISP1_CIF_ISP_WDR_BASE + 0x00000004) #define RKISP1_CIF_ISP_WDR_TONECURVE_2 (RKISP1_CIF_ISP_WDR_BASE + 0x00000008) -#define RKISP1_CIF_ISP_WDR_TONECURVE_3 (RKISP1_CIF_ISP_WDR_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_3 (RKISP1_CIF_ISP_WDR_BASE + 0x0000000c) #define RKISP1_CIF_ISP_WDR_TONECURVE_4 (RKISP1_CIF_ISP_WDR_BASE + 0x00000010) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0 (RKISP1_CIF_ISP_WDR_BASE + 0x00000014) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1 (RKISP1_CIF_ISP_WDR_BASE + 0x00000018) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2 (RKISP1_CIF_ISP_WDR_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2 (RKISP1_CIF_ISP_WDR_BASE + 0x0000001c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3 (RKISP1_CIF_ISP_WDR_BASE + 0x00000020) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4 (RKISP1_CIF_ISP_WDR_BASE + 0x00000024) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5 (RKISP1_CIF_ISP_WDR_BASE + 0x00000028) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6 (RKISP1_CIF_ISP_WDR_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6 (RKISP1_CIF_ISP_WDR_BASE + 0x0000002c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7 (RKISP1_CIF_ISP_WDR_BASE + 0x00000030) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8 (RKISP1_CIF_ISP_WDR_BASE + 0x00000034) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9 (RKISP1_CIF_ISP_WDR_BASE + 0x00000038) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10 (RKISP1_CIF_ISP_WDR_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10 (RKISP1_CIF_ISP_WDR_BASE + 0x0000003c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11 (RKISP1_CIF_ISP_WDR_BASE + 0x00000040) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12 (RKISP1_CIF_ISP_WDR_BASE + 0x00000044) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13 (RKISP1_CIF_ISP_WDR_BASE + 0x00000048) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14 (RKISP1_CIF_ISP_WDR_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14 (RKISP1_CIF_ISP_WDR_BASE + 0x0000004c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15 (RKISP1_CIF_ISP_WDR_BASE + 0x00000050) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16 (RKISP1_CIF_ISP_WDR_BASE + 0x00000054) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17 (RKISP1_CIF_ISP_WDR_BASE + 0x00000058) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18 (RKISP1_CIF_ISP_WDR_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18 (RKISP1_CIF_ISP_WDR_BASE + 0x0000005c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19 (RKISP1_CIF_ISP_WDR_BASE + 0x00000060) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20 (RKISP1_CIF_ISP_WDR_BASE + 0x00000064) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21 (RKISP1_CIF_ISP_WDR_BASE + 0x00000068) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22 (RKISP1_CIF_ISP_WDR_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22 (RKISP1_CIF_ISP_WDR_BASE + 0x0000006c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23 (RKISP1_CIF_ISP_WDR_BASE + 0x00000070) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24 (RKISP1_CIF_ISP_WDR_BASE + 0x00000074) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25 (RKISP1_CIF_ISP_WDR_BASE + 0x00000078) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26 (RKISP1_CIF_ISP_WDR_BASE + 0x0000007C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26 (RKISP1_CIF_ISP_WDR_BASE + 0x0000007c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27 (RKISP1_CIF_ISP_WDR_BASE + 0x00000080) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28 (RKISP1_CIF_ISP_WDR_BASE + 0x00000084) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29 (RKISP1_CIF_ISP_WDR_BASE + 0x00000088) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30 (RKISP1_CIF_ISP_WDR_BASE + 0x0000008C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30 (RKISP1_CIF_ISP_WDR_BASE + 0x0000008c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31 (RKISP1_CIF_ISP_WDR_BASE + 0x00000090) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32 (RKISP1_CIF_ISP_WDR_BASE + 0x00000094) #define RKISP1_CIF_ISP_WDR_OFFSET (RKISP1_CIF_ISP_WDR_BASE + 0x00000098) -#define RKISP1_CIF_ISP_WDR_DELTAMIN (RKISP1_CIF_ISP_WDR_BASE + 0x0000009C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000AC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000BC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000CC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000DC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000EC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000FC) +#define RKISP1_CIF_ISP_WDR_DELTAMIN (RKISP1_CIF_ISP_WDR_BASE + 0x0000009c) +#define RKISP1_CIF_ISP_WDR_TONECURVE_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000a0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000a4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000a8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000ac) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000b0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000b4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000b8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000bc) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000c0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000c4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000c8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000cc) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000d0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000d4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000d8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000dc) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000e0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000e4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000e8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000ec) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000f0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000f4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000f8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000fc) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000100) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000104) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000108) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000010C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000010c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000110) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000114) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000118) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000011C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000011c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000120) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000124) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000128) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000012C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000012c) #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000130) -#define RKISP1_CIF_ISP_HIST_BASE_V12 0x00002C00 +#define RKISP1_CIF_ISP_HIST_BASE_V12 0x00002c00 #define RKISP1_CIF_ISP_HIST_CTRL_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000000) #define RKISP1_CIF_ISP_HIST_SIZE_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000004) #define RKISP1_CIF_ISP_HIST_OFFS_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000008) -#define RKISP1_CIF_ISP_HIST_DBG1_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000000C) -#define RKISP1_CIF_ISP_HIST_DBG2_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000001C) -#define RKISP1_CIF_ISP_HIST_DBG3_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000002C) -#define RKISP1_CIF_ISP_HIST_WEIGHT_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000003C) +#define RKISP1_CIF_ISP_HIST_DBG1_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000000c) +#define RKISP1_CIF_ISP_HIST_DBG2_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000001c) +#define RKISP1_CIF_ISP_HIST_DBG3_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000002c) +#define RKISP1_CIF_ISP_HIST_WEIGHT_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x0000003c) #define RKISP1_CIF_ISP_HIST_BIN_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000120) -#define RKISP1_CIF_ISP_VSM_BASE 0x00002F00 +#define RKISP1_CIF_ISP_VSM_BASE 0x00002f00 #define RKISP1_CIF_ISP_VSM_MODE (RKISP1_CIF_ISP_VSM_BASE + 0x00000000) #define RKISP1_CIF_ISP_VSM_H_OFFS (RKISP1_CIF_ISP_VSM_BASE + 0x00000004) #define RKISP1_CIF_ISP_VSM_V_OFFS (RKISP1_CIF_ISP_VSM_BASE + 0x00000008) -#define RKISP1_CIF_ISP_VSM_H_SIZE (RKISP1_CIF_ISP_VSM_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_VSM_H_SIZE (RKISP1_CIF_ISP_VSM_BASE + 0x0000000c) #define RKISP1_CIF_ISP_VSM_V_SIZE (RKISP1_CIF_ISP_VSM_BASE + 0x00000010) #define RKISP1_CIF_ISP_VSM_H_SEGMENTS (RKISP1_CIF_ISP_VSM_BASE + 0x00000014) #define RKISP1_CIF_ISP_VSM_V_SEGMENTS (RKISP1_CIF_ISP_VSM_BASE + 0x00000018) -#define RKISP1_CIF_ISP_VSM_DELTA_H (RKISP1_CIF_ISP_VSM_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_VSM_DELTA_H (RKISP1_CIF_ISP_VSM_BASE + 0x0000001c) #define RKISP1_CIF_ISP_VSM_DELTA_V (RKISP1_CIF_ISP_VSM_BASE + 0x00000020) #define RKISP1_CIF_ISP_CSI0_BASE 0x00007000 diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index c15ae02181..6297870ee9 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -60,7 +60,6 @@ struct rkisp1_rsz_config { const int min_rsz_height; /* registers */ struct { - u32 ctrl; u32 yuvmode_mask; u32 rawmode_mask; u32 h_offset; @@ -78,7 +77,6 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_mp = { .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, /* registers */ .dual_crop = { - .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, .yuvmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_YUV, .rawmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_RAW, .h_offset = RKISP1_CIF_DUAL_CROP_M_H_OFFS, @@ -96,7 +94,6 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = { .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, /* registers */ .dual_crop = { - .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, .yuvmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_YUV, .rawmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_RAW, .h_offset = RKISP1_CIF_DUAL_CROP_S_H_OFFS, @@ -117,34 +114,6 @@ static inline void rkisp1_rsz_write(struct rkisp1_resizer *rsz, u32 offset, rkisp1_write(rsz->rkisp1, rsz->regs_base + offset, value); } -static struct v4l2_mbus_framefmt * -rkisp1_rsz_get_pad_fmt(struct rkisp1_resizer *rsz, - struct v4l2_subdev_state *sd_state, - unsigned int pad, u32 which) -{ - struct v4l2_subdev_state state = { - .pads = rsz->pad_cfg, - }; - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&rsz->sd, sd_state, pad); - else - return v4l2_subdev_get_try_format(&rsz->sd, &state, pad); -} - -static struct v4l2_rect * -rkisp1_rsz_get_pad_crop(struct rkisp1_resizer *rsz, - struct v4l2_subdev_state *sd_state, - unsigned int pad, u32 which) -{ - struct v4l2_subdev_state state = { - .pads = rsz->pad_cfg, - }; - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&rsz->sd, sd_state, pad); - else - return v4l2_subdev_get_try_crop(&rsz->sd, &state, pad); -} - /* ---------------------------------------------------------------------------- * Dual crop hw configs */ @@ -152,7 +121,7 @@ rkisp1_rsz_get_pad_crop(struct rkisp1_resizer *rsz, static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz, enum rkisp1_shadow_regs_when when) { - u32 dc_ctrl = rkisp1_read(rsz->rkisp1, rsz->config->dual_crop.ctrl); + u32 dc_ctrl = rkisp1_read(rsz->rkisp1, RKISP1_CIF_DUAL_CROP_CTRL); u32 mask = ~(rsz->config->dual_crop.yuvmode_mask | rsz->config->dual_crop.rawmode_mask); @@ -161,21 +130,22 @@ static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz, dc_ctrl |= RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD; else dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; - rkisp1_write(rsz->rkisp1, rsz->config->dual_crop.ctrl, dc_ctrl); + rkisp1_write(rsz->rkisp1, RKISP1_CIF_DUAL_CROP_CTRL, dc_ctrl); } /* configure dual-crop unit */ -static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz) +static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz, + struct v4l2_subdev_state *sd_state) { struct rkisp1_device *rkisp1 = rsz->rkisp1; struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; u32 dc_ctrl; - sink_crop = rkisp1_rsz_get_pad_crop(rsz, NULL, RKISP1_RSZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); + sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); if (sink_crop->width == sink_fmt->width && sink_crop->height == sink_fmt->height && @@ -185,14 +155,14 @@ static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz) return; } - dc_ctrl = rkisp1_read(rkisp1, rsz->config->dual_crop.ctrl); + dc_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_DUAL_CROP_CTRL); rkisp1_write(rkisp1, rsz->config->dual_crop.h_offset, sink_crop->left); rkisp1_write(rkisp1, rsz->config->dual_crop.v_offset, sink_crop->top); rkisp1_write(rkisp1, rsz->config->dual_crop.h_size, sink_crop->width); rkisp1_write(rkisp1, rsz->config->dual_crop.v_size, sink_crop->height); dc_ctrl |= rsz->config->dual_crop.yuvmode_mask; dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; - rkisp1_write(rkisp1, rsz->config->dual_crop.ctrl, dc_ctrl); + rkisp1_write(rkisp1, RKISP1_CIF_DUAL_CROP_CTRL, dc_ctrl); dev_dbg(rkisp1->dev, "stream %d crop: %dx%d -> %dx%d\n", rsz->id, sink_fmt->width, sink_fmt->height, @@ -236,10 +206,10 @@ static void rkisp1_rsz_disable(struct rkisp1_resizer *rsz, } static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, - struct v4l2_rect *sink_y, - struct v4l2_rect *sink_c, - struct v4l2_rect *src_y, - struct v4l2_rect *src_c, + const struct v4l2_rect *sink_y, + const struct v4l2_rect *sink_c, + const struct v4l2_area *src_y, + const struct v4l2_area *src_c, enum rkisp1_shadow_regs_when when) { u32 ratio, rsz_ctrl = 0; @@ -296,61 +266,63 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, } static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, + struct v4l2_subdev_state *sd_state, enum rkisp1_shadow_regs_when when) { const struct rkisp1_rsz_yuv_mbus_info *sink_yuv_info, *src_yuv_info; - struct v4l2_rect sink_y, sink_c, src_y, src_c; - struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; - struct v4l2_rect *sink_crop; + const struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; + const struct v4l2_rect *sink_y; + struct v4l2_area src_y, src_c; + struct v4l2_rect sink_c; + + sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SRC); - sink_crop = rkisp1_rsz_get_pad_crop(rsz, NULL, RKISP1_RSZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); - src_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SRC, - V4L2_SUBDEV_FORMAT_ACTIVE); - src_yuv_info = rkisp1_rsz_get_yuv_mbus_info(src_fmt->code); - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); sink_yuv_info = rkisp1_rsz_get_yuv_mbus_info(sink_fmt->code); + src_yuv_info = rkisp1_rsz_get_yuv_mbus_info(src_fmt->code); /* - * The resizer only works on yuv formats, - * so return if it is bayer format. + * The resizer only works on yuv formats, so return if it is bayer + * format. */ - if (rsz->pixel_enc == V4L2_PIXEL_ENC_BAYER) { + if (!sink_yuv_info) { rkisp1_rsz_disable(rsz, when); return; } - sink_y.width = sink_crop->width; - sink_y.height = sink_crop->height; + sink_y = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + sink_c.width = sink_y->width / sink_yuv_info->hdiv; + sink_c.height = sink_y->height / sink_yuv_info->vdiv; + src_y.width = src_fmt->width; src_y.height = src_fmt->height; - - sink_c.width = sink_y.width / sink_yuv_info->hdiv; - sink_c.height = sink_y.height / sink_yuv_info->vdiv; + src_c.width = src_y.width / src_yuv_info->hdiv; + src_c.height = src_y.height / src_yuv_info->vdiv; /* * The resizer is used not only to change the dimensions of the frame - * but also to change the scale for YUV formats, - * (4:2:2 -> 4:2:0 for example). So the width/height of the CbCr - * streams should be set according to the media bus format in the src pad. + * but also to change the subsampling for YUV formats (for instance + * converting from 4:2:2 to 4:2:0). Check both the luma and chroma + * dimensions to decide whether or not to enable the resizer. */ - src_c.width = src_y.width / src_yuv_info->hdiv; - src_c.height = src_y.height / src_yuv_info->vdiv; - if (sink_c.width == src_c.width && sink_c.height == src_c.height) { + dev_dbg(rsz->rkisp1->dev, + "stream %u rsz/scale: Y %ux%u -> %ux%u, CbCr %ux%u -> %ux%u\n", + rsz->id, sink_y->width, sink_y->height, + src_fmt->width, src_fmt->height, + sink_c.width, sink_c.height, src_c.width, src_c.height); + + if (sink_y->width == src_y.width && sink_y->height == src_y.height && + sink_c.width == src_c.width && sink_c.height == src_c.height) { rkisp1_rsz_disable(rsz, when); return; } - dev_dbg(rsz->rkisp1->dev, "stream %d rsz/scale: %dx%d -> %dx%d\n", - rsz->id, sink_crop->width, sink_crop->height, - src_fmt->width, src_fmt->height); - dev_dbg(rsz->rkisp1->dev, "chroma scaling %dx%d -> %dx%d\n", - sink_c.width, sink_c.height, src_c.width, src_c.height); - - /* set values in the hw */ - rkisp1_rsz_config_regs(rsz, &sink_y, &sink_c, &src_y, &src_c, when); + /* Set values in the hardware. */ + rkisp1_rsz_config_regs(rsz, sink_y, &sink_c, &src_y, &src_c, when); } /* ---------------------------------------------------------------------------- @@ -363,12 +335,8 @@ static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd, { struct rkisp1_resizer *rsz = container_of(sd, struct rkisp1_resizer, sd); - struct v4l2_subdev_pad_config dummy_cfg; - struct v4l2_subdev_state pad_state = { - .pads = &dummy_cfg - }; - u32 pad = code->pad; - int ret; + unsigned int index = code->index; + unsigned int i; if (code->pad == RKISP1_RSZ_PAD_SRC) { /* supported mbus codes on the src are the same as in the capture */ @@ -388,15 +356,29 @@ static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd, return 0; } - /* supported mbus codes on the sink pad are the same as isp src pad */ - code->pad = RKISP1_ISP_PAD_SOURCE_VIDEO; - ret = v4l2_subdev_call(&rsz->rkisp1->isp.sd, pad, enum_mbus_code, - &pad_state, code); + /* + * Supported mbus codes on the sink pad are the same as on the ISP + * source pad. + */ + for (i = 0; ; i++) { + const struct rkisp1_mbus_info *fmt = + rkisp1_mbus_info_get_by_index(i); - /* restore pad */ - code->pad = pad; - code->flags = 0; - return ret; + if (!fmt) + break; + + if (!(fmt->direction & RKISP1_ISP_SD_SRC)) + continue; + + if (!index) { + code->code = fmt->mbus_code; + return 0; + } + + index--; + } + + return -EINVAL; } static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, @@ -405,7 +387,7 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop; - sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, + sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_RSZ_PAD_SRC); sink_fmt->width = RKISP1_DEFAULT_WIDTH; sink_fmt->height = RKISP1_DEFAULT_HEIGHT; @@ -423,7 +405,7 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, sink_crop->left = 0; sink_crop->top = 0; - src_fmt = v4l2_subdev_get_try_format(sd, sd_state, + src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_RSZ_PAD_SINK); *src_fmt = *sink_fmt; @@ -434,16 +416,16 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz, struct v4l2_subdev_state *sd_state, - struct v4l2_mbus_framefmt *format, - unsigned int which) + struct v4l2_mbus_framefmt *format) { const struct rkisp1_mbus_info *sink_mbus_info; struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK, - which); - src_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SRC, - which); + sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SRC); + sink_mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); /* for YUV formats, userspace can change the mbus code on the src pad if it is supported */ @@ -463,18 +445,16 @@ static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz, static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, struct v4l2_subdev_state *sd_state, - struct v4l2_rect *r, - unsigned int which) + struct v4l2_rect *r) { const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK, - which); - sink_crop = rkisp1_rsz_get_pad_crop(rsz, sd_state, - RKISP1_RSZ_PAD_SINK, - which); + sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); /* Not crop for MP bayer raw data */ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); @@ -501,21 +481,20 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, struct v4l2_subdev_state *sd_state, - struct v4l2_mbus_framefmt *format, - unsigned int which) + struct v4l2_mbus_framefmt *format) { const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop; bool is_yuv; - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK, - which); - src_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SRC, - which); - sink_crop = rkisp1_rsz_get_pad_crop(rsz, sd_state, - RKISP1_RSZ_PAD_SINK, - which); + sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SRC); + sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state, + RKISP1_RSZ_PAD_SINK); + if (rsz->id == RKISP1_SELFPATH) sink_fmt->code = MEDIA_BUS_FMT_YUYV8_2X8; else @@ -526,8 +505,6 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, sink_fmt->code = RKISP1_DEF_FMT; mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); } - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - rsz->pixel_enc = mbus_info->pixel_enc; sink_fmt->width = clamp_t(u32, format->width, RKISP1_ISP_MIN_WIDTH, @@ -576,21 +553,7 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, src_fmt->quantization = sink_fmt->quantization; /* Update sink crop */ - rkisp1_rsz_set_sink_crop(rsz, sd_state, sink_crop, which); -} - -static int rkisp1_rsz_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct rkisp1_resizer *rsz = - container_of(sd, struct rkisp1_resizer, sd); - - mutex_lock(&rsz->ops_lock); - fmt->format = *rkisp1_rsz_get_pad_fmt(rsz, sd_state, fmt->pad, - fmt->which); - mutex_unlock(&rsz->ops_lock); - return 0; + rkisp1_rsz_set_sink_crop(rsz, sd_state, sink_crop); } static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd, @@ -600,15 +563,11 @@ static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd, struct rkisp1_resizer *rsz = container_of(sd, struct rkisp1_resizer, sd); - mutex_lock(&rsz->ops_lock); if (fmt->pad == RKISP1_RSZ_PAD_SINK) - rkisp1_rsz_set_sink_fmt(rsz, sd_state, &fmt->format, - fmt->which); + rkisp1_rsz_set_sink_fmt(rsz, sd_state, &fmt->format); else - rkisp1_rsz_set_src_fmt(rsz, sd_state, &fmt->format, - fmt->which); + rkisp1_rsz_set_src_fmt(rsz, sd_state, &fmt->format); - mutex_unlock(&rsz->ops_lock); return 0; } @@ -616,35 +575,32 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct rkisp1_resizer *rsz = - container_of(sd, struct rkisp1_resizer, sd); struct v4l2_mbus_framefmt *mf_sink; int ret = 0; if (sel->pad == RKISP1_RSZ_PAD_SRC) return -EINVAL; - mutex_lock(&rsz->ops_lock); switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: - mf_sink = rkisp1_rsz_get_pad_fmt(rsz, sd_state, - RKISP1_RSZ_PAD_SINK, - sel->which); + mf_sink = v4l2_subdev_get_pad_format(sd, sd_state, + RKISP1_RSZ_PAD_SINK); sel->r.height = mf_sink->height; sel->r.width = mf_sink->width; sel->r.left = 0; sel->r.top = 0; break; + case V4L2_SEL_TGT_CROP: - sel->r = *rkisp1_rsz_get_pad_crop(rsz, sd_state, - RKISP1_RSZ_PAD_SINK, - sel->which); + sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, + RKISP1_RSZ_PAD_SINK); break; + default: ret = -EINVAL; + break; } - mutex_unlock(&rsz->ops_lock); return ret; } @@ -661,9 +617,7 @@ static int rkisp1_rsz_set_selection(struct v4l2_subdev *sd, dev_dbg(rsz->rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); - mutex_lock(&rsz->ops_lock); - rkisp1_rsz_set_sink_crop(rsz, sd_state, &sel->r, sel->which); - mutex_unlock(&rsz->ops_lock); + rkisp1_rsz_set_sink_crop(rsz, sd_state, &sel->r); return 0; } @@ -677,7 +631,7 @@ static const struct v4l2_subdev_pad_ops rkisp1_rsz_pad_ops = { .get_selection = rkisp1_rsz_get_selection, .set_selection = rkisp1_rsz_set_selection, .init_cfg = rkisp1_rsz_init_config, - .get_fmt = rkisp1_rsz_get_fmt, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = rkisp1_rsz_set_fmt, .link_validate = v4l2_subdev_link_validate_default, }; @@ -693,6 +647,7 @@ static int rkisp1_rsz_s_stream(struct v4l2_subdev *sd, int enable) struct rkisp1_device *rkisp1 = rsz->rkisp1; struct rkisp1_capture *other = &rkisp1->capture_devs[rsz->id ^ 1]; enum rkisp1_shadow_regs_when when = RKISP1_SHADOW_REGS_SYNC; + struct v4l2_subdev_state *sd_state; if (!enable) { rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_ASYNC); @@ -703,11 +658,13 @@ static int rkisp1_rsz_s_stream(struct v4l2_subdev *sd, int enable) if (other->is_streaming) when = RKISP1_SHADOW_REGS_ASYNC; - mutex_lock(&rsz->ops_lock); - rkisp1_rsz_config(rsz, when); - rkisp1_dcrop_config(rsz); + sd_state = v4l2_subdev_lock_and_get_active_state(sd); + + rkisp1_rsz_config(rsz, sd_state, when); + rkisp1_dcrop_config(rsz, sd_state); + + v4l2_subdev_unlock_state(sd_state); - mutex_unlock(&rsz->ops_lock); return 0; } @@ -726,15 +683,12 @@ static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz) return; v4l2_device_unregister_subdev(&rsz->sd); + v4l2_subdev_cleanup(&rsz->sd); media_entity_cleanup(&rsz->sd.entity); - mutex_destroy(&rsz->ops_lock); } static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) { - struct v4l2_subdev_state state = { - .pads = rsz->pad_cfg, - }; static const char * const dev_names[] = { RKISP1_RSZ_MP_DEV_NAME, RKISP1_RSZ_SP_DEV_NAME @@ -763,25 +717,26 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) pads[RKISP1_RSZ_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT; - rsz->pixel_enc = RKISP1_DEF_PIXEL_ENC; - - mutex_init(&rsz->ops_lock); ret = media_entity_pads_init(&sd->entity, RKISP1_RSZ_PAD_MAX, pads); if (ret) - goto error; + goto err_entity_cleanup; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto err_entity_cleanup; ret = v4l2_device_register_subdev(&rsz->rkisp1->v4l2_dev, sd); if (ret) { dev_err(sd->dev, "Failed to register resizer subdev\n"); - goto error; + goto err_subdev_cleanup; } - rkisp1_rsz_init_config(sd, &state); return 0; -error: +err_subdev_cleanup: + v4l2_subdev_cleanup(sd); +err_entity_cleanup: media_entity_cleanup(&sd->entity); - mutex_destroy(&rsz->ops_lock); return ret; } diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.c b/drivers/media/platform/samsung/exynos4-is/fimc-is.c index 530a148fe4..a08c87ef6e 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.c @@ -767,12 +767,32 @@ static void fimc_is_debugfs_create(struct fimc_is *is) static int fimc_is_runtime_resume(struct device *dev); static int fimc_is_runtime_suspend(struct device *dev); +static void __iomem *fimc_is_get_pmu_regs(struct device *dev) +{ + struct device_node *node; + void __iomem *regs; + + node = of_parse_phandle(dev->of_node, "samsung,pmu-syscon", 0); + if (!node) { + node = of_get_child_by_name(dev->of_node, "pmu"); + if (!node) + return IOMEM_ERR_PTR(-ENODEV); + dev_warn(dev, "Found PMU node via deprecated method, update your DTB\n"); + } + + regs = of_iomap(node, 0); + of_node_put(node); + if (!regs) + return IOMEM_ERR_PTR(-ENOMEM); + + return regs; +} + static int fimc_is_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct fimc_is *is; struct resource res; - struct device_node *node; int ret; is = devm_kzalloc(&pdev->dev, sizeof(*is), GFP_KERNEL); @@ -794,14 +814,9 @@ static int fimc_is_probe(struct platform_device *pdev) if (IS_ERR(is->regs)) return PTR_ERR(is->regs); - node = of_get_child_by_name(dev->of_node, "pmu"); - if (!node) - return -ENODEV; - - is->pmu_regs = of_iomap(node, 0); - of_node_put(node); - if (!is->pmu_regs) - return -ENOMEM; + is->pmu_regs = fimc_is_get_pmu_regs(dev); + if (IS_ERR(is->pmu_regs)) + return PTR_ERR(is->pmu_regs); is->irq = irq_of_parse_and_map(dev->of_node, 0); if (!is->irq) { diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c index f62703cebb..4b4c129c09 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -1297,7 +1297,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) if (ctx->state == MFCINST_FINISHING && ctx->ref_queue_cnt == 0) src_ready = false; if (!src_ready || ctx->dst_queue_cnt == 0) - clear_work_bit(ctx); + clear_work_bit_irqsave(ctx); return 0; } diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c index 5dc1f908b4..e4cf27b5a0 100644 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c @@ -695,16 +695,10 @@ static int c8sectpfe_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fei); - fei->c8sectpfeclk = devm_clk_get(dev, "c8sectpfe"); + fei->c8sectpfeclk = devm_clk_get_enabled(dev, "c8sectpfe"); if (IS_ERR(fei->c8sectpfeclk)) { - dev_err(dev, "c8sectpfe clk not found\n"); - return PTR_ERR(fei->c8sectpfeclk); - } - - ret = clk_prepare_enable(fei->c8sectpfeclk); - if (ret) { dev_err(dev, "Failed to enable c8sectpfe clock\n"); - return ret; + return PTR_ERR(fei->c8sectpfeclk); } /* to save power disable all IP's (on by default) */ @@ -722,7 +716,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) 0, "c8sectpfe-idle-irq", fei); if (ret) { dev_err(dev, "Can't register c8sectpfe-idle-irq IRQ.\n"); - goto err_clk_disable; + return ret; } ret = devm_request_irq(dev, fei->error_irq, @@ -730,7 +724,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) "c8sectpfe-error-irq", fei); if (ret) { dev_err(dev, "Can't register c8sectpfe-error-irq IRQ.\n"); - goto err_clk_disable; + return ret; } fei->tsin_count = of_get_child_count(np); @@ -739,16 +733,14 @@ static int c8sectpfe_probe(struct platform_device *pdev) fei->tsin_count > fei->hw_stats.num_ib) { dev_err(dev, "More tsin declared than exist on SoC!\n"); - ret = -EINVAL; - goto err_clk_disable; + return -EINVAL; } fei->pinctrl = devm_pinctrl_get(dev); if (IS_ERR(fei->pinctrl)) { dev_err(dev, "Error getting tsin pins\n"); - ret = PTR_ERR(fei->pinctrl); - goto err_clk_disable; + return PTR_ERR(fei->pinctrl); } for_each_child_of_node(np, child) { @@ -859,7 +851,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "c8sectpfe_tuner_register_frontend failed (%d)\n", ret); - goto err_clk_disable; + return ret; } c8sectpfe_debugfs_init(fei); @@ -868,8 +860,6 @@ static int c8sectpfe_probe(struct platform_device *pdev) err_node_put: of_node_put(child); -err_clk_disable: - clk_disable_unprepare(fei->c8sectpfeclk); return ret; } @@ -903,8 +893,6 @@ static void c8sectpfe_remove(struct platform_device *pdev) if (readl(fei->io + SYS_OTHER_CLKEN)) writel(0, fei->io + SYS_OTHER_CLKEN); - - clk_disable_unprepare(fei->c8sectpfeclk); } diff --git a/drivers/media/platform/ti/Kconfig b/drivers/media/platform/ti/Kconfig index e1ab56c3be..bab998c417 100644 --- a/drivers/media/platform/ti/Kconfig +++ b/drivers/media/platform/ti/Kconfig @@ -63,6 +63,18 @@ config VIDEO_TI_VPE_DEBUG help Enable debug messages on VPE driver. +config VIDEO_TI_J721E_CSI2RX + tristate "TI J721E CSI2RX wrapper layer driver" + depends on VIDEO_DEV && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_SUPPORT && MEDIA_CONTROLLER + depends on (PHY_CADENCE_DPHY_RX && VIDEO_CADENCE_CSI2RX) || COMPILE_TEST + depends on ARCH_K3 || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + help + Support for TI CSI2RX wrapper layer. This just enables the wrapper driver. + The Cadence CSI2RX bridge driver needs to be enabled separately. + source "drivers/media/platform/ti/am437x/Kconfig" source "drivers/media/platform/ti/davinci/Kconfig" source "drivers/media/platform/ti/omap/Kconfig" diff --git a/drivers/media/platform/ti/Makefile b/drivers/media/platform/ti/Makefile index 98c5fe5c40..8a2f74c938 100644 --- a/drivers/media/platform/ti/Makefile +++ b/drivers/media/platform/ti/Makefile @@ -3,5 +3,6 @@ obj-y += am437x/ obj-y += cal/ obj-y += vpe/ obj-y += davinci/ +obj-y += j721e-csi2rx/ obj-y += omap/ obj-y += omap3isp/ diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.c b/drivers/media/platform/ti/am437x/am437x-vpfe.c index 63092013d4..5fa2ea9025 100644 --- a/drivers/media/platform/ti/am437x/am437x-vpfe.c +++ b/drivers/media/platform/ti/am437x/am437x-vpfe.c @@ -1271,12 +1271,8 @@ static inline void vpfe_attach_irq(struct vpfe_device *vpfe) static int vpfe_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct vpfe_device *vpfe = video_drvdata(file); - strscpy(cap->driver, VPFE_MODULE_NAME, sizeof(cap->driver)); strscpy(cap->card, "TI AM437x VPFE", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", vpfe->v4l2_dev.name); return 0; } diff --git a/drivers/media/platform/ti/j721e-csi2rx/Makefile b/drivers/media/platform/ti/j721e-csi2rx/Makefile new file mode 100644 index 0000000000..377afc1d62 --- /dev/null +++ b/drivers/media/platform/ti/j721e-csi2rx/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_VIDEO_TI_J721E_CSI2RX) += j721e-csi2rx.o diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c new file mode 100644 index 0000000000..ada61391c8 --- /dev/null +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -0,0 +1,1159 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * TI CSI2RX Shim Wrapper Driver + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + * + * Author: Pratyush Yadav <p.yadav@ti.com> + * Author: Jai Luthra <j-luthra@ti.com> + */ + +#include <linux/bitfield.h> +#include <linux/dmaengine.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> + +#include <media/mipi-csi2.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mc.h> +#include <media/videobuf2-dma-contig.h> + +#define TI_CSI2RX_MODULE_NAME "j721e-csi2rx" + +#define SHIM_CNTL 0x10 +#define SHIM_CNTL_PIX_RST BIT(0) + +#define SHIM_DMACNTX 0x20 +#define SHIM_DMACNTX_EN BIT(31) +#define SHIM_DMACNTX_YUV422 GENMASK(27, 26) +#define SHIM_DMACNTX_SIZE GENMASK(21, 20) +#define SHIM_DMACNTX_FMT GENMASK(5, 0) +#define SHIM_DMACNTX_YUV422_MODE_11 3 +#define SHIM_DMACNTX_SIZE_8 0 +#define SHIM_DMACNTX_SIZE_16 1 +#define SHIM_DMACNTX_SIZE_32 2 + +#define SHIM_PSI_CFG0 0x24 +#define SHIM_PSI_CFG0_SRC_TAG GENMASK(15, 0) +#define SHIM_PSI_CFG0_DST_TAG GENMASK(31, 16) + +#define PSIL_WORD_SIZE_BYTES 16 +/* + * There are no hard limits on the width or height. The DMA engine can handle + * all sizes. The max width and height are arbitrary numbers for this driver. + * Use 16K * 16K as the arbitrary limit. It is large enough that it is unlikely + * the limit will be hit in practice. + */ +#define MAX_WIDTH_BYTES SZ_16K +#define MAX_HEIGHT_LINES SZ_16K + +#define DRAIN_TIMEOUT_MS 50 +#define DRAIN_BUFFER_SIZE SZ_32K + +struct ti_csi2rx_fmt { + u32 fourcc; /* Four character code. */ + u32 code; /* Mbus code. */ + u32 csi_dt; /* CSI Data type. */ + u8 bpp; /* Bits per pixel. */ + u8 size; /* Data size shift when unpacking. */ +}; + +struct ti_csi2rx_buffer { + /* Common v4l2 buffer. Must be first. */ + struct vb2_v4l2_buffer vb; + struct list_head list; + struct ti_csi2rx_dev *csi; +}; + +enum ti_csi2rx_dma_state { + TI_CSI2RX_DMA_STOPPED, /* Streaming not started yet. */ + TI_CSI2RX_DMA_IDLE, /* Streaming but no pending DMA operation. */ + TI_CSI2RX_DMA_ACTIVE, /* Streaming and pending DMA operation. */ +}; + +struct ti_csi2rx_dma { + /* Protects all fields in this struct. */ + spinlock_t lock; + struct dma_chan *chan; + /* Buffers queued to the driver, waiting to be processed by DMA. */ + struct list_head queue; + enum ti_csi2rx_dma_state state; + /* + * Queue of buffers submitted to DMA engine. + */ + struct list_head submitted; + /* Buffer to drain stale data from PSI-L endpoint */ + struct { + void *vaddr; + dma_addr_t paddr; + size_t len; + } drain; +}; + +struct ti_csi2rx_dev { + struct device *dev; + void __iomem *shim; + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct media_device mdev; + struct media_pipeline pipe; + struct media_pad pad; + struct v4l2_async_notifier notifier; + struct v4l2_subdev *source; + struct vb2_queue vidq; + struct mutex mutex; /* To serialize ioctls. */ + struct v4l2_format v_fmt; + struct ti_csi2rx_dma dma; + u32 sequence; +}; + +static const struct ti_csi2rx_fmt ti_csi2rx_formats[] = { + { + .fourcc = V4L2_PIX_FMT_YUYV, + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_YVYU, + .code = MEDIA_BUS_FMT_YVYU8_1X16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_VYUY, + .code = MEDIA_BUS_FMT_VYUY8_1X16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, + + /* More formats can be supported but they are not listed for now. */ +}; + +/* Forward declaration needed by ti_csi2rx_dma_callback. */ +static int ti_csi2rx_start_dma(struct ti_csi2rx_dev *csi, + struct ti_csi2rx_buffer *buf); + +static const struct ti_csi2rx_fmt *find_format_by_fourcc(u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ti_csi2rx_formats); i++) { + if (ti_csi2rx_formats[i].fourcc == pixelformat) + return &ti_csi2rx_formats[i]; + } + + return NULL; +} + +static const struct ti_csi2rx_fmt *find_format_by_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ti_csi2rx_formats); i++) { + if (ti_csi2rx_formats[i].code == code) + return &ti_csi2rx_formats[i]; + } + + return NULL; +} + +static void ti_csi2rx_fill_fmt(const struct ti_csi2rx_fmt *csi_fmt, + struct v4l2_format *v4l2_fmt) +{ + struct v4l2_pix_format *pix = &v4l2_fmt->fmt.pix; + unsigned int pixels_in_word; + + pixels_in_word = PSIL_WORD_SIZE_BYTES * 8 / csi_fmt->bpp; + + /* Clamp width and height to sensible maximums (16K x 16K) */ + pix->width = clamp_t(unsigned int, pix->width, + pixels_in_word, + MAX_WIDTH_BYTES * 8 / csi_fmt->bpp); + pix->height = clamp_t(unsigned int, pix->height, 1, MAX_HEIGHT_LINES); + + /* Width should be a multiple of transfer word-size */ + pix->width = rounddown(pix->width, pixels_in_word); + + v4l2_fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + pix->pixelformat = csi_fmt->fourcc; + pix->bytesperline = pix->width * (csi_fmt->bpp / 8); + pix->sizeimage = pix->bytesperline * pix->height; +} + +static int ti_csi2rx_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, TI_CSI2RX_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, TI_CSI2RX_MODULE_NAME, sizeof(cap->card)); + + return 0; +} + +static int ti_csi2rx_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + const struct ti_csi2rx_fmt *fmt = NULL; + + if (f->mbus_code) { + /* 1-to-1 mapping between bus formats and pixel formats */ + if (f->index > 0) + return -EINVAL; + + fmt = find_format_by_code(f->mbus_code); + } else { + if (f->index >= ARRAY_SIZE(ti_csi2rx_formats)) + return -EINVAL; + + fmt = &ti_csi2rx_formats[f->index]; + } + + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->fourcc; + memset(f->reserved, 0, sizeof(f->reserved)); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int ti_csi2rx_g_fmt_vid_cap(struct file *file, void *prov, + struct v4l2_format *f) +{ + struct ti_csi2rx_dev *csi = video_drvdata(file); + + *f = csi->v_fmt; + + return 0; +} + +static int ti_csi2rx_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + const struct ti_csi2rx_fmt *fmt; + + /* + * Default to the first format if the requested pixel format code isn't + * supported. + */ + fmt = find_format_by_fourcc(f->fmt.pix.pixelformat); + if (!fmt) + fmt = &ti_csi2rx_formats[0]; + + /* Interlaced formats are not supported. */ + f->fmt.pix.field = V4L2_FIELD_NONE; + + ti_csi2rx_fill_fmt(fmt, f); + + return 0; +} + +static int ti_csi2rx_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ti_csi2rx_dev *csi = video_drvdata(file); + struct vb2_queue *q = &csi->vidq; + int ret; + + if (vb2_is_busy(q)) + return -EBUSY; + + ret = ti_csi2rx_try_fmt_vid_cap(file, priv, f); + if (ret < 0) + return ret; + + csi->v_fmt = *f; + + return 0; +} + +static int ti_csi2rx_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + const struct ti_csi2rx_fmt *fmt; + unsigned int pixels_in_word; + + fmt = find_format_by_fourcc(fsize->pixel_format); + if (!fmt || fsize->index != 0) + return -EINVAL; + + /* + * Number of pixels in one PSI-L word. The transfer happens in multiples + * of PSI-L word sizes. + */ + pixels_in_word = PSIL_WORD_SIZE_BYTES * 8 / fmt->bpp; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = pixels_in_word; + fsize->stepwise.max_width = rounddown(MAX_WIDTH_BYTES * 8 / fmt->bpp, + pixels_in_word); + fsize->stepwise.step_width = pixels_in_word; + fsize->stepwise.min_height = 1; + fsize->stepwise.max_height = MAX_HEIGHT_LINES; + fsize->stepwise.step_height = 1; + + return 0; +} + +static const struct v4l2_ioctl_ops csi_ioctl_ops = { + .vidioc_querycap = ti_csi2rx_querycap, + .vidioc_enum_fmt_vid_cap = ti_csi2rx_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = ti_csi2rx_try_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = ti_csi2rx_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = ti_csi2rx_s_fmt_vid_cap, + .vidioc_enum_framesizes = ti_csi2rx_enum_framesizes, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static const struct v4l2_file_operations csi_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +static int csi_async_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asc) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(notifier->v4l2_dev->dev); + + csi->source = subdev; + + return 0; +} + +static int csi_async_notifier_complete(struct v4l2_async_notifier *notifier) +{ + struct ti_csi2rx_dev *csi = dev_get_drvdata(notifier->v4l2_dev->dev); + struct video_device *vdev = &csi->vdev; + int ret; + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) + return ret; + + ret = v4l2_create_fwnode_links_to_pad(csi->source, &csi->pad, + MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); + + if (ret) { + video_unregister_device(vdev); + return ret; + } + + ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); + if (ret) + video_unregister_device(vdev); + + return ret; +} + +static const struct v4l2_async_notifier_operations csi_async_notifier_ops = { + .bound = csi_async_notifier_bound, + .complete = csi_async_notifier_complete, +}; + +static int ti_csi2rx_notifier_register(struct ti_csi2rx_dev *csi) +{ + struct fwnode_handle *fwnode; + struct v4l2_async_connection *asc; + struct device_node *node; + int ret; + + node = of_get_child_by_name(csi->dev->of_node, "csi-bridge"); + if (!node) + return -EINVAL; + + fwnode = of_fwnode_handle(node); + if (!fwnode) { + of_node_put(node); + return -EINVAL; + } + + v4l2_async_nf_init(&csi->notifier, &csi->v4l2_dev); + csi->notifier.ops = &csi_async_notifier_ops; + + asc = v4l2_async_nf_add_fwnode(&csi->notifier, fwnode, + struct v4l2_async_connection); + of_node_put(node); + if (IS_ERR(asc)) { + v4l2_async_nf_cleanup(&csi->notifier); + return PTR_ERR(asc); + } + + ret = v4l2_async_nf_register(&csi->notifier); + if (ret) { + v4l2_async_nf_cleanup(&csi->notifier); + return ret; + } + + return 0; +} + +static void ti_csi2rx_setup_shim(struct ti_csi2rx_dev *csi) +{ + const struct ti_csi2rx_fmt *fmt; + unsigned int reg; + + fmt = find_format_by_fourcc(csi->v_fmt.fmt.pix.pixelformat); + + /* De-assert the pixel interface reset. */ + reg = SHIM_CNTL_PIX_RST; + writel(reg, csi->shim + SHIM_CNTL); + + reg = SHIM_DMACNTX_EN; + reg |= FIELD_PREP(SHIM_DMACNTX_FMT, fmt->csi_dt); + + /* + * The hardware assumes incoming YUV422 8-bit data on MIPI CSI2 bus + * follows the spec and is packed in the order U0 -> Y0 -> V0 -> Y1 -> + * ... + * + * There is an option to swap the bytes around before storing in + * memory, to achieve different pixel formats: + * + * Byte3 <----------- Byte0 + * [ Y1 ][ V0 ][ Y0 ][ U0 ] MODE 11 + * [ Y1 ][ U0 ][ Y0 ][ V0 ] MODE 10 + * [ V0 ][ Y1 ][ U0 ][ Y0 ] MODE 01 + * [ U0 ][ Y1 ][ V0 ][ Y0 ] MODE 00 + * + * We don't have any requirement to change pixelformat from what is + * coming from the source, so we keep it in MODE 11, which does not + * swap any bytes when storing in memory. + */ + switch (fmt->fourcc) { + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + reg |= FIELD_PREP(SHIM_DMACNTX_YUV422, + SHIM_DMACNTX_YUV422_MODE_11); + break; + default: + /* Ignore if not YUV 4:2:2 */ + break; + } + + reg |= FIELD_PREP(SHIM_DMACNTX_SIZE, fmt->size); + + writel(reg, csi->shim + SHIM_DMACNTX); + + reg = FIELD_PREP(SHIM_PSI_CFG0_SRC_TAG, 0) | + FIELD_PREP(SHIM_PSI_CFG0_DST_TAG, 0); + writel(reg, csi->shim + SHIM_PSI_CFG0); +} + +static void ti_csi2rx_drain_callback(void *param) +{ + struct completion *drain_complete = param; + + complete(drain_complete); +} + +/* + * Drain the stale data left at the PSI-L endpoint. + * + * This might happen if no buffers are queued in time but source is still + * streaming. In multi-stream scenarios this can happen when one stream is + * stopped but other is still streaming, and thus module-level pixel reset is + * not asserted. + * + * To prevent that stale data corrupting the subsequent transactions, it is + * required to issue DMA requests to drain it out. + */ +static int ti_csi2rx_drain_dma(struct ti_csi2rx_dev *csi) +{ + struct dma_async_tx_descriptor *desc; + struct completion drain_complete; + dma_cookie_t cookie; + int ret; + + init_completion(&drain_complete); + + desc = dmaengine_prep_slave_single(csi->dma.chan, csi->dma.drain.paddr, + csi->dma.drain.len, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + ret = -EIO; + goto out; + } + + desc->callback = ti_csi2rx_drain_callback; + desc->callback_param = &drain_complete; + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) + goto out; + + dma_async_issue_pending(csi->dma.chan); + + if (!wait_for_completion_timeout(&drain_complete, + msecs_to_jiffies(DRAIN_TIMEOUT_MS))) { + dmaengine_terminate_sync(csi->dma.chan); + dev_dbg(csi->dev, "DMA transfer timed out for drain buffer\n"); + ret = -ETIMEDOUT; + goto out; + } +out: + return ret; +} + +static void ti_csi2rx_dma_callback(void *param) +{ + struct ti_csi2rx_buffer *buf = param; + struct ti_csi2rx_dev *csi = buf->csi; + struct ti_csi2rx_dma *dma = &csi->dma; + unsigned long flags; + + /* + * TODO: Derive the sequence number from the CSI2RX frame number + * hardware monitor registers. + */ + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.sequence = csi->sequence++; + + spin_lock_irqsave(&dma->lock, flags); + + WARN_ON(!list_is_first(&buf->list, &dma->submitted)); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + list_del(&buf->list); + + /* If there are more buffers to process then start their transfer. */ + while (!list_empty(&dma->queue)) { + buf = list_entry(dma->queue.next, struct ti_csi2rx_buffer, list); + + if (ti_csi2rx_start_dma(csi, buf)) { + dev_err(csi->dev, "Failed to queue the next buffer for DMA\n"); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } else { + list_move_tail(&buf->list, &dma->submitted); + } + } + + if (list_empty(&dma->submitted)) + dma->state = TI_CSI2RX_DMA_IDLE; + + spin_unlock_irqrestore(&dma->lock, flags); +} + +static int ti_csi2rx_start_dma(struct ti_csi2rx_dev *csi, + struct ti_csi2rx_buffer *buf) +{ + unsigned long addr; + struct dma_async_tx_descriptor *desc; + size_t len = csi->v_fmt.fmt.pix.sizeimage; + dma_cookie_t cookie; + int ret = 0; + + addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + desc = dmaengine_prep_slave_single(csi->dma.chan, addr, len, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + return -EIO; + + desc->callback = ti_csi2rx_dma_callback; + desc->callback_param = buf; + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) + return ret; + + dma_async_issue_pending(csi->dma.chan); + + return 0; +} + +static void ti_csi2rx_stop_dma(struct ti_csi2rx_dev *csi) +{ + struct ti_csi2rx_dma *dma = &csi->dma; + enum ti_csi2rx_dma_state state; + unsigned long flags; + int ret; + + spin_lock_irqsave(&dma->lock, flags); + state = csi->dma.state; + dma->state = TI_CSI2RX_DMA_STOPPED; + spin_unlock_irqrestore(&dma->lock, flags); + + if (state != TI_CSI2RX_DMA_STOPPED) { + /* + * Normal DMA termination does not clean up pending data on + * the endpoint if multiple streams are running and only one + * is stopped, as the module-level pixel reset cannot be + * enforced before terminating DMA. + */ + ret = ti_csi2rx_drain_dma(csi); + if (ret && ret != -ETIMEDOUT) + dev_warn(csi->dev, + "Failed to drain DMA. Next frame might be bogus\n"); + } + + ret = dmaengine_terminate_sync(csi->dma.chan); + if (ret) + dev_err(csi->dev, "Failed to stop DMA: %d\n", ret); +} + +static void ti_csi2rx_cleanup_buffers(struct ti_csi2rx_dev *csi, + enum vb2_buffer_state state) +{ + struct ti_csi2rx_dma *dma = &csi->dma; + struct ti_csi2rx_buffer *buf, *tmp; + unsigned long flags; + + spin_lock_irqsave(&dma->lock, flags); + list_for_each_entry_safe(buf, tmp, &csi->dma.queue, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + list_for_each_entry_safe(buf, tmp, &csi->dma.submitted, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + spin_unlock_irqrestore(&dma->lock, flags); +} + +static int ti_csi2rx_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct ti_csi2rx_dev *csi = vb2_get_drv_priv(q); + unsigned int size = csi->v_fmt.fmt.pix.sizeimage; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + size = sizes[0]; + } + + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int ti_csi2rx_buffer_prepare(struct vb2_buffer *vb) +{ + struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size = csi->v_fmt.fmt.pix.sizeimage; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(csi->dev, "Data will not fit into plane\n"); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + return 0; +} + +static void ti_csi2rx_buffer_queue(struct vb2_buffer *vb) +{ + struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vb->vb2_queue); + struct ti_csi2rx_buffer *buf; + struct ti_csi2rx_dma *dma = &csi->dma; + bool restart_dma = false; + unsigned long flags = 0; + int ret; + + buf = container_of(vb, struct ti_csi2rx_buffer, vb.vb2_buf); + buf->csi = csi; + + spin_lock_irqsave(&dma->lock, flags); + /* + * Usually the DMA callback takes care of queueing the pending buffers. + * But if DMA has stalled due to lack of buffers, restart it now. + */ + if (dma->state == TI_CSI2RX_DMA_IDLE) { + /* + * Do not restart DMA with the lock held because + * ti_csi2rx_drain_dma() might block for completion. + * There won't be a race on queueing DMA anyway since the + * callback is not being fired. + */ + restart_dma = true; + dma->state = TI_CSI2RX_DMA_ACTIVE; + } else { + list_add_tail(&buf->list, &dma->queue); + } + spin_unlock_irqrestore(&dma->lock, flags); + + if (restart_dma) { + /* + * Once frames start dropping, some data gets stuck in the DMA + * pipeline somewhere. So the first DMA transfer after frame + * drops gives a partial frame. This is obviously not useful to + * the application and will only confuse it. Issue a DMA + * transaction to drain that up. + */ + ret = ti_csi2rx_drain_dma(csi); + if (ret && ret != -ETIMEDOUT) + dev_warn(csi->dev, + "Failed to drain DMA. Next frame might be bogus\n"); + + ret = ti_csi2rx_start_dma(csi, buf); + if (ret) { + dev_err(csi->dev, "Failed to start DMA: %d\n", ret); + spin_lock_irqsave(&dma->lock, flags); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dma->state = TI_CSI2RX_DMA_IDLE; + spin_unlock_irqrestore(&dma->lock, flags); + } else { + spin_lock_irqsave(&dma->lock, flags); + list_add_tail(&buf->list, &dma->submitted); + spin_unlock_irqrestore(&dma->lock, flags); + } + } +} + +static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vq); + struct ti_csi2rx_dma *dma = &csi->dma; + struct ti_csi2rx_buffer *buf; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&dma->lock, flags); + if (list_empty(&dma->queue)) + ret = -EIO; + spin_unlock_irqrestore(&dma->lock, flags); + if (ret) + return ret; + + ret = video_device_pipeline_start(&csi->vdev, &csi->pipe); + if (ret) + goto err; + + ti_csi2rx_setup_shim(csi); + + csi->sequence = 0; + + spin_lock_irqsave(&dma->lock, flags); + buf = list_entry(dma->queue.next, struct ti_csi2rx_buffer, list); + + ret = ti_csi2rx_start_dma(csi, buf); + if (ret) { + dev_err(csi->dev, "Failed to start DMA: %d\n", ret); + spin_unlock_irqrestore(&dma->lock, flags); + goto err_pipeline; + } + + list_move_tail(&buf->list, &dma->submitted); + dma->state = TI_CSI2RX_DMA_ACTIVE; + spin_unlock_irqrestore(&dma->lock, flags); + + ret = v4l2_subdev_call(csi->source, video, s_stream, 1); + if (ret) + goto err_dma; + + return 0; + +err_dma: + ti_csi2rx_stop_dma(csi); +err_pipeline: + video_device_pipeline_stop(&csi->vdev); + writel(0, csi->shim + SHIM_CNTL); + writel(0, csi->shim + SHIM_DMACNTX); +err: + ti_csi2rx_cleanup_buffers(csi, VB2_BUF_STATE_QUEUED); + return ret; +} + +static void ti_csi2rx_stop_streaming(struct vb2_queue *vq) +{ + struct ti_csi2rx_dev *csi = vb2_get_drv_priv(vq); + int ret; + + video_device_pipeline_stop(&csi->vdev); + + writel(0, csi->shim + SHIM_CNTL); + writel(0, csi->shim + SHIM_DMACNTX); + + ret = v4l2_subdev_call(csi->source, video, s_stream, 0); + if (ret) + dev_err(csi->dev, "Failed to stop subdev stream\n"); + + ti_csi2rx_stop_dma(csi); + ti_csi2rx_cleanup_buffers(csi, VB2_BUF_STATE_ERROR); +} + +static const struct vb2_ops csi_vb2_qops = { + .queue_setup = ti_csi2rx_queue_setup, + .buf_prepare = ti_csi2rx_buffer_prepare, + .buf_queue = ti_csi2rx_buffer_queue, + .start_streaming = ti_csi2rx_start_streaming, + .stop_streaming = ti_csi2rx_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int ti_csi2rx_init_vb2q(struct ti_csi2rx_dev *csi) +{ + struct vb2_queue *q = &csi->vidq; + int ret; + + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = csi; + q->buf_struct_size = sizeof(struct ti_csi2rx_buffer); + q->ops = &csi_vb2_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->dev = dmaengine_get_dma_device(csi->dma.chan); + q->lock = &csi->mutex; + q->min_buffers_needed = 1; + + ret = vb2_queue_init(q); + if (ret) + return ret; + + csi->vdev.queue = q; + + return 0; +} + +static int ti_csi2rx_link_validate(struct media_link *link) +{ + struct media_entity *entity = link->sink->entity; + struct video_device *vdev = media_entity_to_video_device(entity); + struct ti_csi2rx_dev *csi = container_of(vdev, struct ti_csi2rx_dev, vdev); + struct v4l2_pix_format *csi_fmt = &csi->v_fmt.fmt.pix; + struct v4l2_subdev_format source_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .pad = link->source->index, + }; + const struct ti_csi2rx_fmt *ti_fmt; + int ret; + + ret = v4l2_subdev_call_state_active(csi->source, pad, + get_fmt, &source_fmt); + if (ret) + return ret; + + if (source_fmt.format.width != csi_fmt->width) { + dev_dbg(csi->dev, "Width does not match (source %u, sink %u)\n", + source_fmt.format.width, csi_fmt->width); + return -EPIPE; + } + + if (source_fmt.format.height != csi_fmt->height) { + dev_dbg(csi->dev, "Height does not match (source %u, sink %u)\n", + source_fmt.format.height, csi_fmt->height); + return -EPIPE; + } + + if (source_fmt.format.field != csi_fmt->field && + csi_fmt->field != V4L2_FIELD_NONE) { + dev_dbg(csi->dev, "Field does not match (source %u, sink %u)\n", + source_fmt.format.field, csi_fmt->field); + return -EPIPE; + } + + ti_fmt = find_format_by_code(source_fmt.format.code); + if (!ti_fmt) { + dev_dbg(csi->dev, "Media bus format 0x%x not supported\n", + source_fmt.format.code); + return -EPIPE; + } + + if (ti_fmt->fourcc != csi_fmt->pixelformat) { + dev_dbg(csi->dev, + "Cannot transform source fmt 0x%x to sink fmt 0x%x\n", + ti_fmt->fourcc, csi_fmt->pixelformat); + return -EPIPE; + } + + return 0; +} + +static const struct media_entity_operations ti_csi2rx_video_entity_ops = { + .link_validate = ti_csi2rx_link_validate, +}; + +static int ti_csi2rx_init_dma(struct ti_csi2rx_dev *csi) +{ + struct dma_slave_config cfg = { + .src_addr_width = DMA_SLAVE_BUSWIDTH_16_BYTES, + }; + int ret; + + INIT_LIST_HEAD(&csi->dma.queue); + INIT_LIST_HEAD(&csi->dma.submitted); + spin_lock_init(&csi->dma.lock); + + csi->dma.state = TI_CSI2RX_DMA_STOPPED; + + csi->dma.chan = dma_request_chan(csi->dev, "rx0"); + if (IS_ERR(csi->dma.chan)) + return PTR_ERR(csi->dma.chan); + + ret = dmaengine_slave_config(csi->dma.chan, &cfg); + if (ret) { + dma_release_channel(csi->dma.chan); + return ret; + } + + csi->dma.drain.len = DRAIN_BUFFER_SIZE; + csi->dma.drain.vaddr = dma_alloc_coherent(csi->dev, csi->dma.drain.len, + &csi->dma.drain.paddr, + GFP_KERNEL); + if (!csi->dma.drain.vaddr) + return -ENOMEM; + + return 0; +} + +static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) +{ + struct media_device *mdev = &csi->mdev; + struct video_device *vdev = &csi->vdev; + const struct ti_csi2rx_fmt *fmt; + struct v4l2_pix_format *pix_fmt = &csi->v_fmt.fmt.pix; + int ret; + + fmt = find_format_by_fourcc(V4L2_PIX_FMT_UYVY); + if (!fmt) + return -EINVAL; + + pix_fmt->width = 640; + pix_fmt->height = 480; + pix_fmt->field = V4L2_FIELD_NONE; + pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; + pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601, + pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE, + pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB, + + ti_csi2rx_fill_fmt(fmt, &csi->v_fmt); + + mdev->dev = csi->dev; + mdev->hw_revision = 1; + strscpy(mdev->model, "TI-CSI2RX", sizeof(mdev->model)); + + media_device_init(mdev); + + strscpy(vdev->name, TI_CSI2RX_MODULE_NAME, sizeof(vdev->name)); + vdev->v4l2_dev = &csi->v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + vdev->fops = &csi_fops; + vdev->ioctl_ops = &csi_ioctl_ops; + vdev->release = video_device_release_empty; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_IO_MC; + vdev->lock = &csi->mutex; + video_set_drvdata(vdev, csi); + + csi->pad.flags = MEDIA_PAD_FL_SINK; + vdev->entity.ops = &ti_csi2rx_video_entity_ops; + ret = media_entity_pads_init(&csi->vdev.entity, 1, &csi->pad); + if (ret) + return ret; + + csi->v4l2_dev.mdev = mdev; + + ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); + if (ret) + return ret; + + ret = media_device_register(mdev); + if (ret) { + v4l2_device_unregister(&csi->v4l2_dev); + media_device_cleanup(mdev); + return ret; + } + + return 0; +} + +static void ti_csi2rx_cleanup_dma(struct ti_csi2rx_dev *csi) +{ + dma_free_coherent(csi->dev, csi->dma.drain.len, + csi->dma.drain.vaddr, csi->dma.drain.paddr); + csi->dma.drain.vaddr = NULL; + dma_release_channel(csi->dma.chan); +} + +static void ti_csi2rx_cleanup_v4l2(struct ti_csi2rx_dev *csi) +{ + media_device_unregister(&csi->mdev); + v4l2_device_unregister(&csi->v4l2_dev); + media_device_cleanup(&csi->mdev); +} + +static void ti_csi2rx_cleanup_subdev(struct ti_csi2rx_dev *csi) +{ + v4l2_async_nf_unregister(&csi->notifier); + v4l2_async_nf_cleanup(&csi->notifier); +} + +static void ti_csi2rx_cleanup_vb2q(struct ti_csi2rx_dev *csi) +{ + vb2_queue_release(&csi->vidq); +} + +static int ti_csi2rx_probe(struct platform_device *pdev) +{ + struct ti_csi2rx_dev *csi; + struct resource *res; + int ret; + + csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); + if (!csi) + return -ENOMEM; + + csi->dev = &pdev->dev; + platform_set_drvdata(pdev, csi); + + mutex_init(&csi->mutex); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + csi->shim = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(csi->shim)) { + ret = PTR_ERR(csi->shim); + goto err_mutex; + } + + ret = ti_csi2rx_init_dma(csi); + if (ret) + goto err_mutex; + + ret = ti_csi2rx_v4l2_init(csi); + if (ret) + goto err_dma; + + ret = ti_csi2rx_init_vb2q(csi); + if (ret) + goto err_v4l2; + + ret = ti_csi2rx_notifier_register(csi); + if (ret) + goto err_vb2q; + + ret = of_platform_populate(csi->dev->of_node, NULL, NULL, csi->dev); + if (ret) { + dev_err(csi->dev, "Failed to create children: %d\n", ret); + goto err_subdev; + } + + return 0; + +err_subdev: + ti_csi2rx_cleanup_subdev(csi); +err_vb2q: + ti_csi2rx_cleanup_vb2q(csi); +err_v4l2: + ti_csi2rx_cleanup_v4l2(csi); +err_dma: + ti_csi2rx_cleanup_dma(csi); +err_mutex: + mutex_destroy(&csi->mutex); + return ret; +} + +static int ti_csi2rx_remove(struct platform_device *pdev) +{ + struct ti_csi2rx_dev *csi = platform_get_drvdata(pdev); + + video_unregister_device(&csi->vdev); + + ti_csi2rx_cleanup_vb2q(csi); + ti_csi2rx_cleanup_subdev(csi); + ti_csi2rx_cleanup_v4l2(csi); + ti_csi2rx_cleanup_dma(csi); + + mutex_destroy(&csi->mutex); + + return 0; +} + +static const struct of_device_id ti_csi2rx_of_match[] = { + { .compatible = "ti,j721e-csi2rx-shim", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ti_csi2rx_of_match); + +static struct platform_driver ti_csi2rx_pdrv = { + .probe = ti_csi2rx_probe, + .remove = ti_csi2rx_remove, + .driver = { + .name = TI_CSI2RX_MODULE_NAME, + .of_match_table = ti_csi2rx_of_match, + }, +}; + +module_platform_driver(ti_csi2rx_pdrv); + +MODULE_DESCRIPTION("TI J721E CSI2 RX Driver"); +MODULE_AUTHOR("Jai Luthra <j-luthra@ti.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/ti/omap3isp/ispstat.c b/drivers/media/platform/ti/omap3isp/ispstat.c index 68cf68dbca..359a846205 100644 --- a/drivers/media/platform/ti/omap3isp/ispstat.c +++ b/drivers/media/platform/ti/omap3isp/ispstat.c @@ -1039,7 +1039,7 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name, struct media_entity *me = &subdev->entity; v4l2_subdev_init(subdev, sd_ops); - snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); + snprintf(subdev->name, sizeof(subdev->name), "OMAP3 ISP %s", name); subdev->grp_id = BIT(16); /* group ID for isp subdevs */ subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; v4l2_set_subdevdata(subdev, stat); diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 1874c97608..3a2a0f28cb 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -899,8 +899,9 @@ static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid) vfd->vfl_dir = VFL_DIR_M2M; vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; vfd->ioctl_ops = &hantro_ioctl_ops; - snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible, - funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? "enc" : "dec"); + strscpy(vfd->name, match->compatible, sizeof(vfd->name)); + strlcat(vfd->name, funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? + "-enc" : "-dec", sizeof(vfd->name)); if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) { vpu->encoder = func; diff --git a/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.c b/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.c index f2ae84f0b4..f64dea797e 100644 --- a/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.c +++ b/drivers/media/platform/verisilicon/rockchip_av1_filmgrain.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only or Apache-2.0 +// SPDX-License-Identifier: GPL-2.0-only OR Apache-2.0 #include "rockchip_av1_filmgrain.h" diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 80d6f5b072..a96de5d388 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -708,9 +708,8 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, snprintf(name, sizeof(name), "port%u", port); dma->dma = dma_request_chan(dma->xdev->dev, name); if (IS_ERR(dma->dma)) { - ret = PTR_ERR(dma->dma); - if (ret != -EPROBE_DEFER) - dev_err(dma->xdev->dev, "no VDMA channel found\n"); + ret = dev_err_probe(dma->xdev->dev, PTR_ERR(dma->dma), + "no VDMA channel found\n"); goto error; } diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index c591c0851f..ad49151f5f 100644 --- a/drivers/media/radio/radio-isa.c +++ b/drivers/media/radio/radio-isa.c @@ -36,7 +36,7 @@ static int radio_isa_querycap(struct file *file, void *priv, strscpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver)); strscpy(v->card, isa->drv->card, sizeof(v->card)); - snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name); + snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev_name(isa->v4l2_dev.dev)); return 0; } diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 99788834c6..08be77b8f3 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -199,11 +199,9 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { - struct pcm20 *dev = video_drvdata(file); - strscpy(v->driver, "Miro PCM20", sizeof(v->driver)); strscpy(v->card, "Miro PCM20", sizeof(v->card)); - snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name); + strscpy(v->bus_info, "ISA:radio-miropcm20", sizeof(v->bus_info)); return 0; } diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 6061506159..b2c5809a8b 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -328,9 +328,7 @@ static int si476x_radio_querycap(struct file *file, void *priv, strscpy(capability->driver, radio->v4l2dev.name, sizeof(capability->driver)); - strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); - snprintf(capability->bus_info, sizeof(capability->bus_info), - "platform:%s", radio->v4l2dev.name); + strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); return 0; } diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index e8166eac9e..f6b98c304b 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1020,7 +1020,7 @@ static int wl1273_fm_set_rds(struct wl1273_device *radio, unsigned int new_mode) } if (!r) - radio->rds_on = (new_mode == WL1273_RDS_ON) ? true : false; + radio->rds_on = new_mode == WL1273_RDS_ON; return r; } diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 07bdf649c6..2afe67ffa2 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -338,16 +338,6 @@ config IR_REDRAT3 To compile this driver as a module, choose M here: the module will be called redrat3. -config IR_RX51 - tristate "Nokia N900 IR transmitter diode" - depends on (OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS || COMPILE_TEST) && RC_CORE - help - Say Y or M here if you want to enable support for the IR - transmitter diode built in the Nokia N900 (RX51) device. - - The driver uses omap DM timers for generating the carrier - wave and pulses. - config IR_SERIAL tristate "Homebrew Serial Port Receiver" depends on HAS_IOPORT diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index a9285266e9..2bca6f7f07 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -43,7 +43,6 @@ obj-$(CONFIG_IR_MTK) += mtk-cir.o obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o obj-$(CONFIG_IR_PWM_TX) += pwm-ir-tx.o obj-$(CONFIG_IR_REDRAT3) += redrat3.o -obj-$(CONFIG_IR_RX51) += ir-rx51.o obj-$(CONFIG_IR_SERIAL) += serial_ir.o obj-$(CONFIG_IR_SPI) += ir-spi.o obj-$(CONFIG_IR_STREAMZAP) += streamzap.o diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index fff4dd48ea..d7721e6077 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -251,7 +251,7 @@ struct ati_remote { char rc_name[NAME_BUFSIZE]; char rc_phys[NAME_BUFSIZE]; - char mouse_name[NAME_BUFSIZE]; + char mouse_name[NAME_BUFSIZE + 6]; char mouse_phys[NAME_BUFSIZE]; wait_queue_head_t wait; diff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c index fe17c7f98e..52d82cbe76 100644 --- a/drivers/media/rc/bpf-lirc.c +++ b/drivers/media/rc/bpf-lirc.c @@ -253,7 +253,7 @@ int lirc_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog) if (attr->attach_flags) return -EINVAL; - rcdev = rc_dev_get_from_fd(attr->target_fd); + rcdev = rc_dev_get_from_fd(attr->target_fd, true); if (IS_ERR(rcdev)) return PTR_ERR(rcdev); @@ -278,7 +278,7 @@ int lirc_prog_detach(const union bpf_attr *attr) if (IS_ERR(prog)) return PTR_ERR(prog); - rcdev = rc_dev_get_from_fd(attr->target_fd); + rcdev = rc_dev_get_from_fd(attr->target_fd, true); if (IS_ERR(rcdev)) { bpf_prog_put(prog); return PTR_ERR(rcdev); @@ -303,7 +303,7 @@ int lirc_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr) if (attr->query.query_flags) return -EINVAL; - rcdev = rc_dev_get_from_fd(attr->query.target_fd); + rcdev = rc_dev_get_from_fd(attr->query.target_fd, false); if (IS_ERR(rcdev)) return PTR_ERR(rcdev); diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c deleted file mode 100644 index 13e81bf800..0000000000 --- a/drivers/media/rc/ir-rx51.c +++ /dev/null @@ -1,285 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2008 Nokia Corporation - * - * Based on lirc_serial.c - */ -#include <linux/clk.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/wait.h> -#include <linux/pwm.h> -#include <linux/of.h> -#include <linux/hrtimer.h> - -#include <media/rc-core.h> - -#define WBUF_LEN 256 - -struct ir_rx51 { - struct rc_dev *rcdev; - struct pwm_device *pwm; - struct pwm_state state; - struct hrtimer timer; - struct device *dev; - wait_queue_head_t wqueue; - - unsigned int freq; /* carrier frequency */ - unsigned int duty_cycle; /* carrier duty cycle */ - int wbuf[WBUF_LEN]; - int wbuf_index; - unsigned long device_is_open; -}; - -static inline void ir_rx51_on(struct ir_rx51 *ir_rx51) -{ - ir_rx51->state.enabled = true; - pwm_apply_state(ir_rx51->pwm, &ir_rx51->state); -} - -static inline void ir_rx51_off(struct ir_rx51 *ir_rx51) -{ - ir_rx51->state.enabled = false; - pwm_apply_state(ir_rx51->pwm, &ir_rx51->state); -} - -static int init_timing_params(struct ir_rx51 *ir_rx51) -{ - ir_rx51->state.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, ir_rx51->freq); - pwm_set_relative_duty_cycle(&ir_rx51->state, ir_rx51->duty_cycle, 100); - - return 0; -} - -static enum hrtimer_restart ir_rx51_timer_cb(struct hrtimer *timer) -{ - struct ir_rx51 *ir_rx51 = container_of(timer, struct ir_rx51, timer); - ktime_t now; - - if (ir_rx51->wbuf_index < 0) { - dev_err_ratelimited(ir_rx51->dev, - "BUG wbuf_index has value of %i\n", - ir_rx51->wbuf_index); - goto end; - } - - /* - * If we happen to hit an odd latency spike, loop through the - * pulses until we catch up. - */ - do { - u64 ns; - - if (ir_rx51->wbuf_index >= WBUF_LEN) - goto end; - if (ir_rx51->wbuf[ir_rx51->wbuf_index] == -1) - goto end; - - if (ir_rx51->wbuf_index % 2) - ir_rx51_off(ir_rx51); - else - ir_rx51_on(ir_rx51); - - ns = US_TO_NS(ir_rx51->wbuf[ir_rx51->wbuf_index]); - hrtimer_add_expires_ns(timer, ns); - - ir_rx51->wbuf_index++; - - now = timer->base->get_time(); - - } while (hrtimer_get_expires_tv64(timer) < now); - - return HRTIMER_RESTART; -end: - /* Stop TX here */ - ir_rx51_off(ir_rx51); - ir_rx51->wbuf_index = -1; - - wake_up_interruptible(&ir_rx51->wqueue); - - return HRTIMER_NORESTART; -} - -static int ir_rx51_tx(struct rc_dev *dev, unsigned int *buffer, - unsigned int count) -{ - struct ir_rx51 *ir_rx51 = dev->priv; - - if (count > WBUF_LEN) - return -EINVAL; - - memcpy(ir_rx51->wbuf, buffer, count * sizeof(unsigned int)); - - /* Wait any pending transfers to finish */ - wait_event_interruptible(ir_rx51->wqueue, ir_rx51->wbuf_index < 0); - - init_timing_params(ir_rx51); - if (count < WBUF_LEN) - ir_rx51->wbuf[count] = -1; /* Insert termination mark */ - - /* - * REVISIT: Adjust latency requirements so the device doesn't go in too - * deep sleep states with pm_qos_add_request(). - */ - - ir_rx51_on(ir_rx51); - ir_rx51->wbuf_index = 1; - hrtimer_start(&ir_rx51->timer, - ns_to_ktime(US_TO_NS(ir_rx51->wbuf[0])), - HRTIMER_MODE_REL); - /* - * Don't return back to the userspace until the transfer has - * finished - */ - wait_event_interruptible(ir_rx51->wqueue, ir_rx51->wbuf_index < 0); - - /* REVISIT: Remove pm_qos constraint, we can sleep again */ - - return count; -} - -static int ir_rx51_open(struct rc_dev *dev) -{ - struct ir_rx51 *ir_rx51 = dev->priv; - - if (test_and_set_bit(1, &ir_rx51->device_is_open)) - return -EBUSY; - - ir_rx51->pwm = pwm_get(ir_rx51->dev, NULL); - if (IS_ERR(ir_rx51->pwm)) { - int res = PTR_ERR(ir_rx51->pwm); - - dev_err(ir_rx51->dev, "pwm_get failed: %d\n", res); - return res; - } - - return 0; -} - -static void ir_rx51_release(struct rc_dev *dev) -{ - struct ir_rx51 *ir_rx51 = dev->priv; - - hrtimer_cancel(&ir_rx51->timer); - ir_rx51_off(ir_rx51); - pwm_put(ir_rx51->pwm); - - clear_bit(1, &ir_rx51->device_is_open); -} - -static struct ir_rx51 ir_rx51 = { - .duty_cycle = 50, - .wbuf_index = -1, -}; - -static int ir_rx51_set_duty_cycle(struct rc_dev *dev, u32 duty) -{ - struct ir_rx51 *ir_rx51 = dev->priv; - - ir_rx51->duty_cycle = duty; - - return 0; -} - -static int ir_rx51_set_tx_carrier(struct rc_dev *dev, u32 carrier) -{ - struct ir_rx51 *ir_rx51 = dev->priv; - - if (carrier > 500000 || carrier < 20000) - return -EINVAL; - - ir_rx51->freq = carrier; - - return 0; -} - -#ifdef CONFIG_PM - -static int ir_rx51_suspend(struct platform_device *dev, pm_message_t state) -{ - /* - * In case the device is still open, do not suspend. Normally - * this should not be a problem as lircd only keeps the device - * open only for short periods of time. We also don't want to - * get involved with race conditions that might happen if we - * were in a middle of a transmit. Thus, we defer any suspend - * actions until transmit has completed. - */ - if (test_and_set_bit(1, &ir_rx51.device_is_open)) - return -EAGAIN; - - clear_bit(1, &ir_rx51.device_is_open); - - return 0; -} - -static int ir_rx51_resume(struct platform_device *dev) -{ - return 0; -} - -#else - -#define ir_rx51_suspend NULL -#define ir_rx51_resume NULL - -#endif /* CONFIG_PM */ - -static int ir_rx51_probe(struct platform_device *dev) -{ - struct pwm_device *pwm; - struct rc_dev *rcdev; - - pwm = pwm_get(&dev->dev, NULL); - if (IS_ERR(pwm)) - return dev_err_probe(&dev->dev, PTR_ERR(pwm), "pwm_get failed\n"); - - /* Use default, in case userspace does not set the carrier */ - ir_rx51.freq = DIV_ROUND_CLOSEST_ULL(pwm_get_period(pwm), NSEC_PER_SEC); - pwm_init_state(pwm, &ir_rx51.state); - pwm_put(pwm); - - hrtimer_init(&ir_rx51.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - ir_rx51.timer.function = ir_rx51_timer_cb; - - ir_rx51.dev = &dev->dev; - - rcdev = devm_rc_allocate_device(&dev->dev, RC_DRIVER_IR_RAW_TX); - if (!rcdev) - return -ENOMEM; - - rcdev->priv = &ir_rx51; - rcdev->open = ir_rx51_open; - rcdev->close = ir_rx51_release; - rcdev->tx_ir = ir_rx51_tx; - rcdev->s_tx_duty_cycle = ir_rx51_set_duty_cycle; - rcdev->s_tx_carrier = ir_rx51_set_tx_carrier; - rcdev->driver_name = KBUILD_MODNAME; - - ir_rx51.rcdev = rcdev; - - return devm_rc_register_device(&dev->dev, ir_rx51.rcdev); -} - -static const struct of_device_id ir_rx51_match[] = { - { - .compatible = "nokia,n900-ir", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, ir_rx51_match); - -static struct platform_driver ir_rx51_platform_driver = { - .probe = ir_rx51_probe, - .suspend = ir_rx51_suspend, - .resume = ir_rx51_resume, - .driver = { - .name = KBUILD_MODNAME, - .of_match_table = ir_rx51_match, - }, -}; -module_platform_driver(ir_rx51_platform_driver); - -MODULE_DESCRIPTION("IR TX driver for Nokia RX51"); -MODULE_AUTHOR("Nokia Corporation"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c index 1968067092..69e630d852 100644 --- a/drivers/media/rc/ir_toy.c +++ b/drivers/media/rc/ir_toy.c @@ -332,6 +332,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count) sizeof(COMMAND_SMODE_EXIT), STATE_COMMAND_NO_RESP); if (err) { dev_err(irtoy->dev, "exit sample mode: %d\n", err); + kfree(buf); return err; } @@ -339,6 +340,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count) sizeof(COMMAND_SMODE_ENTER), STATE_COMMAND); if (err) { dev_err(irtoy->dev, "enter sample mode: %d\n", err); + kfree(buf); return err; } diff --git a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c index 0a867ca900..e24946c8fe 100644 --- a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c +++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c @@ -83,3 +83,4 @@ module_exit(exit_rc_map_adstech_dvb_t_pci) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("ADS Tech Instant TV DVB-T PCI Remote"); diff --git a/drivers/media/rc/keymaps/rc-alink-dtu-m.c b/drivers/media/rc/keymaps/rc-alink-dtu-m.c index 8a2ccaf3b8..9926259b43 100644 --- a/drivers/media/rc/keymaps/rc-alink-dtu-m.c +++ b/drivers/media/rc/keymaps/rc-alink-dtu-m.c @@ -54,3 +54,4 @@ module_exit(exit_rc_map_alink_dtu_m) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("A-Link DTU(m) slim remote, 6 rows, 3 columns."); diff --git a/drivers/media/rc/keymaps/rc-anysee.c b/drivers/media/rc/keymaps/rc-anysee.c index 34da03c461..e4bcbf889f 100644 --- a/drivers/media/rc/keymaps/rc-anysee.c +++ b/drivers/media/rc/keymaps/rc-anysee.c @@ -79,3 +79,4 @@ module_exit(exit_rc_map_anysee) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("Anysee remote keytable"); diff --git a/drivers/media/rc/keymaps/rc-apac-viewcomp.c b/drivers/media/rc/keymaps/rc-apac-viewcomp.c index bdc47e25d4..80b096f02e 100644 --- a/drivers/media/rc/keymaps/rc-apac-viewcomp.c +++ b/drivers/media/rc/keymaps/rc-apac-viewcomp.c @@ -74,3 +74,4 @@ module_exit(exit_rc_map_apac_viewcomp) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("apac-viewcomp remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c b/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c index 1d32213789..212b0d9209 100644 --- a/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c +++ b/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c @@ -62,3 +62,4 @@ module_exit(exit_rc_map_t2hybrid) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>"); +MODULE_DESCRIPTION("Astrometa T2hybrid remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-asus-pc39.c b/drivers/media/rc/keymaps/rc-asus-pc39.c index 7a4b3a6e3a..bd55b7c6f8 100644 --- a/drivers/media/rc/keymaps/rc-asus-pc39.c +++ b/drivers/media/rc/keymaps/rc-asus-pc39.c @@ -85,3 +85,4 @@ module_exit(exit_rc_map_asus_pc39) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Model PC-39 keytable for asus-pc39 remote controller"); diff --git a/drivers/media/rc/keymaps/rc-asus-ps3-100.c b/drivers/media/rc/keymaps/rc-asus-ps3-100.c index 09b60fa335..9d63c1e4a1 100644 --- a/drivers/media/rc/keymaps/rc-asus-ps3-100.c +++ b/drivers/media/rc/keymaps/rc-asus-ps3-100.c @@ -84,3 +84,4 @@ module_exit(exit_rc_map_asus_ps3_100) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Asus My Cinema PS3-100 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c index b4b7932c0c..063237f0d2 100644 --- a/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c +++ b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c @@ -63,3 +63,4 @@ module_exit(exit_rc_map_ati_tv_wonder_hd_600) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("ati-tv-wonder-hd-600 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c index 31fe1106b7..9f7cbe9a1a 100644 --- a/drivers/media/rc/keymaps/rc-ati-x10.c +++ b/drivers/media/rc/keymaps/rc-ati-x10.c @@ -123,3 +123,4 @@ module_exit(exit_rc_map_ati_x10) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>"); +MODULE_DESCRIPTION("ATI X10 RF remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-a16d.c b/drivers/media/rc/keymaps/rc-avermedia-a16d.c index 6467ff6e48..98497f4f6f 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-a16d.c +++ b/drivers/media/rc/keymaps/rc-avermedia-a16d.c @@ -69,3 +69,4 @@ module_exit(exit_rc_map_avermedia_a16d) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("avermedia-a16d remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c index 54fc6d9022..5832c2f8ab 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c +++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c @@ -91,3 +91,4 @@ module_exit(exit_rc_map_avermedia_cardbus) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("avermedia-cardbus remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c index 92c6df3360..3157d0c1ce 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c +++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c @@ -72,3 +72,4 @@ module_exit(exit_rc_map_avermedia_dvbt) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("avermedia-dvbt remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c index 311ddeb061..cc1318ad09 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m135a.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c @@ -142,3 +142,4 @@ module_exit(exit_rc_map_avermedia_m135a) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Avermedia M135A with RM-JX and RM-K6 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c index a970ed5a09..ec6c866c9f 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c @@ -90,3 +90,4 @@ module_exit(exit_rc_map_avermedia_m733a_rm_k6) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Avermedia M733A with IR model RM-K6 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c index cf8a4fd107..ee4fe5791a 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c +++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c @@ -65,3 +65,4 @@ module_exit(exit_rc_map_avermedia_rm_ks) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("AverMedia RM-KS remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avermedia.c b/drivers/media/rc/keymaps/rc-avermedia.c index f96f229b70..b827536a1f 100644 --- a/drivers/media/rc/keymaps/rc-avermedia.c +++ b/drivers/media/rc/keymaps/rc-avermedia.c @@ -80,3 +80,4 @@ module_exit(exit_rc_map_avermedia) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("avermedia remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-avertv-303.c b/drivers/media/rc/keymaps/rc-avertv-303.c index a3e2e945c7..71d1da4252 100644 --- a/drivers/media/rc/keymaps/rc-avertv-303.c +++ b/drivers/media/rc/keymaps/rc-avertv-303.c @@ -79,3 +79,4 @@ module_exit(exit_rc_map_avertv_303) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("AVERTV STUDIO 303 Remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c index 5fc8e4cd10..56f8eb1f0d 100644 --- a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c +++ b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c @@ -88,3 +88,4 @@ module_exit(exit_rc_map_azurewave_ad_tu700) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("TwinHan AzureWave AD-TU700(704J) remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-beelink-gs1.c b/drivers/media/rc/keymaps/rc-beelink-gs1.c index cedbd5d20b..6e767d88c7 100644 --- a/drivers/media/rc/keymaps/rc-beelink-gs1.c +++ b/drivers/media/rc/keymaps/rc-beelink-gs1.c @@ -82,3 +82,4 @@ module_exit(exit_rc_map_beelink_gs1) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Clément Péron <peron.clem@gmail.com>"); +MODULE_DESCRIPTION("Beelink GS1 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-beelink-mxiii.c b/drivers/media/rc/keymaps/rc-beelink-mxiii.c index 01180cd922..88fad9959a 100644 --- a/drivers/media/rc/keymaps/rc-beelink-mxiii.c +++ b/drivers/media/rc/keymaps/rc-beelink-mxiii.c @@ -55,3 +55,4 @@ module_exit(exit_rc_map_beelink_mxiii) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); +MODULE_DESCRIPTION("Beelink Mini MXIII remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c index 8579b3d512..6bdc924ac3 100644 --- a/drivers/media/rc/keymaps/rc-behold-columbus.c +++ b/drivers/media/rc/keymaps/rc-behold-columbus.c @@ -102,3 +102,4 @@ module_exit(exit_rc_map_behold_columbus) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("BeholdTV Columbus remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c index 28397ce05a..0251ce835f 100644 --- a/drivers/media/rc/keymaps/rc-behold.c +++ b/drivers/media/rc/keymaps/rc-behold.c @@ -135,3 +135,4 @@ module_exit(exit_rc_map_behold) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("BeholdTV 60x series remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-budget-ci-old.c b/drivers/media/rc/keymaps/rc-budget-ci-old.c index 6ca8222568..8fda5d1e14 100644 --- a/drivers/media/rc/keymaps/rc-budget-ci-old.c +++ b/drivers/media/rc/keymaps/rc-budget-ci-old.c @@ -87,3 +87,4 @@ module_exit(exit_rc_map_budget_ci_old) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("budget-ci-old remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-cinergy-1400.c b/drivers/media/rc/keymaps/rc-cinergy-1400.c index 4433d28b21..092c3533d7 100644 --- a/drivers/media/rc/keymaps/rc-cinergy-1400.c +++ b/drivers/media/rc/keymaps/rc-cinergy-1400.c @@ -78,3 +78,4 @@ module_exit(exit_rc_map_cinergy_1400) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Cinergy 1400 DVB-T remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-cinergy.c b/drivers/media/rc/keymaps/rc-cinergy.c index b34a37b8fe..334a290a3b 100644 --- a/drivers/media/rc/keymaps/rc-cinergy.c +++ b/drivers/media/rc/keymaps/rc-cinergy.c @@ -72,3 +72,4 @@ module_exit(exit_rc_map_cinergy) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("cinergy remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-ct-90405.c b/drivers/media/rc/keymaps/rc-ct-90405.c index 8914c83c9d..d4638df37c 100644 --- a/drivers/media/rc/keymaps/rc-ct-90405.c +++ b/drivers/media/rc/keymaps/rc-ct-90405.c @@ -84,3 +84,4 @@ module_exit(exit_rc_map_ct_90405) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexander Voronov <avv.0@ya.ru>"); +MODULE_DESCRIPTION("Toshiba CT-90405 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-d680-dmb.c b/drivers/media/rc/keymaps/rc-d680-dmb.c index d491a5e975..7870d36f2c 100644 --- a/drivers/media/rc/keymaps/rc-d680-dmb.c +++ b/drivers/media/rc/keymaps/rc-d680-dmb.c @@ -70,3 +70,4 @@ module_exit(exit_rc_map_d680_dmb) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("d680-dmb remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c index f1fcdf16f4..0323049fd2 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-nec.c +++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c @@ -118,3 +118,4 @@ module_exit(exit_rc_map) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("dib0700-nec remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dib0700-rc5.c b/drivers/media/rc/keymaps/rc-dib0700-rc5.c index 002fffcba9..d34e92eb92 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-rc5.c +++ b/drivers/media/rc/keymaps/rc-dib0700-rc5.c @@ -229,3 +229,4 @@ module_exit(exit_rc_map) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("dib0700-rc5 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c index 2466d8c502..d18b8f93a0 100644 --- a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c +++ b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c @@ -84,3 +84,4 @@ module_exit(exit_rc_map_digitalnow_tinytwin) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("DigitalNow TinyTwin remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-digittrade.c b/drivers/media/rc/keymaps/rc-digittrade.c index 65bc8ad7e5..129a81f59b 100644 --- a/drivers/media/rc/keymaps/rc-digittrade.c +++ b/drivers/media/rc/keymaps/rc-digittrade.c @@ -68,3 +68,4 @@ module_exit(exit_rc_map_digittrade) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("Digittrade DVB-T USB Stick remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dm1105-nec.c b/drivers/media/rc/keymaps/rc-dm1105-nec.c index cd0b985c99..b82290ce92 100644 --- a/drivers/media/rc/keymaps/rc-dm1105-nec.c +++ b/drivers/media/rc/keymaps/rc-dm1105-nec.c @@ -70,3 +70,4 @@ module_exit(exit_rc_map_dm1105_nec) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("dm1105-nec remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c index a82f64dc94..4b23335615 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c @@ -72,3 +72,4 @@ module_exit(exit_rc_map_dntv_live_dvb_t) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("dntv-live-dvb-t remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c index d3f5048a02..46d8ea1b49 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c @@ -91,3 +91,4 @@ module_exit(exit_rc_map_dntv_live_dvbt_pro) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("DigitalNow DNTV Live DVB-T Remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dreambox.c b/drivers/media/rc/keymaps/rc-dreambox.c index dea024fa3a..e1ec99ce31 100644 --- a/drivers/media/rc/keymaps/rc-dreambox.c +++ b/drivers/media/rc/keymaps/rc-dreambox.c @@ -149,3 +149,4 @@ module_exit(exit_rc_map_dreambox) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Emanuel Strobel <emanuel.strobel@yahoo.com>"); +MODULE_DESCRIPTION("Dreambox RC10/RC0 and RC20/RC-BT remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dtt200u.c b/drivers/media/rc/keymaps/rc-dtt200u.c index e7f87baa32..eeb2f6e303 100644 --- a/drivers/media/rc/keymaps/rc-dtt200u.c +++ b/drivers/media/rc/keymaps/rc-dtt200u.c @@ -53,3 +53,4 @@ module_exit(exit_rc_map_dtt200u) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>"); +MODULE_DESCRIPTION("Wideview WT-220U remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c index f5063af2e5..1fcd47bd85 100644 --- a/drivers/media/rc/keymaps/rc-dvbsky.c +++ b/drivers/media/rc/keymaps/rc-dvbsky.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_rc5_dvbsky) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Nibble Max <nibble.max@gmail.com>"); +MODULE_DESCRIPTION("DVBSky remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dvico-mce.c b/drivers/media/rc/keymaps/rc-dvico-mce.c index b1bb8cdb37..4bb4222d25 100644 --- a/drivers/media/rc/keymaps/rc-dvico-mce.c +++ b/drivers/media/rc/keymaps/rc-dvico-mce.c @@ -80,3 +80,4 @@ module_exit(exit_rc_map_dvico_mce) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("dvico-mce remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-dvico-portable.c b/drivers/media/rc/keymaps/rc-dvico-portable.c index ec12ba6995..ba9ef9b757 100644 --- a/drivers/media/rc/keymaps/rc-dvico-portable.c +++ b/drivers/media/rc/keymaps/rc-dvico-portable.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_dvico_portable) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("dvico-portable remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-em-terratec.c b/drivers/media/rc/keymaps/rc-em-terratec.c index a1f59aa6ff..8a51fe6328 100644 --- a/drivers/media/rc/keymaps/rc-em-terratec.c +++ b/drivers/media/rc/keymaps/rc-em-terratec.c @@ -63,3 +63,4 @@ module_exit(exit_rc_map_em_terratec) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("em-terratec remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c index 7a00471b60..320e184f42 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c @@ -75,3 +75,4 @@ module_exit(exit_rc_map_encore_enltv_fm53) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Encore ENLTV-FM v5.3 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c index 712210097b..0b235d72e5 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv.c @@ -106,3 +106,4 @@ module_exit(exit_rc_map_encore_enltv) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Encore ENLTV-FM remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c index a08470b4f1..d8057f4125 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv2.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c @@ -84,3 +84,4 @@ module_exit(exit_rc_map_encore_enltv2) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Encore ENLTV2-FM remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-evga-indtube.c b/drivers/media/rc/keymaps/rc-evga-indtube.c index f439844433..95295f6882 100644 --- a/drivers/media/rc/keymaps/rc-evga-indtube.c +++ b/drivers/media/rc/keymaps/rc-evga-indtube.c @@ -55,3 +55,4 @@ module_exit(exit_rc_map_evga_indtube) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("EVGA inDtube remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-eztv.c b/drivers/media/rc/keymaps/rc-eztv.c index 4e494d953e..522e772f7c 100644 --- a/drivers/media/rc/keymaps/rc-eztv.c +++ b/drivers/media/rc/keymaps/rc-eztv.c @@ -90,3 +90,4 @@ module_exit(exit_rc_map_eztv) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("eztv remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c index 202a1fbd19..fcb3bcadd8 100644 --- a/drivers/media/rc/keymaps/rc-flydvb.c +++ b/drivers/media/rc/keymaps/rc-flydvb.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_flydvb) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("flydvb remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-flyvideo.c b/drivers/media/rc/keymaps/rc-flyvideo.c index a44467fb15..fcb70c9507 100644 --- a/drivers/media/rc/keymaps/rc-flyvideo.c +++ b/drivers/media/rc/keymaps/rc-flyvideo.c @@ -64,3 +64,4 @@ module_exit(exit_rc_map_flyvideo) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("flyvideo remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c index 253199f553..43f73db910 100644 --- a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c +++ b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c @@ -92,3 +92,4 @@ module_exit(exit_rc_map_fusionhdtv_mce) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("DViCO FUSION HDTV MCE remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c index c630ef306f..8a446d1257 100644 --- a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c +++ b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c @@ -75,3 +75,4 @@ module_exit(exit_rc_map_gadmei_rm008z) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("GADMEI UTV330+ RM008Z remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-geekbox.c b/drivers/media/rc/keymaps/rc-geekbox.c index 11735ad36c..d3f2e960c9 100644 --- a/drivers/media/rc/keymaps/rc-geekbox.c +++ b/drivers/media/rc/keymaps/rc-geekbox.c @@ -47,3 +47,4 @@ module_exit(exit_rc_map_geekbox) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); +MODULE_DESCRIPTION("GeekBox remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c index c966c130b0..e49828ea2b 100644 --- a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c +++ b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c @@ -78,3 +78,4 @@ module_exit(exit_rc_map_genius_tvgo_a11mce) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Genius TVGO A11MCE remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-gotview7135.c b/drivers/media/rc/keymaps/rc-gotview7135.c index 0dc4ef36d7..a044991e30 100644 --- a/drivers/media/rc/keymaps/rc-gotview7135.c +++ b/drivers/media/rc/keymaps/rc-gotview7135.c @@ -73,3 +73,4 @@ module_exit(exit_rc_map_gotview7135) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("gotview7135 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c index 82552360c3..d7156774aa 100644 --- a/drivers/media/rc/keymaps/rc-hauppauge.c +++ b/drivers/media/rc/keymaps/rc-hauppauge.c @@ -287,3 +287,4 @@ module_exit(exit_rc_map_rc5_hauppauge_new) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Hauppauge remote controllers keytable"); diff --git a/drivers/media/rc/keymaps/rc-hisi-poplar.c b/drivers/media/rc/keymaps/rc-hisi-poplar.c index 49a18e9169..b10ad674c3 100644 --- a/drivers/media/rc/keymaps/rc-hisi-poplar.c +++ b/drivers/media/rc/keymaps/rc-hisi-poplar.c @@ -63,3 +63,4 @@ module_init(init_rc_map_hisi_poplar) module_exit(exit_rc_map_hisi_poplar) MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HiSilicon poplar remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-hisi-tv-demo.c b/drivers/media/rc/keymaps/rc-hisi-tv-demo.c index c73068b653..24dcb38df2 100644 --- a/drivers/media/rc/keymaps/rc-hisi-tv-demo.c +++ b/drivers/media/rc/keymaps/rc-hisi-tv-demo.c @@ -75,3 +75,4 @@ module_init(init_rc_map_hisi_tv_demo) module_exit(exit_rc_map_hisi_tv_demo) MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HiSilicon tv demo remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-imon-mce.c b/drivers/media/rc/keymaps/rc-imon-mce.c index b89e3569e7..130f685ae3 100644 --- a/drivers/media/rc/keymaps/rc-imon-mce.c +++ b/drivers/media/rc/keymaps/rc-imon-mce.c @@ -137,3 +137,4 @@ module_exit(exit_rc_map_imon_mce) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); +MODULE_DESCRIPTION("iMON MCE remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c index bceb4e7726..cd5ba44d03 100644 --- a/drivers/media/rc/keymaps/rc-imon-pad.c +++ b/drivers/media/rc/keymaps/rc-imon-pad.c @@ -150,3 +150,4 @@ module_exit(exit_rc_map_imon_pad) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); +MODULE_DESCRIPTION("iMON PAD remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-imon-rsc.c b/drivers/media/rc/keymaps/rc-imon-rsc.c index 38787dd0e4..e4124fadf7 100644 --- a/drivers/media/rc/keymaps/rc-imon-rsc.c +++ b/drivers/media/rc/keymaps/rc-imon-rsc.c @@ -80,3 +80,4 @@ module_exit(exit_rc_map_imon_rsc) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sean Young <sean@mess.org>"); +MODULE_DESCRIPTION("iMON RSC remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c index 9cc6ea0f42..95256e8545 100644 --- a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c +++ b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c @@ -82,3 +82,4 @@ module_exit(exit_rc_map_iodata_bctv7e) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("IO-DATA BCTV7E remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-it913x-v1.c b/drivers/media/rc/keymaps/rc-it913x-v1.c index 1e049f26a2..d80764c98f 100644 --- a/drivers/media/rc/keymaps/rc-it913x-v1.c +++ b/drivers/media/rc/keymaps/rc-it913x-v1.c @@ -89,3 +89,4 @@ module_exit(exit_rc_it913x_v1_map) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); +MODULE_DESCRIPTION("it913x-v1 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c index da3107da26..c37358cf8b 100644 --- a/drivers/media/rc/keymaps/rc-it913x-v2.c +++ b/drivers/media/rc/keymaps/rc-it913x-v2.c @@ -88,3 +88,4 @@ module_exit(exit_rc_it913x_v2_map) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); +MODULE_DESCRIPTION("it913x-v2 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-kaiomy.c b/drivers/media/rc/keymaps/rc-kaiomy.c index 548760e86a..bea50c6f7e 100644 --- a/drivers/media/rc/keymaps/rc-kaiomy.c +++ b/drivers/media/rc/keymaps/rc-kaiomy.c @@ -81,3 +81,4 @@ module_exit(exit_rc_map_kaiomy) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Kaiomy TVnPC U2 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-khadas.c b/drivers/media/rc/keymaps/rc-khadas.c index ce4938444d..2b7161e1bc 100644 --- a/drivers/media/rc/keymaps/rc-khadas.c +++ b/drivers/media/rc/keymaps/rc-khadas.c @@ -52,3 +52,4 @@ module_exit(exit_rc_map_khadas) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com>"); +MODULE_DESCRIPTION("Khadas VIM/EDGE SBC remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-khamsin.c b/drivers/media/rc/keymaps/rc-khamsin.c index 0c98c2faac..2121cad8d3 100644 --- a/drivers/media/rc/keymaps/rc-khamsin.c +++ b/drivers/media/rc/keymaps/rc-khamsin.c @@ -73,3 +73,4 @@ module_exit(exit_rc_map_khamsin) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com>"); +MODULE_DESCRIPTION("KHAMSIN remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c index f5aed4b960..f849dd6b7e 100644 --- a/drivers/media/rc/keymaps/rc-kworld-315u.c +++ b/drivers/media/rc/keymaps/rc-kworld-315u.c @@ -77,3 +77,4 @@ module_exit(exit_rc_map_kworld_315u) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Kworld 315U remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-kworld-pc150u.c b/drivers/media/rc/keymaps/rc-kworld-pc150u.c index 7938761eb9..630ef7c330 100644 --- a/drivers/media/rc/keymaps/rc-kworld-pc150u.c +++ b/drivers/media/rc/keymaps/rc-kworld-pc150u.c @@ -96,3 +96,4 @@ module_exit(exit_rc_map_kworld_pc150u) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kyle Strickland <kyle@kyle.strickland.name>"); +MODULE_DESCRIPTION("Kworld PC150-U remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c index 75389b74e0..1fb9dc4346 100644 --- a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c +++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c @@ -97,3 +97,4 @@ module_exit(exit_rc_map_kworld_plus_tv_analog) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Kworld Plus TV Analog Lite PCI IR remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c index 2f2b981e19..c637312643 100644 --- a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c +++ b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c @@ -85,3 +85,4 @@ module_exit(exit_rc_map_leadtek_y04g0051) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("LeadTek Y04G0051 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c index 181e48f0cb..575485655a 100644 --- a/drivers/media/rc/keymaps/rc-lme2510.c +++ b/drivers/media/rc/keymaps/rc-lme2510.c @@ -104,3 +104,4 @@ module_exit(exit_rc_lme2510_map) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); +MODULE_DESCRIPTION("LME2510 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c index e884aeb5c3..b81149a0df 100644 --- a/drivers/media/rc/keymaps/rc-manli.c +++ b/drivers/media/rc/keymaps/rc-manli.c @@ -128,3 +128,4 @@ module_exit(exit_rc_map_manli) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("MANLI MTV00[0x0c] and BeholdTV 40[13] remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-mecool-kii-pro.c b/drivers/media/rc/keymaps/rc-mecool-kii-pro.c index 77ca8a8fad..273fe1a304 100644 --- a/drivers/media/rc/keymaps/rc-mecool-kii-pro.c +++ b/drivers/media/rc/keymaps/rc-mecool-kii-pro.c @@ -89,3 +89,4 @@ module_exit(exit_rc_map_mecool_kii_pro) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); +MODULE_DESCRIPTION("Mecool Kii Pro remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-mecool-kiii-pro.c b/drivers/media/rc/keymaps/rc-mecool-kiii-pro.c index 8e99686fd6..53fd7c895d 100644 --- a/drivers/media/rc/keymaps/rc-mecool-kiii-pro.c +++ b/drivers/media/rc/keymaps/rc-mecool-kiii-pro.c @@ -86,3 +86,4 @@ module_exit(exit_rc_map_mecool_kiii_pro) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); +MODULE_DESCRIPTION("Mecool Kiii Pro remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c index 843dba3bad..3ea8fdbaf1 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10.c +++ b/drivers/media/rc/keymaps/rc-medion-x10.c @@ -102,3 +102,4 @@ module_exit(exit_rc_map_medion_x10) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>"); +MODULE_DESCRIPTION("Medion X10 RF remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-minix-neo.c b/drivers/media/rc/keymaps/rc-minix-neo.c index 9165af548f..ce16e964e7 100644 --- a/drivers/media/rc/keymaps/rc-minix-neo.c +++ b/drivers/media/rc/keymaps/rc-minix-neo.c @@ -53,3 +53,4 @@ module_exit(exit_rc_map_minix_neo) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); +MODULE_DESCRIPTION("Minix NEO remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c index ab001d2dac..f152626fd8 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c @@ -53,3 +53,4 @@ module_exit(exit_rc_map_msi_digivox_ii) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("MSI DIGIVOX mini II remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c index 6129d3e925..1250cde336 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_msi_digivox_iii) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("MSI DIGIVOX mini III remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c index 42270a7ef3..648bac448f 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c @@ -117,3 +117,4 @@ module_exit(exit_rc_map_msi_tvanywhere_plus) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("MSI TV@nywhere Plus remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c index 45793c6410..b59af39ba0 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c @@ -63,3 +63,4 @@ module_exit(exit_rc_map_msi_tvanywhere) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("MSI TV@nywhere MASTER remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c index 2dc6061f69..23b75269d3 100644 --- a/drivers/media/rc/keymaps/rc-nebula.c +++ b/drivers/media/rc/keymaps/rc-nebula.c @@ -90,3 +90,4 @@ module_exit(exit_rc_map_nebula) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("nebula remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c index b12c54d47d..94340a1864 100644 --- a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c @@ -151,3 +151,4 @@ module_exit(exit_rc_map_nec_terratec_cinergy_xs) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Terratec Cinergy Hybrid T USB XS FM remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c index acd5b1ccf8..da00003a5e 100644 --- a/drivers/media/rc/keymaps/rc-norwood.c +++ b/drivers/media/rc/keymaps/rc-norwood.c @@ -79,3 +79,4 @@ module_exit(exit_rc_map_norwood) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Norwood Micro (non-Pro) TV Tuner remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-npgtech.c b/drivers/media/rc/keymaps/rc-npgtech.c index 98a755e8bc..6f4412922e 100644 --- a/drivers/media/rc/keymaps/rc-npgtech.c +++ b/drivers/media/rc/keymaps/rc-npgtech.c @@ -74,3 +74,4 @@ module_exit(exit_rc_map_npgtech) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("npgtech remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-odroid.c b/drivers/media/rc/keymaps/rc-odroid.c index c6fbb64b5c..0353229a49 100644 --- a/drivers/media/rc/keymaps/rc-odroid.c +++ b/drivers/media/rc/keymaps/rc-odroid.c @@ -52,3 +52,4 @@ module_exit(exit_rc_map_odroid) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); +MODULE_DESCRIPTION("HardKernel ODROID remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-pctv-sedna.c b/drivers/media/rc/keymaps/rc-pctv-sedna.c index c3bb1ecdd0..6583bf4fcb 100644 --- a/drivers/media/rc/keymaps/rc-pctv-sedna.c +++ b/drivers/media/rc/keymaps/rc-pctv-sedna.c @@ -74,3 +74,4 @@ module_exit(exit_rc_map_pctv_sedna) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("pctv-sedna remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-pine64.c b/drivers/media/rc/keymaps/rc-pine64.c index 9b2bdbbce0..bcdb99997d 100644 --- a/drivers/media/rc/keymaps/rc-pine64.c +++ b/drivers/media/rc/keymaps/rc-pine64.c @@ -63,3 +63,4 @@ module_exit(exit_rc_map_pine64) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jonas Karlman"); +MODULE_DESCRIPTION("Pine64 IR remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-pinnacle-color.c b/drivers/media/rc/keymaps/rc-pinnacle-color.c index b862725635..f33c38644f 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-color.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-color.c @@ -88,3 +88,4 @@ module_exit(exit_rc_map_pinnacle_color) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("pinnacle-color remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-pinnacle-grey.c b/drivers/media/rc/keymaps/rc-pinnacle-grey.c index 3853b653ce..22ef3d4e2e 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-grey.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-grey.c @@ -83,3 +83,4 @@ module_exit(exit_rc_map_pinnacle_grey) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("pinnacle-grey remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c index 96d8112fb4..35f0c790cc 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c @@ -64,3 +64,4 @@ module_exit(exit_rc_map_pinnacle_pctv_hd) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Pinnacle PCTV HD 800i mini remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-pixelview-002t.c b/drivers/media/rc/keymaps/rc-pixelview-002t.c index c3439c4664..0966ebf090 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-002t.c +++ b/drivers/media/rc/keymaps/rc-pixelview-002t.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_pixelview) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("002-T IR remote keytable"); diff --git a/drivers/media/rc/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c index ea11ccde84..e187744738 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-mk12.c +++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c @@ -77,3 +77,4 @@ module_exit(exit_rc_map_pixelview) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("MK-F12 IR remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-pixelview-new.c b/drivers/media/rc/keymaps/rc-pixelview-new.c index 0259666831..cf7f1cf8c3 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-new.c +++ b/drivers/media/rc/keymaps/rc-pixelview-new.c @@ -77,3 +77,4 @@ module_exit(exit_rc_map_pixelview_new) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("pixelview-new remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-pixelview.c b/drivers/media/rc/keymaps/rc-pixelview.c index 29f6d2c013..567ad0a076 100644 --- a/drivers/media/rc/keymaps/rc-pixelview.c +++ b/drivers/media/rc/keymaps/rc-pixelview.c @@ -76,3 +76,4 @@ module_exit(exit_rc_map_pixelview) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("pixelview remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c index 66fe2e52e7..e7a6add1df 100644 --- a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c +++ b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c @@ -75,3 +75,4 @@ module_exit(exit_rc_map_powercolor_real_angel) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Powercolor Real Angel 330 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-proteus-2309.c b/drivers/media/rc/keymaps/rc-proteus-2309.c index 36eebefd97..1300482a61 100644 --- a/drivers/media/rc/keymaps/rc-proteus-2309.c +++ b/drivers/media/rc/keymaps/rc-proteus-2309.c @@ -63,3 +63,4 @@ module_exit(exit_rc_map_proteus_2309) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("proteus-2309 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-purpletv.c b/drivers/media/rc/keymaps/rc-purpletv.c index bf4543fecb..9f6ee0be13 100644 --- a/drivers/media/rc/keymaps/rc-purpletv.c +++ b/drivers/media/rc/keymaps/rc-purpletv.c @@ -75,3 +75,4 @@ module_exit(exit_rc_map_purpletv) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("purpletv remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-pv951.c b/drivers/media/rc/keymaps/rc-pv951.c index 69db554630..539e8573eb 100644 --- a/drivers/media/rc/keymaps/rc-pv951.c +++ b/drivers/media/rc/keymaps/rc-pv951.c @@ -72,3 +72,4 @@ module_exit(exit_rc_map_pv951) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("pv951 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c index d491e0fa86..ef1c61eb99 100644 --- a/drivers/media/rc/keymaps/rc-rc6-mce.c +++ b/drivers/media/rc/keymaps/rc-rc6-mce.c @@ -114,3 +114,4 @@ module_exit(exit_rc_map_rc6_mce) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); +MODULE_DESCRIPTION("rc6 MCE remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c index 33bb458b81..088ead8f73 100644 --- a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c +++ b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c @@ -72,3 +72,4 @@ module_exit(exit_rc_map_real_audio_220_32_keys) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Zogis Real Audio 220 - 32 keys remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-reddo.c b/drivers/media/rc/keymaps/rc-reddo.c index b70390d19e..af50d1ca4b 100644 --- a/drivers/media/rc/keymaps/rc-reddo.c +++ b/drivers/media/rc/keymaps/rc-reddo.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_reddo) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("reddo remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c index e3d5bff3bd..826f44595e 100644 --- a/drivers/media/rc/keymaps/rc-snapstream-firefly.c +++ b/drivers/media/rc/keymaps/rc-snapstream-firefly.c @@ -92,3 +92,4 @@ module_exit(exit_rc_map_snapstream_firefly) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>"); +MODULE_DESCRIPTION("SnapStream Firefly X10 RF remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-streamzap.c b/drivers/media/rc/keymaps/rc-streamzap.c index 6684e2e86b..b82c3cdfca 100644 --- a/drivers/media/rc/keymaps/rc-streamzap.c +++ b/drivers/media/rc/keymaps/rc-streamzap.c @@ -75,3 +75,4 @@ module_exit(exit_rc_map_streamzap) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); +MODULE_DESCRIPTION("Streamzap remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-su3000.c b/drivers/media/rc/keymaps/rc-su3000.c index 64cfc01aa4..a333ade3b1 100644 --- a/drivers/media/rc/keymaps/rc-su3000.c +++ b/drivers/media/rc/keymaps/rc-su3000.c @@ -69,3 +69,4 @@ module_exit(exit_rc_map_su3000) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Evgeny Plehov <Evgeny Plehov@ukr.net>"); +MODULE_DESCRIPTION("Geniatech HDStar remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-tanix-tx3mini.c b/drivers/media/rc/keymaps/rc-tanix-tx3mini.c index d486cd69af..b5d77a0c94 100644 --- a/drivers/media/rc/keymaps/rc-tanix-tx3mini.c +++ b/drivers/media/rc/keymaps/rc-tanix-tx3mini.c @@ -75,3 +75,4 @@ module_exit(exit_rc_map_tanix_tx3mini) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com>"); +MODULE_DESCRIPTION("Tanix TX3 mini STB remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-tanix-tx5max.c b/drivers/media/rc/keymaps/rc-tanix-tx5max.c index 59aaabed80..91db901784 100644 --- a/drivers/media/rc/keymaps/rc-tanix-tx5max.c +++ b/drivers/media/rc/keymaps/rc-tanix-tx5max.c @@ -66,3 +66,4 @@ module_exit(exit_rc_map_tanix_tx5max) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com>"); +MODULE_DESCRIPTION("Tanix TX5 max STB remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-tbs-nec.c b/drivers/media/rc/keymaps/rc-tbs-nec.c index 420980925f..426c767c90 100644 --- a/drivers/media/rc/keymaps/rc-tbs-nec.c +++ b/drivers/media/rc/keymaps/rc-tbs-nec.c @@ -69,3 +69,4 @@ module_exit(exit_rc_map_tbs_nec) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("tbs-nec remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-technisat-ts35.c b/drivers/media/rc/keymaps/rc-technisat-ts35.c index 9a917ea0ce..07d5e0884e 100644 --- a/drivers/media/rc/keymaps/rc-technisat-ts35.c +++ b/drivers/media/rc/keymaps/rc-technisat-ts35.c @@ -70,3 +70,4 @@ module_init(init_rc_map) module_exit(exit_rc_map) MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("TechniSat TS35 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-technisat-usb2.c b/drivers/media/rc/keymaps/rc-technisat-usb2.c index 942100686c..74ac89d379 100644 --- a/drivers/media/rc/keymaps/rc-technisat-usb2.c +++ b/drivers/media/rc/keymaps/rc-technisat-usb2.c @@ -88,3 +88,4 @@ module_exit(exit_rc_map) MODULE_AUTHOR("Patrick Boettcher <pboettcher@kernellabs.com>"); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("TechniSat TS35 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c index da06f844d8..d448913081 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c @@ -82,3 +82,4 @@ module_init(init_rc_map_terratec_cinergy_c_pci); module_exit(exit_rc_map_terratec_cinergy_c_pci); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Terratec Cinergy C PCI remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c index a1844b5315..dbbb1ba024 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c @@ -80,3 +80,4 @@ module_init(init_rc_map_terratec_cinergy_s2_hd); module_exit(exit_rc_map_terratec_cinergy_s2_hd); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Terratec Cinergy S2 HD remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c index fe587e3f02..a9452d5813 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c @@ -86,3 +86,4 @@ module_exit(exit_rc_map_terratec_cinergy_xs) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Terratec Cinergy Hybrid T USB XS remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-terratec-slim-2.c b/drivers/media/rc/keymaps/rc-terratec-slim-2.c index a54a59f903..ea259d8876 100644 --- a/drivers/media/rc/keymaps/rc-terratec-slim-2.c +++ b/drivers/media/rc/keymaps/rc-terratec-slim-2.c @@ -58,3 +58,4 @@ module_exit(exit_rc_map_terratec_slim_2) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("TerraTec slim remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-terratec-slim.c b/drivers/media/rc/keymaps/rc-terratec-slim.c index 146e3a3480..bb40cbd58e 100644 --- a/drivers/media/rc/keymaps/rc-terratec-slim.c +++ b/drivers/media/rc/keymaps/rc-terratec-slim.c @@ -65,3 +65,4 @@ module_exit(exit_rc_map_terratec_slim) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("TerraTec slim remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-tevii-nec.c b/drivers/media/rc/keymaps/rc-tevii-nec.c index 5b96e9a38e..ee7f801474 100644 --- a/drivers/media/rc/keymaps/rc-tevii-nec.c +++ b/drivers/media/rc/keymaps/rc-tevii-nec.c @@ -82,3 +82,4 @@ module_exit(exit_rc_map_tevii_nec) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("tevii-nec remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-tivo.c b/drivers/media/rc/keymaps/rc-tivo.c index c51606a3be..c02b8c8abd 100644 --- a/drivers/media/rc/keymaps/rc-tivo.c +++ b/drivers/media/rc/keymaps/rc-tivo.c @@ -93,3 +93,4 @@ module_exit(exit_rc_map_tivo) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); +MODULE_DESCRIPTION("TiVo remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c index 40b773ba45..290d1cc857 100644 --- a/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c +++ b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_total_media_in_hand_02) MODULE_LICENSE("GPL"); MODULE_AUTHOR(" Alfredo J. Delaiti <alfredodelaiti@netscape.net>"); +MODULE_DESCRIPTION("Total Media In Hand_02 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand.c b/drivers/media/rc/keymaps/rc-total-media-in-hand.c index 2144db485d..7f4b31b98f 100644 --- a/drivers/media/rc/keymaps/rc-total-media-in-hand.c +++ b/drivers/media/rc/keymaps/rc-total-media-in-hand.c @@ -71,3 +71,4 @@ module_exit(exit_rc_map_total_media_in_hand) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("Total Media In Hand remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-trekstor.c b/drivers/media/rc/keymaps/rc-trekstor.c index e938e0da51..ff01de5509 100644 --- a/drivers/media/rc/keymaps/rc-trekstor.c +++ b/drivers/media/rc/keymaps/rc-trekstor.c @@ -66,3 +66,4 @@ module_exit(exit_rc_map_trekstor) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("TrekStor remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c index ff70aab13b..eb8d7fc506 100644 --- a/drivers/media/rc/keymaps/rc-tt-1500.c +++ b/drivers/media/rc/keymaps/rc-tt-1500.c @@ -76,3 +76,4 @@ module_exit(exit_rc_map_tt_1500) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Technotrend 1500 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c index 5fc696d9e5..8e5cf8eb0d 100644 --- a/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c +++ b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c @@ -92,3 +92,4 @@ module_init(init_rc_map_twinhan_dtv_cab_ci); module_exit(exit_rc_map_twinhan_dtv_cab_ci); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Twinhan DTV CAB CI remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-twinhan1027.c b/drivers/media/rc/keymaps/rc-twinhan1027.c index e1cdcfa792..411ce3c8cb 100644 --- a/drivers/media/rc/keymaps/rc-twinhan1027.c +++ b/drivers/media/rc/keymaps/rc-twinhan1027.c @@ -87,3 +87,4 @@ module_exit(exit_rc_map_twinhan_vp1027) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sergey Ivanov <123kash@gmail.com>"); +MODULE_DESCRIPTION("twinhan1027 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-vega-s9x.c b/drivers/media/rc/keymaps/rc-vega-s9x.c index bf210c4dc5..40fbf408bf 100644 --- a/drivers/media/rc/keymaps/rc-vega-s9x.c +++ b/drivers/media/rc/keymaps/rc-vega-s9x.c @@ -52,3 +52,4 @@ module_exit(exit_rc_map_vega_s9x) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); +MODULE_DESCRIPTION("Tronsmart Vega S9x remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-m1f.c index e16b9b851c..1f9be84ff2 100644 --- a/drivers/media/rc/keymaps/rc-videomate-m1f.c +++ b/drivers/media/rc/keymaps/rc-videomate-m1f.c @@ -87,3 +87,4 @@ module_exit(exit_rc_map_videomate_k100) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pavel Osnova <pvosnova@gmail.com>"); +MODULE_DESCRIPTION("videomate-m1f remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-videomate-s350.c b/drivers/media/rc/keymaps/rc-videomate-s350.c index a867d7a080..281cc74722 100644 --- a/drivers/media/rc/keymaps/rc-videomate-s350.c +++ b/drivers/media/rc/keymaps/rc-videomate-s350.c @@ -79,3 +79,4 @@ module_exit(exit_rc_map_videomate_s350) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("videomate-s350 remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c index fdc3b0e135..829842425f 100644 --- a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c +++ b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c @@ -81,3 +81,4 @@ module_exit(exit_rc_map_videomate_tv_pvr) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("videomate-tv-pvr remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c b/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c index 414d4d231e..10cbc2c781 100644 --- a/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c +++ b/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c @@ -81,3 +81,4 @@ module_exit(exit_rc_map_kii_pro) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mohammad Rasim <mohammad.rasim96@gmail.com>"); +MODULE_DESCRIPTION("Videostrong KII Pro STB remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-wetek-hub.c b/drivers/media/rc/keymaps/rc-wetek-hub.c index b5a21aff45..591ec20399 100644 --- a/drivers/media/rc/keymaps/rc-wetek-hub.c +++ b/drivers/media/rc/keymaps/rc-wetek-hub.c @@ -51,3 +51,4 @@ module_exit(exit_rc_map_wetek_hub) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com>"); +MODULE_DESCRIPTION("WeTek Hub STB remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-wetek-play2.c b/drivers/media/rc/keymaps/rc-wetek-play2.c index bbbb11fa3c..ce3b1029df 100644 --- a/drivers/media/rc/keymaps/rc-wetek-play2.c +++ b/drivers/media/rc/keymaps/rc-wetek-play2.c @@ -91,3 +91,4 @@ module_exit(exit_rc_map_wetek_play2) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); +MODULE_DESCRIPTION("WeTek Play 2 STB remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c index 999ba4e084..edfba31f9a 100644 --- a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c +++ b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c @@ -76,3 +76,4 @@ module_exit(exit_rc_map_winfast_usbii_deluxe) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Leadtek Winfast TV USB II Deluxe remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c index be52a3e1f8..89649c8cde 100644 --- a/drivers/media/rc/keymaps/rc-winfast.c +++ b/drivers/media/rc/keymaps/rc-winfast.c @@ -96,3 +96,4 @@ module_exit(exit_rc_map_winfast) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION("Leadtek Winfast remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-x96max.c b/drivers/media/rc/keymaps/rc-x96max.c index 0998ec3320..a22fcbbfa3 100644 --- a/drivers/media/rc/keymaps/rc-x96max.c +++ b/drivers/media/rc/keymaps/rc-x96max.c @@ -81,3 +81,4 @@ module_exit(exit_rc_map_x96max) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); +MODULE_DESCRIPTION("X96-max STB remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-xbox-360.c b/drivers/media/rc/keymaps/rc-xbox-360.c index 231aa00514..1364daf3ae 100644 --- a/drivers/media/rc/keymaps/rc-xbox-360.c +++ b/drivers/media/rc/keymaps/rc-xbox-360.c @@ -81,3 +81,4 @@ module_init(init_rc_map) module_exit(exit_rc_map) MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Xbox 360 Universal Media remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-xbox-dvd.c b/drivers/media/rc/keymaps/rc-xbox-dvd.c index 9d656042a8..11ab134b05 100644 --- a/drivers/media/rc/keymaps/rc-xbox-dvd.c +++ b/drivers/media/rc/keymaps/rc-xbox-dvd.c @@ -61,3 +61,4 @@ module_init(init_rc_map) module_exit(exit_rc_map) MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Xbox DVD remote controller keytable"); diff --git a/drivers/media/rc/keymaps/rc-zx-irdec.c b/drivers/media/rc/keymaps/rc-zx-irdec.c index 7bb0c05eb7..e4bea7b39f 100644 --- a/drivers/media/rc/keymaps/rc-zx-irdec.c +++ b/drivers/media/rc/keymaps/rc-zx-irdec.c @@ -74,3 +74,4 @@ module_exit(exit_rc_map_zx_irdec) MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("zx-irdec remote controller keytable"); diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index a537734832..caad59f767 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -814,7 +814,7 @@ void __exit lirc_dev_exit(void) unregister_chrdev_region(lirc_base_dev, RC_DEV_MAX); } -struct rc_dev *rc_dev_get_from_fd(int fd) +struct rc_dev *rc_dev_get_from_fd(int fd, bool write) { struct fd f = fdget(fd); struct lirc_fh *fh; @@ -828,6 +828,9 @@ struct rc_dev *rc_dev_get_from_fd(int fd) return ERR_PTR(-EINVAL); } + if (write && !(f.file->f_mode & FMODE_WRITE)) + return ERR_PTR(-EPERM); + fh = f.file->private_data; dev = fh->rc; diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 70322fab34..5303e6da58 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -20,48 +20,196 @@ #define DRIVER_NAME "meson-ir" -#define IR_DEC_LDR_ACTIVE 0x00 -#define IR_DEC_LDR_IDLE 0x04 -#define IR_DEC_LDR_REPEAT 0x08 -#define IR_DEC_BIT_0 0x0c -#define IR_DEC_REG0 0x10 -#define IR_DEC_REG0_BASE_TIME GENMASK(11, 0) -#define IR_DEC_FRAME 0x14 -#define IR_DEC_STATUS 0x18 -#define IR_DEC_STATUS_PULSE BIT(8) -#define IR_DEC_REG1 0x1c -#define IR_DEC_REG1_TIME_IV GENMASK(28, 16) -#define IR_DEC_REG1_ENABLE BIT(15) -#define IR_DEC_REG1_MODE GENMASK(8, 7) -#define IR_DEC_REG1_IRQSEL GENMASK(3, 2) -#define IR_DEC_REG1_RESET BIT(0) -/* The following regs are only available on Meson 8b and newer */ -#define IR_DEC_REG2 0x20 -#define IR_DEC_REG2_MODE GENMASK(3, 0) - -#define DEC_MODE_NEC 0x0 -#define DEC_MODE_RAW 0x2 - -#define IRQSEL_NEC_MODE 0 -#define IRQSEL_RISE_FALL 1 -#define IRQSEL_FALL 2 -#define IRQSEL_RISE 3 - -#define MESON_RAW_TRATE 10 /* us */ -#define MESON_HW_TRATE 20 /* us */ +#define IR_DEC_LDR_ACTIVE 0x00 +#define IR_DEC_LDR_ACTIVE_MAX GENMASK(28, 16) +#define IR_DEC_LDR_ACTIVE_MIN GENMASK(12, 0) +#define IR_DEC_LDR_IDLE 0x04 +#define IR_DEC_LDR_IDLE_MAX GENMASK(28, 16) +#define IR_DEC_LDR_IDLE_MIN GENMASK(12, 0) +#define IR_DEC_LDR_REPEAT 0x08 +#define IR_DEC_LDR_REPEAT_MAX GENMASK(25, 16) +#define IR_DEC_LDR_REPEAT_MIN GENMASK(9, 0) +#define IR_DEC_BIT_0 0x0c +#define IR_DEC_BIT_0_MAX GENMASK(25, 16) +#define IR_DEC_BIT_0_MIN GENMASK(9, 0) +#define IR_DEC_REG0 0x10 +#define IR_DEC_REG0_FILTER GENMASK(30, 28) +#define IR_DEC_REG0_FRAME_TIME_MAX GENMASK(24, 12) +#define IR_DEC_REG0_BASE_TIME GENMASK(11, 0) +#define IR_DEC_FRAME 0x14 +#define IR_DEC_STATUS 0x18 +#define IR_DEC_STATUS_BIT_1_ENABLE BIT(30) +#define IR_DEC_STATUS_BIT_1_MAX GENMASK(29, 20) +#define IR_DEC_STATUS_BIT_1_MIN GENMASK(19, 10) +#define IR_DEC_STATUS_PULSE BIT(8) +#define IR_DEC_STATUS_BUSY BIT(7) +#define IR_DEC_STATUS_FRAME_STATUS GENMASK(3, 0) +#define IR_DEC_REG1 0x1c +#define IR_DEC_REG1_TIME_IV GENMASK(28, 16) +#define IR_DEC_REG1_FRAME_LEN GENMASK(13, 8) +#define IR_DEC_REG1_ENABLE BIT(15) +#define IR_DEC_REG1_HOLD_CODE BIT(6) +#define IR_DEC_REG1_IRQSEL GENMASK(3, 2) +#define IR_DEC_REG1_RESET BIT(0) +/* Meson 6b uses REG1 to configure IR mode */ +#define IR_DEC_REG1_MODE GENMASK(8, 7) + +/* The following registers are only available on Meson 8b and newer */ +#define IR_DEC_REG2 0x20 +#define IR_DEC_REG2_TICK_MODE BIT(15) +#define IR_DEC_REG2_REPEAT_COUNTER BIT(13) +#define IR_DEC_REG2_REPEAT_TIME BIT(12) +#define IR_DEC_REG2_COMPARE_FRAME BIT(11) +#define IR_DEC_REG2_BIT_ORDER BIT(8) +/* Meson 8b / GXBB use REG2 to configure IR mode */ +#define IR_DEC_REG2_MODE GENMASK(3, 0) +#define IR_DEC_DURATN2 0x24 +#define IR_DEC_DURATN2_MAX GENMASK(25, 16) +#define IR_DEC_DURATN2_MIN GENMASK(9, 0) +#define IR_DEC_DURATN3 0x28 +#define IR_DEC_DURATN3_MAX GENMASK(25, 16) +#define IR_DEC_DURATN3_MIN GENMASK(9, 0) +#define IR_DEC_FRAME1 0x2c + +#define FRAME_MSB_FIRST true +#define FRAME_LSB_FIRST false + +#define DEC_MODE_NEC 0x0 +#define DEC_MODE_RAW 0x2 +#define DEC_MODE_RC6 0x9 +#define DEC_MODE_XMP 0xE +#define DEC_MODE_UNKNOW 0xFF + +#define DEC_STATUS_VALID BIT(3) +#define DEC_STATUS_DATA_CODE_ERR BIT(2) +#define DEC_STATUS_CUSTOM_CODE_ERR BIT(1) +#define DEC_STATUS_REPEAT BIT(0) + +#define IRQSEL_DEC_MODE 0 +#define IRQSEL_RISE_FALL 1 +#define IRQSEL_FALL 2 +#define IRQSEL_RISE 3 + +#define MESON_RAW_TRATE 10 /* us */ +#define MESON_HW_TRATE 20 /* us */ + +/** + * struct meson_ir_protocol - describe IR Protocol parameter + * + * @hw_protocol: select IR Protocol from IR Controller + * @repeat_counter_enable: enable frame-to-frame time counter, it should work + * with @repeat_compare_enable to detect the repeat frame + * @repeat_check_enable: enable repeat time check for repeat detection + * @repeat_compare_enable: enable to compare frame for repeat frame detection. + * Some IR Protocol send the same data as repeat frame. + * In this case, it should work with + * @repeat_counter_enable to detect the repeat frame. + * @bit_order: bit order, LSB or MSB + * @bit1_match_enable: enable to check bit 1 + * @hold_code_enable: hold frame code in register IR_DEC_FRAME1, the new one + * frame code will not be store in IR_DEC_FRAME1. + * until IR_DEC_FRAME1 has been read + * @count_tick_mode: increasing time unit of frame-to-frame time counter. + * 0 = 100us, 1 = 10us + * @code_length: length (N-1) of data frame + * @frame_time_max: max time for whole frame. Unit: MESON_HW_TRATE + * @leader_active_max: max time for NEC/RC6 leader active part. Unit: MESON_HW_TRATE + * @leader_active_min: min time for NEC/RC6 leader active part. Unit: MESON_HW_TRATE + * @leader_idle_max: max time for NEC/RC6 leader idle part. Unit: MESON_HW_TRATE + * @leader_idle_min: min time for NEC/RC6 leader idle part. Unit: MESON_HW_TRATE + * @repeat_leader_max: max time for NEC repeat leader idle part. Unit: MESON_HW_TRATE + * @repeat_leader_min: min time for NEC repeat leader idle part. Unit: MESON_HW_TRATE + * @bit0_max: max time for NEC Logic '0', half of RC6 trailer bit, XMP Logic '00' + * @bit0_min: min time for NEC Logic '0', half of RC6 trailer bit, XMP Logic '00' + * @bit1_max: max time for NEC Logic '1', whole of RC6 trailer bit, XMP Logic '01' + * @bit1_min: min time for NEC Logic '1', whole of RC6 trailer bit, XMP Logic '01' + * @duration2_max: max time for half of RC6 normal bit, XMP Logic '10' + * @duration2_min: min time for half of RC6 normal bit, XMP Logic '10' + * @duration3_max: max time for whole of RC6 normal bit, XMP Logic '11' + * @duration3_min: min time for whole of RC6 normal bit, XMP Logic '11' + */ + +struct meson_ir_protocol { + u8 hw_protocol; + bool repeat_counter_enable; + bool repeat_check_enable; + bool repeat_compare_enable; + bool bit_order; + bool bit1_match_enable; + bool hold_code_enable; + bool count_tick_mode; + u8 code_length; + u16 frame_time_max; + u16 leader_active_max; + u16 leader_active_min; + u16 leader_idle_max; + u16 leader_idle_min; + u16 repeat_leader_max; + u16 repeat_leader_min; + u16 bit0_max; + u16 bit0_min; + u16 bit1_max; + u16 bit1_min; + u16 duration2_max; + u16 duration2_min; + u16 duration3_max; + u16 duration3_min; +}; + +struct meson_ir_param { + bool support_hw_decoder; + unsigned int max_register; +}; struct meson_ir { + const struct meson_ir_param *param; struct regmap *reg; struct rc_dev *rc; spinlock_t lock; }; -static const struct regmap_config meson_ir_regmap_config = { +static struct regmap_config meson_ir_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, }; +static const struct meson_ir_protocol protocol_timings[] = { + /* protocol, repeat counter, repeat check, repeat compare, order */ + {DEC_MODE_NEC, false, false, false, FRAME_LSB_FIRST, + /* bit 1 match, hold code, count tick, len, frame time */ + true, false, false, 32, 4000, + /* leader active max/min, leader idle max/min, repeat leader max/min */ + 500, 400, 300, 200, 150, 80, + /* bit0 max/min, bit1 max/min, duration2 max/min, duration3 max/min */ + 72, 40, 134, 90, 0, 0, 0, 0} +}; + +static void meson_ir_nec_handler(struct meson_ir *ir) +{ + u32 code = 0; + u32 status = 0; + enum rc_proto proto; + + regmap_read(ir->reg, IR_DEC_STATUS, &status); + + if (status & DEC_STATUS_REPEAT) { + rc_repeat(ir->rc); + } else { + regmap_read(ir->reg, IR_DEC_FRAME, &code); + + code = ir_nec_bytes_to_scancode(code, code >> 8, + code >> 16, code >> 24, &proto); + rc_keydown(ir->rc, proto, code, 0); + } +} + +static void meson_ir_hw_handler(struct meson_ir *ir) +{ + if (ir->rc->enabled_protocols & RC_PROTO_BIT_NEC) + meson_ir_nec_handler(ir); +} + static irqreturn_t meson_ir_irq(int irqno, void *dev_id) { struct meson_ir *ir = dev_id; @@ -70,22 +218,232 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id) spin_lock(&ir->lock); - regmap_read(ir->reg, IR_DEC_REG1, &duration); - duration = FIELD_GET(IR_DEC_REG1_TIME_IV, duration); - rawir.duration = duration * MESON_RAW_TRATE; - regmap_read(ir->reg, IR_DEC_STATUS, &status); - rawir.pulse = !!(status & IR_DEC_STATUS_PULSE); - ir_raw_event_store_with_timeout(ir->rc, &rawir); + if (ir->rc->driver_type == RC_DRIVER_IR_RAW) { + rawir.pulse = !!(status & IR_DEC_STATUS_PULSE); + + regmap_read(ir->reg, IR_DEC_REG1, &duration); + duration = FIELD_GET(IR_DEC_REG1_TIME_IV, duration); + rawir.duration = duration * MESON_RAW_TRATE; + + ir_raw_event_store_with_timeout(ir->rc, &rawir); + } else if (ir->rc->driver_type == RC_DRIVER_SCANCODE) { + if (status & DEC_STATUS_VALID) + meson_ir_hw_handler(ir); + } spin_unlock(&ir->lock); return IRQ_HANDLED; } +static int meson_ir_hw_decoder_init(struct rc_dev *dev, u64 *rc_type) +{ + u8 protocol; + u32 regval; + int i; + unsigned long flags; + const struct meson_ir_protocol *timings; + struct meson_ir *ir = dev->priv; + + if (*rc_type & RC_PROTO_BIT_NEC) + protocol = DEC_MODE_NEC; + else + return 0; + + for (i = 0; i < ARRAY_SIZE(protocol_timings); i++) + if (protocol_timings[i].hw_protocol == protocol) + break; + + if (i == ARRAY_SIZE(protocol_timings)) { + dev_err(&dev->dev, "hw protocol isn't supported: %d\n", + protocol); + return -EINVAL; + } + timings = &protocol_timings[i]; + + spin_lock_irqsave(&ir->lock, flags); + + /* Clear controller status */ + regmap_read(ir->reg, IR_DEC_STATUS, ®val); + regmap_read(ir->reg, IR_DEC_FRAME, ®val); + + /* Reset ir decoder and disable decoder */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, 0); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, + IR_DEC_REG1_RESET); + + /* Base time resolution, (19+1)*1us=20us */ + regval = FIELD_PREP(IR_DEC_REG0_BASE_TIME, MESON_HW_TRATE - 1); + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_BASE_TIME, regval); + + /* Monitor timing for input filter */ + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_FILTER, + FIELD_PREP(IR_DEC_REG0_FILTER, 7)); + + /* HW protocol */ + regval = FIELD_PREP(IR_DEC_REG2_MODE, timings->hw_protocol); + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, regval); + + /* Hold frame data until register was read */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_HOLD_CODE, + timings->hold_code_enable ? + IR_DEC_REG1_HOLD_CODE : 0); + + /* Bit order */ + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_BIT_ORDER, + timings->bit_order ? IR_DEC_REG2_BIT_ORDER : 0); + + /* Select tick mode */ + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_TICK_MODE, + timings->count_tick_mode ? + IR_DEC_REG2_TICK_MODE : 0); + + /* + * Some protocols transmit the same data frame as repeat frame + * when the key is pressing. In this case, it could be detected as + * repeat frame if the repeat checker was enabled. + */ + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_REPEAT_COUNTER, + timings->repeat_counter_enable ? + IR_DEC_REG2_REPEAT_COUNTER : 0); + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_REPEAT_TIME, + timings->repeat_check_enable ? + IR_DEC_REG2_REPEAT_TIME : 0); + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_COMPARE_FRAME, + timings->repeat_compare_enable ? + IR_DEC_REG2_COMPARE_FRAME : 0); + + /* + * FRAME_TIME_MAX should be larger than the time between + * data frame and repeat frame + */ + regval = FIELD_PREP(IR_DEC_REG0_FRAME_TIME_MAX, + timings->frame_time_max); + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_FRAME_TIME_MAX, + regval); + + /* Length(N-1) of data frame */ + regval = FIELD_PREP(IR_DEC_REG1_FRAME_LEN, timings->code_length - 1); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_FRAME_LEN, regval); + + /* Time for leader active part */ + regval = FIELD_PREP(IR_DEC_LDR_ACTIVE_MAX, + timings->leader_active_max) | + FIELD_PREP(IR_DEC_LDR_ACTIVE_MIN, + timings->leader_active_min); + regmap_update_bits(ir->reg, IR_DEC_LDR_ACTIVE, IR_DEC_LDR_ACTIVE_MAX | + IR_DEC_LDR_ACTIVE_MIN, regval); + + /* Time for leader idle part */ + regval = FIELD_PREP(IR_DEC_LDR_IDLE_MAX, timings->leader_idle_max) | + FIELD_PREP(IR_DEC_LDR_IDLE_MIN, timings->leader_idle_min); + regmap_update_bits(ir->reg, IR_DEC_LDR_IDLE, + IR_DEC_LDR_IDLE_MAX | IR_DEC_LDR_IDLE_MIN, regval); + + /* Time for repeat leader idle part */ + regval = FIELD_PREP(IR_DEC_LDR_REPEAT_MAX, timings->repeat_leader_max) | + FIELD_PREP(IR_DEC_LDR_REPEAT_MIN, timings->repeat_leader_min); + regmap_update_bits(ir->reg, IR_DEC_LDR_REPEAT, IR_DEC_LDR_REPEAT_MAX | + IR_DEC_LDR_REPEAT_MIN, regval); + + /* + * NEC: Time for logic '0' + * RC6: Time for half of trailer bit + */ + regval = FIELD_PREP(IR_DEC_BIT_0_MAX, timings->bit0_max) | + FIELD_PREP(IR_DEC_BIT_0_MIN, timings->bit0_min); + regmap_update_bits(ir->reg, IR_DEC_BIT_0, + IR_DEC_BIT_0_MAX | IR_DEC_BIT_0_MIN, regval); + + /* + * NEC: Time for logic '1' + * RC6: Time for whole of trailer bit + */ + regval = FIELD_PREP(IR_DEC_STATUS_BIT_1_MAX, timings->bit1_max) | + FIELD_PREP(IR_DEC_STATUS_BIT_1_MIN, timings->bit1_min); + regmap_update_bits(ir->reg, IR_DEC_STATUS, IR_DEC_STATUS_BIT_1_MAX | + IR_DEC_STATUS_BIT_1_MIN, regval); + + /* Enable to match logic '1' */ + regmap_update_bits(ir->reg, IR_DEC_STATUS, IR_DEC_STATUS_BIT_1_ENABLE, + timings->bit1_match_enable ? + IR_DEC_STATUS_BIT_1_ENABLE : 0); + + /* + * NEC: Unused + * RC6: Time for halt of logic 0/1 + */ + regval = FIELD_PREP(IR_DEC_DURATN2_MAX, timings->duration2_max) | + FIELD_PREP(IR_DEC_DURATN2_MIN, timings->duration2_min); + regmap_update_bits(ir->reg, IR_DEC_DURATN2, + IR_DEC_DURATN2_MAX | IR_DEC_DURATN2_MIN, regval); + + /* + * NEC: Unused + * RC6: Time for whole logic 0/1 + */ + regval = FIELD_PREP(IR_DEC_DURATN3_MAX, timings->duration3_max) | + FIELD_PREP(IR_DEC_DURATN3_MIN, timings->duration3_min); + regmap_update_bits(ir->reg, IR_DEC_DURATN3, + IR_DEC_DURATN3_MAX | IR_DEC_DURATN3_MIN, regval); + + /* Reset ir decoder and enable decode */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, + IR_DEC_REG1_RESET); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, 0); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, + IR_DEC_REG1_ENABLE); + + spin_unlock_irqrestore(&ir->lock, flags); + + dev_info(&dev->dev, "hw decoder init, protocol: %d\n", protocol); + + return 0; +} + +static void meson_ir_sw_decoder_init(struct rc_dev *dev) +{ + unsigned long flags; + struct meson_ir *ir = dev->priv; + + spin_lock_irqsave(&ir->lock, flags); + + /* Reset the decoder */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, + IR_DEC_REG1_RESET); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, 0); + + /* Set general operation mode (= raw/software decoding) */ + if (of_device_is_compatible(dev->dev.of_node, "amlogic,meson6-ir")) + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_MODE, + FIELD_PREP(IR_DEC_REG1_MODE, + DEC_MODE_RAW)); + else + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, + FIELD_PREP(IR_DEC_REG2_MODE, + DEC_MODE_RAW)); + + /* Set rate */ + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_BASE_TIME, + FIELD_PREP(IR_DEC_REG0_BASE_TIME, + MESON_RAW_TRATE - 1)); + /* IRQ on rising and falling edges */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_IRQSEL, + FIELD_PREP(IR_DEC_REG1_IRQSEL, IRQSEL_RISE_FALL)); + /* Enable the decoder */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, + IR_DEC_REG1_ENABLE); + + spin_unlock_irqrestore(&ir->lock, flags); + + dev_info(&dev->dev, "sw decoder init\n"); +} + static int meson_ir_probe(struct platform_device *pdev) { + const struct meson_ir_param *match_data; struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; void __iomem *res_start; @@ -97,10 +455,17 @@ static int meson_ir_probe(struct platform_device *pdev) if (!ir) return -ENOMEM; + match_data = of_device_get_match_data(dev); + if (!match_data) + return dev_err_probe(dev, -ENODEV, "failed to get match data\n"); + + ir->param = match_data; + res_start = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(res_start)) return PTR_ERR(res_start); + meson_ir_regmap_config.max_register = ir->param->max_register; ir->reg = devm_regmap_init_mmio(&pdev->dev, res_start, &meson_ir_regmap_config); if (IS_ERR(ir->reg)) @@ -110,23 +475,34 @@ static int meson_ir_probe(struct platform_device *pdev) if (irq < 0) return irq; - ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); + if (ir->param->support_hw_decoder) + ir->rc = devm_rc_allocate_device(&pdev->dev, + RC_DRIVER_SCANCODE); + else + ir->rc = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW); + if (!ir->rc) { dev_err(dev, "failed to allocate rc device\n"); return -ENOMEM; } + if (ir->rc->driver_type == RC_DRIVER_IR_RAW) { + ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + ir->rc->rx_resolution = MESON_RAW_TRATE; + ir->rc->min_timeout = 1; + ir->rc->timeout = IR_DEFAULT_TIMEOUT; + ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; + } else if (ir->rc->driver_type == RC_DRIVER_SCANCODE) { + ir->rc->allowed_protocols = RC_PROTO_BIT_NEC; + ir->rc->change_protocol = meson_ir_hw_decoder_init; + } + ir->rc->priv = ir; ir->rc->device_name = DRIVER_NAME; ir->rc->input_phys = DRIVER_NAME "/input0"; ir->rc->input_id.bustype = BUS_HOST; map_name = of_get_property(node, "linux,rc-map-name", NULL); ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY; - ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; - ir->rc->rx_resolution = MESON_RAW_TRATE; - ir->rc->min_timeout = 1; - ir->rc->timeout = IR_DEFAULT_TIMEOUT; - ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; ir->rc->driver_name = DRIVER_NAME; spin_lock_init(&ir->lock); @@ -138,36 +514,15 @@ static int meson_ir_probe(struct platform_device *pdev) return ret; } - ret = devm_request_irq(dev, irq, meson_ir_irq, 0, NULL, ir); + if (ir->rc->driver_type == RC_DRIVER_IR_RAW) + meson_ir_sw_decoder_init(ir->rc); + + ret = devm_request_irq(dev, irq, meson_ir_irq, 0, "meson_ir", ir); if (ret) { dev_err(dev, "failed to request irq\n"); return ret; } - /* Reset the decoder */ - regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, - IR_DEC_REG1_RESET); - regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, 0); - - /* Set general operation mode (= raw/software decoding) */ - if (of_device_is_compatible(node, "amlogic,meson6-ir")) - regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_MODE, - FIELD_PREP(IR_DEC_REG1_MODE, DEC_MODE_RAW)); - else - regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, - FIELD_PREP(IR_DEC_REG2_MODE, DEC_MODE_RAW)); - - /* Set rate */ - regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_BASE_TIME, - FIELD_PREP(IR_DEC_REG0_BASE_TIME, - MESON_RAW_TRATE - 1)); - /* IRQ on rising and falling edges */ - regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_IRQSEL, - FIELD_PREP(IR_DEC_REG1_IRQSEL, IRQSEL_RISE_FALL)); - /* Enable the decoder */ - regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, - IR_DEC_REG1_ENABLE); - dev_info(dev, "receiver initialized\n"); return 0; @@ -212,11 +567,36 @@ static void meson_ir_shutdown(struct platform_device *pdev) spin_unlock_irqrestore(&ir->lock, flags); } +static const struct meson_ir_param meson6_ir_param = { + .support_hw_decoder = false, + .max_register = IR_DEC_REG1, +}; + +static const struct meson_ir_param meson8b_ir_param = { + .support_hw_decoder = false, + .max_register = IR_DEC_REG2, +}; + +static const struct meson_ir_param meson_s4_ir_param = { + .support_hw_decoder = true, + .max_register = IR_DEC_FRAME1, +}; + static const struct of_device_id meson_ir_match[] = { - { .compatible = "amlogic,meson6-ir" }, - { .compatible = "amlogic,meson8b-ir" }, - { .compatible = "amlogic,meson-gxbb-ir" }, - { }, + { + .compatible = "amlogic,meson6-ir", + .data = &meson6_ir_param, + }, { + .compatible = "amlogic,meson8b-ir", + .data = &meson8b_ir_param, + }, { + .compatible = "amlogic,meson-gxbb-ir", + .data = &meson8b_ir_param, + }, { + .compatible = "amlogic,meson-s4-ir", + .data = &meson_s4_ir_param, + }, + {}, }; MODULE_DEVICE_TABLE(of, meson_ir_match); diff --git a/drivers/media/rc/pwm-ir-tx.c b/drivers/media/rc/pwm-ir-tx.c index 7732054c46..c5f37c03af 100644 --- a/drivers/media/rc/pwm-ir-tx.c +++ b/drivers/media/rc/pwm-ir-tx.c @@ -23,6 +23,7 @@ struct pwm_ir { static const struct of_device_id pwm_ir_of_match[] = { { .compatible = "pwm-ir-tx", }, + { .compatible = "nokia,n900-ir" }, { }, }; MODULE_DEVICE_TABLE(of, pwm_ir_of_match); diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index ef1e95e1af..7df949fc65 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -325,7 +325,7 @@ void lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev); void lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc); int lirc_register(struct rc_dev *dev); void lirc_unregister(struct rc_dev *dev); -struct rc_dev *rc_dev_get_from_fd(int fd); +struct rc_dev *rc_dev_get_from_fd(int fd, bool write); #else static inline int lirc_dev_init(void) { return 0; } static inline void lirc_dev_exit(void) {} diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index e95bdccfc1..394c9f81ea 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -240,7 +240,7 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "vivid", sizeof(cap->driver)); strscpy(cap->card, "vivid", sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", dev->v4l2_dev.name); + "platform:%s-%03d", VIVID_MODULE_NAME, dev->inst); cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps | dev->vbi_cap_caps | dev->vbi_out_caps | diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index c5e21785fa..fe4410a5e1 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -937,7 +937,6 @@ static int cx231xx_load_firmware(struct cx231xx *dev) u32 *p_current_fw, *p_fw; u32 *p_fw_data; int frame = 0; - u16 _buffer_size = 4096; u8 *p_buffer; p_current_fw = vmalloc(1884180 * 4); @@ -947,7 +946,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev) return -ENOMEM; } - p_buffer = vmalloc(4096); + p_buffer = vmalloc(EP5_BUF_SIZE); if (p_buffer == NULL) { dprintk(2, "FAIL!!!\n"); vfree(p_current_fw); @@ -1030,9 +1029,9 @@ static int cx231xx_load_firmware(struct cx231xx *dev) /*download the firmware by ep5-out*/ - for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size); + for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/EP5_BUF_SIZE); frame++) { - for (i = 0; i < _buffer_size; i++) { + for (i = 0; i < EP5_BUF_SIZE; i++) { *(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF); i++; *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8); @@ -1041,7 +1040,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev) i++; *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24); } - cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size); + cx231xx_ep5_bulkout(dev, p_buffer, EP5_BUF_SIZE); } p_current_fw = p_fw; diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index f1feccc28b..d831220169 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -751,13 +751,12 @@ int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size) int ret = -ENOMEM; u32 *buffer; - buffer = kzalloc(4096, GFP_KERNEL); + buffer = kmemdup(firmware, EP5_BUF_SIZE, GFP_KERNEL); if (buffer == NULL) return -ENOMEM; - memcpy(&buffer[0], firmware, 4096); ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 5), - buffer, 4096, &actlen, 2000); + buffer, EP5_BUF_SIZE, &actlen, EP5_TIMEOUT_MS); if (ret) dev_err(dev->dev, @@ -994,7 +993,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, /* De-allocates all pending stuff */ cx231xx_uninit_isoc(dev); - dma_q->p_left_data = kzalloc(4096, GFP_KERNEL); + dma_q->p_left_data = kzalloc(EP5_BUF_SIZE, GFP_KERNEL); if (dma_q->p_left_data == NULL) return -ENOMEM; diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 6929e4d970..74339a6a2f 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -120,6 +120,9 @@ #define CX23417_OSC_EN 8 #define CX23417_RESET 9 +#define EP5_BUF_SIZE 4096 +#define EP5_TIMEOUT_MS 2000 + struct cx23417_fmt { u32 fourcc; /* v4l2 format id */ int depth; diff --git a/drivers/media/usb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c index b2b27a86df..4cd21bb880 100644 --- a/drivers/media/usb/dvb-usb/gp8psk.c +++ b/drivers/media/usb/dvb-usb/gp8psk.c @@ -287,7 +287,7 @@ static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) int id = le16_to_cpu(d->udev->descriptor.idProduct); int is_rev1; - is_rev1 = (id == USB_PID_GENPIX_8PSK_REV_1_WARM) ? true : false; + is_rev1 = id == USB_PID_GENPIX_8PSK_REV_1_WARM; adap->fe_adap[0].fe = dvb_attach(gp8psk_fe_attach, &gp8psk_fe_ops, d, is_rev1); diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 8a39cac76c..9d9e14c858 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -279,10 +279,8 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) } } - fw_buffer = kmalloc(fw->size, GFP_KERNEL); + fw_buffer = kmemdup(fw->data, fw->size, GFP_KERNEL); if (fw_buffer) { - memcpy(fw_buffer, fw->data, fw->size); - rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2), fw_buffer, fw->size, &dummy, 1000); diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 4e966f6bf6..366f0e4a5d 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -107,8 +107,7 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) /* * TODO: These stk1160_dbg are very spammy! - * We should 1) check why we are getting them - * and 2) add ratelimit. + * We should check why we are getting them. * * UPDATE: One of the reasons (the only one?) for getting these * is incorrect standard (mismatch between expected and configured). @@ -151,7 +150,7 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) /* Let the bug hunt begin! sanity checks! */ if (lencopy < 0) { - stk1160_dbg("copy skipped: negative lencopy\n"); + printk_ratelimited(KERN_DEBUG "copy skipped: negative lencopy\n"); return; } diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 08fcd2ffa7..bbd90123a4 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -2592,6 +2592,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, + /* Chicony Electronics Co., Ltd Integrated Camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x04f2, + .idProduct = 0xb67c, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = UVC_PC_PROTOCOL_15, + .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 }, /* Chicony EasyCamera */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2994,6 +3003,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) }, + /* SunplusIT Inc HD Camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x2b7e, + .idProduct = 0xb752, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = UVC_PC_PROTOCOL_15, + .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 }, /* Lenovo Integrated Camera */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index f77ebd688c..331b8e535e 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -82,19 +82,3 @@ config V4L2_CCI_I2C depends on I2C select REGMAP_I2C select V4L2_CCI - -# Used by drivers that need Videobuf modules -config VIDEOBUF_GEN - tristate - -config VIDEOBUF_DMA_SG - tristate - select VIDEOBUF_GEN - -config VIDEOBUF_VMALLOC - tristate - select VIDEOBUF_GEN - -config VIDEOBUF_DMA_CONTIG - tristate - select VIDEOBUF_GEN diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index be25517057..2177b9d63a 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -33,10 +33,5 @@ obj-$(CONFIG_V4L2_JPEG_HELPER) += v4l2-jpeg.o obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o obj-$(CONFIG_V4L2_VP9) += v4l2-vp9.o -obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o -obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o -obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o -obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o - obj-$(CONFIG_VIDEO_TUNER) += tuner.o obj-$(CONFIG_VIDEO_DEV) += v4l2-dv-timings.o videodev.o diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c index c5ce9f11ad..3898ff7edd 100644 --- a/drivers/media/v4l2-core/v4l2-event.c +++ b/drivers/media/v4l2-core/v4l2-event.c @@ -238,6 +238,7 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, sev = kvzalloc(struct_size(sev, events, elems), GFP_KERNEL); if (!sev) return -ENOMEM; + sev->elems = elems; for (i = 0; i < elems; i++) sev->events[i].sev = sev; sev->type = sub->type; @@ -245,7 +246,6 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, sev->flags = sub->flags; sev->fh = fh; sev->ops = ops; - sev->elems = elems; mutex_lock(&fh->subscribe_lock); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index f4d9d62790..9b1de54ce3 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1510,6 +1510,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_AV1_FRAME: descr = "AV1 Frame"; break; case V4L2_PIX_FMT_MT2110T: descr = "Mediatek 10bit Tile Mode"; break; case V4L2_PIX_FMT_MT2110R: descr = "Mediatek 10bit Raster Mode"; break; + case V4L2_PIX_FMT_HEXTILE: descr = "Hextile Compressed Format"; break; default: if (fmt->description[0]) return; diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 31752c06d1..be86b906c9 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/overflow.h> #include <linux/slab.h> +#include <linux/string.h> #include <linux/types.h> #include <linux/version.h> #include <linux/videodev2.h> @@ -306,6 +307,42 @@ static int call_set_selection(struct v4l2_subdev *sd, sd->ops->pad->set_selection(sd, state, sel); } +static int call_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + unsigned int i; + int ret; + + memset(fd, 0, sizeof(*fd)); + + ret = sd->ops->pad->get_frame_desc(sd, pad, fd); + if (ret) + return ret; + + dev_dbg(sd->dev, "Frame descriptor on pad %u, type %s\n", pad, + fd->type == V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL ? "parallel" : + fd->type == V4L2_MBUS_FRAME_DESC_TYPE_CSI2 ? "CSI-2" : + "unknown"); + + for (i = 0; i < fd->num_entries; i++) { + struct v4l2_mbus_frame_desc_entry *entry = &fd->entry[i]; + char buf[20] = ""; + + if (fd->type == V4L2_MBUS_FRAME_DESC_TYPE_CSI2) + WARN_ON(snprintf(buf, sizeof(buf), + ", vc %u, dt 0x%02x", + entry->bus.csi2.vc, + entry->bus.csi2.dt) >= sizeof(buf)); + + dev_dbg(sd->dev, + "\tstream %u, code 0x%04x, length %u, flags 0x%04x%s\n", + entry->stream, entry->pixelcode, entry->length, + entry->flags, buf); + } + + return 0; +} + static inline int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) { @@ -359,6 +396,18 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable) { int ret; + /* + * The .s_stream() operation must never be called to start or stop an + * already started or stopped subdev. Catch offenders but don't return + * an error yet to avoid regressions. + * + * As .s_stream() is mutually exclusive with the .enable_streams() and + * .disable_streams() operation, we can use the enabled_streams field + * to store the subdev streaming state. + */ + if (WARN_ON(!!sd->enabled_streams == !!enable)) + return 0; + #if IS_REACHABLE(CONFIG_LEDS_CLASS) if (!IS_ERR_OR_NULL(sd->privacy_led)) { if (enable) @@ -372,9 +421,12 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable) if (!enable && ret < 0) { dev_warn(sd->dev, "disabling streaming failed (%d)\n", ret); - return 0; + ret = 0; } + if (!ret) + sd->enabled_streams = enable ? BIT(0) : 0; + return ret; } @@ -431,6 +483,7 @@ static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = { .set_edid = call_set_edid, .dv_timings_cap = call_dv_timings_cap, .enum_dv_timings = call_enum_dv_timings, + .get_frame_desc = call_get_frame_desc, .get_mbus_config = call_get_mbus_config, }; diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c deleted file mode 100644 index 606a271bdd..0000000000 --- a/drivers/media/v4l2-core/videobuf-core.c +++ /dev/null @@ -1,1198 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * generic helper functions for handling video4linux capture buffers - * - * (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org> - * - * Highly based on video-buf written originally by: - * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> - * (c) 2006 Mauro Carvalho Chehab, <mchehab@kernel.org> - * (c) 2006 Ted Walther and John Sokol - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/interrupt.h> - -#include <media/videobuf-core.h> -#include <media/v4l2-common.h> - -#define MAGIC_BUFFER 0x20070728 -#define MAGIC_CHECK(is, should) \ - do { \ - if (unlikely((is) != (should))) { \ - printk(KERN_ERR \ - "magic mismatch: %x (expected %x)\n", \ - is, should); \ - BUG(); \ - } \ - } while (0) - -static int debug; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux buffers"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>"); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) \ - do { \ - if (debug >= level) \ - printk(KERN_DEBUG "vbuf: " fmt, ## arg); \ - } while (0) - -/* --------------------------------------------------------------------- */ - -#define CALL(q, f, arg...) \ - ((q->int_ops->f) ? q->int_ops->f(arg) : 0) -#define CALLPTR(q, f, arg...) \ - ((q->int_ops->f) ? q->int_ops->f(arg) : NULL) - -struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q) -{ - struct videobuf_buffer *vb; - - BUG_ON(q->msize < sizeof(*vb)); - - if (!q->int_ops || !q->int_ops->alloc_vb) { - printk(KERN_ERR "No specific ops defined!\n"); - BUG(); - } - - vb = q->int_ops->alloc_vb(q->msize); - if (NULL != vb) { - init_waitqueue_head(&vb->done); - vb->magic = MAGIC_BUFFER; - } - - return vb; -} -EXPORT_SYMBOL_GPL(videobuf_alloc_vb); - -static int state_neither_active_nor_queued(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - unsigned long flags; - bool rc; - - spin_lock_irqsave(q->irqlock, flags); - rc = vb->state != VIDEOBUF_ACTIVE && vb->state != VIDEOBUF_QUEUED; - spin_unlock_irqrestore(q->irqlock, flags); - return rc; -}; - -int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb, - int non_blocking, int intr) -{ - bool is_ext_locked; - int ret = 0; - - MAGIC_CHECK(vb->magic, MAGIC_BUFFER); - - if (non_blocking) { - if (state_neither_active_nor_queued(q, vb)) - return 0; - return -EAGAIN; - } - - is_ext_locked = q->ext_lock && mutex_is_locked(q->ext_lock); - - /* Release vdev lock to prevent this wait from blocking outside access to - the device. */ - if (is_ext_locked) - mutex_unlock(q->ext_lock); - if (intr) - ret = wait_event_interruptible(vb->done, - state_neither_active_nor_queued(q, vb)); - else - wait_event(vb->done, state_neither_active_nor_queued(q, vb)); - /* Relock */ - if (is_ext_locked) - mutex_lock(q->ext_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_waiton); - -int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - MAGIC_CHECK(vb->magic, MAGIC_BUFFER); - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - return CALL(q, iolock, q, vb, fbuf); -} -EXPORT_SYMBOL_GPL(videobuf_iolock); - -void *videobuf_queue_to_vaddr(struct videobuf_queue *q, - struct videobuf_buffer *buf) -{ - if (q->int_ops->vaddr) - return q->int_ops->vaddr(buf); - return NULL; -} -EXPORT_SYMBOL_GPL(videobuf_queue_to_vaddr); - -/* --------------------------------------------------------------------- */ - - -void videobuf_queue_core_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct videobuf_qtype_ops *int_ops, - struct mutex *ext_lock) -{ - BUG_ON(!q); - memset(q, 0, sizeof(*q)); - q->irqlock = irqlock; - q->ext_lock = ext_lock; - q->dev = dev; - q->type = type; - q->field = field; - q->msize = msize; - q->ops = ops; - q->priv_data = priv; - q->int_ops = int_ops; - - /* All buffer operations are mandatory */ - BUG_ON(!q->ops->buf_setup); - BUG_ON(!q->ops->buf_prepare); - BUG_ON(!q->ops->buf_queue); - BUG_ON(!q->ops->buf_release); - - /* Lock is mandatory for queue_cancel to work */ - BUG_ON(!irqlock); - - /* Having implementations for abstract methods are mandatory */ - BUG_ON(!q->int_ops); - - mutex_init(&q->vb_lock); - init_waitqueue_head(&q->wait); - INIT_LIST_HEAD(&q->stream); -} -EXPORT_SYMBOL_GPL(videobuf_queue_core_init); - -/* Locking: Only usage in bttv unsafe find way to remove */ -int videobuf_queue_is_busy(struct videobuf_queue *q) -{ - int i; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - if (q->streaming) { - dprintk(1, "busy: streaming active\n"); - return 1; - } - if (q->reading) { - dprintk(1, "busy: pending read #1\n"); - return 1; - } - if (q->read_buf) { - dprintk(1, "busy: pending read #2\n"); - return 1; - } - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->map) { - dprintk(1, "busy: buffer #%d mapped\n", i); - return 1; - } - if (q->bufs[i]->state == VIDEOBUF_QUEUED) { - dprintk(1, "busy: buffer #%d queued\n", i); - return 1; - } - if (q->bufs[i]->state == VIDEOBUF_ACTIVE) { - dprintk(1, "busy: buffer #%d active\n", i); - return 1; - } - } - return 0; -} -EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); - -/* - * __videobuf_free() - free all the buffers and their control structures - * - * This function can only be called if streaming/reading is off, i.e. no buffers - * are under control of the driver. - */ -/* Locking: Caller holds q->vb_lock */ -static int __videobuf_free(struct videobuf_queue *q) -{ - int i; - - dprintk(1, "%s\n", __func__); - if (!q) - return 0; - - if (q->streaming || q->reading) { - dprintk(1, "Cannot free buffers when streaming or reading\n"); - return -EBUSY; - } - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - for (i = 0; i < VIDEO_MAX_FRAME; i++) - if (q->bufs[i] && q->bufs[i]->map) { - dprintk(1, "Cannot free mmapped buffers\n"); - return -EBUSY; - } - - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q, q->bufs[i]); - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - - return 0; -} - -/* Locking: Caller holds q->vb_lock */ -void videobuf_queue_cancel(struct videobuf_queue *q) -{ - unsigned long flags = 0; - int i; - - q->streaming = 0; - q->reading = 0; - wake_up_interruptible_sync(&q->wait); - - /* remove queued buffers from list */ - spin_lock_irqsave(q->irqlock, flags); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (q->bufs[i]->state == VIDEOBUF_QUEUED) { - list_del(&q->bufs[i]->queue); - q->bufs[i]->state = VIDEOBUF_ERROR; - wake_up_all(&q->bufs[i]->done); - } - } - spin_unlock_irqrestore(q->irqlock, flags); - - /* free all buffers + clear queue */ - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - q->ops->buf_release(q, q->bufs[i]); - } - INIT_LIST_HEAD(&q->stream); -} -EXPORT_SYMBOL_GPL(videobuf_queue_cancel); - -/* --------------------------------------------------------------------- */ - -/* Locking: Caller holds q->vb_lock */ -enum v4l2_field videobuf_next_field(struct videobuf_queue *q) -{ - enum v4l2_field field = q->field; - - BUG_ON(V4L2_FIELD_ANY == field); - - if (V4L2_FIELD_ALTERNATE == field) { - if (V4L2_FIELD_TOP == q->last) { - field = V4L2_FIELD_BOTTOM; - q->last = V4L2_FIELD_BOTTOM; - } else { - field = V4L2_FIELD_TOP; - q->last = V4L2_FIELD_TOP; - } - } - return field; -} -EXPORT_SYMBOL_GPL(videobuf_next_field); - -/* Locking: Caller holds q->vb_lock */ -static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, - struct videobuf_buffer *vb, enum v4l2_buf_type type) -{ - MAGIC_CHECK(vb->magic, MAGIC_BUFFER); - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - b->index = vb->i; - b->type = type; - - b->memory = vb->memory; - switch (b->memory) { - case V4L2_MEMORY_MMAP: - b->m.offset = vb->boff; - b->length = vb->bsize; - break; - case V4L2_MEMORY_USERPTR: - b->m.userptr = vb->baddr; - b->length = vb->bsize; - break; - case V4L2_MEMORY_OVERLAY: - b->m.offset = vb->boff; - break; - case V4L2_MEMORY_DMABUF: - /* DMABUF is not handled in videobuf framework */ - break; - } - - b->flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - if (vb->map) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (vb->state) { - case VIDEOBUF_PREPARED: - case VIDEOBUF_QUEUED: - case VIDEOBUF_ACTIVE: - b->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case VIDEOBUF_ERROR: - b->flags |= V4L2_BUF_FLAG_ERROR; - fallthrough; - case VIDEOBUF_DONE: - b->flags |= V4L2_BUF_FLAG_DONE; - break; - case VIDEOBUF_NEEDS_INIT: - case VIDEOBUF_IDLE: - /* nothing */ - break; - } - - b->field = vb->field; - v4l2_buffer_set_timestamp(b, vb->ts); - b->bytesused = vb->size; - b->sequence = vb->field_count >> 1; -} - -int videobuf_mmap_free(struct videobuf_queue *q) -{ - int ret; - videobuf_queue_lock(q); - ret = __videobuf_free(q); - videobuf_queue_unlock(q); - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_mmap_free); - -/* Locking: Caller holds q->vb_lock */ -int __videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory) -{ - unsigned int i; - int err; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - err = __videobuf_free(q); - if (0 != err) - return err; - - /* Allocate and initialize buffers */ - for (i = 0; i < bcount; i++) { - q->bufs[i] = videobuf_alloc_vb(q); - - if (NULL == q->bufs[i]) - break; - - q->bufs[i]->i = i; - q->bufs[i]->memory = memory; - q->bufs[i]->bsize = bsize; - switch (memory) { - case V4L2_MEMORY_MMAP: - q->bufs[i]->boff = PAGE_ALIGN(bsize) * i; - break; - case V4L2_MEMORY_USERPTR: - case V4L2_MEMORY_OVERLAY: - case V4L2_MEMORY_DMABUF: - /* nothing */ - break; - } - } - - if (!i) - return -ENOMEM; - - dprintk(1, "mmap setup: %d buffers, %d bytes each\n", i, bsize); - - return i; -} -EXPORT_SYMBOL_GPL(__videobuf_mmap_setup); - -int videobuf_mmap_setup(struct videobuf_queue *q, - unsigned int bcount, unsigned int bsize, - enum v4l2_memory memory) -{ - int ret; - videobuf_queue_lock(q); - ret = __videobuf_mmap_setup(q, bcount, bsize, memory); - videobuf_queue_unlock(q); - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_mmap_setup); - -int videobuf_reqbufs(struct videobuf_queue *q, - struct v4l2_requestbuffers *req) -{ - unsigned int size, count; - int retval; - - if (req->memory != V4L2_MEMORY_MMAP && - req->memory != V4L2_MEMORY_USERPTR && - req->memory != V4L2_MEMORY_OVERLAY) { - dprintk(1, "reqbufs: memory type invalid\n"); - return -EINVAL; - } - - videobuf_queue_lock(q); - if (req->type != q->type) { - dprintk(1, "reqbufs: queue type invalid\n"); - retval = -EINVAL; - goto done; - } - - if (q->streaming) { - dprintk(1, "reqbufs: streaming already exists\n"); - retval = -EBUSY; - goto done; - } - if (!list_empty(&q->stream)) { - dprintk(1, "reqbufs: stream running\n"); - retval = -EBUSY; - goto done; - } - - if (req->count == 0) { - dprintk(1, "reqbufs: count invalid (%d)\n", req->count); - retval = __videobuf_free(q); - goto done; - } - - count = req->count; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = 0; - q->ops->buf_setup(q, &count, &size); - dprintk(1, "reqbufs: bufs=%d, size=0x%x [%u pages total]\n", - count, size, - (unsigned int)((count * PAGE_ALIGN(size)) >> PAGE_SHIFT)); - - retval = __videobuf_mmap_setup(q, count, size, req->memory); - if (retval < 0) { - dprintk(1, "reqbufs: mmap setup returned %d\n", retval); - goto done; - } - - req->count = retval; - retval = 0; - - done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_reqbufs); - -int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) -{ - int ret = -EINVAL; - - videobuf_queue_lock(q); - if (unlikely(b->type != q->type)) { - dprintk(1, "querybuf: Wrong type.\n"); - goto done; - } - if (unlikely(b->index >= VIDEO_MAX_FRAME)) { - dprintk(1, "querybuf: index out of range.\n"); - goto done; - } - if (unlikely(NULL == q->bufs[b->index])) { - dprintk(1, "querybuf: buffer is null.\n"); - goto done; - } - - videobuf_status(q, b, q->bufs[b->index], q->type); - - ret = 0; -done: - videobuf_queue_unlock(q); - return ret; -} -EXPORT_SYMBOL_GPL(videobuf_querybuf); - -int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b) -{ - struct videobuf_buffer *buf; - enum v4l2_field field; - unsigned long flags = 0; - int retval; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - if (b->memory == V4L2_MEMORY_MMAP) - mmap_read_lock(current->mm); - - videobuf_queue_lock(q); - retval = -EBUSY; - if (q->reading) { - dprintk(1, "qbuf: Reading running...\n"); - goto done; - } - retval = -EINVAL; - if (b->type != q->type) { - dprintk(1, "qbuf: Wrong type.\n"); - goto done; - } - if (b->index >= VIDEO_MAX_FRAME) { - dprintk(1, "qbuf: index out of range.\n"); - goto done; - } - buf = q->bufs[b->index]; - if (NULL == buf) { - dprintk(1, "qbuf: buffer is null.\n"); - goto done; - } - MAGIC_CHECK(buf->magic, MAGIC_BUFFER); - if (buf->memory != b->memory) { - dprintk(1, "qbuf: memory type is wrong.\n"); - goto done; - } - if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) { - dprintk(1, "qbuf: buffer is already queued or active.\n"); - goto done; - } - - switch (b->memory) { - case V4L2_MEMORY_MMAP: - if (0 == buf->baddr) { - dprintk(1, "qbuf: mmap requested but buffer addr is zero!\n"); - goto done; - } - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT - || q->type == V4L2_BUF_TYPE_VBI_OUTPUT - || q->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT - || q->type == V4L2_BUF_TYPE_SDR_OUTPUT) { - buf->size = b->bytesused; - buf->field = b->field; - buf->ts = v4l2_buffer_get_timestamp(b); - } - break; - case V4L2_MEMORY_USERPTR: - if (b->length < buf->bsize) { - dprintk(1, "qbuf: buffer length is not enough\n"); - goto done; - } - if (VIDEOBUF_NEEDS_INIT != buf->state && - buf->baddr != b->m.userptr) - q->ops->buf_release(q, buf); - buf->baddr = b->m.userptr; - break; - case V4L2_MEMORY_OVERLAY: - buf->boff = b->m.offset; - break; - default: - dprintk(1, "qbuf: wrong memory type\n"); - goto done; - } - - dprintk(1, "qbuf: requesting next field\n"); - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, buf, field); - if (0 != retval) { - dprintk(1, "qbuf: buffer_prepare returned %d\n", retval); - goto done; - } - - list_add_tail(&buf->stream, &q->stream); - if (q->streaming) { - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, buf); - spin_unlock_irqrestore(q->irqlock, flags); - } - dprintk(1, "qbuf: succeeded\n"); - retval = 0; - wake_up_interruptible_sync(&q->wait); - -done: - videobuf_queue_unlock(q); - - if (b->memory == V4L2_MEMORY_MMAP) - mmap_read_unlock(current->mm); - - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_qbuf); - -/* Locking: Caller holds q->vb_lock */ -static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock) -{ - int retval; - -checks: - if (!q->streaming) { - dprintk(1, "next_buffer: Not streaming\n"); - retval = -EINVAL; - goto done; - } - - if (list_empty(&q->stream)) { - if (noblock) { - retval = -EAGAIN; - dprintk(2, "next_buffer: no buffers to dequeue\n"); - goto done; - } else { - dprintk(2, "next_buffer: waiting on buffer\n"); - - /* Drop lock to avoid deadlock with qbuf */ - videobuf_queue_unlock(q); - - /* Checking list_empty and streaming is safe without - * locks because we goto checks to validate while - * holding locks before proceeding */ - retval = wait_event_interruptible(q->wait, - !list_empty(&q->stream) || !q->streaming); - videobuf_queue_lock(q); - - if (retval) - goto done; - - goto checks; - } - } - - retval = 0; - -done: - return retval; -} - -/* Locking: Caller holds q->vb_lock */ -static int stream_next_buffer(struct videobuf_queue *q, - struct videobuf_buffer **vb, int nonblocking) -{ - int retval; - struct videobuf_buffer *buf = NULL; - - retval = stream_next_buffer_check_queue(q, nonblocking); - if (retval) - goto done; - - buf = list_entry(q->stream.next, struct videobuf_buffer, stream); - retval = videobuf_waiton(q, buf, nonblocking, 1); - if (retval < 0) - goto done; - - *vb = buf; -done: - return retval; -} - -int videobuf_dqbuf(struct videobuf_queue *q, - struct v4l2_buffer *b, int nonblocking) -{ - struct videobuf_buffer *buf = NULL; - int retval; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - memset(b, 0, sizeof(*b)); - videobuf_queue_lock(q); - - retval = stream_next_buffer(q, &buf, nonblocking); - if (retval < 0) { - dprintk(1, "dqbuf: next_buffer error: %i\n", retval); - goto done; - } - - switch (buf->state) { - case VIDEOBUF_ERROR: - dprintk(1, "dqbuf: state is error\n"); - break; - case VIDEOBUF_DONE: - dprintk(1, "dqbuf: state is done\n"); - break; - default: - dprintk(1, "dqbuf: state invalid\n"); - retval = -EINVAL; - goto done; - } - CALL(q, sync, q, buf); - videobuf_status(q, b, buf, q->type); - list_del(&buf->stream); - buf->state = VIDEOBUF_IDLE; - b->flags &= ~V4L2_BUF_FLAG_DONE; -done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_dqbuf); - -int videobuf_streamon(struct videobuf_queue *q) -{ - struct videobuf_buffer *buf; - unsigned long flags = 0; - int retval; - - videobuf_queue_lock(q); - retval = -EBUSY; - if (q->reading) - goto done; - retval = 0; - if (q->streaming) - goto done; - q->streaming = 1; - spin_lock_irqsave(q->irqlock, flags); - list_for_each_entry(buf, &q->stream, stream) - if (buf->state == VIDEOBUF_PREPARED) - q->ops->buf_queue(q, buf); - spin_unlock_irqrestore(q->irqlock, flags); - - wake_up_interruptible_sync(&q->wait); -done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_streamon); - -/* Locking: Caller holds q->vb_lock */ -static int __videobuf_streamoff(struct videobuf_queue *q) -{ - if (!q->streaming) - return -EINVAL; - - videobuf_queue_cancel(q); - - return 0; -} - -int videobuf_streamoff(struct videobuf_queue *q) -{ - int retval; - - videobuf_queue_lock(q); - retval = __videobuf_streamoff(q); - videobuf_queue_unlock(q); - - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_streamoff); - -/* Locking: Caller holds q->vb_lock */ -static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, - char __user *data, - size_t count, loff_t *ppos) -{ - enum v4l2_field field; - unsigned long flags = 0; - int retval; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - /* setup stuff */ - q->read_buf = videobuf_alloc_vb(q); - if (NULL == q->read_buf) - return -ENOMEM; - - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->baddr = (unsigned long)data; - q->read_buf->bsize = count; - - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, q->read_buf, field); - if (0 != retval) - goto done; - - /* start capture & wait */ - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, q->read_buf); - spin_unlock_irqrestore(q->irqlock, flags); - retval = videobuf_waiton(q, q->read_buf, 0, 0); - if (0 == retval) { - CALL(q, sync, q, q->read_buf); - if (VIDEOBUF_ERROR == q->read_buf->state) - retval = -EIO; - else - retval = q->read_buf->size; - } - -done: - /* cleanup */ - q->ops->buf_release(q, q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - return retval; -} - -static int __videobuf_copy_to_user(struct videobuf_queue *q, - struct videobuf_buffer *buf, - char __user *data, size_t count, - int nonblocking) -{ - void *vaddr = CALLPTR(q, vaddr, buf); - - /* copy to userspace */ - if (count > buf->size - q->read_off) - count = buf->size - q->read_off; - - if (copy_to_user(data, vaddr + q->read_off, count)) - return -EFAULT; - - return count; -} - -static int __videobuf_copy_stream(struct videobuf_queue *q, - struct videobuf_buffer *buf, - char __user *data, size_t count, size_t pos, - int vbihack, int nonblocking) -{ - unsigned int *fc = CALLPTR(q, vaddr, buf); - - if (vbihack) { - /* dirty, undocumented hack -- pass the frame counter - * within the last four bytes of each vbi data block. - * We need that one to maintain backward compatibility - * to all vbi decoding software out there ... */ - fc += (buf->size >> 2) - 1; - *fc = buf->field_count >> 1; - dprintk(1, "vbihack: %d\n", *fc); - } - - /* copy stuff using the common method */ - count = __videobuf_copy_to_user(q, buf, data, count, nonblocking); - - if ((count == -EFAULT) && (pos == 0)) - return -EFAULT; - - return count; -} - -ssize_t videobuf_read_one(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int nonblocking) -{ - enum v4l2_field field; - unsigned long flags = 0; - unsigned size = 0, nbufs = 1; - int retval; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - videobuf_queue_lock(q); - - q->ops->buf_setup(q, &nbufs, &size); - - if (NULL == q->read_buf && - count >= size && - !nonblocking) { - retval = videobuf_read_zerocopy(q, data, count, ppos); - if (retval >= 0 || retval == -EIO) - /* ok, all done */ - goto done; - /* fallback to kernel bounce buffer on failures */ - } - - if (NULL == q->read_buf) { - /* need to capture a new frame */ - retval = -ENOMEM; - q->read_buf = videobuf_alloc_vb(q); - - dprintk(1, "video alloc=0x%p\n", q->read_buf); - if (NULL == q->read_buf) - goto done; - q->read_buf->memory = V4L2_MEMORY_USERPTR; - q->read_buf->bsize = count; /* preferred size */ - field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, q->read_buf, field); - - if (0 != retval) { - kfree(q->read_buf); - q->read_buf = NULL; - goto done; - } - - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, q->read_buf); - spin_unlock_irqrestore(q->irqlock, flags); - - q->read_off = 0; - } - - /* wait until capture is done */ - retval = videobuf_waiton(q, q->read_buf, nonblocking, 1); - if (0 != retval) - goto done; - - CALL(q, sync, q, q->read_buf); - - if (VIDEOBUF_ERROR == q->read_buf->state) { - /* catch I/O errors */ - q->ops->buf_release(q, q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - retval = -EIO; - goto done; - } - - /* Copy to userspace */ - retval = __videobuf_copy_to_user(q, q->read_buf, data, count, nonblocking); - if (retval < 0) - goto done; - - q->read_off += retval; - if (q->read_off == q->read_buf->size) { - /* all data copied, cleanup */ - q->ops->buf_release(q, q->read_buf); - kfree(q->read_buf); - q->read_buf = NULL; - } - -done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_read_one); - -/* Locking: Caller holds q->vb_lock */ -static int __videobuf_read_start(struct videobuf_queue *q) -{ - enum v4l2_field field; - unsigned long flags = 0; - unsigned int count = 0, size = 0; - int err, i; - - q->ops->buf_setup(q, &count, &size); - if (count < 2) - count = 2; - if (count > VIDEO_MAX_FRAME) - count = VIDEO_MAX_FRAME; - size = PAGE_ALIGN(size); - - err = __videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); - if (err < 0) - return err; - - count = err; - - for (i = 0; i < count; i++) { - field = videobuf_next_field(q); - err = q->ops->buf_prepare(q, q->bufs[i], field); - if (err) - return err; - list_add_tail(&q->bufs[i]->stream, &q->stream); - } - spin_lock_irqsave(q->irqlock, flags); - for (i = 0; i < count; i++) - q->ops->buf_queue(q, q->bufs[i]); - spin_unlock_irqrestore(q->irqlock, flags); - q->reading = 1; - return 0; -} - -static void __videobuf_read_stop(struct videobuf_queue *q) -{ - int i; - - videobuf_queue_cancel(q); - __videobuf_free(q); - INIT_LIST_HEAD(&q->stream); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - q->read_buf = NULL; -} - -int videobuf_read_start(struct videobuf_queue *q) -{ - int rc; - - videobuf_queue_lock(q); - rc = __videobuf_read_start(q); - videobuf_queue_unlock(q); - - return rc; -} -EXPORT_SYMBOL_GPL(videobuf_read_start); - -void videobuf_read_stop(struct videobuf_queue *q) -{ - videobuf_queue_lock(q); - __videobuf_read_stop(q); - videobuf_queue_unlock(q); -} -EXPORT_SYMBOL_GPL(videobuf_read_stop); - -void videobuf_stop(struct videobuf_queue *q) -{ - videobuf_queue_lock(q); - - if (q->streaming) - __videobuf_streamoff(q); - - if (q->reading) - __videobuf_read_stop(q); - - videobuf_queue_unlock(q); -} -EXPORT_SYMBOL_GPL(videobuf_stop); - -ssize_t videobuf_read_stream(struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos, - int vbihack, int nonblocking) -{ - int rc, retval; - unsigned long flags = 0; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - dprintk(2, "%s\n", __func__); - videobuf_queue_lock(q); - retval = -EBUSY; - if (q->streaming) - goto done; - if (!q->reading) { - retval = __videobuf_read_start(q); - if (retval < 0) - goto done; - } - - retval = 0; - while (count > 0) { - /* get / wait for data */ - if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - rc = videobuf_waiton(q, q->read_buf, nonblocking, 1); - if (rc < 0) { - if (0 == retval) - retval = rc; - break; - } - - if (q->read_buf->state == VIDEOBUF_DONE) { - rc = __videobuf_copy_stream(q, q->read_buf, data + retval, count, - retval, vbihack, nonblocking); - if (rc < 0) { - retval = rc; - break; - } - retval += rc; - count -= rc; - q->read_off += rc; - } else { - /* some error */ - q->read_off = q->read_buf->size; - if (0 == retval) - retval = -EIO; - } - - /* requeue buffer when done with copying */ - if (q->read_off == q->read_buf->size) { - list_add_tail(&q->read_buf->stream, - &q->stream); - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, q->read_buf); - spin_unlock_irqrestore(q->irqlock, flags); - q->read_buf = NULL; - } - if (retval < 0) - break; - } - -done: - videobuf_queue_unlock(q); - return retval; -} -EXPORT_SYMBOL_GPL(videobuf_read_stream); - -__poll_t videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait) -{ - __poll_t req_events = poll_requested_events(wait); - struct videobuf_buffer *buf = NULL; - __poll_t rc = 0; - - videobuf_queue_lock(q); - if (q->streaming) { - if (!list_empty(&q->stream)) - buf = list_entry(q->stream.next, - struct videobuf_buffer, stream); - } else if (req_events & (EPOLLIN | EPOLLRDNORM)) { - if (!q->reading) - __videobuf_read_start(q); - if (!q->reading) { - rc = EPOLLERR; - } else if (NULL == q->read_buf) { - q->read_buf = list_entry(q->stream.next, - struct videobuf_buffer, - stream); - list_del(&q->read_buf->stream); - q->read_off = 0; - } - buf = q->read_buf; - } - if (buf) - poll_wait(file, &buf->done, wait); - else - rc = EPOLLERR; - - if (0 == rc) { - if (buf->state == VIDEOBUF_DONE || - buf->state == VIDEOBUF_ERROR) { - switch (q->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - case V4L2_BUF_TYPE_VBI_OUTPUT: - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - case V4L2_BUF_TYPE_SDR_OUTPUT: - rc = EPOLLOUT | EPOLLWRNORM; - break; - default: - rc = EPOLLIN | EPOLLRDNORM; - break; - } - } - } - videobuf_queue_unlock(q); - return rc; -} -EXPORT_SYMBOL_GPL(videobuf_poll_stream); - -int videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma) -{ - int rc = -EINVAL; - int i; - - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) { - dprintk(1, "mmap appl bug: PROT_WRITE and MAP_SHARED are required\n"); - return -EINVAL; - } - - videobuf_queue_lock(q); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - struct videobuf_buffer *buf = q->bufs[i]; - - if (buf && buf->memory == V4L2_MEMORY_MMAP && - buf->boff == (vma->vm_pgoff << PAGE_SHIFT)) { - rc = CALL(q, mmap_mapper, q, buf, vma); - break; - } - } - videobuf_queue_unlock(q); - - return rc; -} -EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c deleted file mode 100644 index 4c2ec7a0d8..0000000000 --- a/drivers/media/v4l2-core/videobuf-dma-contig.c +++ /dev/null @@ -1,402 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * helper functions for physically contiguous capture buffers - * - * The functions support hardware lacking scatter gather support - * (i.e. the buffers must be linear in physical memory) - * - * Copyright (c) 2008 Magnus Damm - * - * Based on videobuf-vmalloc.c, - * (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org> - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/mm.h> -#include <linux/pagemap.h> -#include <linux/dma-mapping.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <media/videobuf-dma-contig.h> - -struct videobuf_dma_contig_memory { - u32 magic; - void *vaddr; - dma_addr_t dma_handle; - unsigned long size; -}; - -#define MAGIC_DC_MEM 0x0733ac61 -#define MAGIC_CHECK(is, should) \ - if (unlikely((is) != (should))) { \ - pr_err("magic mismatch: %x expected %x\n", (is), (should)); \ - BUG(); \ - } - -static int __videobuf_dc_alloc(struct device *dev, - struct videobuf_dma_contig_memory *mem, - unsigned long size) -{ - mem->size = size; - mem->vaddr = dma_alloc_coherent(dev, mem->size, &mem->dma_handle, - GFP_KERNEL); - if (!mem->vaddr) { - dev_err(dev, "memory alloc size %ld failed\n", mem->size); - return -ENOMEM; - } - - dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size); - - return 0; -} - -static void __videobuf_dc_free(struct device *dev, - struct videobuf_dma_contig_memory *mem) -{ - dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle); - - mem->vaddr = NULL; -} - -static void videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", - map, map->count, vma->vm_start, vma->vm_end); - - map->count++; -} - -static void videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - int i; - - dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", - map, map->count, vma->vm_start, vma->vm_end); - - map->count--; - if (0 == map->count) { - struct videobuf_dma_contig_memory *mem; - - dev_dbg(q->dev, "munmap %p q=%p\n", map, q); - videobuf_queue_lock(q); - - /* We need first to cancel streams, before unmapping */ - if (q->streaming) - videobuf_queue_cancel(q); - - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - - if (q->bufs[i]->map != map) - continue; - - mem = q->bufs[i]->priv; - if (mem) { - /* This callback is called only if kernel has - allocated memory and this memory is mmapped. - In this case, memory should be freed, - in order to do memory unmap. - */ - - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - /* vfree is not atomic - can't be - called with IRQ's disabled - */ - dev_dbg(q->dev, "buf[%d] freeing %p\n", - i, mem->vaddr); - - __videobuf_dc_free(q->dev, mem); - mem->vaddr = NULL; - } - - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - } - - kfree(map); - - videobuf_queue_unlock(q); - } -} - -static const struct vm_operations_struct videobuf_vm_ops = { - .open = videobuf_vm_open, - .close = videobuf_vm_close, -}; - -/** - * videobuf_dma_contig_user_put() - reset pointer to user space buffer - * @mem: per-buffer private videobuf-dma-contig data - * - * This function resets the user space pointer - */ -static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem) -{ - mem->dma_handle = 0; - mem->size = 0; -} - -/** - * videobuf_dma_contig_user_get() - setup user space memory pointer - * @mem: per-buffer private videobuf-dma-contig data - * @vb: video buffer to map - * - * This function validates and sets up a pointer to user space memory. - * Only physically contiguous pfn-mapped memory is accepted. - * - * Returns 0 if successful. - */ -static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem, - struct videobuf_buffer *vb) -{ - unsigned long untagged_baddr = untagged_addr(vb->baddr); - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - unsigned long prev_pfn, this_pfn; - unsigned long pages_done, user_address; - unsigned int offset; - int ret; - - offset = untagged_baddr & ~PAGE_MASK; - mem->size = PAGE_ALIGN(vb->size + offset); - ret = -EINVAL; - - mmap_read_lock(mm); - - vma = find_vma(mm, untagged_baddr); - if (!vma) - goto out_up; - - if ((untagged_baddr + mem->size) > vma->vm_end) - goto out_up; - - pages_done = 0; - prev_pfn = 0; /* kill warning */ - user_address = untagged_baddr; - - while (pages_done < (mem->size >> PAGE_SHIFT)) { - ret = follow_pfn(vma, user_address, &this_pfn); - if (ret) - break; - - if (pages_done == 0) - mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset; - else if (this_pfn != (prev_pfn + 1)) - ret = -EFAULT; - - if (ret) - break; - - prev_pfn = this_pfn; - user_address += PAGE_SIZE; - pages_done++; - } - -out_up: - mmap_read_unlock(current->mm); - - return ret; -} - -static struct videobuf_buffer *__videobuf_alloc(size_t size) -{ - struct videobuf_dma_contig_memory *mem; - struct videobuf_buffer *vb; - - vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); - if (vb) { - vb->priv = ((char *)vb) + size; - mem = vb->priv; - mem->magic = MAGIC_DC_MEM; - } - - return vb; -} - -static void *__videobuf_to_vaddr(struct videobuf_buffer *buf) -{ - struct videobuf_dma_contig_memory *mem = buf->priv; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - return mem->vaddr; -} - -static int __videobuf_iolock(struct videobuf_queue *q, - struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - struct videobuf_dma_contig_memory *mem = vb->priv; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - dev_dbg(q->dev, "%s memory method MMAP\n", __func__); - - /* All handling should be done by __videobuf_mmap_mapper() */ - if (!mem->vaddr) { - dev_err(q->dev, "memory is not allocated/mmapped.\n"); - return -EINVAL; - } - break; - case V4L2_MEMORY_USERPTR: - dev_dbg(q->dev, "%s memory method USERPTR\n", __func__); - - /* handle pointer from user space */ - if (vb->baddr) - return videobuf_dma_contig_user_get(mem, vb); - - /* allocate memory for the read() method */ - if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size))) - return -ENOMEM; - break; - case V4L2_MEMORY_OVERLAY: - default: - dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__); - return -EINVAL; - } - - return 0; -} - -static int __videobuf_mmap_mapper(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma) -{ - struct videobuf_dma_contig_memory *mem; - struct videobuf_mapping *map; - int retval; - - dev_dbg(q->dev, "%s\n", __func__); - - /* create mapping + update buffer list */ - map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); - if (!map) - return -ENOMEM; - - buf->map = map; - map->q = q; - - buf->baddr = vma->vm_start; - - mem = buf->priv; - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize))) - goto error; - - /* the "vm_pgoff" is just used in v4l2 to find the - * corresponding buffer data structure which is allocated - * earlier and it does not mean the offset from the physical - * buffer start address as usual. So set it to 0 to pass - * the sanity check in dma_mmap_coherent(). - */ - vma->vm_pgoff = 0; - retval = dma_mmap_coherent(q->dev, vma, mem->vaddr, mem->dma_handle, - mem->size); - if (retval) { - dev_err(q->dev, "mmap: remap failed with error %d. ", - retval); - dma_free_coherent(q->dev, mem->size, - mem->vaddr, mem->dma_handle); - goto error; - } - - vma->vm_ops = &videobuf_vm_ops; - vm_flags_set(vma, VM_DONTEXPAND); - vma->vm_private_data = map; - - dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", - map, q, vma->vm_start, vma->vm_end, - (long int)buf->bsize, vma->vm_pgoff, buf->i); - - videobuf_vm_open(vma); - - return 0; - -error: - kfree(map); - return -ENOMEM; -} - -static struct videobuf_qtype_ops qops = { - .magic = MAGIC_QTYPE_OPS, - .alloc_vb = __videobuf_alloc, - .iolock = __videobuf_iolock, - .mmap_mapper = __videobuf_mmap_mapper, - .vaddr = __videobuf_to_vaddr, -}; - -void videobuf_queue_dma_contig_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock) -{ - videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, - priv, &qops, ext_lock); -} -EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init); - -dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf) -{ - struct videobuf_dma_contig_memory *mem = buf->priv; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - return mem->dma_handle; -} -EXPORT_SYMBOL_GPL(videobuf_to_dma_contig); - -void videobuf_dma_contig_free(struct videobuf_queue *q, - struct videobuf_buffer *buf) -{ - struct videobuf_dma_contig_memory *mem = buf->priv; - - /* mmapped memory can't be freed here, otherwise mmapped region - would be released, while still needed. In this case, the memory - release should happen inside videobuf_vm_close(). - So, it should free memory only if the memory were allocated for - read() operation. - */ - if (buf->memory != V4L2_MEMORY_USERPTR) - return; - - if (!mem) - return; - - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - /* handle user space pointer case */ - if (buf->baddr) { - videobuf_dma_contig_user_put(mem); - return; - } - - /* read() method */ - if (mem->vaddr) { - __videobuf_dc_free(q->dev, mem); - mem->vaddr = NULL; - } -} -EXPORT_SYMBOL_GPL(videobuf_dma_contig_free); - -MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers"); -MODULE_AUTHOR("Magnus Damm"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c deleted file mode 100644 index 405b89ea10..0000000000 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ /dev/null @@ -1,681 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * helper functions for SG DMA video4linux capture buffers - * - * The functions expect the hardware being able to scatter gather - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * (c) 2007 Mauro Carvalho Chehab, <mchehab@kernel.org> - * - * Highly based on video-buf written originally by: - * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> - * (c) 2006 Mauro Carvalho Chehab, <mchehab@kernel.org> - * (c) 2006 Ted Walther and John Sokol - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/sched/mm.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/pgtable.h> - -#include <linux/dma-mapping.h> -#include <linux/vmalloc.h> -#include <linux/pagemap.h> -#include <linux/scatterlist.h> -#include <asm/page.h> - -#include <media/videobuf-dma-sg.h> - -#define MAGIC_DMABUF 0x19721112 -#define MAGIC_SG_MEM 0x17890714 - -#define MAGIC_CHECK(is, should) \ - if (unlikely((is) != (should))) { \ - printk(KERN_ERR "magic mismatch: %x (expected %x)\n", \ - is, should); \ - BUG(); \ - } - -static int debug; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux dma sg buffers"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>"); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) \ - if (debug >= level) \ - printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) - -/* --------------------------------------------------------------------- */ - -/* - * Return a scatterlist for some page-aligned vmalloc()'ed memory - * block (NULL on errors). Memory for the scatterlist is allocated - * using kmalloc. The caller must free the memory. - */ -static struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, - int nr_pages) -{ - struct scatterlist *sglist; - struct page *pg; - int i; - - sglist = vzalloc(array_size(nr_pages, sizeof(*sglist))); - if (NULL == sglist) - return NULL; - sg_init_table(sglist, nr_pages); - for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { - pg = vmalloc_to_page(virt); - if (NULL == pg) - goto err; - BUG_ON(PageHighMem(pg)); - sg_set_page(&sglist[i], pg, PAGE_SIZE, 0); - } - return sglist; - -err: - vfree(sglist); - return NULL; -} - -/* - * Return a scatterlist for a an array of userpages (NULL on errors). - * Memory for the scatterlist is allocated using kmalloc. The caller - * must free the memory. - */ -static struct scatterlist *videobuf_pages_to_sg(struct page **pages, - int nr_pages, int offset, size_t size) -{ - struct scatterlist *sglist; - int i; - - if (NULL == pages[0]) - return NULL; - sglist = vmalloc(array_size(nr_pages, sizeof(*sglist))); - if (NULL == sglist) - return NULL; - sg_init_table(sglist, nr_pages); - - if (PageHighMem(pages[0])) - /* DMA to highmem pages might not work */ - goto highmem; - sg_set_page(&sglist[0], pages[0], - min_t(size_t, PAGE_SIZE - offset, size), offset); - size -= min_t(size_t, PAGE_SIZE - offset, size); - for (i = 1; i < nr_pages; i++) { - if (NULL == pages[i]) - goto nopage; - if (PageHighMem(pages[i])) - goto highmem; - sg_set_page(&sglist[i], pages[i], min_t(size_t, PAGE_SIZE, size), 0); - size -= min_t(size_t, PAGE_SIZE, size); - } - return sglist; - -nopage: - dprintk(2, "sgl: oops - no page\n"); - vfree(sglist); - return NULL; - -highmem: - dprintk(2, "sgl: oops - highmem page\n"); - vfree(sglist); - return NULL; -} - -/* --------------------------------------------------------------------- */ - -struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf) -{ - struct videobuf_dma_sg_memory *mem = buf->priv; - BUG_ON(!mem); - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - return &mem->dma; -} -EXPORT_SYMBOL_GPL(videobuf_to_dma); - -static void videobuf_dma_init(struct videobuf_dmabuf *dma) -{ - memset(dma, 0, sizeof(*dma)); - dma->magic = MAGIC_DMABUF; -} - -static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, - int direction, unsigned long data, unsigned long size) -{ - unsigned int gup_flags = FOLL_LONGTERM; - unsigned long first, last; - int err; - - dma->direction = direction; - switch (dma->direction) { - case DMA_FROM_DEVICE: - gup_flags |= FOLL_WRITE; - break; - case DMA_TO_DEVICE: - break; - default: - BUG(); - } - - first = (data & PAGE_MASK) >> PAGE_SHIFT; - last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; - dma->offset = data & ~PAGE_MASK; - dma->size = size; - dma->nr_pages = last-first+1; - dma->pages = kmalloc_array(dma->nr_pages, sizeof(struct page *), - GFP_KERNEL); - if (NULL == dma->pages) - return -ENOMEM; - - dprintk(1, "init user [0x%lx+0x%lx => %lu pages]\n", - data, size, dma->nr_pages); - - err = pin_user_pages(data & PAGE_MASK, dma->nr_pages, gup_flags, - dma->pages); - - if (err != dma->nr_pages) { - dma->nr_pages = (err >= 0) ? err : 0; - dprintk(1, "pin_user_pages: err=%d [%lu]\n", err, - dma->nr_pages); - return err < 0 ? err : -EINVAL; - } - return 0; -} - -static int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, - unsigned long data, unsigned long size) -{ - int ret; - - mmap_read_lock(current->mm); - ret = videobuf_dma_init_user_locked(dma, direction, data, size); - mmap_read_unlock(current->mm); - - return ret; -} - -static int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, - unsigned long nr_pages) -{ - int i; - - dprintk(1, "init kernel [%lu pages]\n", nr_pages); - - dma->direction = direction; - dma->vaddr_pages = kcalloc(nr_pages, sizeof(*dma->vaddr_pages), - GFP_KERNEL); - if (!dma->vaddr_pages) - return -ENOMEM; - - dma->dma_addr = kcalloc(nr_pages, sizeof(*dma->dma_addr), GFP_KERNEL); - if (!dma->dma_addr) { - kfree(dma->vaddr_pages); - return -ENOMEM; - } - for (i = 0; i < nr_pages; i++) { - void *addr; - - addr = dma_alloc_coherent(dma->dev, PAGE_SIZE, - &(dma->dma_addr[i]), GFP_KERNEL); - if (addr == NULL) - goto out_free_pages; - - dma->vaddr_pages[i] = virt_to_page(addr); - } - dma->vaddr = vmap(dma->vaddr_pages, nr_pages, VM_MAP | VM_IOREMAP, - PAGE_KERNEL); - if (NULL == dma->vaddr) { - dprintk(1, "vmalloc_32(%lu pages) failed\n", nr_pages); - goto out_free_pages; - } - - dprintk(1, "vmalloc is at addr %p, size=%lu\n", - dma->vaddr, nr_pages << PAGE_SHIFT); - - memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT); - dma->nr_pages = nr_pages; - - return 0; -out_free_pages: - while (i > 0) { - void *addr; - - i--; - addr = page_address(dma->vaddr_pages[i]); - dma_free_coherent(dma->dev, PAGE_SIZE, addr, dma->dma_addr[i]); - } - kfree(dma->dma_addr); - dma->dma_addr = NULL; - kfree(dma->vaddr_pages); - dma->vaddr_pages = NULL; - - return -ENOMEM; - -} - -static int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, - dma_addr_t addr, unsigned long nr_pages) -{ - dprintk(1, "init overlay [%lu pages @ bus 0x%lx]\n", - nr_pages, (unsigned long)addr); - dma->direction = direction; - - if (0 == addr) - return -EINVAL; - - dma->bus_addr = addr; - dma->nr_pages = nr_pages; - - return 0; -} - -static int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma) -{ - MAGIC_CHECK(dma->magic, MAGIC_DMABUF); - BUG_ON(0 == dma->nr_pages); - - if (dma->pages) { - dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, - dma->offset, dma->size); - } - if (dma->vaddr) { - dma->sglist = videobuf_vmalloc_to_sg(dma->vaddr, - dma->nr_pages); - } - if (dma->bus_addr) { - dma->sglist = vmalloc(sizeof(*dma->sglist)); - if (NULL != dma->sglist) { - dma->sglen = 1; - sg_dma_address(&dma->sglist[0]) = dma->bus_addr - & PAGE_MASK; - dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; - sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; - } - } - if (NULL == dma->sglist) { - dprintk(1, "scatterlist is NULL\n"); - return -ENOMEM; - } - if (!dma->bus_addr) { - dma->sglen = dma_map_sg(dev, dma->sglist, - dma->nr_pages, dma->direction); - if (0 == dma->sglen) { - printk(KERN_WARNING - "%s: videobuf_map_sg failed\n", __func__); - vfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - return -ENOMEM; - } - } - - return 0; -} - -int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma) -{ - MAGIC_CHECK(dma->magic, MAGIC_DMABUF); - - if (!dma->sglen) - return 0; - - dma_unmap_sg(dev, dma->sglist, dma->nr_pages, dma->direction); - - vfree(dma->sglist); - dma->sglist = NULL; - dma->sglen = 0; - - return 0; -} -EXPORT_SYMBOL_GPL(videobuf_dma_unmap); - -int videobuf_dma_free(struct videobuf_dmabuf *dma) -{ - int i; - MAGIC_CHECK(dma->magic, MAGIC_DMABUF); - BUG_ON(dma->sglen); - - if (dma->pages) { - unpin_user_pages_dirty_lock(dma->pages, dma->nr_pages, - dma->direction == DMA_FROM_DEVICE); - kfree(dma->pages); - dma->pages = NULL; - } - - if (dma->dma_addr) { - for (i = 0; i < dma->nr_pages; i++) { - void *addr; - - addr = page_address(dma->vaddr_pages[i]); - dma_free_coherent(dma->dev, PAGE_SIZE, addr, - dma->dma_addr[i]); - } - kfree(dma->dma_addr); - dma->dma_addr = NULL; - kfree(dma->vaddr_pages); - dma->vaddr_pages = NULL; - vunmap(dma->vaddr); - dma->vaddr = NULL; - } - - if (dma->bus_addr) - dma->bus_addr = 0; - dma->direction = DMA_NONE; - - return 0; -} -EXPORT_SYMBOL_GPL(videobuf_dma_free); - -/* --------------------------------------------------------------------- */ - -static void videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map, - map->count, vma->vm_start, vma->vm_end); - - map->count++; -} - -static void videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - struct videobuf_dma_sg_memory *mem; - int i; - - dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map, - map->count, vma->vm_start, vma->vm_end); - - map->count--; - if (0 == map->count) { - dprintk(1, "munmap %p q=%p\n", map, q); - videobuf_queue_lock(q); - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - mem = q->bufs[i]->priv; - if (!mem) - continue; - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - if (q->bufs[i]->map != map) - continue; - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - q->ops->buf_release(q, q->bufs[i]); - } - videobuf_queue_unlock(q); - kfree(map); - } -} - -/* - * Get a anonymous page for the mapping. Make sure we can DMA to that - * memory location with 32bit PCI devices (i.e. don't use highmem for - * now ...). Bounce buffers don't work very well for the data rates - * video capture has. - */ -static vm_fault_t videobuf_vm_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct page *page; - - dprintk(3, "fault: fault @ %08lx [vma %08lx-%08lx]\n", - vmf->address, vma->vm_start, vma->vm_end); - - page = alloc_page(GFP_USER | __GFP_DMA32); - if (!page) - return VM_FAULT_OOM; - clear_user_highpage(page, vmf->address); - vmf->page = page; - - return 0; -} - -static const struct vm_operations_struct videobuf_vm_ops = { - .open = videobuf_vm_open, - .close = videobuf_vm_close, - .fault = videobuf_vm_fault, -}; - -/* --------------------------------------------------------------------- - * SG handlers for the generic methods - */ - -/* Allocated area consists on 3 parts: - struct video_buffer - struct <driver>_buffer (cx88_buffer, saa7134_buf, ...) - struct videobuf_dma_sg_memory - */ - -static struct videobuf_buffer *__videobuf_alloc_vb(size_t size) -{ - struct videobuf_dma_sg_memory *mem; - struct videobuf_buffer *vb; - - vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); - if (!vb) - return vb; - - mem = vb->priv = ((char *)vb) + size; - mem->magic = MAGIC_SG_MEM; - - videobuf_dma_init(&mem->dma); - - dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n", - __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb), - mem, (long)sizeof(*mem)); - - return vb; -} - -static void *__videobuf_to_vaddr(struct videobuf_buffer *buf) -{ - struct videobuf_dma_sg_memory *mem = buf->priv; - BUG_ON(!mem); - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - return mem->dma.vaddr; -} - -static int __videobuf_iolock(struct videobuf_queue *q, - struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - struct videobuf_dma_sg_memory *mem = vb->priv; - unsigned long pages; - dma_addr_t bus; - int err; - - BUG_ON(!mem); - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - if (!mem->dma.dev) - mem->dma.dev = q->dev; - else - WARN_ON(mem->dma.dev != q->dev); - - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - case V4L2_MEMORY_USERPTR: - if (0 == vb->baddr) { - /* no userspace addr -- kernel bounce buffer */ - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_kernel(&mem->dma, - DMA_FROM_DEVICE, - pages); - if (0 != err) - return err; - } else if (vb->memory == V4L2_MEMORY_USERPTR) { - /* dma directly to userspace */ - err = videobuf_dma_init_user(&mem->dma, - DMA_FROM_DEVICE, - vb->baddr, vb->bsize); - if (0 != err) - return err; - } else { - /* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP - buffers can only be called from videobuf_qbuf - we take current->mm->mmap_lock there, to prevent - locking inversion, so don't take it here */ - - err = videobuf_dma_init_user_locked(&mem->dma, - DMA_FROM_DEVICE, - vb->baddr, vb->bsize); - if (0 != err) - return err; - } - break; - case V4L2_MEMORY_OVERLAY: - if (NULL == fbuf) - return -EINVAL; - /* FIXME: need sanity checks for vb->boff */ - /* - * Using a double cast to avoid compiler warnings when - * building for PAE. Compiler doesn't like direct casting - * of a 32 bit ptr to 64 bit integer. - */ - bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff; - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_overlay(&mem->dma, DMA_FROM_DEVICE, - bus, pages); - if (0 != err) - return err; - break; - default: - BUG(); - } - err = videobuf_dma_map(q->dev, &mem->dma); - if (0 != err) - return err; - - return 0; -} - -static int __videobuf_sync(struct videobuf_queue *q, - struct videobuf_buffer *buf) -{ - struct videobuf_dma_sg_memory *mem = buf->priv; - BUG_ON(!mem || !mem->dma.sglen); - - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - MAGIC_CHECK(mem->dma.magic, MAGIC_DMABUF); - - dma_sync_sg_for_cpu(q->dev, mem->dma.sglist, - mem->dma.nr_pages, mem->dma.direction); - - return 0; -} - -static int __videobuf_mmap_mapper(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma) -{ - struct videobuf_dma_sg_memory *mem = buf->priv; - struct videobuf_mapping *map; - unsigned int first, last, size = 0, i; - int retval; - - retval = -EINVAL; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - - /* look for first buffer to map */ - for (first = 0; first < VIDEO_MAX_FRAME; first++) { - if (buf == q->bufs[first]) { - size = PAGE_ALIGN(q->bufs[first]->bsize); - break; - } - } - - /* paranoia, should never happen since buf is always valid. */ - if (!size) { - dprintk(1, "mmap app bug: offset invalid [offset=0x%lx]\n", - (vma->vm_pgoff << PAGE_SHIFT)); - goto done; - } - - last = first; - - /* create mapping + update buffer list */ - retval = -ENOMEM; - map = kmalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); - if (NULL == map) - goto done; - - size = 0; - for (i = first; i <= last; i++) { - if (NULL == q->bufs[i]) - continue; - q->bufs[i]->map = map; - q->bufs[i]->baddr = vma->vm_start + size; - size += PAGE_ALIGN(q->bufs[i]->bsize); - } - - map->count = 1; - map->q = q; - vma->vm_ops = &videobuf_vm_ops; - /* using shared anonymous pages */ - vm_flags_mod(vma, VM_DONTEXPAND | VM_DONTDUMP, VM_IO); - vma->vm_private_data = map; - dprintk(1, "mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", - map, q, vma->vm_start, vma->vm_end, vma->vm_pgoff, first, last); - retval = 0; - -done: - return retval; -} - -static struct videobuf_qtype_ops sg_ops = { - .magic = MAGIC_QTYPE_OPS, - - .alloc_vb = __videobuf_alloc_vb, - .iolock = __videobuf_iolock, - .sync = __videobuf_sync, - .mmap_mapper = __videobuf_mmap_mapper, - .vaddr = __videobuf_to_vaddr, -}; - -void *videobuf_sg_alloc(size_t size) -{ - struct videobuf_queue q; - - /* Required to make generic handler to call __videobuf_alloc */ - q.int_ops = &sg_ops; - - q.msize = size; - - return videobuf_alloc_vb(&q); -} -EXPORT_SYMBOL_GPL(videobuf_sg_alloc); - -void videobuf_queue_sg_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock) -{ - videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, - priv, &sg_ops, ext_lock); -} -EXPORT_SYMBOL_GPL(videobuf_queue_sg_init); - diff --git a/drivers/media/v4l2-core/videobuf-vmalloc.c b/drivers/media/v4l2-core/videobuf-vmalloc.c deleted file mode 100644 index 85c7090606..0000000000 --- a/drivers/media/v4l2-core/videobuf-vmalloc.c +++ /dev/null @@ -1,326 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * helper functions for vmalloc video4linux capture buffers - * - * The functions expect the hardware being able to scatter gather - * (i.e. the buffers are not linear in physical memory, but fragmented - * into PAGE_SIZE chunks). They also assume the driver does not need - * to touch the video data. - * - * (c) 2007 Mauro Carvalho Chehab <mchehab@kernel.org> - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/pgtable.h> - -#include <linux/pci.h> -#include <linux/vmalloc.h> -#include <linux/pagemap.h> -#include <asm/page.h> - -#include <media/videobuf-vmalloc.h> - -#define MAGIC_DMABUF 0x17760309 -#define MAGIC_VMAL_MEM 0x18221223 - -#define MAGIC_CHECK(is, should) \ - if (unlikely((is) != (should))) { \ - printk(KERN_ERR "magic mismatch: %x (expected %x)\n", \ - is, should); \ - BUG(); \ - } - -static int debug; -module_param(debug, int, 0644); - -MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>"); -MODULE_LICENSE("GPL"); - -#define dprintk(level, fmt, arg...) \ - if (debug >= level) \ - printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg) - - -/***************************************************************************/ - -static void videobuf_vm_open(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - - dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map, - map->count, vma->vm_start, vma->vm_end); - - map->count++; -} - -static void videobuf_vm_close(struct vm_area_struct *vma) -{ - struct videobuf_mapping *map = vma->vm_private_data; - struct videobuf_queue *q = map->q; - int i; - - dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, - map->count, vma->vm_start, vma->vm_end); - - map->count--; - if (0 == map->count) { - struct videobuf_vmalloc_memory *mem; - - dprintk(1, "munmap %p q=%p\n", map, q); - videobuf_queue_lock(q); - - /* We need first to cancel streams, before unmapping */ - if (q->streaming) - videobuf_queue_cancel(q); - - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - - if (q->bufs[i]->map != map) - continue; - - mem = q->bufs[i]->priv; - if (mem) { - /* This callback is called only if kernel has - allocated memory and this memory is mmapped. - In this case, memory should be freed, - in order to do memory unmap. - */ - - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - /* vfree is not atomic - can't be - called with IRQ's disabled - */ - dprintk(1, "%s: buf[%d] freeing (%p)\n", - __func__, i, mem->vaddr); - - vfree(mem->vaddr); - mem->vaddr = NULL; - } - - q->bufs[i]->map = NULL; - q->bufs[i]->baddr = 0; - } - - kfree(map); - - videobuf_queue_unlock(q); - } - - return; -} - -static const struct vm_operations_struct videobuf_vm_ops = { - .open = videobuf_vm_open, - .close = videobuf_vm_close, -}; - -/* --------------------------------------------------------------------- - * vmalloc handlers for the generic methods - */ - -/* Allocated area consists on 3 parts: - struct video_buffer - struct <driver>_buffer (cx88_buffer, saa7134_buf, ...) - struct videobuf_dma_sg_memory - */ - -static struct videobuf_buffer *__videobuf_alloc_vb(size_t size) -{ - struct videobuf_vmalloc_memory *mem; - struct videobuf_buffer *vb; - - vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); - if (!vb) - return vb; - - mem = vb->priv = ((char *)vb) + size; - mem->magic = MAGIC_VMAL_MEM; - - dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n", - __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb), - mem, (long)sizeof(*mem)); - - return vb; -} - -static int __videobuf_iolock(struct videobuf_queue *q, - struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) -{ - struct videobuf_vmalloc_memory *mem = vb->priv; - int pages; - - BUG_ON(!mem); - - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - switch (vb->memory) { - case V4L2_MEMORY_MMAP: - dprintk(1, "%s memory method MMAP\n", __func__); - - /* All handling should be done by __videobuf_mmap_mapper() */ - if (!mem->vaddr) { - printk(KERN_ERR "memory is not allocated/mmapped.\n"); - return -EINVAL; - } - break; - case V4L2_MEMORY_USERPTR: - pages = PAGE_ALIGN(vb->size); - - dprintk(1, "%s memory method USERPTR\n", __func__); - - if (vb->baddr) { - printk(KERN_ERR "USERPTR is currently not supported\n"); - return -EINVAL; - } - - /* The only USERPTR currently supported is the one needed for - * read() method. - */ - - mem->vaddr = vmalloc_user(pages); - if (!mem->vaddr) { - printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); - return -ENOMEM; - } - dprintk(1, "vmalloc is at addr %p (%d pages)\n", - mem->vaddr, pages); - break; - case V4L2_MEMORY_OVERLAY: - default: - dprintk(1, "%s memory method OVERLAY/unknown\n", __func__); - - /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ - printk(KERN_ERR "Memory method currently unsupported.\n"); - return -EINVAL; - } - - return 0; -} - -static int __videobuf_mmap_mapper(struct videobuf_queue *q, - struct videobuf_buffer *buf, - struct vm_area_struct *vma) -{ - struct videobuf_vmalloc_memory *mem; - struct videobuf_mapping *map; - int retval, pages; - - dprintk(1, "%s\n", __func__); - - /* create mapping + update buffer list */ - map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); - if (NULL == map) - return -ENOMEM; - - buf->map = map; - map->q = q; - - buf->baddr = vma->vm_start; - - mem = buf->priv; - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - pages = PAGE_ALIGN(vma->vm_end - vma->vm_start); - mem->vaddr = vmalloc_user(pages); - if (!mem->vaddr) { - printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); - goto error; - } - dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages); - - /* Try to remap memory */ - retval = remap_vmalloc_range(vma, mem->vaddr, 0); - if (retval < 0) { - printk(KERN_ERR "mmap: remap failed with error %d. ", retval); - vfree(mem->vaddr); - goto error; - } - - vma->vm_ops = &videobuf_vm_ops; - vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP); - vma->vm_private_data = map; - - dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", - map, q, vma->vm_start, vma->vm_end, - (long int)buf->bsize, - vma->vm_pgoff, buf->i); - - videobuf_vm_open(vma); - - return 0; - -error: - mem = NULL; - kfree(map); - return -ENOMEM; -} - -static struct videobuf_qtype_ops qops = { - .magic = MAGIC_QTYPE_OPS, - - .alloc_vb = __videobuf_alloc_vb, - .iolock = __videobuf_iolock, - .mmap_mapper = __videobuf_mmap_mapper, - .vaddr = videobuf_to_vmalloc, -}; - -void videobuf_queue_vmalloc_init(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock) -{ - videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, - priv, &qops, ext_lock); -} -EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); - -void *videobuf_to_vmalloc(struct videobuf_buffer *buf) -{ - struct videobuf_vmalloc_memory *mem = buf->priv; - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - return mem->vaddr; -} -EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); - -void videobuf_vmalloc_free(struct videobuf_buffer *buf) -{ - struct videobuf_vmalloc_memory *mem = buf->priv; - - /* mmapped memory can't be freed here, otherwise mmapped region - would be released, while still needed. In this case, the memory - release should happen inside videobuf_vm_close(). - So, it should free memory only if the memory were allocated for - read() operation. - */ - if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr) - return; - - if (!mem) - return; - - MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - - vfree(mem->vaddr); - mem->vaddr = NULL; - - return; -} -EXPORT_SYMBOL_GPL(videobuf_vmalloc_free); - |