diff options
Diffstat (limited to 'drivers/media')
561 files changed, 36771 insertions, 5497 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 55d9c2b82b7e..edfe99b22d56 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -8,6 +8,11 @@ config CEC_CORE config CEC_NOTIFIER bool +config CEC_PIN + bool + +source "drivers/media/rc/Kconfig" + menuconfig MEDIA_SUPPORT tristate "Multimedia support" depends on HAS_IOMEM @@ -72,20 +77,6 @@ config MEDIA_SDR_SUPPORT Say Y when you have a software defined radio device. -config MEDIA_RC_SUPPORT - bool "Remote Controller support" - depends on INPUT - ---help--- - Enable support for Remote Controllers on Linux. This is - needed in order to support several video capture adapters, - standalone IR receivers/transmitters, and RF receivers. - - Enable this option if you have a video capture board even - if you don't need IR, as otherwise, you may not be able to - compile the driver for your adapter. - - Say Y when you have a TV or an IR device. - config MEDIA_CEC_SUPPORT bool "HDMI CEC support" ---help--- @@ -175,7 +166,6 @@ config TTPCI_EEPROM source "drivers/media/dvb-core/Kconfig" comment "Media drivers" -source "drivers/media/rc/Kconfig" # # V4L platform/mem2mem drivers diff --git a/drivers/media/cec/Makefile b/drivers/media/cec/Makefile index eaf408e64669..3353c1741961 100644 --- a/drivers/media/cec/Makefile +++ b/drivers/media/cec/Makefile @@ -4,4 +4,8 @@ ifeq ($(CONFIG_CEC_NOTIFIER),y) cec-objs += cec-notifier.o endif +ifeq ($(CONFIG_CEC_PIN),y) + cec-objs += cec-pin.o +endif + obj-$(CONFIG_CEC_CORE) += cec.o diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index d596b601ff42..dd769e40416f 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -78,42 +78,62 @@ static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr * Queue a new event for this filehandle. If ts == 0, then set it * to the current time. * - * The two events that are currently defined do not need to keep track - * of intermediate events, so no actual queue of events is needed, - * instead just store the latest state and the total number of lost - * messages. - * - * Should new events be added in the future that require intermediate - * results to be queued as well, then a proper queue data structure is - * required. But until then, just keep it simple. + * We keep a queue of at most max_event events where max_event differs + * per event. If the queue becomes full, then drop the oldest event and + * keep track of how many events we've dropped. */ void cec_queue_event_fh(struct cec_fh *fh, const struct cec_event *new_ev, u64 ts) { - struct cec_event *ev = &fh->events[new_ev->event - 1]; + static const u8 max_events[CEC_NUM_EVENTS] = { + 1, 1, 64, 64, + }; + struct cec_event_entry *entry; + unsigned int ev_idx = new_ev->event - 1; + + if (WARN_ON(ev_idx >= ARRAY_SIZE(fh->events))) + return; if (ts == 0) ts = ktime_get_ns(); mutex_lock(&fh->lock); - if (new_ev->event == CEC_EVENT_LOST_MSGS && - fh->pending_events & (1 << new_ev->event)) { - /* - * If there is already a lost_msgs event, then just - * update the lost_msgs count. This effectively - * merges the old and new events into one. - */ - ev->lost_msgs.lost_msgs += new_ev->lost_msgs.lost_msgs; - goto unlock; - } + if (ev_idx < CEC_NUM_CORE_EVENTS) + entry = &fh->core_events[ev_idx]; + else + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (entry) { + if (new_ev->event == CEC_EVENT_LOST_MSGS && + fh->queued_events[ev_idx]) { + entry->ev.lost_msgs.lost_msgs += + new_ev->lost_msgs.lost_msgs; + goto unlock; + } + entry->ev = *new_ev; + entry->ev.ts = ts; + + if (fh->queued_events[ev_idx] < max_events[ev_idx]) { + /* Add new msg at the end of the queue */ + list_add_tail(&entry->list, &fh->events[ev_idx]); + fh->queued_events[ev_idx]++; + fh->total_queued_events++; + goto unlock; + } - /* - * Intermediate states are not interesting, so just - * overwrite any older event. - */ - *ev = *new_ev; - ev->ts = ts; - fh->pending_events |= 1 << new_ev->event; + if (ev_idx >= CEC_NUM_CORE_EVENTS) { + list_add_tail(&entry->list, &fh->events[ev_idx]); + /* drop the oldest event */ + entry = list_first_entry(&fh->events[ev_idx], + struct cec_event_entry, list); + list_del(&entry->list); + kfree(entry); + } + } + /* Mark that events were lost */ + entry = list_first_entry_or_null(&fh->events[ev_idx], + struct cec_event_entry, list); + if (entry) + entry->ev.flags |= CEC_EVENT_FL_DROPPED_EVENTS; unlock: mutex_unlock(&fh->lock); @@ -133,47 +153,68 @@ static void cec_queue_event(struct cec_adapter *adap, mutex_unlock(&adap->devnode.lock); } +/* Notify userspace that the CEC pin changed state at the given time. */ +void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, ktime_t ts) +{ + struct cec_event ev = { + .event = is_high ? CEC_EVENT_PIN_CEC_HIGH : + CEC_EVENT_PIN_CEC_LOW, + }; + struct cec_fh *fh; + + mutex_lock(&adap->devnode.lock); + list_for_each_entry(fh, &adap->devnode.fhs, list) + if (fh->mode_follower == CEC_MODE_MONITOR_PIN) + cec_queue_event_fh(fh, &ev, ktime_to_ns(ts)); + mutex_unlock(&adap->devnode.lock); +} +EXPORT_SYMBOL_GPL(cec_queue_pin_cec_event); + /* - * Queue a new message for this filehandle. If there is no more room - * in the queue, then send the LOST_MSGS event instead. + * Queue a new message for this filehandle. + * + * We keep a queue of at most CEC_MAX_MSG_RX_QUEUE_SZ messages. If the + * queue becomes full, then drop the oldest message and keep track + * of how many messages we've dropped. */ static void cec_queue_msg_fh(struct cec_fh *fh, const struct cec_msg *msg) { - static const struct cec_event ev_lost_msg = { - .ts = 0, + static const struct cec_event ev_lost_msgs = { .event = CEC_EVENT_LOST_MSGS, - .flags = 0, - { - .lost_msgs.lost_msgs = 1, - }, + .lost_msgs.lost_msgs = 1, }; struct cec_msg_entry *entry; mutex_lock(&fh->lock); entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - goto lost_msgs; - - entry->msg = *msg; - /* Add new msg at the end of the queue */ - list_add_tail(&entry->list, &fh->msgs); + if (entry) { + entry->msg = *msg; + /* Add new msg at the end of the queue */ + list_add_tail(&entry->list, &fh->msgs); + + if (fh->queued_msgs < CEC_MAX_MSG_RX_QUEUE_SZ) { + /* All is fine if there is enough room */ + fh->queued_msgs++; + mutex_unlock(&fh->lock); + wake_up_interruptible(&fh->wait); + return; + } - /* - * if the queue now has more than CEC_MAX_MSG_RX_QUEUE_SZ - * messages, drop the oldest one and send a lost message event. - */ - if (fh->queued_msgs == CEC_MAX_MSG_RX_QUEUE_SZ) { + /* + * if the message queue is full, then drop the oldest one and + * send a lost message event. + */ + entry = list_first_entry(&fh->msgs, struct cec_msg_entry, list); list_del(&entry->list); - goto lost_msgs; + kfree(entry); } - fh->queued_msgs++; mutex_unlock(&fh->lock); - wake_up_interruptible(&fh->wait); - return; -lost_msgs: - mutex_unlock(&fh->lock); - cec_queue_event_fh(fh, &ev_lost_msg, 0); + /* + * We lost a message, either because kmalloc failed or the queue + * was full. + */ + cec_queue_event_fh(fh, &ev_lost_msgs, ktime_get_ns()); } /* @@ -394,13 +435,17 @@ int cec_thread_func(void *_adap) if (adap->transmitting && timeout) { /* - * If we timeout, then log that. This really shouldn't - * happen and is an indication of a faulty CEC adapter - * driver, or the CEC bus is in some weird state. + * If we timeout, then log that. Normally this does + * not happen and it is an indication of a faulty CEC + * adapter driver, or the CEC bus is in some weird + * state. On rare occasions it can happen if there is + * so much traffic on the bus that the adapter was + * unable to transmit for CEC_XFER_TIMEOUT_MS (2.1s). */ - dprintk(0, "%s: message %*ph timed out!\n", __func__, + dprintk(1, "%s: message %*ph timed out\n", __func__, adap->transmitting->msg.len, adap->transmitting->msg.msg); + adap->tx_timeouts++; /* Just give up on this. */ cec_data_cancel(adap->transmitting); goto unlock; @@ -467,14 +512,19 @@ unlock: /* * Called by the CEC adapter if a transmit finished. */ -void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt, - u8 nack_cnt, u8 low_drive_cnt, u8 error_cnt) +void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, + u8 arb_lost_cnt, u8 nack_cnt, u8 low_drive_cnt, + u8 error_cnt, ktime_t ts) { struct cec_data *data; struct cec_msg *msg; - u64 ts = ktime_get_ns(); + unsigned int attempts_made = arb_lost_cnt + nack_cnt + + low_drive_cnt + error_cnt; dprintk(2, "%s: status %02x\n", __func__, status); + if (attempts_made < 1) + attempts_made = 1; + mutex_lock(&adap->lock); data = adap->transmitting; if (!data) { @@ -492,7 +542,7 @@ void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt, /* Drivers must fill in the status! */ WARN_ON(status == 0); - msg->tx_ts = ts; + msg->tx_ts = ktime_to_ns(ts); msg->tx_status |= status; msg->tx_arb_lost_cnt += arb_lost_cnt; msg->tx_nack_cnt += nack_cnt; @@ -507,10 +557,10 @@ void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt, * the hardware didn't signal that it retried itself (by setting * CEC_TX_STATUS_MAX_RETRIES), then we will retry ourselves. */ - if (data->attempts > 1 && + if (data->attempts > attempts_made && !(status & (CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_OK))) { /* Retry this message */ - data->attempts--; + data->attempts -= attempts_made; if (msg->timeout) dprintk(2, "retransmit: %*ph (attempts: %d, wait for 0x%02x)\n", msg->len, msg->msg, data->attempts, msg->reply); @@ -555,25 +605,26 @@ wake_thread: unlock: mutex_unlock(&adap->lock); } -EXPORT_SYMBOL_GPL(cec_transmit_done); +EXPORT_SYMBOL_GPL(cec_transmit_done_ts); -void cec_transmit_attempt_done(struct cec_adapter *adap, u8 status) +void cec_transmit_attempt_done_ts(struct cec_adapter *adap, + u8 status, ktime_t ts) { switch (status & ~CEC_TX_STATUS_MAX_RETRIES) { case CEC_TX_STATUS_OK: - cec_transmit_done(adap, status, 0, 0, 0, 0); + cec_transmit_done_ts(adap, status, 0, 0, 0, 0, ts); return; case CEC_TX_STATUS_ARB_LOST: - cec_transmit_done(adap, status, 1, 0, 0, 0); + cec_transmit_done_ts(adap, status, 1, 0, 0, 0, ts); return; case CEC_TX_STATUS_NACK: - cec_transmit_done(adap, status, 0, 1, 0, 0); + cec_transmit_done_ts(adap, status, 0, 1, 0, 0, ts); return; case CEC_TX_STATUS_LOW_DRIVE: - cec_transmit_done(adap, status, 0, 0, 1, 0); + cec_transmit_done_ts(adap, status, 0, 0, 1, 0, ts); return; case CEC_TX_STATUS_ERROR: - cec_transmit_done(adap, status, 0, 0, 0, 1); + cec_transmit_done_ts(adap, status, 0, 0, 0, 1, ts); return; default: /* Should never happen */ @@ -581,7 +632,7 @@ void cec_transmit_attempt_done(struct cec_adapter *adap, u8 status) return; } } -EXPORT_SYMBOL_GPL(cec_transmit_attempt_done); +EXPORT_SYMBOL_GPL(cec_transmit_attempt_done_ts); /* * Called when waiting for a reply times out. @@ -630,9 +681,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, msg->tx_nack_cnt = 0; msg->tx_low_drive_cnt = 0; msg->tx_error_cnt = 0; - msg->sequence = ++adap->sequence; - if (!msg->sequence) - msg->sequence = ++adap->sequence; + msg->sequence = 0; if (msg->reply && msg->timeout == 0) { /* Make sure the timeout isn't 0. */ @@ -671,6 +720,9 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, msg->tx_status = CEC_TX_STATUS_NACK | CEC_TX_STATUS_MAX_RETRIES; msg->tx_nack_cnt = 1; + msg->sequence = ++adap->sequence; + if (!msg->sequence) + msg->sequence = ++adap->sequence; return 0; } } @@ -705,6 +757,10 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, if (!data) return -ENOMEM; + msg->sequence = ++adap->sequence; + if (!msg->sequence) + msg->sequence = ++adap->sequence; + if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { msg->msg[2] = adap->phys_addr >> 8; msg->msg[3] = adap->phys_addr & 0xff; @@ -712,7 +768,8 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, if (msg->timeout) dprintk(2, "%s: %*ph (wait for 0x%02x%s)\n", - __func__, msg->len, msg->msg, msg->reply, !block ? ", nb" : ""); + __func__, msg->len, msg->msg, msg->reply, + !block ? ", nb" : ""); else dprintk(2, "%s: %*ph%s\n", __func__, msg->len, msg->msg, !block ? " (nb)" : ""); @@ -909,7 +966,8 @@ static const u8 cec_msg_size[256] = { }; /* Called by the CEC adapter if a message is received */ -void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) +void cec_received_msg_ts(struct cec_adapter *adap, + struct cec_msg *msg, ktime_t ts) { struct cec_data *data; u8 msg_init = cec_msg_initiator(msg); @@ -937,7 +995,7 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) cec_has_log_addr(adap, msg_init)) return; - msg->rx_ts = ktime_get_ns(); + msg->rx_ts = ktime_to_ns(ts); msg->rx_status = CEC_RX_STATUS_OK; msg->sequence = msg->reply = msg->timeout = 0; msg->tx_status = 0; @@ -1102,7 +1160,7 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) */ cec_receive_notify(adap, msg, is_reply); } -EXPORT_SYMBOL_GPL(cec_received_msg); +EXPORT_SYMBOL_GPL(cec_received_msg_ts); /* Logical Address Handling */ @@ -1390,7 +1448,9 @@ static void cec_claim_log_addrs(struct cec_adapter *adap, bool block) */ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) { - if (phys_addr == adap->phys_addr || adap->devnode.unregistered) + if (phys_addr == adap->phys_addr) + return; + if (phys_addr != CEC_PHYS_ADDR_INVALID && adap->devnode.unregistered) return; dprintk(1, "new physical address %x.%x.%x.%x\n", @@ -1471,8 +1531,13 @@ int __cec_s_log_addrs(struct cec_adapter *adap, return -ENODEV; if (!log_addrs || log_addrs->num_log_addrs == 0) { - adap->log_addrs.num_log_addrs = 0; cec_adap_unconfigure(adap); + adap->log_addrs.num_log_addrs = 0; + for (i = 0; i < CEC_MAX_LOG_ADDRS; i++) + adap->log_addrs.log_addr[i] = CEC_LOG_ADDR_INVALID; + adap->log_addrs.osd_name[0] = '\0'; + adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE; + adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0; return 0; } @@ -1704,6 +1769,9 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, int la_idx = cec_log_addr2idx(adap, dest_laddr); bool from_unregistered = init_laddr == 0xf; struct cec_msg tx_cec_msg = { }; +#ifdef CONFIG_MEDIA_CEC_RC + int scancode; +#endif dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg); @@ -1792,11 +1860,9 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, */ case 0x60: if (msg->len == 2) - rc_keydown(adap->rc, RC_TYPE_CEC, - msg->msg[2], 0); + scancode = msg->msg[2]; else - rc_keydown(adap->rc, RC_TYPE_CEC, - msg->msg[2] << 8 | msg->msg[3], 0); + scancode = msg->msg[2] << 8 | msg->msg[3]; break; /* * Other function messages that are not handled. @@ -1809,11 +1875,54 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, */ case 0x56: case 0x57: case 0x67: case 0x68: case 0x69: case 0x6a: + scancode = -1; break; default: - rc_keydown(adap->rc, RC_TYPE_CEC, msg->msg[2], 0); + scancode = msg->msg[2]; break; } + + /* Was repeating, but keypress timed out */ + if (adap->rc_repeating && !adap->rc->keypressed) { + adap->rc_repeating = false; + adap->rc_last_scancode = -1; + } + /* Different keypress from last time, ends repeat mode */ + if (adap->rc_last_scancode != scancode) { + rc_keyup(adap->rc); + adap->rc_repeating = false; + } + /* We can't handle this scancode */ + if (scancode < 0) { + adap->rc_last_scancode = scancode; + break; + } + + /* Send key press */ + rc_keydown(adap->rc, RC_PROTO_CEC, scancode, 0); + + /* When in repeating mode, we're done */ + if (adap->rc_repeating) + break; + + /* + * We are not repeating, but the new scancode is + * the same as the last one, and this second key press is + * within 550 ms (the 'Follower Safety Timeout') from the + * previous key press, so we now enable the repeating mode. + */ + if (adap->rc_last_scancode == scancode && + msg->rx_ts - adap->rc_last_keypress < 550 * NSEC_PER_MSEC) { + adap->rc_repeating = true; + break; + } + /* + * Not in repeating mode, so avoid triggering repeat mode + * by calling keyup. + */ + rc_keyup(adap->rc); + adap->rc_last_scancode = scancode; + adap->rc_last_keypress = msg->rx_ts; #endif break; @@ -1823,6 +1932,8 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, break; #ifdef CONFIG_MEDIA_CEC_RC rc_keyup(adap->rc); + adap->rc_repeating = false; + adap->rc_last_scancode = -1; #endif break; @@ -1941,6 +2052,11 @@ int cec_adap_status(struct seq_file *file, void *priv) if (adap->monitor_all_cnt) seq_printf(file, "file handles in Monitor All mode: %u\n", adap->monitor_all_cnt); + if (adap->tx_timeouts) { + seq_printf(file, "transmit timeouts: %u\n", + adap->tx_timeouts); + adap->tx_timeouts = 0; + } data = adap->transmitting; if (data) seq_printf(file, "transmitting message: %*ph (reply: %02x, timeout: %ums)\n", diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index f7eb4c54a354..a079f7fe018c 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -30,6 +30,7 @@ #include <linux/uaccess.h> #include <linux/version.h> +#include <media/cec-pin.h> #include "cec-priv.h" static inline struct cec_devnode *cec_devnode_data(struct file *filp) @@ -57,7 +58,7 @@ static unsigned int cec_poll(struct file *filp, res |= POLLOUT | POLLWRNORM; if (fh->queued_msgs) res |= POLLIN | POLLRDNORM; - if (fh->pending_events) + if (fh->total_queued_events) res |= POLLPRI; poll_wait(filp, &fh->wait, poll); mutex_unlock(&adap->lock); @@ -289,15 +290,17 @@ static long cec_receive(struct cec_adapter *adap, struct cec_fh *fh, static long cec_dqevent(struct cec_adapter *adap, struct cec_fh *fh, bool block, struct cec_event __user *parg) { - struct cec_event *ev = NULL; + struct cec_event_entry *ev = NULL; u64 ts = ~0ULL; unsigned int i; + unsigned int ev_idx; long err = 0; mutex_lock(&fh->lock); - while (!fh->pending_events && block) { + while (!fh->total_queued_events && block) { mutex_unlock(&fh->lock); - err = wait_event_interruptible(fh->wait, fh->pending_events); + err = wait_event_interruptible(fh->wait, + fh->total_queued_events); if (err) return err; mutex_lock(&fh->lock); @@ -305,23 +308,29 @@ static long cec_dqevent(struct cec_adapter *adap, struct cec_fh *fh, /* Find the oldest event */ for (i = 0; i < CEC_NUM_EVENTS; i++) { - if (fh->pending_events & (1 << (i + 1)) && - fh->events[i].ts <= ts) { - ev = &fh->events[i]; - ts = ev->ts; + struct cec_event_entry *entry = + list_first_entry_or_null(&fh->events[i], + struct cec_event_entry, list); + + if (entry && entry->ev.ts <= ts) { + ev = entry; + ev_idx = i; + ts = ev->ev.ts; } } + if (!ev) { err = -EAGAIN; goto unlock; } + list_del(&ev->list); - if (copy_to_user(parg, ev, sizeof(*ev))) { + if (copy_to_user(parg, &ev->ev, sizeof(ev->ev))) err = -EFAULT; - goto unlock; - } - - fh->pending_events &= ~(1 << ev->event); + if (ev_idx >= CEC_NUM_CORE_EVENTS) + kfree(ev); + fh->queued_events[ev_idx]--; + fh->total_queued_events--; unlock: mutex_unlock(&fh->lock); @@ -348,33 +357,50 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh, if (copy_from_user(&mode, parg, sizeof(mode))) return -EFAULT; - if (mode & ~(CEC_MODE_INITIATOR_MSK | CEC_MODE_FOLLOWER_MSK)) + if (mode & ~(CEC_MODE_INITIATOR_MSK | CEC_MODE_FOLLOWER_MSK)) { + dprintk(1, "%s: invalid mode bits set\n", __func__); return -EINVAL; + } mode_initiator = mode & CEC_MODE_INITIATOR_MSK; mode_follower = mode & CEC_MODE_FOLLOWER_MSK; if (mode_initiator > CEC_MODE_EXCL_INITIATOR || - mode_follower > CEC_MODE_MONITOR_ALL) + mode_follower > CEC_MODE_MONITOR_ALL) { + dprintk(1, "%s: unknown mode\n", __func__); return -EINVAL; + } if (mode_follower == CEC_MODE_MONITOR_ALL && - !(adap->capabilities & CEC_CAP_MONITOR_ALL)) + !(adap->capabilities & CEC_CAP_MONITOR_ALL)) { + dprintk(1, "%s: MONITOR_ALL not supported\n", __func__); return -EINVAL; + } + + if (mode_follower == CEC_MODE_MONITOR_PIN && + !(adap->capabilities & CEC_CAP_MONITOR_PIN)) { + dprintk(1, "%s: MONITOR_PIN not supported\n", __func__); + return -EINVAL; + } /* Follower modes should always be able to send CEC messages */ if ((mode_initiator == CEC_MODE_NO_INITIATOR || !(adap->capabilities & CEC_CAP_TRANSMIT)) && mode_follower >= CEC_MODE_FOLLOWER && - mode_follower <= CEC_MODE_EXCL_FOLLOWER_PASSTHRU) + mode_follower <= CEC_MODE_EXCL_FOLLOWER_PASSTHRU) { + dprintk(1, "%s: cannot transmit\n", __func__); return -EINVAL; + } /* Monitor modes require CEC_MODE_NO_INITIATOR */ - if (mode_initiator && mode_follower >= CEC_MODE_MONITOR) + if (mode_initiator && mode_follower >= CEC_MODE_MONITOR_PIN) { + dprintk(1, "%s: monitor modes require NO_INITIATOR\n", + __func__); return -EINVAL; + } /* Monitor modes require CAP_NET_ADMIN */ - if (mode_follower >= CEC_MODE_MONITOR && !capable(CAP_NET_ADMIN)) + if (mode_follower >= CEC_MODE_MONITOR_PIN && !capable(CAP_NET_ADMIN)) return -EPERM; mutex_lock(&adap->lock); @@ -413,8 +439,20 @@ static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh, if (fh->mode_follower == CEC_MODE_FOLLOWER) adap->follower_cnt--; + if (fh->mode_follower == CEC_MODE_MONITOR_PIN) + adap->monitor_pin_cnt--; if (mode_follower == CEC_MODE_FOLLOWER) adap->follower_cnt++; + if (mode_follower == CEC_MODE_MONITOR_PIN) { + struct cec_event ev = { + .flags = CEC_EVENT_FL_INITIAL_STATE, + }; + + ev.event = adap->cec_pin_is_high ? CEC_EVENT_PIN_CEC_HIGH : + CEC_EVENT_PIN_CEC_LOW; + cec_queue_event_fh(fh, &ev, 0); + adap->monitor_pin_cnt++; + } if (mode_follower == CEC_MODE_EXCL_FOLLOWER || mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU) { adap->passthrough = @@ -495,6 +533,7 @@ static int cec_open(struct inode *inode, struct file *filp) .event = CEC_EVENT_STATE_CHANGE, .flags = CEC_EVENT_FL_INITIAL_STATE, }; + unsigned int i; int err; if (!fh) @@ -502,6 +541,8 @@ static int cec_open(struct inode *inode, struct file *filp) INIT_LIST_HEAD(&fh->msgs); INIT_LIST_HEAD(&fh->xfer_list); + for (i = 0; i < CEC_NUM_EVENTS; i++) + INIT_LIST_HEAD(&fh->events[i]); mutex_init(&fh->lock); init_waitqueue_head(&fh->wait); @@ -544,6 +585,7 @@ static int cec_release(struct inode *inode, struct file *filp) struct cec_devnode *devnode = cec_devnode_data(filp); struct cec_adapter *adap = to_cec_adapter(devnode); struct cec_fh *fh = filp->private_data; + unsigned int i; mutex_lock(&adap->lock); if (adap->cec_initiator == fh) @@ -554,6 +596,8 @@ static int cec_release(struct inode *inode, struct file *filp) } if (fh->mode_follower == CEC_MODE_FOLLOWER) adap->follower_cnt--; + if (fh->mode_follower == CEC_MODE_MONITOR_PIN) + adap->monitor_pin_cnt--; if (fh->mode_follower == CEC_MODE_MONITOR_ALL) cec_monitor_all_cnt_dec(adap); mutex_unlock(&adap->lock); @@ -585,6 +629,16 @@ static int cec_release(struct inode *inode, struct file *filp) list_del(&entry->list); kfree(entry); } + for (i = CEC_NUM_CORE_EVENTS; i < CEC_NUM_EVENTS; i++) { + while (!list_empty(&fh->events[i])) { + struct cec_event_entry *entry = + list_first_entry(&fh->events[i], + struct cec_event_entry, list); + + list_del(&entry->list); + kfree(entry); + } + } kfree(fh); cec_put_device(devnode); diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index b516d599d6c4..648136e552d5 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -227,6 +227,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, return ERR_PTR(-ENOMEM); strlcpy(adap->name, name, sizeof(adap->name)); adap->phys_addr = CEC_PHYS_ADDR_INVALID; + adap->cec_pin_is_high = true; adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0; adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE; adap->capabilities = caps; @@ -263,22 +264,24 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, return ERR_PTR(-ENOMEM); } - snprintf(adap->input_name, sizeof(adap->input_name), + snprintf(adap->device_name, sizeof(adap->device_name), "RC for %s", name); snprintf(adap->input_phys, sizeof(adap->input_phys), "%s/input0", name); - adap->rc->input_name = adap->input_name; + adap->rc->device_name = adap->device_name; adap->rc->input_phys = adap->input_phys; adap->rc->input_id.bustype = BUS_CEC; adap->rc->input_id.vendor = 0; adap->rc->input_id.product = 0; adap->rc->input_id.version = 1; adap->rc->driver_name = CEC_NAME; - adap->rc->allowed_protocols = RC_BIT_CEC; + adap->rc->allowed_protocols = RC_PROTO_BIT_CEC; + adap->rc->enabled_protocols = RC_PROTO_BIT_CEC; adap->rc->priv = adap; adap->rc->map_name = RC_MAP_CEC; adap->rc->timeout = MS_TO_NS(100); + adap->rc_last_scancode = -1; #endif return adap; } @@ -310,6 +313,17 @@ int cec_register_adapter(struct cec_adapter *adap, adap->rc = NULL; return res; } + /* + * The REP_DELAY for CEC is really the time between the initial + * 'User Control Pressed' message and the second. The first + * keypress is always seen as non-repeating, the second + * (provided it has the same UI Command) will start the 'Press + * and Hold' (aka repeat) behavior. By setting REP_DELAY to the + * same value as REP_PERIOD the expected CEC behavior is + * reproduced. + */ + adap->rc->input_dev->rep[REP_DELAY] = + adap->rc->input_dev->rep[REP_PERIOD]; } #endif @@ -374,6 +388,8 @@ void cec_delete_adapter(struct cec_adapter *adap) kthread_stop(adap->kthread); if (adap->kthread_config) kthread_stop(adap->kthread_config); + if (adap->ops->adap_free) + adap->ops->adap_free(adap); #ifdef CONFIG_MEDIA_CEC_RC rc_free_device(adap->rc); #endif @@ -386,11 +402,8 @@ EXPORT_SYMBOL_GPL(cec_delete_adapter); */ static int __init cec_devnode_init(void) { - int ret; + int ret = alloc_chrdev_region(&cec_dev_t, 0, CEC_NUM_DEVICES, CEC_NAME); - pr_info("Linux cec interface: v0.10\n"); - ret = alloc_chrdev_region(&cec_dev_t, 0, CEC_NUM_DEVICES, - CEC_NAME); if (ret < 0) { pr_warn("cec: unable to allocate major\n"); return ret; diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c new file mode 100644 index 000000000000..c003b8eac617 --- /dev/null +++ b/drivers/media/cec/cec-pin.c @@ -0,0 +1,802 @@ +/* + * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/sched/types.h> + +#include <media/cec-pin.h> + +/* All timings are in microseconds */ + +/* start bit timings */ +#define CEC_TIM_START_BIT_LOW 3700 +#define CEC_TIM_START_BIT_LOW_MIN 3500 +#define CEC_TIM_START_BIT_LOW_MAX 3900 +#define CEC_TIM_START_BIT_TOTAL 4500 +#define CEC_TIM_START_BIT_TOTAL_MIN 4300 +#define CEC_TIM_START_BIT_TOTAL_MAX 4700 + +/* data bit timings */ +#define CEC_TIM_DATA_BIT_0_LOW 1500 +#define CEC_TIM_DATA_BIT_0_LOW_MIN 1300 +#define CEC_TIM_DATA_BIT_0_LOW_MAX 1700 +#define CEC_TIM_DATA_BIT_1_LOW 600 +#define CEC_TIM_DATA_BIT_1_LOW_MIN 400 +#define CEC_TIM_DATA_BIT_1_LOW_MAX 800 +#define CEC_TIM_DATA_BIT_TOTAL 2400 +#define CEC_TIM_DATA_BIT_TOTAL_MIN 2050 +#define CEC_TIM_DATA_BIT_TOTAL_MAX 2750 +/* earliest safe time to sample the bit state */ +#define CEC_TIM_DATA_BIT_SAMPLE 850 +/* earliest time the bit is back to 1 (T7 + 50) */ +#define CEC_TIM_DATA_BIT_HIGH 1750 + +/* when idle, sample once per millisecond */ +#define CEC_TIM_IDLE_SAMPLE 1000 +/* when processing the start bit, sample twice per millisecond */ +#define CEC_TIM_START_BIT_SAMPLE 500 +/* when polling for a state change, sample once every 50 micoseconds */ +#define CEC_TIM_SAMPLE 50 + +#define CEC_TIM_LOW_DRIVE_ERROR (1.5 * CEC_TIM_DATA_BIT_TOTAL) + +struct cec_state { + const char * const name; + unsigned int usecs; +}; + +static const struct cec_state states[CEC_PIN_STATES] = { + { "Off", 0 }, + { "Idle", CEC_TIM_IDLE_SAMPLE }, + { "Tx Wait", CEC_TIM_SAMPLE }, + { "Tx Wait for High", CEC_TIM_IDLE_SAMPLE }, + { "Tx Start Bit Low", CEC_TIM_START_BIT_LOW }, + { "Tx Start Bit High", CEC_TIM_START_BIT_TOTAL - CEC_TIM_START_BIT_LOW }, + { "Tx Data 0 Low", CEC_TIM_DATA_BIT_0_LOW }, + { "Tx Data 0 High", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_0_LOW }, + { "Tx Data 1 Low", CEC_TIM_DATA_BIT_1_LOW }, + { "Tx Data 1 High", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_1_LOW }, + { "Tx Data 1 Pre Sample", CEC_TIM_DATA_BIT_SAMPLE - CEC_TIM_DATA_BIT_1_LOW }, + { "Tx Data 1 Post Sample", CEC_TIM_DATA_BIT_TOTAL - CEC_TIM_DATA_BIT_SAMPLE }, + { "Rx Start Bit Low", CEC_TIM_SAMPLE }, + { "Rx Start Bit High", CEC_TIM_SAMPLE }, + { "Rx Data Sample", CEC_TIM_DATA_BIT_SAMPLE }, + { "Rx Data Post Sample", CEC_TIM_DATA_BIT_HIGH - CEC_TIM_DATA_BIT_SAMPLE }, + { "Rx Data High", CEC_TIM_SAMPLE }, + { "Rx Ack Low", CEC_TIM_DATA_BIT_0_LOW }, + { "Rx Ack Low Post", CEC_TIM_DATA_BIT_HIGH - CEC_TIM_DATA_BIT_0_LOW }, + { "Rx Ack High Post", CEC_TIM_DATA_BIT_HIGH }, + { "Rx Ack Finish", CEC_TIM_DATA_BIT_TOTAL_MIN - CEC_TIM_DATA_BIT_HIGH }, + { "Rx Low Drive", CEC_TIM_LOW_DRIVE_ERROR }, + { "Rx Irq", 0 }, +}; + +static void cec_pin_update(struct cec_pin *pin, bool v, bool force) +{ + if (!force && v == pin->adap->cec_pin_is_high) + return; + + pin->adap->cec_pin_is_high = v; + if (atomic_read(&pin->work_pin_events) < CEC_NUM_PIN_EVENTS) { + pin->work_pin_is_high[pin->work_pin_events_wr] = v; + pin->work_pin_ts[pin->work_pin_events_wr] = ktime_get(); + pin->work_pin_events_wr = + (pin->work_pin_events_wr + 1) % CEC_NUM_PIN_EVENTS; + atomic_inc(&pin->work_pin_events); + } + wake_up_interruptible(&pin->kthread_waitq); +} + +static bool cec_pin_read(struct cec_pin *pin) +{ + bool v = pin->ops->read(pin->adap); + + cec_pin_update(pin, v, false); + return v; +} + +static void cec_pin_low(struct cec_pin *pin) +{ + pin->ops->low(pin->adap); + cec_pin_update(pin, false, false); +} + +static bool cec_pin_high(struct cec_pin *pin) +{ + pin->ops->high(pin->adap); + return cec_pin_read(pin); +} + +static void cec_pin_to_idle(struct cec_pin *pin) +{ + /* + * Reset all status fields, release the bus and + * go to idle state. + */ + pin->rx_bit = pin->tx_bit = 0; + pin->rx_msg.len = 0; + memset(pin->rx_msg.msg, 0, sizeof(pin->rx_msg.msg)); + pin->state = CEC_ST_IDLE; + pin->ts = 0; +} + +/* + * Handle Transmit-related states + * + * Basic state changes when transmitting: + * + * Idle -> Tx Wait (waiting for the end of signal free time) -> + * Tx Start Bit Low -> Tx Start Bit High -> + * + * Regular data bits + EOM: + * Tx Data 0 Low -> Tx Data 0 High -> + * or: + * Tx Data 1 Low -> Tx Data 1 High -> + * + * First 4 data bits or Ack bit: + * Tx Data 0 Low -> Tx Data 0 High -> + * or: + * Tx Data 1 Low -> Tx Data 1 High -> Tx Data 1 Pre Sample -> + * Tx Data 1 Post Sample -> + * + * After the last Ack go to Idle. + * + * If it detects a Low Drive condition then: + * Tx Wait For High -> Idle + * + * If it loses arbitration, then it switches to state Rx Data Post Sample. + */ +static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts) +{ + bool v; + bool is_ack_bit, ack; + + switch (pin->state) { + case CEC_ST_TX_WAIT_FOR_HIGH: + if (cec_pin_read(pin)) + cec_pin_to_idle(pin); + break; + + case CEC_ST_TX_START_BIT_LOW: + pin->state = CEC_ST_TX_START_BIT_HIGH; + /* Generate start bit */ + cec_pin_high(pin); + break; + + case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE: + /* If the read value is 1, then all is OK */ + if (!cec_pin_read(pin)) { + /* + * It's 0, so someone detected an error and pulled the + * line low for 1.5 times the nominal bit period. + */ + pin->tx_msg.len = 0; + pin->work_tx_ts = ts; + pin->work_tx_status = CEC_TX_STATUS_LOW_DRIVE; + pin->state = CEC_ST_TX_WAIT_FOR_HIGH; + wake_up_interruptible(&pin->kthread_waitq); + break; + } + if (pin->tx_nacked) { + cec_pin_to_idle(pin); + pin->tx_msg.len = 0; + pin->work_tx_ts = ts; + pin->work_tx_status = CEC_TX_STATUS_NACK; + wake_up_interruptible(&pin->kthread_waitq); + break; + } + /* fall through */ + case CEC_ST_TX_DATA_BIT_0_HIGH: + case CEC_ST_TX_DATA_BIT_1_HIGH: + pin->tx_bit++; + /* fall through */ + case CEC_ST_TX_START_BIT_HIGH: + if (pin->tx_bit / 10 >= pin->tx_msg.len) { + cec_pin_to_idle(pin); + pin->tx_msg.len = 0; + pin->work_tx_ts = ts; + pin->work_tx_status = CEC_TX_STATUS_OK; + wake_up_interruptible(&pin->kthread_waitq); + break; + } + + switch (pin->tx_bit % 10) { + default: + v = pin->tx_msg.msg[pin->tx_bit / 10] & + (1 << (7 - (pin->tx_bit % 10))); + pin->state = v ? CEC_ST_TX_DATA_BIT_1_LOW : + CEC_ST_TX_DATA_BIT_0_LOW; + break; + case 8: + v = pin->tx_bit / 10 == pin->tx_msg.len - 1; + pin->state = v ? CEC_ST_TX_DATA_BIT_1_LOW : + CEC_ST_TX_DATA_BIT_0_LOW; + break; + case 9: + pin->state = CEC_ST_TX_DATA_BIT_1_LOW; + break; + } + cec_pin_low(pin); + break; + + case CEC_ST_TX_DATA_BIT_0_LOW: + case CEC_ST_TX_DATA_BIT_1_LOW: + v = pin->state == CEC_ST_TX_DATA_BIT_1_LOW; + pin->state = v ? CEC_ST_TX_DATA_BIT_1_HIGH : + CEC_ST_TX_DATA_BIT_0_HIGH; + is_ack_bit = pin->tx_bit % 10 == 9; + if (v && (pin->tx_bit < 4 || is_ack_bit)) + pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE; + cec_pin_high(pin); + break; + + case CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE: + /* Read the CEC value at the sample time */ + v = cec_pin_read(pin); + is_ack_bit = pin->tx_bit % 10 == 9; + /* + * If v == 0 and we're within the first 4 bits + * of the initiator, then someone else started + * transmitting and we lost the arbitration + * (i.e. the logical address of the other + * transmitter has more leading 0 bits in the + * initiator). + */ + if (!v && !is_ack_bit) { + pin->tx_msg.len = 0; + pin->work_tx_ts = ts; + pin->work_tx_status = CEC_TX_STATUS_ARB_LOST; + wake_up_interruptible(&pin->kthread_waitq); + pin->rx_bit = pin->tx_bit; + pin->tx_bit = 0; + memset(pin->rx_msg.msg, 0, sizeof(pin->rx_msg.msg)); + pin->rx_msg.msg[0] = pin->tx_msg.msg[0]; + pin->rx_msg.msg[0] &= ~(1 << (7 - pin->rx_bit)); + pin->rx_msg.len = 0; + pin->state = CEC_ST_RX_DATA_POST_SAMPLE; + pin->rx_bit++; + break; + } + pin->state = CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE; + if (!is_ack_bit) + break; + /* Was the message ACKed? */ + ack = cec_msg_is_broadcast(&pin->tx_msg) ? v : !v; + if (!ack) { + /* + * Note: the CEC spec is ambiguous regarding + * what action to take when a NACK appears + * before the last byte of the payload was + * transmitted: either stop transmitting + * immediately, or wait until the last byte + * was transmitted. + * + * Most CEC implementations appear to stop + * immediately, and that's what we do here + * as well. + */ + pin->tx_nacked = true; + } + break; + + default: + break; + } +} + +/* + * Handle Receive-related states + * + * Basic state changes when receiving: + * + * Rx Start Bit Low -> Rx Start Bit High -> + * Regular data bits + EOM: + * Rx Data Sample -> Rx Data Post Sample -> Rx Data High -> + * Ack bit 0: + * Rx Ack Low -> Rx Ack Low Post -> Rx Data High -> + * Ack bit 1: + * Rx Ack High Post -> Rx Data High -> + * Ack bit 0 && EOM: + * Rx Ack Low -> Rx Ack Low Post -> Rx Ack Finish -> Idle + */ +static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) +{ + s32 delta; + bool v; + bool ack; + bool bcast, for_us; + u8 dest; + + switch (pin->state) { + /* Receive states */ + case CEC_ST_RX_START_BIT_LOW: + v = cec_pin_read(pin); + if (!v) + break; + pin->state = CEC_ST_RX_START_BIT_HIGH; + delta = ktime_us_delta(ts, pin->ts); + pin->ts = ts; + /* Start bit low is too short, go back to idle */ + if (delta < CEC_TIM_START_BIT_LOW_MIN - + CEC_TIM_IDLE_SAMPLE) { + cec_pin_to_idle(pin); + } + break; + + case CEC_ST_RX_START_BIT_HIGH: + v = cec_pin_read(pin); + delta = ktime_us_delta(ts, pin->ts); + if (v && delta > CEC_TIM_START_BIT_TOTAL_MAX - + CEC_TIM_START_BIT_LOW_MIN) { + cec_pin_to_idle(pin); + break; + } + if (v) + break; + pin->state = CEC_ST_RX_DATA_SAMPLE; + pin->ts = ts; + pin->rx_eom = false; + break; + + case CEC_ST_RX_DATA_SAMPLE: + v = cec_pin_read(pin); + pin->state = CEC_ST_RX_DATA_POST_SAMPLE; + switch (pin->rx_bit % 10) { + default: + if (pin->rx_bit / 10 < CEC_MAX_MSG_SIZE) + pin->rx_msg.msg[pin->rx_bit / 10] |= + v << (7 - (pin->rx_bit % 10)); + break; + case 8: + pin->rx_eom = v; + pin->rx_msg.len = pin->rx_bit / 10 + 1; + break; + case 9: + break; + } + pin->rx_bit++; + break; + + case CEC_ST_RX_DATA_POST_SAMPLE: + pin->state = CEC_ST_RX_DATA_HIGH; + break; + + case CEC_ST_RX_DATA_HIGH: + v = cec_pin_read(pin); + delta = ktime_us_delta(ts, pin->ts); + if (v && delta > CEC_TIM_DATA_BIT_TOTAL_MAX) { + cec_pin_to_idle(pin); + break; + } + if (v) + break; + /* + * Go to low drive state when the total bit time is + * too short. + */ + if (delta < CEC_TIM_DATA_BIT_TOTAL_MIN) { + cec_pin_low(pin); + pin->state = CEC_ST_LOW_DRIVE; + break; + } + pin->ts = ts; + if (pin->rx_bit % 10 != 9) { + pin->state = CEC_ST_RX_DATA_SAMPLE; + break; + } + + dest = cec_msg_destination(&pin->rx_msg); + bcast = dest == CEC_LOG_ADDR_BROADCAST; + /* for_us == broadcast or directed to us */ + for_us = bcast || (pin->la_mask & (1 << dest)); + /* ACK bit value */ + ack = bcast ? 1 : !for_us; + + if (ack) { + /* No need to write to the bus, just wait */ + pin->state = CEC_ST_RX_ACK_HIGH_POST; + break; + } + cec_pin_low(pin); + pin->state = CEC_ST_RX_ACK_LOW; + break; + + case CEC_ST_RX_ACK_LOW: + cec_pin_high(pin); + pin->state = CEC_ST_RX_ACK_LOW_POST; + break; + + case CEC_ST_RX_ACK_LOW_POST: + case CEC_ST_RX_ACK_HIGH_POST: + v = cec_pin_read(pin); + if (v && pin->rx_eom) { + pin->work_rx_msg = pin->rx_msg; + pin->work_rx_msg.rx_ts = ts; + wake_up_interruptible(&pin->kthread_waitq); + pin->ts = ts; + pin->state = CEC_ST_RX_ACK_FINISH; + break; + } + pin->rx_bit++; + pin->state = CEC_ST_RX_DATA_HIGH; + break; + + case CEC_ST_RX_ACK_FINISH: + cec_pin_to_idle(pin); + break; + + default: + break; + } +} + +/* + * Main timer function + * + */ +static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) +{ + struct cec_pin *pin = container_of(timer, struct cec_pin, timer); + struct cec_adapter *adap = pin->adap; + ktime_t ts; + s32 delta; + + ts = ktime_get(); + if (pin->timer_ts) { + delta = ktime_us_delta(ts, pin->timer_ts); + pin->timer_cnt++; + if (delta > 100 && pin->state != CEC_ST_IDLE) { + /* Keep track of timer overruns */ + pin->timer_sum_overrun += delta; + pin->timer_100ms_overruns++; + if (delta > 300) + pin->timer_300ms_overruns++; + if (delta > pin->timer_max_overrun) + pin->timer_max_overrun = delta; + } + } + if (adap->monitor_pin_cnt) + cec_pin_read(pin); + + if (pin->wait_usecs) { + /* + * If we are monitoring the pin, then we have to + * sample at regular intervals. + */ + if (pin->wait_usecs > 150) { + pin->wait_usecs -= 100; + pin->timer_ts = ktime_add_us(ts, 100); + hrtimer_forward_now(timer, 100000); + return HRTIMER_RESTART; + } + if (pin->wait_usecs > 100) { + pin->wait_usecs /= 2; + pin->timer_ts = ktime_add_us(ts, pin->wait_usecs); + hrtimer_forward_now(timer, pin->wait_usecs * 1000); + return HRTIMER_RESTART; + } + pin->timer_ts = ktime_add_us(ts, pin->wait_usecs); + hrtimer_forward_now(timer, pin->wait_usecs * 1000); + pin->wait_usecs = 0; + return HRTIMER_RESTART; + } + + switch (pin->state) { + /* Transmit states */ + case CEC_ST_TX_WAIT_FOR_HIGH: + case CEC_ST_TX_START_BIT_LOW: + case CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE: + case CEC_ST_TX_DATA_BIT_0_HIGH: + case CEC_ST_TX_DATA_BIT_1_HIGH: + case CEC_ST_TX_START_BIT_HIGH: + case CEC_ST_TX_DATA_BIT_0_LOW: + case CEC_ST_TX_DATA_BIT_1_LOW: + case CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE: + cec_pin_tx_states(pin, ts); + break; + + /* Receive states */ + case CEC_ST_RX_START_BIT_LOW: + case CEC_ST_RX_START_BIT_HIGH: + case CEC_ST_RX_DATA_SAMPLE: + case CEC_ST_RX_DATA_POST_SAMPLE: + case CEC_ST_RX_DATA_HIGH: + case CEC_ST_RX_ACK_LOW: + case CEC_ST_RX_ACK_LOW_POST: + case CEC_ST_RX_ACK_HIGH_POST: + case CEC_ST_RX_ACK_FINISH: + cec_pin_rx_states(pin, ts); + break; + + case CEC_ST_IDLE: + case CEC_ST_TX_WAIT: + if (!cec_pin_high(pin)) { + /* Start bit, switch to receive state */ + pin->ts = ts; + pin->state = CEC_ST_RX_START_BIT_LOW; + break; + } + if (pin->ts == 0) + pin->ts = ts; + if (pin->tx_msg.len) { + /* + * Check if the bus has been free for long enough + * so we can kick off the pending transmit. + */ + delta = ktime_us_delta(ts, pin->ts); + if (delta / CEC_TIM_DATA_BIT_TOTAL > + pin->tx_signal_free_time) { + pin->tx_nacked = false; + pin->state = CEC_ST_TX_START_BIT_LOW; + /* Generate start bit */ + cec_pin_low(pin); + break; + } + if (delta / CEC_TIM_DATA_BIT_TOTAL > + pin->tx_signal_free_time - 1) + pin->state = CEC_ST_TX_WAIT; + break; + } + if (pin->state != CEC_ST_IDLE || pin->ops->enable_irq == NULL || + pin->enable_irq_failed || adap->is_configuring || + adap->is_configured || adap->monitor_all_cnt) + break; + /* Switch to interrupt mode */ + atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_ENABLE); + pin->state = CEC_ST_RX_IRQ; + wake_up_interruptible(&pin->kthread_waitq); + return HRTIMER_NORESTART; + + case CEC_ST_LOW_DRIVE: + cec_pin_to_idle(pin); + break; + + default: + break; + } + if (!adap->monitor_pin_cnt || states[pin->state].usecs <= 150) { + pin->wait_usecs = 0; + pin->timer_ts = ktime_add_us(ts, states[pin->state].usecs); + hrtimer_forward_now(timer, states[pin->state].usecs * 1000); + return HRTIMER_RESTART; + } + pin->wait_usecs = states[pin->state].usecs - 100; + pin->timer_ts = ktime_add_us(ts, 100); + hrtimer_forward_now(timer, 100000); + return HRTIMER_RESTART; +} + +static int cec_pin_thread_func(void *_adap) +{ + struct cec_adapter *adap = _adap; + struct cec_pin *pin = adap->pin; + + for (;;) { + wait_event_interruptible(pin->kthread_waitq, + kthread_should_stop() || + pin->work_rx_msg.len || + pin->work_tx_status || + atomic_read(&pin->work_irq_change) || + atomic_read(&pin->work_pin_events)); + + if (pin->work_rx_msg.len) { + cec_received_msg_ts(adap, &pin->work_rx_msg, + pin->work_rx_msg.rx_ts); + pin->work_rx_msg.len = 0; + } + if (pin->work_tx_status) { + unsigned int tx_status = pin->work_tx_status; + + pin->work_tx_status = 0; + cec_transmit_attempt_done_ts(adap, tx_status, + pin->work_tx_ts); + } + + while (atomic_read(&pin->work_pin_events)) { + unsigned int idx = pin->work_pin_events_rd; + + cec_queue_pin_cec_event(adap, + pin->work_pin_is_high[idx], + pin->work_pin_ts[idx]); + pin->work_pin_events_rd = (idx + 1) % CEC_NUM_PIN_EVENTS; + atomic_dec(&pin->work_pin_events); + } + + switch (atomic_xchg(&pin->work_irq_change, + CEC_PIN_IRQ_UNCHANGED)) { + case CEC_PIN_IRQ_DISABLE: + pin->ops->disable_irq(adap); + cec_pin_high(pin); + cec_pin_to_idle(pin); + hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL); + break; + case CEC_PIN_IRQ_ENABLE: + pin->enable_irq_failed = !pin->ops->enable_irq(adap); + if (pin->enable_irq_failed) { + cec_pin_to_idle(pin); + hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL); + } + break; + default: + break; + } + + if (kthread_should_stop()) + break; + } + return 0; +} + +static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct cec_pin *pin = adap->pin; + + pin->enabled = enable; + if (enable) { + atomic_set(&pin->work_pin_events, 0); + pin->work_pin_events_rd = pin->work_pin_events_wr = 0; + cec_pin_read(pin); + cec_pin_to_idle(pin); + pin->tx_msg.len = 0; + pin->timer_ts = 0; + atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED); + pin->kthread = kthread_run(cec_pin_thread_func, adap, + "cec-pin"); + if (IS_ERR(pin->kthread)) { + pr_err("cec-pin: kernel_thread() failed\n"); + return PTR_ERR(pin->kthread); + } + hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL); + } else { + if (pin->ops->disable_irq) + pin->ops->disable_irq(adap); + hrtimer_cancel(&pin->timer); + kthread_stop(pin->kthread); + cec_pin_read(pin); + cec_pin_to_idle(pin); + pin->state = CEC_ST_OFF; + } + return 0; +} + +static int cec_pin_adap_log_addr(struct cec_adapter *adap, u8 log_addr) +{ + struct cec_pin *pin = adap->pin; + + if (log_addr == CEC_LOG_ADDR_INVALID) + pin->la_mask = 0; + else + pin->la_mask |= (1 << log_addr); + return 0; +} + +static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct cec_pin *pin = adap->pin; + + pin->tx_signal_free_time = signal_free_time; + pin->tx_msg = *msg; + pin->work_tx_status = 0; + pin->tx_bit = 0; + if (pin->state == CEC_ST_RX_IRQ) { + atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED); + pin->ops->disable_irq(adap); + cec_pin_high(pin); + cec_pin_to_idle(pin); + hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL); + } + return 0; +} + +static void cec_pin_adap_status(struct cec_adapter *adap, + struct seq_file *file) +{ + struct cec_pin *pin = adap->pin; + + seq_printf(file, "state: %s\n", states[pin->state].name); + seq_printf(file, "tx_bit: %d\n", pin->tx_bit); + seq_printf(file, "rx_bit: %d\n", pin->rx_bit); + seq_printf(file, "cec pin: %d\n", pin->ops->read(adap)); + seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed); + if (pin->timer_100ms_overruns) { + seq_printf(file, "timer overruns > 100ms: %u of %u\n", + pin->timer_100ms_overruns, pin->timer_cnt); + seq_printf(file, "timer overruns > 300ms: %u of %u\n", + pin->timer_300ms_overruns, pin->timer_cnt); + seq_printf(file, "max timer overrun: %u usecs\n", + pin->timer_max_overrun); + seq_printf(file, "avg timer overrun: %u usecs\n", + pin->timer_sum_overrun / pin->timer_100ms_overruns); + } + pin->timer_cnt = 0; + pin->timer_100ms_overruns = 0; + pin->timer_300ms_overruns = 0; + pin->timer_max_overrun = 0; + pin->timer_sum_overrun = 0; + if (pin->ops->status) + pin->ops->status(adap, file); +} + +static int cec_pin_adap_monitor_all_enable(struct cec_adapter *adap, + bool enable) +{ + struct cec_pin *pin = adap->pin; + + pin->monitor_all = enable; + return 0; +} + +static void cec_pin_adap_free(struct cec_adapter *adap) +{ + struct cec_pin *pin = adap->pin; + + if (pin->ops->free) + pin->ops->free(adap); + adap->pin = NULL; + kfree(pin); +} + +void cec_pin_changed(struct cec_adapter *adap, bool value) +{ + struct cec_pin *pin = adap->pin; + + cec_pin_update(pin, value, false); + if (!value && (adap->is_configuring || adap->is_configured || + adap->monitor_all_cnt)) + atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_DISABLE); +} +EXPORT_SYMBOL_GPL(cec_pin_changed); + +static const struct cec_adap_ops cec_pin_adap_ops = { + .adap_enable = cec_pin_adap_enable, + .adap_monitor_all_enable = cec_pin_adap_monitor_all_enable, + .adap_log_addr = cec_pin_adap_log_addr, + .adap_transmit = cec_pin_adap_transmit, + .adap_status = cec_pin_adap_status, + .adap_free = cec_pin_adap_free, +}; + +struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops, + void *priv, const char *name, u32 caps) +{ + struct cec_adapter *adap; + struct cec_pin *pin = kzalloc(sizeof(*pin), GFP_KERNEL); + + if (pin == NULL) + return ERR_PTR(-ENOMEM); + pin->ops = pin_ops; + hrtimer_init(&pin->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + pin->timer.function = cec_pin_timer; + init_waitqueue_head(&pin->kthread_waitq); + + adap = cec_allocate_adapter(&cec_pin_adap_ops, priv, name, + caps | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN, + CEC_MAX_LOG_ADDRS); + + if (PTR_ERR_OR_ZERO(adap)) { + kfree(pin); + return adap; + } + + adap->pin = pin; + pin->adap = adap; + cec_pin_update(pin, cec_pin_high(pin), true); + return adap; +} +EXPORT_SYMBOL_GPL(cec_pin_allocate_adapter); diff --git a/drivers/media/common/saa7146/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c index 239a2db35068..75897f95e4b4 100644 --- a/drivers/media/common/saa7146/saa7146_i2c.c +++ b/drivers/media/common/saa7146/saa7146_i2c.c @@ -395,7 +395,7 @@ static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, in /* i2c-adapter helper functions */ /* exported algorithm data */ -static struct i2c_algorithm saa7146_algo = { +static const struct i2c_algorithm saa7146_algo = { .master_xfer = saa7146_i2c_xfer, .functionality = saa7146_i2c_func, }; diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index 3553ac4cba5c..d79e4d7ecd9f 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -308,7 +308,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) saa7146_dma_free(dev,q,buf); } -static struct videobuf_queue_ops vbi_qops = { +static const struct videobuf_queue_ops vbi_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index b3b29d4f36ed..37b4654dc21c 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -1187,7 +1187,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) release_all_pagetables(dev, buf); } -static struct videobuf_queue_ops video_qops = { +static const struct videobuf_queue_ops video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c index 7c898b06d85c..e77bb0c95e69 100644 --- a/drivers/media/common/siano/smsir.c +++ b/drivers/media/common/siano/smsir.c @@ -73,7 +73,7 @@ int sms_ir_init(struct smscore_device_t *coredev) strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys)); strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys)); - dev->input_name = coredev->ir.name; + dev->device_name = coredev->ir.name; dev->input_phys = coredev->ir.phys; dev->dev.parent = coredev->device; @@ -86,12 +86,12 @@ int sms_ir_init(struct smscore_device_t *coredev) #endif dev->priv = coredev; - dev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + dev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; dev->map_name = sms_get_board(board_id)->rc_codes; dev->driver_name = MODULE_NAME; pr_debug("Input device (IR) %s is set for key events\n", - dev->input_name); + dev->device_name); err = rc_register_device(dev); if (err < 0) { diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c index 9bcbd318489b..5b5f95c38fe1 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-colors.c @@ -646,14 +646,14 @@ const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_S [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][5] = { 3248, 944, 1094 }, [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][6] = { 1017, 967, 3168 }, [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][1] = { 3802, 3805, 2602 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][2] = { 0, 3806, 3797 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][3] = { 1780, 3812, 2592 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][4] = { 3820, 2215, 3796 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][5] = { 3824, 2409, 2574 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][6] = { 2491, 2435, 3795 }, - [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][1] = { 1815, 1818, 910 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][2] = { 0, 1819, 1811 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][3] = { 472, 1825, 904 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][4] = { 1832, 686, 1810 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][5] = { 1835, 794, 893 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][6] = { 843, 809, 1810 }, + [V4L2_COLORSPACE_SMPTE170M][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 }, [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][1] = { 2953, 2963, 586 }, [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_709][2] = { 0, 2967, 2937 }, @@ -702,14 +702,14 @@ const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_S [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][5] = { 3248, 944, 1094 }, [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][6] = { 1017, 967, 3168 }, [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][1] = { 3802, 3805, 2602 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][2] = { 0, 3806, 3797 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][3] = { 1780, 3812, 2592 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][4] = { 3820, 2215, 3796 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][5] = { 3824, 2409, 2574 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][6] = { 2491, 2435, 3795 }, - [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][1] = { 1815, 1818, 910 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][2] = { 0, 1819, 1811 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][3] = { 472, 1825, 904 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][4] = { 1832, 686, 1810 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][5] = { 1835, 794, 893 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][6] = { 843, 809, 1810 }, + [V4L2_COLORSPACE_SMPTE240M][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 }, [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 547 }, [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_709][2] = { 547, 2939, 2939 }, @@ -758,14 +758,14 @@ const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_S [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][5] = { 3175, 1084, 1084 }, [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3175 }, [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][1] = { 3798, 3798, 2563 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][2] = { 2563, 3798, 3798 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][3] = { 2563, 3798, 2563 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][4] = { 3798, 2563, 3798 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][5] = { 3798, 2563, 2563 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][6] = { 2563, 2563, 3798 }, - [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][1] = { 1812, 1812, 886 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][2] = { 886, 1812, 1812 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][3] = { 886, 1812, 886 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][4] = { 1812, 886, 1812 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][5] = { 1812, 886, 886 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][6] = { 886, 886, 1812 }, + [V4L2_COLORSPACE_REC709][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 }, [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][1] = { 2892, 3034, 910 }, [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_709][2] = { 1715, 2916, 2914 }, @@ -814,14 +814,14 @@ const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_S [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][5] = { 2765, 1182, 1190 }, [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][6] = { 1270, 0, 3094 }, [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][1] = { 3784, 3825, 2879 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][2] = { 3351, 3791, 3790 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][3] = { 3311, 3819, 2815 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][4] = { 3659, 1900, 3777 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][5] = { 3640, 2662, 2669 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][6] = { 2743, 0, 3769 }, - [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][1] = { 1800, 1836, 1090 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][2] = { 1436, 1806, 1805 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][3] = { 1405, 1830, 1047 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][4] = { 1691, 527, 1793 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][5] = { 1674, 947, 952 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][6] = { 1000, 0, 1786 }, + [V4L2_COLORSPACE_470_SYSTEM_M][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 }, [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 464 }, [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_709][2] = { 786, 2939, 2939 }, @@ -870,14 +870,14 @@ const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_S [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][5] = { 3126, 1084, 1084 }, [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3188 }, [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][1] = { 3798, 3798, 2476 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][2] = { 2782, 3798, 3798 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][3] = { 2782, 3798, 2476 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][4] = { 3780, 2563, 3803 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][5] = { 3780, 2563, 2563 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][6] = { 2563, 2563, 3803 }, - [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][1] = { 1812, 1812, 833 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][2] = { 1025, 1812, 1812 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][3] = { 1025, 1812, 833 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][4] = { 1796, 886, 1816 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][5] = { 1796, 886, 886 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][6] = { 886, 886, 1816 }, + [V4L2_COLORSPACE_470_SYSTEM_BG][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 }, [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 547 }, [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_709][2] = { 547, 2939, 2939 }, @@ -926,14 +926,14 @@ const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_S [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][5] = { 3175, 1084, 1084 }, [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3175 }, [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][1] = { 3798, 3798, 2563 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][2] = { 2563, 3798, 3798 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][3] = { 2563, 3798, 2563 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][4] = { 3798, 2563, 3798 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 3798, 2563, 2563 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 2563, 2563, 3798 }, - [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][1] = { 1812, 1812, 886 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][2] = { 886, 1812, 1812 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][3] = { 886, 1812, 886 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][4] = { 1812, 886, 1812 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 1812, 886, 886 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 886, 886, 1812 }, + [V4L2_COLORSPACE_SRGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 }, [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][1] = { 2939, 2939, 781 }, [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_709][2] = { 1622, 2939, 2939 }, @@ -982,14 +982,14 @@ const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_S [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][5] = { 2816, 1084, 1084 }, [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][6] = { 1084, 1084, 3127 }, [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][1] = { 3798, 3798, 2778 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][2] = { 3306, 3798, 3798 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][3] = { 3306, 3798, 2778 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][4] = { 3661, 2563, 3781 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 3661, 2563, 2563 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 2563, 2563, 3781 }, - [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][1] = { 1812, 1812, 1022 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][2] = { 1402, 1812, 1812 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][3] = { 1402, 1812, 1022 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][4] = { 1692, 886, 1797 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][5] = { 1692, 886, 886 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][6] = { 886, 886, 1797 }, + [V4L2_COLORSPACE_ADOBERGB][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][1] = { 2877, 2923, 1058 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_709][2] = { 1837, 2840, 2916 }, @@ -1038,14 +1038,14 @@ const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_S [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][5] = { 2690, 1431, 1182 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][6] = { 1318, 1153, 3051 }, [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][1] = { 3780, 3793, 2984 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][2] = { 3406, 3768, 3791 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][3] = { 3359, 3763, 2939 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][4] = { 3636, 2916, 3760 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][5] = { 3609, 2880, 2661 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][6] = { 2786, 2633, 3753 }, - [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][1] = { 1796, 1808, 1163 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][2] = { 1480, 1786, 1806 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][3] = { 1443, 1781, 1131 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][4] = { 1670, 1116, 1778 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][5] = { 1648, 1091, 947 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][6] = { 1028, 929, 1772 }, + [V4L2_COLORSPACE_BT2020][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 }, [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][0] = { 2939, 2939, 2939 }, [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][1] = { 2936, 2934, 992 }, [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_709][2] = { 1159, 2890, 2916 }, @@ -1094,14 +1094,14 @@ const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_S [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][5] = { 3018, 1276, 1184 }, [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][6] = { 1100, 1107, 3071 }, [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_DCI_P3][7] = { 1084, 1084, 1084 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][0] = { 3798, 3798, 3798 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][1] = { 3797, 3796, 2938 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][2] = { 3049, 3783, 3791 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][3] = { 3044, 3782, 2887 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][4] = { 3741, 2765, 3768 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][5] = { 3740, 2749, 2663 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][6] = { 2580, 2587, 3760 }, - [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][7] = { 2563, 2563, 2563 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][0] = { 1812, 1812, 1812 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][1] = { 1811, 1810, 1131 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][2] = { 1210, 1799, 1806 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][3] = { 1206, 1798, 1096 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][4] = { 1762, 1014, 1785 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][5] = { 1761, 1004, 948 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][6] = { 896, 901, 1778 }, + [V4L2_COLORSPACE_DCI_P3][V4L2_XFER_FUNC_SMPTE2084][7] = { 886, 886, 886 }, }; #else @@ -1225,6 +1225,12 @@ static double transfer_rgb_to_smpte2084(double v) const double c2 = 32.0 * 2413.0 / 4096.0; const double c3 = 32.0 * 2392.0 / 4096.0; + /* + * The RGB input maps to the luminance range 0-100 cd/m^2, while + * SMPTE-2084 maps values to the luminance range of 0-10000 cd/m^2. + * Hence the factor 100. + */ + v /= 100.0; v = pow(v, m1); return pow((c1 + c2 * v) / (1 + c3 * v), m2); } diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 3dd22da7e17d..a772976cfe26 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -615,7 +615,7 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b, static const int bt2020_full[3][3] = { { COEFF(0.2627, 255), COEFF(0.6780, 255), COEFF(0.0593, 255) }, { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255) }, - { COEFF(0.5, 255), COEFF(-0.4698, 255), COEFF(-0.0402, 255) }, + { COEFF(0.5, 255), COEFF(-0.4598, 255), COEFF(-0.0402, 255) }, }; static const int bt2020c[4] = { COEFF(1.0 / 1.9404, 224), COEFF(1.0 / 1.5816, 224), diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h index f854309ba8a5..c4df6cee48e6 100644 --- a/drivers/media/dvb-core/demux.h +++ b/drivers/media/dvb-core/demux.h @@ -210,7 +210,7 @@ struct dmx_section_feed { * the start of the first undelivered TS packet within a circular buffer. * The @buffer2 buffer parameter is normally NULL, except when the received * TS packets have crossed the last address of the circular buffer and - * ”wrapped” to the beginning of the buffer. In the latter case the @buffer1 + * "wrapped" to the beginning of the buffer. In the latter case the @buffer1 * parameter would contain an address within the circular buffer, while the * @buffer2 parameter would contain the first address of the circular buffer. * The number of bytes delivered with this function (i.e. @buffer1_length + diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 45e91add73ba..18e4230865be 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -562,7 +562,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, { ktime_t timeout = 0; struct dmx_pes_filter_params *para = &filter->params.pes; - dmx_output_t otype; + enum dmx_output otype; int ret; int ts_type; enum dmx_ts_pes ts_pes; @@ -787,7 +787,7 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, return 0; } -static inline void invert_mode(dmx_filter_t *filter) +static inline void invert_mode(struct dmx_filter *filter) { int i; @@ -1025,26 +1025,6 @@ static int dvb_demux_do_ioctl(struct file *file, dmxdev->demux->get_pes_pids(dmxdev->demux, parg); break; -#if 0 - /* Not used upstream and never documented */ - - case DMX_GET_CAPS: - if (!dmxdev->demux->get_caps) { - ret = -EINVAL; - break; - } - ret = dmxdev->demux->get_caps(dmxdev->demux, parg); - break; - - case DMX_SET_SOURCE: - if (!dmxdev->demux->set_source) { - ret = -EINVAL; - break; - } - ret = dmxdev->demux->set_source(dmxdev->demux, parg); - break; -#endif - case DMX_GET_STC: if (!dmxdev->demux->get_stc) { ret = -EINVAL; diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index e200aa6f2d2f..5b6041d462bc 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h @@ -279,6 +279,7 @@ #define USB_PID_TERRATEC_H7 0x10b4 #define USB_PID_TERRATEC_H7_2 0x10a3 #define USB_PID_TERRATEC_H7_3 0x10a5 +#define USB_PID_TERRATEC_T1 0x10ae #define USB_PID_TERRATEC_T3 0x10a0 #define USB_PID_TERRATEC_T5 0x10a1 #define USB_PID_NOXON_DAB_STICK 0x00b3 diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index 17970cdd55fa..95b3723282f4 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -76,8 +76,6 @@ MODULE_PARM_DESC(cam_debug, "enable verbose debug messages"); #define STATUSREG_WE 2 /* write error */ #define STATUSREG_FR 0x40 /* module free */ #define STATUSREG_DA 0x80 /* data available */ -#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE) /* general transfer error */ - #define DVB_CA_SLOTSTATE_NONE 0 #define DVB_CA_SLOTSTATE_UNINITIALISED 1 @@ -88,10 +86,8 @@ MODULE_PARM_DESC(cam_debug, "enable verbose debug messages"); #define DVB_CA_SLOTSTATE_WAITFR 6 #define DVB_CA_SLOTSTATE_LINKINIT 7 - /* Information on a CA slot */ struct dvb_ca_slot { - /* current state of the CAM */ int slot_state; @@ -157,7 +153,10 @@ struct dvb_ca_private { /* Delay the main thread should use */ unsigned long delay; - /* Slot to start looking for data to read from in the next user-space read operation */ + /* + * Slot to start looking for data to read from in the next user-space + * read operation + */ int next_read_slot; /* mutex serializing ioctls */ @@ -178,7 +177,9 @@ static void dvb_ca_private_free(struct dvb_ca_private *ca) static void dvb_ca_private_release(struct kref *ref) { - struct dvb_ca_private *ca = container_of(ref, struct dvb_ca_private, refcount); + struct dvb_ca_private *ca; + + ca = container_of(ref, struct dvb_ca_private, refcount); dvb_ca_private_free(ca); } @@ -198,7 +199,6 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 *ebuf, int ecount); - /** * Safely find needle in haystack. * @@ -223,25 +223,22 @@ static char *findstr(char *haystack, int hlen, char *needle, int nlen) return NULL; } - - -/* ******************************************************************************** */ +/* ************************************************************************** */ /* EN50221 physical interface functions */ - /** * dvb_ca_en50221_check_camstatus - Check CAM status. */ static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot) { + struct dvb_ca_slot *sl = &ca->slot_info[slot]; int slot_status; int cam_present_now; int cam_changed; /* IRQ mode */ - if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) { - return (atomic_read(&ca->slot_info[slot].camchange_count) != 0); - } + if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) + return (atomic_read(&sl->camchange_count) != 0); /* poll mode */ slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open); @@ -249,29 +246,28 @@ static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot) cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0; cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0; if (!cam_changed) { - int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE); + int cam_present_old = (sl->slot_state != DVB_CA_SLOTSTATE_NONE); + cam_changed = (cam_present_now != cam_present_old); } if (cam_changed) { - if (!cam_present_now) { - ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; - } else { - ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED; - } - atomic_set(&ca->slot_info[slot].camchange_count, 1); + if (!cam_present_now) + sl->camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; + else + sl->camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED; + atomic_set(&sl->camchange_count, 1); } else { - if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) && + if ((sl->slot_state == DVB_CA_SLOTSTATE_WAITREADY) && (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) { - // move to validate state if reset is completed - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE; + /* move to validate state if reset is completed */ + sl->slot_state = DVB_CA_SLOTSTATE_VALIDATE; } } return cam_changed; } - /** * dvb_ca_en50221_wait_if_status - Wait for flags to become set on the STATUS * register on a CAM interface, checking for errors and timeout. @@ -295,8 +291,10 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, start = jiffies; timeout = jiffies + timeout_hz; while (1) { + int res; + /* read the status and check for error */ - int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); + res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); if (res < 0) return -EIO; @@ -308,12 +306,11 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, } /* check for timeout */ - if (time_after(jiffies, timeout)) { + if (time_after(jiffies, timeout)) break; - } /* wait for a bit */ - msleep(1); + usleep_range(1000, 1100); } dprintk("%s failed timeout:%lu\n", __func__, jiffies - start); @@ -322,7 +319,6 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, return -ETIMEDOUT; } - /** * dvb_ca_en50221_link_init - Initialise the link layer connection to a CAM. * @@ -333,6 +329,7 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, */ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) { + struct dvb_ca_slot *sl = &ca->slot_info[slot]; int ret; int buf_size; u8 buf[2]; @@ -340,40 +337,54 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) dprintk("%s\n", __func__); /* we'll be determining these during this function */ - ca->slot_info[slot].da_irq_supported = 0; + sl->da_irq_supported = 0; - /* set the host link buffer size temporarily. it will be overwritten with the - * real negotiated size later. */ - ca->slot_info[slot].link_buf_size = 2; + /* + * set the host link buffer size temporarily. it will be overwritten + * with the real negotiated size later. + */ + sl->link_buf_size = 2; /* read the buffer size from the CAM */ - if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0) + ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, + IRQEN | CMDREG_SR); + if (ret) return ret; ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ); - if (ret != 0) + if (ret) return ret; - if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2) + ret = dvb_ca_en50221_read_data(ca, slot, buf, 2); + if (ret != 2) return -EIO; - if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) + ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); + if (ret) return ret; - /* store it, and choose the minimum of our buffer and the CAM's buffer size */ + /* + * store it, and choose the minimum of our buffer and the CAM's buffer + * size + */ buf_size = (buf[0] << 8) | buf[1]; if (buf_size > HOST_LINK_BUF_SIZE) buf_size = HOST_LINK_BUF_SIZE; - ca->slot_info[slot].link_buf_size = buf_size; + sl->link_buf_size = buf_size; buf[0] = buf_size >> 8; buf[1] = buf_size & 0xff; dprintk("Chosen link buffer size of %i\n", buf_size); /* write the buffer size to the CAM */ - if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0) + ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, + IRQEN | CMDREG_SW); + if (ret) return ret; - if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0) + ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10); + if (ret) return ret; - if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2) + ret = dvb_ca_en50221_write_data(ca, slot, buf, 2); + if (ret != 2) return -EIO; - if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) + ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); + if (ret) return ret; /* success */ @@ -393,47 +404,50 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) * @return 0 on success, nonzero on error. */ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot, - int *address, int *tupleType, - int *tupleLength, u8 *tuple) + int *address, int *tuple_type, + int *tuple_length, u8 *tuple) { int i; - int _tupleType; - int _tupleLength; + int _tuple_type; + int _tuple_length; int _address = *address; /* grab the next tuple length and type */ - if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0) - return _tupleType; - if (_tupleType == 0xff) { - dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType); + _tuple_type = ca->pub->read_attribute_mem(ca->pub, slot, _address); + if (_tuple_type < 0) + return _tuple_type; + if (_tuple_type == 0xff) { + dprintk("END OF CHAIN TUPLE type:0x%x\n", _tuple_type); *address += 2; - *tupleType = _tupleType; - *tupleLength = 0; + *tuple_type = _tuple_type; + *tuple_length = 0; return 0; } - if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0) - return _tupleLength; + _tuple_length = ca->pub->read_attribute_mem(ca->pub, slot, + _address + 2); + if (_tuple_length < 0) + return _tuple_length; _address += 4; - dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength); + dprintk("TUPLE type:0x%x length:%i\n", _tuple_type, _tuple_length); /* read in the whole tuple */ - for (i = 0; i < _tupleLength; i++) { - tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i * 2)); + for (i = 0; i < _tuple_length; i++) { + tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, + _address + (i * 2)); dprintk(" 0x%02x: 0x%02x %c\n", i, tuple[i] & 0xff, ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.'); } - _address += (_tupleLength * 2); + _address += (_tuple_length * 2); - // success - *tupleType = _tupleType; - *tupleLength = _tupleLength; + /* success */ + *tuple_type = _tuple_type; + *tuple_length = _tuple_length; *address = _address; return 0; } - /** * dvb_ca_en50221_parse_attributes - Parse attribute memory of a CAM module, * extracting Config register, and checking it is a DVB CAM module. @@ -445,9 +459,10 @@ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot, */ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) { + struct dvb_ca_slot *sl; int address = 0; - int tupleLength; - int tupleType; + int tuple_length; + int tuple_type; u8 tuple[257]; char *dvb_str; int rasz; @@ -458,70 +473,66 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) u16 manfid = 0; u16 devid = 0; - - // CISTPL_DEVICE_0A - if ((status = - dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) + /* CISTPL_DEVICE_0A */ + status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tuple_type, + &tuple_length, tuple); + if (status < 0) return status; - if (tupleType != 0x1D) + if (tuple_type != 0x1D) return -EINVAL; - - - // CISTPL_DEVICE_0C - if ((status = - dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) + /* CISTPL_DEVICE_0C */ + status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tuple_type, + &tuple_length, tuple); + if (status < 0) return status; - if (tupleType != 0x1C) + if (tuple_type != 0x1C) return -EINVAL; - - - // CISTPL_VERS_1 - if ((status = - dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) + /* CISTPL_VERS_1 */ + status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tuple_type, + &tuple_length, tuple); + if (status < 0) return status; - if (tupleType != 0x15) + if (tuple_type != 0x15) return -EINVAL; - - - // CISTPL_MANFID - if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, - &tupleLength, tuple)) < 0) + /* CISTPL_MANFID */ + status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tuple_type, + &tuple_length, tuple); + if (status < 0) return status; - if (tupleType != 0x20) + if (tuple_type != 0x20) return -EINVAL; - if (tupleLength != 4) + if (tuple_length != 4) return -EINVAL; manfid = (tuple[1] << 8) | tuple[0]; devid = (tuple[3] << 8) | tuple[2]; - - - // CISTPL_CONFIG - if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, - &tupleLength, tuple)) < 0) + /* CISTPL_CONFIG */ + status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tuple_type, + &tuple_length, tuple); + if (status < 0) return status; - if (tupleType != 0x1A) + if (tuple_type != 0x1A) return -EINVAL; - if (tupleLength < 3) + if (tuple_length < 3) return -EINVAL; /* extract the configbase */ rasz = tuple[0] & 3; - if (tupleLength < (3 + rasz + 14)) + if (tuple_length < (3 + rasz + 14)) return -EINVAL; - ca->slot_info[slot].config_base = 0; - for (i = 0; i < rasz + 1; i++) { - ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i)); - } + sl = &ca->slot_info[slot]; + sl->config_base = 0; + for (i = 0; i < rasz + 1; i++) + sl->config_base |= (tuple[2 + i] << (8 * i)); /* check it contains the correct DVB string */ - dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8); - if (dvb_str == NULL) + dvb_str = findstr((char *)tuple, tuple_length, "DVB_CI_V", 8); + if (!dvb_str) return -EINVAL; - if (tupleLength < ((dvb_str - (char *) tuple) + 12)) + if (tuple_length < ((dvb_str - (char *)tuple) + 12)) return -EINVAL; /* is it a version we support? */ @@ -534,12 +545,14 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) /* process the CFTABLE_ENTRY tuples, and any after those */ while ((!end_chain) && (address < 0x1000)) { - if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, - &tupleLength, tuple)) < 0) + status = dvb_ca_en50221_read_tuple(ca, slot, &address, + &tuple_type, &tuple_length, + tuple); + if (status < 0) return status; - switch (tupleType) { - case 0x1B: // CISTPL_CFTABLE_ENTRY - if (tupleLength < (2 + 11 + 17)) + switch (tuple_type) { + case 0x1B: /* CISTPL_CFTABLE_ENTRY */ + if (tuple_length < (2 + 11 + 17)) break; /* if we've already parsed one, just use it */ @@ -547,26 +560,28 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) break; /* get the config option */ - ca->slot_info[slot].config_option = tuple[0] & 0x3f; + sl->config_option = tuple[0] & 0x3f; /* OK, check it contains the correct strings */ - if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) || - (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL)) + if (!findstr((char *)tuple, tuple_length, + "DVB_HOST", 8) || + !findstr((char *)tuple, tuple_length, + "DVB_CI_MODULE", 13)) break; got_cftableentry = 1; break; - case 0x14: // CISTPL_NO_LINK + case 0x14: /* CISTPL_NO_LINK */ break; - case 0xFF: // CISTPL_END + case 0xFF: /* CISTPL_END */ end_chain = 1; break; - default: /* Unknown tuple type - just skip this tuple and move to the next one */ + default: /* Unknown tuple type - just skip this tuple */ dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", - tupleType, tupleLength); + tuple_type, tuple_length); break; } } @@ -575,14 +590,12 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) return -EINVAL; dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n", - manfid, devid, ca->slot_info[slot].config_base, - ca->slot_info[slot].config_option); + manfid, devid, sl->config_base, sl->config_option); - // success! + /* success! */ return 0; } - /** * dvb_ca_en50221_set_configoption - Set CAM's configoption correctly. * @@ -591,26 +604,25 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) */ static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot) { + struct dvb_ca_slot *sl = &ca->slot_info[slot]; int configoption; dprintk("%s\n", __func__); /* set the config option */ - ca->pub->write_attribute_mem(ca->pub, slot, - ca->slot_info[slot].config_base, - ca->slot_info[slot].config_option); + ca->pub->write_attribute_mem(ca->pub, slot, sl->config_base, + sl->config_option); /* check it */ - configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base); + configoption = ca->pub->read_attribute_mem(ca->pub, slot, + sl->config_base); dprintk("Set configoption 0x%x, read configoption 0x%x\n", - ca->slot_info[slot].config_option, configoption & 0x3f); + sl->config_option, configoption & 0x3f); /* fine! */ return 0; - } - /** * dvb_ca_en50221_read_data - This function talks to an EN50221 CAM control * interface. It reads a buffer of data from the CAM. The data can either @@ -628,6 +640,7 @@ static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot) static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 *ebuf, int ecount) { + struct dvb_ca_slot *sl = &ca->slot_info[slot]; int bytes_read; int status; u8 buf[HOST_LINK_BUF_SIZE]; @@ -636,16 +649,16 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, dprintk("%s\n", __func__); /* check if we have space for a link buf in the rx_buffer */ - if (ebuf == NULL) { + if (!ebuf) { int buf_free; - if (ca->slot_info[slot].rx_buffer.data == NULL) { + if (!sl->rx_buffer.data) { status = -EIO; goto exit; } - buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer); + buf_free = dvb_ringbuffer_free(&sl->rx_buffer); - if (buf_free < (ca->slot_info[slot].link_buf_size + + if (buf_free < (sl->link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) { status = -EAGAIN; goto exit; @@ -653,8 +666,8 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, } if (ca->pub->read_data && - (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_LINKINIT)) { - if (ebuf == NULL) + (sl->slot_state != DVB_CA_SLOTSTATE_LINKINIT)) { + if (!ebuf) status = ca->pub->read_data(ca->pub, slot, buf, sizeof(buf)); else @@ -665,7 +678,6 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, if (status == 0) goto exit; } else { - /* check if there is data available */ status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); @@ -690,21 +702,19 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, bytes_read |= status; /* check it will fit */ - if (ebuf == NULL) { - if (bytes_read > ca->slot_info[slot].link_buf_size) { + if (!ebuf) { + if (bytes_read > sl->link_buf_size) { pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n", ca->dvbdev->adapter->num, bytes_read, - ca->slot_info[slot].link_buf_size); - ca->slot_info[slot].slot_state = - DVB_CA_SLOTSTATE_LINKINIT; + sl->link_buf_size); + sl->slot_state = DVB_CA_SLOTSTATE_LINKINIT; status = -EIO; goto exit; } if (bytes_read < 2) { pr_err("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n", ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = - DVB_CA_SLOTSTATE_LINKINIT; + sl->slot_state = DVB_CA_SLOTSTATE_LINKINIT; status = -EIO; goto exit; } @@ -735,20 +745,22 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, if (status < 0) goto exit; if (status & STATUSREG_RE) { - ca->slot_info[slot].slot_state = - DVB_CA_SLOTSTATE_LINKINIT; + sl->slot_state = DVB_CA_SLOTSTATE_LINKINIT; status = -EIO; goto exit; } } - /* OK, add it to the receive buffer, or copy into external buffer if supplied */ - if (ebuf == NULL) { - if (ca->slot_info[slot].rx_buffer.data == NULL) { + /* + * OK, add it to the receive buffer, or copy into external buffer if + * supplied + */ + if (!ebuf) { + if (!sl->rx_buffer.data) { status = -EIO; goto exit; } - dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); + dvb_ringbuffer_pkt_write(&sl->rx_buffer, buf, bytes_read); } else { memcpy(ebuf, buf, bytes_read); } @@ -757,16 +769,15 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, buf[0], (buf[1] & 0x80) == 0, bytes_read); /* wake up readers when a last_fragment is received */ - if ((buf[1] & 0x80) == 0x00) { + if ((buf[1] & 0x80) == 0x00) wake_up_interruptible(&ca->wait_queue); - } + status = bytes_read; exit: return status; } - /** * dvb_ca_en50221_write_data - This function talks to an EN50221 CAM control * interface. It writes a buffer of data to a CAM. @@ -782,25 +793,28 @@ exit: static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 *buf, int bytes_write) { + struct dvb_ca_slot *sl = &ca->slot_info[slot]; int status; int i; dprintk("%s\n", __func__); - /* sanity check */ - if (bytes_write > ca->slot_info[slot].link_buf_size) + if (bytes_write > sl->link_buf_size) return -EINVAL; if (ca->pub->write_data && - (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_LINKINIT)) + (sl->slot_state != DVB_CA_SLOTSTATE_LINKINIT)) return ca->pub->write_data(ca->pub, slot, buf, bytes_write); - /* it is possible we are dealing with a single buffer implementation, - thus if there is data available for read or if there is even a read - already in progress, we do nothing but awake the kernel thread to - process the data if necessary. */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + /* + * it is possible we are dealing with a single buffer implementation, + * thus if there is data available for read or if there is even a read + * already in progress, we do nothing but awake the kernel thread to + * process the data if necessary. + */ + status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); + if (status < 0) goto exitnowrite; if (status & (STATUSREG_DA | STATUSREG_RE)) { if (status & STATUSREG_DA) @@ -811,12 +825,14 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, } /* OK, set HC bit */ - if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, - IRQEN | CMDREG_HC)) != 0) + status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, + IRQEN | CMDREG_HC); + if (status) goto exit; /* check if interface is still free */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); + if (status < 0) goto exit; if (!(status & STATUSREG_FR)) { /* it wasn't free => try again later */ @@ -848,23 +864,29 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, } /* send the amount of data */ - if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) + status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, + bytes_write >> 8); + if (status) goto exit; - if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW, - bytes_write & 0xff)) != 0) + status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW, + bytes_write & 0xff); + if (status) goto exit; /* send the buffer */ for (i = 0; i < bytes_write; i++) { - if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0) + status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, + buf[i]); + if (status) goto exit; } /* check for write error (WE should now be 0) */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); + if (status < 0) goto exit; if (status & STATUSREG_WE) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; + sl->slot_state = DVB_CA_SLOTSTATE_LINKINIT; status = -EIO; goto exit; } @@ -880,12 +902,9 @@ exitnowrite: return status; } - - -/* ******************************************************************************** */ +/* ************************************************************************** */ /* EN50221 higher level functions */ - /** * dvb_ca_en50221_slot_shutdown - A CAM has been removed => shut it down. * @@ -899,8 +918,10 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot) ca->pub->slot_shutdown(ca->pub, slot); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; - /* need to wake up all processes to check if they're now - trying to write to a defunct CAM */ + /* + * need to wake up all processes to check if they're now trying to + * write to a defunct CAM + */ wake_up_interruptible(&ca->wait_queue); dprintk("Slot %i shutdown\n", slot); @@ -909,7 +930,6 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot) return 0; } - /** * dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred. * @@ -917,9 +937,11 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot) * @slot: Slot concerned. * @change_type: One of the DVB_CA_CAMCHANGE_* values. */ -void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type) +void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, + int change_type) { struct dvb_ca_private *ca = pubca->private; + struct dvb_ca_slot *sl = &ca->slot_info[slot]; dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type); @@ -932,13 +954,12 @@ void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int ch return; } - ca->slot_info[slot].camchange_type = change_type; - atomic_inc(&ca->slot_info[slot].camchange_count); + sl->camchange_type = change_type; + atomic_inc(&sl->camchange_count); dvb_ca_en50221_thread_wakeup(ca); } EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq); - /** * dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred. * @@ -948,17 +969,17 @@ EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq); void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot) { struct dvb_ca_private *ca = pubca->private; + struct dvb_ca_slot *sl = &ca->slot_info[slot]; dprintk("CAMREADY IRQ slot:%i\n", slot); - if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE; + if (sl->slot_state == DVB_CA_SLOTSTATE_WAITREADY) { + sl->slot_state = DVB_CA_SLOTSTATE_VALIDATE; dvb_ca_en50221_thread_wakeup(ca); } } EXPORT_SYMBOL(dvb_ca_en50221_camready_irq); - /** * dvb_ca_en50221_frda_irq - An FR or DA IRQ has occurred. * @@ -968,16 +989,17 @@ EXPORT_SYMBOL(dvb_ca_en50221_camready_irq); void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) { struct dvb_ca_private *ca = pubca->private; + struct dvb_ca_slot *sl = &ca->slot_info[slot]; int flags; dprintk("FR/DA IRQ slot:%i\n", slot); - switch (ca->slot_info[slot].slot_state) { + switch (sl->slot_state) { case DVB_CA_SLOTSTATE_LINKINIT: flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS); if (flags & STATUSREG_DA) { dprintk("CAM supports DA IRQ\n"); - ca->slot_info[slot].da_irq_supported = 1; + sl->da_irq_supported = 1; } break; @@ -989,8 +1011,7 @@ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) } EXPORT_SYMBOL(dvb_ca_en50221_frda_irq); - -/* ******************************************************************************** */ +/* ************************************************************************** */ /* EN50221 thread functions */ /** @@ -1000,7 +1021,6 @@ EXPORT_SYMBOL(dvb_ca_en50221_frda_irq); */ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca) { - dprintk("%s\n", __func__); ca->wakeup = 1; @@ -1019,11 +1039,14 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) int curdelay = 100000000; int slot; - /* Beware of too high polling frequency, because one polling + /* + * Beware of too high polling frequency, because one polling * call might take several hundred milliseconds until timeout! */ for (slot = 0; slot < ca->slot_count; slot++) { - switch (ca->slot_info[slot].slot_state) { + struct dvb_ca_slot *sl = &ca->slot_info[slot]; + + switch (sl->slot_state) { default: case DVB_CA_SLOTSTATE_NONE: delay = HZ * 60; /* 60s */ @@ -1049,7 +1072,7 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) delay = HZ / 10; /* 100ms */ if (ca->open) { - if ((!ca->slot_info[slot].da_irq_supported) || + if ((!sl->da_irq_supported) || (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) delay = HZ / 10; /* 100ms */ } @@ -1063,215 +1086,250 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) ca->delay = curdelay; } +/** + * Poll if the CAM is gone. + * + * @ca: CA instance. + * @slot: Slot to process. + * @return: 0 .. no change + * 1 .. CAM state changed + */ +static int dvb_ca_en50221_poll_cam_gone(struct dvb_ca_private *ca, int slot) +{ + int changed = 0; + int status; + + /* + * we need this extra check for annoying interfaces like the + * budget-av + */ + if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && + (ca->pub->poll_slot_status)) { + status = ca->pub->poll_slot_status(ca->pub, slot, 0); + if (!(status & + DVB_CA_EN50221_POLL_CAM_PRESENT)) { + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; + dvb_ca_en50221_thread_update_delay(ca); + changed = 1; + } + } + return changed; +} /** - * Kernel thread which monitors CA slots for CAM changes, and performs data transfers. + * Thread state machine for one CA slot to perform the data transfer. + * + * @ca: CA instance. + * @slot: Slot to process. */ -static int dvb_ca_en50221_thread(void *data) +static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca, + int slot) { - struct dvb_ca_private *ca = data; - int slot; + struct dvb_ca_slot *sl = &ca->slot_info[slot]; int flags; - int status; int pktcount; void *rxbuf; - dprintk("%s\n", __func__); + mutex_lock(&sl->slot_lock); - /* choose the correct initial delay */ - dvb_ca_en50221_thread_update_delay(ca); + /* check the cam status + deal with CAMCHANGEs */ + while (dvb_ca_en50221_check_camstatus(ca, slot)) { + /* clear down an old CI slot if necessary */ + if (sl->slot_state != DVB_CA_SLOTSTATE_NONE) + dvb_ca_en50221_slot_shutdown(ca, slot); - /* main loop */ - while (!kthread_should_stop()) { - /* sleep for a bit */ - if (!ca->wakeup) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(ca->delay); - if (kthread_should_stop()) - return 0; + /* if a CAM is NOW present, initialise it */ + if (sl->camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) + sl->slot_state = DVB_CA_SLOTSTATE_UNINITIALISED; + + /* we've handled one CAMCHANGE */ + dvb_ca_en50221_thread_update_delay(ca); + atomic_dec(&sl->camchange_count); + } + + /* CAM state machine */ + switch (sl->slot_state) { + case DVB_CA_SLOTSTATE_NONE: + case DVB_CA_SLOTSTATE_INVALID: + /* no action needed */ + break; + + case DVB_CA_SLOTSTATE_UNINITIALISED: + sl->slot_state = DVB_CA_SLOTSTATE_WAITREADY; + ca->pub->slot_reset(ca->pub, slot); + sl->timeout = jiffies + (INIT_TIMEOUT_SECS * HZ); + break; + + case DVB_CA_SLOTSTATE_WAITREADY: + if (time_after(jiffies, sl->timeout)) { + pr_err("dvb_ca adaptor %d: PC card did not respond :(\n", + ca->dvbdev->adapter->num); + sl->slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; } - ca->wakeup = 0; + /* + * no other action needed; will automatically change state when + * ready + */ + break; - /* go through all the slots processing them */ - for (slot = 0; slot < ca->slot_count; slot++) { + case DVB_CA_SLOTSTATE_VALIDATE: + if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) { + if (dvb_ca_en50221_poll_cam_gone(ca, slot)) + break; - mutex_lock(&ca->slot_info[slot].slot_lock); + pr_err("dvb_ca adapter %d: Invalid PC card inserted :(\n", + ca->dvbdev->adapter->num); + sl->slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + if (dvb_ca_en50221_set_configoption(ca, slot) != 0) { + pr_err("dvb_ca adapter %d: Unable to initialise CAM :(\n", + ca->dvbdev->adapter->num); + sl->slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + if (ca->pub->write_cam_control(ca->pub, slot, + CTRLIF_COMMAND, + CMDREG_RS) != 0) { + pr_err("dvb_ca adapter %d: Unable to reset CAM IF\n", + ca->dvbdev->adapter->num); + sl->slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + dprintk("DVB CAM validated successfully\n"); - // check the cam status + deal with CAMCHANGEs - while (dvb_ca_en50221_check_camstatus(ca, slot)) { - /* clear down an old CI slot if necessary */ - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) - dvb_ca_en50221_slot_shutdown(ca, slot); + sl->timeout = jiffies + (INIT_TIMEOUT_SECS * HZ); + sl->slot_state = DVB_CA_SLOTSTATE_WAITFR; + ca->wakeup = 1; + break; - /* if a CAM is NOW present, initialise it */ - if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED; - } + case DVB_CA_SLOTSTATE_WAITFR: + if (time_after(jiffies, sl->timeout)) { + pr_err("dvb_ca adapter %d: DVB CAM did not respond :(\n", + ca->dvbdev->adapter->num); + sl->slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } - /* we've handled one CAMCHANGE */ - dvb_ca_en50221_thread_update_delay(ca); - atomic_dec(&ca->slot_info[slot].camchange_count); - } + flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); + if (flags & STATUSREG_FR) { + sl->slot_state = DVB_CA_SLOTSTATE_LINKINIT; + ca->wakeup = 1; + } + break; - // CAM state machine - switch (ca->slot_info[slot].slot_state) { - case DVB_CA_SLOTSTATE_NONE: - case DVB_CA_SLOTSTATE_INVALID: - // no action needed + case DVB_CA_SLOTSTATE_LINKINIT: + if (dvb_ca_en50221_link_init(ca, slot) != 0) { + if (dvb_ca_en50221_poll_cam_gone(ca, slot)) break; - case DVB_CA_SLOTSTATE_UNINITIALISED: - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY; - ca->pub->slot_reset(ca->pub, slot); - ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ); - break; + pr_err("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", + ca->dvbdev->adapter->num); + sl->slot_state = DVB_CA_SLOTSTATE_UNINITIALISED; + dvb_ca_en50221_thread_update_delay(ca); + break; + } - case DVB_CA_SLOTSTATE_WAITREADY: - if (time_after(jiffies, ca->slot_info[slot].timeout)) { - pr_err("dvb_ca adaptor %d: PC card did not respond :(\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - // no other action needed; will automatically change state when ready + if (!sl->rx_buffer.data) { + rxbuf = vmalloc(RX_BUFFER_SIZE); + if (!rxbuf) { + pr_err("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", + ca->dvbdev->adapter->num); + sl->slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); break; + } + dvb_ringbuffer_init(&sl->rx_buffer, rxbuf, + RX_BUFFER_SIZE); + } - case DVB_CA_SLOTSTATE_VALIDATE: - if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) { - /* we need this extra check for annoying interfaces like the budget-av */ - if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && - (ca->pub->poll_slot_status)) { - status = ca->pub->poll_slot_status(ca->pub, slot, 0); - if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - } - - pr_err("dvb_ca adapter %d: Invalid PC card inserted :(\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - if (dvb_ca_en50221_set_configoption(ca, slot) != 0) { - pr_err("dvb_ca adapter %d: Unable to initialise CAM :(\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - if (ca->pub->write_cam_control(ca->pub, slot, - CTRLIF_COMMAND, CMDREG_RS) != 0) { - pr_err("dvb_ca adapter %d: Unable to reset CAM IF\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - dprintk("DVB CAM validated successfully\n"); - - ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR; - ca->wakeup = 1; - break; + ca->pub->slot_ts_enable(ca->pub, slot); + sl->slot_state = DVB_CA_SLOTSTATE_RUNNING; + dvb_ca_en50221_thread_update_delay(ca); + pr_err("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", + ca->dvbdev->adapter->num); + break; - case DVB_CA_SLOTSTATE_WAITFR: - if (time_after(jiffies, ca->slot_info[slot].timeout)) { - pr_err("dvb_ca adapter %d: DVB CAM did not respond :(\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - - flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); - if (flags & STATUSREG_FR) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; - ca->wakeup = 1; - } - break; + case DVB_CA_SLOTSTATE_RUNNING: + if (!ca->open) + break; - case DVB_CA_SLOTSTATE_LINKINIT: - if (dvb_ca_en50221_link_init(ca, slot) != 0) { - /* we need this extra check for annoying interfaces like the budget-av */ - if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && - (ca->pub->poll_slot_status)) { - status = ca->pub->poll_slot_status(ca->pub, slot, 0); - if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - } - - pr_err("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = - DVB_CA_SLOTSTATE_UNINITIALISED; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - - if (ca->slot_info[slot].rx_buffer.data == NULL) { - rxbuf = vmalloc(RX_BUFFER_SIZE); - if (rxbuf == NULL) { - pr_err("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", - ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; - } - dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); - } - - ca->pub->slot_ts_enable(ca->pub, slot); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING; - dvb_ca_en50221_thread_update_delay(ca); - pr_err("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", - ca->dvbdev->adapter->num); + /* poll slots for data */ + pktcount = 0; + while (dvb_ca_en50221_read_data(ca, slot, NULL, 0) > 0) { + if (!ca->open) break; - case DVB_CA_SLOTSTATE_RUNNING: - if (!ca->open) - break; - - // poll slots for data - pktcount = 0; - while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) { - if (!ca->open) - break; - - /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */ - if (dvb_ca_en50221_check_camstatus(ca, slot)) { - // we dont want to sleep on the next iteration so we can handle the cam change - ca->wakeup = 1; - break; - } - - /* check if we've hit our limit this time */ - if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) { - // dont sleep; there is likely to be more data to read - ca->wakeup = 1; - break; - } - } + /* + * if a CAMCHANGE occurred at some point, do not do any + * more processing of this slot + */ + if (dvb_ca_en50221_check_camstatus(ca, slot)) { + /* + * we don't want to sleep on the next iteration + * so we can handle the cam change + */ + ca->wakeup = 1; break; } - mutex_unlock(&ca->slot_info[slot].slot_lock); + /* check if we've hit our limit this time */ + if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) { + /* + * don't sleep; there is likely to be more data + * to read + */ + ca->wakeup = 1; + break; + } } + break; } - return 0; + mutex_unlock(&sl->slot_lock); } +/** + * Kernel thread which monitors CA slots for CAM changes, and performs data + * transfers. + */ +static int dvb_ca_en50221_thread(void *data) +{ + struct dvb_ca_private *ca = data; + int slot; + + dprintk("%s\n", __func__); + + /* choose the correct initial delay */ + dvb_ca_en50221_thread_update_delay(ca); + + /* main loop */ + while (!kthread_should_stop()) { + /* sleep for a bit */ + if (!ca->wakeup) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(ca->delay); + if (kthread_should_stop()) + return 0; + } + ca->wakeup = 0; + + /* go through all the slots processing them */ + for (slot = 0; slot < ca->slot_count; slot++) + dvb_ca_en50221_thread_state_machine(ca, slot); + } + return 0; +} -/* ******************************************************************************** */ +/* ************************************************************************** */ /* EN50221 IO interface functions */ /** @@ -1301,15 +1359,17 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file, switch (cmd) { case CA_RESET: for (slot = 0; slot < ca->slot_count; slot++) { - mutex_lock(&ca->slot_info[slot].slot_lock); - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) { + struct dvb_ca_slot *sl = &ca->slot_info[slot]; + + mutex_lock(&sl->slot_lock); + if (sl->slot_state != DVB_CA_SLOTSTATE_NONE) { dvb_ca_en50221_slot_shutdown(ca, slot); if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) dvb_ca_en50221_camchange_irq(ca->pub, slot, DVB_CA_EN50221_CAMCHANGE_INSERTED); } - mutex_unlock(&ca->slot_info[slot].slot_lock); + mutex_unlock(&sl->slot_lock); } ca->next_read_slot = 0; dvb_ca_en50221_thread_wakeup(ca); @@ -1327,21 +1387,23 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file, case CA_GET_SLOT_INFO: { struct ca_slot_info *info = parg; + struct dvb_ca_slot *sl; - if ((info->num > ca->slot_count) || (info->num < 0)) { + slot = info->num; + if ((slot > ca->slot_count) || (slot < 0)) { err = -EINVAL; goto out_unlock; } info->type = CA_CI_LINK; info->flags = 0; - if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE) - && (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) { + sl = &ca->slot_info[slot]; + if ((sl->slot_state != DVB_CA_SLOTSTATE_NONE) && + (sl->slot_state != DVB_CA_SLOTSTATE_INVALID)) { info->flags = CA_CI_MODULE_PRESENT; } - if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) { + if (sl->slot_state == DVB_CA_SLOTSTATE_RUNNING) info->flags |= CA_CI_MODULE_READY; - } break; } @@ -1355,7 +1417,6 @@ out_unlock: return err; } - /** * Wrapper for ioctl implementation. * @@ -1372,7 +1433,6 @@ static long dvb_ca_en50221_io_ioctl(struct file *file, return dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl); } - /** * Implementation of write() syscall. * @@ -1389,6 +1449,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, { struct dvb_device *dvbdev = file->private_data; struct dvb_ca_private *ca = dvbdev->priv; + struct dvb_ca_slot *sl; u8 slot, connection_id; int status; u8 fragbuf[HOST_LINK_BUF_SIZE]; @@ -1399,7 +1460,10 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, dprintk("%s\n", __func__); - /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ + /* + * Incoming packet has a 2 byte header. + * hdr[0] = slot_id, hdr[1] = connection_id + */ if (count < 2) return -EINVAL; @@ -1410,14 +1474,15 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, return -EFAULT; buf += 2; count -= 2; + sl = &ca->slot_info[slot]; /* check if the slot is actually running */ - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) + if (sl->slot_state != DVB_CA_SLOTSTATE_RUNNING) return -EINVAL; /* fragment the packets & store in the buffer */ while (fragpos < count) { - fraglen = ca->slot_info[slot].link_buf_size - 2; + fraglen = sl->link_buf_size - 2; if (fraglen < 0) break; if (fraglen > HOST_LINK_BUF_SIZE - 2) @@ -1436,15 +1501,19 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, timeout = jiffies + HZ / 2; written = 0; while (!time_after(jiffies, timeout)) { - /* check the CAM hasn't been removed/reset in the meantime */ - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) { + /* + * check the CAM hasn't been removed/reset in the + * meantime + */ + if (sl->slot_state != DVB_CA_SLOTSTATE_RUNNING) { status = -EIO; goto exit; } - mutex_lock(&ca->slot_info[slot].slot_lock); - status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2); - mutex_unlock(&ca->slot_info[slot].slot_lock); + mutex_lock(&sl->slot_lock); + status = dvb_ca_en50221_write_data(ca, slot, fragbuf, + fraglen + 2); + mutex_unlock(&sl->slot_lock); if (status == (fraglen + 2)) { written = 1; break; @@ -1452,7 +1521,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, if (status != -EAGAIN) goto exit; - msleep(1); + usleep_range(1000, 1100); } if (!written) { status = -EIO; @@ -1467,7 +1536,6 @@ exit: return status; } - /** * Condition for waking up in dvb_ca_en50221_io_read_condition */ @@ -1484,25 +1552,28 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, slot = ca->next_read_slot; while ((slot_count < ca->slot_count) && (!found)) { - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) + struct dvb_ca_slot *sl = &ca->slot_info[slot]; + + if (sl->slot_state != DVB_CA_SLOTSTATE_RUNNING) goto nextslot; - if (ca->slot_info[slot].rx_buffer.data == NULL) { + if (!sl->rx_buffer.data) return 0; - } - idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); + idx = dvb_ringbuffer_pkt_next(&sl->rx_buffer, -1, &fraglen); while (idx != -1) { - dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2); + dvb_ringbuffer_pkt_read(&sl->rx_buffer, idx, 0, hdr, 2); if (connection_id == -1) connection_id = hdr[0]; - if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) { + if ((hdr[0] == connection_id) && + ((hdr[1] & 0x80) == 0)) { *_slot = slot; found = 1; break; } - idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); + idx = dvb_ringbuffer_pkt_next(&sl->rx_buffer, idx, + &fraglen); } nextslot: @@ -1514,7 +1585,6 @@ nextslot: return found; } - /** * Implementation of read() syscall. * @@ -1530,6 +1600,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, { struct dvb_device *dvbdev = file->private_data; struct dvb_ca_private *ca = dvbdev->priv; + struct dvb_ca_slot *sl; int status; int result = 0; u8 hdr[2]; @@ -1543,13 +1614,16 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, dprintk("%s\n", __func__); - /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ + /* + * Outgoing packet has a 2 byte header. + * hdr[0] = slot_id, hdr[1] = connection_id + */ if (count < 2) return -EINVAL; /* wait for some data */ - if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) { - + status = dvb_ca_en50221_io_read_condition(ca, &result, &slot); + if (status == 0) { /* if we're in nonblocking mode, exit immediately */ if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK; @@ -1565,7 +1639,8 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, return status; } - idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); + sl = &ca->slot_info[slot]; + idx = dvb_ringbuffer_pkt_next(&sl->rx_buffer, -1, &fraglen); pktlen = 2; do { if (idx == -1) { @@ -1575,21 +1650,24 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, goto exit; } - dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2); + dvb_ringbuffer_pkt_read(&sl->rx_buffer, idx, 0, hdr, 2); if (connection_id == -1) connection_id = hdr[0]; if (hdr[0] == connection_id) { if (pktlen < count) { - if ((pktlen + fraglen - 2) > count) { + if ((pktlen + fraglen - 2) > count) fraglen = count - pktlen; - } else { + else fraglen -= 2; - } - if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2, - buf + pktlen, fraglen)) < 0) { + status = + dvb_ringbuffer_pkt_read_user(&sl->rx_buffer, + idx, 2, + buf + pktlen, + fraglen); + if (status < 0) goto exit; - } + pktlen += fraglen; } @@ -1598,9 +1676,9 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, dispose = 1; } - idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); + idx2 = dvb_ringbuffer_pkt_next(&sl->rx_buffer, idx, &fraglen); if (dispose) - dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx); + dvb_ringbuffer_pkt_dispose(&sl->rx_buffer, idx); idx = idx2; dispose = 0; } while (!last_fragment); @@ -1618,7 +1696,6 @@ exit: return status; } - /** * Implementation of file open syscall. * @@ -1646,12 +1723,16 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) } for (i = 0; i < ca->slot_count; i++) { - - if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { - if (ca->slot_info[i].rx_buffer.data != NULL) { - /* it is safe to call this here without locks because - * ca->open == 0. Data is not read in this case */ - dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); + struct dvb_ca_slot *sl = &ca->slot_info[i]; + + if (sl->slot_state == DVB_CA_SLOTSTATE_RUNNING) { + if (!sl->rx_buffer.data) { + /* + * it is safe to call this here without locks + * because ca->open == 0. Data is not read in + * this case + */ + dvb_ringbuffer_flush(&sl->rx_buffer); } } } @@ -1665,7 +1746,6 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) return 0; } - /** * Implementation of file close syscall. * @@ -1695,7 +1775,6 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) return err; } - /** * Implementation of poll() syscall. * @@ -1714,9 +1793,8 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait) dprintk("%s\n", __func__); - if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { + if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) mask |= POLLIN; - } /* if there is something, return now */ if (mask) @@ -1725,14 +1803,11 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait) /* wait for something to happen */ poll_wait(file, &ca->wait_queue, wait); - if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { + if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) mask |= POLLIN; - } return mask; } -EXPORT_SYMBOL(dvb_ca_en50221_init); - static const struct file_operations dvb_ca_fops = { .owner = THIS_MODULE, @@ -1756,10 +1831,9 @@ static const struct dvb_device dvbdev_ca = { .fops = &dvb_ca_fops, }; -/* ******************************************************************************** */ +/* ************************************************************************** */ /* Initialisation/shutdown functions */ - /** * Initialise a new DVB CA EN50221 interface device. * @@ -1783,7 +1857,8 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, return -EINVAL; /* initialise the system data */ - if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) { + ca = kzalloc(sizeof(*ca), GFP_KERNEL); + if (!ca) { ret = -ENOMEM; goto exit; } @@ -1791,7 +1866,9 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, ca->pub = pubca; ca->flags = flags; ca->slot_count = slot_count; - if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) { + ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), + GFP_KERNEL); + if (!ca->slot_info) { ret = -ENOMEM; goto free_ca; } @@ -1802,17 +1879,20 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, pubca->private = ca; /* register the DVB device */ - ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA, 0); + ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, + DVB_DEVICE_CA, 0); if (ret) goto free_slot_info; /* now initialise each slot */ for (i = 0; i < slot_count; i++) { - memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot)); - ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; - atomic_set(&ca->slot_info[i].camchange_count, 0); - ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; - mutex_init(&ca->slot_info[i].slot_lock); + struct dvb_ca_slot *sl = &ca->slot_info[i]; + + memset(sl, 0, sizeof(struct dvb_ca_slot)); + sl->slot_state = DVB_CA_SLOTSTATE_NONE; + atomic_set(&sl->camchange_count, 0); + sl->camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; + mutex_init(&sl->slot_lock); } mutex_init(&ca->ioctl_mutex); @@ -1844,9 +1924,7 @@ exit: pubca->private = NULL; return ret; } -EXPORT_SYMBOL(dvb_ca_en50221_release); - - +EXPORT_SYMBOL(dvb_ca_en50221_init); /** * Release a DVB CA EN50221 interface device. @@ -1864,10 +1942,11 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) /* shutdown the thread if there was one */ kthread_stop(ca->thread); - for (i = 0; i < ca->slot_count; i++) { + for (i = 0; i < ca->slot_count; i++) dvb_ca_en50221_slot_shutdown(ca, i); - } + dvb_remove_device(ca->dvbdev); dvb_ca_private_put(ca); pubca->private = NULL; } +EXPORT_SYMBOL(dvb_ca_en50221_release); diff --git a/drivers/media/dvb-core/dvb_ca_en50221.h b/drivers/media/dvb-core/dvb_ca_en50221.h index 82617bac0875..367687d2b41a 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.h +++ b/drivers/media/dvb-core/dvb_ca_en50221.h @@ -69,9 +69,9 @@ struct dvb_ca_en50221 { int slot, u8 address, u8 value); int (*read_data)(struct dvb_ca_en50221 *ca, - int slot, u8 *ebuf, int ecount); + int slot, u8 *ebuf, int ecount); int (*write_data)(struct dvb_ca_en50221 *ca, - int slot, u8 *ebuf, int ecount); + int slot, u8 *ebuf, int ecount); int (*slot_reset)(struct dvb_ca_en50221 *ca, int slot); int (*slot_shutdown)(struct dvb_ca_en50221 *ca, int slot); @@ -128,8 +128,8 @@ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *ca, int slot); * * @return 0 on success, nonzero on failure */ -extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, - struct dvb_ca_en50221 *ca, int flags, +int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, + struct dvb_ca_en50221 *ca, int flags, int slot_count); /** @@ -137,6 +137,6 @@ extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, * * @ca: The associated dvb_ca instance. */ -extern void dvb_ca_en50221_release(struct dvb_ca_en50221 *ca); +void dvb_ca_en50221_release(struct dvb_ca_en50221 *ca); #endif diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index e3fff8f64d37..2fcba1616168 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -460,7 +460,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra static void dvb_frontend_swzigzag(struct dvb_frontend *fe) { - enum fe_status s = 0; + enum fe_status s = FE_NONE; int retval = 0; struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp; @@ -631,7 +631,7 @@ static int dvb_frontend_thread(void *data) struct dvb_frontend *fe = data; struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_frontend_private *fepriv = fe->frontend_priv; - enum fe_status s; + enum fe_status s = FE_NONE; enum dvbfe_algo algo; bool re_tune = false; bool semheld = false; @@ -1000,6 +1000,17 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) .buffer = b \ } +struct dtv_cmds_h { + char *name; /* A display name for debugging purposes */ + + __u32 cmd; /* A unique ID */ + + /* Flags */ + __u32 set:1; /* Either a set or get property */ + __u32 buffer:1; /* Does this property use the buffer? */ + __u32 reserved:30; /* Align */ +}; + static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_TUNE, 1, 0), _DTV_CMD(DTV_CLEAR, 1, 0), diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 3a260b82b3e8..2631d0e0a024 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -28,6 +28,15 @@ config DVB_STV090x DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators. Say Y when you want to support these frontends. +config DVB_STV0910 + tristate "STV0910 based" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + ST STV0910 DVB-S/S2 demodulator driver. + + Say Y when you want to support these frontends. + config DVB_STV6110x tristate "STV6110/(A) based tuners" depends on DVB_CORE && I2C @@ -35,6 +44,24 @@ config DVB_STV6110x help A Silicon tuner that supports DVB-S and DVB-S2 modes +config DVB_STV6111 + tristate "STV6111 based tuners" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + A Silicon tuner that supports DVB-S and DVB-S2 modes + + Say Y when you want to support these frontends. + +config DVB_MXL5XX + tristate "MaxLinear MxL5xx based tuner-demodulators" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + MaxLinear MxL5xx family of DVB-S/S2 tuners/demodulators. + + Say Y when you want to support these frontends. + config DVB_M88DS3103 tristate "Montage Technology M88DS3103" depends on DVB_CORE && I2C && I2C_MUX diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index 3fccaf34ef52..f45f6a4a4371 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -110,6 +110,9 @@ obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o obj-$(CONFIG_DVB_CXD2841ER) += cxd2841er.o obj-$(CONFIG_DVB_DRXK) += drxk.o obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o +obj-$(CONFIG_DVB_STV0910) += stv0910.o +obj-$(CONFIG_DVB_STV6111) += stv6111.o +obj-$(CONFIG_DVB_MXL5XX) += mxl5xx.o obj-$(CONFIG_DVB_SI2165) += si2165.o obj-$(CONFIG_DVB_A8293) += a8293.o obj-$(CONFIG_DVB_SP2) += sp2.o diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c index 4ae3d922a8e8..1d59d1d3bd82 100644 --- a/drivers/media/dvb-frontends/cx24123.c +++ b/drivers/media/dvb-frontends/cx24123.c @@ -1032,7 +1032,7 @@ static u32 cx24123_tuner_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm cx24123_tuner_i2c_algo = { +static const struct i2c_algorithm cx24123_tuner_i2c_algo = { .master_xfer = cx24123_tuner_i2c_tuner_xfer, .functionality = cx24123_tuner_i2c_func, }; diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c index 12bff778c97f..48ee9bc00c06 100644 --- a/drivers/media/dvb-frontends/cxd2841er.c +++ b/drivers/media/dvb-frontends/cxd2841er.c @@ -487,6 +487,8 @@ static int cxd2841er_sleep_tc_to_shutdown(struct cxd2841er_priv *priv); static int cxd2841er_shutdown_to_sleep_tc(struct cxd2841er_priv *priv); +static int cxd2841er_sleep_tc(struct dvb_frontend *fe); + static int cxd2841er_retune_active(struct cxd2841er_priv *priv, struct dtv_frontend_properties *p) { @@ -2178,42 +2180,42 @@ static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv, u32 iffreq, ifhz; u8 data[MAX_WRITE_REGSIZE]; - const uint8_t nominalRate8bw[3][5] = { + static const uint8_t nominalRate8bw[3][5] = { /* TRCG Nominal Rate [37:0] */ {0x11, 0xF0, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ {0x15, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ {0x11, 0xF0, 0x00, 0x00, 0x00} /* 41MHz XTal */ }; - const uint8_t nominalRate7bw[3][5] = { + static const uint8_t nominalRate7bw[3][5] = { /* TRCG Nominal Rate [37:0] */ {0x14, 0x80, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ {0x18, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ {0x14, 0x80, 0x00, 0x00, 0x00} /* 41MHz XTal */ }; - const uint8_t nominalRate6bw[3][5] = { + static const uint8_t nominalRate6bw[3][5] = { /* TRCG Nominal Rate [37:0] */ {0x17, 0xEA, 0xAA, 0xAA, 0xAA}, /* 20.5MHz XTal */ {0x1C, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ {0x17, 0xEA, 0xAA, 0xAA, 0xAA} /* 41MHz XTal */ }; - const uint8_t nominalRate5bw[3][5] = { + static const uint8_t nominalRate5bw[3][5] = { /* TRCG Nominal Rate [37:0] */ {0x1C, 0xB3, 0x33, 0x33, 0x33}, /* 20.5MHz XTal */ {0x21, 0x99, 0x99, 0x99, 0x99}, /* 24MHz XTal */ {0x1C, 0xB3, 0x33, 0x33, 0x33} /* 41MHz XTal */ }; - const uint8_t nominalRate17bw[3][5] = { + static const uint8_t nominalRate17bw[3][5] = { /* TRCG Nominal Rate [37:0] */ {0x58, 0xE2, 0xAF, 0xE0, 0xBC}, /* 20.5MHz XTal */ {0x68, 0x0F, 0xA2, 0x32, 0xD0}, /* 24MHz XTal */ {0x58, 0xE2, 0xAF, 0xE0, 0xBC} /* 41MHz XTal */ }; - const uint8_t itbCoef8bw[3][14] = { + static const uint8_t itbCoef8bw[3][14] = { {0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, 0x23, 0xA9, 0x1F, 0xA8, 0x2C, 0xC8}, /* 20.5MHz XTal */ {0x2F, 0xBA, 0x28, 0x9B, 0x28, 0x9D, 0x28, 0xA1, @@ -2222,7 +2224,7 @@ static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv, 0x23, 0xA9, 0x1F, 0xA8, 0x2C, 0xC8} /* 41MHz XTal */ }; - const uint8_t itbCoef7bw[3][14] = { + static const uint8_t itbCoef7bw[3][14] = { {0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, 0x29, 0xB0, 0x26, 0xA9, 0x21, 0xA5}, /* 20.5MHz XTal */ {0x30, 0xB1, 0x29, 0x9A, 0x28, 0x9C, 0x28, 0xA0, @@ -2231,7 +2233,7 @@ static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv, 0x29, 0xB0, 0x26, 0xA9, 0x21, 0xA5} /* 41MHz XTal */ }; - const uint8_t itbCoef6bw[3][14] = { + static const uint8_t itbCoef6bw[3][14] = { {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, @@ -2240,7 +2242,7 @@ static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4} /* 41MHz XTal */ }; - const uint8_t itbCoef5bw[3][14] = { + static const uint8_t itbCoef5bw[3][14] = { {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, @@ -2249,7 +2251,7 @@ static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4} /* 41MHz XTal */ }; - const uint8_t itbCoef17bw[3][14] = { + static const uint8_t itbCoef17bw[3][14] = { {0x25, 0xA0, 0x36, 0x8D, 0x2E, 0x94, 0x28, 0x9B, 0x32, 0x90, 0x2C, 0x9D, 0x29, 0x99}, /* 20.5MHz XTal */ {0x33, 0x8E, 0x2B, 0x97, 0x2D, 0x95, 0x37, 0x8B, @@ -2423,32 +2425,32 @@ static int cxd2841er_sleep_tc_to_active_t_band( { u8 data[MAX_WRITE_REGSIZE]; u32 iffreq, ifhz; - u8 nominalRate8bw[3][5] = { + static const u8 nominalRate8bw[3][5] = { /* TRCG Nominal Rate [37:0] */ {0x11, 0xF0, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ {0x15, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ {0x11, 0xF0, 0x00, 0x00, 0x00} /* 41MHz XTal */ }; - u8 nominalRate7bw[3][5] = { + static const u8 nominalRate7bw[3][5] = { /* TRCG Nominal Rate [37:0] */ {0x14, 0x80, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ {0x18, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ {0x14, 0x80, 0x00, 0x00, 0x00} /* 41MHz XTal */ }; - u8 nominalRate6bw[3][5] = { + static const u8 nominalRate6bw[3][5] = { /* TRCG Nominal Rate [37:0] */ {0x17, 0xEA, 0xAA, 0xAA, 0xAA}, /* 20.5MHz XTal */ {0x1C, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ {0x17, 0xEA, 0xAA, 0xAA, 0xAA} /* 41MHz XTal */ }; - u8 nominalRate5bw[3][5] = { + static const u8 nominalRate5bw[3][5] = { /* TRCG Nominal Rate [37:0] */ {0x1C, 0xB3, 0x33, 0x33, 0x33}, /* 20.5MHz XTal */ {0x21, 0x99, 0x99, 0x99, 0x99}, /* 24MHz XTal */ {0x1C, 0xB3, 0x33, 0x33, 0x33} /* 41MHz XTal */ }; - u8 itbCoef8bw[3][14] = { + static const u8 itbCoef8bw[3][14] = { {0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, 0x23, 0xA9, 0x1F, 0xA8, 0x2C, 0xC8}, /* 20.5MHz XTal */ {0x2F, 0xBA, 0x28, 0x9B, 0x28, 0x9D, 0x28, 0xA1, 0x29, 0xA5, @@ -2456,7 +2458,7 @@ static int cxd2841er_sleep_tc_to_active_t_band( {0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, 0x23, 0xA9, 0x1F, 0xA8, 0x2C, 0xC8} /* 41MHz XTal */ }; - u8 itbCoef7bw[3][14] = { + static const u8 itbCoef7bw[3][14] = { {0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, 0x29, 0xB0, 0x26, 0xA9, 0x21, 0xA5}, /* 20.5MHz XTal */ {0x30, 0xB1, 0x29, 0x9A, 0x28, 0x9C, 0x28, 0xA0, 0x29, 0xA2, @@ -2464,7 +2466,7 @@ static int cxd2841er_sleep_tc_to_active_t_band( {0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, 0x29, 0xB0, 0x26, 0xA9, 0x21, 0xA5} /* 41MHz XTal */ }; - u8 itbCoef6bw[3][14] = { + static const u8 itbCoef6bw[3][14] = { {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, 0x29, 0xA4, @@ -2472,7 +2474,7 @@ static int cxd2841er_sleep_tc_to_active_t_band( {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4} /* 41MHz XTal */ }; - u8 itbCoef5bw[3][14] = { + static const u8 itbCoef5bw[3][14] = { {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, 0x29, 0xA4, @@ -2652,39 +2654,39 @@ static int cxd2841er_sleep_tc_to_active_i_band( u8 data[3]; /* TRCG Nominal Rate */ - u8 nominalRate8bw[3][5] = { + static const u8 nominalRate8bw[3][5] = { {0x00, 0x00, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ {0x11, 0xB8, 0x00, 0x00, 0x00}, /* 24MHz XTal */ {0x00, 0x00, 0x00, 0x00, 0x00} /* 41MHz XTal */ }; - u8 nominalRate7bw[3][5] = { + static const u8 nominalRate7bw[3][5] = { {0x00, 0x00, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ {0x14, 0x40, 0x00, 0x00, 0x00}, /* 24MHz XTal */ {0x00, 0x00, 0x00, 0x00, 0x00} /* 41MHz XTal */ }; - u8 nominalRate6bw[3][5] = { + static const u8 nominalRate6bw[3][5] = { {0x14, 0x2E, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ {0x17, 0xA0, 0x00, 0x00, 0x00}, /* 24MHz XTal */ {0x14, 0x2E, 0x00, 0x00, 0x00} /* 41MHz XTal */ }; - u8 itbCoef8bw[3][14] = { + static const u8 itbCoef8bw[3][14] = { {0x00}, /* 20.5MHz XTal */ {0x2F, 0xBA, 0x28, 0x9B, 0x28, 0x9D, 0x28, 0xA1, 0x29, 0xA5, 0x2A, 0xAC, 0x29, 0xB5}, /* 24MHz Xtal */ {0x0}, /* 41MHz XTal */ }; - u8 itbCoef7bw[3][14] = { + static const u8 itbCoef7bw[3][14] = { {0x00}, /* 20.5MHz XTal */ {0x30, 0xB1, 0x29, 0x9A, 0x28, 0x9C, 0x28, 0xA0, 0x29, 0xA2, 0x2B, 0xA6, 0x2B, 0xAD}, /* 24MHz Xtal */ {0x00}, /* 41MHz XTal */ }; - u8 itbCoef6bw[3][14] = { + static const u8 itbCoef6bw[3][14] = { {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, 0x29, @@ -3378,6 +3380,14 @@ static int cxd2841er_set_frontend_tc(struct dvb_frontend *fe) if (priv->flags & CXD2841ER_EARLY_TUNE) cxd2841er_tuner_set(fe); + /* deconfigure/put demod to sleep on delsys switch if active */ + if (priv->state == STATE_ACTIVE_TC && + priv->system != p->delivery_system) { + dev_dbg(&priv->i2c->dev, "%s(): old_delsys=%d, new_delsys=%d -> sleep\n", + __func__, priv->system, p->delivery_system); + cxd2841er_sleep_tc(fe); + } + if (p->delivery_system == SYS_DVBT) { priv->system = SYS_DVBT; switch (priv->state) { @@ -3594,6 +3604,7 @@ static int cxd2841er_sleep_tc(struct dvb_frontend *fe) struct cxd2841er_priv *priv = fe->demodulator_priv; dev_dbg(&priv->i2c->dev, "%s()\n", __func__); + if (priv->state == STATE_ACTIVE_TC) { switch (priv->system) { case SYS_DVBT: @@ -3619,7 +3630,17 @@ static int cxd2841er_sleep_tc(struct dvb_frontend *fe) __func__, priv->state); return -EINVAL; } - cxd2841er_sleep_tc_to_shutdown(priv); + return 0; +} + +static int cxd2841er_shutdown_tc(struct dvb_frontend *fe) +{ + struct cxd2841er_priv *priv = fe->demodulator_priv; + + dev_dbg(&priv->i2c->dev, "%s()\n", __func__); + + if (!cxd2841er_sleep_tc(fe)) + cxd2841er_sleep_tc_to_shutdown(priv); return 0; } @@ -3968,7 +3989,7 @@ static struct dvb_frontend_ops cxd2841er_t_c_ops = { .symbol_rate_max = 11700000 }, .init = cxd2841er_init_tc, - .sleep = cxd2841er_sleep_tc, + .sleep = cxd2841er_shutdown_tc, .release = cxd2841er_release, .set_frontend = cxd2841er_set_frontend_tc, .get_frontend = cxd2841er_get_frontend, @@ -3978,6 +3999,6 @@ static struct dvb_frontend_ops cxd2841er_t_c_ops = { .get_frontend_algo = cxd2841er_get_algo }; -MODULE_DESCRIPTION("Sony CXD2841ER/CXD2854ER DVB-C/C2/T/T2/S/S2 demodulator driver"); +MODULE_DESCRIPTION("Sony CXD2837/38/41/43/54ER DVB-C/C2/T/T2/S/S2 demodulator driver"); MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>, Abylay Ospan <aospan@netup.ru>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index 33af14df27bd..d9d730dfe0b1 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c @@ -2052,7 +2052,7 @@ int dib0090_update_tuning_table_7090(struct dvb_frontend *fe, struct dib0090_state *state = fe->tuner_priv; const struct dib0090_tuning *tune = dib0090_tuning_table_cband_7090e_sensitivity; - const struct dib0090_tuning dib0090_tuning_table_cband_7090e_aci[] = { + static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_aci[] = { { 300000, 0 , 3, 0x8165, 0x2c0, 0x2d12, 0xb84e, EN_CAB }, { 650000, 0 , 4, 0x815B, 0x280, 0x2d12, 0xb84e, EN_CAB }, { 860000, 0 , 5, 0x84EF, 0x280, 0x2d12, 0xb84e, EN_CAB }, @@ -2435,14 +2435,7 @@ static int dib0090_tune(struct dvb_frontend *fe) Den = 1; if (Rest > 0) { - if (state->config->analog_output) - lo6 |= (1 << 2) | 2; - else { - if (state->identity.in_soc) - lo6 |= (1 << 2) | 2; - else - lo6 |= (1 << 2) | 2; - } + lo6 |= (1 << 2) | 2; Den = 255; } dib0090_write_reg(state, 0x15, (u16) FBDiv); diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 1caa04d8f60f..0fbaabe43682 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -2388,7 +2388,7 @@ static u32 dib7000p_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm dib7090_tuner_xfer_algo = { +static const struct i2c_algorithm dib7090_tuner_xfer_algo = { .master_xfer = dib7090_tuner_xfer, .functionality = dib7000p_i2c_func, }; diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index e501ec964df1..5d9381509b07 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -1880,7 +1880,7 @@ static u32 dib8096p_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm dib8096p_tuner_xfer_algo = { +static const struct i2c_algorithm dib8096p_tuner_xfer_algo = { .master_xfer = dib8096p_tuner_xfer, .functionality = dib8096p_i2c_func, }; @@ -4255,23 +4255,6 @@ static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_fronte return -ENOMEM; } -static int dib8000_remove_slave_frontend(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - u8 index_frontend = 1; - - while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) - index_frontend++; - if (index_frontend != 1) { - dprintk("remove slave fe %p (index %i)\n", state->fe[index_frontend-1], index_frontend-1); - state->fe[index_frontend] = NULL; - return 0; - } - - dprintk("no frontend to be removed\n"); - return -ENODEV; -} - static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) { struct dib8000_state *state = fe->demodulator_priv; @@ -4506,7 +4489,6 @@ void *dib8000_attach(struct dib8000_ops *ops) ops->get_slave_frontend = dib8000_get_slave_frontend; ops->set_tune_state = dib8000_set_tune_state; ops->pid_filter_ctrl = dib8000_pid_filter_ctrl; - ops->remove_slave_frontend = dib8000_remove_slave_frontend; ops->get_adc_power = dib8000_get_adc_power; ops->update_pll = dib8000_update_pll; ops->tuner_sleep = dib8096p_tuner_sleep; diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h index 2b8b4b1656a2..75cc8e47ec8f 100644 --- a/drivers/media/dvb-frontends/dib8000.h +++ b/drivers/media/dvb-frontends/dib8000.h @@ -53,7 +53,6 @@ struct dib8000_ops { enum frontend_tune_state (*get_tune_state)(struct dvb_frontend *fe); int (*set_tune_state)(struct dvb_frontend *fe, enum frontend_tune_state tune_state); int (*set_slave_frontend)(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); - int (*remove_slave_frontend)(struct dvb_frontend *fe); struct dvb_frontend *(*get_slave_frontend)(struct dvb_frontend *fe, int slave_index); int (*i2c_enumeration)(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr, u8 is_dib8096p); diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c index c95fff4f9582..1b7a4331af05 100644 --- a/drivers/media/dvb-frontends/dib9000.c +++ b/drivers/media/dvb-frontends/dib9000.c @@ -1714,12 +1714,12 @@ static u32 dib9000_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm dib9000_tuner_algo = { +static const struct i2c_algorithm dib9000_tuner_algo = { .master_xfer = dib9000_tuner_xfer, .functionality = dib9000_i2c_func, }; -static struct i2c_algorithm dib9000_component_bus_algo = { +static const struct i2c_algorithm dib9000_component_bus_algo = { .master_xfer = dib9000_fw_component_bus_xfer, .functionality = dib9000_i2c_func, }; @@ -2462,24 +2462,6 @@ int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_ } EXPORT_SYMBOL(dib9000_set_slave_frontend); -int dib9000_remove_slave_frontend(struct dvb_frontend *fe) -{ - struct dib9000_state *state = fe->demodulator_priv; - u8 index_frontend = 1; - - while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) - index_frontend++; - if (index_frontend != 1) { - dprintk("remove slave fe %p (index %i)\n", state->fe[index_frontend - 1], index_frontend - 1); - state->fe[index_frontend] = NULL; - return 0; - } - - dprintk("no frontend to be removed\n"); - return -ENODEV; -} -EXPORT_SYMBOL(dib9000_remove_slave_frontend); - struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) { struct dib9000_state *state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/dib9000.h b/drivers/media/dvb-frontends/dib9000.h index b10a70aa7c9f..40883b41e66b 100644 --- a/drivers/media/dvb-frontends/dib9000.h +++ b/drivers/media/dvb-frontends/dib9000.h @@ -37,7 +37,6 @@ extern int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff); extern int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff); extern int dib9000_firmware_post_pll_init(struct dvb_frontend *fe); extern int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); -extern int dib9000_remove_slave_frontend(struct dvb_frontend *fe); extern struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); extern struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe); extern int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c); @@ -97,12 +96,6 @@ static inline int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb return -ENODEV; } -static inline int dib9000_remove_slave_frontend(struct dvb_frontend *fe) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - static inline struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 14040c915dbb..499ccff557bf 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -5489,7 +5489,7 @@ static int set_vsb_leak_n_gain(struct drx_demod_instance *demod) struct i2c_device_addr *dev_addr = NULL; int rc; - const u8 vsb_ffe_leak_gain_ram0[] = { + static const u8 vsb_ffe_leak_gain_ram0[] = { DRXJ_16TO8(0x8), /* FFETRAINLKRATIO1 */ DRXJ_16TO8(0x8), /* FFETRAINLKRATIO2 */ DRXJ_16TO8(0x8), /* FFETRAINLKRATIO3 */ @@ -5620,7 +5620,7 @@ static int set_vsb_leak_n_gain(struct drx_demod_instance *demod) DRXJ_16TO8(0x1010) /* FIRRCA1GAIN8 */ }; - const u8 vsb_ffe_leak_gain_ram1[] = { + static const u8 vsb_ffe_leak_gain_ram1[] = { DRXJ_16TO8(0x1010), /* FIRRCA1GAIN9 */ DRXJ_16TO8(0x0808), /* FIRRCA1GAIN10 */ DRXJ_16TO8(0x0808), /* FIRRCA1GAIN11 */ @@ -5710,7 +5710,7 @@ static int set_vsb(struct drx_demod_instance *demod) struct drxj_data *ext_attr = NULL; u16 cmd_result = 0; u16 cmd_param = 0; - const u8 vsb_taps_re[] = { + static const u8 vsb_taps_re[] = { DRXJ_16TO8(-2), /* re0 */ DRXJ_16TO8(4), /* re1 */ DRXJ_16TO8(1), /* re2 */ @@ -6666,7 +6666,7 @@ static int set_qam16(struct drx_demod_instance *demod) { struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; int rc; - const u8 qam_dq_qual_fun[] = { + static const u8 qam_dq_qual_fun[] = { DRXJ_16TO8(2), /* fun0 */ DRXJ_16TO8(2), /* fun1 */ DRXJ_16TO8(2), /* fun2 */ @@ -6674,7 +6674,7 @@ static int set_qam16(struct drx_demod_instance *demod) DRXJ_16TO8(3), /* fun4 */ DRXJ_16TO8(3), /* fun5 */ }; - const u8 qam_eq_cma_rad[] = { + static const u8 qam_eq_cma_rad[] = { DRXJ_16TO8(13517), /* RAD0 */ DRXJ_16TO8(13517), /* RAD1 */ DRXJ_16TO8(13517), /* RAD2 */ @@ -6901,7 +6901,7 @@ static int set_qam32(struct drx_demod_instance *demod) { struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; int rc; - const u8 qam_dq_qual_fun[] = { + static const u8 qam_dq_qual_fun[] = { DRXJ_16TO8(3), /* fun0 */ DRXJ_16TO8(3), /* fun1 */ DRXJ_16TO8(3), /* fun2 */ @@ -6909,7 +6909,7 @@ static int set_qam32(struct drx_demod_instance *demod) DRXJ_16TO8(4), /* fun4 */ DRXJ_16TO8(4), /* fun5 */ }; - const u8 qam_eq_cma_rad[] = { + static const u8 qam_eq_cma_rad[] = { DRXJ_16TO8(6707), /* RAD0 */ DRXJ_16TO8(6707), /* RAD1 */ DRXJ_16TO8(6707), /* RAD2 */ @@ -7136,7 +7136,8 @@ static int set_qam64(struct drx_demod_instance *demod) { struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; int rc; - const u8 qam_dq_qual_fun[] = { /* this is hw reset value. no necessary to re-write */ + static const u8 qam_dq_qual_fun[] = { + /* this is hw reset value. no necessary to re-write */ DRXJ_16TO8(4), /* fun0 */ DRXJ_16TO8(4), /* fun1 */ DRXJ_16TO8(4), /* fun2 */ @@ -7144,7 +7145,7 @@ static int set_qam64(struct drx_demod_instance *demod) DRXJ_16TO8(6), /* fun4 */ DRXJ_16TO8(6), /* fun5 */ }; - const u8 qam_eq_cma_rad[] = { + static const u8 qam_eq_cma_rad[] = { DRXJ_16TO8(13336), /* RAD0 */ DRXJ_16TO8(12618), /* RAD1 */ DRXJ_16TO8(11988), /* RAD2 */ @@ -7371,7 +7372,7 @@ static int set_qam128(struct drx_demod_instance *demod) { struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; int rc; - const u8 qam_dq_qual_fun[] = { + static const u8 qam_dq_qual_fun[] = { DRXJ_16TO8(6), /* fun0 */ DRXJ_16TO8(6), /* fun1 */ DRXJ_16TO8(6), /* fun2 */ @@ -7379,7 +7380,7 @@ static int set_qam128(struct drx_demod_instance *demod) DRXJ_16TO8(9), /* fun4 */ DRXJ_16TO8(9), /* fun5 */ }; - const u8 qam_eq_cma_rad[] = { + static const u8 qam_eq_cma_rad[] = { DRXJ_16TO8(6164), /* RAD0 */ DRXJ_16TO8(6598), /* RAD1 */ DRXJ_16TO8(6394), /* RAD2 */ @@ -7606,7 +7607,7 @@ static int set_qam256(struct drx_demod_instance *demod) { struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr; int rc; - const u8 qam_dq_qual_fun[] = { + static const u8 qam_dq_qual_fun[] = { DRXJ_16TO8(8), /* fun0 */ DRXJ_16TO8(8), /* fun1 */ DRXJ_16TO8(8), /* fun2 */ @@ -7614,7 +7615,7 @@ static int set_qam256(struct drx_demod_instance *demod) DRXJ_16TO8(12), /* fun4 */ DRXJ_16TO8(12), /* fun5 */ }; - const u8 qam_eq_cma_rad[] = { + static const u8 qam_eq_cma_rad[] = { DRXJ_16TO8(12345), /* RAD0 */ DRXJ_16TO8(12345), /* RAD1 */ DRXJ_16TO8(13626), /* RAD2 */ @@ -7862,7 +7863,7 @@ set_qam(struct drx_demod_instance *demod, /* parameter */ NULL, /* result */ NULL }; - const u8 qam_a_taps[] = { + static const u8 qam_a_taps[] = { DRXJ_16TO8(-1), /* re0 */ DRXJ_16TO8(1), /* re1 */ DRXJ_16TO8(1), /* re2 */ @@ -7892,7 +7893,7 @@ set_qam(struct drx_demod_instance *demod, DRXJ_16TO8(-40), /* re26 */ DRXJ_16TO8(619) /* re27 */ }; - const u8 qam_b64_taps[] = { + static const u8 qam_b64_taps[] = { DRXJ_16TO8(0), /* re0 */ DRXJ_16TO8(-2), /* re1 */ DRXJ_16TO8(1), /* re2 */ @@ -7922,7 +7923,7 @@ set_qam(struct drx_demod_instance *demod, DRXJ_16TO8(-46), /* re26 */ DRXJ_16TO8(614) /* re27 */ }; - const u8 qam_b256_taps[] = { + static const u8 qam_b256_taps[] = { DRXJ_16TO8(-2), /* re0 */ DRXJ_16TO8(4), /* re1 */ DRXJ_16TO8(1), /* re2 */ @@ -7952,7 +7953,7 @@ set_qam(struct drx_demod_instance *demod, DRXJ_16TO8(-32), /* re26 */ DRXJ_16TO8(628) /* re27 */ }; - const u8 qam_c_taps[] = { + static const u8 qam_c_taps[] = { DRXJ_16TO8(-3), /* re0 */ DRXJ_16TO8(3), /* re1 */ DRXJ_16TO8(2), /* re2 */ diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 17638e08835a..7d04400b18dd 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -638,8 +638,10 @@ static int SetCfgIfAgc(struct drxd_state *state, struct SCfgAgc *cfg) /* == Speed == */ { const u16 maxRur = 8; - const u16 slowIncrDecLUT[] = { 3, 4, 4, 5, 6 }; - const u16 fastIncrDecLUT[] = { 14, 15, 15, 16, + static const u16 slowIncrDecLUT[] = { + 3, 4, 4, 5, 6 }; + const u16 fastIncrDecLUT[] = { + 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, diff --git a/drivers/media/dvb-frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c index 838b42771a05..3f3487887672 100644 --- a/drivers/media/dvb-frontends/isl6421.c +++ b/drivers/media/dvb-frontends/isl6421.c @@ -38,35 +38,101 @@ struct isl6421 { u8 override_and; struct i2c_adapter *i2c; u8 i2c_addr; + bool is_off; }; static int isl6421_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { + int ret; + u8 buf; + bool is_off; struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv; - struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, - .buf = &isl6421->config, - .len = sizeof(isl6421->config) }; + struct i2c_msg msg[2] = { + { + .addr = isl6421->i2c_addr, + .flags = 0, + .buf = &isl6421->config, + .len = 1, + }, { + .addr = isl6421->i2c_addr, + .flags = I2C_M_RD, + .buf = &buf, + .len = 1, + } + + }; isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1); switch(voltage) { case SEC_VOLTAGE_OFF: + is_off = true; break; case SEC_VOLTAGE_13: + is_off = false; isl6421->config |= ISL6421_EN1; break; case SEC_VOLTAGE_18: + is_off = false; isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1); break; default: return -EINVAL; } + /* + * If LNBf were not powered on, disable dynamic current limit, as, + * according with datasheet, highly capacitive load on the output may + * cause a difficult start-up. + */ + if (isl6421->is_off && !is_off) + isl6421->config |= ISL6421_DCL; + isl6421->config |= isl6421->override_or; isl6421->config &= isl6421->override_and; - return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; + ret = i2c_transfer(isl6421->i2c, msg, 2); + if (ret < 0) + return ret; + if (ret != 2) + return -EIO; + + /* Store off status now incase future commands fail */ + isl6421->is_off = is_off; + + /* On overflow, the device will try again after 900 ms (typically) */ + if (!is_off && (buf & ISL6421_OLF1)) + msleep(1000); + + /* Re-enable dynamic current limit */ + if ((isl6421->config & ISL6421_DCL) && + !(isl6421->override_or & ISL6421_DCL)) { + isl6421->config &= ~ISL6421_DCL; + + ret = i2c_transfer(isl6421->i2c, msg, 2); + if (ret < 0) + return ret; + if (ret != 2) + return -EIO; + } + + /* Check if overload flag is active. If so, disable power */ + if (!is_off && (buf & ISL6421_OLF1)) { + isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1); + ret = i2c_transfer(isl6421->i2c, msg, 1); + if (ret < 0) + return ret; + if (ret != 1) + return -EIO; + isl6421->is_off = true; + + dev_warn(&isl6421->i2c->dev, + "Overload current detected. disabling LNBf power\n"); + return -EINVAL; + } + + return 0; } static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) @@ -148,6 +214,8 @@ struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter return NULL; } + isl6421->is_off = true; + /* install release callback */ fe->ops.release_sec = isl6421_release; diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c index 9bb122c39c1b..dfe322eccaa1 100644 --- a/drivers/media/dvb-frontends/mb86a16.c +++ b/drivers/media/dvb-frontends/mb86a16.c @@ -415,27 +415,21 @@ static int signal_det(struct mb86a16_state *state, int smrt, unsigned char *SIG) { - - int ret ; - int smrtd ; - int wait_sym ; - - u32 wait_t; - unsigned char S[3] ; - int i ; + int ret; + int smrtd; + unsigned char S[3]; + int i; if (*SIG > 45) { if (CNTM_set(state, 2, 1, 2) < 0) { dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error"); return -1; } - wait_sym = 40000; } else { if (CNTM_set(state, 3, 1, 2) < 0) { dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error"); return -1; } - wait_sym = 80000; } for (i = 0; i < 3; i++) { if (i == 0) @@ -447,22 +441,17 @@ static int signal_det(struct mb86a16_state *state, smrt_info_get(state, smrtd); smrt_set(state, smrtd); srst(state); - wait_t = (wait_sym + 99 * smrtd / 100) / smrtd; - if (wait_t == 0) - wait_t = 1; msleep_interruptible(10); if (mb86a16_read(state, 0x37, &(S[i])) != 2) { dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); return -EREMOTEIO; } } - if ((S[1] > S[0] * 112 / 100) && - (S[1] > S[2] * 112 / 100)) { - + if ((S[1] > S[0] * 112 / 100) && (S[1] > S[2] * 112 / 100)) ret = 1; - } else { + else ret = 0; - } + *SIG = S[1]; if (CNTM_set(state, 0, 1, 2) < 0) { diff --git a/drivers/media/dvb-frontends/mn88472.c b/drivers/media/dvb-frontends/mn88472.c index f6938f9607ac..5e8fd63832e9 100644 --- a/drivers/media/dvb-frontends/mn88472.c +++ b/drivers/media/dvb-frontends/mn88472.c @@ -377,7 +377,9 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) ret = regmap_write(dev->regmap[1], 0xf6, 0x05); if (ret) goto err; - ret = regmap_write(dev->regmap[2], 0x32, c->stream_id); + ret = regmap_write(dev->regmap[2], 0x32, + (c->stream_id == NO_STREAM_ID_FILTER) ? 0 : + c->stream_id ); if (ret) goto err; break; diff --git a/drivers/media/dvb-frontends/mn88473.c b/drivers/media/dvb-frontends/mn88473.c index 15874244fd8b..58247432a628 100644 --- a/drivers/media/dvb-frontends/mn88473.c +++ b/drivers/media/dvb-frontends/mn88473.c @@ -225,7 +225,9 @@ static int mn88473_set_frontend(struct dvb_frontend *fe) /* PLP */ if (c->delivery_system == SYS_DVBT2) { - ret = regmap_write(dev->regmap[2], 0x36, c->stream_id); + ret = regmap_write(dev->regmap[2], 0x36, + (c->stream_id == NO_STREAM_ID_FILTER) ? 0 : + c->stream_id ); if (ret) goto err; } diff --git a/drivers/media/dvb-frontends/mxl5xx.c b/drivers/media/dvb-frontends/mxl5xx.c new file mode 100644 index 000000000000..676c96c216c3 --- /dev/null +++ b/drivers/media/dvb-frontends/mxl5xx.c @@ -0,0 +1,1873 @@ +/* + * Driver for the MaxLinear MxL5xx family of tuners/demods + * + * Copyright (C) 2014-2015 Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * developed for Digital Devices GmbH + * + * based on code: + * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved + * which was released under GPL V2 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/firmware.h> +#include <linux/i2c.h> +#include <linux/version.h> +#include <linux/mutex.h> +#include <linux/vmalloc.h> +#include <asm/div64.h> +#include <asm/unaligned.h> + +#include "dvb_frontend.h" +#include "mxl5xx.h" +#include "mxl5xx_regs.h" +#include "mxl5xx_defs.h" + +#define BYTE0(v) ((v >> 0) & 0xff) +#define BYTE1(v) ((v >> 8) & 0xff) +#define BYTE2(v) ((v >> 16) & 0xff) +#define BYTE3(v) ((v >> 24) & 0xff) + +LIST_HEAD(mxllist); + +struct mxl_base { + struct list_head mxllist; + struct list_head mxls; + + u8 adr; + struct i2c_adapter *i2c; + + u32 count; + u32 type; + u32 sku_type; + u32 chipversion; + u32 clock; + u32 fwversion; + + u8 *ts_map; + u8 can_clkout; + u8 chan_bond; + u8 demod_num; + u8 tuner_num; + + unsigned long next_tune; + + struct mutex i2c_lock; + struct mutex status_lock; + struct mutex tune_lock; + + u8 buf[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN]; + + u32 cmd_size; + u8 cmd_data[MAX_CMD_DATA]; +}; + +struct mxl { + struct list_head mxl; + + struct mxl_base *base; + struct dvb_frontend fe; + struct device *i2cdev; + u32 demod; + u32 tuner; + u32 tuner_in_use; + u8 xbar[3]; + + unsigned long tune_time; +}; + +static void convert_endian(u8 flag, u32 size, u8 *d) +{ + u32 i; + + if (!flag) + return; + for (i = 0; i < (size & ~3); i += 4) { + d[i + 0] ^= d[i + 3]; + d[i + 3] ^= d[i + 0]; + d[i + 0] ^= d[i + 3]; + + d[i + 1] ^= d[i + 2]; + d[i + 2] ^= d[i + 1]; + d[i + 1] ^= d[i + 2]; + } + + switch (size & 3) { + case 0: + case 1: + /* do nothing */ + break; + case 2: + d[i + 0] ^= d[i + 1]; + d[i + 1] ^= d[i + 0]; + d[i + 0] ^= d[i + 1]; + break; + + case 3: + d[i + 0] ^= d[i + 2]; + d[i + 2] ^= d[i + 0]; + d[i + 0] ^= d[i + 2]; + break; + } + +} + +static int i2c_write(struct i2c_adapter *adap, u8 adr, + u8 *data, u32 len) +{ + struct i2c_msg msg = {.addr = adr, .flags = 0, + .buf = data, .len = len}; + + return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; +} + +static int i2c_read(struct i2c_adapter *adap, u8 adr, + u8 *data, u32 len) +{ + struct i2c_msg msg = {.addr = adr, .flags = I2C_M_RD, + .buf = data, .len = len}; + + return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; +} + +static int i2cread(struct mxl *state, u8 *data, int len) +{ + return i2c_read(state->base->i2c, state->base->adr, data, len); +} + +static int i2cwrite(struct mxl *state, u8 *data, int len) +{ + return i2c_write(state->base->i2c, state->base->adr, data, len); +} + +static int read_register_unlocked(struct mxl *state, u32 reg, u32 *val) +{ + int stat; + u8 data[MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE] = { + MXL_HYDRA_PLID_REG_READ, 0x04, + GET_BYTE(reg, 0), GET_BYTE(reg, 1), + GET_BYTE(reg, 2), GET_BYTE(reg, 3), + }; + + stat = i2cwrite(state, data, + MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE); + if (stat) + dev_err(state->i2cdev, "i2c read error 1\n"); + if (!stat) + stat = i2cread(state, (u8 *) val, + MXL_HYDRA_REG_SIZE_IN_BYTES); + le32_to_cpus(val); + if (stat) + dev_err(state->i2cdev, "i2c read error 2\n"); + return stat; +} + +#define DMA_I2C_INTERRUPT_ADDR 0x8000011C +#define DMA_INTR_PROT_WR_CMP 0x08 + +static int send_command(struct mxl *state, u32 size, u8 *buf) +{ + int stat; + u32 val, count = 10; + + mutex_lock(&state->base->i2c_lock); + if (state->base->fwversion > 0x02010109) { + read_register_unlocked(state, DMA_I2C_INTERRUPT_ADDR, &val); + if (DMA_INTR_PROT_WR_CMP & val) + dev_info(state->i2cdev, "%s busy\n", __func__); + while ((DMA_INTR_PROT_WR_CMP & val) && --count) { + mutex_unlock(&state->base->i2c_lock); + usleep_range(1000, 2000); + mutex_lock(&state->base->i2c_lock); + read_register_unlocked(state, DMA_I2C_INTERRUPT_ADDR, + &val); + } + if (!count) { + dev_info(state->i2cdev, "%s busy\n", __func__); + mutex_unlock(&state->base->i2c_lock); + return -EBUSY; + } + } + stat = i2cwrite(state, buf, size); + mutex_unlock(&state->base->i2c_lock); + return stat; +} + +static int write_register(struct mxl *state, u32 reg, u32 val) +{ + int stat; + u8 data[MXL_HYDRA_REG_WRITE_LEN] = { + MXL_HYDRA_PLID_REG_WRITE, 0x08, + BYTE0(reg), BYTE1(reg), BYTE2(reg), BYTE3(reg), + BYTE0(val), BYTE1(val), BYTE2(val), BYTE3(val), + }; + mutex_lock(&state->base->i2c_lock); + stat = i2cwrite(state, data, sizeof(data)); + mutex_unlock(&state->base->i2c_lock); + if (stat) + dev_err(state->i2cdev, "i2c write error\n"); + return stat; +} + +static int write_firmware_block(struct mxl *state, + u32 reg, u32 size, u8 *reg_data_ptr) +{ + int stat; + u8 *buf = state->base->buf; + + mutex_lock(&state->base->i2c_lock); + buf[0] = MXL_HYDRA_PLID_REG_WRITE; + buf[1] = size + 4; + buf[2] = GET_BYTE(reg, 0); + buf[3] = GET_BYTE(reg, 1); + buf[4] = GET_BYTE(reg, 2); + buf[5] = GET_BYTE(reg, 3); + memcpy(&buf[6], reg_data_ptr, size); + stat = i2cwrite(state, buf, + MXL_HYDRA_I2C_HDR_SIZE + + MXL_HYDRA_REG_SIZE_IN_BYTES + size); + mutex_unlock(&state->base->i2c_lock); + if (stat) + dev_err(state->i2cdev, "fw block write failed\n"); + return stat; +} + +static int read_register(struct mxl *state, u32 reg, u32 *val) +{ + int stat; + u8 data[MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE] = { + MXL_HYDRA_PLID_REG_READ, 0x04, + GET_BYTE(reg, 0), GET_BYTE(reg, 1), + GET_BYTE(reg, 2), GET_BYTE(reg, 3), + }; + + mutex_lock(&state->base->i2c_lock); + stat = i2cwrite(state, data, + MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE); + if (stat) + dev_err(state->i2cdev, "i2c read error 1\n"); + if (!stat) + stat = i2cread(state, (u8 *) val, + MXL_HYDRA_REG_SIZE_IN_BYTES); + mutex_unlock(&state->base->i2c_lock); + le32_to_cpus(val); + if (stat) + dev_err(state->i2cdev, "i2c read error 2\n"); + return stat; +} + +static int read_register_block(struct mxl *state, u32 reg, u32 size, u8 *data) +{ + int stat; + u8 *buf = state->base->buf; + + mutex_lock(&state->base->i2c_lock); + + buf[0] = MXL_HYDRA_PLID_REG_READ; + buf[1] = size + 4; + buf[2] = GET_BYTE(reg, 0); + buf[3] = GET_BYTE(reg, 1); + buf[4] = GET_BYTE(reg, 2); + buf[5] = GET_BYTE(reg, 3); + stat = i2cwrite(state, buf, + MXL_HYDRA_I2C_HDR_SIZE + MXL_HYDRA_REG_SIZE_IN_BYTES); + if (!stat) { + stat = i2cread(state, data, size); + convert_endian(MXL_ENABLE_BIG_ENDIAN, size, data); + } + mutex_unlock(&state->base->i2c_lock); + return stat; +} + +static int read_by_mnemonic(struct mxl *state, + u32 reg, u8 lsbloc, u8 numofbits, u32 *val) +{ + u32 data = 0, mask = 0; + int stat; + + stat = read_register(state, reg, &data); + if (stat) + return stat; + mask = MXL_GET_REG_MASK_32(lsbloc, numofbits); + data &= mask; + data >>= lsbloc; + *val = data; + return 0; +} + + +static int update_by_mnemonic(struct mxl *state, + u32 reg, u8 lsbloc, u8 numofbits, u32 val) +{ + u32 data, mask; + int stat; + + stat = read_register(state, reg, &data); + if (stat) + return stat; + mask = MXL_GET_REG_MASK_32(lsbloc, numofbits); + data = (data & ~mask) | ((val << lsbloc) & mask); + stat = write_register(state, reg, data); + return stat; +} + +static int firmware_is_alive(struct mxl *state) +{ + u32 hb0, hb1; + + if (read_register(state, HYDRA_HEAR_BEAT, &hb0)) + return 0; + msleep(20); + if (read_register(state, HYDRA_HEAR_BEAT, &hb1)) + return 0; + if (hb1 == hb0) + return 0; + return 1; +} + +static int init(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + + /* init fe stats */ + p->strength.len = 1; + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.len = 1; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_error.len = 1; + p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_count.len = 1; + p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_error.len = 1; + p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_count.len = 1; + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + return 0; +} + +static void release(struct dvb_frontend *fe) +{ + struct mxl *state = fe->demodulator_priv; + + list_del(&state->mxl); + /* Release one frontend, two more shall take its place! */ + state->base->count--; + if (state->base->count == 0) { + list_del(&state->base->mxllist); + kfree(state->base); + } + kfree(state); +} + +static int get_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_HW; +} + +static int cfg_demod_abort_tune(struct mxl *state) +{ + struct MXL_HYDRA_DEMOD_ABORT_TUNE_T abort_tune_cmd; + u8 cmd_size = sizeof(abort_tune_cmd); + u8 cmd_buff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN]; + + abort_tune_cmd.demod_id = state->demod; + BUILD_HYDRA_CMD(MXL_HYDRA_ABORT_TUNE_CMD, MXL_CMD_WRITE, + cmd_size, &abort_tune_cmd, cmd_buff); + return send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE, + &cmd_buff[0]); +} + +static int send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + /*struct mxl *state = fe->demodulator_priv;*/ + + return 0; /*CfgDemodAbortTune(state);*/ +} + +static int set_parameters(struct dvb_frontend *fe) +{ + struct mxl *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct MXL_HYDRA_DEMOD_PARAM_T demod_chan_cfg; + u8 cmd_size = sizeof(demod_chan_cfg); + u8 cmd_buff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN]; + u32 srange = 10; + int stat; + + if (p->frequency < 950000 || p->frequency > 2150000) + return -EINVAL; + if (p->symbol_rate < 1000000 || p->symbol_rate > 45000000) + return -EINVAL; + + /* CfgDemodAbortTune(state); */ + + switch (p->delivery_system) { + case SYS_DSS: + demod_chan_cfg.standard = MXL_HYDRA_DSS; + demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_AUTO; + break; + case SYS_DVBS: + srange = p->symbol_rate / 1000000; + if (srange > 10) + srange = 10; + demod_chan_cfg.standard = MXL_HYDRA_DVBS; + demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_0_35; + demod_chan_cfg.modulation_scheme = MXL_HYDRA_MOD_QPSK; + demod_chan_cfg.pilots = MXL_HYDRA_PILOTS_OFF; + break; + case SYS_DVBS2: + demod_chan_cfg.standard = MXL_HYDRA_DVBS2; + demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_AUTO; + demod_chan_cfg.modulation_scheme = MXL_HYDRA_MOD_AUTO; + demod_chan_cfg.pilots = MXL_HYDRA_PILOTS_AUTO; + /* cfg_scrambler(state); */ + break; + default: + return -EINVAL; + } + demod_chan_cfg.tuner_index = state->tuner; + demod_chan_cfg.demod_index = state->demod; + demod_chan_cfg.frequency_in_hz = p->frequency * 1000; + demod_chan_cfg.symbol_rate_in_hz = p->symbol_rate; + demod_chan_cfg.max_carrier_offset_in_mhz = srange; + demod_chan_cfg.spectrum_inversion = MXL_HYDRA_SPECTRUM_AUTO; + demod_chan_cfg.fec_code_rate = MXL_HYDRA_FEC_AUTO; + + mutex_lock(&state->base->tune_lock); + if (time_after(jiffies + msecs_to_jiffies(200), + state->base->next_tune)) + while (time_before(jiffies, state->base->next_tune)) + usleep_range(10000, 11000); + state->base->next_tune = jiffies + msecs_to_jiffies(100); + state->tuner_in_use = state->tuner; + BUILD_HYDRA_CMD(MXL_HYDRA_DEMOD_SET_PARAM_CMD, MXL_CMD_WRITE, + cmd_size, &demod_chan_cfg, cmd_buff); + stat = send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE, + &cmd_buff[0]); + mutex_unlock(&state->base->tune_lock); + return stat; +} + +static int enable_tuner(struct mxl *state, u32 tuner, u32 enable); + +static int sleep(struct dvb_frontend *fe) +{ + struct mxl *state = fe->demodulator_priv; + struct mxl *p; + + cfg_demod_abort_tune(state); + if (state->tuner_in_use != 0xffffffff) { + mutex_lock(&state->base->tune_lock); + state->tuner_in_use = 0xffffffff; + list_for_each_entry(p, &state->base->mxls, mxl) { + if (p->tuner_in_use == state->tuner) + break; + } + if (&p->mxl == &state->base->mxls) + enable_tuner(state, state->tuner, 0); + mutex_unlock(&state->base->tune_lock); + } + return 0; +} + +static int read_snr(struct dvb_frontend *fe) +{ + struct mxl *state = fe->demodulator_priv; + int stat; + u32 reg_data = 0; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + + mutex_lock(&state->base->status_lock); + HYDRA_DEMOD_STATUS_LOCK(state, state->demod); + stat = read_register(state, (HYDRA_DMD_SNR_ADDR_OFFSET + + HYDRA_DMD_STATUS_OFFSET(state->demod)), + ®_data); + HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod); + mutex_unlock(&state->base->status_lock); + + p->cnr.stat[0].scale = FE_SCALE_DECIBEL; + p->cnr.stat[0].svalue = (s16)reg_data * 10; + + return stat; +} + +static int read_ber(struct dvb_frontend *fe) +{ + struct mxl *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 reg[8]; + + mutex_lock(&state->base->status_lock); + HYDRA_DEMOD_STATUS_LOCK(state, state->demod); + read_register_block(state, + (HYDRA_DMD_DVBS_1ST_CORR_RS_ERRORS_ADDR_OFFSET + + HYDRA_DMD_STATUS_OFFSET(state->demod)), + (4 * sizeof(u32)), + (u8 *) ®[0]); + HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod); + + switch (p->delivery_system) { + case SYS_DSS: + case SYS_DVBS: + p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; + p->pre_bit_error.stat[0].uvalue = reg[2]; + p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; + p->pre_bit_count.stat[0].uvalue = reg[3]; + break; + default: + break; + } + + read_register_block(state, + (HYDRA_DMD_DVBS2_CRC_ERRORS_ADDR_OFFSET + + HYDRA_DMD_STATUS_OFFSET(state->demod)), + (7 * sizeof(u32)), + (u8 *) ®[0]); + + switch (p->delivery_system) { + case SYS_DSS: + case SYS_DVBS: + p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + p->post_bit_error.stat[0].uvalue = reg[5]; + p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + p->post_bit_count.stat[0].uvalue = reg[6]; + break; + case SYS_DVBS2: + p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + p->post_bit_error.stat[0].uvalue = reg[1]; + p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + p->post_bit_count.stat[0].uvalue = reg[2]; + break; + default: + break; + } + + mutex_unlock(&state->base->status_lock); + + return 0; +} + +static int read_signal_strength(struct dvb_frontend *fe) +{ + struct mxl *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int stat; + u32 reg_data = 0; + + mutex_lock(&state->base->status_lock); + HYDRA_DEMOD_STATUS_LOCK(state, state->demod); + stat = read_register(state, (HYDRA_DMD_STATUS_INPUT_POWER_ADDR + + HYDRA_DMD_STATUS_OFFSET(state->demod)), + ®_data); + HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod); + mutex_unlock(&state->base->status_lock); + + p->strength.stat[0].scale = FE_SCALE_DECIBEL; + p->strength.stat[0].svalue = (s16) reg_data * 10; /* fix scale */ + + return stat; +} + +static int read_status(struct dvb_frontend *fe, enum fe_status *status) +{ + struct mxl *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 reg_data = 0; + + mutex_lock(&state->base->status_lock); + HYDRA_DEMOD_STATUS_LOCK(state, state->demod); + read_register(state, (HYDRA_DMD_LOCK_STATUS_ADDR_OFFSET + + HYDRA_DMD_STATUS_OFFSET(state->demod)), + ®_data); + HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod); + mutex_unlock(&state->base->status_lock); + + *status = (reg_data == 1) ? 0x1f : 0; + + /* signal statistics */ + + /* signal strength is always available */ + read_signal_strength(fe); + + if (*status & FE_HAS_CARRIER) + read_snr(fe); + else + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + if (*status & FE_HAS_SYNC) + read_ber(fe); + else { + p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + return 0; +} + +static int tune(struct dvb_frontend *fe, bool re_tune, + unsigned int mode_flags, + unsigned int *delay, enum fe_status *status) +{ + struct mxl *state = fe->demodulator_priv; + int r = 0; + + *delay = HZ / 2; + if (re_tune) { + r = set_parameters(fe); + if (r) + return r; + state->tune_time = jiffies; + return 0; + } + if (*status & FE_HAS_LOCK) + return 0; + + r = read_status(fe, status); + if (r) + return r; + + return 0; +} + +static enum fe_code_rate conv_fec(enum MXL_HYDRA_FEC_E fec) +{ + enum fe_code_rate fec2fec[11] = { + FEC_NONE, FEC_1_2, FEC_3_5, FEC_2_3, + FEC_3_4, FEC_4_5, FEC_5_6, FEC_6_7, + FEC_7_8, FEC_8_9, FEC_9_10 + }; + + if (fec > MXL_HYDRA_FEC_9_10) + return FEC_NONE; + return fec2fec[fec]; +} + +static int get_frontend(struct dvb_frontend *fe, + struct dtv_frontend_properties *p) +{ + struct mxl *state = fe->demodulator_priv; + u32 reg_data[MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE]; + u32 freq; + + mutex_lock(&state->base->status_lock); + HYDRA_DEMOD_STATUS_LOCK(state, state->demod); + read_register_block(state, + (HYDRA_DMD_STANDARD_ADDR_OFFSET + + HYDRA_DMD_STATUS_OFFSET(state->demod)), + (MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE * 4), /* 25 * 4 bytes */ + (u8 *) ®_data[0]); + /* read demod channel parameters */ + read_register_block(state, + (HYDRA_DMD_STATUS_CENTER_FREQ_IN_KHZ_ADDR + + HYDRA_DMD_STATUS_OFFSET(state->demod)), + (4), /* 4 bytes */ + (u8 *) &freq); + HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod); + mutex_unlock(&state->base->status_lock); + + dev_dbg(state->i2cdev, "freq=%u delsys=%u srate=%u\n", + freq * 1000, reg_data[DMD_STANDARD_ADDR], + reg_data[DMD_SYMBOL_RATE_ADDR]); + p->symbol_rate = reg_data[DMD_SYMBOL_RATE_ADDR]; + p->frequency = freq; + /* + * p->delivery_system = + * (MXL_HYDRA_BCAST_STD_E) regData[DMD_STANDARD_ADDR]; + * p->inversion = + * (MXL_HYDRA_SPECTRUM_E) regData[DMD_SPECTRUM_INVERSION_ADDR]; + * freqSearchRangeKHz = + * (regData[DMD_FREQ_SEARCH_RANGE_IN_KHZ_ADDR]); + */ + + p->fec_inner = conv_fec(reg_data[DMD_FEC_CODE_RATE_ADDR]); + switch (p->delivery_system) { + case SYS_DSS: + break; + case SYS_DVBS2: + switch ((enum MXL_HYDRA_PILOTS_E) + reg_data[DMD_DVBS2_PILOT_ON_OFF_ADDR]) { + case MXL_HYDRA_PILOTS_OFF: + p->pilot = PILOT_OFF; + break; + case MXL_HYDRA_PILOTS_ON: + p->pilot = PILOT_ON; + break; + default: + break; + } + case SYS_DVBS: + switch ((enum MXL_HYDRA_MODULATION_E) + reg_data[DMD_MODULATION_SCHEME_ADDR]) { + case MXL_HYDRA_MOD_QPSK: + p->modulation = QPSK; + break; + case MXL_HYDRA_MOD_8PSK: + p->modulation = PSK_8; + break; + default: + break; + } + switch ((enum MXL_HYDRA_ROLLOFF_E) + reg_data[DMD_SPECTRUM_ROLL_OFF_ADDR]) { + case MXL_HYDRA_ROLLOFF_0_20: + p->rolloff = ROLLOFF_20; + break; + case MXL_HYDRA_ROLLOFF_0_35: + p->rolloff = ROLLOFF_35; + break; + case MXL_HYDRA_ROLLOFF_0_25: + p->rolloff = ROLLOFF_25; + break; + default: + break; + } + break; + default: + return -EINVAL; + } + return 0; +} + +static int set_input(struct dvb_frontend *fe, int input) +{ + struct mxl *state = fe->demodulator_priv; + + state->tuner = input; + return 0; +} + +static struct dvb_frontend_ops mxl_ops = { + .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, + .info = { + .name = "MaxLinear MxL5xx DVB-S/S2 tuner-demodulator", + .frequency_min = 300000, + .frequency_max = 2350000, + .frequency_stepsize = 0, + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_2G_MODULATION + }, + .init = init, + .release = release, + .get_frontend_algo = get_algo, + .tune = tune, + .read_status = read_status, + .sleep = sleep, + .get_frontend = get_frontend, + .diseqc_send_master_cmd = send_master_cmd, +}; + +static struct mxl_base *match_base(struct i2c_adapter *i2c, u8 adr) +{ + struct mxl_base *p; + + list_for_each_entry(p, &mxllist, mxllist) + if (p->i2c == i2c && p->adr == adr) + return p; + return NULL; +} + +static void cfg_dev_xtal(struct mxl *state, u32 freq, u32 cap, u32 enable) +{ + if (state->base->can_clkout || !enable) + update_by_mnemonic(state, 0x90200054, 23, 1, enable); + + if (freq == 24000000) + write_register(state, HYDRA_CRYSTAL_SETTING, 0); + else + write_register(state, HYDRA_CRYSTAL_SETTING, 1); + + write_register(state, HYDRA_CRYSTAL_CAP, cap); +} + +static u32 get_big_endian(u8 num_of_bits, const u8 buf[]) +{ + u32 ret_value = 0; + + switch (num_of_bits) { + case 24: + ret_value = (((u32) buf[0]) << 16) | + (((u32) buf[1]) << 8) | buf[2]; + break; + case 32: + ret_value = (((u32) buf[0]) << 24) | + (((u32) buf[1]) << 16) | + (((u32) buf[2]) << 8) | buf[3]; + break; + default: + break; + } + + return ret_value; +} + +static int write_fw_segment(struct mxl *state, + u32 mem_addr, u32 total_size, u8 *data_ptr) +{ + int status; + u32 data_count = 0; + u32 size = 0; + u32 orig_size = 0; + u8 *w_buf_ptr = NULL; + u32 block_size = ((MXL_HYDRA_OEM_MAX_BLOCK_WRITE_LENGTH - + (MXL_HYDRA_I2C_HDR_SIZE + + MXL_HYDRA_REG_SIZE_IN_BYTES)) / 4) * 4; + u8 w_msg_buffer[MXL_HYDRA_OEM_MAX_BLOCK_WRITE_LENGTH - + (MXL_HYDRA_I2C_HDR_SIZE + MXL_HYDRA_REG_SIZE_IN_BYTES)]; + + do { + size = orig_size = (((u32)(data_count + block_size)) > total_size) ? + (total_size - data_count) : block_size; + + if (orig_size & 3) + size = (orig_size + 4) & ~3; + w_buf_ptr = &w_msg_buffer[0]; + memset((void *) w_buf_ptr, 0, size); + memcpy((void *) w_buf_ptr, (void *) data_ptr, orig_size); + convert_endian(1, size, w_buf_ptr); + status = write_firmware_block(state, mem_addr, size, w_buf_ptr); + if (status) + return status; + data_count += size; + mem_addr += size; + data_ptr += size; + } while (data_count < total_size); + + return status; +} + +static int do_firmware_download(struct mxl *state, u8 *mbin_buffer_ptr, + u32 mbin_buffer_size) + +{ + int status; + u32 index = 0; + u32 seg_length = 0; + u32 seg_address = 0; + struct MBIN_FILE_T *mbin_ptr = (struct MBIN_FILE_T *)mbin_buffer_ptr; + struct MBIN_SEGMENT_T *segment_ptr; + enum MXL_BOOL_E xcpu_fw_flag = MXL_FALSE; + + if (mbin_ptr->header.id != MBIN_FILE_HEADER_ID) { + dev_err(state->i2cdev, "%s: Invalid file header ID (%c)\n", + __func__, mbin_ptr->header.id); + return -EINVAL; + } + status = write_register(state, FW_DL_SIGN_ADDR, 0); + if (status) + return status; + segment_ptr = (struct MBIN_SEGMENT_T *) (&mbin_ptr->data[0]); + for (index = 0; index < mbin_ptr->header.num_segments; index++) { + if (segment_ptr->header.id != MBIN_SEGMENT_HEADER_ID) { + dev_err(state->i2cdev, "%s: Invalid segment header ID (%c)\n", + __func__, segment_ptr->header.id); + return -EINVAL; + } + seg_length = get_big_endian(24, + &(segment_ptr->header.len24[0])); + seg_address = get_big_endian(32, + &(segment_ptr->header.address[0])); + + if (state->base->type == MXL_HYDRA_DEVICE_568) { + if ((((seg_address & 0x90760000) == 0x90760000) || + ((seg_address & 0x90740000) == 0x90740000)) && + (xcpu_fw_flag == MXL_FALSE)) { + update_by_mnemonic(state, 0x8003003C, 0, 1, 1); + msleep(200); + write_register(state, 0x90720000, 0); + usleep_range(10000, 11000); + xcpu_fw_flag = MXL_TRUE; + } + status = write_fw_segment(state, seg_address, + seg_length, + (u8 *) segment_ptr->data); + } else { + if (((seg_address & 0x90760000) != 0x90760000) && + ((seg_address & 0x90740000) != 0x90740000)) + status = write_fw_segment(state, seg_address, + seg_length, (u8 *) segment_ptr->data); + } + if (status) + return status; + segment_ptr = (struct MBIN_SEGMENT_T *) + &(segment_ptr->data[((seg_length + 3) / 4) * 4]); + } + return status; +} + +static int check_fw(struct mxl *state, u8 *mbin, u32 mbin_len) +{ + struct MBIN_FILE_HEADER_T *fh = (struct MBIN_FILE_HEADER_T *) mbin; + u32 flen = (fh->image_size24[0] << 16) | + (fh->image_size24[1] << 8) | fh->image_size24[2]; + u8 *fw, cs = 0; + u32 i; + + if (fh->id != 'M' || fh->fmt_version != '1' || flen > 0x3FFF0) { + dev_info(state->i2cdev, "Invalid FW Header\n"); + return -1; + } + fw = mbin + sizeof(struct MBIN_FILE_HEADER_T); + for (i = 0; i < flen; i += 1) + cs += fw[i]; + if (cs != fh->image_checksum) { + dev_info(state->i2cdev, "Invalid FW Checksum\n"); + return -1; + } + return 0; +} + +static int firmware_download(struct mxl *state, u8 *mbin, u32 mbin_len) +{ + int status; + u32 reg_data = 0; + struct MXL_HYDRA_SKU_COMMAND_T dev_sku_cfg; + u8 cmd_size = sizeof(struct MXL_HYDRA_SKU_COMMAND_T); + u8 cmd_buff[sizeof(struct MXL_HYDRA_SKU_COMMAND_T) + 6]; + + if (check_fw(state, mbin, mbin_len)) + return -1; + + /* put CPU into reset */ + status = update_by_mnemonic(state, 0x8003003C, 0, 1, 0); + if (status) + return status; + usleep_range(1000, 2000); + + /* Reset TX FIFO's, BBAND, XBAR */ + status = write_register(state, HYDRA_RESET_TRANSPORT_FIFO_REG, + HYDRA_RESET_TRANSPORT_FIFO_DATA); + if (status) + return status; + status = write_register(state, HYDRA_RESET_BBAND_REG, + HYDRA_RESET_BBAND_DATA); + if (status) + return status; + status = write_register(state, HYDRA_RESET_XBAR_REG, + HYDRA_RESET_XBAR_DATA); + if (status) + return status; + + /* Disable clock to Baseband, Wideband, SerDes, + * Alias ext & Transport modules + */ + status = write_register(state, HYDRA_MODULES_CLK_2_REG, + HYDRA_DISABLE_CLK_2); + if (status) + return status; + /* Clear Software & Host interrupt status - (Clear on read) */ + status = read_register(state, HYDRA_PRCM_ROOT_CLK_REG, ®_data); + if (status) + return status; + status = do_firmware_download(state, mbin, mbin_len); + if (status) + return status; + + if (state->base->type == MXL_HYDRA_DEVICE_568) { + usleep_range(10000, 11000); + + /* bring XCPU out of reset */ + status = write_register(state, 0x90720000, 1); + if (status) + return status; + msleep(500); + + /* Enable XCPU UART message processing in MCPU */ + status = write_register(state, 0x9076B510, 1); + if (status) + return status; + } else { + /* Bring CPU out of reset */ + status = update_by_mnemonic(state, 0x8003003C, 0, 1, 1); + if (status) + return status; + /* Wait until FW boots */ + msleep(150); + } + + /* Initialize XPT XBAR */ + status = write_register(state, XPT_DMD0_BASEADDR, 0x76543210); + if (status) + return status; + + if (!firmware_is_alive(state)) + return -1; + + dev_info(state->i2cdev, "Hydra FW alive. Hail!\n"); + + /* sometimes register values are wrong shortly + * after first heart beats + */ + msleep(50); + + dev_sku_cfg.sku_type = state->base->sku_type; + BUILD_HYDRA_CMD(MXL_HYDRA_DEV_CFG_SKU_CMD, MXL_CMD_WRITE, + cmd_size, &dev_sku_cfg, cmd_buff); + status = send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE, + &cmd_buff[0]); + + return status; +} + +static int cfg_ts_pad_mux(struct mxl *state, enum MXL_BOOL_E enable_serial_ts) +{ + int status = 0; + u32 pad_mux_value = 0; + + if (enable_serial_ts == MXL_TRUE) { + pad_mux_value = 0; + if ((state->base->type == MXL_HYDRA_DEVICE_541) || + (state->base->type == MXL_HYDRA_DEVICE_541S)) + pad_mux_value = 2; + } else { + if ((state->base->type == MXL_HYDRA_DEVICE_581) || + (state->base->type == MXL_HYDRA_DEVICE_581S)) + pad_mux_value = 2; + else + pad_mux_value = 3; + } + + switch (state->base->type) { + case MXL_HYDRA_DEVICE_561: + case MXL_HYDRA_DEVICE_581: + case MXL_HYDRA_DEVICE_541: + case MXL_HYDRA_DEVICE_541S: + case MXL_HYDRA_DEVICE_561S: + case MXL_HYDRA_DEVICE_581S: + status |= update_by_mnemonic(state, 0x90000170, 24, 3, + pad_mux_value); + status |= update_by_mnemonic(state, 0x90000170, 28, 3, + pad_mux_value); + status |= update_by_mnemonic(state, 0x90000174, 0, 3, + pad_mux_value); + status |= update_by_mnemonic(state, 0x90000174, 4, 3, + pad_mux_value); + status |= update_by_mnemonic(state, 0x90000174, 8, 3, + pad_mux_value); + status |= update_by_mnemonic(state, 0x90000174, 12, 3, + pad_mux_value); + status |= update_by_mnemonic(state, 0x90000174, 16, 3, + pad_mux_value); + status |= update_by_mnemonic(state, 0x90000174, 20, 3, + pad_mux_value); + status |= update_by_mnemonic(state, 0x90000174, 24, 3, + pad_mux_value); + status |= update_by_mnemonic(state, 0x90000174, 28, 3, + pad_mux_value); + status |= update_by_mnemonic(state, 0x90000178, 0, 3, + pad_mux_value); + status |= update_by_mnemonic(state, 0x90000178, 4, 3, + pad_mux_value); + status |= update_by_mnemonic(state, 0x90000178, 8, 3, + pad_mux_value); + break; + + case MXL_HYDRA_DEVICE_544: + case MXL_HYDRA_DEVICE_542: + status |= update_by_mnemonic(state, 0x9000016C, 4, 3, 1); + status |= update_by_mnemonic(state, 0x9000016C, 8, 3, 0); + status |= update_by_mnemonic(state, 0x9000016C, 12, 3, 0); + status |= update_by_mnemonic(state, 0x9000016C, 16, 3, 0); + status |= update_by_mnemonic(state, 0x90000170, 0, 3, 0); + status |= update_by_mnemonic(state, 0x90000178, 12, 3, 1); + status |= update_by_mnemonic(state, 0x90000178, 16, 3, 1); + status |= update_by_mnemonic(state, 0x90000178, 20, 3, 1); + status |= update_by_mnemonic(state, 0x90000178, 24, 3, 1); + status |= update_by_mnemonic(state, 0x9000017C, 0, 3, 1); + status |= update_by_mnemonic(state, 0x9000017C, 4, 3, 1); + if (enable_serial_ts == MXL_ENABLE) { + status |= update_by_mnemonic(state, + 0x90000170, 4, 3, 0); + status |= update_by_mnemonic(state, + 0x90000170, 8, 3, 0); + status |= update_by_mnemonic(state, + 0x90000170, 12, 3, 0); + status |= update_by_mnemonic(state, + 0x90000170, 16, 3, 0); + status |= update_by_mnemonic(state, + 0x90000170, 20, 3, 1); + status |= update_by_mnemonic(state, + 0x90000170, 24, 3, 1); + status |= update_by_mnemonic(state, + 0x90000170, 28, 3, 2); + status |= update_by_mnemonic(state, + 0x90000174, 0, 3, 2); + status |= update_by_mnemonic(state, + 0x90000174, 4, 3, 2); + status |= update_by_mnemonic(state, + 0x90000174, 8, 3, 2); + status |= update_by_mnemonic(state, + 0x90000174, 12, 3, 2); + status |= update_by_mnemonic(state, + 0x90000174, 16, 3, 2); + status |= update_by_mnemonic(state, + 0x90000174, 20, 3, 2); + status |= update_by_mnemonic(state, + 0x90000174, 24, 3, 2); + status |= update_by_mnemonic(state, + 0x90000174, 28, 3, 2); + status |= update_by_mnemonic(state, + 0x90000178, 0, 3, 2); + status |= update_by_mnemonic(state, + 0x90000178, 4, 3, 2); + status |= update_by_mnemonic(state, + 0x90000178, 8, 3, 2); + } else { + status |= update_by_mnemonic(state, + 0x90000170, 4, 3, 3); + status |= update_by_mnemonic(state, + 0x90000170, 8, 3, 3); + status |= update_by_mnemonic(state, + 0x90000170, 12, 3, 3); + status |= update_by_mnemonic(state, + 0x90000170, 16, 3, 3); + status |= update_by_mnemonic(state, + 0x90000170, 20, 3, 3); + status |= update_by_mnemonic(state, + 0x90000170, 24, 3, 3); + status |= update_by_mnemonic(state, + 0x90000170, 28, 3, 3); + status |= update_by_mnemonic(state, + 0x90000174, 0, 3, 3); + status |= update_by_mnemonic(state, + 0x90000174, 4, 3, 3); + status |= update_by_mnemonic(state, + 0x90000174, 8, 3, 3); + status |= update_by_mnemonic(state, + 0x90000174, 12, 3, 3); + status |= update_by_mnemonic(state, + 0x90000174, 16, 3, 3); + status |= update_by_mnemonic(state, + 0x90000174, 20, 3, 1); + status |= update_by_mnemonic(state, + 0x90000174, 24, 3, 1); + status |= update_by_mnemonic(state, + 0x90000174, 28, 3, 1); + status |= update_by_mnemonic(state, + 0x90000178, 0, 3, 1); + status |= update_by_mnemonic(state, + 0x90000178, 4, 3, 1); + status |= update_by_mnemonic(state, + 0x90000178, 8, 3, 1); + } + break; + + case MXL_HYDRA_DEVICE_568: + if (enable_serial_ts == MXL_FALSE) { + status |= update_by_mnemonic(state, + 0x9000016C, 8, 3, 5); + status |= update_by_mnemonic(state, + 0x9000016C, 12, 3, 5); + status |= update_by_mnemonic(state, + 0x9000016C, 16, 3, 5); + status |= update_by_mnemonic(state, + 0x9000016C, 20, 3, 5); + status |= update_by_mnemonic(state, + 0x9000016C, 24, 3, 5); + status |= update_by_mnemonic(state, + 0x9000016C, 28, 3, 5); + status |= update_by_mnemonic(state, + 0x90000170, 0, 3, 5); + status |= update_by_mnemonic(state, + 0x90000170, 4, 3, 5); + status |= update_by_mnemonic(state, + 0x90000170, 8, 3, 5); + status |= update_by_mnemonic(state, + 0x90000170, 12, 3, 5); + status |= update_by_mnemonic(state, + 0x90000170, 16, 3, 5); + status |= update_by_mnemonic(state, + 0x90000170, 20, 3, 5); + + status |= update_by_mnemonic(state, + 0x90000170, 24, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 0, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 4, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 8, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 12, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 16, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 20, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 24, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 28, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000178, 0, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000178, 4, 3, pad_mux_value); + + status |= update_by_mnemonic(state, + 0x90000178, 8, 3, 5); + status |= update_by_mnemonic(state, + 0x90000178, 12, 3, 5); + status |= update_by_mnemonic(state, + 0x90000178, 16, 3, 5); + status |= update_by_mnemonic(state, + 0x90000178, 20, 3, 5); + status |= update_by_mnemonic(state, + 0x90000178, 24, 3, 5); + status |= update_by_mnemonic(state, + 0x90000178, 28, 3, 5); + status |= update_by_mnemonic(state, + 0x9000017C, 0, 3, 5); + status |= update_by_mnemonic(state, + 0x9000017C, 4, 3, 5); + } else { + status |= update_by_mnemonic(state, + 0x90000170, 4, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000170, 8, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000170, 12, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000170, 16, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000170, 20, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000170, 24, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000170, 28, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 0, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 4, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 8, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 12, 3, pad_mux_value); + } + break; + + + case MXL_HYDRA_DEVICE_584: + default: + status |= update_by_mnemonic(state, + 0x90000170, 4, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000170, 8, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000170, 12, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000170, 16, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000170, 20, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000170, 24, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000170, 28, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 0, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 4, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 8, 3, pad_mux_value); + status |= update_by_mnemonic(state, + 0x90000174, 12, 3, pad_mux_value); + break; + } + return status; +} + +static int set_drive_strength(struct mxl *state, + enum MXL_HYDRA_TS_DRIVE_STRENGTH_E ts_drive_strength) +{ + int stat = 0; + u32 val; + + read_register(state, 0x90000194, &val); + dev_info(state->i2cdev, "DIGIO = %08x\n", val); + dev_info(state->i2cdev, "set drive_strength = %u\n", ts_drive_strength); + + + stat |= update_by_mnemonic(state, 0x90000194, 0, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x90000194, 20, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x90000194, 24, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x90000198, 12, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x90000198, 16, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x90000198, 20, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x90000198, 24, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x9000019C, 0, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x9000019C, 4, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x9000019C, 8, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x9000019C, 24, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x9000019C, 28, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x900001A0, 0, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x900001A0, 4, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x900001A0, 20, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x900001A0, 24, 3, ts_drive_strength); + stat |= update_by_mnemonic(state, 0x900001A0, 28, 3, ts_drive_strength); + + return stat; +} + +static int enable_tuner(struct mxl *state, u32 tuner, u32 enable) +{ + int stat = 0; + struct MXL_HYDRA_TUNER_CMD ctrl_tuner_cmd; + u8 cmd_size = sizeof(ctrl_tuner_cmd); + u8 cmd_buff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN]; + u32 val, count = 10; + + ctrl_tuner_cmd.tuner_id = tuner; + ctrl_tuner_cmd.enable = enable; + BUILD_HYDRA_CMD(MXL_HYDRA_TUNER_ACTIVATE_CMD, MXL_CMD_WRITE, + cmd_size, &ctrl_tuner_cmd, cmd_buff); + stat = send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE, + &cmd_buff[0]); + if (stat) + return stat; + read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val); + while (--count && ((val >> tuner) & 1) != enable) { + msleep(20); + read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val); + } + if (!count) + return -1; + read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val); + dev_dbg(state->i2cdev, "tuner %u ready = %u\n", + tuner, (val >> tuner) & 1); + + return 0; +} + + +static int config_ts(struct mxl *state, enum MXL_HYDRA_DEMOD_ID_E demod_id, + struct MXL_HYDRA_MPEGOUT_PARAM_T *mpeg_out_param_ptr) +{ + int status = 0; + u32 nco_count_min = 0; + u32 clk_type = 0; + + struct MXL_REG_FIELD_T xpt_sync_polarity[MXL_HYDRA_DEMOD_MAX] = { + {0x90700010, 8, 1}, {0x90700010, 9, 1}, + {0x90700010, 10, 1}, {0x90700010, 11, 1}, + {0x90700010, 12, 1}, {0x90700010, 13, 1}, + {0x90700010, 14, 1}, {0x90700010, 15, 1} }; + struct MXL_REG_FIELD_T xpt_clock_polarity[MXL_HYDRA_DEMOD_MAX] = { + {0x90700010, 16, 1}, {0x90700010, 17, 1}, + {0x90700010, 18, 1}, {0x90700010, 19, 1}, + {0x90700010, 20, 1}, {0x90700010, 21, 1}, + {0x90700010, 22, 1}, {0x90700010, 23, 1} }; + struct MXL_REG_FIELD_T xpt_valid_polarity[MXL_HYDRA_DEMOD_MAX] = { + {0x90700014, 0, 1}, {0x90700014, 1, 1}, + {0x90700014, 2, 1}, {0x90700014, 3, 1}, + {0x90700014, 4, 1}, {0x90700014, 5, 1}, + {0x90700014, 6, 1}, {0x90700014, 7, 1} }; + struct MXL_REG_FIELD_T xpt_ts_clock_phase[MXL_HYDRA_DEMOD_MAX] = { + {0x90700018, 0, 3}, {0x90700018, 4, 3}, + {0x90700018, 8, 3}, {0x90700018, 12, 3}, + {0x90700018, 16, 3}, {0x90700018, 20, 3}, + {0x90700018, 24, 3}, {0x90700018, 28, 3} }; + struct MXL_REG_FIELD_T xpt_lsb_first[MXL_HYDRA_DEMOD_MAX] = { + {0x9070000C, 16, 1}, {0x9070000C, 17, 1}, + {0x9070000C, 18, 1}, {0x9070000C, 19, 1}, + {0x9070000C, 20, 1}, {0x9070000C, 21, 1}, + {0x9070000C, 22, 1}, {0x9070000C, 23, 1} }; + struct MXL_REG_FIELD_T xpt_sync_byte[MXL_HYDRA_DEMOD_MAX] = { + {0x90700010, 0, 1}, {0x90700010, 1, 1}, + {0x90700010, 2, 1}, {0x90700010, 3, 1}, + {0x90700010, 4, 1}, {0x90700010, 5, 1}, + {0x90700010, 6, 1}, {0x90700010, 7, 1} }; + struct MXL_REG_FIELD_T xpt_enable_output[MXL_HYDRA_DEMOD_MAX] = { + {0x9070000C, 0, 1}, {0x9070000C, 1, 1}, + {0x9070000C, 2, 1}, {0x9070000C, 3, 1}, + {0x9070000C, 4, 1}, {0x9070000C, 5, 1}, + {0x9070000C, 6, 1}, {0x9070000C, 7, 1} }; + struct MXL_REG_FIELD_T xpt_err_replace_sync[MXL_HYDRA_DEMOD_MAX] = { + {0x9070000C, 24, 1}, {0x9070000C, 25, 1}, + {0x9070000C, 26, 1}, {0x9070000C, 27, 1}, + {0x9070000C, 28, 1}, {0x9070000C, 29, 1}, + {0x9070000C, 30, 1}, {0x9070000C, 31, 1} }; + struct MXL_REG_FIELD_T xpt_err_replace_valid[MXL_HYDRA_DEMOD_MAX] = { + {0x90700014, 8, 1}, {0x90700014, 9, 1}, + {0x90700014, 10, 1}, {0x90700014, 11, 1}, + {0x90700014, 12, 1}, {0x90700014, 13, 1}, + {0x90700014, 14, 1}, {0x90700014, 15, 1} }; + struct MXL_REG_FIELD_T xpt_continuous_clock[MXL_HYDRA_DEMOD_MAX] = { + {0x907001D4, 0, 1}, {0x907001D4, 1, 1}, + {0x907001D4, 2, 1}, {0x907001D4, 3, 1}, + {0x907001D4, 4, 1}, {0x907001D4, 5, 1}, + {0x907001D4, 6, 1}, {0x907001D4, 7, 1} }; + struct MXL_REG_FIELD_T xpt_nco_clock_rate[MXL_HYDRA_DEMOD_MAX] = { + {0x90700044, 16, 80}, {0x90700044, 16, 81}, + {0x90700044, 16, 82}, {0x90700044, 16, 83}, + {0x90700044, 16, 84}, {0x90700044, 16, 85}, + {0x90700044, 16, 86}, {0x90700044, 16, 87} }; + + demod_id = state->base->ts_map[demod_id]; + + if (mpeg_out_param_ptr->enable == MXL_ENABLE) { + if (mpeg_out_param_ptr->mpeg_mode == + MXL_HYDRA_MPEG_MODE_PARALLEL) { + } else { + cfg_ts_pad_mux(state, MXL_TRUE); + update_by_mnemonic(state, + 0x90700010, 27, 1, MXL_FALSE); + } + } + + nco_count_min = + (u32)(MXL_HYDRA_NCO_CLK / mpeg_out_param_ptr->max_mpeg_clk_rate); + + if (state->base->chipversion >= 2) { + status |= update_by_mnemonic(state, + xpt_nco_clock_rate[demod_id].reg_addr, /* Reg Addr */ + xpt_nco_clock_rate[demod_id].lsb_pos, /* LSB pos */ + xpt_nco_clock_rate[demod_id].num_of_bits, /* Num of bits */ + nco_count_min); /* Data */ + } else + update_by_mnemonic(state, 0x90700044, 16, 8, nco_count_min); + + if (mpeg_out_param_ptr->mpeg_clk_type == MXL_HYDRA_MPEG_CLK_CONTINUOUS) + clk_type = 1; + + if (mpeg_out_param_ptr->mpeg_mode < MXL_HYDRA_MPEG_MODE_PARALLEL) { + status |= update_by_mnemonic(state, + xpt_continuous_clock[demod_id].reg_addr, + xpt_continuous_clock[demod_id].lsb_pos, + xpt_continuous_clock[demod_id].num_of_bits, + clk_type); + } else + update_by_mnemonic(state, 0x907001D4, 8, 1, clk_type); + + status |= update_by_mnemonic(state, + xpt_sync_polarity[demod_id].reg_addr, + xpt_sync_polarity[demod_id].lsb_pos, + xpt_sync_polarity[demod_id].num_of_bits, + mpeg_out_param_ptr->mpeg_sync_pol); + + status |= update_by_mnemonic(state, + xpt_valid_polarity[demod_id].reg_addr, + xpt_valid_polarity[demod_id].lsb_pos, + xpt_valid_polarity[demod_id].num_of_bits, + mpeg_out_param_ptr->mpeg_valid_pol); + + status |= update_by_mnemonic(state, + xpt_clock_polarity[demod_id].reg_addr, + xpt_clock_polarity[demod_id].lsb_pos, + xpt_clock_polarity[demod_id].num_of_bits, + mpeg_out_param_ptr->mpeg_clk_pol); + + status |= update_by_mnemonic(state, + xpt_sync_byte[demod_id].reg_addr, + xpt_sync_byte[demod_id].lsb_pos, + xpt_sync_byte[demod_id].num_of_bits, + mpeg_out_param_ptr->mpeg_sync_pulse_width); + + status |= update_by_mnemonic(state, + xpt_ts_clock_phase[demod_id].reg_addr, + xpt_ts_clock_phase[demod_id].lsb_pos, + xpt_ts_clock_phase[demod_id].num_of_bits, + mpeg_out_param_ptr->mpeg_clk_phase); + + status |= update_by_mnemonic(state, + xpt_lsb_first[demod_id].reg_addr, + xpt_lsb_first[demod_id].lsb_pos, + xpt_lsb_first[demod_id].num_of_bits, + mpeg_out_param_ptr->lsb_or_msb_first); + + switch (mpeg_out_param_ptr->mpeg_error_indication) { + case MXL_HYDRA_MPEG_ERR_REPLACE_SYNC: + status |= update_by_mnemonic(state, + xpt_err_replace_sync[demod_id].reg_addr, + xpt_err_replace_sync[demod_id].lsb_pos, + xpt_err_replace_sync[demod_id].num_of_bits, + MXL_TRUE); + status |= update_by_mnemonic(state, + xpt_err_replace_valid[demod_id].reg_addr, + xpt_err_replace_valid[demod_id].lsb_pos, + xpt_err_replace_valid[demod_id].num_of_bits, + MXL_FALSE); + break; + + case MXL_HYDRA_MPEG_ERR_REPLACE_VALID: + status |= update_by_mnemonic(state, + xpt_err_replace_sync[demod_id].reg_addr, + xpt_err_replace_sync[demod_id].lsb_pos, + xpt_err_replace_sync[demod_id].num_of_bits, + MXL_FALSE); + + status |= update_by_mnemonic(state, + xpt_err_replace_valid[demod_id].reg_addr, + xpt_err_replace_valid[demod_id].lsb_pos, + xpt_err_replace_valid[demod_id].num_of_bits, + MXL_TRUE); + break; + + case MXL_HYDRA_MPEG_ERR_INDICATION_DISABLED: + default: + status |= update_by_mnemonic(state, + xpt_err_replace_sync[demod_id].reg_addr, + xpt_err_replace_sync[demod_id].lsb_pos, + xpt_err_replace_sync[demod_id].num_of_bits, + MXL_FALSE); + + status |= update_by_mnemonic(state, + xpt_err_replace_valid[demod_id].reg_addr, + xpt_err_replace_valid[demod_id].lsb_pos, + xpt_err_replace_valid[demod_id].num_of_bits, + MXL_FALSE); + + break; + + } + + if (mpeg_out_param_ptr->mpeg_mode != MXL_HYDRA_MPEG_MODE_PARALLEL) { + status |= update_by_mnemonic(state, + xpt_enable_output[demod_id].reg_addr, + xpt_enable_output[demod_id].lsb_pos, + xpt_enable_output[demod_id].num_of_bits, + mpeg_out_param_ptr->enable); + } + return status; +} + +static int config_mux(struct mxl *state) +{ + update_by_mnemonic(state, 0x9070000C, 0, 1, 0); + update_by_mnemonic(state, 0x9070000C, 1, 1, 0); + update_by_mnemonic(state, 0x9070000C, 2, 1, 0); + update_by_mnemonic(state, 0x9070000C, 3, 1, 0); + update_by_mnemonic(state, 0x9070000C, 4, 1, 0); + update_by_mnemonic(state, 0x9070000C, 5, 1, 0); + update_by_mnemonic(state, 0x9070000C, 6, 1, 0); + update_by_mnemonic(state, 0x9070000C, 7, 1, 0); + update_by_mnemonic(state, 0x90700008, 0, 2, 1); + update_by_mnemonic(state, 0x90700008, 2, 2, 1); + return 0; +} + +static int load_fw(struct mxl *state, struct mxl5xx_cfg *cfg) +{ + int stat = 0; + u8 *buf; + + if (cfg->fw) + return firmware_download(state, cfg->fw, cfg->fw_len); + + if (!cfg->fw_read) + return -1; + + buf = vmalloc(0x40000); + if (!buf) + return -ENOMEM; + + cfg->fw_read(cfg->fw_priv, buf, 0x40000); + stat = firmware_download(state, buf, 0x40000); + vfree(buf); + + return stat; +} + +static int validate_sku(struct mxl *state) +{ + u32 pad_mux_bond = 0, prcm_chip_id = 0, prcm_so_cid = 0; + int status; + u32 type = state->base->type; + + status = read_by_mnemonic(state, 0x90000190, 0, 3, &pad_mux_bond); + status |= read_by_mnemonic(state, 0x80030000, 0, 12, &prcm_chip_id); + status |= read_by_mnemonic(state, 0x80030004, 24, 8, &prcm_so_cid); + if (status) + return -1; + + dev_info(state->i2cdev, "padMuxBond=%08x, prcmChipId=%08x, prcmSoCId=%08x\n", + pad_mux_bond, prcm_chip_id, prcm_so_cid); + + if (prcm_chip_id != 0x560) { + switch (pad_mux_bond) { + case MXL_HYDRA_SKU_ID_581: + if (type == MXL_HYDRA_DEVICE_581) + return 0; + if (type == MXL_HYDRA_DEVICE_581S) { + state->base->type = MXL_HYDRA_DEVICE_581; + return 0; + } + break; + case MXL_HYDRA_SKU_ID_584: + if (type == MXL_HYDRA_DEVICE_584) + return 0; + break; + case MXL_HYDRA_SKU_ID_544: + if (type == MXL_HYDRA_DEVICE_544) + return 0; + if (type == MXL_HYDRA_DEVICE_542) + return 0; + break; + case MXL_HYDRA_SKU_ID_582: + if (type == MXL_HYDRA_DEVICE_582) + return 0; + break; + default: + return -1; + } + } else { + + } + return -1; +} + +static int get_fwinfo(struct mxl *state) +{ + int status; + u32 val = 0; + + status = read_by_mnemonic(state, 0x90000190, 0, 3, &val); + if (status) + return status; + dev_info(state->i2cdev, "chipID=%08x\n", val); + + status = read_by_mnemonic(state, 0x80030004, 8, 8, &val); + if (status) + return status; + dev_info(state->i2cdev, "chipVer=%08x\n", val); + + status = read_register(state, HYDRA_FIRMWARE_VERSION, &val); + if (status) + return status; + dev_info(state->i2cdev, "FWVer=%08x\n", val); + + state->base->fwversion = val; + return status; +} + + +static u8 ts_map1_to_1[MXL_HYDRA_DEMOD_MAX] = { + MXL_HYDRA_DEMOD_ID_0, + MXL_HYDRA_DEMOD_ID_1, + MXL_HYDRA_DEMOD_ID_2, + MXL_HYDRA_DEMOD_ID_3, + MXL_HYDRA_DEMOD_ID_4, + MXL_HYDRA_DEMOD_ID_5, + MXL_HYDRA_DEMOD_ID_6, + MXL_HYDRA_DEMOD_ID_7, +}; + +static u8 ts_map54x[MXL_HYDRA_DEMOD_MAX] = { + MXL_HYDRA_DEMOD_ID_2, + MXL_HYDRA_DEMOD_ID_3, + MXL_HYDRA_DEMOD_ID_4, + MXL_HYDRA_DEMOD_ID_5, + MXL_HYDRA_DEMOD_MAX, + MXL_HYDRA_DEMOD_MAX, + MXL_HYDRA_DEMOD_MAX, + MXL_HYDRA_DEMOD_MAX, +}; + +static int probe(struct mxl *state, struct mxl5xx_cfg *cfg) +{ + u32 chipver; + int fw, status, j; + struct MXL_HYDRA_MPEGOUT_PARAM_T mpeg_interface_cfg; + + state->base->ts_map = ts_map1_to_1; + + switch (state->base->type) { + case MXL_HYDRA_DEVICE_581: + case MXL_HYDRA_DEVICE_581S: + state->base->can_clkout = 1; + state->base->demod_num = 8; + state->base->tuner_num = 1; + state->base->sku_type = MXL_HYDRA_SKU_TYPE_581; + break; + case MXL_HYDRA_DEVICE_582: + state->base->can_clkout = 1; + state->base->demod_num = 8; + state->base->tuner_num = 3; + state->base->sku_type = MXL_HYDRA_SKU_TYPE_582; + break; + case MXL_HYDRA_DEVICE_585: + state->base->can_clkout = 0; + state->base->demod_num = 8; + state->base->tuner_num = 4; + state->base->sku_type = MXL_HYDRA_SKU_TYPE_585; + break; + case MXL_HYDRA_DEVICE_544: + state->base->can_clkout = 0; + state->base->demod_num = 4; + state->base->tuner_num = 4; + state->base->sku_type = MXL_HYDRA_SKU_TYPE_544; + state->base->ts_map = ts_map54x; + break; + case MXL_HYDRA_DEVICE_541: + case MXL_HYDRA_DEVICE_541S: + state->base->can_clkout = 0; + state->base->demod_num = 4; + state->base->tuner_num = 1; + state->base->sku_type = MXL_HYDRA_SKU_TYPE_541; + state->base->ts_map = ts_map54x; + break; + case MXL_HYDRA_DEVICE_561: + case MXL_HYDRA_DEVICE_561S: + state->base->can_clkout = 0; + state->base->demod_num = 6; + state->base->tuner_num = 1; + state->base->sku_type = MXL_HYDRA_SKU_TYPE_561; + break; + case MXL_HYDRA_DEVICE_568: + state->base->can_clkout = 0; + state->base->demod_num = 8; + state->base->tuner_num = 1; + state->base->chan_bond = 1; + state->base->sku_type = MXL_HYDRA_SKU_TYPE_568; + break; + case MXL_HYDRA_DEVICE_542: + state->base->can_clkout = 1; + state->base->demod_num = 4; + state->base->tuner_num = 3; + state->base->sku_type = MXL_HYDRA_SKU_TYPE_542; + state->base->ts_map = ts_map54x; + break; + case MXL_HYDRA_DEVICE_TEST: + case MXL_HYDRA_DEVICE_584: + default: + state->base->can_clkout = 0; + state->base->demod_num = 8; + state->base->tuner_num = 4; + state->base->sku_type = MXL_HYDRA_SKU_TYPE_584; + break; + } + + status = validate_sku(state); + if (status) + return status; + + update_by_mnemonic(state, 0x80030014, 9, 1, 1); + update_by_mnemonic(state, 0x8003003C, 12, 1, 1); + status = read_by_mnemonic(state, 0x80030000, 12, 4, &chipver); + if (status) + state->base->chipversion = 0; + else + state->base->chipversion = (chipver == 2) ? 2 : 1; + dev_info(state->i2cdev, "Hydra chip version %u\n", + state->base->chipversion); + + cfg_dev_xtal(state, cfg->clk, cfg->cap, 0); + + fw = firmware_is_alive(state); + if (!fw) { + status = load_fw(state, cfg); + if (status) + return status; + } + get_fwinfo(state); + + config_mux(state); + mpeg_interface_cfg.enable = MXL_ENABLE; + mpeg_interface_cfg.lsb_or_msb_first = MXL_HYDRA_MPEG_SERIAL_MSB_1ST; + /* supports only (0-104&139)MHz */ + if (cfg->ts_clk) + mpeg_interface_cfg.max_mpeg_clk_rate = cfg->ts_clk; + else + mpeg_interface_cfg.max_mpeg_clk_rate = 69; /* 139; */ + mpeg_interface_cfg.mpeg_clk_phase = MXL_HYDRA_MPEG_CLK_PHASE_SHIFT_0_DEG; + mpeg_interface_cfg.mpeg_clk_pol = MXL_HYDRA_MPEG_CLK_IN_PHASE; + /* MXL_HYDRA_MPEG_CLK_GAPPED; */ + mpeg_interface_cfg.mpeg_clk_type = MXL_HYDRA_MPEG_CLK_CONTINUOUS; + mpeg_interface_cfg.mpeg_error_indication = + MXL_HYDRA_MPEG_ERR_INDICATION_DISABLED; + mpeg_interface_cfg.mpeg_mode = MXL_HYDRA_MPEG_MODE_SERIAL_3_WIRE; + mpeg_interface_cfg.mpeg_sync_pol = MXL_HYDRA_MPEG_ACTIVE_HIGH; + mpeg_interface_cfg.mpeg_sync_pulse_width = MXL_HYDRA_MPEG_SYNC_WIDTH_BIT; + mpeg_interface_cfg.mpeg_valid_pol = MXL_HYDRA_MPEG_ACTIVE_HIGH; + + for (j = 0; j < state->base->demod_num; j++) { + status = config_ts(state, (enum MXL_HYDRA_DEMOD_ID_E) j, + &mpeg_interface_cfg); + if (status) + return status; + } + set_drive_strength(state, 1); + return 0; +} + +struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c, + struct mxl5xx_cfg *cfg, u32 demod, u32 tuner, + int (**fn_set_input)(struct dvb_frontend *, int)) +{ + struct mxl *state; + struct mxl_base *base; + + state = kzalloc(sizeof(struct mxl), GFP_KERNEL); + if (!state) + return NULL; + + state->demod = demod; + state->tuner = tuner; + state->tuner_in_use = 0xffffffff; + state->i2cdev = &i2c->dev; + + base = match_base(i2c, cfg->adr); + if (base) { + base->count++; + if (base->count > base->demod_num) + goto fail; + state->base = base; + } else { + base = kzalloc(sizeof(struct mxl_base), GFP_KERNEL); + if (!base) + goto fail; + base->i2c = i2c; + base->adr = cfg->adr; + base->type = cfg->type; + base->count = 1; + mutex_init(&base->i2c_lock); + mutex_init(&base->status_lock); + mutex_init(&base->tune_lock); + INIT_LIST_HEAD(&base->mxls); + + state->base = base; + if (probe(state, cfg) < 0) { + kfree(base); + goto fail; + } + list_add(&base->mxllist, &mxllist); + } + state->fe.ops = mxl_ops; + state->xbar[0] = 4; + state->xbar[1] = demod; + state->xbar[2] = 8; + state->fe.demodulator_priv = state; + *fn_set_input = set_input; + + list_add(&state->mxl, &base->mxls); + return &state->fe; + +fail: + kfree(state); + return NULL; +} +EXPORT_SYMBOL_GPL(mxl5xx_attach); + +MODULE_DESCRIPTION("MaxLinear MxL5xx DVB-S/S2 tuner-demodulator driver"); +MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/mxl5xx.h b/drivers/media/dvb-frontends/mxl5xx.h new file mode 100644 index 000000000000..532e08111537 --- /dev/null +++ b/drivers/media/dvb-frontends/mxl5xx.h @@ -0,0 +1,41 @@ +#ifndef _MXL5XX_H_ +#define _MXL5XX_H_ + +#include <linux/types.h> +#include <linux/i2c.h> + +#include "dvb_frontend.h" + +struct mxl5xx_cfg { + u8 adr; + u8 type; + u32 cap; + u32 clk; + u32 ts_clk; + + u8 *fw; + u32 fw_len; + + int (*fw_read)(void *priv, u8 *buf, u32 len); + void *fw_priv; +}; + +#if IS_REACHABLE(CONFIG_DVB_MXL5XX) + +extern struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c, + struct mxl5xx_cfg *cfg, u32 demod, u32 tuner, + int (**fn_set_input)(struct dvb_frontend *, int)); + +#else + +static inline struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c, + struct mxl5xx_cfg *cfg, u32 demod, u32 tuner, + int (**fn_set_input)(struct dvb_frontend *, int)) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif /* CONFIG_DVB_MXL5XX */ + +#endif /* _MXL5XX_H_ */ diff --git a/drivers/media/dvb-frontends/mxl5xx_defs.h b/drivers/media/dvb-frontends/mxl5xx_defs.h new file mode 100644 index 000000000000..fd9e61e0188f --- /dev/null +++ b/drivers/media/dvb-frontends/mxl5xx_defs.h @@ -0,0 +1,731 @@ +/* + * Defines for the Maxlinear MX58x family of tuners/demods + * + * Copyright (C) 2014 Digital Devices GmbH + * + * based on code: + * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved + * which was released under GPL V2 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + */ + +enum MXL_BOOL_E { + MXL_DISABLE = 0, + MXL_ENABLE = 1, + + MXL_FALSE = 0, + MXL_TRUE = 1, + + MXL_INVALID = 0, + MXL_VALID = 1, + + MXL_NO = 0, + MXL_YES = 1, + + MXL_OFF = 0, + MXL_ON = 1 +}; + +/* Firmware-Host Command IDs */ +enum MXL_HYDRA_HOST_CMD_ID_E { + /* --Device command IDs-- */ + MXL_HYDRA_DEV_NO_OP_CMD = 0, /* No OP */ + + MXL_HYDRA_DEV_SET_POWER_MODE_CMD = 1, + MXL_HYDRA_DEV_SET_OVERWRITE_DEF_CMD = 2, + + /* Host-used CMD, not used by firmware */ + MXL_HYDRA_DEV_FIRMWARE_DOWNLOAD_CMD = 3, + + /* Additional CONTROL types from DTV */ + MXL_HYDRA_DEV_SET_BROADCAST_PID_STB_ID_CMD = 4, + MXL_HYDRA_DEV_GET_PMM_SLEEP_CMD = 5, + + /* --Tuner command IDs-- */ + MXL_HYDRA_TUNER_TUNE_CMD = 6, + MXL_HYDRA_TUNER_GET_STATUS_CMD = 7, + + /* --Demod command IDs-- */ + MXL_HYDRA_DEMOD_SET_PARAM_CMD = 8, + MXL_HYDRA_DEMOD_GET_STATUS_CMD = 9, + + MXL_HYDRA_DEMOD_RESET_FEC_COUNTER_CMD = 10, + + MXL_HYDRA_DEMOD_SET_PKT_NUM_CMD = 11, + + MXL_HYDRA_DEMOD_SET_IQ_SOURCE_CMD = 12, + MXL_HYDRA_DEMOD_GET_IQ_DATA_CMD = 13, + + MXL_HYDRA_DEMOD_GET_M68HC05_VER_CMD = 14, + + MXL_HYDRA_DEMOD_SET_ERROR_COUNTER_MODE_CMD = 15, + + /* --- ABORT channel tune */ + MXL_HYDRA_ABORT_TUNE_CMD = 16, /* Abort current tune command. */ + + /* --SWM/FSK command IDs-- */ + MXL_HYDRA_FSK_RESET_CMD = 17, + MXL_HYDRA_FSK_MSG_CMD = 18, + MXL_HYDRA_FSK_SET_OP_MODE_CMD = 19, + + /* --DiSeqC command IDs-- */ + MXL_HYDRA_DISEQC_MSG_CMD = 20, + MXL_HYDRA_DISEQC_COPY_MSG_TO_MAILBOX = 21, + MXL_HYDRA_DISEQC_CFG_MSG_CMD = 22, + + /* --- FFT Debug Command IDs-- */ + MXL_HYDRA_REQ_FFT_SPECTRUM_CMD = 23, + + /* -- Demod scramblle code */ + MXL_HYDRA_DEMOD_SCRAMBLE_CODE_CMD = 24, + + /* ---For host to know how many commands in total */ + MXL_HYDRA_LAST_HOST_CMD = 25, + + MXL_HYDRA_DEMOD_INTR_TYPE_CMD = 47, + MXL_HYDRA_DEV_INTR_CLEAR_CMD = 48, + MXL_HYDRA_TUNER_SPECTRUM_REQ_CMD = 53, + MXL_HYDRA_TUNER_ACTIVATE_CMD = 55, + MXL_HYDRA_DEV_CFG_POWER_MODE_CMD = 56, + MXL_HYDRA_DEV_XTAL_CAP_CMD = 57, + MXL_HYDRA_DEV_CFG_SKU_CMD = 58, + MXL_HYDRA_TUNER_SPECTRUM_MIN_GAIN_CMD = 59, + MXL_HYDRA_DISEQC_CONT_TONE_CFG = 60, + MXL_HYDRA_DEV_RF_WAKE_UP_CMD = 61, + MXL_HYDRA_DEMOD_CFG_EQ_CTRL_PARAM_CMD = 62, + MXL_HYDRA_DEMOD_FREQ_OFFSET_SEARCH_RANGE_CMD = 63, + MXL_HYDRA_DEV_REQ_PWR_FROM_ADCRSSI_CMD = 64, + + MXL_XCPU_PID_FLT_CFG_CMD = 65, + MXL_XCPU_SHMEM_TEST_CMD = 66, + MXL_XCPU_ABORT_TUNE_CMD = 67, + MXL_XCPU_CHAN_TUNE_CMD = 68, + MXL_XCPU_FLT_BOND_HDRS_CMD = 69, + + MXL_HYDRA_DEV_BROADCAST_WAKE_UP_CMD = 70, + MXL_HYDRA_FSK_CFG_FSK_FREQ_CMD = 71, + MXL_HYDRA_FSK_POWER_DOWN_CMD = 72, + MXL_XCPU_CLEAR_CB_STATS_CMD = 73, + MXL_XCPU_CHAN_BOND_RESTART_CMD = 74 +}; + +#define MXL_ENABLE_BIG_ENDIAN (0) + +#define MXL_HYDRA_OEM_MAX_BLOCK_WRITE_LENGTH 248 + +#define MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN (248) + +#define MXL_HYDRA_CAP_MIN 10 +#define MXL_HYDRA_CAP_MAX 33 + +#define MXL_HYDRA_PLID_REG_READ 0xFB /* Read register PLID */ +#define MXL_HYDRA_PLID_REG_WRITE 0xFC /* Write register PLID */ + +#define MXL_HYDRA_PLID_CMD_READ 0xFD /* Command Read PLID */ +#define MXL_HYDRA_PLID_CMD_WRITE 0xFE /* Command Write PLID */ + +#define MXL_HYDRA_REG_SIZE_IN_BYTES 4 /* Hydra register size in bytes */ +#define MXL_HYDRA_I2C_HDR_SIZE (2 * sizeof(u8)) /* PLID + LEN(0xFF) */ +#define MXL_HYDRA_CMD_HEADER_SIZE (MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE) + +#define MXL_HYDRA_SKU_ID_581 0 +#define MXL_HYDRA_SKU_ID_584 1 +#define MXL_HYDRA_SKU_ID_585 2 +#define MXL_HYDRA_SKU_ID_544 3 +#define MXL_HYDRA_SKU_ID_561 4 +#define MXL_HYDRA_SKU_ID_582 5 +#define MXL_HYDRA_SKU_ID_568 6 + +/* macro for register write data buffer size + * (PLID + LEN (0xFF) + RegAddr + RegData) + */ +#define MXL_HYDRA_REG_WRITE_LEN (MXL_HYDRA_I2C_HDR_SIZE + (2 * MXL_HYDRA_REG_SIZE_IN_BYTES)) + +/* macro to extract a single byte from 4-byte(32-bit) data */ +#define GET_BYTE(x, n) (((x) >> (8*(n))) & 0xFF) + +#define MAX_CMD_DATA 512 + +#define MXL_GET_REG_MASK_32(lsb_loc, num_of_bits) ((0xFFFFFFFF >> (32 - (num_of_bits))) << (lsb_loc)) + +#define FW_DL_SIGN (0xDEADBEEF) + +#define MBIN_FORMAT_VERSION '1' +#define MBIN_FILE_HEADER_ID 'M' +#define MBIN_SEGMENT_HEADER_ID 'S' +#define MBIN_MAX_FILE_LENGTH (1<<23) + +struct MBIN_FILE_HEADER_T { + u8 id; + u8 fmt_version; + u8 header_len; + u8 num_segments; + u8 entry_address[4]; + u8 image_size24[3]; + u8 image_checksum; + u8 reserved[4]; +}; + +struct MBIN_FILE_T { + struct MBIN_FILE_HEADER_T header; + u8 data[1]; +}; + +struct MBIN_SEGMENT_HEADER_T { + u8 id; + u8 len24[3]; + u8 address[4]; +}; + +struct MBIN_SEGMENT_T { + struct MBIN_SEGMENT_HEADER_T header; + u8 data[1]; +}; + +enum MXL_CMD_TYPE_E { MXL_CMD_WRITE = 0, MXL_CMD_READ }; + +#define BUILD_HYDRA_CMD(cmd_id, req_type, size, data_ptr, cmd_buff) \ + do { \ + cmd_buff[0] = ((req_type == MXL_CMD_WRITE) ? MXL_HYDRA_PLID_CMD_WRITE : MXL_HYDRA_PLID_CMD_READ); \ + cmd_buff[1] = (size > 251) ? 0xff : (u8) (size + 4); \ + cmd_buff[2] = size; \ + cmd_buff[3] = cmd_id; \ + cmd_buff[4] = 0x00; \ + cmd_buff[5] = 0x00; \ + convert_endian(MXL_ENABLE_BIG_ENDIAN, size, (u8 *)data_ptr); \ + memcpy((void *)&cmd_buff[6], data_ptr, size); \ + } while (0) + +struct MXL_REG_FIELD_T { + u32 reg_addr; + u8 lsb_pos; + u8 num_of_bits; +}; + +struct MXL_DEV_CMD_DATA_T { + u32 data_size; + u8 data[MAX_CMD_DATA]; +}; + +enum MXL_HYDRA_SKU_TYPE_E { + MXL_HYDRA_SKU_TYPE_MIN = 0x00, + MXL_HYDRA_SKU_TYPE_581 = 0x00, + MXL_HYDRA_SKU_TYPE_584 = 0x01, + MXL_HYDRA_SKU_TYPE_585 = 0x02, + MXL_HYDRA_SKU_TYPE_544 = 0x03, + MXL_HYDRA_SKU_TYPE_561 = 0x04, + MXL_HYDRA_SKU_TYPE_5XX = 0x05, + MXL_HYDRA_SKU_TYPE_5YY = 0x06, + MXL_HYDRA_SKU_TYPE_511 = 0x07, + MXL_HYDRA_SKU_TYPE_561_DE = 0x08, + MXL_HYDRA_SKU_TYPE_582 = 0x09, + MXL_HYDRA_SKU_TYPE_541 = 0x0A, + MXL_HYDRA_SKU_TYPE_568 = 0x0B, + MXL_HYDRA_SKU_TYPE_542 = 0x0C, + MXL_HYDRA_SKU_TYPE_MAX = 0x0D, +}; + +struct MXL_HYDRA_SKU_COMMAND_T { + enum MXL_HYDRA_SKU_TYPE_E sku_type; +}; + +enum MXL_HYDRA_DEMOD_ID_E { + MXL_HYDRA_DEMOD_ID_0 = 0, + MXL_HYDRA_DEMOD_ID_1, + MXL_HYDRA_DEMOD_ID_2, + MXL_HYDRA_DEMOD_ID_3, + MXL_HYDRA_DEMOD_ID_4, + MXL_HYDRA_DEMOD_ID_5, + MXL_HYDRA_DEMOD_ID_6, + MXL_HYDRA_DEMOD_ID_7, + MXL_HYDRA_DEMOD_MAX +}; + +#define MXL_DEMOD_SCRAMBLE_SEQ_LEN 12 + +#define MAX_STEP_SIZE_24_XTAL_102_05_KHZ 195 +#define MAX_STEP_SIZE_24_XTAL_204_10_KHZ 215 +#define MAX_STEP_SIZE_24_XTAL_306_15_KHZ 203 +#define MAX_STEP_SIZE_24_XTAL_408_20_KHZ 177 + +#define MAX_STEP_SIZE_27_XTAL_102_05_KHZ 195 +#define MAX_STEP_SIZE_27_XTAL_204_10_KHZ 215 +#define MAX_STEP_SIZE_27_XTAL_306_15_KHZ 203 +#define MAX_STEP_SIZE_27_XTAL_408_20_KHZ 177 + +#define MXL_HYDRA_SPECTRUM_MIN_FREQ_KHZ 300000 +#define MXL_HYDRA_SPECTRUM_MAX_FREQ_KHZ 2350000 + +enum MXL_DEMOD_CHAN_PARAMS_OFFSET_E { + DMD_STANDARD_ADDR = 0, + DMD_SPECTRUM_INVERSION_ADDR, + DMD_SPECTRUM_ROLL_OFF_ADDR, + DMD_SYMBOL_RATE_ADDR, + DMD_MODULATION_SCHEME_ADDR, + DMD_FEC_CODE_RATE_ADDR, + DMD_SNR_ADDR, + DMD_FREQ_OFFSET_ADDR, + DMD_CTL_FREQ_OFFSET_ADDR, + DMD_STR_FREQ_OFFSET_ADDR, + DMD_FTL_FREQ_OFFSET_ADDR, + DMD_STR_NBC_SYNC_LOCK_ADDR, + DMD_CYCLE_SLIP_COUNT_ADDR, + DMD_DISPLAY_IQ_ADDR, + DMD_DVBS2_CRC_ERRORS_ADDR, + DMD_DVBS2_PER_COUNT_ADDR, + DMD_DVBS2_PER_WINDOW_ADDR, + DMD_DVBS_CORR_RS_ERRORS_ADDR, + DMD_DVBS_UNCORR_RS_ERRORS_ADDR, + DMD_DVBS_BER_COUNT_ADDR, + DMD_DVBS_BER_WINDOW_ADDR, + DMD_TUNER_ID_ADDR, + DMD_DVBS2_PILOT_ON_OFF_ADDR, + DMD_FREQ_SEARCH_RANGE_IN_KHZ_ADDR, + + MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE, +}; + +enum MXL_HYDRA_TUNER_ID_E { + MXL_HYDRA_TUNER_ID_0 = 0, + MXL_HYDRA_TUNER_ID_1, + MXL_HYDRA_TUNER_ID_2, + MXL_HYDRA_TUNER_ID_3, + MXL_HYDRA_TUNER_MAX +}; + +enum MXL_HYDRA_BCAST_STD_E { + MXL_HYDRA_DSS = 0, + MXL_HYDRA_DVBS, + MXL_HYDRA_DVBS2, +}; + +enum MXL_HYDRA_FEC_E { + MXL_HYDRA_FEC_AUTO = 0, + MXL_HYDRA_FEC_1_2, + MXL_HYDRA_FEC_3_5, + MXL_HYDRA_FEC_2_3, + MXL_HYDRA_FEC_3_4, + MXL_HYDRA_FEC_4_5, + MXL_HYDRA_FEC_5_6, + MXL_HYDRA_FEC_6_7, + MXL_HYDRA_FEC_7_8, + MXL_HYDRA_FEC_8_9, + MXL_HYDRA_FEC_9_10, +}; + +enum MXL_HYDRA_MODULATION_E { + MXL_HYDRA_MOD_AUTO = 0, + MXL_HYDRA_MOD_QPSK, + MXL_HYDRA_MOD_8PSK +}; + +enum MXL_HYDRA_SPECTRUM_E { + MXL_HYDRA_SPECTRUM_AUTO = 0, + MXL_HYDRA_SPECTRUM_INVERTED, + MXL_HYDRA_SPECTRUM_NON_INVERTED, +}; + +enum MXL_HYDRA_ROLLOFF_E { + MXL_HYDRA_ROLLOFF_AUTO = 0, + MXL_HYDRA_ROLLOFF_0_20, + MXL_HYDRA_ROLLOFF_0_25, + MXL_HYDRA_ROLLOFF_0_35 +}; + +enum MXL_HYDRA_PILOTS_E { + MXL_HYDRA_PILOTS_OFF = 0, + MXL_HYDRA_PILOTS_ON, + MXL_HYDRA_PILOTS_AUTO +}; + +enum MXL_HYDRA_CONSTELLATION_SRC_E { + MXL_HYDRA_FORMATTER = 0, + MXL_HYDRA_LEGACY_FEC, + MXL_HYDRA_FREQ_RECOVERY, + MXL_HYDRA_NBC, + MXL_HYDRA_CTL, + MXL_HYDRA_EQ, +}; + +struct MXL_HYDRA_DEMOD_LOCK_T { + int agc_lock; /* AGC lock info */ + int fec_lock; /* Demod FEC block lock info */ +}; + +struct MXL_HYDRA_DEMOD_STATUS_DVBS_T { + u32 rs_errors; /* RS decoder err counter */ + u32 ber_window; /* Ber Windows */ + u32 ber_count; /* BER count */ + u32 ber_window_iter1; /* Ber Windows - post viterbi */ + u32 ber_count_iter1; /* BER count - post viterbi */ +}; + +struct MXL_HYDRA_DEMOD_STATUS_DSS_T { + u32 rs_errors; /* RS decoder err counter */ + u32 ber_window; /* Ber Windows */ + u32 ber_count; /* BER count */ +}; + +struct MXL_HYDRA_DEMOD_STATUS_DVBS2_T { + u32 crc_errors; /* CRC error counter */ + u32 packet_error_count; /* Number of packet errors */ + u32 total_packets; /* Total packets */ +}; + +struct MXL_HYDRA_DEMOD_STATUS_T { + enum MXL_HYDRA_BCAST_STD_E standard_mask; /* Standard DVB-S, DVB-S2 or DSS */ + + union { + struct MXL_HYDRA_DEMOD_STATUS_DVBS_T demod_status_dvbs; /* DVB-S demod status */ + struct MXL_HYDRA_DEMOD_STATUS_DVBS2_T demod_status_dvbs2; /* DVB-S2 demod status */ + struct MXL_HYDRA_DEMOD_STATUS_DSS_T demod_status_dss; /* DSS demod status */ + } u; +}; + +struct MXL_HYDRA_DEMOD_SIG_OFFSET_INFO_T { + s32 carrier_offset_in_hz; /* CRL offset info */ + s32 symbol_offset_in_symbol; /* SRL offset info */ +}; + +struct MXL_HYDRA_DEMOD_SCRAMBLE_INFO_T { + u8 scramble_sequence[MXL_DEMOD_SCRAMBLE_SEQ_LEN]; /* scramble sequence */ + u32 scramble_code; /* scramble gold code */ +}; + +enum MXL_HYDRA_SPECTRUM_STEP_SIZE_E { + MXL_HYDRA_STEP_SIZE_24_XTAL_102_05KHZ, /* 102.05 KHz for 24 MHz XTAL */ + MXL_HYDRA_STEP_SIZE_24_XTAL_204_10KHZ, /* 204.10 KHz for 24 MHz XTAL */ + MXL_HYDRA_STEP_SIZE_24_XTAL_306_15KHZ, /* 306.15 KHz for 24 MHz XTAL */ + MXL_HYDRA_STEP_SIZE_24_XTAL_408_20KHZ, /* 408.20 KHz for 24 MHz XTAL */ + + MXL_HYDRA_STEP_SIZE_27_XTAL_102_05KHZ, /* 102.05 KHz for 27 MHz XTAL */ + MXL_HYDRA_STEP_SIZE_27_XTAL_204_35KHZ, /* 204.35 KHz for 27 MHz XTAL */ + MXL_HYDRA_STEP_SIZE_27_XTAL_306_52KHZ, /* 306.52 KHz for 27 MHz XTAL */ + MXL_HYDRA_STEP_SIZE_27_XTAL_408_69KHZ, /* 408.69 KHz for 27 MHz XTAL */ +}; + +enum MXL_HYDRA_SPECTRUM_RESOLUTION_E { + MXL_HYDRA_SPECTRUM_RESOLUTION_00_1_DB, /* 0.1 dB */ + MXL_HYDRA_SPECTRUM_RESOLUTION_01_0_DB, /* 1.0 dB */ + MXL_HYDRA_SPECTRUM_RESOLUTION_05_0_DB, /* 5.0 dB */ + MXL_HYDRA_SPECTRUM_RESOLUTION_10_0_DB, /* 10 dB */ +}; + +enum MXL_HYDRA_SPECTRUM_ERROR_CODE_E { + MXL_SPECTRUM_NO_ERROR, + MXL_SPECTRUM_INVALID_PARAMETER, + MXL_SPECTRUM_INVALID_STEP_SIZE, + MXL_SPECTRUM_BW_CANNOT_BE_COVERED, + MXL_SPECTRUM_DEMOD_BUSY, + MXL_SPECTRUM_TUNER_NOT_ENABLED, +}; + +struct MXL_HYDRA_SPECTRUM_REQ_T { + u32 tuner_index; /* TUNER Ctrl: one of MXL58x_TUNER_ID_E */ + u32 demod_index; /* DEMOD Ctrl: one of MXL58x_DEMOD_ID_E */ + enum MXL_HYDRA_SPECTRUM_STEP_SIZE_E step_size_in_khz; + u32 starting_freq_ink_hz; + u32 total_steps; + enum MXL_HYDRA_SPECTRUM_RESOLUTION_E spectrum_division; +}; + +enum MXL_HYDRA_SEARCH_FREQ_OFFSET_TYPE_E { + MXL_HYDRA_SEARCH_MAX_OFFSET = 0, /* DMD searches for max freq offset (i.e. 5MHz) */ + MXL_HYDRA_SEARCH_BW_PLUS_ROLLOFF, /* DMD searches for BW + ROLLOFF/2 */ +}; + +struct MXL58X_CFG_FREQ_OFF_SEARCH_RANGE_T { + u32 demod_index; + enum MXL_HYDRA_SEARCH_FREQ_OFFSET_TYPE_E search_type; +}; + +/* there are two slices + * slice0 - TS0, TS1, TS2 & TS3 + * slice1 - TS4, TS5, TS6 & TS7 + */ +#define MXL_HYDRA_TS_SLICE_MAX 2 + +#define MAX_FIXED_PID_NUM 32 + +#define MXL_HYDRA_NCO_CLK 418 /* 418 MHz */ + +#define MXL_HYDRA_MAX_TS_CLOCK 139 /* 139 MHz */ + +#define MXL_HYDRA_TS_FIXED_PID_FILT_SIZE 32 + +#define MXL_HYDRA_SHARED_PID_FILT_SIZE_DEFAULT 33 /* Shared PID filter size in 1-1 mux mode */ +#define MXL_HYDRA_SHARED_PID_FILT_SIZE_2_TO_1 66 /* Shared PID filter size in 2-1 mux mode */ +#define MXL_HYDRA_SHARED_PID_FILT_SIZE_4_TO_1 132 /* Shared PID filter size in 4-1 mux mode */ + +enum MXL_HYDRA_PID_BANK_TYPE_E { + MXL_HYDRA_SOFTWARE_PID_BANK = 0, + MXL_HYDRA_HARDWARE_PID_BANK, +}; + +enum MXL_HYDRA_TS_MUX_MODE_E { + MXL_HYDRA_TS_MUX_PID_REMAP = 0, + MXL_HYDRA_TS_MUX_PREFIX_EXTRA_HEADER = 1, +}; + +enum MXL_HYDRA_TS_MUX_TYPE_E { + MXL_HYDRA_TS_MUX_DISABLE = 0, /* No Mux ( 1 TSIF to 1 TSIF) */ + MXL_HYDRA_TS_MUX_2_TO_1, /* Mux 2 TSIF to 1 TSIF */ + MXL_HYDRA_TS_MUX_4_TO_1, /* Mux 4 TSIF to 1 TSIF */ +}; + +enum MXL_HYDRA_TS_GROUP_E { + MXL_HYDRA_TS_GROUP_0_3 = 0, /* TS group 0 to 3 (TS0, TS1, TS2 & TS3) */ + MXL_HYDRA_TS_GROUP_4_7, /* TS group 0 to 3 (TS4, TS5, TS6 & TS7) */ +}; + +enum MXL_HYDRA_TS_PID_FLT_CTRL_E { + MXL_HYDRA_TS_PIDS_ALLOW_ALL = 0, /* Allow all pids */ + MXL_HYDRA_TS_PIDS_DROP_ALL, /* Drop all pids */ + MXL_HYDRA_TS_INVALIDATE_PID_FILTER, /* Delete current PD filter in the device */ +}; + +enum MXL_HYDRA_TS_PID_TYPE_E { + MXL_HYDRA_TS_PID_FIXED = 0, + MXL_HYDRA_TS_PID_REGULAR, +}; + +struct MXL_HYDRA_TS_PID_T { + u16 original_pid; /* pid from TS */ + u16 remapped_pid; /* remapped pid */ + enum MXL_BOOL_E enable; /* enable or disable pid */ + enum MXL_BOOL_E allow_or_drop; /* allow or drop pid */ + enum MXL_BOOL_E enable_pid_remap; /* enable or disable pid remap */ + u8 bond_id; /* Bond ID in A0 always 0 - Only for 568 Sku */ + u8 dest_id; /* Output port ID for the PID - Only for 568 Sku */ +}; + +struct MXL_HYDRA_TS_MUX_PREFIX_HEADER_T { + enum MXL_BOOL_E enable; + u8 num_byte; + u8 header[12]; +}; + +enum MXL_HYDRA_PID_FILTER_BANK_E { + MXL_HYDRA_PID_BANK_A = 0, + MXL_HYDRA_PID_BANK_B, +}; + +enum MXL_HYDRA_MPEG_DATA_FMT_E { + MXL_HYDRA_MPEG_SERIAL_MSB_1ST = 0, + MXL_HYDRA_MPEG_SERIAL_LSB_1ST, + + MXL_HYDRA_MPEG_SYNC_WIDTH_BIT = 0, + MXL_HYDRA_MPEG_SYNC_WIDTH_BYTE +}; + +enum MXL_HYDRA_MPEG_MODE_E { + MXL_HYDRA_MPEG_MODE_SERIAL_4_WIRE = 0, /* MPEG 4 Wire serial mode */ + MXL_HYDRA_MPEG_MODE_SERIAL_3_WIRE, /* MPEG 3 Wire serial mode */ + MXL_HYDRA_MPEG_MODE_SERIAL_2_WIRE, /* MPEG 2 Wire serial mode */ + MXL_HYDRA_MPEG_MODE_PARALLEL /* MPEG parallel mode - valid only for MxL581 */ +}; + +enum MXL_HYDRA_MPEG_CLK_TYPE_E { + MXL_HYDRA_MPEG_CLK_CONTINUOUS = 0, /* Continuous MPEG clock */ + MXL_HYDRA_MPEG_CLK_GAPPED, /* Gapped (gated) MPEG clock */ +}; + +enum MXL_HYDRA_MPEG_CLK_FMT_E { + MXL_HYDRA_MPEG_ACTIVE_LOW = 0, + MXL_HYDRA_MPEG_ACTIVE_HIGH, + + MXL_HYDRA_MPEG_CLK_NEGATIVE = 0, + MXL_HYDRA_MPEG_CLK_POSITIVE, + + MXL_HYDRA_MPEG_CLK_IN_PHASE = 0, + MXL_HYDRA_MPEG_CLK_INVERTED, +}; + +enum MXL_HYDRA_MPEG_CLK_PHASE_E { + MXL_HYDRA_MPEG_CLK_PHASE_SHIFT_0_DEG = 0, + MXL_HYDRA_MPEG_CLK_PHASE_SHIFT_90_DEG, + MXL_HYDRA_MPEG_CLK_PHASE_SHIFT_180_DEG, + MXL_HYDRA_MPEG_CLK_PHASE_SHIFT_270_DEG +}; + +enum MXL_HYDRA_MPEG_ERR_INDICATION_E { + MXL_HYDRA_MPEG_ERR_REPLACE_SYNC = 0, + MXL_HYDRA_MPEG_ERR_REPLACE_VALID, + MXL_HYDRA_MPEG_ERR_INDICATION_DISABLED +}; + +struct MXL_HYDRA_MPEGOUT_PARAM_T { + int enable; /* Enable or Disable MPEG OUT */ + enum MXL_HYDRA_MPEG_CLK_TYPE_E mpeg_clk_type; /* Continuous or gapped */ + enum MXL_HYDRA_MPEG_CLK_FMT_E mpeg_clk_pol; /* MPEG Clk polarity */ + u8 max_mpeg_clk_rate; /* Max MPEG Clk rate (0 - 104 MHz, 139 MHz) */ + enum MXL_HYDRA_MPEG_CLK_PHASE_E mpeg_clk_phase; /* MPEG Clk phase */ + enum MXL_HYDRA_MPEG_DATA_FMT_E lsb_or_msb_first; /* LSB first or MSB first in TS transmission */ + enum MXL_HYDRA_MPEG_DATA_FMT_E mpeg_sync_pulse_width; /* MPEG SYNC pulse width (1-bit or 1-byte) */ + enum MXL_HYDRA_MPEG_CLK_FMT_E mpeg_valid_pol; /* MPEG VALID polarity */ + enum MXL_HYDRA_MPEG_CLK_FMT_E mpeg_sync_pol; /* MPEG SYNC polarity */ + enum MXL_HYDRA_MPEG_MODE_E mpeg_mode; /* config 4/3/2-wire serial or parallel TS out */ + enum MXL_HYDRA_MPEG_ERR_INDICATION_E mpeg_error_indication; /* Enable or Disable MPEG error indication */ +}; + +enum MXL_HYDRA_EXT_TS_IN_ID_E { + MXL_HYDRA_EXT_TS_IN_0 = 0, + MXL_HYDRA_EXT_TS_IN_1, + MXL_HYDRA_EXT_TS_IN_2, + MXL_HYDRA_EXT_TS_IN_3, + MXL_HYDRA_EXT_TS_IN_MAX +}; + +enum MXL_HYDRA_TS_OUT_ID_E { + MXL_HYDRA_TS_OUT_0 = 0, + MXL_HYDRA_TS_OUT_1, + MXL_HYDRA_TS_OUT_2, + MXL_HYDRA_TS_OUT_3, + MXL_HYDRA_TS_OUT_4, + MXL_HYDRA_TS_OUT_5, + MXL_HYDRA_TS_OUT_6, + MXL_HYDRA_TS_OUT_7, + MXL_HYDRA_TS_OUT_MAX +}; + +enum MXL_HYDRA_TS_DRIVE_STRENGTH_E { + MXL_HYDRA_TS_DRIVE_STRENGTH_1X = 0, + MXL_HYDRA_TS_DRIVE_STRENGTH_2X, + MXL_HYDRA_TS_DRIVE_STRENGTH_3X, + MXL_HYDRA_TS_DRIVE_STRENGTH_4X, + MXL_HYDRA_TS_DRIVE_STRENGTH_5X, + MXL_HYDRA_TS_DRIVE_STRENGTH_6X, + MXL_HYDRA_TS_DRIVE_STRENGTH_7X, + MXL_HYDRA_TS_DRIVE_STRENGTH_8X +}; + +enum MXL_HYDRA_DEVICE_E { + MXL_HYDRA_DEVICE_581 = 0, + MXL_HYDRA_DEVICE_584, + MXL_HYDRA_DEVICE_585, + MXL_HYDRA_DEVICE_544, + MXL_HYDRA_DEVICE_561, + MXL_HYDRA_DEVICE_TEST, + MXL_HYDRA_DEVICE_582, + MXL_HYDRA_DEVICE_541, + MXL_HYDRA_DEVICE_568, + MXL_HYDRA_DEVICE_542, + MXL_HYDRA_DEVICE_541S, + MXL_HYDRA_DEVICE_561S, + MXL_HYDRA_DEVICE_581S, + MXL_HYDRA_DEVICE_MAX +}; + +/* Demod IQ data */ +struct MXL_HYDRA_DEMOD_IQ_SRC_T { + u32 demod_id; + u32 source_of_iq; /* == 0, it means I/Q comes from Formatter + * == 1, Legacy FEC + * == 2, Frequency Recovery + * == 3, NBC + * == 4, CTL + * == 5, EQ + * == 6, FPGA + */ +}; + +struct MXL_HYDRA_DEMOD_ABORT_TUNE_T { + u32 demod_id; +}; + +struct MXL_HYDRA_TUNER_CMD { + u8 tuner_id; + u8 enable; +}; + +/* Demod Para for Channel Tune */ +struct MXL_HYDRA_DEMOD_PARAM_T { + u32 tuner_index; + u32 demod_index; + u32 frequency_in_hz; /* Frequency */ + u32 standard; /* one of MXL_HYDRA_BCAST_STD_E */ + u32 spectrum_inversion; /* Input : Spectrum inversion. */ + u32 roll_off; /* rollOff (alpha) factor */ + u32 symbol_rate_in_hz; /* Symbol rate */ + u32 pilots; /* TRUE = pilots enabled */ + u32 modulation_scheme; /* Input : Modulation Scheme is one of MXL_HYDRA_MODULATION_E */ + u32 fec_code_rate; /* Input : Forward error correction rate. Is one of MXL_HYDRA_FEC_E */ + u32 max_carrier_offset_in_mhz; /* Maximum carrier freq offset in MHz. Same as freqSearchRangeKHz, but in unit of MHz. */ +}; + +struct MXL_HYDRA_DEMOD_SCRAMBLE_CODE_T { + u32 demod_index; + u8 scramble_sequence[12]; /* scramble sequence */ + u32 scramble_code; /* scramble gold code */ +}; + +struct MXL_INTR_CFG_T { + u32 intr_type; + u32 intr_duration_in_nano_secs; + u32 intr_mask; +}; + +struct MXL_HYDRA_POWER_MODE_CMD { + u8 power_mode; /* enumeration values are defined in MXL_HYDRA_PWR_MODE_E (device API.h) */ +}; + +struct MXL_HYDRA_RF_WAKEUP_PARAM_T { + u32 time_interval_in_seconds; /* in seconds */ + u32 tuner_index; + s32 rssi_threshold; +}; + +struct MXL_HYDRA_RF_WAKEUP_CFG_T { + u32 tuner_count; + struct MXL_HYDRA_RF_WAKEUP_PARAM_T params; +}; + +enum MXL_HYDRA_AUX_CTRL_MODE_E { + MXL_HYDRA_AUX_CTRL_MODE_FSK = 0, /* Select FSK controller */ + MXL_HYDRA_AUX_CTRL_MODE_DISEQC, /* Select DiSEqC controller */ +}; + +enum MXL_HYDRA_DISEQC_OPMODE_E { + MXL_HYDRA_DISEQC_ENVELOPE_MODE = 0, + MXL_HYDRA_DISEQC_TONE_MODE, +}; + +enum MXL_HYDRA_DISEQC_VER_E { + MXL_HYDRA_DISEQC_1_X = 0, /* Config DiSEqC 1.x mode */ + MXL_HYDRA_DISEQC_2_X, /* Config DiSEqC 2.x mode */ + MXL_HYDRA_DISEQC_DISABLE /* Disable DiSEqC */ +}; + +enum MXL_HYDRA_DISEQC_CARRIER_FREQ_E { + MXL_HYDRA_DISEQC_CARRIER_FREQ_22KHZ = 0, /* DiSEqC signal frequency of 22 KHz */ + MXL_HYDRA_DISEQC_CARRIER_FREQ_33KHZ, /* DiSEqC signal frequency of 33 KHz */ + MXL_HYDRA_DISEQC_CARRIER_FREQ_44KHZ /* DiSEqC signal frequency of 44 KHz */ +}; + +enum MXL_HYDRA_DISEQC_ID_E { + MXL_HYDRA_DISEQC_ID_0 = 0, + MXL_HYDRA_DISEQC_ID_1, + MXL_HYDRA_DISEQC_ID_2, + MXL_HYDRA_DISEQC_ID_3 +}; + +enum MXL_HYDRA_FSK_OP_MODE_E { + MXL_HYDRA_FSK_CFG_TYPE_39KPBS = 0, /* 39.0kbps */ + MXL_HYDRA_FSK_CFG_TYPE_39_017KPBS, /* 39.017kbps */ + MXL_HYDRA_FSK_CFG_TYPE_115_2KPBS /* 115.2kbps */ +}; + +struct MXL58X_DSQ_OP_MODE_T { + u32 diseqc_id; /* DSQ 0, 1, 2 or 3 */ + u32 op_mode; /* Envelope mode (0) or internal tone mode (1) */ + u32 version; /* 0: 1.0, 1: 1.1, 2: Disable */ + u32 center_freq; /* 0: 22KHz, 1: 33KHz and 2: 44 KHz */ +}; + +struct MXL_HYDRA_DISEQC_CFG_CONT_TONE_T { + u32 diseqc_id; + u32 cont_tone_flag; /* 1: Enable , 0: Disable */ +}; diff --git a/drivers/media/dvb-frontends/mxl5xx_regs.h b/drivers/media/dvb-frontends/mxl5xx_regs.h new file mode 100644 index 000000000000..5001dafe1ba8 --- /dev/null +++ b/drivers/media/dvb-frontends/mxl5xx_regs.h @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved + * + * License type: GPLv2 + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * This program may alternatively be licensed under a proprietary license from + * MaxLinear, Inc. + * + */ + +#ifndef __MXL58X_REGISTERS_H__ +#define __MXL58X_REGISTERS_H__ + +#define HYDRA_INTR_STATUS_REG 0x80030008 +#define HYDRA_INTR_MASK_REG 0x8003000C + +#define HYDRA_CRYSTAL_SETTING 0x3FFFC5F0 /* 0 - 24 MHz & 1 - 27 MHz */ +#define HYDRA_CRYSTAL_CAP 0x3FFFEDA4 /* 0 - 24 MHz & 1 - 27 MHz */ + +#define HYDRA_CPU_RESET_REG 0x8003003C +#define HYDRA_CPU_RESET_DATA 0x00000400 + +#define HYDRA_RESET_TRANSPORT_FIFO_REG 0x80030028 +#define HYDRA_RESET_TRANSPORT_FIFO_DATA 0x00000000 + +#define HYDRA_RESET_BBAND_REG 0x80030024 +#define HYDRA_RESET_BBAND_DATA 0x00000000 + +#define HYDRA_RESET_XBAR_REG 0x80030020 +#define HYDRA_RESET_XBAR_DATA 0x00000000 + +#define HYDRA_MODULES_CLK_1_REG 0x80030014 +#define HYDRA_DISABLE_CLK_1 0x00000000 + +#define HYDRA_MODULES_CLK_2_REG 0x8003001C +#define HYDRA_DISABLE_CLK_2 0x0000000B + +#define HYDRA_PRCM_ROOT_CLK_REG 0x80030018 +#define HYDRA_PRCM_ROOT_CLK_DISABLE 0x00000000 + +#define HYDRA_CPU_RESET_CHECK_REG 0x80030008 +#define HYDRA_CPU_RESET_CHECK_OFFSET 0x40000000 /* <bit 30> */ + +#define HYDRA_SKU_ID_REG 0x90000190 + +#define FW_DL_SIGN_ADDR 0x3FFFEAE0 + +/* Register to check if FW is running or not */ +#define HYDRA_HEAR_BEAT 0x3FFFEDDC + +/* Firmware version */ +#define HYDRA_FIRMWARE_VERSION 0x3FFFEDB8 +#define HYDRA_FW_RC_VERSION 0x3FFFCFAC + +/* Firmware patch version */ +#define HYDRA_FIRMWARE_PATCH_VERSION 0x3FFFEDC2 + +/* SOC operating temperature in C */ +#define HYDRA_TEMPARATURE 0x3FFFEDB4 + +/* Demod & Tuner status registers */ +/* Demod 0 status base address */ +#define HYDRA_DEMOD_0_BASE_ADDR 0x3FFFC64C + +/* Tuner 0 status base address */ +#define HYDRA_TUNER_0_BASE_ADDR 0x3FFFCE4C + +#define POWER_FROM_ADCRSSI_READBACK 0x3FFFEB6C + +/* Macros to determine base address of respective demod or tuner */ +#define HYDRA_DMD_STATUS_OFFSET(demodID) ((demodID) * 0x100) +#define HYDRA_TUNER_STATUS_OFFSET(tunerID) ((tunerID) * 0x40) + +/* Demod status address offset from respective demod's base address */ +#define HYDRA_DMD_AGC_DIG_LEVEL_ADDR_OFFSET 0x3FFFC64C +#define HYDRA_DMD_LOCK_STATUS_ADDR_OFFSET 0x3FFFC650 +#define HYDRA_DMD_ACQ_STATUS_ADDR_OFFSET 0x3FFFC654 + +#define HYDRA_DMD_STANDARD_ADDR_OFFSET 0x3FFFC658 +#define HYDRA_DMD_SPECTRUM_INVERSION_ADDR_OFFSET 0x3FFFC65C +#define HYDRA_DMD_SPECTRUM_ROLL_OFF_ADDR_OFFSET 0x3FFFC660 +#define HYDRA_DMD_SYMBOL_RATE_ADDR_OFFSET 0x3FFFC664 +#define HYDRA_DMD_MODULATION_SCHEME_ADDR_OFFSET 0x3FFFC668 +#define HYDRA_DMD_FEC_CODE_RATE_ADDR_OFFSET 0x3FFFC66C + +#define HYDRA_DMD_SNR_ADDR_OFFSET 0x3FFFC670 +#define HYDRA_DMD_FREQ_OFFSET_ADDR_OFFSET 0x3FFFC674 +#define HYDRA_DMD_CTL_FREQ_OFFSET_ADDR_OFFSET 0x3FFFC678 +#define HYDRA_DMD_STR_FREQ_OFFSET_ADDR_OFFSET 0x3FFFC67C +#define HYDRA_DMD_FTL_FREQ_OFFSET_ADDR_OFFSET 0x3FFFC680 +#define HYDRA_DMD_STR_NBC_SYNC_LOCK_ADDR_OFFSET 0x3FFFC684 +#define HYDRA_DMD_CYCLE_SLIP_COUNT_ADDR_OFFSET 0x3FFFC688 + +#define HYDRA_DMD_DISPLAY_I_ADDR_OFFSET 0x3FFFC68C +#define HYDRA_DMD_DISPLAY_Q_ADDR_OFFSET 0x3FFFC68E + +#define HYDRA_DMD_DVBS2_CRC_ERRORS_ADDR_OFFSET 0x3FFFC690 +#define HYDRA_DMD_DVBS2_PER_COUNT_ADDR_OFFSET 0x3FFFC694 +#define HYDRA_DMD_DVBS2_PER_WINDOW_ADDR_OFFSET 0x3FFFC698 + +#define HYDRA_DMD_DVBS_CORR_RS_ERRORS_ADDR_OFFSET 0x3FFFC69C +#define HYDRA_DMD_DVBS_UNCORR_RS_ERRORS_ADDR_OFFSET 0x3FFFC6A0 +#define HYDRA_DMD_DVBS_BER_COUNT_ADDR_OFFSET 0x3FFFC6A4 +#define HYDRA_DMD_DVBS_BER_WINDOW_ADDR_OFFSET 0x3FFFC6A8 + +/* Debug-purpose DVB-S DMD 0 */ +#define HYDRA_DMD_DVBS_1ST_CORR_RS_ERRORS_ADDR_OFFSET 0x3FFFC6C8 /* corrected RS Errors: 1st iteration */ +#define HYDRA_DMD_DVBS_1ST_UNCORR_RS_ERRORS_ADDR_OFFSET 0x3FFFC6CC /* uncorrected RS Errors: 1st iteration */ +#define HYDRA_DMD_DVBS_BER_COUNT_1ST_ADDR_OFFSET 0x3FFFC6D0 +#define HYDRA_DMD_DVBS_BER_WINDOW_1ST_ADDR_OFFSET 0x3FFFC6D4 + +#define HYDRA_DMD_TUNER_ID_ADDR_OFFSET 0x3FFFC6AC +#define HYDRA_DMD_DVBS2_PILOT_ON_OFF_ADDR_OFFSET 0x3FFFC6B0 +#define HYDRA_DMD_FREQ_SEARCH_RANGE_KHZ_ADDR_OFFSET 0x3FFFC6B4 +#define HYDRA_DMD_STATUS_LOCK_ADDR_OFFSET 0x3FFFC6B8 +#define HYDRA_DMD_STATUS_CENTER_FREQ_IN_KHZ_ADDR 0x3FFFC704 +#define HYDRA_DMD_STATUS_INPUT_POWER_ADDR 0x3FFFC708 + +/* DVB-S new scaled_BER_count for a new BER API, see HYDRA-1343 "DVB-S post viterbi information" */ +#define DMD0_STATUS_DVBS_1ST_SCALED_BER_COUNT_ADDR 0x3FFFC710 /* DMD 0: 1st iteration BER count scaled by HYDRA_BER_COUNT_SCALING_FACTOR */ +#define DMD0_STATUS_DVBS_SCALED_BER_COUNT_ADDR 0x3FFFC714 /* DMD 0: 2nd iteration BER count scaled by HYDRA_BER_COUNT_SCALING_FACTOR */ + +#define DMD0_SPECTRUM_MIN_GAIN_STATUS 0x3FFFC73C +#define DMD0_SPECTRUM_MIN_GAIN_WB_SAGC_VALUE 0x3FFFC740 +#define DMD0_SPECTRUM_MIN_GAIN_NB_SAGC_VALUE 0x3FFFC744 + +#define HYDRA_DMD_STATUS_END_ADDR_OFFSET 0x3FFFC748 + +/* Tuner status address offset from respective tuners's base address */ +#define HYDRA_TUNER_DEMOD_ID_ADDR_OFFSET 0x3FFFCE4C +#define HYDRA_TUNER_AGC_LOCK_OFFSET 0x3FFFCE50 +#define HYDRA_TUNER_SPECTRUM_STATUS_OFFSET 0x3FFFCE54 +#define HYDRA_TUNER_SPECTRUM_BIN_SIZE_OFFSET 0x3FFFCE58 +#define HYDRA_TUNER_SPECTRUM_ADDRESS_OFFSET 0x3FFFCE5C +#define HYDRA_TUNER_ENABLE_COMPLETE 0x3FFFEB78 + +#define HYDRA_DEMOD_STATUS_LOCK(devId, demodId) write_register(devId, (HYDRA_DMD_STATUS_LOCK_ADDR_OFFSET + HYDRA_DMD_STATUS_OFFSET(demodId)), MXL_YES) +#define HYDRA_DEMOD_STATUS_UNLOCK(devId, demodId) write_register(devId, (HYDRA_DMD_STATUS_LOCK_ADDR_OFFSET + HYDRA_DMD_STATUS_OFFSET(demodId)), MXL_NO) + +#define HYDRA_VERSION 0x3FFFEDB8 +#define HYDRA_DEMOD0_VERSION 0x3FFFEDBC +#define HYDRA_DEMOD1_VERSION 0x3FFFEDC0 +#define HYDRA_DEMOD2_VERSION 0x3FFFEDC4 +#define HYDRA_DEMOD3_VERSION 0x3FFFEDC8 +#define HYDRA_DEMOD4_VERSION 0x3FFFEDCC +#define HYDRA_DEMOD5_VERSION 0x3FFFEDD0 +#define HYDRA_DEMOD6_VERSION 0x3FFFEDD4 +#define HYDRA_DEMOD7_VERSION 0x3FFFEDD8 +#define HYDRA_HEAR_BEAT 0x3FFFEDDC +#define HYDRA_SKU_MGMT 0x3FFFEBC0 + +#define MXL_HYDRA_FPGA_A_ADDRESS 0x91C00000 +#define MXL_HYDRA_FPGA_B_ADDRESS 0x91D00000 + +/* TS control base address */ +#define HYDRA_TS_CTRL_BASE_ADDR 0x90700000 + +#define MPEG_MUX_MODE_SLICE0_REG (HYDRA_TS_CTRL_BASE_ADDR + 0x08) + +#define MPEG_MUX_MODE_SLICE1_REG (HYDRA_TS_CTRL_BASE_ADDR + 0x08) + +#define PID_BANK_SEL_SLICE0_REG (HYDRA_TS_CTRL_BASE_ADDR + 0x190) +#define PID_BANK_SEL_SLICE1_REG (HYDRA_TS_CTRL_BASE_ADDR + 0x1B0) + +#define MPEG_CLK_GATED_REG (HYDRA_TS_CTRL_BASE_ADDR + 0x20) + +#define MPEG_CLK_ALWAYS_ON_REG (HYDRA_TS_CTRL_BASE_ADDR + 0x1D4) + +#define HYDRA_REGULAR_PID_BANK_A_REG (HYDRA_TS_CTRL_BASE_ADDR + 0x190) + +#define HYDRA_FIXED_PID_BANK_A_REG (HYDRA_TS_CTRL_BASE_ADDR + 0x190) + +#define HYDRA_REGULAR_PID_BANK_B_REG (HYDRA_TS_CTRL_BASE_ADDR + 0x1B0) + +#define HYDRA_FIXED_PID_BANK_B_REG (HYDRA_TS_CTRL_BASE_ADDR + 0x1B0) + +#define FIXED_PID_TBL_REG_ADDRESS_0 (HYDRA_TS_CTRL_BASE_ADDR + 0x9000) +#define FIXED_PID_TBL_REG_ADDRESS_1 (HYDRA_TS_CTRL_BASE_ADDR + 0x9100) +#define FIXED_PID_TBL_REG_ADDRESS_2 (HYDRA_TS_CTRL_BASE_ADDR + 0x9200) +#define FIXED_PID_TBL_REG_ADDRESS_3 (HYDRA_TS_CTRL_BASE_ADDR + 0x9300) + +#define FIXED_PID_TBL_REG_ADDRESS_4 (HYDRA_TS_CTRL_BASE_ADDR + 0xB000) +#define FIXED_PID_TBL_REG_ADDRESS_5 (HYDRA_TS_CTRL_BASE_ADDR + 0xB100) +#define FIXED_PID_TBL_REG_ADDRESS_6 (HYDRA_TS_CTRL_BASE_ADDR + 0xB200) +#define FIXED_PID_TBL_REG_ADDRESS_7 (HYDRA_TS_CTRL_BASE_ADDR + 0xB300) + +#define REGULAR_PID_TBL_REG_ADDRESS_0 (HYDRA_TS_CTRL_BASE_ADDR + 0x8000) +#define REGULAR_PID_TBL_REG_ADDRESS_1 (HYDRA_TS_CTRL_BASE_ADDR + 0x8200) +#define REGULAR_PID_TBL_REG_ADDRESS_2 (HYDRA_TS_CTRL_BASE_ADDR + 0x8400) +#define REGULAR_PID_TBL_REG_ADDRESS_3 (HYDRA_TS_CTRL_BASE_ADDR + 0x8600) + +#define REGULAR_PID_TBL_REG_ADDRESS_4 (HYDRA_TS_CTRL_BASE_ADDR + 0xA000) +#define REGULAR_PID_TBL_REG_ADDRESS_5 (HYDRA_TS_CTRL_BASE_ADDR + 0xA200) +#define REGULAR_PID_TBL_REG_ADDRESS_6 (HYDRA_TS_CTRL_BASE_ADDR + 0xA400) +#define REGULAR_PID_TBL_REG_ADDRESS_7 (HYDRA_TS_CTRL_BASE_ADDR + 0xA600) + +/***************************************************************************/ + +#define PAD_MUX_GPIO_00_SYNC_BASEADDR 0x90000188 + + +#define PAD_MUX_UART_RX_C_PINMUX_BASEADDR 0x9000001C + +#define XPT_PACKET_GAP_MIN_BASEADDR 0x90700044 +#define XPT_NCO_COUNT_BASEADDR 0x90700238 + +#define XPT_NCO_COUNT_BASEADDR1 0x9070023C + +/* V2 DigRF status register */ + +#define XPT_PID_BASEADDR 0x90708000 + +#define XPT_PID_REMAP_BASEADDR 0x90708004 + +#define XPT_KNOWN_PID_BASEADDR 0x90709000 + +#define XPT_PID_BASEADDR1 0x9070A000 + +#define XPT_PID_REMAP_BASEADDR1 0x9070A004 + +#define XPT_KNOWN_PID_BASEADDR1 0x9070B000 + +#define XPT_BERT_LOCK_BASEADDR 0x907000B8 + +#define XPT_BERT_BASEADDR 0x907000BC + +#define XPT_BERT_INVERT_BASEADDR 0x907000C0 + +#define XPT_BERT_HEADER_BASEADDR 0x907000C4 + +#define XPT_BERT_BASEADDR1 0x907000C8 + +#define XPT_BERT_BIT_COUNT0_BASEADDR 0x907000CC + +#define XPT_BERT_BIT_COUNT0_BASEADDR1 0x907000D0 + +#define XPT_BERT_BIT_COUNT1_BASEADDR 0x907000D4 + +#define XPT_BERT_BIT_COUNT1_BASEADDR1 0x907000D8 + +#define XPT_BERT_BIT_COUNT2_BASEADDR 0x907000DC + +#define XPT_BERT_BIT_COUNT2_BASEADDR1 0x907000E0 + +#define XPT_BERT_BIT_COUNT3_BASEADDR 0x907000E4 + +#define XPT_BERT_BIT_COUNT3_BASEADDR1 0x907000E8 + +#define XPT_BERT_BIT_COUNT4_BASEADDR 0x907000EC + +#define XPT_BERT_BIT_COUNT4_BASEADDR1 0x907000F0 + +#define XPT_BERT_BIT_COUNT5_BASEADDR 0x907000F4 + +#define XPT_BERT_BIT_COUNT5_BASEADDR1 0x907000F8 + +#define XPT_BERT_BIT_COUNT6_BASEADDR 0x907000FC + +#define XPT_BERT_BIT_COUNT6_BASEADDR1 0x90700100 + +#define XPT_BERT_BIT_COUNT7_BASEADDR 0x90700104 + +#define XPT_BERT_BIT_COUNT7_BASEADDR1 0x90700108 + +#define XPT_BERT_ERR_COUNT0_BASEADDR 0x9070010C + +#define XPT_BERT_ERR_COUNT0_BASEADDR1 0x90700110 + +#define XPT_BERT_ERR_COUNT1_BASEADDR 0x90700114 + +#define XPT_BERT_ERR_COUNT1_BASEADDR1 0x90700118 + +#define XPT_BERT_ERR_COUNT2_BASEADDR 0x9070011C + +#define XPT_BERT_ERR_COUNT2_BASEADDR1 0x90700120 + +#define XPT_BERT_ERR_COUNT3_BASEADDR 0x90700124 + +#define XPT_BERT_ERR_COUNT3_BASEADDR1 0x90700128 + +#define XPT_BERT_ERR_COUNT4_BASEADDR 0x9070012C + +#define XPT_BERT_ERR_COUNT4_BASEADDR1 0x90700130 + +#define XPT_BERT_ERR_COUNT5_BASEADDR 0x90700134 + +#define XPT_BERT_ERR_COUNT5_BASEADDR1 0x90700138 + +#define XPT_BERT_ERR_COUNT6_BASEADDR 0x9070013C + +#define XPT_BERT_ERR_COUNT6_BASEADDR1 0x90700140 + +#define XPT_BERT_ERR_COUNT7_BASEADDR 0x90700144 + +#define XPT_BERT_ERR_COUNT7_BASEADDR1 0x90700148 + +#define XPT_BERT_ERROR_BASEADDR 0x9070014C + +#define XPT_BERT_ANALYZER_BASEADDR 0x90700150 + +#define XPT_BERT_ANALYZER_BASEADDR1 0x90700154 + +#define XPT_BERT_ANALYZER_BASEADDR2 0x90700158 + +#define XPT_BERT_ANALYZER_BASEADDR3 0x9070015C + +#define XPT_BERT_ANALYZER_BASEADDR4 0x90700160 + +#define XPT_BERT_ANALYZER_BASEADDR5 0x90700164 + +#define XPT_BERT_ANALYZER_BASEADDR6 0x90700168 + +#define XPT_BERT_ANALYZER_BASEADDR7 0x9070016C + +#define XPT_BERT_ANALYZER_BASEADDR8 0x90700170 + +#define XPT_BERT_ANALYZER_BASEADDR9 0x90700174 + +#define XPT_DMD0_BASEADDR 0x9070024C + +/* V2 AGC Gain Freeze & step */ +#define DBG_ENABLE_DISABLE_AGC (0x3FFFCF60) /* 1: DISABLE, 0:ENABLE */ +#define WB_DFE0_DFE_FB_RF1_BASEADDR 0x903004A4 + +#define WB_DFE1_DFE_FB_RF1_BASEADDR 0x904004A4 + +#define WB_DFE2_DFE_FB_RF1_BASEADDR 0x905004A4 + +#define WB_DFE3_DFE_FB_RF1_BASEADDR 0x906004A4 + +#define AFE_REG_D2A_TA_RFFE_LNA_BO_1P8_BASEADDR 0x90200104 + +#define AFE_REG_AFE_REG_SPARE_BASEADDR 0x902000A0 + +#define AFE_REG_AFE_REG_SPARE_BASEADDR1 0x902000B4 + +#define AFE_REG_AFE_REG_SPARE_BASEADDR2 0x902000C4 + +#define AFE_REG_AFE_REG_SPARE_BASEADDR3 0x902000D4 + +#define WB_DFE0_DFE_FB_AGC_BASEADDR 0x90300498 + +#define WB_DFE1_DFE_FB_AGC_BASEADDR 0x90400498 + +#define WB_DFE2_DFE_FB_AGC_BASEADDR 0x90500498 + +#define WB_DFE3_DFE_FB_AGC_BASEADDR 0x90600498 + +#define WDT_WD_INT_BASEADDR 0x8002000C + +#define FSK_TX_FTM_BASEADDR 0x80090000 + +#define FSK_TX_FTM_TX_CNT_BASEADDR 0x80090018 + +#define AFE_REG_D2A_FSK_BIAS_BASEADDR 0x90200040 + +#define DMD_TEI_BASEADDR 0x3FFFEBE0 + +#endif /* __MXL58X_REGISTERS_H__ */ diff --git a/drivers/media/dvb-frontends/s5h1420.c b/drivers/media/dvb-frontends/s5h1420.c index cba9bff05b12..fd427a29c001 100644 --- a/drivers/media/dvb-frontends/s5h1420.c +++ b/drivers/media/dvb-frontends/s5h1420.c @@ -864,7 +864,7 @@ static int s5h1420_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c return i2c_transfer(state->i2c, m, 1 + num) == 1 + num ? num : -EIO; } -static struct i2c_algorithm s5h1420_tuner_i2c_algo = { +static const struct i2c_algorithm s5h1420_tuner_i2c_algo = { .master_xfer = s5h1420_tuner_i2c_tuner_xfer, .functionality = s5h1420_tuner_i2c_func, }; diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 8ac0f598978d..f3529df8211d 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -2149,6 +2149,71 @@ static u32 stv0367cab_GetSymbolRate(struct stv0367_state *state, u32 mclk_hz) return regsym; } +static u32 stv0367cab_fsm_status(struct stv0367_state *state) +{ + return stv0367_readbits(state, F367CAB_FSM_STATUS); +} + +static u32 stv0367cab_qamfec_lock(struct stv0367_state *state) +{ + return stv0367_readbits(state, + (state->cab_state->qamfec_status_reg ? + state->cab_state->qamfec_status_reg : + F367CAB_QAMFEC_LOCK)); +} + +static +enum stv0367_cab_signal_type stv0367cab_fsm_signaltype(u32 qam_fsm_status) +{ + enum stv0367_cab_signal_type signaltype = FE_CAB_NOAGC; + + switch (qam_fsm_status) { + case 1: + signaltype = FE_CAB_NOAGC; + break; + case 2: + signaltype = FE_CAB_NOTIMING; + break; + case 3: + signaltype = FE_CAB_TIMINGOK; + break; + case 4: + signaltype = FE_CAB_NOCARRIER; + break; + case 5: + signaltype = FE_CAB_CARRIEROK; + break; + case 7: + signaltype = FE_CAB_NOBLIND; + break; + case 8: + signaltype = FE_CAB_BLINDOK; + break; + case 10: + signaltype = FE_CAB_NODEMOD; + break; + case 11: + signaltype = FE_CAB_DEMODOK; + break; + case 12: + signaltype = FE_CAB_DEMODOK; + break; + case 13: + signaltype = FE_CAB_NODEMOD; + break; + case 14: + signaltype = FE_CAB_NOBLIND; + break; + case 15: + signaltype = FE_CAB_NOSIGNAL; + break; + default: + break; + } + + return signaltype; +} + static int stv0367cab_read_status(struct dvb_frontend *fe, enum fe_status *status) { @@ -2158,22 +2223,26 @@ static int stv0367cab_read_status(struct dvb_frontend *fe, *status = 0; - if (state->cab_state->state > FE_CAB_NOSIGNAL) - *status |= FE_HAS_SIGNAL; + /* update cab_state->state from QAM_FSM_STATUS */ + state->cab_state->state = stv0367cab_fsm_signaltype( + stv0367cab_fsm_status(state)); - if (state->cab_state->state > FE_CAB_NOCARRIER) - *status |= FE_HAS_CARRIER; + if (stv0367cab_qamfec_lock(state)) { + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI + | FE_HAS_SYNC | FE_HAS_LOCK; + dprintk("%s: stv0367 has locked\n", __func__); + } else { + if (state->cab_state->state > FE_CAB_NOSIGNAL) + *status |= FE_HAS_SIGNAL; - if (state->cab_state->state >= FE_CAB_DEMODOK) - *status |= FE_HAS_VITERBI; + if (state->cab_state->state > FE_CAB_NOCARRIER) + *status |= FE_HAS_CARRIER; - if (state->cab_state->state >= FE_CAB_DATAOK) - *status |= FE_HAS_SYNC; + if (state->cab_state->state >= FE_CAB_DEMODOK) + *status |= FE_HAS_VITERBI; - if (stv0367_readbits(state, (state->cab_state->qamfec_status_reg ? - state->cab_state->qamfec_status_reg : F367CAB_QAMFEC_LOCK))) { - *status |= FE_HAS_LOCK; - dprintk("%s: stv0367 has locked\n", __func__); + if (state->cab_state->state >= FE_CAB_DATAOK) + *status |= FE_HAS_SYNC; } return 0; @@ -2374,7 +2443,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, LockTime = 0; stv0367_writereg(state, R367CAB_CTRL_1, 0x00); do { - QAM_Lock = stv0367_readbits(state, F367CAB_FSM_STATUS); + QAM_Lock = stv0367cab_fsm_status(state); if ((LockTime >= (DemodTimeOut - EQLTimeOut)) && (QAM_Lock == 0x04)) /* @@ -2435,10 +2504,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, do { usleep_range(5000, 7000); LockTime += 5; - QAMFEC_Lock = stv0367_readbits(state, - (state->cab_state->qamfec_status_reg ? - state->cab_state->qamfec_status_reg : - F367CAB_QAMFEC_LOCK)); + QAMFEC_Lock = stv0367cab_qamfec_lock(state); } while (!QAMFEC_Lock && (LockTime < FECTimeOut)); } else QAMFEC_Lock = 0; @@ -2474,52 +2540,8 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, cab_state->locked = 1; /* stv0367_setbits(state, F367CAB_AGC_ACCUMRSTSEL,7);*/ - } else { - switch (QAM_Lock) { - case 1: - signalType = FE_CAB_NOAGC; - break; - case 2: - signalType = FE_CAB_NOTIMING; - break; - case 3: - signalType = FE_CAB_TIMINGOK; - break; - case 4: - signalType = FE_CAB_NOCARRIER; - break; - case 5: - signalType = FE_CAB_CARRIEROK; - break; - case 7: - signalType = FE_CAB_NOBLIND; - break; - case 8: - signalType = FE_CAB_BLINDOK; - break; - case 10: - signalType = FE_CAB_NODEMOD; - break; - case 11: - signalType = FE_CAB_DEMODOK; - break; - case 12: - signalType = FE_CAB_DEMODOK; - break; - case 13: - signalType = FE_CAB_NODEMOD; - break; - case 14: - signalType = FE_CAB_NOBLIND; - break; - case 15: - signalType = FE_CAB_NOSIGNAL; - break; - default: - break; - } - - } + } else + signalType = stv0367cab_fsm_signaltype(QAM_Lock); /* Set the AGC control values to tracking values */ stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, TrackAGCAccum); @@ -3090,7 +3112,7 @@ static int stv0367ddb_read_status(struct dvb_frontend *fe, { struct stv0367_state *state = fe->demodulator_priv; struct dtv_frontend_properties *p = &fe->dtv_property_cache; - int ret; + int ret = 0; switch (state->activedemod) { case demod_ter: @@ -3100,7 +3122,7 @@ static int stv0367ddb_read_status(struct dvb_frontend *fe, ret = stv0367cab_read_status(fe, status); break; default: - return 0; + break; } /* stop and report on *_read_status failure */ @@ -3138,7 +3160,7 @@ static int stv0367ddb_get_frontend(struct dvb_frontend *fe, break; } - return -EINVAL; + return 0; } static int stv0367ddb_sleep(struct dvb_frontend *fe) @@ -3261,7 +3283,7 @@ static const struct dvb_frontend_ops stv0367ddb_ops = { 0x400 |/* FE_CAN_QAM_4 */ FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | - FE_CAN_QAM_256 | FE_CAN_QAM_AUTO | + FE_CAN_QAM_256 | /* DVB-T */ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c new file mode 100644 index 000000000000..8bf855c301f5 --- /dev/null +++ b/drivers/media/dvb-frontends/stv0910.c @@ -0,0 +1,1813 @@ +/* + * Driver for the ST STV0910 DVB-S/S2 demodulator. + * + * Copyright (C) 2014-2015 Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * developed for Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/firmware.h> +#include <linux/i2c.h> +#include <asm/div64.h> + +#include "dvb_math.h" +#include "dvb_frontend.h" +#include "stv0910.h" +#include "stv0910_regs.h" + +#define EXT_CLOCK 30000000 +#define TUNING_DELAY 200 +#define BER_SRC_S 0x20 +#define BER_SRC_S2 0x20 + +static LIST_HEAD(stvlist); + +enum receive_mode { RCVMODE_NONE, RCVMODE_DVBS, RCVMODE_DVBS2, RCVMODE_AUTO }; + +enum dvbs2_fectype { DVBS2_64K, DVBS2_16K }; + +enum dvbs2_mod_cod { + DVBS2_DUMMY_PLF, DVBS2_QPSK_1_4, DVBS2_QPSK_1_3, DVBS2_QPSK_2_5, + DVBS2_QPSK_1_2, DVBS2_QPSK_3_5, DVBS2_QPSK_2_3, DVBS2_QPSK_3_4, + DVBS2_QPSK_4_5, DVBS2_QPSK_5_6, DVBS2_QPSK_8_9, DVBS2_QPSK_9_10, + DVBS2_8PSK_3_5, DVBS2_8PSK_2_3, DVBS2_8PSK_3_4, DVBS2_8PSK_5_6, + DVBS2_8PSK_8_9, DVBS2_8PSK_9_10, DVBS2_16APSK_2_3, DVBS2_16APSK_3_4, + DVBS2_16APSK_4_5, DVBS2_16APSK_5_6, DVBS2_16APSK_8_9, DVBS2_16APSK_9_10, + DVBS2_32APSK_3_4, DVBS2_32APSK_4_5, DVBS2_32APSK_5_6, DVBS2_32APSK_8_9, + DVBS2_32APSK_9_10 +}; + +enum fe_stv0910_mod_cod { + FE_DUMMY_PLF, FE_QPSK_14, FE_QPSK_13, FE_QPSK_25, + FE_QPSK_12, FE_QPSK_35, FE_QPSK_23, FE_QPSK_34, + FE_QPSK_45, FE_QPSK_56, FE_QPSK_89, FE_QPSK_910, + FE_8PSK_35, FE_8PSK_23, FE_8PSK_34, FE_8PSK_56, + FE_8PSK_89, FE_8PSK_910, FE_16APSK_23, FE_16APSK_34, + FE_16APSK_45, FE_16APSK_56, FE_16APSK_89, FE_16APSK_910, + FE_32APSK_34, FE_32APSK_45, FE_32APSK_56, FE_32APSK_89, + FE_32APSK_910 +}; + +enum fe_stv0910_roll_off { FE_SAT_35, FE_SAT_25, FE_SAT_20, FE_SAT_15 }; + +static inline u32 muldiv32(u32 a, u32 b, u32 c) +{ + u64 tmp64; + + tmp64 = (u64)a * (u64)b; + do_div(tmp64, c); + + return (u32)tmp64; +} + +struct stv_base { + struct list_head stvlist; + + u8 adr; + struct i2c_adapter *i2c; + struct mutex i2c_lock; /* shared I2C access protect */ + struct mutex reg_lock; /* shared register write protect */ + int count; + + u32 extclk; + u32 mclk; +}; + +struct stv { + struct stv_base *base; + struct dvb_frontend fe; + int nr; + u16 regoff; + u8 i2crpt; + u8 tscfgh; + u8 tsgeneral; + u8 tsspeed; + u8 single; + unsigned long tune_time; + + s32 search_range; + u32 started; + u32 demod_lock_time; + enum receive_mode receive_mode; + u32 demod_timeout; + u32 fec_timeout; + u32 first_time_lock; + u8 demod_bits; + u32 symbol_rate; + + u8 last_viterbi_rate; + enum fe_code_rate puncture_rate; + enum fe_stv0910_mod_cod mod_cod; + enum dvbs2_fectype fectype; + u32 pilots; + enum fe_stv0910_roll_off feroll_off; + + int is_standard_broadcast; + int is_vcm; + + u32 cur_scrambling_code; + + u32 last_bernumerator; + u32 last_berdenominator; + u8 berscale; + + u8 vth[6]; +}; + +struct sinit_table { + u16 address; + u8 data; +}; + +struct slookup { + s16 value; + u32 reg_value; +}; + +static inline int i2c_write(struct i2c_adapter *adap, u8 adr, + u8 *data, int len) +{ + struct i2c_msg msg = {.addr = adr, .flags = 0, + .buf = data, .len = len}; + + if (i2c_transfer(adap, &msg, 1) != 1) { + dev_warn(&adap->dev, "i2c write error ([%02x] %04x: %02x)\n", + adr, (data[0] << 8) | data[1], + (len > 2 ? data[2] : 0)); + return -EREMOTEIO; + } + return 0; +} + +static int i2c_write_reg16(struct i2c_adapter *adap, u8 adr, u16 reg, u8 val) +{ + u8 msg[3] = {reg >> 8, reg & 0xff, val}; + + return i2c_write(adap, adr, msg, 3); +} + +static int write_reg(struct stv *state, u16 reg, u8 val) +{ + return i2c_write_reg16(state->base->i2c, state->base->adr, reg, val); +} + +static inline int i2c_read_regs16(struct i2c_adapter *adapter, u8 adr, + u16 reg, u8 *val, int count) +{ + u8 msg[2] = {reg >> 8, reg & 0xff}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = count } }; + + if (i2c_transfer(adapter, msgs, 2) != 2) { + dev_warn(&adapter->dev, "i2c read error ([%02x] %04x)\n", + adr, reg); + return -EREMOTEIO; + } + return 0; +} + +static int read_reg(struct stv *state, u16 reg, u8 *val) +{ + return i2c_read_regs16(state->base->i2c, state->base->adr, + reg, val, 1); +} + +static int read_regs(struct stv *state, u16 reg, u8 *val, int len) +{ + return i2c_read_regs16(state->base->i2c, state->base->adr, + reg, val, len); +} + +static int write_shared_reg(struct stv *state, u16 reg, u8 mask, u8 val) +{ + int status; + u8 tmp; + + mutex_lock(&state->base->reg_lock); + status = read_reg(state, reg, &tmp); + if (!status) + status = write_reg(state, reg, (tmp & ~mask) | (val & mask)); + mutex_unlock(&state->base->reg_lock); + return status; +} + +static const struct slookup s1_sn_lookup[] = { + { 0, 9242 }, /* C/N= 0dB */ + { 5, 9105 }, /* C/N= 0.5dB */ + { 10, 8950 }, /* C/N= 1.0dB */ + { 15, 8780 }, /* C/N= 1.5dB */ + { 20, 8566 }, /* C/N= 2.0dB */ + { 25, 8366 }, /* C/N= 2.5dB */ + { 30, 8146 }, /* C/N= 3.0dB */ + { 35, 7908 }, /* C/N= 3.5dB */ + { 40, 7666 }, /* C/N= 4.0dB */ + { 45, 7405 }, /* C/N= 4.5dB */ + { 50, 7136 }, /* C/N= 5.0dB */ + { 55, 6861 }, /* C/N= 5.5dB */ + { 60, 6576 }, /* C/N= 6.0dB */ + { 65, 6330 }, /* C/N= 6.5dB */ + { 70, 6048 }, /* C/N= 7.0dB */ + { 75, 5768 }, /* C/N= 7.5dB */ + { 80, 5492 }, /* C/N= 8.0dB */ + { 85, 5224 }, /* C/N= 8.5dB */ + { 90, 4959 }, /* C/N= 9.0dB */ + { 95, 4709 }, /* C/N= 9.5dB */ + { 100, 4467 }, /* C/N=10.0dB */ + { 105, 4236 }, /* C/N=10.5dB */ + { 110, 4013 }, /* C/N=11.0dB */ + { 115, 3800 }, /* C/N=11.5dB */ + { 120, 3598 }, /* C/N=12.0dB */ + { 125, 3406 }, /* C/N=12.5dB */ + { 130, 3225 }, /* C/N=13.0dB */ + { 135, 3052 }, /* C/N=13.5dB */ + { 140, 2889 }, /* C/N=14.0dB */ + { 145, 2733 }, /* C/N=14.5dB */ + { 150, 2587 }, /* C/N=15.0dB */ + { 160, 2318 }, /* C/N=16.0dB */ + { 170, 2077 }, /* C/N=17.0dB */ + { 180, 1862 }, /* C/N=18.0dB */ + { 190, 1670 }, /* C/N=19.0dB */ + { 200, 1499 }, /* C/N=20.0dB */ + { 210, 1347 }, /* C/N=21.0dB */ + { 220, 1213 }, /* C/N=22.0dB */ + { 230, 1095 }, /* C/N=23.0dB */ + { 240, 992 }, /* C/N=24.0dB */ + { 250, 900 }, /* C/N=25.0dB */ + { 260, 826 }, /* C/N=26.0dB */ + { 270, 758 }, /* C/N=27.0dB */ + { 280, 702 }, /* C/N=28.0dB */ + { 290, 653 }, /* C/N=29.0dB */ + { 300, 613 }, /* C/N=30.0dB */ + { 310, 579 }, /* C/N=31.0dB */ + { 320, 550 }, /* C/N=32.0dB */ + { 330, 526 }, /* C/N=33.0dB */ + { 350, 490 }, /* C/N=33.0dB */ + { 400, 445 }, /* C/N=40.0dB */ + { 450, 430 }, /* C/N=45.0dB */ + { 500, 426 }, /* C/N=50.0dB */ + { 510, 425 } /* C/N=51.0dB */ +}; + +static const struct slookup s2_sn_lookup[] = { + { -30, 13950 }, /* C/N=-2.5dB */ + { -25, 13580 }, /* C/N=-2.5dB */ + { -20, 13150 }, /* C/N=-2.0dB */ + { -15, 12760 }, /* C/N=-1.5dB */ + { -10, 12345 }, /* C/N=-1.0dB */ + { -5, 11900 }, /* C/N=-0.5dB */ + { 0, 11520 }, /* C/N= 0dB */ + { 5, 11080 }, /* C/N= 0.5dB */ + { 10, 10630 }, /* C/N= 1.0dB */ + { 15, 10210 }, /* C/N= 1.5dB */ + { 20, 9790 }, /* C/N= 2.0dB */ + { 25, 9390 }, /* C/N= 2.5dB */ + { 30, 8970 }, /* C/N= 3.0dB */ + { 35, 8575 }, /* C/N= 3.5dB */ + { 40, 8180 }, /* C/N= 4.0dB */ + { 45, 7800 }, /* C/N= 4.5dB */ + { 50, 7430 }, /* C/N= 5.0dB */ + { 55, 7080 }, /* C/N= 5.5dB */ + { 60, 6720 }, /* C/N= 6.0dB */ + { 65, 6320 }, /* C/N= 6.5dB */ + { 70, 6060 }, /* C/N= 7.0dB */ + { 75, 5760 }, /* C/N= 7.5dB */ + { 80, 5480 }, /* C/N= 8.0dB */ + { 85, 5200 }, /* C/N= 8.5dB */ + { 90, 4930 }, /* C/N= 9.0dB */ + { 95, 4680 }, /* C/N= 9.5dB */ + { 100, 4425 }, /* C/N=10.0dB */ + { 105, 4210 }, /* C/N=10.5dB */ + { 110, 3980 }, /* C/N=11.0dB */ + { 115, 3765 }, /* C/N=11.5dB */ + { 120, 3570 }, /* C/N=12.0dB */ + { 125, 3315 }, /* C/N=12.5dB */ + { 130, 3140 }, /* C/N=13.0dB */ + { 135, 2980 }, /* C/N=13.5dB */ + { 140, 2820 }, /* C/N=14.0dB */ + { 145, 2670 }, /* C/N=14.5dB */ + { 150, 2535 }, /* C/N=15.0dB */ + { 160, 2270 }, /* C/N=16.0dB */ + { 170, 2035 }, /* C/N=17.0dB */ + { 180, 1825 }, /* C/N=18.0dB */ + { 190, 1650 }, /* C/N=19.0dB */ + { 200, 1485 }, /* C/N=20.0dB */ + { 210, 1340 }, /* C/N=21.0dB */ + { 220, 1212 }, /* C/N=22.0dB */ + { 230, 1100 }, /* C/N=23.0dB */ + { 240, 1000 }, /* C/N=24.0dB */ + { 250, 910 }, /* C/N=25.0dB */ + { 260, 836 }, /* C/N=26.0dB */ + { 270, 772 }, /* C/N=27.0dB */ + { 280, 718 }, /* C/N=28.0dB */ + { 290, 671 }, /* C/N=29.0dB */ + { 300, 635 }, /* C/N=30.0dB */ + { 310, 602 }, /* C/N=31.0dB */ + { 320, 575 }, /* C/N=32.0dB */ + { 330, 550 }, /* C/N=33.0dB */ + { 350, 517 }, /* C/N=35.0dB */ + { 400, 480 }, /* C/N=40.0dB */ + { 450, 466 }, /* C/N=45.0dB */ + { 500, 464 }, /* C/N=50.0dB */ + { 510, 463 }, /* C/N=51.0dB */ +}; + +static const struct slookup padc_lookup[] = { + { 0, 118000 }, /* PADC= +0dBm */ + { -100, 93600 }, /* PADC= -1dBm */ + { -200, 74500 }, /* PADC= -2dBm */ + { -300, 59100 }, /* PADC= -3dBm */ + { -400, 47000 }, /* PADC= -4dBm */ + { -500, 37300 }, /* PADC= -5dBm */ + { -600, 29650 }, /* PADC= -6dBm */ + { -700, 23520 }, /* PADC= -7dBm */ + { -900, 14850 }, /* PADC= -9dBm */ + { -1100, 9380 }, /* PADC=-11dBm */ + { -1300, 5910 }, /* PADC=-13dBm */ + { -1500, 3730 }, /* PADC=-15dBm */ + { -1700, 2354 }, /* PADC=-17dBm */ + { -1900, 1485 }, /* PADC=-19dBm */ + { -2000, 1179 }, /* PADC=-20dBm */ + { -2100, 1000 }, /* PADC=-21dBm */ +}; + +/********************************************************************* + * Tracking carrier loop carrier QPSK 1/4 to 8PSK 9/10 long Frame + *********************************************************************/ +static const u8 s2car_loop[] = { + /* + * Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff + * 20MPon 20MPoff 30MPon 30MPoff + */ + + /* FE_QPSK_14 */ + 0x0C, 0x3C, 0x0B, 0x3C, 0x2A, 0x2C, 0x2A, 0x1C, 0x3A, 0x3B, + /* FE_QPSK_13 */ + 0x0C, 0x3C, 0x0B, 0x3C, 0x2A, 0x2C, 0x3A, 0x0C, 0x3A, 0x2B, + /* FE_QPSK_25 */ + 0x1C, 0x3C, 0x1B, 0x3C, 0x3A, 0x1C, 0x3A, 0x3B, 0x3A, 0x2B, + /* FE_QPSK_12 */ + 0x0C, 0x1C, 0x2B, 0x1C, 0x0B, 0x2C, 0x0B, 0x0C, 0x2A, 0x2B, + /* FE_QPSK_35 */ + 0x1C, 0x1C, 0x2B, 0x1C, 0x0B, 0x2C, 0x0B, 0x0C, 0x2A, 0x2B, + /* FE_QPSK_23 */ + 0x2C, 0x2C, 0x2B, 0x1C, 0x0B, 0x2C, 0x0B, 0x0C, 0x2A, 0x2B, + /* FE_QPSK_34 */ + 0x3C, 0x2C, 0x3B, 0x2C, 0x1B, 0x1C, 0x1B, 0x3B, 0x3A, 0x1B, + /* FE_QPSK_45 */ + 0x0D, 0x3C, 0x3B, 0x2C, 0x1B, 0x1C, 0x1B, 0x3B, 0x3A, 0x1B, + /* FE_QPSK_56 */ + 0x1D, 0x3C, 0x0C, 0x2C, 0x2B, 0x1C, 0x1B, 0x3B, 0x0B, 0x1B, + /* FE_QPSK_89 */ + 0x3D, 0x0D, 0x0C, 0x2C, 0x2B, 0x0C, 0x2B, 0x2B, 0x0B, 0x0B, + /* FE_QPSK_910 */ + 0x1E, 0x0D, 0x1C, 0x2C, 0x3B, 0x0C, 0x2B, 0x2B, 0x1B, 0x0B, + /* FE_8PSK_35 */ + 0x28, 0x09, 0x28, 0x09, 0x28, 0x09, 0x28, 0x08, 0x28, 0x27, + /* FE_8PSK_23 */ + 0x19, 0x29, 0x19, 0x29, 0x19, 0x29, 0x38, 0x19, 0x28, 0x09, + /* FE_8PSK_34 */ + 0x1A, 0x0B, 0x1A, 0x3A, 0x0A, 0x2A, 0x39, 0x2A, 0x39, 0x1A, + /* FE_8PSK_56 */ + 0x2B, 0x2B, 0x1B, 0x1B, 0x0B, 0x1B, 0x1A, 0x0B, 0x1A, 0x1A, + /* FE_8PSK_89 */ + 0x0C, 0x0C, 0x3B, 0x3B, 0x1B, 0x1B, 0x2A, 0x0B, 0x2A, 0x2A, + /* FE_8PSK_910 */ + 0x0C, 0x1C, 0x0C, 0x3B, 0x2B, 0x1B, 0x3A, 0x0B, 0x2A, 0x2A, + + /********************************************************************** + * Tracking carrier loop carrier 16APSK 2/3 to 32APSK 9/10 long Frame + **********************************************************************/ + + /* + * Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon + * 20MPoff 30MPon 30MPoff + */ + + /* FE_16APSK_23 */ + 0x0A, 0x0A, 0x0A, 0x0A, 0x1A, 0x0A, 0x39, 0x0A, 0x29, 0x0A, + /* FE_16APSK_34 */ + 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0A, 0x2A, 0x0A, 0x1A, 0x0A, + /* FE_16APSK_45 */ + 0x0A, 0x0A, 0x0A, 0x0A, 0x1B, 0x0A, 0x3A, 0x0A, 0x2A, 0x0A, + /* FE_16APSK_56 */ + 0x0A, 0x0A, 0x0A, 0x0A, 0x1B, 0x0A, 0x3A, 0x0A, 0x2A, 0x0A, + /* FE_16APSK_89 */ + 0x0A, 0x0A, 0x0A, 0x0A, 0x2B, 0x0A, 0x0B, 0x0A, 0x3A, 0x0A, + /* FE_16APSK_910 */ + 0x0A, 0x0A, 0x0A, 0x0A, 0x2B, 0x0A, 0x0B, 0x0A, 0x3A, 0x0A, + /* FE_32APSK_34 */ + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + /* FE_32APSK_45 */ + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + /* FE_32APSK_56 */ + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + /* FE_32APSK_89 */ + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + /* FE_32APSK_910 */ + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, +}; + +static u8 get_optim_cloop(struct stv *state, + enum fe_stv0910_mod_cod mod_cod, u32 pilots) +{ + int i = 0; + + if (mod_cod >= FE_32APSK_910) + i = ((int)FE_32APSK_910 - (int)FE_QPSK_14) * 10; + else if (mod_cod >= FE_QPSK_14) + i = ((int)mod_cod - (int)FE_QPSK_14) * 10; + + if (state->symbol_rate <= 3000000) + i += 0; + else if (state->symbol_rate <= 7000000) + i += 2; + else if (state->symbol_rate <= 15000000) + i += 4; + else if (state->symbol_rate <= 25000000) + i += 6; + else + i += 8; + + if (!pilots) + i += 1; + + return s2car_loop[i]; +} + +static int get_cur_symbol_rate(struct stv *state, u32 *p_symbol_rate) +{ + int status = 0; + u8 symb_freq0; + u8 symb_freq1; + u8 symb_freq2; + u8 symb_freq3; + u8 tim_offs0; + u8 tim_offs1; + u8 tim_offs2; + u32 symbol_rate; + s32 timing_offset; + + *p_symbol_rate = 0; + if (!state->started) + return status; + + read_reg(state, RSTV0910_P2_SFR3 + state->regoff, &symb_freq3); + read_reg(state, RSTV0910_P2_SFR2 + state->regoff, &symb_freq2); + read_reg(state, RSTV0910_P2_SFR1 + state->regoff, &symb_freq1); + read_reg(state, RSTV0910_P2_SFR0 + state->regoff, &symb_freq0); + read_reg(state, RSTV0910_P2_TMGREG2 + state->regoff, &tim_offs2); + read_reg(state, RSTV0910_P2_TMGREG1 + state->regoff, &tim_offs1); + read_reg(state, RSTV0910_P2_TMGREG0 + state->regoff, &tim_offs0); + + symbol_rate = ((u32)symb_freq3 << 24) | ((u32)symb_freq2 << 16) | + ((u32)symb_freq1 << 8) | (u32)symb_freq0; + timing_offset = ((u32)tim_offs2 << 16) | ((u32)tim_offs1 << 8) | + (u32)tim_offs0; + + if ((timing_offset & (1 << 23)) != 0) + timing_offset |= 0xFF000000; /* Sign extent */ + + symbol_rate = (u32)(((u64)symbol_rate * state->base->mclk) >> 32); + timing_offset = (s32)(((s64)symbol_rate * (s64)timing_offset) >> 29); + + *p_symbol_rate = symbol_rate + timing_offset; + + return 0; +} + +static int get_signal_parameters(struct stv *state) +{ + u8 tmp; + + if (!state->started) + return -EINVAL; + + if (state->receive_mode == RCVMODE_DVBS2) { + read_reg(state, RSTV0910_P2_DMDMODCOD + state->regoff, &tmp); + state->mod_cod = (enum fe_stv0910_mod_cod)((tmp & 0x7c) >> 2); + state->pilots = (tmp & 0x01) != 0; + state->fectype = (enum dvbs2_fectype)((tmp & 0x02) >> 1); + + } else if (state->receive_mode == RCVMODE_DVBS) { + read_reg(state, RSTV0910_P2_VITCURPUN + state->regoff, &tmp); + state->puncture_rate = FEC_NONE; + switch (tmp & 0x1F) { + case 0x0d: + state->puncture_rate = FEC_1_2; + break; + case 0x12: + state->puncture_rate = FEC_2_3; + break; + case 0x15: + state->puncture_rate = FEC_3_4; + break; + case 0x18: + state->puncture_rate = FEC_5_6; + break; + case 0x1a: + state->puncture_rate = FEC_7_8; + break; + } + state->is_vcm = 0; + state->is_standard_broadcast = 1; + state->feroll_off = FE_SAT_35; + } + return 0; +} + +static int tracking_optimization(struct stv *state) +{ + u32 symbol_rate = 0; + u8 tmp; + + get_cur_symbol_rate(state, &symbol_rate); + read_reg(state, RSTV0910_P2_DMDCFGMD + state->regoff, &tmp); + tmp &= ~0xC0; + + switch (state->receive_mode) { + case RCVMODE_DVBS: + tmp |= 0x40; + break; + case RCVMODE_DVBS2: + tmp |= 0x80; + break; + default: + tmp |= 0xC0; + break; + } + write_reg(state, RSTV0910_P2_DMDCFGMD + state->regoff, tmp); + + if (state->receive_mode == RCVMODE_DVBS2) { + /* Disable Reed-Solomon */ + write_shared_reg(state, + RSTV0910_TSTTSRS, state->nr ? 0x02 : 0x01, + 0x03); + + if (state->fectype == DVBS2_64K) { + u8 aclc = get_optim_cloop(state, state->mod_cod, + state->pilots); + + if (state->mod_cod <= FE_QPSK_910) { + write_reg(state, RSTV0910_P2_ACLC2S2Q + + state->regoff, aclc); + } else if (state->mod_cod <= FE_8PSK_910) { + write_reg(state, RSTV0910_P2_ACLC2S2Q + + state->regoff, 0x2a); + write_reg(state, RSTV0910_P2_ACLC2S28 + + state->regoff, aclc); + } else if (state->mod_cod <= FE_16APSK_910) { + write_reg(state, RSTV0910_P2_ACLC2S2Q + + state->regoff, 0x2a); + write_reg(state, RSTV0910_P2_ACLC2S216A + + state->regoff, aclc); + } else if (state->mod_cod <= FE_32APSK_910) { + write_reg(state, RSTV0910_P2_ACLC2S2Q + + state->regoff, 0x2a); + write_reg(state, RSTV0910_P2_ACLC2S232A + + state->regoff, aclc); + } + } + } + return 0; +} + +static s32 table_lookup(const struct slookup *table, + int table_size, u32 reg_value) +{ + s32 value; + int imin = 0; + int imax = table_size - 1; + int i; + s32 reg_diff; + + /* Assumes Table[0].RegValue > Table[imax].RegValue */ + if (reg_value >= table[0].reg_value) { + value = table[0].value; + } else if (reg_value <= table[imax].reg_value) { + value = table[imax].value; + } else { + while ((imax - imin) > 1) { + i = (imax + imin) / 2; + if ((table[imin].reg_value >= reg_value) && + (reg_value >= table[i].reg_value)) + imax = i; + else + imin = i; + } + + reg_diff = table[imax].reg_value - table[imin].reg_value; + value = table[imin].value; + if (reg_diff != 0) + value += ((s32)(reg_value - table[imin].reg_value) * + (s32)(table[imax].value + - table[imin].value)) + / (reg_diff); + } + + return value; +} + +static int get_signal_to_noise(struct stv *state, s32 *signal_to_noise) +{ + u8 data0; + u8 data1; + u16 data; + int n_lookup; + const struct slookup *lookup; + + *signal_to_noise = 0; + + if (!state->started) + return -EINVAL; + + if (state->receive_mode == RCVMODE_DVBS2) { + read_reg(state, RSTV0910_P2_NNOSPLHT1 + state->regoff, + &data1); + read_reg(state, RSTV0910_P2_NNOSPLHT0 + state->regoff, + &data0); + n_lookup = ARRAY_SIZE(s2_sn_lookup); + lookup = s2_sn_lookup; + } else { + read_reg(state, RSTV0910_P2_NNOSDATAT1 + state->regoff, + &data1); + read_reg(state, RSTV0910_P2_NNOSDATAT0 + state->regoff, + &data0); + n_lookup = ARRAY_SIZE(s1_sn_lookup); + lookup = s1_sn_lookup; + } + data = (((u16)data1) << 8) | (u16)data0; + *signal_to_noise = table_lookup(lookup, n_lookup, data); + return 0; +} + +static int get_bit_error_rate_s(struct stv *state, u32 *bernumerator, + u32 *berdenominator) +{ + u8 regs[3]; + + int status = read_regs(state, + RSTV0910_P2_ERRCNT12 + state->regoff, + regs, 3); + + if (status) + return -EINVAL; + + if ((regs[0] & 0x80) == 0) { + state->last_berdenominator = 1 << ((state->berscale * 2) + + 10 + 3); + state->last_bernumerator = ((u32)(regs[0] & 0x7F) << 16) | + ((u32)regs[1] << 8) | regs[2]; + if (state->last_bernumerator < 256 && state->berscale < 6) { + state->berscale += 1; + status = write_reg(state, RSTV0910_P2_ERRCTRL1 + + state->regoff, + 0x20 | state->berscale); + } else if (state->last_bernumerator > 1024 && + state->berscale > 2) { + state->berscale -= 1; + status = write_reg(state, RSTV0910_P2_ERRCTRL1 + + state->regoff, 0x20 | + state->berscale); + } + } + *bernumerator = state->last_bernumerator; + *berdenominator = state->last_berdenominator; + return 0; +} + +static u32 dvbs2_nbch(enum dvbs2_mod_cod mod_cod, enum dvbs2_fectype fectype) +{ + static const u32 nbch[][2] = { + { 0, 0}, /* DUMMY_PLF */ + {16200, 3240}, /* QPSK_1_4, */ + {21600, 5400}, /* QPSK_1_3, */ + {25920, 6480}, /* QPSK_2_5, */ + {32400, 7200}, /* QPSK_1_2, */ + {38880, 9720}, /* QPSK_3_5, */ + {43200, 10800}, /* QPSK_2_3, */ + {48600, 11880}, /* QPSK_3_4, */ + {51840, 12600}, /* QPSK_4_5, */ + {54000, 13320}, /* QPSK_5_6, */ + {57600, 14400}, /* QPSK_8_9, */ + {58320, 16000}, /* QPSK_9_10, */ + {43200, 9720}, /* 8PSK_3_5, */ + {48600, 10800}, /* 8PSK_2_3, */ + {51840, 11880}, /* 8PSK_3_4, */ + {54000, 13320}, /* 8PSK_5_6, */ + {57600, 14400}, /* 8PSK_8_9, */ + {58320, 16000}, /* 8PSK_9_10, */ + {43200, 10800}, /* 16APSK_2_3, */ + {48600, 11880}, /* 16APSK_3_4, */ + {51840, 12600}, /* 16APSK_4_5, */ + {54000, 13320}, /* 16APSK_5_6, */ + {57600, 14400}, /* 16APSK_8_9, */ + {58320, 16000}, /* 16APSK_9_10 */ + {48600, 11880}, /* 32APSK_3_4, */ + {51840, 12600}, /* 32APSK_4_5, */ + {54000, 13320}, /* 32APSK_5_6, */ + {57600, 14400}, /* 32APSK_8_9, */ + {58320, 16000}, /* 32APSK_9_10 */ + }; + + if (mod_cod >= DVBS2_QPSK_1_4 && + mod_cod <= DVBS2_32APSK_9_10 && fectype <= DVBS2_16K) + return nbch[mod_cod][fectype]; + return 64800; +} + +static int get_bit_error_rate_s2(struct stv *state, u32 *bernumerator, + u32 *berdenominator) +{ + u8 regs[3]; + + int status = read_regs(state, RSTV0910_P2_ERRCNT12 + state->regoff, + regs, 3); + + if (status) + return -EINVAL; + + if ((regs[0] & 0x80) == 0) { + state->last_berdenominator = + dvbs2_nbch((enum dvbs2_mod_cod)state->mod_cod, + state->fectype) << + (state->berscale * 2); + state->last_bernumerator = (((u32)regs[0] & 0x7F) << 16) | + ((u32)regs[1] << 8) | regs[2]; + if (state->last_bernumerator < 256 && state->berscale < 6) { + state->berscale += 1; + write_reg(state, RSTV0910_P2_ERRCTRL1 + state->regoff, + 0x20 | state->berscale); + } else if (state->last_bernumerator > 1024 && + state->berscale > 2) { + state->berscale -= 1; + write_reg(state, RSTV0910_P2_ERRCTRL1 + state->regoff, + 0x20 | state->berscale); + } + } + *bernumerator = state->last_bernumerator; + *berdenominator = state->last_berdenominator; + return status; +} + +static int get_bit_error_rate(struct stv *state, u32 *bernumerator, + u32 *berdenominator) +{ + *bernumerator = 0; + *berdenominator = 1; + + switch (state->receive_mode) { + case RCVMODE_DVBS: + return get_bit_error_rate_s(state, + bernumerator, berdenominator); + case RCVMODE_DVBS2: + return get_bit_error_rate_s2(state, + bernumerator, berdenominator); + default: + break; + } + return 0; +} + +static int set_mclock(struct stv *state, u32 master_clock) +{ + u32 idf = 1; + u32 odf = 4; + u32 quartz = state->base->extclk / 1000000; + u32 fphi = master_clock / 1000000; + u32 ndiv = (fphi * odf * idf) / quartz; + u32 cp = 7; + u32 fvco; + + if (ndiv >= 7 && ndiv <= 71) + cp = 7; + else if (ndiv >= 72 && ndiv <= 79) + cp = 8; + else if (ndiv >= 80 && ndiv <= 87) + cp = 9; + else if (ndiv >= 88 && ndiv <= 95) + cp = 10; + else if (ndiv >= 96 && ndiv <= 103) + cp = 11; + else if (ndiv >= 104 && ndiv <= 111) + cp = 12; + else if (ndiv >= 112 && ndiv <= 119) + cp = 13; + else if (ndiv >= 120 && ndiv <= 127) + cp = 14; + else if (ndiv >= 128 && ndiv <= 135) + cp = 15; + else if (ndiv >= 136 && ndiv <= 143) + cp = 16; + else if (ndiv >= 144 && ndiv <= 151) + cp = 17; + else if (ndiv >= 152 && ndiv <= 159) + cp = 18; + else if (ndiv >= 160 && ndiv <= 167) + cp = 19; + else if (ndiv >= 168 && ndiv <= 175) + cp = 20; + else if (ndiv >= 176 && ndiv <= 183) + cp = 21; + else if (ndiv >= 184 && ndiv <= 191) + cp = 22; + else if (ndiv >= 192 && ndiv <= 199) + cp = 23; + else if (ndiv >= 200 && ndiv <= 207) + cp = 24; + else if (ndiv >= 208 && ndiv <= 215) + cp = 25; + else if (ndiv >= 216 && ndiv <= 223) + cp = 26; + else if (ndiv >= 224 && ndiv <= 225) + cp = 27; + + write_reg(state, RSTV0910_NCOARSE, (cp << 3) | idf); + write_reg(state, RSTV0910_NCOARSE2, odf); + write_reg(state, RSTV0910_NCOARSE1, ndiv); + + fvco = (quartz * 2 * ndiv) / idf; + state->base->mclk = fvco / (2 * odf) * 1000000; + + return 0; +} + +static int stop(struct stv *state) +{ + if (state->started) { + u8 tmp; + + write_reg(state, RSTV0910_P2_TSCFGH + state->regoff, + state->tscfgh | 0x01); + read_reg(state, RSTV0910_P2_PDELCTRL1 + state->regoff, &tmp); + tmp &= ~0x01; /* release reset DVBS2 packet delin */ + write_reg(state, RSTV0910_P2_PDELCTRL1 + state->regoff, tmp); + /* Blind optim*/ + write_reg(state, RSTV0910_P2_AGC2O + state->regoff, 0x5B); + /* Stop the demod */ + write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff, 0x5c); + state->started = 0; + } + state->receive_mode = RCVMODE_NONE; + return 0; +} + +static int init_search_param(struct stv *state) +{ + u8 tmp; + + read_reg(state, RSTV0910_P2_PDELCTRL1 + state->regoff, &tmp); + tmp |= 0x20; /* Filter_en (no effect if SIS=non-MIS */ + write_reg(state, RSTV0910_P2_PDELCTRL1 + state->regoff, tmp); + + read_reg(state, RSTV0910_P2_PDELCTRL2 + state->regoff, &tmp); + tmp &= ~0x02; /* frame mode = 0 */ + write_reg(state, RSTV0910_P2_PDELCTRL2 + state->regoff, tmp); + + write_reg(state, RSTV0910_P2_UPLCCST0 + state->regoff, 0xe0); + write_reg(state, RSTV0910_P2_ISIBITENA + state->regoff, 0x00); + + read_reg(state, RSTV0910_P2_TSSTATEM + state->regoff, &tmp); + tmp &= ~0x01; /* nosync = 0, in case next signal is standard TS */ + write_reg(state, RSTV0910_P2_TSSTATEM + state->regoff, tmp); + + read_reg(state, RSTV0910_P2_TSCFGL + state->regoff, &tmp); + tmp &= ~0x04; /* embindvb = 0 */ + write_reg(state, RSTV0910_P2_TSCFGL + state->regoff, tmp); + + read_reg(state, RSTV0910_P2_TSINSDELH + state->regoff, &tmp); + tmp &= ~0x80; /* syncbyte = 0 */ + write_reg(state, RSTV0910_P2_TSINSDELH + state->regoff, tmp); + + read_reg(state, RSTV0910_P2_TSINSDELM + state->regoff, &tmp); + tmp &= ~0x08; /* token = 0 */ + write_reg(state, RSTV0910_P2_TSINSDELM + state->regoff, tmp); + + read_reg(state, RSTV0910_P2_TSDLYSET2 + state->regoff, &tmp); + tmp &= ~0x30; /* hysteresis threshold = 0 */ + write_reg(state, RSTV0910_P2_TSDLYSET2 + state->regoff, tmp); + + read_reg(state, RSTV0910_P2_PDELCTRL0 + state->regoff, &tmp); + tmp = (tmp & ~0x30) | 0x10; /* isi obs mode = 1, observe min ISI */ + write_reg(state, RSTV0910_P2_PDELCTRL0 + state->regoff, tmp); + + return 0; +} + +static int enable_puncture_rate(struct stv *state, enum fe_code_rate rate) +{ + switch (rate) { + case FEC_1_2: + return write_reg(state, + RSTV0910_P2_PRVIT + state->regoff, 0x01); + case FEC_2_3: + return write_reg(state, + RSTV0910_P2_PRVIT + state->regoff, 0x02); + case FEC_3_4: + return write_reg(state, + RSTV0910_P2_PRVIT + state->regoff, 0x04); + case FEC_5_6: + return write_reg(state, + RSTV0910_P2_PRVIT + state->regoff, 0x08); + case FEC_7_8: + return write_reg(state, + RSTV0910_P2_PRVIT + state->regoff, 0x20); + case FEC_NONE: + default: + return write_reg(state, + RSTV0910_P2_PRVIT + state->regoff, 0x2f); + } +} + +static int set_vth_default(struct stv *state) +{ + state->vth[0] = 0xd7; + state->vth[1] = 0x85; + state->vth[2] = 0x58; + state->vth[3] = 0x3a; + state->vth[4] = 0x34; + state->vth[5] = 0x28; + write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 0, state->vth[0]); + write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 1, state->vth[1]); + write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 2, state->vth[2]); + write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 3, state->vth[3]); + write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 4, state->vth[4]); + write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 5, state->vth[5]); + return 0; +} + +static int set_vth(struct stv *state) +{ + static const struct slookup vthlookup_table[] = { + {250, 8780}, /* C/N= 1.5dB */ + {100, 7405}, /* C/N= 4.5dB */ + {40, 6330}, /* C/N= 6.5dB */ + {12, 5224}, /* C/N= 8.5dB */ + {5, 4236} /* C/N=10.5dB */ + }; + + int i; + u8 tmp[2]; + int status = read_regs(state, + RSTV0910_P2_NNOSDATAT1 + state->regoff, + tmp, 2); + u16 reg_value = (tmp[0] << 8) | tmp[1]; + s32 vth = table_lookup(vthlookup_table, ARRAY_SIZE(vthlookup_table), + reg_value); + + for (i = 0; i < 6; i += 1) + if (state->vth[i] > vth) + state->vth[i] = vth; + + write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 0, state->vth[0]); + write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 1, state->vth[1]); + write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 2, state->vth[2]); + write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 3, state->vth[3]); + write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 4, state->vth[4]); + write_reg(state, RSTV0910_P2_VTH12 + state->regoff + 5, state->vth[5]); + return status; +} + +static int start(struct stv *state, struct dtv_frontend_properties *p) +{ + s32 freq; + u8 reg_dmdcfgmd; + u16 symb; + u32 scrambling_code = 1; + + if (p->symbol_rate < 100000 || p->symbol_rate > 70000000) + return -EINVAL; + + state->receive_mode = RCVMODE_NONE; + state->demod_lock_time = 0; + + /* Demod Stop */ + if (state->started) + write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff, 0x5C); + + init_search_param(state); + + if (p->stream_id != NO_STREAM_ID_FILTER) { + /* + * Backwards compatibility to "crazy" API. + * PRBS X root cannot be 0, so this should always work. + */ + if (p->stream_id & 0xffffff00) + scrambling_code = p->stream_id >> 8; + write_reg(state, RSTV0910_P2_ISIENTRY + state->regoff, + p->stream_id & 0xff); + write_reg(state, RSTV0910_P2_ISIBITENA + state->regoff, + 0xff); + } + + if (scrambling_code != state->cur_scrambling_code) { + write_reg(state, RSTV0910_P2_PLROOT0 + state->regoff, + scrambling_code & 0xff); + write_reg(state, RSTV0910_P2_PLROOT1 + state->regoff, + (scrambling_code >> 8) & 0xff); + write_reg(state, RSTV0910_P2_PLROOT2 + state->regoff, + (scrambling_code >> 16) & 0x0f); + state->cur_scrambling_code = scrambling_code; + } + + if (p->symbol_rate <= 1000000) { /* SR <=1Msps */ + state->demod_timeout = 3000; + state->fec_timeout = 2000; + } else if (p->symbol_rate <= 2000000) { /* 1Msps < SR <=2Msps */ + state->demod_timeout = 2500; + state->fec_timeout = 1300; + } else if (p->symbol_rate <= 5000000) { /* 2Msps< SR <=5Msps */ + state->demod_timeout = 1000; + state->fec_timeout = 650; + } else if (p->symbol_rate <= 10000000) { /* 5Msps< SR <=10Msps */ + state->demod_timeout = 700; + state->fec_timeout = 350; + } else if (p->symbol_rate < 20000000) { /* 10Msps< SR <=20Msps */ + state->demod_timeout = 400; + state->fec_timeout = 200; + } else { /* SR >=20Msps */ + state->demod_timeout = 300; + state->fec_timeout = 200; + } + + /* Set the Init Symbol rate */ + symb = muldiv32(p->symbol_rate, 65536, state->base->mclk); + write_reg(state, RSTV0910_P2_SFRINIT1 + state->regoff, + ((symb >> 8) & 0x7F)); + write_reg(state, RSTV0910_P2_SFRINIT0 + state->regoff, (symb & 0xFF)); + + state->demod_bits |= 0x80; + write_reg(state, RSTV0910_P2_DEMOD + state->regoff, state->demod_bits); + + /* FE_STV0910_SetSearchStandard */ + read_reg(state, RSTV0910_P2_DMDCFGMD + state->regoff, ®_dmdcfgmd); + write_reg(state, RSTV0910_P2_DMDCFGMD + state->regoff, + reg_dmdcfgmd |= 0xC0); + + write_shared_reg(state, + RSTV0910_TSTTSRS, state->nr ? 0x02 : 0x01, 0x00); + + /* Disable DSS */ + write_reg(state, RSTV0910_P2_FECM + state->regoff, 0x00); + write_reg(state, RSTV0910_P2_PRVIT + state->regoff, 0x2F); + + enable_puncture_rate(state, FEC_NONE); + + /* 8PSK 3/5, 8PSK 2/3 Poff tracking optimization WA */ + write_reg(state, RSTV0910_P2_ACLC2S2Q + state->regoff, 0x0B); + write_reg(state, RSTV0910_P2_ACLC2S28 + state->regoff, 0x0A); + write_reg(state, RSTV0910_P2_BCLC2S2Q + state->regoff, 0x84); + write_reg(state, RSTV0910_P2_BCLC2S28 + state->regoff, 0x84); + write_reg(state, RSTV0910_P2_CARHDR + state->regoff, 0x1C); + write_reg(state, RSTV0910_P2_CARFREQ + state->regoff, 0x79); + + write_reg(state, RSTV0910_P2_ACLC2S216A + state->regoff, 0x29); + write_reg(state, RSTV0910_P2_ACLC2S232A + state->regoff, 0x09); + write_reg(state, RSTV0910_P2_BCLC2S216A + state->regoff, 0x84); + write_reg(state, RSTV0910_P2_BCLC2S232A + state->regoff, 0x84); + + /* + * Reset CAR3, bug DVBS2->DVBS1 lock + * Note: The bit is only pulsed -> no lock on shared register needed + */ + write_reg(state, RSTV0910_TSTRES0, state->nr ? 0x04 : 0x08); + write_reg(state, RSTV0910_TSTRES0, 0); + + set_vth_default(state); + /* Reset demod */ + write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff, 0x1F); + + write_reg(state, RSTV0910_P2_CARCFG + state->regoff, 0x46); + + if (p->symbol_rate <= 5000000) + freq = (state->search_range / 2000) + 80; + else + freq = (state->search_range / 2000) + 1600; + freq = (freq << 16) / (state->base->mclk / 1000); + + write_reg(state, RSTV0910_P2_CFRUP1 + state->regoff, + (freq >> 8) & 0xff); + write_reg(state, RSTV0910_P2_CFRUP0 + state->regoff, (freq & 0xff)); + /* CFR Low Setting */ + freq = -freq; + write_reg(state, RSTV0910_P2_CFRLOW1 + state->regoff, + (freq >> 8) & 0xff); + write_reg(state, RSTV0910_P2_CFRLOW0 + state->regoff, (freq & 0xff)); + + /* init the demod frequency offset to 0 */ + write_reg(state, RSTV0910_P2_CFRINIT1 + state->regoff, 0); + write_reg(state, RSTV0910_P2_CFRINIT0 + state->regoff, 0); + + write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff, 0x1F); + /* Trigger acq */ + write_reg(state, RSTV0910_P2_DMDISTATE + state->regoff, 0x15); + + state->demod_lock_time += TUNING_DELAY; + state->started = 1; + + return 0; +} + +static int init_diseqc(struct stv *state) +{ + u16 offs = state->nr ? 0x40 : 0; /* Address offset */ + u8 freq = ((state->base->mclk + 11000 * 32) / (22000 * 32)); + + /* Disable receiver */ + write_reg(state, RSTV0910_P1_DISRXCFG + offs, 0x00); + write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0xBA); /* Reset = 1 */ + write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); /* Reset = 0 */ + write_reg(state, RSTV0910_P1_DISTXF22 + offs, freq); + return 0; +} + +static int probe(struct stv *state) +{ + u8 id; + + state->receive_mode = RCVMODE_NONE; + state->started = 0; + + if (read_reg(state, RSTV0910_MID, &id) < 0) + return -ENODEV; + + if (id != 0x51) + return -EINVAL; + + /* Configure the I2C repeater to off */ + write_reg(state, RSTV0910_P1_I2CRPT, 0x24); + /* Configure the I2C repeater to off */ + write_reg(state, RSTV0910_P2_I2CRPT, 0x24); + /* Set the I2C to oversampling ratio */ + write_reg(state, RSTV0910_I2CCFG, 0x88); /* state->i2ccfg */ + + write_reg(state, RSTV0910_OUTCFG, 0x00); /* OUTCFG */ + write_reg(state, RSTV0910_PADCFG, 0x05); /* RFAGC Pads Dev = 05 */ + write_reg(state, RSTV0910_SYNTCTRL, 0x02); /* SYNTCTRL */ + write_reg(state, RSTV0910_TSGENERAL, state->tsgeneral); /* TSGENERAL */ + write_reg(state, RSTV0910_CFGEXT, 0x02); /* CFGEXT */ + + if (state->single) + write_reg(state, RSTV0910_GENCFG, 0x14); /* GENCFG */ + else + write_reg(state, RSTV0910_GENCFG, 0x15); /* GENCFG */ + + write_reg(state, RSTV0910_P1_TNRCFG2, 0x02); /* IQSWAP = 0 */ + write_reg(state, RSTV0910_P2_TNRCFG2, 0x82); /* IQSWAP = 1 */ + + write_reg(state, RSTV0910_P1_CAR3CFG, 0x02); + write_reg(state, RSTV0910_P2_CAR3CFG, 0x02); + write_reg(state, RSTV0910_P1_DMDCFG4, 0x04); + write_reg(state, RSTV0910_P2_DMDCFG4, 0x04); + + write_reg(state, RSTV0910_TSTRES0, 0x80); /* LDPC Reset */ + write_reg(state, RSTV0910_TSTRES0, 0x00); + + write_reg(state, RSTV0910_P1_TSPIDFLT1, 0x00); + write_reg(state, RSTV0910_P2_TSPIDFLT1, 0x00); + + write_reg(state, RSTV0910_P1_TMGCFG2, 0x80); + write_reg(state, RSTV0910_P2_TMGCFG2, 0x80); + + set_mclock(state, 135000000); + + /* TS output */ + write_reg(state, RSTV0910_P1_TSCFGH, state->tscfgh | 0x01); + write_reg(state, RSTV0910_P1_TSCFGH, state->tscfgh); + write_reg(state, RSTV0910_P1_TSCFGM, 0xC0); /* Manual speed */ + write_reg(state, RSTV0910_P1_TSCFGL, 0x20); + + /* Speed = 67.5 MHz */ + write_reg(state, RSTV0910_P1_TSSPEED, state->tsspeed); + + write_reg(state, RSTV0910_P2_TSCFGH, state->tscfgh | 0x01); + write_reg(state, RSTV0910_P2_TSCFGH, state->tscfgh); + write_reg(state, RSTV0910_P2_TSCFGM, 0xC0); /* Manual speed */ + write_reg(state, RSTV0910_P2_TSCFGL, 0x20); + + /* Speed = 67.5 MHz */ + write_reg(state, RSTV0910_P2_TSSPEED, state->tsspeed); + + /* Reset stream merger */ + write_reg(state, RSTV0910_P1_TSCFGH, state->tscfgh | 0x01); + write_reg(state, RSTV0910_P2_TSCFGH, state->tscfgh | 0x01); + write_reg(state, RSTV0910_P1_TSCFGH, state->tscfgh); + write_reg(state, RSTV0910_P2_TSCFGH, state->tscfgh); + + write_reg(state, RSTV0910_P1_I2CRPT, state->i2crpt); + write_reg(state, RSTV0910_P2_I2CRPT, state->i2crpt); + + init_diseqc(state); + return 0; +} + +static int gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct stv *state = fe->demodulator_priv; + u8 i2crpt = state->i2crpt & ~0x86; + + /* + * mutex_lock note: Concurrent I2C gate bus accesses must be + * prevented (STV0910 = dual demod on a single IC with a single I2C + * gate/bus, and two tuners attached), similar to most (if not all) + * other I2C host interfaces/busses. + * + * enable=1 (open I2C gate) will grab the lock + * enable=0 (close I2C gate) releases the lock + */ + + if (enable) { + mutex_lock(&state->base->i2c_lock); + i2crpt |= 0x80; + } else { + i2crpt |= 0x02; + } + + if (write_reg(state, state->nr ? RSTV0910_P2_I2CRPT : + RSTV0910_P1_I2CRPT, i2crpt) < 0) { + /* don't hold the I2C bus lock on failure */ + mutex_unlock(&state->base->i2c_lock); + dev_err(&state->base->i2c->dev, + "%s() write_reg failure (enable=%d)\n", + __func__, enable); + return -EIO; + } + + state->i2crpt = i2crpt; + + if (!enable) + mutex_unlock(&state->base->i2c_lock); + return 0; +} + +static void release(struct dvb_frontend *fe) +{ + struct stv *state = fe->demodulator_priv; + + state->base->count--; + if (state->base->count == 0) { + list_del(&state->base->stvlist); + kfree(state->base); + } + kfree(state); +} + +static int set_parameters(struct dvb_frontend *fe) +{ + int stat = 0; + struct stv *state = fe->demodulator_priv; + u32 iffreq; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + + stop(state); + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe); + if (fe->ops.tuner_ops.get_if_frequency) + fe->ops.tuner_ops.get_if_frequency(fe, &iffreq); + state->symbol_rate = p->symbol_rate; + stat = start(state, p); + return stat; +} + +static int manage_matype_info(struct stv *state) +{ + if (!state->started) + return -EINVAL; + if (state->receive_mode == RCVMODE_DVBS2) { + u8 bbheader[2]; + + read_regs(state, RSTV0910_P2_MATSTR1 + state->regoff, + bbheader, 2); + state->feroll_off = + (enum fe_stv0910_roll_off)(bbheader[0] & 0x03); + state->is_vcm = (bbheader[0] & 0x10) == 0; + state->is_standard_broadcast = (bbheader[0] & 0xFC) == 0xF0; + } else if (state->receive_mode == RCVMODE_DVBS) { + state->is_vcm = 0; + state->is_standard_broadcast = 1; + state->feroll_off = FE_SAT_35; + } + return 0; +} + +static int read_snr(struct dvb_frontend *fe) +{ + struct stv *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + s32 snrval; + + if (!get_signal_to_noise(state, &snrval)) { + p->cnr.stat[0].scale = FE_SCALE_DECIBEL; + p->cnr.stat[0].uvalue = 100 * snrval; /* fix scale */ + } else { + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + return 0; +} + +static int read_ber(struct dvb_frontend *fe) +{ + struct stv *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 n, d; + + get_bit_error_rate(state, &n, &d); + + p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; + p->pre_bit_error.stat[0].uvalue = n; + p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; + p->pre_bit_count.stat[0].uvalue = d; + + return 0; +} + +static void read_signal_strength(struct dvb_frontend *fe) +{ + struct stv *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &state->fe.dtv_property_cache; + u8 reg[2]; + u16 agc; + s32 padc, power = 0; + int i; + + read_regs(state, RSTV0910_P2_AGCIQIN1 + state->regoff, reg, 2); + + agc = (((u32)reg[0]) << 8) | reg[1]; + + for (i = 0; i < 5; i += 1) { + read_regs(state, RSTV0910_P2_POWERI + state->regoff, reg, 2); + power += (u32)reg[0] * (u32)reg[0] + + (u32)reg[1] * (u32)reg[1]; + usleep_range(3000, 4000); + } + power /= 5; + + padc = table_lookup(padc_lookup, ARRAY_SIZE(padc_lookup), power) + 352; + + p->strength.stat[0].scale = FE_SCALE_DECIBEL; + p->strength.stat[0].svalue = (padc - agc); +} + +static int read_status(struct dvb_frontend *fe, enum fe_status *status) +{ + struct stv *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u8 dmd_state = 0; + u8 dstatus = 0; + enum receive_mode cur_receive_mode = RCVMODE_NONE; + u32 feclock = 0; + + *status = 0; + + read_reg(state, RSTV0910_P2_DMDSTATE + state->regoff, &dmd_state); + + if (dmd_state & 0x40) { + read_reg(state, RSTV0910_P2_DSTATUS + state->regoff, &dstatus); + if (dstatus & 0x08) + cur_receive_mode = (dmd_state & 0x20) ? + RCVMODE_DVBS : RCVMODE_DVBS2; + } + if (cur_receive_mode == RCVMODE_NONE) { + set_vth(state); + + /* reset signal statistics */ + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + return 0; + } + + *status |= (FE_HAS_SIGNAL + | FE_HAS_CARRIER + | FE_HAS_VITERBI + | FE_HAS_SYNC); + + if (state->receive_mode == RCVMODE_NONE) { + state->receive_mode = cur_receive_mode; + state->demod_lock_time = jiffies; + state->first_time_lock = 1; + + get_signal_parameters(state); + tracking_optimization(state); + + write_reg(state, RSTV0910_P2_TSCFGH + state->regoff, + state->tscfgh); + usleep_range(3000, 4000); + write_reg(state, RSTV0910_P2_TSCFGH + state->regoff, + state->tscfgh | 0x01); + write_reg(state, RSTV0910_P2_TSCFGH + state->regoff, + state->tscfgh); + } + if (dmd_state & 0x40) { + if (state->receive_mode == RCVMODE_DVBS2) { + u8 pdelstatus; + + read_reg(state, + RSTV0910_P2_PDELSTATUS1 + state->regoff, + &pdelstatus); + feclock = (pdelstatus & 0x02) != 0; + } else { + u8 vstatus; + + read_reg(state, + RSTV0910_P2_VSTATUSVIT + state->regoff, + &vstatus); + feclock = (vstatus & 0x08) != 0; + } + } + + if (feclock) { + *status |= FE_HAS_LOCK; + + if (state->first_time_lock) { + u8 tmp; + + state->first_time_lock = 0; + + manage_matype_info(state); + + if (state->receive_mode == RCVMODE_DVBS2) { + /* + * FSTV0910_P2_MANUALSX_ROLLOFF, + * FSTV0910_P2_MANUALS2_ROLLOFF = 0 + */ + state->demod_bits &= ~0x84; + write_reg(state, + RSTV0910_P2_DEMOD + state->regoff, + state->demod_bits); + read_reg(state, + RSTV0910_P2_PDELCTRL2 + state->regoff, + &tmp); + /* reset DVBS2 packet delinator error counter */ + tmp |= 0x40; + write_reg(state, + RSTV0910_P2_PDELCTRL2 + state->regoff, + tmp); + /* reset DVBS2 packet delinator error counter */ + tmp &= ~0x40; + write_reg(state, + RSTV0910_P2_PDELCTRL2 + state->regoff, + tmp); + + state->berscale = 2; + state->last_bernumerator = 0; + state->last_berdenominator = 1; + /* force to PRE BCH Rate */ + write_reg(state, + RSTV0910_P2_ERRCTRL1 + state->regoff, + BER_SRC_S2 | state->berscale); + } else { + state->berscale = 2; + state->last_bernumerator = 0; + state->last_berdenominator = 1; + /* force to PRE RS Rate */ + write_reg(state, + RSTV0910_P2_ERRCTRL1 + state->regoff, + BER_SRC_S | state->berscale); + } + /* Reset the Total packet counter */ + write_reg(state, + RSTV0910_P2_FBERCPT4 + state->regoff, 0x00); + /* + * Reset the packet Error counter2 (and Set it to + * infinit error count mode) + */ + write_reg(state, + RSTV0910_P2_ERRCTRL2 + state->regoff, 0xc1); + + set_vth_default(state); + if (state->receive_mode == RCVMODE_DVBS) + enable_puncture_rate(state, + state->puncture_rate); + } + } + + /* read signal statistics */ + + /* read signal strength */ + read_signal_strength(fe); + + /* read carrier/noise on FE_HAS_CARRIER */ + if (*status & FE_HAS_CARRIER) + read_snr(fe); + else + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + /* read ber */ + if (*status & FE_HAS_VITERBI) { + read_ber(fe); + } else { + p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + return 0; +} + +static int get_frontend(struct dvb_frontend *fe, + struct dtv_frontend_properties *p) +{ + struct stv *state = fe->demodulator_priv; + u8 tmp; + + if (state->receive_mode == RCVMODE_DVBS2) { + u32 mc; + const enum fe_modulation modcod2mod[0x20] = { + QPSK, QPSK, QPSK, QPSK, + QPSK, QPSK, QPSK, QPSK, + QPSK, QPSK, QPSK, QPSK, + PSK_8, PSK_8, PSK_8, PSK_8, + PSK_8, PSK_8, APSK_16, APSK_16, + APSK_16, APSK_16, APSK_16, APSK_16, + APSK_32, APSK_32, APSK_32, APSK_32, + APSK_32, + }; + const enum fe_code_rate modcod2fec[0x20] = { + FEC_NONE, FEC_NONE, FEC_NONE, FEC_2_5, + FEC_1_2, FEC_3_5, FEC_2_3, FEC_3_4, + FEC_4_5, FEC_5_6, FEC_8_9, FEC_9_10, + FEC_3_5, FEC_2_3, FEC_3_4, FEC_5_6, + FEC_8_9, FEC_9_10, FEC_2_3, FEC_3_4, + FEC_4_5, FEC_5_6, FEC_8_9, FEC_9_10, + FEC_3_4, FEC_4_5, FEC_5_6, FEC_8_9, + FEC_9_10 + }; + read_reg(state, RSTV0910_P2_DMDMODCOD + state->regoff, &tmp); + mc = ((tmp & 0x7c) >> 2); + p->pilot = (tmp & 0x01) ? PILOT_ON : PILOT_OFF; + p->modulation = modcod2mod[mc]; + p->fec_inner = modcod2fec[mc]; + } else if (state->receive_mode == RCVMODE_DVBS) { + read_reg(state, RSTV0910_P2_VITCURPUN + state->regoff, &tmp); + switch (tmp & 0x1F) { + case 0x0d: + p->fec_inner = FEC_1_2; + break; + case 0x12: + p->fec_inner = FEC_2_3; + break; + case 0x15: + p->fec_inner = FEC_3_4; + break; + case 0x18: + p->fec_inner = FEC_5_6; + break; + case 0x1a: + p->fec_inner = FEC_7_8; + break; + default: + p->fec_inner = FEC_NONE; + break; + } + p->rolloff = ROLLOFF_35; + } + + return 0; +} + +static int tune(struct dvb_frontend *fe, bool re_tune, + unsigned int mode_flags, + unsigned int *delay, enum fe_status *status) +{ + struct stv *state = fe->demodulator_priv; + int r; + + if (re_tune) { + r = set_parameters(fe); + if (r) + return r; + state->tune_time = jiffies; + } + + r = read_status(fe, status); + if (r) + return r; + + if (*status & FE_HAS_LOCK) + return 0; + *delay = HZ; + + return 0; +} + +static int get_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_HW; +} + +static int set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) +{ + struct stv *state = fe->demodulator_priv; + u16 offs = state->nr ? 0x40 : 0; + + switch (tone) { + case SEC_TONE_ON: + return write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x38); + case SEC_TONE_OFF: + return write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3a); + default: + break; + } + return -EINVAL; +} + +static int wait_dis(struct stv *state, u8 flag, u8 val) +{ + int i; + u8 stat; + u16 offs = state->nr ? 0x40 : 0; + + for (i = 0; i < 10; i++) { + read_reg(state, RSTV0910_P1_DISTXSTATUS + offs, &stat); + if ((stat & flag) == val) + return 0; + usleep_range(10000, 11000); + } + return -ETIMEDOUT; +} + +static int send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + struct stv *state = fe->demodulator_priv; + u16 offs = state->nr ? 0x40 : 0; + int i; + + write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E); + for (i = 0; i < cmd->msg_len; i++) { + wait_dis(state, 0x40, 0x00); + write_reg(state, RSTV0910_P1_DISTXFIFO + offs, cmd->msg[i]); + } + write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); + wait_dis(state, 0x20, 0x20); + return 0; +} + +static int send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst) +{ + struct stv *state = fe->demodulator_priv; + u16 offs = state->nr ? 0x40 : 0; + u8 value; + + if (burst == SEC_MINI_A) { + write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3F); + value = 0x00; + } else { + write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E); + value = 0xFF; + } + wait_dis(state, 0x40, 0x00); + write_reg(state, RSTV0910_P1_DISTXFIFO + offs, value); + write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); + wait_dis(state, 0x20, 0x20); + + return 0; +} + +static int sleep(struct dvb_frontend *fe) +{ + struct stv *state = fe->demodulator_priv; + + stop(state); + return 0; +} + +static const struct dvb_frontend_ops stv0910_ops = { + .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, + .info = { + .name = "ST STV0910", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 0, + .frequency_tolerance = 0, + .symbol_rate_min = 100000, + .symbol_rate_max = 70000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_2G_MODULATION | + FE_CAN_MULTISTREAM + }, + .sleep = sleep, + .release = release, + .i2c_gate_ctrl = gate_ctrl, + .set_frontend = set_parameters, + .get_frontend_algo = get_algo, + .get_frontend = get_frontend, + .tune = tune, + .read_status = read_status, + .set_tone = set_tone, + + .diseqc_send_master_cmd = send_master_cmd, + .diseqc_send_burst = send_burst, +}; + +static struct stv_base *match_base(struct i2c_adapter *i2c, u8 adr) +{ + struct stv_base *p; + + list_for_each_entry(p, &stvlist, stvlist) + if (p->i2c == i2c && p->adr == adr) + return p; + return NULL; +} + +static void stv0910_init_stats(struct stv *state) +{ + struct dtv_frontend_properties *p = &state->fe.dtv_property_cache; + + p->strength.len = 1; + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.len = 1; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_error.len = 1; + p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_count.len = 1; + p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; +} + +struct dvb_frontend *stv0910_attach(struct i2c_adapter *i2c, + struct stv0910_cfg *cfg, + int nr) +{ + struct stv *state; + struct stv_base *base; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + state->tscfgh = 0x20 | (cfg->parallel ? 0 : 0x40); + state->tsgeneral = (cfg->parallel == 2) ? 0x02 : 0x00; + state->i2crpt = 0x0A | ((cfg->rptlvl & 0x07) << 4); + state->tsspeed = 0x28; + state->nr = nr; + state->regoff = state->nr ? 0 : 0x200; + state->search_range = 16000000; + state->demod_bits = 0x10; /* Inversion : Auto with reset to 0 */ + state->receive_mode = RCVMODE_NONE; + state->cur_scrambling_code = (~0U); + state->single = cfg->single ? 1 : 0; + + base = match_base(i2c, cfg->adr); + if (base) { + base->count++; + state->base = base; + } else { + base = kzalloc(sizeof(*base), GFP_KERNEL); + if (!base) + goto fail; + base->i2c = i2c; + base->adr = cfg->adr; + base->count = 1; + base->extclk = cfg->clk ? cfg->clk : 30000000; + + mutex_init(&base->i2c_lock); + mutex_init(&base->reg_lock); + state->base = base; + if (probe(state) < 0) { + dev_info(&i2c->dev, "No demod found at adr %02X on %s\n", + cfg->adr, dev_name(&i2c->dev)); + kfree(base); + goto fail; + } + list_add(&base->stvlist, &stvlist); + } + state->fe.ops = stv0910_ops; + state->fe.demodulator_priv = state; + state->nr = nr; + + dev_info(&i2c->dev, "%s demod found at adr %02X on %s\n", + state->fe.ops.info.name, cfg->adr, dev_name(&i2c->dev)); + + stv0910_init_stats(state); + + return &state->fe; + +fail: + kfree(state); + return NULL; +} +EXPORT_SYMBOL_GPL(stv0910_attach); + +MODULE_DESCRIPTION("ST STV0910 multistandard frontend driver"); +MODULE_AUTHOR("Ralph and Marcus Metzler, Manfred Voelkel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/stv0910.h b/drivers/media/dvb-frontends/stv0910.h new file mode 100644 index 000000000000..fccd8d9b665f --- /dev/null +++ b/drivers/media/dvb-frontends/stv0910.h @@ -0,0 +1,32 @@ +#ifndef _STV0910_H_ +#define _STV0910_H_ + +#include <linux/types.h> +#include <linux/i2c.h> + +struct stv0910_cfg { + u32 clk; + u8 adr; + u8 parallel; + u8 rptlvl; + u8 single; +}; + +#if IS_REACHABLE(CONFIG_DVB_STV0910) + +struct dvb_frontend *stv0910_attach(struct i2c_adapter *i2c, + struct stv0910_cfg *cfg, int nr); + +#else + +static inline struct dvb_frontend *stv0910_attach(struct i2c_adapter *i2c, + struct stv0910_cfg *cfg, + int nr) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif /* CONFIG_DVB_STV0910 */ + +#endif /* _STV0910_H_ */ diff --git a/drivers/media/dvb-frontends/stv0910_regs.h b/drivers/media/dvb-frontends/stv0910_regs.h new file mode 100644 index 000000000000..32ced4eaf296 --- /dev/null +++ b/drivers/media/dvb-frontends/stv0910_regs.h @@ -0,0 +1,4760 @@ +/* + * @DVB-S/DVB-S2 STMicroelectronics STV0900 register definitions + * Author Manfred Voelkel, August 2013 + * (c) 2013 Digital Devices GmbH Germany. All rights reserved + * + * ======================================================================= + * Registers Declaration (Internal ST, All Applications ) + * ------------------------- + * Each register (RSTV0910__XXXXX) is defined by its address (2 bytes). + * + * Each field (FSTV0910__XXXXX)is defined as follow: + * [register address -- 2bytes][field sign -- 1byte][field mask -- 1byte] + * ====================================================================== + */ + +/* MID */ +#define RSTV0910_MID 0xf100 +#define FSTV0910_MCHIP_IDENT 0xf10000f0 +#define FSTV0910_MRELEASE 0xf100000f + +/* DID */ +#define RSTV0910_DID 0xf101 +#define FSTV0910_DEVICE_ID 0xf10100ff + +/* DACR1 */ +#define RSTV0910_DACR1 0xf113 +#define FSTV0910_DAC_MODE 0xf11300e0 +#define FSTV0910_DAC_VALUE1 0xf113000f + +/* DACR2 */ +#define RSTV0910_DACR2 0xf114 +#define FSTV0910_DAC_VALUE0 0xf11400ff + +/* PADCFG */ +#define RSTV0910_PADCFG 0xf11a +#define FSTV0910_AGCRF2_OPD 0xf11a0008 +#define FSTV0910_AGCRF2_XOR 0xf11a0004 +#define FSTV0910_AGCRF1_OPD 0xf11a0002 +#define FSTV0910_AGCRF1_XOR 0xf11a0001 + +/* OUTCFG2 */ +#define RSTV0910_OUTCFG2 0xf11b +#define FSTV0910_TS2_ERROR_XOR 0xf11b0080 +#define FSTV0910_TS2_DPN_XOR 0xf11b0040 +#define FSTV0910_TS2_STROUT_XOR 0xf11b0020 +#define FSTV0910_TS2_CLOCKOUT_XOR 0xf11b0010 +#define FSTV0910_TS1_ERROR_XOR 0xf11b0008 +#define FSTV0910_TS1_DPN_XOR 0xf11b0004 +#define FSTV0910_TS1_STROUT_XOR 0xf11b0002 +#define FSTV0910_TS1_CLOCKOUT_XOR 0xf11b0001 + +/* OUTCFG */ +#define RSTV0910_OUTCFG 0xf11c +#define FSTV0910_TS2_OUTSER_HZ 0xf11c0020 +#define FSTV0910_TS1_OUTSER_HZ 0xf11c0010 +#define FSTV0910_TS2_OUTPAR_HZ 0xf11c0008 +#define FSTV0910_TS1_OUTPAR_HZ 0xf11c0004 +#define FSTV0910_TS_SERDATA0 0xf11c0002 + +/* IRQSTATUS3 */ +#define RSTV0910_IRQSTATUS3 0xf120 +#define FSTV0910_SPLL_LOCK 0xf1200020 +#define FSTV0910_SSTREAM_LCK_1 0xf1200010 +#define FSTV0910_SSTREAM_LCK_2 0xf1200008 +#define FSTV0910_SDVBS1_PRF_2 0xf1200002 +#define FSTV0910_SDVBS1_PRF_1 0xf1200001 + +/* IRQSTATUS2 */ +#define RSTV0910_IRQSTATUS2 0xf121 +#define FSTV0910_SSPY_ENDSIM_1 0xf1210080 +#define FSTV0910_SSPY_ENDSIM_2 0xf1210040 +#define FSTV0910_SPKTDEL_ERROR_2 0xf1210010 +#define FSTV0910_SPKTDEL_LOCKB_2 0xf1210008 +#define FSTV0910_SPKTDEL_LOCK_2 0xf1210004 +#define FSTV0910_SPKTDEL_ERROR_1 0xf1210002 +#define FSTV0910_SPKTDEL_LOCKB_1 0xf1210001 + +/* IRQSTATUS1 */ +#define RSTV0910_IRQSTATUS1 0xf122 +#define FSTV0910_SPKTDEL_LOCK_1 0xf1220080 +#define FSTV0910_SFEC_LOCKB_2 0xf1220040 +#define FSTV0910_SFEC_LOCK_2 0xf1220020 +#define FSTV0910_SFEC_LOCKB_1 0xf1220010 +#define FSTV0910_SFEC_LOCK_1 0xf1220008 +#define FSTV0910_SDEMOD_LOCKB_2 0xf1220004 +#define FSTV0910_SDEMOD_LOCK_2 0xf1220002 +#define FSTV0910_SDEMOD_IRQ_2 0xf1220001 + +/* IRQSTATUS0 */ +#define RSTV0910_IRQSTATUS0 0xf123 +#define FSTV0910_SDEMOD_LOCKB_1 0xf1230080 +#define FSTV0910_SDEMOD_LOCK_1 0xf1230040 +#define FSTV0910_SDEMOD_IRQ_1 0xf1230020 +#define FSTV0910_SBCH_ERRFLAG 0xf1230010 +#define FSTV0910_SDISEQC2_IRQ 0xf1230004 +#define FSTV0910_SDISEQC1_IRQ 0xf1230001 + +/* IRQMASK3 */ +#define RSTV0910_IRQMASK3 0xf124 +#define FSTV0910_MPLL_LOCK 0xf1240020 +#define FSTV0910_MSTREAM_LCK_1 0xf1240010 +#define FSTV0910_MSTREAM_LCK_2 0xf1240008 +#define FSTV0910_MDVBS1_PRF_2 0xf1240002 +#define FSTV0910_MDVBS1_PRF_1 0xf1240001 + +/* IRQMASK2 */ +#define RSTV0910_IRQMASK2 0xf125 +#define FSTV0910_MSPY_ENDSIM_1 0xf1250080 +#define FSTV0910_MSPY_ENDSIM_2 0xf1250040 +#define FSTV0910_MPKTDEL_ERROR_2 0xf1250010 +#define FSTV0910_MPKTDEL_LOCKB_2 0xf1250008 +#define FSTV0910_MPKTDEL_LOCK_2 0xf1250004 +#define FSTV0910_MPKTDEL_ERROR_1 0xf1250002 +#define FSTV0910_MPKTDEL_LOCKB_1 0xf1250001 + +/* IRQMASK1 */ +#define RSTV0910_IRQMASK1 0xf126 +#define FSTV0910_MPKTDEL_LOCK_1 0xf1260080 +#define FSTV0910_MFEC_LOCKB_2 0xf1260040 +#define FSTV0910_MFEC_LOCK_2 0xf1260020 +#define FSTV0910_MFEC_LOCKB_1 0xf1260010 +#define FSTV0910_MFEC_LOCK_1 0xf1260008 +#define FSTV0910_MDEMOD_LOCKB_2 0xf1260004 +#define FSTV0910_MDEMOD_LOCK_2 0xf1260002 +#define FSTV0910_MDEMOD_IRQ_2 0xf1260001 + +/* IRQMASK0 */ +#define RSTV0910_IRQMASK0 0xf127 +#define FSTV0910_MDEMOD_LOCKB_1 0xf1270080 +#define FSTV0910_MDEMOD_LOCK_1 0xf1270040 +#define FSTV0910_MDEMOD_IRQ_1 0xf1270020 +#define FSTV0910_MBCH_ERRFLAG 0xf1270010 +#define FSTV0910_MDISEQC2_IRQ 0xf1270004 +#define FSTV0910_MDISEQC1_IRQ 0xf1270001 + +/* I2CCFG */ +#define RSTV0910_I2CCFG 0xf129 +#define FSTV0910_I2C_FASTMODE 0xf1290008 +#define FSTV0910_I2CADDR_INC 0xf1290003 + +/* P1_I2CRPT */ +#define RSTV0910_P1_I2CRPT 0xf12a +#define FSTV0910_P1_I2CT_ON 0xf12a0080 +#define FSTV0910_P1_ENARPT_LEVEL 0xf12a0070 +#define FSTV0910_P1_SCLT_DELAY 0xf12a0008 +#define FSTV0910_P1_STOP_ENABLE 0xf12a0004 +#define FSTV0910_P1_STOP_SDAT2SDA 0xf12a0002 + +/* P2_I2CRPT */ +#define RSTV0910_P2_I2CRPT 0xf12b +#define FSTV0910_P2_I2CT_ON 0xf12b0080 +#define FSTV0910_P2_ENARPT_LEVEL 0xf12b0070 +#define FSTV0910_P2_SCLT_DELAY 0xf12b0008 +#define FSTV0910_P2_STOP_ENABLE 0xf12b0004 +#define FSTV0910_P2_STOP_SDAT2SDA 0xf12b0002 + +/* GPIO0CFG */ +#define RSTV0910_GPIO0CFG 0xf140 +#define FSTV0910_GPIO0_OPD 0xf1400080 +#define FSTV0910_GPIO0_CONFIG 0xf140007e +#define FSTV0910_GPIO0_XOR 0xf1400001 + +/* GPIO1CFG */ +#define RSTV0910_GPIO1CFG 0xf141 +#define FSTV0910_GPIO1_OPD 0xf1410080 +#define FSTV0910_GPIO1_CONFIG 0xf141007e +#define FSTV0910_GPIO1_XOR 0xf1410001 + +/* GPIO2CFG */ +#define RSTV0910_GPIO2CFG 0xf142 +#define FSTV0910_GPIO2_OPD 0xf1420080 +#define FSTV0910_GPIO2_CONFIG 0xf142007e +#define FSTV0910_GPIO2_XOR 0xf1420001 + +/* GPIO3CFG */ +#define RSTV0910_GPIO3CFG 0xf143 +#define FSTV0910_GPIO3_OPD 0xf1430080 +#define FSTV0910_GPIO3_CONFIG 0xf143007e +#define FSTV0910_GPIO3_XOR 0xf1430001 + +/* GPIO4CFG */ +#define RSTV0910_GPIO4CFG 0xf144 +#define FSTV0910_GPIO4_OPD 0xf1440080 +#define FSTV0910_GPIO4_CONFIG 0xf144007e +#define FSTV0910_GPIO4_XOR 0xf1440001 + +/* GPIO5CFG */ +#define RSTV0910_GPIO5CFG 0xf145 +#define FSTV0910_GPIO5_OPD 0xf1450080 +#define FSTV0910_GPIO5_CONFIG 0xf145007e +#define FSTV0910_GPIO5_XOR 0xf1450001 + +/* GPIO6CFG */ +#define RSTV0910_GPIO6CFG 0xf146 +#define FSTV0910_GPIO6_OPD 0xf1460080 +#define FSTV0910_GPIO6_CONFIG 0xf146007e +#define FSTV0910_GPIO6_XOR 0xf1460001 + +/* GPIO7CFG */ +#define RSTV0910_GPIO7CFG 0xf147 +#define FSTV0910_GPIO7_OPD 0xf1470080 +#define FSTV0910_GPIO7_CONFIG 0xf147007e +#define FSTV0910_GPIO7_XOR 0xf1470001 + +/* GPIO8CFG */ +#define RSTV0910_GPIO8CFG 0xf148 +#define FSTV0910_GPIO8_OPD 0xf1480080 +#define FSTV0910_GPIO8_CONFIG 0xf148007e +#define FSTV0910_GPIO8_XOR 0xf1480001 + +/* GPIO9CFG */ +#define RSTV0910_GPIO9CFG 0xf149 +#define FSTV0910_GPIO9_OPD 0xf1490080 +#define FSTV0910_GPIO9_CONFIG 0xf149007e +#define FSTV0910_GPIO9_XOR 0xf1490001 + +/* GPIO10CFG */ +#define RSTV0910_GPIO10CFG 0xf14a +#define FSTV0910_GPIO10_OPD 0xf14a0080 +#define FSTV0910_GPIO10_CONFIG 0xf14a007e +#define FSTV0910_GPIO10_XOR 0xf14a0001 + +/* GPIO11CFG */ +#define RSTV0910_GPIO11CFG 0xf14b +#define FSTV0910_GPIO11_OPD 0xf14b0080 +#define FSTV0910_GPIO11_CONFIG 0xf14b007e +#define FSTV0910_GPIO11_XOR 0xf14b0001 + +/* GPIO12CFG */ +#define RSTV0910_GPIO12CFG 0xf14c +#define FSTV0910_GPIO12_OPD 0xf14c0080 +#define FSTV0910_GPIO12_CONFIG 0xf14c007e +#define FSTV0910_GPIO12_XOR 0xf14c0001 + +/* GPIO13CFG */ +#define RSTV0910_GPIO13CFG 0xf14d +#define FSTV0910_GPIO13_OPD 0xf14d0080 +#define FSTV0910_GPIO13_CONFIG 0xf14d007e +#define FSTV0910_GPIO13_XOR 0xf14d0001 + +/* GPIO14CFG */ +#define RSTV0910_GPIO14CFG 0xf14e +#define FSTV0910_GPIO14_OPD 0xf14e0080 +#define FSTV0910_GPIO14_CONFIG 0xf14e007e +#define FSTV0910_GPIO14_XOR 0xf14e0001 + +/* GPIO15CFG */ +#define RSTV0910_GPIO15CFG 0xf14f +#define FSTV0910_GPIO15_OPD 0xf14f0080 +#define FSTV0910_GPIO15_CONFIG 0xf14f007e +#define FSTV0910_GPIO15_XOR 0xf14f0001 + +/* GPIO16CFG */ +#define RSTV0910_GPIO16CFG 0xf150 +#define FSTV0910_GPIO16_OPD 0xf1500080 +#define FSTV0910_GPIO16_CONFIG 0xf150007e +#define FSTV0910_GPIO16_XOR 0xf1500001 + +/* GPIO17CFG */ +#define RSTV0910_GPIO17CFG 0xf151 +#define FSTV0910_GPIO17_OPD 0xf1510080 +#define FSTV0910_GPIO17_CONFIG 0xf151007e +#define FSTV0910_GPIO17_XOR 0xf1510001 + +/* GPIO18CFG */ +#define RSTV0910_GPIO18CFG 0xf152 +#define FSTV0910_GPIO18_OPD 0xf1520080 +#define FSTV0910_GPIO18_CONFIG 0xf152007e +#define FSTV0910_GPIO18_XOR 0xf1520001 + +/* GPIO19CFG */ +#define RSTV0910_GPIO19CFG 0xf153 +#define FSTV0910_GPIO19_OPD 0xf1530080 +#define FSTV0910_GPIO19_CONFIG 0xf153007e +#define FSTV0910_GPIO19_XOR 0xf1530001 + +/* GPIO20CFG */ +#define RSTV0910_GPIO20CFG 0xf154 +#define FSTV0910_GPIO20_OPD 0xf1540080 +#define FSTV0910_GPIO20_CONFIG 0xf154007e +#define FSTV0910_GPIO20_XOR 0xf1540001 + +/* GPIO21CFG */ +#define RSTV0910_GPIO21CFG 0xf155 +#define FSTV0910_GPIO21_OPD 0xf1550080 +#define FSTV0910_GPIO21_CONFIG 0xf155007e +#define FSTV0910_GPIO21_XOR 0xf1550001 + +/* GPIO22CFG */ +#define RSTV0910_GPIO22CFG 0xf156 +#define FSTV0910_GPIO22_OPD 0xf1560080 +#define FSTV0910_GPIO22_CONFIG 0xf156007e +#define FSTV0910_GPIO22_XOR 0xf1560001 + +/* STRSTATUS1 */ +#define RSTV0910_STRSTATUS1 0xf16a +#define FSTV0910_STRSTATUS_SEL2 0xf16a00f0 +#define FSTV0910_STRSTATUS_SEL1 0xf16a000f + +/* STRSTATUS2 */ +#define RSTV0910_STRSTATUS2 0xf16b +#define FSTV0910_STRSTATUS_SEL4 0xf16b00f0 +#define FSTV0910_STRSTATUS_SEL3 0xf16b000f + +/* STRSTATUS3 */ +#define RSTV0910_STRSTATUS3 0xf16c +#define FSTV0910_STRSTATUS_SEL6 0xf16c00f0 +#define FSTV0910_STRSTATUS_SEL5 0xf16c000f + +/* FSKTFC2 */ +#define RSTV0910_FSKTFC2 0xf170 +#define FSTV0910_FSKT_KMOD 0xf17000fc +#define FSTV0910_FSKT_CAR2 0xf1700003 + +/* FSKTFC1 */ +#define RSTV0910_FSKTFC1 0xf171 +#define FSTV0910_FSKT_CAR1 0xf17100ff + +/* FSKTFC0 */ +#define RSTV0910_FSKTFC0 0xf172 +#define FSTV0910_FSKT_CAR0 0xf17200ff + +/* FSKTDELTAF1 */ +#define RSTV0910_FSKTDELTAF1 0xf173 +#define FSTV0910_FSKT_DELTAF1 0xf173000f + +/* FSKTDELTAF0 */ +#define RSTV0910_FSKTDELTAF0 0xf174 +#define FSTV0910_FSKT_DELTAF0 0xf17400ff + +/* FSKTCTRL */ +#define RSTV0910_FSKTCTRL 0xf175 +#define FSTV0910_FSKT_PINSEL 0xf1750080 +#define FSTV0910_FSKT_EN_SGN 0xf1750040 +#define FSTV0910_FSKT_MOD_SGN 0xf1750020 +#define FSTV0910_FSKT_MOD_EN 0xf175001c +#define FSTV0910_FSKT_DACMODE 0xf1750003 + +/* FSKRFC2 */ +#define RSTV0910_FSKRFC2 0xf176 +#define FSTV0910_FSKR_DETSGN 0xf1760040 +#define FSTV0910_FSKR_OUTSGN 0xf1760020 +#define FSTV0910_FSKR_KAGC 0xf176001c +#define FSTV0910_FSKR_CAR2 0xf1760003 + +/* FSKRFC1 */ +#define RSTV0910_FSKRFC1 0xf177 +#define FSTV0910_FSKR_CAR1 0xf17700ff + +/* FSKRFC0 */ +#define RSTV0910_FSKRFC0 0xf178 +#define FSTV0910_FSKR_CAR0 0xf17800ff + +/* FSKRK1 */ +#define RSTV0910_FSKRK1 0xf179 +#define FSTV0910_FSKR_K1_EXP 0xf17900e0 +#define FSTV0910_FSKR_K1_MANT 0xf179001f + +/* FSKRK2 */ +#define RSTV0910_FSKRK2 0xf17a +#define FSTV0910_FSKR_K2_EXP 0xf17a00e0 +#define FSTV0910_FSKR_K2_MANT 0xf17a001f + +/* FSKRAGCR */ +#define RSTV0910_FSKRAGCR 0xf17b +#define FSTV0910_FSKR_OUTCTL 0xf17b00c0 +#define FSTV0910_FSKR_AGC_REF 0xf17b003f + +/* FSKRAGC */ +#define RSTV0910_FSKRAGC 0xf17c +#define FSTV0910_FSKR_AGC_ACCU 0xf17c00ff + +/* FSKRALPHA */ +#define RSTV0910_FSKRALPHA 0xf17d +#define FSTV0910_FSKR_ALPHA_EXP 0xf17d001c +#define FSTV0910_FSKR_ALPHA_M 0xf17d0003 + +/* FSKRPLTH1 */ +#define RSTV0910_FSKRPLTH1 0xf17e +#define FSTV0910_FSKR_BETA 0xf17e00f0 +#define FSTV0910_FSKR_PLL_TRESH1 0xf17e000f + +/* FSKRPLTH0 */ +#define RSTV0910_FSKRPLTH0 0xf17f +#define FSTV0910_FSKR_PLL_TRESH0 0xf17f00ff + +/* FSKRDF1 */ +#define RSTV0910_FSKRDF1 0xf180 +#define FSTV0910_FSKR_OUT 0xf1800080 +#define FSTV0910_FSKR_STATE 0xf1800060 +#define FSTV0910_FSKR_DELTAF1 0xf180001f + +/* FSKRDF0 */ +#define RSTV0910_FSKRDF0 0xf181 +#define FSTV0910_FSKR_DELTAF0 0xf18100ff + +/* FSKRSTEPP */ +#define RSTV0910_FSKRSTEPP 0xf182 +#define FSTV0910_FSKR_STEP_PLUS 0xf18200ff + +/* FSKRSTEPM */ +#define RSTV0910_FSKRSTEPM 0xf183 +#define FSTV0910_FSKR_STEP_MINUS 0xf18300ff + +/* FSKRDET1 */ +#define RSTV0910_FSKRDET1 0xf184 +#define FSTV0910_FSKR_DETECT 0xf1840080 +#define FSTV0910_FSKR_CARDET_ACCU1 0xf184000f + +/* FSKRDET0 */ +#define RSTV0910_FSKRDET0 0xf185 +#define FSTV0910_FSKR_CARDET_ACCU0 0xf18500ff + +/* FSKRDTH1 */ +#define RSTV0910_FSKRDTH1 0xf186 +#define FSTV0910_FSKR_CARLOSS_THRESH1 0xf18600f0 +#define FSTV0910_FSKR_CARDET_THRESH1 0xf186000f + +/* FSKRDTH0 */ +#define RSTV0910_FSKRDTH0 0xf187 +#define FSTV0910_FSKR_CARDET_THRESH0 0xf18700ff + +/* FSKRLOSS */ +#define RSTV0910_FSKRLOSS 0xf188 +#define FSTV0910_FSKR_CARLOSS_THRESH0 0xf18800ff + +/* NCOARSE */ +#define RSTV0910_NCOARSE 0xf1b3 +#define FSTV0910_CP 0xf1b300f8 +#define FSTV0910_IDF 0xf1b30007 + +/* NCOARSE1 */ +#define RSTV0910_NCOARSE1 0xf1b4 +#define FSTV0910_N_DIV 0xf1b400ff + +/* NCOARSE2 */ +#define RSTV0910_NCOARSE2 0xf1b5 +#define FSTV0910_ODF 0xf1b5003f + +/* SYNTCTRL */ +#define RSTV0910_SYNTCTRL 0xf1b6 +#define FSTV0910_STANDBY 0xf1b60080 +#define FSTV0910_BYPASSPLLCORE 0xf1b60040 +#define FSTV0910_STOP_PLL 0xf1b60008 +#define FSTV0910_OSCI_E 0xf1b60002 + +/* FILTCTRL */ +#define RSTV0910_FILTCTRL 0xf1b7 +#define FSTV0910_INV_CLKFSK 0xf1b70002 +#define FSTV0910_BYPASS_APPLI 0xf1b70001 + +/* PLLSTAT */ +#define RSTV0910_PLLSTAT 0xf1b8 +#define FSTV0910_PLLLOCK 0xf1b80001 + +/* STOPCLK1 */ +#define RSTV0910_STOPCLK1 0xf1c2 +#define FSTV0910_INV_CLKADCI2 0xf1c20004 +#define FSTV0910_INV_CLKADCI1 0xf1c20001 + +/* STOPCLK2 */ +#define RSTV0910_STOPCLK2 0xf1c3 +#define FSTV0910_STOP_DVBS2FEC2 0xf1c30020 +#define FSTV0910_STOP_DVBS2FEC 0xf1c30010 +#define FSTV0910_STOP_DVBS1FEC2 0xf1c30008 +#define FSTV0910_STOP_DVBS1FEC 0xf1c30004 +#define FSTV0910_STOP_DEMOD2 0xf1c30002 +#define FSTV0910_STOP_DEMOD 0xf1c30001 + +/* PREGCTL */ +#define RSTV0910_PREGCTL 0xf1c8 +#define FSTV0910_REG3V3TO2V5_POFF 0xf1c80080 + +/* TSTTNR0 */ +#define RSTV0910_TSTTNR0 0xf1df +#define FSTV0910_FSK_PON 0xf1df0004 + +/* TSTTNR1 */ +#define RSTV0910_TSTTNR1 0xf1e0 +#define FSTV0910_ADC1_PON 0xf1e00002 + +/* TSTTNR2 */ +#define RSTV0910_TSTTNR2 0xf1e1 +#define FSTV0910_I2C_DISEQC_PON 0xf1e10020 +#define FSTV0910_DISEQC_CLKDIV 0xf1e1000f + +/* TSTTNR3 */ +#define RSTV0910_TSTTNR3 0xf1e2 +#define FSTV0910_ADC2_PON 0xf1e20002 + +/* P2_IQCONST */ +#define RSTV0910_P2_IQCONST 0xf200 +#define FSTV0910_P2_CONSTEL_SELECT 0xf2000060 +#define FSTV0910_P2_IQSYMB_SEL 0xf200001f + +/* P2_NOSCFG */ +#define RSTV0910_P2_NOSCFG 0xf201 +#define FSTV0910_P2_DUMMYPL_NOSDATA 0xf2010020 +#define FSTV0910_P2_NOSPLH_BETA 0xf2010018 +#define FSTV0910_P2_NOSDATA_BETA 0xf2010007 + +/* P2_ISYMB */ +#define RSTV0910_P2_ISYMB 0xf202 +#define FSTV0910_P2_I_SYMBOL 0xf20201ff + +/* P2_QSYMB */ +#define RSTV0910_P2_QSYMB 0xf203 +#define FSTV0910_P2_Q_SYMBOL 0xf20301ff + +/* P2_AGC1CFG */ +#define RSTV0910_P2_AGC1CFG 0xf204 +#define FSTV0910_P2_DC_FROZEN 0xf2040080 +#define FSTV0910_P2_DC_CORRECT 0xf2040040 +#define FSTV0910_P2_AMM_FROZEN 0xf2040020 +#define FSTV0910_P2_AMM_CORRECT 0xf2040010 +#define FSTV0910_P2_QUAD_FROZEN 0xf2040008 +#define FSTV0910_P2_QUAD_CORRECT 0xf2040004 + +/* P2_AGC1CN */ +#define RSTV0910_P2_AGC1CN 0xf206 +#define FSTV0910_P2_AGC1_LOCKED 0xf2060080 +#define FSTV0910_P2_AGC1_MINPOWER 0xf2060010 +#define FSTV0910_P2_AGCOUT_FAST 0xf2060008 +#define FSTV0910_P2_AGCIQ_BETA 0xf2060007 + +/* P2_AGC1REF */ +#define RSTV0910_P2_AGC1REF 0xf207 +#define FSTV0910_P2_AGCIQ_REF 0xf20700ff + +/* P2_IDCCOMP */ +#define RSTV0910_P2_IDCCOMP 0xf208 +#define FSTV0910_P2_IAVERAGE_ADJ 0xf20801ff + +/* P2_QDCCOMP */ +#define RSTV0910_P2_QDCCOMP 0xf209 +#define FSTV0910_P2_QAVERAGE_ADJ 0xf20901ff + +/* P2_POWERI */ +#define RSTV0910_P2_POWERI 0xf20a +#define FSTV0910_P2_POWER_I 0xf20a00ff + +/* P2_POWERQ */ +#define RSTV0910_P2_POWERQ 0xf20b +#define FSTV0910_P2_POWER_Q 0xf20b00ff + +/* P2_AGC1AMM */ +#define RSTV0910_P2_AGC1AMM 0xf20c +#define FSTV0910_P2_AMM_VALUE 0xf20c00ff + +/* P2_AGC1QUAD */ +#define RSTV0910_P2_AGC1QUAD 0xf20d +#define FSTV0910_P2_QUAD_VALUE 0xf20d01ff + +/* P2_AGCIQIN1 */ +#define RSTV0910_P2_AGCIQIN1 0xf20e +#define FSTV0910_P2_AGCIQ_VALUE1 0xf20e00ff + +/* P2_AGCIQIN0 */ +#define RSTV0910_P2_AGCIQIN0 0xf20f +#define FSTV0910_P2_AGCIQ_VALUE0 0xf20f00ff + +/* P2_DEMOD */ +#define RSTV0910_P2_DEMOD 0xf210 +#define FSTV0910_P2_MANUALS2_ROLLOFF 0xf2100080 +#define FSTV0910_P2_SPECINV_CONTROL 0xf2100030 +#define FSTV0910_P2_MANUALSX_ROLLOFF 0xf2100004 +#define FSTV0910_P2_ROLLOFF_CONTROL 0xf2100003 + +/* P2_DMDMODCOD */ +#define RSTV0910_P2_DMDMODCOD 0xf211 +#define FSTV0910_P2_MANUAL_MODCOD 0xf2110080 +#define FSTV0910_P2_DEMOD_MODCOD 0xf211007c +#define FSTV0910_P2_DEMOD_TYPE 0xf2110003 + +/* P2_DSTATUS */ +#define RSTV0910_P2_DSTATUS 0xf212 +#define FSTV0910_P2_CAR_LOCK 0xf2120080 +#define FSTV0910_P2_TMGLOCK_QUALITY 0xf2120060 +#define FSTV0910_P2_LOCK_DEFINITIF 0xf2120008 +#define FSTV0910_P2_OVADC_DETECT 0xf2120001 + +/* P2_DSTATUS2 */ +#define RSTV0910_P2_DSTATUS2 0xf213 +#define FSTV0910_P2_DEMOD_DELOCK 0xf2130080 +#define FSTV0910_P2_MODCODRQ_SYNCTAG 0xf2130020 +#define FSTV0910_P2_POLYPH_SATEVENT 0xf2130010 +#define FSTV0910_P2_AGC1_NOSIGNALACK 0xf2130008 +#define FSTV0910_P2_AGC2_OVERFLOW 0xf2130004 +#define FSTV0910_P2_CFR_OVERFLOW 0xf2130002 +#define FSTV0910_P2_GAMMA_OVERUNDER 0xf2130001 + +/* P2_DMDCFGMD */ +#define RSTV0910_P2_DMDCFGMD 0xf214 +#define FSTV0910_P2_DVBS2_ENABLE 0xf2140080 +#define FSTV0910_P2_DVBS1_ENABLE 0xf2140040 +#define FSTV0910_P2_SCAN_ENABLE 0xf2140010 +#define FSTV0910_P2_CFR_AUTOSCAN 0xf2140008 +#define FSTV0910_P2_TUN_RNG 0xf2140003 + +/* P2_DMDCFG2 */ +#define RSTV0910_P2_DMDCFG2 0xf215 +#define FSTV0910_P2_S1S2_SEQUENTIAL 0xf2150040 +#define FSTV0910_P2_INFINITE_RELOCK 0xf2150010 + +/* P2_DMDISTATE */ +#define RSTV0910_P2_DMDISTATE 0xf216 +#define FSTV0910_P2_I2C_NORESETDMODE 0xf2160080 +#define FSTV0910_P2_I2C_DEMOD_MODE 0xf216001f + +/* P2_DMDT0M */ +#define RSTV0910_P2_DMDT0M 0xf217 +#define FSTV0910_P2_DMDT0_MIN 0xf21700ff + +/* P2_DMDSTATE */ +#define RSTV0910_P2_DMDSTATE 0xf21b +#define FSTV0910_P2_HEADER_MODE 0xf21b0060 + +/* P2_DMDFLYW */ +#define RSTV0910_P2_DMDFLYW 0xf21c +#define FSTV0910_P2_I2C_IRQVAL 0xf21c00f0 +#define FSTV0910_P2_FLYWHEEL_CPT 0xf21c000f + +/* P2_DSTATUS3 */ +#define RSTV0910_P2_DSTATUS3 0xf21d +#define FSTV0910_P2_CFR_ZIGZAG 0xf21d0080 +#define FSTV0910_P2_DEMOD_CFGMODE 0xf21d0060 +#define FSTV0910_P2_GAMMA_LOWBAUDRATE 0xf21d0010 + +/* P2_DMDCFG3 */ +#define RSTV0910_P2_DMDCFG3 0xf21e +#define FSTV0910_P2_NOSTOP_FIFOFULL 0xf21e0008 + +/* P2_DMDCFG4 */ +#define RSTV0910_P2_DMDCFG4 0xf21f +#define FSTV0910_P2_DIS_VITLOCK 0xf21f0080 +#define FSTV0910_P2_DIS_CLKENABLE 0xf21f0004 + +/* P2_CORRELMANT */ +#define RSTV0910_P2_CORRELMANT 0xf220 +#define FSTV0910_P2_CORREL_MANT 0xf22000ff + +/* P2_CORRELABS */ +#define RSTV0910_P2_CORRELABS 0xf221 +#define FSTV0910_P2_CORREL_ABS 0xf22100ff + +/* P2_CORRELEXP */ +#define RSTV0910_P2_CORRELEXP 0xf222 +#define FSTV0910_P2_CORREL_ABSEXP 0xf22200f0 +#define FSTV0910_P2_CORREL_EXP 0xf222000f + +/* P2_PLHMODCOD */ +#define RSTV0910_P2_PLHMODCOD 0xf224 +#define FSTV0910_P2_SPECINV_DEMOD 0xf2240080 +#define FSTV0910_P2_PLH_MODCOD 0xf224007c +#define FSTV0910_P2_PLH_TYPE 0xf2240003 + +/* P2_DMDREG */ +#define RSTV0910_P2_DMDREG 0xf225 +#define FSTV0910_P2_DECIM_PLFRAMES 0xf2250001 + +/* P2_AGCNADJ */ +#define RSTV0910_P2_AGCNADJ 0xf226 +#define FSTV0910_P2_RADJOFF_AGC2 0xf2260080 +#define FSTV0910_P2_RADJOFF_AGC1 0xf2260040 +#define FSTV0910_P2_AGC_NADJ 0xf226013f + +/* P2_AGCKS */ +#define RSTV0910_P2_AGCKS 0xf227 +#define FSTV0910_P2_RSADJ_MANUALCFG 0xf2270080 +#define FSTV0910_P2_RSADJ_CCMMODE 0xf2270040 +#define FSTV0910_P2_RADJ_SPSK 0xf227013f + +/* P2_AGCKQ */ +#define RSTV0910_P2_AGCKQ 0xf228 +#define FSTV0910_P2_RADJON_DVBS1 0xf2280040 +#define FSTV0910_P2_RADJ_QPSK 0xf228013f + +/* P2_AGCK8 */ +#define RSTV0910_P2_AGCK8 0xf229 +#define FSTV0910_P2_RADJ_8PSK 0xf229013f + +/* P2_AGCK16 */ +#define RSTV0910_P2_AGCK16 0xf22a +#define FSTV0910_P2_R2ADJOFF_16APSK 0xf22a0040 +#define FSTV0910_P2_R1ADJOFF_16APSK 0xf22a0020 +#define FSTV0910_P2_RADJ_16APSK 0xf22a011f + +/* P2_AGCK32 */ +#define RSTV0910_P2_AGCK32 0xf22b +#define FSTV0910_P2_R3ADJOFF_32APSK 0xf22b0080 +#define FSTV0910_P2_R2ADJOFF_32APSK 0xf22b0040 +#define FSTV0910_P2_R1ADJOFF_32APSK 0xf22b0020 +#define FSTV0910_P2_RADJ_32APSK 0xf22b011f + +/* P2_AGC2O */ +#define RSTV0910_P2_AGC2O 0xf22c +#define FSTV0910_P2_CSTENV_MODE 0xf22c00c0 +#define FSTV0910_P2_AGC2_COEF 0xf22c0007 + +/* P2_AGC2REF */ +#define RSTV0910_P2_AGC2REF 0xf22d +#define FSTV0910_P2_AGC2_REF 0xf22d00ff + +/* P2_AGC1ADJ */ +#define RSTV0910_P2_AGC1ADJ 0xf22e +#define FSTV0910_P2_AGC1_ADJUSTED 0xf22e007f + +/* P2_AGCRSADJ */ +#define RSTV0910_P2_AGCRSADJ 0xf22f +#define FSTV0910_P2_RS_ADJUSTED 0xf22f007f + +/* P2_AGCRQADJ */ +#define RSTV0910_P2_AGCRQADJ 0xf230 +#define FSTV0910_P2_RQ_ADJUSTED 0xf230007f + +/* P2_AGCR8ADJ */ +#define RSTV0910_P2_AGCR8ADJ 0xf231 +#define FSTV0910_P2_R8_ADJUSTED 0xf231007f + +/* P2_AGCR1ADJ */ +#define RSTV0910_P2_AGCR1ADJ 0xf232 +#define FSTV0910_P2_R1_ADJUSTED 0xf232007f + +/* P2_AGCR2ADJ */ +#define RSTV0910_P2_AGCR2ADJ 0xf233 +#define FSTV0910_P2_R2_ADJUSTED 0xf233007f + +/* P2_AGCR3ADJ */ +#define RSTV0910_P2_AGCR3ADJ 0xf234 +#define FSTV0910_P2_R3_ADJUSTED 0xf234007f + +/* P2_AGCREFADJ */ +#define RSTV0910_P2_AGCREFADJ 0xf235 +#define FSTV0910_P2_AGC2REF_ADJUSTED 0xf235007f + +/* P2_AGC2I1 */ +#define RSTV0910_P2_AGC2I1 0xf236 +#define FSTV0910_P2_AGC2_INTEGRATOR1 0xf23600ff + +/* P2_AGC2I0 */ +#define RSTV0910_P2_AGC2I0 0xf237 +#define FSTV0910_P2_AGC2_INTEGRATOR0 0xf23700ff + +/* P2_CARCFG */ +#define RSTV0910_P2_CARCFG 0xf238 +#define FSTV0910_P2_ROTAON 0xf2380004 +#define FSTV0910_P2_PH_DET_ALGO 0xf2380003 + +/* P2_ACLC */ +#define RSTV0910_P2_ACLC 0xf239 +#define FSTV0910_P2_CAR_ALPHA_MANT 0xf2390030 +#define FSTV0910_P2_CAR_ALPHA_EXP 0xf239000f + +/* P2_BCLC */ +#define RSTV0910_P2_BCLC 0xf23a +#define FSTV0910_P2_CAR_BETA_MANT 0xf23a0030 +#define FSTV0910_P2_CAR_BETA_EXP 0xf23a000f + +/* P2_ACLCS2 */ +#define RSTV0910_P2_ACLCS2 0xf23b +#define FSTV0910_P2_CARS2_APLHA_MANTISSE 0xf23b0030 +#define FSTV0910_P2_CARS2_ALPHA_EXP 0xf23b000f + +/* P2_BCLCS2 */ +#define RSTV0910_P2_BCLCS2 0xf23c +#define FSTV0910_P2_CARS2_BETA_MANTISSE 0xf23c0030 +#define FSTV0910_P2_CARS2_BETA_EXP 0xf23c000f + +/* P2_CARFREQ */ +#define RSTV0910_P2_CARFREQ 0xf23d +#define FSTV0910_P2_KC_COARSE_EXP 0xf23d00f0 +#define FSTV0910_P2_BETA_FREQ 0xf23d000f + +/* P2_CARHDR */ +#define RSTV0910_P2_CARHDR 0xf23e +#define FSTV0910_P2_K_FREQ_HDR 0xf23e00ff + +/* P2_LDT */ +#define RSTV0910_P2_LDT 0xf23f +#define FSTV0910_P2_CARLOCK_THRES 0xf23f01ff + +/* P2_LDT2 */ +#define RSTV0910_P2_LDT2 0xf240 +#define FSTV0910_P2_CARLOCK_THRES2 0xf24001ff + +/* P2_CFRICFG */ +#define RSTV0910_P2_CFRICFG 0xf241 +#define FSTV0910_P2_NEG_CFRSTEP 0xf2410001 + +/* P2_CFRUP1 */ +#define RSTV0910_P2_CFRUP1 0xf242 +#define FSTV0910_P2_CFR_UP1 0xf24201ff + +/* P2_CFRUP0 */ +#define RSTV0910_P2_CFRUP0 0xf243 +#define FSTV0910_P2_CFR_UP0 0xf24300ff + +/* P2_CFRIBASE1 */ +#define RSTV0910_P2_CFRIBASE1 0xf244 +#define FSTV0910_P2_CFRINIT_BASE1 0xf24400ff + +/* P2_CFRIBASE0 */ +#define RSTV0910_P2_CFRIBASE0 0xf245 +#define FSTV0910_P2_CFRINIT_BASE0 0xf24500ff + +/* P2_CFRLOW1 */ +#define RSTV0910_P2_CFRLOW1 0xf246 +#define FSTV0910_P2_CFR_LOW1 0xf24601ff + +/* P2_CFRLOW0 */ +#define RSTV0910_P2_CFRLOW0 0xf247 +#define FSTV0910_P2_CFR_LOW0 0xf24700ff + +/* P2_CFRINIT1 */ +#define RSTV0910_P2_CFRINIT1 0xf248 +#define FSTV0910_P2_CFR_INIT1 0xf24801ff + +/* P2_CFRINIT0 */ +#define RSTV0910_P2_CFRINIT0 0xf249 +#define FSTV0910_P2_CFR_INIT0 0xf24900ff + +/* P2_CFRINC1 */ +#define RSTV0910_P2_CFRINC1 0xf24a +#define FSTV0910_P2_MANUAL_CFRINC 0xf24a0080 +#define FSTV0910_P2_CFR_INC1 0xf24a003f + +/* P2_CFRINC0 */ +#define RSTV0910_P2_CFRINC0 0xf24b +#define FSTV0910_P2_CFR_INC0 0xf24b00ff + +/* P2_CFR2 */ +#define RSTV0910_P2_CFR2 0xf24c +#define FSTV0910_P2_CAR_FREQ2 0xf24c01ff + +/* P2_CFR1 */ +#define RSTV0910_P2_CFR1 0xf24d +#define FSTV0910_P2_CAR_FREQ1 0xf24d00ff + +/* P2_CFR0 */ +#define RSTV0910_P2_CFR0 0xf24e +#define FSTV0910_P2_CAR_FREQ0 0xf24e00ff + +/* P2_LDI */ +#define RSTV0910_P2_LDI 0xf24f +#define FSTV0910_P2_LOCK_DET_INTEGR 0xf24f01ff + +/* P2_TMGCFG */ +#define RSTV0910_P2_TMGCFG 0xf250 +#define FSTV0910_P2_TMGLOCK_BETA 0xf25000c0 +#define FSTV0910_P2_DO_TIMING_CORR 0xf2500010 +#define FSTV0910_P2_TMG_MINFREQ 0xf2500003 + +/* P2_RTC */ +#define RSTV0910_P2_RTC 0xf251 +#define FSTV0910_P2_TMGALPHA_EXP 0xf25100f0 +#define FSTV0910_P2_TMGBETA_EXP 0xf251000f + +/* P2_RTCS2 */ +#define RSTV0910_P2_RTCS2 0xf252 +#define FSTV0910_P2_TMGALPHAS2_EXP 0xf25200f0 +#define FSTV0910_P2_TMGBETAS2_EXP 0xf252000f + +/* P2_TMGTHRISE */ +#define RSTV0910_P2_TMGTHRISE 0xf253 +#define FSTV0910_P2_TMGLOCK_THRISE 0xf25300ff + +/* P2_TMGTHFALL */ +#define RSTV0910_P2_TMGTHFALL 0xf254 +#define FSTV0910_P2_TMGLOCK_THFALL 0xf25400ff + +/* P2_SFRUPRATIO */ +#define RSTV0910_P2_SFRUPRATIO 0xf255 +#define FSTV0910_P2_SFR_UPRATIO 0xf25500ff + +/* P2_SFRLOWRATIO */ +#define RSTV0910_P2_SFRLOWRATIO 0xf256 +#define FSTV0910_P2_SFR_LOWRATIO 0xf25600ff + +/* P2_KTTMG */ +#define RSTV0910_P2_KTTMG 0xf257 +#define FSTV0910_P2_KT_TMG_EXP 0xf25700f0 + +/* P2_KREFTMG */ +#define RSTV0910_P2_KREFTMG 0xf258 +#define FSTV0910_P2_KREF_TMG 0xf25800ff + +/* P2_SFRSTEP */ +#define RSTV0910_P2_SFRSTEP 0xf259 +#define FSTV0910_P2_SFR_SCANSTEP 0xf25900f0 +#define FSTV0910_P2_SFR_CENTERSTEP 0xf259000f + +/* P2_TMGCFG2 */ +#define RSTV0910_P2_TMGCFG2 0xf25a +#define FSTV0910_P2_DIS_AUTOSAMP 0xf25a0008 +#define FSTV0910_P2_SFRRATIO_FINE 0xf25a0001 + +/* P2_KREFTMG2 */ +#define RSTV0910_P2_KREFTMG2 0xf25b +#define FSTV0910_P2_KREF_TMG2 0xf25b00ff + +/* P2_TMGCFG3 */ +#define RSTV0910_P2_TMGCFG3 0xf25d +#define FSTV0910_P2_CONT_TMGCENTER 0xf25d0008 +#define FSTV0910_P2_AUTO_GUP 0xf25d0004 +#define FSTV0910_P2_AUTO_GLOW 0xf25d0002 + +/* P2_SFRINIT1 */ +#define RSTV0910_P2_SFRINIT1 0xf25e +#define FSTV0910_P2_SFR_INIT1 0xf25e00ff + +/* P2_SFRINIT0 */ +#define RSTV0910_P2_SFRINIT0 0xf25f +#define FSTV0910_P2_SFR_INIT0 0xf25f00ff + +/* P2_SFRUP1 */ +#define RSTV0910_P2_SFRUP1 0xf260 +#define FSTV0910_P2_SYMB_FREQ_UP1 0xf26000ff + +/* P2_SFRUP0 */ +#define RSTV0910_P2_SFRUP0 0xf261 +#define FSTV0910_P2_SYMB_FREQ_UP0 0xf26100ff + +/* P2_SFRLOW1 */ +#define RSTV0910_P2_SFRLOW1 0xf262 +#define FSTV0910_P2_SYMB_FREQ_LOW1 0xf26200ff + +/* P2_SFRLOW0 */ +#define RSTV0910_P2_SFRLOW0 0xf263 +#define FSTV0910_P2_SYMB_FREQ_LOW0 0xf26300ff + +/* P2_SFR3 */ +#define RSTV0910_P2_SFR3 0xf264 +#define FSTV0910_P2_SYMB_FREQ3 0xf26400ff + +/* P2_SFR2 */ +#define RSTV0910_P2_SFR2 0xf265 +#define FSTV0910_P2_SYMB_FREQ2 0xf26500ff + +/* P2_SFR1 */ +#define RSTV0910_P2_SFR1 0xf266 +#define FSTV0910_P2_SYMB_FREQ1 0xf26600ff + +/* P2_SFR0 */ +#define RSTV0910_P2_SFR0 0xf267 +#define FSTV0910_P2_SYMB_FREQ0 0xf26700ff + +/* P2_TMGREG2 */ +#define RSTV0910_P2_TMGREG2 0xf268 +#define FSTV0910_P2_TMGREG2 0xf26800ff + +/* P2_TMGREG1 */ +#define RSTV0910_P2_TMGREG1 0xf269 +#define FSTV0910_P2_TMGREG1 0xf26900ff + +/* P2_TMGREG0 */ +#define RSTV0910_P2_TMGREG0 0xf26a +#define FSTV0910_P2_TMGREG0 0xf26a00ff + +/* P2_TMGLOCK1 */ +#define RSTV0910_P2_TMGLOCK1 0xf26b +#define FSTV0910_P2_TMGLOCK_LEVEL1 0xf26b01ff + +/* P2_TMGLOCK0 */ +#define RSTV0910_P2_TMGLOCK0 0xf26c +#define FSTV0910_P2_TMGLOCK_LEVEL0 0xf26c00ff + +/* P2_TMGOBS */ +#define RSTV0910_P2_TMGOBS 0xf26d +#define FSTV0910_P2_ROLLOFF_STATUS 0xf26d00c0 + +/* P2_EQUALCFG */ +#define RSTV0910_P2_EQUALCFG 0xf26f +#define FSTV0910_P2_EQUAL_ON 0xf26f0040 +#define FSTV0910_P2_MU_EQUALDFE 0xf26f0007 + +/* P2_EQUAI1 */ +#define RSTV0910_P2_EQUAI1 0xf270 +#define FSTV0910_P2_EQUA_ACCI1 0xf27001ff + +/* P2_EQUAQ1 */ +#define RSTV0910_P2_EQUAQ1 0xf271 +#define FSTV0910_P2_EQUA_ACCQ1 0xf27101ff + +/* P2_EQUAI2 */ +#define RSTV0910_P2_EQUAI2 0xf272 +#define FSTV0910_P2_EQUA_ACCI2 0xf27201ff + +/* P2_EQUAQ2 */ +#define RSTV0910_P2_EQUAQ2 0xf273 +#define FSTV0910_P2_EQUA_ACCQ2 0xf27301ff + +/* P2_EQUAI3 */ +#define RSTV0910_P2_EQUAI3 0xf274 +#define FSTV0910_P2_EQUA_ACCI3 0xf27401ff + +/* P2_EQUAQ3 */ +#define RSTV0910_P2_EQUAQ3 0xf275 +#define FSTV0910_P2_EQUA_ACCQ3 0xf27501ff + +/* P2_EQUAI4 */ +#define RSTV0910_P2_EQUAI4 0xf276 +#define FSTV0910_P2_EQUA_ACCI4 0xf27601ff + +/* P2_EQUAQ4 */ +#define RSTV0910_P2_EQUAQ4 0xf277 +#define FSTV0910_P2_EQUA_ACCQ4 0xf27701ff + +/* P2_EQUAI5 */ +#define RSTV0910_P2_EQUAI5 0xf278 +#define FSTV0910_P2_EQUA_ACCI5 0xf27801ff + +/* P2_EQUAQ5 */ +#define RSTV0910_P2_EQUAQ5 0xf279 +#define FSTV0910_P2_EQUA_ACCQ5 0xf27901ff + +/* P2_EQUAI6 */ +#define RSTV0910_P2_EQUAI6 0xf27a +#define FSTV0910_P2_EQUA_ACCI6 0xf27a01ff + +/* P2_EQUAQ6 */ +#define RSTV0910_P2_EQUAQ6 0xf27b +#define FSTV0910_P2_EQUA_ACCQ6 0xf27b01ff + +/* P2_EQUAI7 */ +#define RSTV0910_P2_EQUAI7 0xf27c +#define FSTV0910_P2_EQUA_ACCI7 0xf27c01ff + +/* P2_EQUAQ7 */ +#define RSTV0910_P2_EQUAQ7 0xf27d +#define FSTV0910_P2_EQUA_ACCQ7 0xf27d01ff + +/* P2_EQUAI8 */ +#define RSTV0910_P2_EQUAI8 0xf27e +#define FSTV0910_P2_EQUA_ACCI8 0xf27e01ff + +/* P2_EQUAQ8 */ +#define RSTV0910_P2_EQUAQ8 0xf27f +#define FSTV0910_P2_EQUA_ACCQ8 0xf27f01ff + +/* P2_NNOSDATAT1 */ +#define RSTV0910_P2_NNOSDATAT1 0xf280 +#define FSTV0910_P2_NOSDATAT_NORMED1 0xf28000ff + +/* P2_NNOSDATAT0 */ +#define RSTV0910_P2_NNOSDATAT0 0xf281 +#define FSTV0910_P2_NOSDATAT_NORMED0 0xf28100ff + +/* P2_NNOSDATA1 */ +#define RSTV0910_P2_NNOSDATA1 0xf282 +#define FSTV0910_P2_NOSDATA_NORMED1 0xf28200ff + +/* P2_NNOSDATA0 */ +#define RSTV0910_P2_NNOSDATA0 0xf283 +#define FSTV0910_P2_NOSDATA_NORMED0 0xf28300ff + +/* P2_NNOSPLHT1 */ +#define RSTV0910_P2_NNOSPLHT1 0xf284 +#define FSTV0910_P2_NOSPLHT_NORMED1 0xf28400ff + +/* P2_NNOSPLHT0 */ +#define RSTV0910_P2_NNOSPLHT0 0xf285 +#define FSTV0910_P2_NOSPLHT_NORMED0 0xf28500ff + +/* P2_NNOSPLH1 */ +#define RSTV0910_P2_NNOSPLH1 0xf286 +#define FSTV0910_P2_NOSPLH_NORMED1 0xf28600ff + +/* P2_NNOSPLH0 */ +#define RSTV0910_P2_NNOSPLH0 0xf287 +#define FSTV0910_P2_NOSPLH_NORMED0 0xf28700ff + +/* P2_NOSDATAT1 */ +#define RSTV0910_P2_NOSDATAT1 0xf288 +#define FSTV0910_P2_NOSDATAT_UNNORMED1 0xf28800ff + +/* P2_NOSDATAT0 */ +#define RSTV0910_P2_NOSDATAT0 0xf289 +#define FSTV0910_P2_NOSDATAT_UNNORMED0 0xf28900ff + +/* P2_NNOSFRAME1 */ +#define RSTV0910_P2_NNOSFRAME1 0xf28a +#define FSTV0910_P2_NOSFRAME_NORMED1 0xf28a00ff + +/* P2_NNOSFRAME0 */ +#define RSTV0910_P2_NNOSFRAME0 0xf28b +#define FSTV0910_P2_NOSFRAME_NORMED0 0xf28b00ff + +/* P2_NNOSRAD1 */ +#define RSTV0910_P2_NNOSRAD1 0xf28c +#define FSTV0910_P2_NOSRADIAL_NORMED1 0xf28c00ff + +/* P2_NNOSRAD0 */ +#define RSTV0910_P2_NNOSRAD0 0xf28d +#define FSTV0910_P2_NOSRADIAL_NORMED0 0xf28d00ff + +/* P2_NOSCFGF1 */ +#define RSTV0910_P2_NOSCFGF1 0xf28e +#define FSTV0910_P2_LOWNOISE_MESURE 0xf28e0080 +#define FSTV0910_P2_NOS_DELFRAME 0xf28e0040 +#define FSTV0910_P2_NOSDATA_MODE 0xf28e0030 +#define FSTV0910_P2_FRAMESEL_TYPESEL 0xf28e000c +#define FSTV0910_P2_FRAMESEL_TYPE 0xf28e0003 + +/* P2_NOSCFGF2 */ +#define RSTV0910_P2_NOSCFGF2 0xf28f +#define FSTV0910_P2_DIS_NOSPILOTS 0xf28f0080 +#define FSTV0910_P2_FRAMESEL_MODCODSEL 0xf28f0060 +#define FSTV0910_P2_FRAMESEL_MODCOD 0xf28f001f + +/* P2_CAR2CFG */ +#define RSTV0910_P2_CAR2CFG 0xf290 +#define FSTV0910_P2_ROTA2ON 0xf2900004 +#define FSTV0910_P2_PH_DET_ALGO2 0xf2900003 + +/* P2_CFR2CFR1 */ +#define RSTV0910_P2_CFR2CFR1 0xf291 +#define FSTV0910_P2_EN_S2CAR2CENTER 0xf2910020 +#define FSTV0910_P2_CFR2TOCFR1_BETA 0xf2910007 + +/* P2_CAR3CFG */ +#define RSTV0910_P2_CAR3CFG 0xf292 +#define FSTV0910_P2_CARRIER23_MODE 0xf29200c0 +#define FSTV0910_P2_CAR3INTERM_DVBS1 0xf2920020 +#define FSTV0910_P2_ABAMPLIF_MODE 0xf2920018 +#define FSTV0910_P2_CARRIER3_ALPHA3DL 0xf2920007 + +/* P2_CFR22 */ +#define RSTV0910_P2_CFR22 0xf293 +#define FSTV0910_P2_CAR2_FREQ2 0xf29301ff + +/* P2_CFR21 */ +#define RSTV0910_P2_CFR21 0xf294 +#define FSTV0910_P2_CAR2_FREQ1 0xf29400ff + +/* P2_CFR20 */ +#define RSTV0910_P2_CFR20 0xf295 +#define FSTV0910_P2_CAR2_FREQ0 0xf29500ff + +/* P2_ACLC2S2Q */ +#define RSTV0910_P2_ACLC2S2Q 0xf297 +#define FSTV0910_P2_ENAB_SPSKSYMB 0xf2970080 +#define FSTV0910_P2_CAR2S2_Q_ALPH_M 0xf2970030 +#define FSTV0910_P2_CAR2S2_Q_ALPH_E 0xf297000f + +/* P2_ACLC2S28 */ +#define RSTV0910_P2_ACLC2S28 0xf298 +#define FSTV0910_P2_CAR2S2_8_ALPH_M 0xf2980030 +#define FSTV0910_P2_CAR2S2_8_ALPH_E 0xf298000f + +/* P2_ACLC2S216A */ +#define RSTV0910_P2_ACLC2S216A 0xf299 +#define FSTV0910_P2_CAR2S2_16A_ALPH_M 0xf2990030 +#define FSTV0910_P2_CAR2S2_16A_ALPH_E 0xf299000f + +/* P2_ACLC2S232A */ +#define RSTV0910_P2_ACLC2S232A 0xf29a +#define FSTV0910_P2_CAR2S2_32A_ALPH_M 0xf29a0030 +#define FSTV0910_P2_CAR2S2_32A_ALPH_E 0xf29a000f + +/* P2_BCLC2S2Q */ +#define RSTV0910_P2_BCLC2S2Q 0xf29c +#define FSTV0910_P2_CAR2S2_Q_BETA_M 0xf29c0030 +#define FSTV0910_P2_CAR2S2_Q_BETA_E 0xf29c000f + +/* P2_BCLC2S28 */ +#define RSTV0910_P2_BCLC2S28 0xf29d +#define FSTV0910_P2_CAR2S2_8_BETA_M 0xf29d0030 +#define FSTV0910_P2_CAR2S2_8_BETA_E 0xf29d000f + +/* P2_BCLC2S216A */ +#define RSTV0910_P2_BCLC2S216A 0xf29e +#define FSTV0910_P2_DVBS2S216A_NIP 0xf29e0080 +#define FSTV0910_P2_CAR2S2_16A_BETA_M 0xf29e0030 +#define FSTV0910_P2_CAR2S2_16A_BETA_E 0xf29e000f + +/* P2_BCLC2S232A */ +#define RSTV0910_P2_BCLC2S232A 0xf29f +#define FSTV0910_P2_DVBS2S232A_NIP 0xf29f0080 +#define FSTV0910_P2_CAR2S2_32A_BETA_M 0xf29f0030 +#define FSTV0910_P2_CAR2S2_32A_BETA_E 0xf29f000f + +/* P2_PLROOT2 */ +#define RSTV0910_P2_PLROOT2 0xf2ac +#define FSTV0910_P2_PLSCRAMB_MODE 0xf2ac000c +#define FSTV0910_P2_PLSCRAMB_ROOT2 0xf2ac0003 + +/* P2_PLROOT1 */ +#define RSTV0910_P2_PLROOT1 0xf2ad +#define FSTV0910_P2_PLSCRAMB_ROOT1 0xf2ad00ff + +/* P2_PLROOT0 */ +#define RSTV0910_P2_PLROOT0 0xf2ae +#define FSTV0910_P2_PLSCRAMB_ROOT0 0xf2ae00ff + +/* P2_MODCODLST0 */ +#define RSTV0910_P2_MODCODLST0 0xf2b0 +#define FSTV0910_P2_NACCES_MODCODCH 0xf2b00001 + +/* P2_MODCODLST1 */ +#define RSTV0910_P2_MODCODLST1 0xf2b1 +#define FSTV0910_P2_SYMBRATE_FILTER 0xf2b10008 +#define FSTV0910_P2_NRESET_MODCODLST 0xf2b10004 +#define FSTV0910_P2_DIS_32PSK_9_10 0xf2b10003 + +/* P2_MODCODLST2 */ +#define RSTV0910_P2_MODCODLST2 0xf2b2 +#define FSTV0910_P2_DIS_32PSK_8_9 0xf2b200f0 +#define FSTV0910_P2_DIS_32PSK_5_6 0xf2b2000f + +/* P2_MODCODLST3 */ +#define RSTV0910_P2_MODCODLST3 0xf2b3 +#define FSTV0910_P2_DIS_32PSK_4_5 0xf2b300f0 +#define FSTV0910_P2_DIS_32PSK_3_4 0xf2b3000f + +/* P2_MODCODLST4 */ +#define RSTV0910_P2_MODCODLST4 0xf2b4 +#define FSTV0910_P2_DUMMYPL_PILOT 0xf2b40080 +#define FSTV0910_P2_DUMMYPL_NOPILOT 0xf2b40040 +#define FSTV0910_P2_DIS_16PSK_9_10 0xf2b40030 +#define FSTV0910_P2_DIS_16PSK_8_9 0xf2b4000f + +/* P2_MODCODLST5 */ +#define RSTV0910_P2_MODCODLST5 0xf2b5 +#define FSTV0910_P2_DIS_16PSK_5_6 0xf2b500f0 +#define FSTV0910_P2_DIS_16PSK_4_5 0xf2b5000f + +/* P2_MODCODLST6 */ +#define RSTV0910_P2_MODCODLST6 0xf2b6 +#define FSTV0910_P2_DIS_16PSK_3_4 0xf2b600f0 +#define FSTV0910_P2_DIS_16PSK_2_3 0xf2b6000f + +/* P2_MODCODLST7 */ +#define RSTV0910_P2_MODCODLST7 0xf2b7 +#define FSTV0910_P2_MODCOD_NNOSFILTER 0xf2b70080 +#define FSTV0910_P2_DIS_8PSK_9_10 0xf2b70030 +#define FSTV0910_P2_DIS_8PSK_8_9 0xf2b7000f + +/* P2_MODCODLST8 */ +#define RSTV0910_P2_MODCODLST8 0xf2b8 +#define FSTV0910_P2_DIS_8PSK_5_6 0xf2b800f0 +#define FSTV0910_P2_DIS_8PSK_3_4 0xf2b8000f + +/* P2_MODCODLST9 */ +#define RSTV0910_P2_MODCODLST9 0xf2b9 +#define FSTV0910_P2_DIS_8PSK_2_3 0xf2b900f0 +#define FSTV0910_P2_DIS_8PSK_3_5 0xf2b9000f + +/* P2_MODCODLSTA */ +#define RSTV0910_P2_MODCODLSTA 0xf2ba +#define FSTV0910_P2_NOSFILTER_LIMITE 0xf2ba0080 +#define FSTV0910_P2_DIS_QPSK_9_10 0xf2ba0030 +#define FSTV0910_P2_DIS_QPSK_8_9 0xf2ba000f + +/* P2_MODCODLSTB */ +#define RSTV0910_P2_MODCODLSTB 0xf2bb +#define FSTV0910_P2_DIS_QPSK_5_6 0xf2bb00f0 +#define FSTV0910_P2_DIS_QPSK_4_5 0xf2bb000f + +/* P2_MODCODLSTC */ +#define RSTV0910_P2_MODCODLSTC 0xf2bc +#define FSTV0910_P2_DIS_QPSK_3_4 0xf2bc00f0 +#define FSTV0910_P2_DIS_QPSK_2_3 0xf2bc000f + +/* P2_MODCODLSTD */ +#define RSTV0910_P2_MODCODLSTD 0xf2bd +#define FSTV0910_P2_DIS_QPSK_3_5 0xf2bd00f0 +#define FSTV0910_P2_DIS_QPSK_1_2 0xf2bd000f + +/* P2_MODCODLSTE */ +#define RSTV0910_P2_MODCODLSTE 0xf2be +#define FSTV0910_P2_DIS_QPSK_2_5 0xf2be00f0 +#define FSTV0910_P2_DIS_QPSK_1_3 0xf2be000f + +/* P2_MODCODLSTF */ +#define RSTV0910_P2_MODCODLSTF 0xf2bf +#define FSTV0910_P2_DIS_QPSK_1_4 0xf2bf00f0 +#define FSTV0910_P2_DEMOD_INVMODLST 0xf2bf0008 +#define FSTV0910_P2_DEMODOUT_ENABLE 0xf2bf0004 +#define FSTV0910_P2_DDEMOD_NSET 0xf2bf0002 +#define FSTV0910_P2_MODCOD_NSTOCK 0xf2bf0001 + +/* P2_GAUSSR0 */ +#define RSTV0910_P2_GAUSSR0 0xf2c0 +#define FSTV0910_P2_EN_CCIMODE 0xf2c00080 +#define FSTV0910_P2_R0_GAUSSIEN 0xf2c0007f + +/* P2_CCIR0 */ +#define RSTV0910_P2_CCIR0 0xf2c1 +#define FSTV0910_P2_CCIDETECT_PLHONLY 0xf2c10080 +#define FSTV0910_P2_R0_CCI 0xf2c1007f + +/* P2_CCIQUANT */ +#define RSTV0910_P2_CCIQUANT 0xf2c2 +#define FSTV0910_P2_CCI_BETA 0xf2c200e0 +#define FSTV0910_P2_CCI_QUANT 0xf2c2001f + +/* P2_CCITHRES */ +#define RSTV0910_P2_CCITHRES 0xf2c3 +#define FSTV0910_P2_CCI_THRESHOLD 0xf2c300ff + +/* P2_CCIACC */ +#define RSTV0910_P2_CCIACC 0xf2c4 +#define FSTV0910_P2_CCI_VALUE 0xf2c400ff + +/* P2_DSTATUS4 */ +#define RSTV0910_P2_DSTATUS4 0xf2c5 +#define FSTV0910_P2_RAINFADE_DETECT 0xf2c50080 +#define FSTV0910_P2_NOTHRES2_FAIL 0xf2c50040 +#define FSTV0910_P2_NOTHRES1_FAIL 0xf2c50020 +#define FSTV0910_P2_DMDPROG_ERROR 0xf2c50004 +#define FSTV0910_P2_CSTENV_DETECT 0xf2c50002 +#define FSTV0910_P2_DETECTION_TRIAX 0xf2c50001 + +/* P2_DMDRESCFG */ +#define RSTV0910_P2_DMDRESCFG 0xf2c6 +#define FSTV0910_P2_DMDRES_RESET 0xf2c60080 +#define FSTV0910_P2_DMDRES_STRALL 0xf2c60008 +#define FSTV0910_P2_DMDRES_NEWONLY 0xf2c60004 +#define FSTV0910_P2_DMDRES_NOSTORE 0xf2c60002 + +/* P2_DMDRESADR */ +#define RSTV0910_P2_DMDRESADR 0xf2c7 +#define FSTV0910_P2_DMDRES_VALIDCFR 0xf2c70040 +#define FSTV0910_P2_DMDRES_MEMFULL 0xf2c70030 +#define FSTV0910_P2_DMDRES_RESNBR 0xf2c7000f + +/* P2_DMDRESDATA7 */ +#define RSTV0910_P2_DMDRESDATA7 0xf2c8 +#define FSTV0910_P2_DMDRES_DATA7 0xf2c800ff + +/* P2_DMDRESDATA6 */ +#define RSTV0910_P2_DMDRESDATA6 0xf2c9 +#define FSTV0910_P2_DMDRES_DATA6 0xf2c900ff + +/* P2_DMDRESDATA5 */ +#define RSTV0910_P2_DMDRESDATA5 0xf2ca +#define FSTV0910_P2_DMDRES_DATA5 0xf2ca00ff + +/* P2_DMDRESDATA4 */ +#define RSTV0910_P2_DMDRESDATA4 0xf2cb +#define FSTV0910_P2_DMDRES_DATA4 0xf2cb00ff + +/* P2_DMDRESDATA3 */ +#define RSTV0910_P2_DMDRESDATA3 0xf2cc +#define FSTV0910_P2_DMDRES_DATA3 0xf2cc00ff + +/* P2_DMDRESDATA2 */ +#define RSTV0910_P2_DMDRESDATA2 0xf2cd +#define FSTV0910_P2_DMDRES_DATA2 0xf2cd00ff + +/* P2_DMDRESDATA1 */ +#define RSTV0910_P2_DMDRESDATA1 0xf2ce +#define FSTV0910_P2_DMDRES_DATA1 0xf2ce00ff + +/* P2_DMDRESDATA0 */ +#define RSTV0910_P2_DMDRESDATA0 0xf2cf +#define FSTV0910_P2_DMDRES_DATA0 0xf2cf00ff + +/* P2_FFEI1 */ +#define RSTV0910_P2_FFEI1 0xf2d0 +#define FSTV0910_P2_FFE_ACCI1 0xf2d001ff + +/* P2_FFEQ1 */ +#define RSTV0910_P2_FFEQ1 0xf2d1 +#define FSTV0910_P2_FFE_ACCQ1 0xf2d101ff + +/* P2_FFEI2 */ +#define RSTV0910_P2_FFEI2 0xf2d2 +#define FSTV0910_P2_FFE_ACCI2 0xf2d201ff + +/* P2_FFEQ2 */ +#define RSTV0910_P2_FFEQ2 0xf2d3 +#define FSTV0910_P2_FFE_ACCQ2 0xf2d301ff + +/* P2_FFEI3 */ +#define RSTV0910_P2_FFEI3 0xf2d4 +#define FSTV0910_P2_FFE_ACCI3 0xf2d401ff + +/* P2_FFEQ3 */ +#define RSTV0910_P2_FFEQ3 0xf2d5 +#define FSTV0910_P2_FFE_ACCQ3 0xf2d501ff + +/* P2_FFEI4 */ +#define RSTV0910_P2_FFEI4 0xf2d6 +#define FSTV0910_P2_FFE_ACCI4 0xf2d601ff + +/* P2_FFEQ4 */ +#define RSTV0910_P2_FFEQ4 0xf2d7 +#define FSTV0910_P2_FFE_ACCQ4 0xf2d701ff + +/* P2_FFECFG */ +#define RSTV0910_P2_FFECFG 0xf2d8 +#define FSTV0910_P2_EQUALFFE_ON 0xf2d80040 +#define FSTV0910_P2_EQUAL_USEDSYMB 0xf2d80030 +#define FSTV0910_P2_MU_EQUALFFE 0xf2d80007 + +/* P2_TNRCFG2 */ +#define RSTV0910_P2_TNRCFG2 0xf2e1 +#define FSTV0910_P2_TUN_IQSWAP 0xf2e10080 + +/* P2_SMAPCOEF7 */ +#define RSTV0910_P2_SMAPCOEF7 0xf300 +#define FSTV0910_P2_DIS_QSCALE 0xf3000080 +#define FSTV0910_P2_SMAPCOEF_Q_LLR12 0xf300017f + +/* P2_SMAPCOEF6 */ +#define RSTV0910_P2_SMAPCOEF6 0xf301 +#define FSTV0910_P2_DIS_AGC2SCALE 0xf3010080 +#define FSTV0910_P2_ADJ_8PSKLLR1 0xf3010004 +#define FSTV0910_P2_OLD_8PSKLLR1 0xf3010002 +#define FSTV0910_P2_DIS_AB8PSK 0xf3010001 + +/* P2_SMAPCOEF5 */ +#define RSTV0910_P2_SMAPCOEF5 0xf302 +#define FSTV0910_P2_DIS_8SCALE 0xf3020080 +#define FSTV0910_P2_SMAPCOEF_8P_LLR23 0xf302017f + +/* P2_SMAPCOEF4 */ +#define RSTV0910_P2_SMAPCOEF4 0xf303 +#define FSTV0910_P2_SMAPCOEF_16APSK_LLR12 0xf303017f + +/* P2_SMAPCOEF3 */ +#define RSTV0910_P2_SMAPCOEF3 0xf304 +#define FSTV0910_P2_SMAPCOEF_16APSK_LLR34 0xf304017f + +/* P2_SMAPCOEF2 */ +#define RSTV0910_P2_SMAPCOEF2 0xf305 +#define FSTV0910_P2_SMAPCOEF_32APSK_R2R3 0xf30501f0 +#define FSTV0910_P2_SMAPCOEF_32APSK_LLR2 0xf305010f + +/* P2_SMAPCOEF1 */ +#define RSTV0910_P2_SMAPCOEF1 0xf306 +#define FSTV0910_P2_DIS_16SCALE 0xf3060080 +#define FSTV0910_P2_SMAPCOEF_32_LLR34 0xf306017f + +/* P2_SMAPCOEF0 */ +#define RSTV0910_P2_SMAPCOEF0 0xf307 +#define FSTV0910_P2_DIS_32SCALE 0xf3070080 +#define FSTV0910_P2_SMAPCOEF_32_LLR15 0xf307017f + +/* P2_NOSTHRES1 */ +#define RSTV0910_P2_NOSTHRES1 0xf309 +#define FSTV0910_P2_NOS_THRESHOLD1 0xf30900ff + +/* P2_NOSTHRES2 */ +#define RSTV0910_P2_NOSTHRES2 0xf30a +#define FSTV0910_P2_NOS_THRESHOLD2 0xf30a00ff + +/* P2_NOSDIFF1 */ +#define RSTV0910_P2_NOSDIFF1 0xf30b +#define FSTV0910_P2_NOSTHRES1_DIFF 0xf30b00ff + +/* P2_RAINFADE */ +#define RSTV0910_P2_RAINFADE 0xf30c +#define FSTV0910_P2_NOSTHRES_DATAT 0xf30c0080 +#define FSTV0910_P2_RAINFADE_CNLIMIT 0xf30c0070 +#define FSTV0910_P2_RAINFADE_TIMEOUT 0xf30c0007 + +/* P2_NOSRAMCFG */ +#define RSTV0910_P2_NOSRAMCFG 0xf30d +#define FSTV0910_P2_NOSRAM_ACTIVATION 0xf30d0030 +#define FSTV0910_P2_NOSRAM_CNRONLY 0xf30d0008 +#define FSTV0910_P2_NOSRAM_LGNCNR1 0xf30d0007 + +/* P2_NOSRAMPOS */ +#define RSTV0910_P2_NOSRAMPOS 0xf30e +#define FSTV0910_P2_NOSRAM_LGNCNR0 0xf30e00f0 +#define FSTV0910_P2_NOSRAM_VALIDE 0xf30e0004 +#define FSTV0910_P2_NOSRAM_CNRVAL1 0xf30e0003 + +/* P2_NOSRAMVAL */ +#define RSTV0910_P2_NOSRAMVAL 0xf30f +#define FSTV0910_P2_NOSRAM_CNRVAL0 0xf30f00ff + +/* P2_DMDPLHSTAT */ +#define RSTV0910_P2_DMDPLHSTAT 0xf320 +#define FSTV0910_P2_PLH_STATISTIC 0xf32000ff + +/* P2_LOCKTIME3 */ +#define RSTV0910_P2_LOCKTIME3 0xf322 +#define FSTV0910_P2_DEMOD_LOCKTIME3 0xf32200ff + +/* P2_LOCKTIME2 */ +#define RSTV0910_P2_LOCKTIME2 0xf323 +#define FSTV0910_P2_DEMOD_LOCKTIME2 0xf32300ff + +/* P2_LOCKTIME1 */ +#define RSTV0910_P2_LOCKTIME1 0xf324 +#define FSTV0910_P2_DEMOD_LOCKTIME1 0xf32400ff + +/* P2_LOCKTIME0 */ +#define RSTV0910_P2_LOCKTIME0 0xf325 +#define FSTV0910_P2_DEMOD_LOCKTIME0 0xf32500ff + +/* P2_VITSCALE */ +#define RSTV0910_P2_VITSCALE 0xf332 +#define FSTV0910_P2_NVTH_NOSRANGE 0xf3320080 +#define FSTV0910_P2_VERROR_MAXMODE 0xf3320040 +#define FSTV0910_P2_NSLOWSN_LOCKED 0xf3320008 +#define FSTV0910_P2_DIS_RSFLOCK 0xf3320002 + +/* P2_FECM */ +#define RSTV0910_P2_FECM 0xf333 +#define FSTV0910_P2_DSS_DVB 0xf3330080 +#define FSTV0910_P2_DSS_SRCH 0xf3330010 +#define FSTV0910_P2_SYNCVIT 0xf3330002 +#define FSTV0910_P2_IQINV 0xf3330001 + +/* P2_VTH12 */ +#define RSTV0910_P2_VTH12 0xf334 +#define FSTV0910_P2_VTH12 0xf33400ff + +/* P2_VTH23 */ +#define RSTV0910_P2_VTH23 0xf335 +#define FSTV0910_P2_VTH23 0xf33500ff + +/* P2_VTH34 */ +#define RSTV0910_P2_VTH34 0xf336 +#define FSTV0910_P2_VTH34 0xf33600ff + +/* P2_VTH56 */ +#define RSTV0910_P2_VTH56 0xf337 +#define FSTV0910_P2_VTH56 0xf33700ff + +/* P2_VTH67 */ +#define RSTV0910_P2_VTH67 0xf338 +#define FSTV0910_P2_VTH67 0xf33800ff + +/* P2_VTH78 */ +#define RSTV0910_P2_VTH78 0xf339 +#define FSTV0910_P2_VTH78 0xf33900ff + +/* P2_VITCURPUN */ +#define RSTV0910_P2_VITCURPUN 0xf33a +#define FSTV0910_P2_VIT_CURPUN 0xf33a001f + +/* P2_VERROR */ +#define RSTV0910_P2_VERROR 0xf33b +#define FSTV0910_P2_REGERR_VIT 0xf33b00ff + +/* P2_PRVIT */ +#define RSTV0910_P2_PRVIT 0xf33c +#define FSTV0910_P2_DIS_VTHLOCK 0xf33c0040 +#define FSTV0910_P2_E7_8VIT 0xf33c0020 +#define FSTV0910_P2_E6_7VIT 0xf33c0010 +#define FSTV0910_P2_E5_6VIT 0xf33c0008 +#define FSTV0910_P2_E3_4VIT 0xf33c0004 +#define FSTV0910_P2_E2_3VIT 0xf33c0002 +#define FSTV0910_P2_E1_2VIT 0xf33c0001 + +/* P2_VAVSRVIT */ +#define RSTV0910_P2_VAVSRVIT 0xf33d +#define FSTV0910_P2_AMVIT 0xf33d0080 +#define FSTV0910_P2_FROZENVIT 0xf33d0040 +#define FSTV0910_P2_SNVIT 0xf33d0030 +#define FSTV0910_P2_TOVVIT 0xf33d000c +#define FSTV0910_P2_HYPVIT 0xf33d0003 + +/* P2_VSTATUSVIT */ +#define RSTV0910_P2_VSTATUSVIT 0xf33e +#define FSTV0910_P2_PRFVIT 0xf33e0010 +#define FSTV0910_P2_LOCKEDVIT 0xf33e0008 + +/* P2_VTHINUSE */ +#define RSTV0910_P2_VTHINUSE 0xf33f +#define FSTV0910_P2_VIT_INUSE 0xf33f00ff + +/* P2_KDIV12 */ +#define RSTV0910_P2_KDIV12 0xf340 +#define FSTV0910_P2_K_DIVIDER_12 0xf340007f + +/* P2_KDIV23 */ +#define RSTV0910_P2_KDIV23 0xf341 +#define FSTV0910_P2_K_DIVIDER_23 0xf341007f + +/* P2_KDIV34 */ +#define RSTV0910_P2_KDIV34 0xf342 +#define FSTV0910_P2_K_DIVIDER_34 0xf342007f + +/* P2_KDIV56 */ +#define RSTV0910_P2_KDIV56 0xf343 +#define FSTV0910_P2_K_DIVIDER_56 0xf343007f + +/* P2_KDIV67 */ +#define RSTV0910_P2_KDIV67 0xf344 +#define FSTV0910_P2_K_DIVIDER_67 0xf344007f + +/* P2_KDIV78 */ +#define RSTV0910_P2_KDIV78 0xf345 +#define FSTV0910_P2_K_DIVIDER_78 0xf345007f + +/* P2_TSPIDFLT1 */ +#define RSTV0910_P2_TSPIDFLT1 0xf346 +#define FSTV0910_P2_PIDFLT_ADDR 0xf34600ff + +/* P2_TSPIDFLT0 */ +#define RSTV0910_P2_TSPIDFLT0 0xf347 +#define FSTV0910_P2_PIDFLT_DATA 0xf34700ff + +/* P2_PDELCTRL0 */ +#define RSTV0910_P2_PDELCTRL0 0xf34f +#define FSTV0910_P2_ISIOBS_MODE 0xf34f0030 + +/* P2_PDELCTRL1 */ +#define RSTV0910_P2_PDELCTRL1 0xf350 +#define FSTV0910_P2_INV_MISMASK 0xf3500080 +#define FSTV0910_P2_FILTER_EN 0xf3500020 +#define FSTV0910_P2_HYSTEN 0xf3500008 +#define FSTV0910_P2_HYSTSWRST 0xf3500004 +#define FSTV0910_P2_EN_MIS00 0xf3500002 +#define FSTV0910_P2_ALGOSWRST 0xf3500001 + +/* P2_PDELCTRL2 */ +#define RSTV0910_P2_PDELCTRL2 0xf351 +#define FSTV0910_P2_FORCE_CONTINUOUS 0xf3510080 +#define FSTV0910_P2_RESET_UPKO_COUNT 0xf3510040 +#define FSTV0910_P2_USER_PKTDELIN_NB 0xf3510020 +#define FSTV0910_P2_FRAME_MODE 0xf3510002 + +/* P2_HYSTTHRESH */ +#define RSTV0910_P2_HYSTTHRESH 0xf354 +#define FSTV0910_P2_DELIN_LOCKTHRES 0xf35400f0 +#define FSTV0910_P2_DELIN_UNLOCKTHRES 0xf354000f + +/* P2_UPLCCST0 */ +#define RSTV0910_P2_UPLCCST0 0xf358 +#define FSTV0910_P2_UPL_CST0 0xf35800f8 +#define FSTV0910_P2_UPL_MODE 0xf3580007 + +/* P2_ISIENTRY */ +#define RSTV0910_P2_ISIENTRY 0xf35e +#define FSTV0910_P2_ISI_ENTRY 0xf35e00ff + +/* P2_ISIBITENA */ +#define RSTV0910_P2_ISIBITENA 0xf35f +#define FSTV0910_P2_ISI_BIT_EN 0xf35f00ff + +/* P2_MATSTR1 */ +#define RSTV0910_P2_MATSTR1 0xf360 +#define FSTV0910_P2_MATYPE_CURRENT1 0xf36000ff + +/* P2_MATSTR0 */ +#define RSTV0910_P2_MATSTR0 0xf361 +#define FSTV0910_P2_MATYPE_CURRENT0 0xf36100ff + +/* P2_UPLSTR1 */ +#define RSTV0910_P2_UPLSTR1 0xf362 +#define FSTV0910_P2_UPL_CURRENT1 0xf36200ff + +/* P2_UPLSTR0 */ +#define RSTV0910_P2_UPLSTR0 0xf363 +#define FSTV0910_P2_UPL_CURRENT0 0xf36300ff + +/* P2_DFLSTR1 */ +#define RSTV0910_P2_DFLSTR1 0xf364 +#define FSTV0910_P2_DFL_CURRENT1 0xf36400ff + +/* P2_DFLSTR0 */ +#define RSTV0910_P2_DFLSTR0 0xf365 +#define FSTV0910_P2_DFL_CURRENT0 0xf36500ff + +/* P2_SYNCSTR */ +#define RSTV0910_P2_SYNCSTR 0xf366 +#define FSTV0910_P2_SYNC_CURRENT 0xf36600ff + +/* P2_SYNCDSTR1 */ +#define RSTV0910_P2_SYNCDSTR1 0xf367 +#define FSTV0910_P2_SYNCD_CURRENT1 0xf36700ff + +/* P2_SYNCDSTR0 */ +#define RSTV0910_P2_SYNCDSTR0 0xf368 +#define FSTV0910_P2_SYNCD_CURRENT0 0xf36800ff + +/* P2_PDELSTATUS1 */ +#define RSTV0910_P2_PDELSTATUS1 0xf369 +#define FSTV0910_P2_PKTDELIN_DELOCK 0xf3690080 +#define FSTV0910_P2_SYNCDUPDFL_BADDFL 0xf3690040 +#define FSTV0910_P2_UNACCEPTED_STREAM 0xf3690010 +#define FSTV0910_P2_BCH_ERROR_FLAG 0xf3690008 +#define FSTV0910_P2_PKTDELIN_LOCK 0xf3690002 +#define FSTV0910_P2_FIRST_LOCK 0xf3690001 + +/* P2_PDELSTATUS2 */ +#define RSTV0910_P2_PDELSTATUS2 0xf36a +#define FSTV0910_P2_FRAME_MODCOD 0xf36a007c +#define FSTV0910_P2_FRAME_TYPE 0xf36a0003 + +/* P2_BBFCRCKO1 */ +#define RSTV0910_P2_BBFCRCKO1 0xf36b +#define FSTV0910_P2_BBHCRC_KOCNT1 0xf36b00ff + +/* P2_BBFCRCKO0 */ +#define RSTV0910_P2_BBFCRCKO0 0xf36c +#define FSTV0910_P2_BBHCRC_KOCNT0 0xf36c00ff + +/* P2_UPCRCKO1 */ +#define RSTV0910_P2_UPCRCKO1 0xf36d +#define FSTV0910_P2_PKTCRC_KOCNT1 0xf36d00ff + +/* P2_UPCRCKO0 */ +#define RSTV0910_P2_UPCRCKO0 0xf36e +#define FSTV0910_P2_PKTCRC_KOCNT0 0xf36e00ff + +/* P2_PDELCTRL3 */ +#define RSTV0910_P2_PDELCTRL3 0xf36f +#define FSTV0910_P2_NOFIFO_BCHERR 0xf36f0020 +#define FSTV0910_P2_PKTDELIN_DELACMERR 0xf36f0010 + +/* P2_TSSTATEM */ +#define RSTV0910_P2_TSSTATEM 0xf370 +#define FSTV0910_P2_TSDIL_ON 0xf3700080 +#define FSTV0910_P2_TSRS_ON 0xf3700020 +#define FSTV0910_P2_TSDESCRAMB_ON 0xf3700010 +#define FSTV0910_P2_TSFRAME_MODE 0xf3700008 +#define FSTV0910_P2_TS_DISABLE 0xf3700004 +#define FSTV0910_P2_TSACM_MODE 0xf3700002 +#define FSTV0910_P2_TSOUT_NOSYNC 0xf3700001 + +/* P2_TSSTATEL */ +#define RSTV0910_P2_TSSTATEL 0xf371 +#define FSTV0910_P2_TSNOSYNCBYTE 0xf3710080 +#define FSTV0910_P2_TSPARITY_ON 0xf3710040 +#define FSTV0910_P2_TSISSYI_ON 0xf3710008 +#define FSTV0910_P2_TSNPD_ON 0xf3710004 +#define FSTV0910_P2_TSCRC8_ON 0xf3710002 +#define FSTV0910_P2_TSDSS_PACKET 0xf3710001 + +/* P2_TSCFGH */ +#define RSTV0910_P2_TSCFGH 0xf372 +#define FSTV0910_P2_TSFIFO_DVBCI 0xf3720080 +#define FSTV0910_P2_TSFIFO_SERIAL 0xf3720040 +#define FSTV0910_P2_TSFIFO_TEIUPDATE 0xf3720020 +#define FSTV0910_P2_TSFIFO_DUTY50 0xf3720010 +#define FSTV0910_P2_TSFIFO_HSGNLOUT 0xf3720008 +#define FSTV0910_P2_TSFIFO_ERRMODE 0xf3720006 +#define FSTV0910_P2_RST_HWARE 0xf3720001 + +/* P2_TSCFGM */ +#define RSTV0910_P2_TSCFGM 0xf373 +#define FSTV0910_P2_TSFIFO_MANSPEED 0xf37300c0 +#define FSTV0910_P2_TSFIFO_PERMDATA 0xf3730020 +#define FSTV0910_P2_TSFIFO_NONEWSGNL 0xf3730010 +#define FSTV0910_P2_TSFIFO_INVDATA 0xf3730001 + +/* P2_TSCFGL */ +#define RSTV0910_P2_TSCFGL 0xf374 +#define FSTV0910_P2_TSFIFO_BCLKDEL1CK 0xf37400c0 +#define FSTV0910_P2_BCHERROR_MODE 0xf3740030 +#define FSTV0910_P2_TSFIFO_NSGNL2DATA 0xf3740008 +#define FSTV0910_P2_TSFIFO_EMBINDVB 0xf3740004 +#define FSTV0910_P2_TSFIFO_BITSPEED 0xf3740003 + +/* P2_TSSYNC */ +#define RSTV0910_P2_TSSYNC 0xf375 +#define FSTV0910_P2_TSFIFO_SYNCMODE 0xf3750018 + +/* P2_TSINSDELH */ +#define RSTV0910_P2_TSINSDELH 0xf376 +#define FSTV0910_P2_TSDEL_SYNCBYTE 0xf3760080 +#define FSTV0910_P2_TSDEL_XXHEADER 0xf3760040 +#define FSTV0910_P2_TSDEL_DATAFIELD 0xf3760010 +#define FSTV0910_P2_TSINSDEL_RSPARITY 0xf3760002 +#define FSTV0910_P2_TSINSDEL_CRC8 0xf3760001 + +/* P2_TSINSDELM */ +#define RSTV0910_P2_TSINSDELM 0xf377 +#define FSTV0910_P2_TSINS_EMODCOD 0xf3770010 +#define FSTV0910_P2_TSINS_TOKEN 0xf3770008 +#define FSTV0910_P2_TSINS_XXXERR 0xf3770004 +#define FSTV0910_P2_TSINS_MATYPE 0xf3770002 +#define FSTV0910_P2_TSINS_UPL 0xf3770001 + +/* P2_TSINSDELL */ +#define RSTV0910_P2_TSINSDELL 0xf378 +#define FSTV0910_P2_TSINS_DFL 0xf3780080 +#define FSTV0910_P2_TSINS_SYNCD 0xf3780040 +#define FSTV0910_P2_TSINS_BLOCLEN 0xf3780020 +#define FSTV0910_P2_TSINS_SIGPCOUNT 0xf3780010 +#define FSTV0910_P2_TSINS_FIFO 0xf3780008 +#define FSTV0910_P2_TSINS_REALPACK 0xf3780004 +#define FSTV0910_P2_TSINS_TSCONFIG 0xf3780002 +#define FSTV0910_P2_TSINS_LATENCY 0xf3780001 + +/* P2_TSDIVN */ +#define RSTV0910_P2_TSDIVN 0xf379 +#define FSTV0910_P2_TSFIFO_SPEEDMODE 0xf37900c0 +#define FSTV0910_P2_TSFIFO_RISEOK 0xf3790007 + +/* P2_TSCFG4 */ +#define RSTV0910_P2_TSCFG4 0xf37a +#define FSTV0910_P2_TSFIFO_TSSPEEDMODE 0xf37a00c0 + +/* P2_TSSPEED */ +#define RSTV0910_P2_TSSPEED 0xf380 +#define FSTV0910_P2_TSFIFO_OUTSPEED 0xf38000ff + +/* P2_TSSTATUS */ +#define RSTV0910_P2_TSSTATUS 0xf381 +#define FSTV0910_P2_TSFIFO_LINEOK 0xf3810080 +#define FSTV0910_P2_TSFIFO_ERROR 0xf3810040 +#define FSTV0910_P2_TSFIFO_NOSYNC 0xf3810010 +#define FSTV0910_P2_TSREGUL_ERROR 0xf3810004 +#define FSTV0910_P2_DIL_READY 0xf3810001 + +/* P2_TSSTATUS2 */ +#define RSTV0910_P2_TSSTATUS2 0xf382 +#define FSTV0910_P2_TSFIFO_DEMODSEL 0xf3820080 +#define FSTV0910_P2_TSFIFOSPEED_STORE 0xf3820040 +#define FSTV0910_P2_DILXX_RESET 0xf3820020 +#define FSTV0910_P2_SCRAMBDETECT 0xf3820002 + +/* P2_TSBITRATE1 */ +#define RSTV0910_P2_TSBITRATE1 0xf383 +#define FSTV0910_P2_TSFIFO_BITRATE1 0xf38300ff + +/* P2_TSBITRATE0 */ +#define RSTV0910_P2_TSBITRATE0 0xf384 +#define FSTV0910_P2_TSFIFO_BITRATE0 0xf38400ff + +/* P2_TSPACKLEN1 */ +#define RSTV0910_P2_TSPACKLEN1 0xf385 +#define FSTV0910_P2_TSFIFO_PACKCPT 0xf38500e0 + +/* P2_TSDLY2 */ +#define RSTV0910_P2_TSDLY2 0xf389 +#define FSTV0910_P2_SOFFIFO_LATENCY2 0xf389000f + +/* P2_TSDLY1 */ +#define RSTV0910_P2_TSDLY1 0xf38a +#define FSTV0910_P2_SOFFIFO_LATENCY1 0xf38a00ff + +/* P2_TSDLY0 */ +#define RSTV0910_P2_TSDLY0 0xf38b +#define FSTV0910_P2_SOFFIFO_LATENCY0 0xf38b00ff + +/* P2_TSNPDAV */ +#define RSTV0910_P2_TSNPDAV 0xf38c +#define FSTV0910_P2_TSNPD_AVERAGE 0xf38c00ff + +/* P2_TSBUFSTAT2 */ +#define RSTV0910_P2_TSBUFSTAT2 0xf38d +#define FSTV0910_P2_TSISCR_3BYTES 0xf38d0080 +#define FSTV0910_P2_TSISCR_NEWDATA 0xf38d0040 +#define FSTV0910_P2_TSISCR_BUFSTAT2 0xf38d003f + +/* P2_TSBUFSTAT1 */ +#define RSTV0910_P2_TSBUFSTAT1 0xf38e +#define FSTV0910_P2_TSISCR_BUFSTAT1 0xf38e00ff + +/* P2_TSBUFSTAT0 */ +#define RSTV0910_P2_TSBUFSTAT0 0xf38f +#define FSTV0910_P2_TSISCR_BUFSTAT0 0xf38f00ff + +/* P2_TSDEBUGL */ +#define RSTV0910_P2_TSDEBUGL 0xf391 +#define FSTV0910_P2_TSFIFO_ERROR_EVNT 0xf3910004 +#define FSTV0910_P2_TSFIFO_OVERFLOWM 0xf3910001 + +/* P2_TSDLYSET2 */ +#define RSTV0910_P2_TSDLYSET2 0xf392 +#define FSTV0910_P2_SOFFIFO_OFFSET 0xf39200c0 +#define FSTV0910_P2_HYSTERESIS_THRESHOLD 0xf3920030 +#define FSTV0910_P2_SOFFIFO_SYMBOFFS2 0xf392000f + +/* P2_TSDLYSET1 */ +#define RSTV0910_P2_TSDLYSET1 0xf393 +#define FSTV0910_P2_SOFFIFO_SYMBOFFS1 0xf39300ff + +/* P2_TSDLYSET0 */ +#define RSTV0910_P2_TSDLYSET0 0xf394 +#define FSTV0910_P2_SOFFIFO_SYMBOFFS0 0xf39400ff + +/* P2_ERRCTRL1 */ +#define RSTV0910_P2_ERRCTRL1 0xf398 +#define FSTV0910_P2_ERR_SOURCE1 0xf39800f0 +#define FSTV0910_P2_NUM_EVENT1 0xf3980007 + +/* P2_ERRCNT12 */ +#define RSTV0910_P2_ERRCNT12 0xf399 +#define FSTV0910_P2_ERRCNT1_OLDVALUE 0xf3990080 +#define FSTV0910_P2_ERR_CNT12 0xf399007f + +/* P2_ERRCNT11 */ +#define RSTV0910_P2_ERRCNT11 0xf39a +#define FSTV0910_P2_ERR_CNT11 0xf39a00ff + +/* P2_ERRCNT10 */ +#define RSTV0910_P2_ERRCNT10 0xf39b +#define FSTV0910_P2_ERR_CNT10 0xf39b00ff + +/* P2_ERRCTRL2 */ +#define RSTV0910_P2_ERRCTRL2 0xf39c +#define FSTV0910_P2_ERR_SOURCE2 0xf39c00f0 +#define FSTV0910_P2_NUM_EVENT2 0xf39c0007 + +/* P2_ERRCNT22 */ +#define RSTV0910_P2_ERRCNT22 0xf39d +#define FSTV0910_P2_ERRCNT2_OLDVALUE 0xf39d0080 +#define FSTV0910_P2_ERR_CNT22 0xf39d007f + +/* P2_ERRCNT21 */ +#define RSTV0910_P2_ERRCNT21 0xf39e +#define FSTV0910_P2_ERR_CNT21 0xf39e00ff + +/* P2_ERRCNT20 */ +#define RSTV0910_P2_ERRCNT20 0xf39f +#define FSTV0910_P2_ERR_CNT20 0xf39f00ff + +/* P2_FECSPY */ +#define RSTV0910_P2_FECSPY 0xf3a0 +#define FSTV0910_P2_SPY_ENABLE 0xf3a00080 +#define FSTV0910_P2_NO_SYNCBYTE 0xf3a00040 +#define FSTV0910_P2_SERIAL_MODE 0xf3a00020 +#define FSTV0910_P2_UNUSUAL_PACKET 0xf3a00010 +#define FSTV0910_P2_BERMETER_DATAMODE 0xf3a0000c +#define FSTV0910_P2_BERMETER_LMODE 0xf3a00002 +#define FSTV0910_P2_BERMETER_RESET 0xf3a00001 + +/* P2_FSPYCFG */ +#define RSTV0910_P2_FSPYCFG 0xf3a1 +#define FSTV0910_P2_FECSPY_INPUT 0xf3a100c0 +#define FSTV0910_P2_RST_ON_ERROR 0xf3a10020 +#define FSTV0910_P2_ONE_SHOT 0xf3a10010 +#define FSTV0910_P2_I2C_MODE 0xf3a1000c +#define FSTV0910_P2_SPY_HYSTERESIS 0xf3a10003 + +/* P2_FSPYDATA */ +#define RSTV0910_P2_FSPYDATA 0xf3a2 +#define FSTV0910_P2_SPY_STUFFING 0xf3a20080 +#define FSTV0910_P2_SPY_CNULLPKT 0xf3a20020 +#define FSTV0910_P2_SPY_OUTDATA_MODE 0xf3a2001f + +/* P2_FSPYOUT */ +#define RSTV0910_P2_FSPYOUT 0xf3a3 +#define FSTV0910_P2_FSPY_DIRECT 0xf3a30080 +#define FSTV0910_P2_STUFF_MODE 0xf3a30007 + +/* P2_FSTATUS */ +#define RSTV0910_P2_FSTATUS 0xf3a4 +#define FSTV0910_P2_SPY_ENDSIM 0xf3a40080 +#define FSTV0910_P2_VALID_SIM 0xf3a40040 +#define FSTV0910_P2_FOUND_SIGNAL 0xf3a40020 +#define FSTV0910_P2_DSS_SYNCBYTE 0xf3a40010 +#define FSTV0910_P2_RESULT_STATE 0xf3a4000f + +/* P2_FBERCPT4 */ +#define RSTV0910_P2_FBERCPT4 0xf3a8 +#define FSTV0910_P2_FBERMETER_CPT4 0xf3a800ff + +/* P2_FBERCPT3 */ +#define RSTV0910_P2_FBERCPT3 0xf3a9 +#define FSTV0910_P2_FBERMETER_CPT3 0xf3a900ff + +/* P2_FBERCPT2 */ +#define RSTV0910_P2_FBERCPT2 0xf3aa +#define FSTV0910_P2_FBERMETER_CPT2 0xf3aa00ff + +/* P2_FBERCPT1 */ +#define RSTV0910_P2_FBERCPT1 0xf3ab +#define FSTV0910_P2_FBERMETER_CPT1 0xf3ab00ff + +/* P2_FBERCPT0 */ +#define RSTV0910_P2_FBERCPT0 0xf3ac +#define FSTV0910_P2_FBERMETER_CPT0 0xf3ac00ff + +/* P2_FBERERR2 */ +#define RSTV0910_P2_FBERERR2 0xf3ad +#define FSTV0910_P2_FBERMETER_ERR2 0xf3ad00ff + +/* P2_FBERERR1 */ +#define RSTV0910_P2_FBERERR1 0xf3ae +#define FSTV0910_P2_FBERMETER_ERR1 0xf3ae00ff + +/* P2_FBERERR0 */ +#define RSTV0910_P2_FBERERR0 0xf3af +#define FSTV0910_P2_FBERMETER_ERR0 0xf3af00ff + +/* P2_FSPYBER */ +#define RSTV0910_P2_FSPYBER 0xf3b2 +#define FSTV0910_P2_FSPYBER_SYNCBYTE 0xf3b20010 +#define FSTV0910_P2_FSPYBER_UNSYNC 0xf3b20008 +#define FSTV0910_P2_FSPYBER_CTIME 0xf3b20007 + +/* P2_SFERROR */ +#define RSTV0910_P2_SFERROR 0xf3c1 +#define FSTV0910_P2_SFEC_REGERR_VIT 0xf3c100ff + +/* P2_SFECSTATUS */ +#define RSTV0910_P2_SFECSTATUS 0xf3c3 +#define FSTV0910_P2_SFEC_ON 0xf3c30080 +#define FSTV0910_P2_SFEC_OFF 0xf3c30040 +#define FSTV0910_P2_LOCKEDSFEC 0xf3c30008 +#define FSTV0910_P2_SFEC_DELOCK 0xf3c30004 +#define FSTV0910_P2_SFEC_DEMODSEL 0xf3c30002 +#define FSTV0910_P2_SFEC_OVFON 0xf3c30001 + +/* P2_SFKDIV12 */ +#define RSTV0910_P2_SFKDIV12 0xf3c4 +#define FSTV0910_P2_SFECKDIV12_MAN 0xf3c40080 + +/* P2_SFKDIV23 */ +#define RSTV0910_P2_SFKDIV23 0xf3c5 +#define FSTV0910_P2_SFECKDIV23_MAN 0xf3c50080 + +/* P2_SFKDIV34 */ +#define RSTV0910_P2_SFKDIV34 0xf3c6 +#define FSTV0910_P2_SFECKDIV34_MAN 0xf3c60080 + +/* P2_SFKDIV56 */ +#define RSTV0910_P2_SFKDIV56 0xf3c7 +#define FSTV0910_P2_SFECKDIV56_MAN 0xf3c70080 + +/* P2_SFKDIV67 */ +#define RSTV0910_P2_SFKDIV67 0xf3c8 +#define FSTV0910_P2_SFECKDIV67_MAN 0xf3c80080 + +/* P2_SFKDIV78 */ +#define RSTV0910_P2_SFKDIV78 0xf3c9 +#define FSTV0910_P2_SFECKDIV78_MAN 0xf3c90080 + +/* P2_SFSTATUS */ +#define RSTV0910_P2_SFSTATUS 0xf3cc +#define FSTV0910_P2_SFEC_LINEOK 0xf3cc0080 +#define FSTV0910_P2_SFEC_ERROR 0xf3cc0040 +#define FSTV0910_P2_SFEC_DATA7 0xf3cc0020 +#define FSTV0910_P2_SFEC_PKTDNBRFAIL 0xf3cc0010 +#define FSTV0910_P2_TSSFEC_DEMODSEL 0xf3cc0008 +#define FSTV0910_P2_SFEC_NOSYNC 0xf3cc0004 +#define FSTV0910_P2_SFEC_UNREGULA 0xf3cc0002 +#define FSTV0910_P2_SFEC_READY 0xf3cc0001 + +/* P2_SFDLYSET2 */ +#define RSTV0910_P2_SFDLYSET2 0xf3d0 +#define FSTV0910_P2_SFEC_DISABLE 0xf3d00002 + +/* P2_SFERRCTRL */ +#define RSTV0910_P2_SFERRCTRL 0xf3d8 +#define FSTV0910_P2_SFEC_ERR_SOURCE 0xf3d800f0 +#define FSTV0910_P2_SFEC_NUM_EVENT 0xf3d80007 + +/* P2_SFERRCNT2 */ +#define RSTV0910_P2_SFERRCNT2 0xf3d9 +#define FSTV0910_P2_SFERRC_OLDVALUE 0xf3d90080 +#define FSTV0910_P2_SFEC_ERR_CNT2 0xf3d9007f + +/* P2_SFERRCNT1 */ +#define RSTV0910_P2_SFERRCNT1 0xf3da +#define FSTV0910_P2_SFEC_ERR_CNT1 0xf3da00ff + +/* P2_SFERRCNT0 */ +#define RSTV0910_P2_SFERRCNT0 0xf3db +#define FSTV0910_P2_SFEC_ERR_CNT0 0xf3db00ff + +/* P1_IQCONST */ +#define RSTV0910_P1_IQCONST 0xf400 +#define FSTV0910_P1_CONSTEL_SELECT 0xf4000060 +#define FSTV0910_P1_IQSYMB_SEL 0xf400001f + +/* P1_NOSCFG */ +#define RSTV0910_P1_NOSCFG 0xf401 +#define FSTV0910_P1_DUMMYPL_NOSDATA 0xf4010020 +#define FSTV0910_P1_NOSPLH_BETA 0xf4010018 +#define FSTV0910_P1_NOSDATA_BETA 0xf4010007 + +/* P1_ISYMB */ +#define RSTV0910_P1_ISYMB 0xf402 +#define FSTV0910_P1_I_SYMBOL 0xf40201ff + +/* P1_QSYMB */ +#define RSTV0910_P1_QSYMB 0xf403 +#define FSTV0910_P1_Q_SYMBOL 0xf40301ff + +/* P1_AGC1CFG */ +#define RSTV0910_P1_AGC1CFG 0xf404 +#define FSTV0910_P1_DC_FROZEN 0xf4040080 +#define FSTV0910_P1_DC_CORRECT 0xf4040040 +#define FSTV0910_P1_AMM_FROZEN 0xf4040020 +#define FSTV0910_P1_AMM_CORRECT 0xf4040010 +#define FSTV0910_P1_QUAD_FROZEN 0xf4040008 +#define FSTV0910_P1_QUAD_CORRECT 0xf4040004 + +/* P1_AGC1CN */ +#define RSTV0910_P1_AGC1CN 0xf406 +#define FSTV0910_P1_AGC1_LOCKED 0xf4060080 +#define FSTV0910_P1_AGC1_MINPOWER 0xf4060010 +#define FSTV0910_P1_AGCOUT_FAST 0xf4060008 +#define FSTV0910_P1_AGCIQ_BETA 0xf4060007 + +/* P1_AGC1REF */ +#define RSTV0910_P1_AGC1REF 0xf407 +#define FSTV0910_P1_AGCIQ_REF 0xf40700ff + +/* P1_IDCCOMP */ +#define RSTV0910_P1_IDCCOMP 0xf408 +#define FSTV0910_P1_IAVERAGE_ADJ 0xf40801ff + +/* P1_QDCCOMP */ +#define RSTV0910_P1_QDCCOMP 0xf409 +#define FSTV0910_P1_QAVERAGE_ADJ 0xf40901ff + +/* P1_POWERI */ +#define RSTV0910_P1_POWERI 0xf40a +#define FSTV0910_P1_POWER_I 0xf40a00ff + +/* P1_POWERQ */ +#define RSTV0910_P1_POWERQ 0xf40b +#define FSTV0910_P1_POWER_Q 0xf40b00ff + +/* P1_AGC1AMM */ +#define RSTV0910_P1_AGC1AMM 0xf40c +#define FSTV0910_P1_AMM_VALUE 0xf40c00ff + +/* P1_AGC1QUAD */ +#define RSTV0910_P1_AGC1QUAD 0xf40d +#define FSTV0910_P1_QUAD_VALUE 0xf40d01ff + +/* P1_AGCIQIN1 */ +#define RSTV0910_P1_AGCIQIN1 0xf40e +#define FSTV0910_P1_AGCIQ_VALUE1 0xf40e00ff + +/* P1_AGCIQIN0 */ +#define RSTV0910_P1_AGCIQIN0 0xf40f +#define FSTV0910_P1_AGCIQ_VALUE0 0xf40f00ff + +/* P1_DEMOD */ +#define RSTV0910_P1_DEMOD 0xf410 +#define FSTV0910_P1_MANUALS2_ROLLOFF 0xf4100080 +#define FSTV0910_P1_SPECINV_CONTROL 0xf4100030 +#define FSTV0910_P1_MANUALSX_ROLLOFF 0xf4100004 +#define FSTV0910_P1_ROLLOFF_CONTROL 0xf4100003 + +/* P1_DMDMODCOD */ +#define RSTV0910_P1_DMDMODCOD 0xf411 +#define FSTV0910_P1_MANUAL_MODCOD 0xf4110080 +#define FSTV0910_P1_DEMOD_MODCOD 0xf411007c +#define FSTV0910_P1_DEMOD_TYPE 0xf4110003 + +/* P1_DSTATUS */ +#define RSTV0910_P1_DSTATUS 0xf412 +#define FSTV0910_P1_CAR_LOCK 0xf4120080 +#define FSTV0910_P1_TMGLOCK_QUALITY 0xf4120060 +#define FSTV0910_P1_LOCK_DEFINITIF 0xf4120008 +#define FSTV0910_P1_OVADC_DETECT 0xf4120001 + +/* P1_DSTATUS2 */ +#define RSTV0910_P1_DSTATUS2 0xf413 +#define FSTV0910_P1_DEMOD_DELOCK 0xf4130080 +#define FSTV0910_P1_MODCODRQ_SYNCTAG 0xf4130020 +#define FSTV0910_P1_POLYPH_SATEVENT 0xf4130010 +#define FSTV0910_P1_AGC1_NOSIGNALACK 0xf4130008 +#define FSTV0910_P1_AGC2_OVERFLOW 0xf4130004 +#define FSTV0910_P1_CFR_OVERFLOW 0xf4130002 +#define FSTV0910_P1_GAMMA_OVERUNDER 0xf4130001 + +/* P1_DMDCFGMD */ +#define RSTV0910_P1_DMDCFGMD 0xf414 +#define FSTV0910_P1_DVBS2_ENABLE 0xf4140080 +#define FSTV0910_P1_DVBS1_ENABLE 0xf4140040 +#define FSTV0910_P1_SCAN_ENABLE 0xf4140010 +#define FSTV0910_P1_CFR_AUTOSCAN 0xf4140008 +#define FSTV0910_P1_TUN_RNG 0xf4140003 + +/* P1_DMDCFG2 */ +#define RSTV0910_P1_DMDCFG2 0xf415 +#define FSTV0910_P1_S1S2_SEQUENTIAL 0xf4150040 +#define FSTV0910_P1_INFINITE_RELOCK 0xf4150010 + +/* P1_DMDISTATE */ +#define RSTV0910_P1_DMDISTATE 0xf416 +#define FSTV0910_P1_I2C_NORESETDMODE 0xf4160080 +#define FSTV0910_P1_I2C_DEMOD_MODE 0xf416001f + +/* P1_DMDT0M */ +#define RSTV0910_P1_DMDT0M 0xf417 +#define FSTV0910_P1_DMDT0_MIN 0xf41700ff + +/* P1_DMDSTATE */ +#define RSTV0910_P1_DMDSTATE 0xf41b +#define FSTV0910_P1_HEADER_MODE 0xf41b0060 + +/* P1_DMDFLYW */ +#define RSTV0910_P1_DMDFLYW 0xf41c +#define FSTV0910_P1_I2C_IRQVAL 0xf41c00f0 +#define FSTV0910_P1_FLYWHEEL_CPT 0xf41c000f + +/* P1_DSTATUS3 */ +#define RSTV0910_P1_DSTATUS3 0xf41d +#define FSTV0910_P1_CFR_ZIGZAG 0xf41d0080 +#define FSTV0910_P1_DEMOD_CFGMODE 0xf41d0060 +#define FSTV0910_P1_GAMMA_LOWBAUDRATE 0xf41d0010 + +/* P1_DMDCFG3 */ +#define RSTV0910_P1_DMDCFG3 0xf41e +#define FSTV0910_P1_NOSTOP_FIFOFULL 0xf41e0008 + +/* P1_DMDCFG4 */ +#define RSTV0910_P1_DMDCFG4 0xf41f +#define FSTV0910_P1_DIS_VITLOCK 0xf41f0080 +#define FSTV0910_P1_DIS_CLKENABLE 0xf41f0004 + +/* P1_CORRELMANT */ +#define RSTV0910_P1_CORRELMANT 0xf420 +#define FSTV0910_P1_CORREL_MANT 0xf42000ff + +/* P1_CORRELABS */ +#define RSTV0910_P1_CORRELABS 0xf421 +#define FSTV0910_P1_CORREL_ABS 0xf42100ff + +/* P1_CORRELEXP */ +#define RSTV0910_P1_CORRELEXP 0xf422 +#define FSTV0910_P1_CORREL_ABSEXP 0xf42200f0 +#define FSTV0910_P1_CORREL_EXP 0xf422000f + +/* P1_PLHMODCOD */ +#define RSTV0910_P1_PLHMODCOD 0xf424 +#define FSTV0910_P1_SPECINV_DEMOD 0xf4240080 +#define FSTV0910_P1_PLH_MODCOD 0xf424007c +#define FSTV0910_P1_PLH_TYPE 0xf4240003 + +/* P1_DMDREG */ +#define RSTV0910_P1_DMDREG 0xf425 +#define FSTV0910_P1_DECIM_PLFRAMES 0xf4250001 + +/* P1_AGCNADJ */ +#define RSTV0910_P1_AGCNADJ 0xf426 +#define FSTV0910_P1_RADJOFF_AGC2 0xf4260080 +#define FSTV0910_P1_RADJOFF_AGC1 0xf4260040 +#define FSTV0910_P1_AGC_NADJ 0xf426013f + +/* P1_AGCKS */ +#define RSTV0910_P1_AGCKS 0xf427 +#define FSTV0910_P1_RSADJ_MANUALCFG 0xf4270080 +#define FSTV0910_P1_RSADJ_CCMMODE 0xf4270040 +#define FSTV0910_P1_RADJ_SPSK 0xf427013f + +/* P1_AGCKQ */ +#define RSTV0910_P1_AGCKQ 0xf428 +#define FSTV0910_P1_RADJON_DVBS1 0xf4280040 +#define FSTV0910_P1_RADJ_QPSK 0xf428013f + +/* P1_AGCK8 */ +#define RSTV0910_P1_AGCK8 0xf429 +#define FSTV0910_P1_RADJ_8PSK 0xf429013f + +/* P1_AGCK16 */ +#define RSTV0910_P1_AGCK16 0xf42a +#define FSTV0910_P1_R2ADJOFF_16APSK 0xf42a0040 +#define FSTV0910_P1_R1ADJOFF_16APSK 0xf42a0020 +#define FSTV0910_P1_RADJ_16APSK 0xf42a011f + +/* P1_AGCK32 */ +#define RSTV0910_P1_AGCK32 0xf42b +#define FSTV0910_P1_R3ADJOFF_32APSK 0xf42b0080 +#define FSTV0910_P1_R2ADJOFF_32APSK 0xf42b0040 +#define FSTV0910_P1_R1ADJOFF_32APSK 0xf42b0020 +#define FSTV0910_P1_RADJ_32APSK 0xf42b011f + +/* P1_AGC2O */ +#define RSTV0910_P1_AGC2O 0xf42c +#define FSTV0910_P1_CSTENV_MODE 0xf42c00c0 +#define FSTV0910_P1_AGC2_COEF 0xf42c0007 + +/* P1_AGC2REF */ +#define RSTV0910_P1_AGC2REF 0xf42d +#define FSTV0910_P1_AGC2_REF 0xf42d00ff + +/* P1_AGC1ADJ */ +#define RSTV0910_P1_AGC1ADJ 0xf42e +#define FSTV0910_P1_AGC1_ADJUSTED 0xf42e007f + +/* P1_AGCRSADJ */ +#define RSTV0910_P1_AGCRSADJ 0xf42f +#define FSTV0910_P1_RS_ADJUSTED 0xf42f007f + +/* P1_AGCRQADJ */ +#define RSTV0910_P1_AGCRQADJ 0xf430 +#define FSTV0910_P1_RQ_ADJUSTED 0xf430007f + +/* P1_AGCR8ADJ */ +#define RSTV0910_P1_AGCR8ADJ 0xf431 +#define FSTV0910_P1_R8_ADJUSTED 0xf431007f + +/* P1_AGCR1ADJ */ +#define RSTV0910_P1_AGCR1ADJ 0xf432 +#define FSTV0910_P1_R1_ADJUSTED 0xf432007f + +/* P1_AGCR2ADJ */ +#define RSTV0910_P1_AGCR2ADJ 0xf433 +#define FSTV0910_P1_R2_ADJUSTED 0xf433007f + +/* P1_AGCR3ADJ */ +#define RSTV0910_P1_AGCR3ADJ 0xf434 +#define FSTV0910_P1_R3_ADJUSTED 0xf434007f + +/* P1_AGCREFADJ */ +#define RSTV0910_P1_AGCREFADJ 0xf435 +#define FSTV0910_P1_AGC2REF_ADJUSTED 0xf435007f + +/* P1_AGC2I1 */ +#define RSTV0910_P1_AGC2I1 0xf436 +#define FSTV0910_P1_AGC2_INTEGRATOR1 0xf43600ff + +/* P1_AGC2I0 */ +#define RSTV0910_P1_AGC2I0 0xf437 +#define FSTV0910_P1_AGC2_INTEGRATOR0 0xf43700ff + +/* P1_CARCFG */ +#define RSTV0910_P1_CARCFG 0xf438 +#define FSTV0910_P1_ROTAON 0xf4380004 +#define FSTV0910_P1_PH_DET_ALGO 0xf4380003 + +/* P1_ACLC */ +#define RSTV0910_P1_ACLC 0xf439 +#define FSTV0910_P1_CAR_ALPHA_MANT 0xf4390030 +#define FSTV0910_P1_CAR_ALPHA_EXP 0xf439000f + +/* P1_BCLC */ +#define RSTV0910_P1_BCLC 0xf43a +#define FSTV0910_P1_CAR_BETA_MANT 0xf43a0030 +#define FSTV0910_P1_CAR_BETA_EXP 0xf43a000f + +/* P1_ACLCS2 */ +#define RSTV0910_P1_ACLCS2 0xf43b +#define FSTV0910_P1_CARS2_APLHA_MANTISSE 0xf43b0030 +#define FSTV0910_P1_CARS2_ALPHA_EXP 0xf43b000f + +/* P1_BCLCS2 */ +#define RSTV0910_P1_BCLCS2 0xf43c +#define FSTV0910_P1_CARS2_BETA_MANTISSE 0xf43c0030 +#define FSTV0910_P1_CARS2_BETA_EXP 0xf43c000f + +/* P1_CARFREQ */ +#define RSTV0910_P1_CARFREQ 0xf43d +#define FSTV0910_P1_KC_COARSE_EXP 0xf43d00f0 +#define FSTV0910_P1_BETA_FREQ 0xf43d000f + +/* P1_CARHDR */ +#define RSTV0910_P1_CARHDR 0xf43e +#define FSTV0910_P1_K_FREQ_HDR 0xf43e00ff + +/* P1_LDT */ +#define RSTV0910_P1_LDT 0xf43f +#define FSTV0910_P1_CARLOCK_THRES 0xf43f01ff + +/* P1_LDT2 */ +#define RSTV0910_P1_LDT2 0xf440 +#define FSTV0910_P1_CARLOCK_THRES2 0xf44001ff + +/* P1_CFRICFG */ +#define RSTV0910_P1_CFRICFG 0xf441 +#define FSTV0910_P1_NEG_CFRSTEP 0xf4410001 + +/* P1_CFRUP1 */ +#define RSTV0910_P1_CFRUP1 0xf442 +#define FSTV0910_P1_CFR_UP1 0xf44201ff + +/* P1_CFRUP0 */ +#define RSTV0910_P1_CFRUP0 0xf443 +#define FSTV0910_P1_CFR_UP0 0xf44300ff + +/* P1_CFRIBASE1 */ +#define RSTV0910_P1_CFRIBASE1 0xf444 +#define FSTV0910_P1_CFRINIT_BASE1 0xf44400ff + +/* P1_CFRIBASE0 */ +#define RSTV0910_P1_CFRIBASE0 0xf445 +#define FSTV0910_P1_CFRINIT_BASE0 0xf44500ff + +/* P1_CFRLOW1 */ +#define RSTV0910_P1_CFRLOW1 0xf446 +#define FSTV0910_P1_CFR_LOW1 0xf44601ff + +/* P1_CFRLOW0 */ +#define RSTV0910_P1_CFRLOW0 0xf447 +#define FSTV0910_P1_CFR_LOW0 0xf44700ff + +/* P1_CFRINIT1 */ +#define RSTV0910_P1_CFRINIT1 0xf448 +#define FSTV0910_P1_CFR_INIT1 0xf44801ff + +/* P1_CFRINIT0 */ +#define RSTV0910_P1_CFRINIT0 0xf449 +#define FSTV0910_P1_CFR_INIT0 0xf44900ff + +/* P1_CFRINC1 */ +#define RSTV0910_P1_CFRINC1 0xf44a +#define FSTV0910_P1_MANUAL_CFRINC 0xf44a0080 +#define FSTV0910_P1_CFR_INC1 0xf44a003f + +/* P1_CFRINC0 */ +#define RSTV0910_P1_CFRINC0 0xf44b +#define FSTV0910_P1_CFR_INC0 0xf44b00ff + +/* P1_CFR2 */ +#define RSTV0910_P1_CFR2 0xf44c +#define FSTV0910_P1_CAR_FREQ2 0xf44c01ff + +/* P1_CFR1 */ +#define RSTV0910_P1_CFR1 0xf44d +#define FSTV0910_P1_CAR_FREQ1 0xf44d00ff + +/* P1_CFR0 */ +#define RSTV0910_P1_CFR0 0xf44e +#define FSTV0910_P1_CAR_FREQ0 0xf44e00ff + +/* P1_LDI */ +#define RSTV0910_P1_LDI 0xf44f +#define FSTV0910_P1_LOCK_DET_INTEGR 0xf44f01ff + +/* P1_TMGCFG */ +#define RSTV0910_P1_TMGCFG 0xf450 +#define FSTV0910_P1_TMGLOCK_BETA 0xf45000c0 +#define FSTV0910_P1_DO_TIMING_CORR 0xf4500010 +#define FSTV0910_P1_TMG_MINFREQ 0xf4500003 + +/* P1_RTC */ +#define RSTV0910_P1_RTC 0xf451 +#define FSTV0910_P1_TMGALPHA_EXP 0xf45100f0 +#define FSTV0910_P1_TMGBETA_EXP 0xf451000f + +/* P1_RTCS2 */ +#define RSTV0910_P1_RTCS2 0xf452 +#define FSTV0910_P1_TMGALPHAS2_EXP 0xf45200f0 +#define FSTV0910_P1_TMGBETAS2_EXP 0xf452000f + +/* P1_TMGTHRISE */ +#define RSTV0910_P1_TMGTHRISE 0xf453 +#define FSTV0910_P1_TMGLOCK_THRISE 0xf45300ff + +/* P1_TMGTHFALL */ +#define RSTV0910_P1_TMGTHFALL 0xf454 +#define FSTV0910_P1_TMGLOCK_THFALL 0xf45400ff + +/* P1_SFRUPRATIO */ +#define RSTV0910_P1_SFRUPRATIO 0xf455 +#define FSTV0910_P1_SFR_UPRATIO 0xf45500ff + +/* P1_SFRLOWRATIO */ +#define RSTV0910_P1_SFRLOWRATIO 0xf456 +#define FSTV0910_P1_SFR_LOWRATIO 0xf45600ff + +/* P1_KTTMG */ +#define RSTV0910_P1_KTTMG 0xf457 +#define FSTV0910_P1_KT_TMG_EXP 0xf45700f0 + +/* P1_KREFTMG */ +#define RSTV0910_P1_KREFTMG 0xf458 +#define FSTV0910_P1_KREF_TMG 0xf45800ff + +/* P1_SFRSTEP */ +#define RSTV0910_P1_SFRSTEP 0xf459 +#define FSTV0910_P1_SFR_SCANSTEP 0xf45900f0 +#define FSTV0910_P1_SFR_CENTERSTEP 0xf459000f + +/* P1_TMGCFG2 */ +#define RSTV0910_P1_TMGCFG2 0xf45a +#define FSTV0910_P1_DIS_AUTOSAMP 0xf45a0008 +#define FSTV0910_P1_SFRRATIO_FINE 0xf45a0001 + +/* P1_KREFTMG2 */ +#define RSTV0910_P1_KREFTMG2 0xf45b +#define FSTV0910_P1_KREF_TMG2 0xf45b00ff + +/* P1_TMGCFG3 */ +#define RSTV0910_P1_TMGCFG3 0xf45d +#define FSTV0910_P1_CONT_TMGCENTER 0xf45d0008 +#define FSTV0910_P1_AUTO_GUP 0xf45d0004 +#define FSTV0910_P1_AUTO_GLOW 0xf45d0002 + +/* P1_SFRINIT1 */ +#define RSTV0910_P1_SFRINIT1 0xf45e +#define FSTV0910_P1_SFR_INIT1 0xf45e00ff + +/* P1_SFRINIT0 */ +#define RSTV0910_P1_SFRINIT0 0xf45f +#define FSTV0910_P1_SFR_INIT0 0xf45f00ff + +/* P1_SFRUP1 */ +#define RSTV0910_P1_SFRUP1 0xf460 +#define FSTV0910_P1_SYMB_FREQ_UP1 0xf46000ff + +/* P1_SFRUP0 */ +#define RSTV0910_P1_SFRUP0 0xf461 +#define FSTV0910_P1_SYMB_FREQ_UP0 0xf46100ff + +/* P1_SFRLOW1 */ +#define RSTV0910_P1_SFRLOW1 0xf462 +#define FSTV0910_P1_SYMB_FREQ_LOW1 0xf46200ff + +/* P1_SFRLOW0 */ +#define RSTV0910_P1_SFRLOW0 0xf463 +#define FSTV0910_P1_SYMB_FREQ_LOW0 0xf46300ff + +/* P1_SFR3 */ +#define RSTV0910_P1_SFR3 0xf464 +#define FSTV0910_P1_SYMB_FREQ3 0xf46400ff + +/* P1_SFR2 */ +#define RSTV0910_P1_SFR2 0xf465 +#define FSTV0910_P1_SYMB_FREQ2 0xf46500ff + +/* P1_SFR1 */ +#define RSTV0910_P1_SFR1 0xf466 +#define FSTV0910_P1_SYMB_FREQ1 0xf46600ff + +/* P1_SFR0 */ +#define RSTV0910_P1_SFR0 0xf467 +#define FSTV0910_P1_SYMB_FREQ0 0xf46700ff + +/* P1_TMGREG2 */ +#define RSTV0910_P1_TMGREG2 0xf468 +#define FSTV0910_P1_TMGREG2 0xf46800ff + +/* P1_TMGREG1 */ +#define RSTV0910_P1_TMGREG1 0xf469 +#define FSTV0910_P1_TMGREG1 0xf46900ff + +/* P1_TMGREG0 */ +#define RSTV0910_P1_TMGREG0 0xf46a +#define FSTV0910_P1_TMGREG0 0xf46a00ff + +/* P1_TMGLOCK1 */ +#define RSTV0910_P1_TMGLOCK1 0xf46b +#define FSTV0910_P1_TMGLOCK_LEVEL1 0xf46b01ff + +/* P1_TMGLOCK0 */ +#define RSTV0910_P1_TMGLOCK0 0xf46c +#define FSTV0910_P1_TMGLOCK_LEVEL0 0xf46c00ff + +/* P1_TMGOBS */ +#define RSTV0910_P1_TMGOBS 0xf46d +#define FSTV0910_P1_ROLLOFF_STATUS 0xf46d00c0 + +/* P1_EQUALCFG */ +#define RSTV0910_P1_EQUALCFG 0xf46f +#define FSTV0910_P1_EQUAL_ON 0xf46f0040 +#define FSTV0910_P1_MU_EQUALDFE 0xf46f0007 + +/* P1_EQUAI1 */ +#define RSTV0910_P1_EQUAI1 0xf470 +#define FSTV0910_P1_EQUA_ACCI1 0xf47001ff + +/* P1_EQUAQ1 */ +#define RSTV0910_P1_EQUAQ1 0xf471 +#define FSTV0910_P1_EQUA_ACCQ1 0xf47101ff + +/* P1_EQUAI2 */ +#define RSTV0910_P1_EQUAI2 0xf472 +#define FSTV0910_P1_EQUA_ACCI2 0xf47201ff + +/* P1_EQUAQ2 */ +#define RSTV0910_P1_EQUAQ2 0xf473 +#define FSTV0910_P1_EQUA_ACCQ2 0xf47301ff + +/* P1_EQUAI3 */ +#define RSTV0910_P1_EQUAI3 0xf474 +#define FSTV0910_P1_EQUA_ACCI3 0xf47401ff + +/* P1_EQUAQ3 */ +#define RSTV0910_P1_EQUAQ3 0xf475 +#define FSTV0910_P1_EQUA_ACCQ3 0xf47501ff + +/* P1_EQUAI4 */ +#define RSTV0910_P1_EQUAI4 0xf476 +#define FSTV0910_P1_EQUA_ACCI4 0xf47601ff + +/* P1_EQUAQ4 */ +#define RSTV0910_P1_EQUAQ4 0xf477 +#define FSTV0910_P1_EQUA_ACCQ4 0xf47701ff + +/* P1_EQUAI5 */ +#define RSTV0910_P1_EQUAI5 0xf478 +#define FSTV0910_P1_EQUA_ACCI5 0xf47801ff + +/* P1_EQUAQ5 */ +#define RSTV0910_P1_EQUAQ5 0xf479 +#define FSTV0910_P1_EQUA_ACCQ5 0xf47901ff + +/* P1_EQUAI6 */ +#define RSTV0910_P1_EQUAI6 0xf47a +#define FSTV0910_P1_EQUA_ACCI6 0xf47a01ff + +/* P1_EQUAQ6 */ +#define RSTV0910_P1_EQUAQ6 0xf47b +#define FSTV0910_P1_EQUA_ACCQ6 0xf47b01ff + +/* P1_EQUAI7 */ +#define RSTV0910_P1_EQUAI7 0xf47c +#define FSTV0910_P1_EQUA_ACCI7 0xf47c01ff + +/* P1_EQUAQ7 */ +#define RSTV0910_P1_EQUAQ7 0xf47d +#define FSTV0910_P1_EQUA_ACCQ7 0xf47d01ff + +/* P1_EQUAI8 */ +#define RSTV0910_P1_EQUAI8 0xf47e +#define FSTV0910_P1_EQUA_ACCI8 0xf47e01ff + +/* P1_EQUAQ8 */ +#define RSTV0910_P1_EQUAQ8 0xf47f +#define FSTV0910_P1_EQUA_ACCQ8 0xf47f01ff + +/* P1_NNOSDATAT1 */ +#define RSTV0910_P1_NNOSDATAT1 0xf480 +#define FSTV0910_P1_NOSDATAT_NORMED1 0xf48000ff + +/* P1_NNOSDATAT0 */ +#define RSTV0910_P1_NNOSDATAT0 0xf481 +#define FSTV0910_P1_NOSDATAT_NORMED0 0xf48100ff + +/* P1_NNOSDATA1 */ +#define RSTV0910_P1_NNOSDATA1 0xf482 +#define FSTV0910_P1_NOSDATA_NORMED1 0xf48200ff + +/* P1_NNOSDATA0 */ +#define RSTV0910_P1_NNOSDATA0 0xf483 +#define FSTV0910_P1_NOSDATA_NORMED0 0xf48300ff + +/* P1_NNOSPLHT1 */ +#define RSTV0910_P1_NNOSPLHT1 0xf484 +#define FSTV0910_P1_NOSPLHT_NORMED1 0xf48400ff + +/* P1_NNOSPLHT0 */ +#define RSTV0910_P1_NNOSPLHT0 0xf485 +#define FSTV0910_P1_NOSPLHT_NORMED0 0xf48500ff + +/* P1_NNOSPLH1 */ +#define RSTV0910_P1_NNOSPLH1 0xf486 +#define FSTV0910_P1_NOSPLH_NORMED1 0xf48600ff + +/* P1_NNOSPLH0 */ +#define RSTV0910_P1_NNOSPLH0 0xf487 +#define FSTV0910_P1_NOSPLH_NORMED0 0xf48700ff + +/* P1_NOSDATAT1 */ +#define RSTV0910_P1_NOSDATAT1 0xf488 +#define FSTV0910_P1_NOSDATAT_UNNORMED1 0xf48800ff + +/* P1_NOSDATAT0 */ +#define RSTV0910_P1_NOSDATAT0 0xf489 +#define FSTV0910_P1_NOSDATAT_UNNORMED0 0xf48900ff + +/* P1_NNOSFRAME1 */ +#define RSTV0910_P1_NNOSFRAME1 0xf48a +#define FSTV0910_P1_NOSFRAME_NORMED1 0xf48a00ff + +/* P1_NNOSFRAME0 */ +#define RSTV0910_P1_NNOSFRAME0 0xf48b +#define FSTV0910_P1_NOSFRAME_NORMED0 0xf48b00ff + +/* P1_NNOSRAD1 */ +#define RSTV0910_P1_NNOSRAD1 0xf48c +#define FSTV0910_P1_NOSRADIAL_NORMED1 0xf48c00ff + +/* P1_NNOSRAD0 */ +#define RSTV0910_P1_NNOSRAD0 0xf48d +#define FSTV0910_P1_NOSRADIAL_NORMED0 0xf48d00ff + +/* P1_NOSCFGF1 */ +#define RSTV0910_P1_NOSCFGF1 0xf48e +#define FSTV0910_P1_LOWNOISE_MESURE 0xf48e0080 +#define FSTV0910_P1_NOS_DELFRAME 0xf48e0040 +#define FSTV0910_P1_NOSDATA_MODE 0xf48e0030 +#define FSTV0910_P1_FRAMESEL_TYPESEL 0xf48e000c +#define FSTV0910_P1_FRAMESEL_TYPE 0xf48e0003 + +/* P1_NOSCFGF2 */ +#define RSTV0910_P1_NOSCFGF2 0xf48f +#define FSTV0910_P1_DIS_NOSPILOTS 0xf48f0080 +#define FSTV0910_P1_FRAMESEL_MODCODSEL 0xf48f0060 +#define FSTV0910_P1_FRAMESEL_MODCOD 0xf48f001f + +/* P1_CAR2CFG */ +#define RSTV0910_P1_CAR2CFG 0xf490 +#define FSTV0910_P1_ROTA2ON 0xf4900004 +#define FSTV0910_P1_PH_DET_ALGO2 0xf4900003 + +/* P1_CFR2CFR1 */ +#define RSTV0910_P1_CFR2CFR1 0xf491 +#define FSTV0910_P1_EN_S2CAR2CENTER 0xf4910020 +#define FSTV0910_P1_CFR2TOCFR1_BETA 0xf4910007 + +/* P1_CAR3CFG */ +#define RSTV0910_P1_CAR3CFG 0xf492 +#define FSTV0910_P1_CARRIER23_MODE 0xf49200c0 +#define FSTV0910_P1_CAR3INTERM_DVBS1 0xf4920020 +#define FSTV0910_P1_ABAMPLIF_MODE 0xf4920018 +#define FSTV0910_P1_CARRIER3_ALPHA3DL 0xf4920007 + +/* P1_CFR22 */ +#define RSTV0910_P1_CFR22 0xf493 +#define FSTV0910_P1_CAR2_FREQ2 0xf49301ff + +/* P1_CFR21 */ +#define RSTV0910_P1_CFR21 0xf494 +#define FSTV0910_P1_CAR2_FREQ1 0xf49400ff + +/* P1_CFR20 */ +#define RSTV0910_P1_CFR20 0xf495 +#define FSTV0910_P1_CAR2_FREQ0 0xf49500ff + +/* P1_ACLC2S2Q */ +#define RSTV0910_P1_ACLC2S2Q 0xf497 +#define FSTV0910_P1_ENAB_SPSKSYMB 0xf4970080 +#define FSTV0910_P1_CAR2S2_Q_ALPH_M 0xf4970030 +#define FSTV0910_P1_CAR2S2_Q_ALPH_E 0xf497000f + +/* P1_ACLC2S28 */ +#define RSTV0910_P1_ACLC2S28 0xf498 +#define FSTV0910_P1_CAR2S2_8_ALPH_M 0xf4980030 +#define FSTV0910_P1_CAR2S2_8_ALPH_E 0xf498000f + +/* P1_ACLC2S216A */ +#define RSTV0910_P1_ACLC2S216A 0xf499 +#define FSTV0910_P1_CAR2S2_16A_ALPH_M 0xf4990030 +#define FSTV0910_P1_CAR2S2_16A_ALPH_E 0xf499000f + +/* P1_ACLC2S232A */ +#define RSTV0910_P1_ACLC2S232A 0xf49a +#define FSTV0910_P1_CAR2S2_32A_ALPH_M 0xf49a0030 +#define FSTV0910_P1_CAR2S2_32A_ALPH_E 0xf49a000f + +/* P1_BCLC2S2Q */ +#define RSTV0910_P1_BCLC2S2Q 0xf49c +#define FSTV0910_P1_CAR2S2_Q_BETA_M 0xf49c0030 +#define FSTV0910_P1_CAR2S2_Q_BETA_E 0xf49c000f + +/* P1_BCLC2S28 */ +#define RSTV0910_P1_BCLC2S28 0xf49d +#define FSTV0910_P1_CAR2S2_8_BETA_M 0xf49d0030 +#define FSTV0910_P1_CAR2S2_8_BETA_E 0xf49d000f + +/* P1_BCLC2S216A */ +#define RSTV0910_P1_BCLC2S216A 0xf49e +#define FSTV0910_P1_DVBS2S216A_NIP 0xf49e0080 +#define FSTV0910_P1_CAR2S2_16A_BETA_M 0xf49e0030 +#define FSTV0910_P1_CAR2S2_16A_BETA_E 0xf49e000f + +/* P1_BCLC2S232A */ +#define RSTV0910_P1_BCLC2S232A 0xf49f +#define FSTV0910_P1_DVBS2S232A_NIP 0xf49f0080 +#define FSTV0910_P1_CAR2S2_32A_BETA_M 0xf49f0030 +#define FSTV0910_P1_CAR2S2_32A_BETA_E 0xf49f000f + +/* P1_PLROOT2 */ +#define RSTV0910_P1_PLROOT2 0xf4ac +#define FSTV0910_P1_PLSCRAMB_MODE 0xf4ac000c +#define FSTV0910_P1_PLSCRAMB_ROOT2 0xf4ac0003 + +/* P1_PLROOT1 */ +#define RSTV0910_P1_PLROOT1 0xf4ad +#define FSTV0910_P1_PLSCRAMB_ROOT1 0xf4ad00ff + +/* P1_PLROOT0 */ +#define RSTV0910_P1_PLROOT0 0xf4ae +#define FSTV0910_P1_PLSCRAMB_ROOT0 0xf4ae00ff + +/* P1_MODCODLST0 */ +#define RSTV0910_P1_MODCODLST0 0xf4b0 +#define FSTV0910_P1_NACCES_MODCODCH 0xf4b00001 + +/* P1_MODCODLST1 */ +#define RSTV0910_P1_MODCODLST1 0xf4b1 +#define FSTV0910_P1_SYMBRATE_FILTER 0xf4b10008 +#define FSTV0910_P1_NRESET_MODCODLST 0xf4b10004 +#define FSTV0910_P1_DIS_32PSK_9_10 0xf4b10003 + +/* P1_MODCODLST2 */ +#define RSTV0910_P1_MODCODLST2 0xf4b2 +#define FSTV0910_P1_DIS_32PSK_8_9 0xf4b200f0 +#define FSTV0910_P1_DIS_32PSK_5_6 0xf4b2000f + +/* P1_MODCODLST3 */ +#define RSTV0910_P1_MODCODLST3 0xf4b3 +#define FSTV0910_P1_DIS_32PSK_4_5 0xf4b300f0 +#define FSTV0910_P1_DIS_32PSK_3_4 0xf4b3000f + +/* P1_MODCODLST4 */ +#define RSTV0910_P1_MODCODLST4 0xf4b4 +#define FSTV0910_P1_DUMMYPL_PILOT 0xf4b40080 +#define FSTV0910_P1_DUMMYPL_NOPILOT 0xf4b40040 +#define FSTV0910_P1_DIS_16PSK_9_10 0xf4b40030 +#define FSTV0910_P1_DIS_16PSK_8_9 0xf4b4000f + +/* P1_MODCODLST5 */ +#define RSTV0910_P1_MODCODLST5 0xf4b5 +#define FSTV0910_P1_DIS_16PSK_5_6 0xf4b500f0 +#define FSTV0910_P1_DIS_16PSK_4_5 0xf4b5000f + +/* P1_MODCODLST6 */ +#define RSTV0910_P1_MODCODLST6 0xf4b6 +#define FSTV0910_P1_DIS_16PSK_3_4 0xf4b600f0 +#define FSTV0910_P1_DIS_16PSK_2_3 0xf4b6000f + +/* P1_MODCODLST7 */ +#define RSTV0910_P1_MODCODLST7 0xf4b7 +#define FSTV0910_P1_MODCOD_NNOSFILTER 0xf4b70080 +#define FSTV0910_P1_DIS_8PSK_9_10 0xf4b70030 +#define FSTV0910_P1_DIS_8PSK_8_9 0xf4b7000f + +/* P1_MODCODLST8 */ +#define RSTV0910_P1_MODCODLST8 0xf4b8 +#define FSTV0910_P1_DIS_8PSK_5_6 0xf4b800f0 +#define FSTV0910_P1_DIS_8PSK_3_4 0xf4b8000f + +/* P1_MODCODLST9 */ +#define RSTV0910_P1_MODCODLST9 0xf4b9 +#define FSTV0910_P1_DIS_8PSK_2_3 0xf4b900f0 +#define FSTV0910_P1_DIS_8PSK_3_5 0xf4b9000f + +/* P1_MODCODLSTA */ +#define RSTV0910_P1_MODCODLSTA 0xf4ba +#define FSTV0910_P1_NOSFILTER_LIMITE 0xf4ba0080 +#define FSTV0910_P1_DIS_QPSK_9_10 0xf4ba0030 +#define FSTV0910_P1_DIS_QPSK_8_9 0xf4ba000f + +/* P1_MODCODLSTB */ +#define RSTV0910_P1_MODCODLSTB 0xf4bb +#define FSTV0910_P1_DIS_QPSK_5_6 0xf4bb00f0 +#define FSTV0910_P1_DIS_QPSK_4_5 0xf4bb000f + +/* P1_MODCODLSTC */ +#define RSTV0910_P1_MODCODLSTC 0xf4bc +#define FSTV0910_P1_DIS_QPSK_3_4 0xf4bc00f0 +#define FSTV0910_P1_DIS_QPSK_2_3 0xf4bc000f + +/* P1_MODCODLSTD */ +#define RSTV0910_P1_MODCODLSTD 0xf4bd +#define FSTV0910_P1_DIS_QPSK_3_5 0xf4bd00f0 +#define FSTV0910_P1_DIS_QPSK_1_2 0xf4bd000f + +/* P1_MODCODLSTE */ +#define RSTV0910_P1_MODCODLSTE 0xf4be +#define FSTV0910_P1_DIS_QPSK_2_5 0xf4be00f0 +#define FSTV0910_P1_DIS_QPSK_1_3 0xf4be000f + +/* P1_MODCODLSTF */ +#define RSTV0910_P1_MODCODLSTF 0xf4bf +#define FSTV0910_P1_DIS_QPSK_1_4 0xf4bf00f0 +#define FSTV0910_P1_DEMOD_INVMODLST 0xf4bf0008 +#define FSTV0910_P1_DEMODOUT_ENABLE 0xf4bf0004 +#define FSTV0910_P1_DDEMOD_NSET 0xf4bf0002 +#define FSTV0910_P1_MODCOD_NSTOCK 0xf4bf0001 + +/* P1_GAUSSR0 */ +#define RSTV0910_P1_GAUSSR0 0xf4c0 +#define FSTV0910_P1_EN_CCIMODE 0xf4c00080 +#define FSTV0910_P1_R0_GAUSSIEN 0xf4c0007f + +/* P1_CCIR0 */ +#define RSTV0910_P1_CCIR0 0xf4c1 +#define FSTV0910_P1_CCIDETECT_PLHONLY 0xf4c10080 +#define FSTV0910_P1_R0_CCI 0xf4c1007f + +/* P1_CCIQUANT */ +#define RSTV0910_P1_CCIQUANT 0xf4c2 +#define FSTV0910_P1_CCI_BETA 0xf4c200e0 +#define FSTV0910_P1_CCI_QUANT 0xf4c2001f + +/* P1_CCITHRES */ +#define RSTV0910_P1_CCITHRES 0xf4c3 +#define FSTV0910_P1_CCI_THRESHOLD 0xf4c300ff + +/* P1_CCIACC */ +#define RSTV0910_P1_CCIACC 0xf4c4 +#define FSTV0910_P1_CCI_VALUE 0xf4c400ff + +/* P1_DSTATUS4 */ +#define RSTV0910_P1_DSTATUS4 0xf4c5 +#define FSTV0910_P1_RAINFADE_DETECT 0xf4c50080 +#define FSTV0910_P1_NOTHRES2_FAIL 0xf4c50040 +#define FSTV0910_P1_NOTHRES1_FAIL 0xf4c50020 +#define FSTV0910_P1_DMDPROG_ERROR 0xf4c50004 +#define FSTV0910_P1_CSTENV_DETECT 0xf4c50002 +#define FSTV0910_P1_DETECTION_TRIAX 0xf4c50001 + +/* P1_DMDRESCFG */ +#define RSTV0910_P1_DMDRESCFG 0xf4c6 +#define FSTV0910_P1_DMDRES_RESET 0xf4c60080 +#define FSTV0910_P1_DMDRES_STRALL 0xf4c60008 +#define FSTV0910_P1_DMDRES_NEWONLY 0xf4c60004 +#define FSTV0910_P1_DMDRES_NOSTORE 0xf4c60002 + +/* P1_DMDRESADR */ +#define RSTV0910_P1_DMDRESADR 0xf4c7 +#define FSTV0910_P1_DMDRES_VALIDCFR 0xf4c70040 +#define FSTV0910_P1_DMDRES_MEMFULL 0xf4c70030 +#define FSTV0910_P1_DMDRES_RESNBR 0xf4c7000f + +/* P1_DMDRESDATA7 */ +#define RSTV0910_P1_DMDRESDATA7 0xf4c8 +#define FSTV0910_P1_DMDRES_DATA7 0xf4c800ff + +/* P1_DMDRESDATA6 */ +#define RSTV0910_P1_DMDRESDATA6 0xf4c9 +#define FSTV0910_P1_DMDRES_DATA6 0xf4c900ff + +/* P1_DMDRESDATA5 */ +#define RSTV0910_P1_DMDRESDATA5 0xf4ca +#define FSTV0910_P1_DMDRES_DATA5 0xf4ca00ff + +/* P1_DMDRESDATA4 */ +#define RSTV0910_P1_DMDRESDATA4 0xf4cb +#define FSTV0910_P1_DMDRES_DATA4 0xf4cb00ff + +/* P1_DMDRESDATA3 */ +#define RSTV0910_P1_DMDRESDATA3 0xf4cc +#define FSTV0910_P1_DMDRES_DATA3 0xf4cc00ff + +/* P1_DMDRESDATA2 */ +#define RSTV0910_P1_DMDRESDATA2 0xf4cd +#define FSTV0910_P1_DMDRES_DATA2 0xf4cd00ff + +/* P1_DMDRESDATA1 */ +#define RSTV0910_P1_DMDRESDATA1 0xf4ce +#define FSTV0910_P1_DMDRES_DATA1 0xf4ce00ff + +/* P1_DMDRESDATA0 */ +#define RSTV0910_P1_DMDRESDATA0 0xf4cf +#define FSTV0910_P1_DMDRES_DATA0 0xf4cf00ff + +/* P1_FFEI1 */ +#define RSTV0910_P1_FFEI1 0xf4d0 +#define FSTV0910_P1_FFE_ACCI1 0xf4d001ff + +/* P1_FFEQ1 */ +#define RSTV0910_P1_FFEQ1 0xf4d1 +#define FSTV0910_P1_FFE_ACCQ1 0xf4d101ff + +/* P1_FFEI2 */ +#define RSTV0910_P1_FFEI2 0xf4d2 +#define FSTV0910_P1_FFE_ACCI2 0xf4d201ff + +/* P1_FFEQ2 */ +#define RSTV0910_P1_FFEQ2 0xf4d3 +#define FSTV0910_P1_FFE_ACCQ2 0xf4d301ff + +/* P1_FFEI3 */ +#define RSTV0910_P1_FFEI3 0xf4d4 +#define FSTV0910_P1_FFE_ACCI3 0xf4d401ff + +/* P1_FFEQ3 */ +#define RSTV0910_P1_FFEQ3 0xf4d5 +#define FSTV0910_P1_FFE_ACCQ3 0xf4d501ff + +/* P1_FFEI4 */ +#define RSTV0910_P1_FFEI4 0xf4d6 +#define FSTV0910_P1_FFE_ACCI4 0xf4d601ff + +/* P1_FFEQ4 */ +#define RSTV0910_P1_FFEQ4 0xf4d7 +#define FSTV0910_P1_FFE_ACCQ4 0xf4d701ff + +/* P1_FFECFG */ +#define RSTV0910_P1_FFECFG 0xf4d8 +#define FSTV0910_P1_EQUALFFE_ON 0xf4d80040 +#define FSTV0910_P1_EQUAL_USEDSYMB 0xf4d80030 +#define FSTV0910_P1_MU_EQUALFFE 0xf4d80007 + +/* P1_TNRCFG2 */ +#define RSTV0910_P1_TNRCFG2 0xf4e1 +#define FSTV0910_P1_TUN_IQSWAP 0xf4e10080 + +/* P1_SMAPCOEF7 */ +#define RSTV0910_P1_SMAPCOEF7 0xf500 +#define FSTV0910_P1_DIS_QSCALE 0xf5000080 +#define FSTV0910_P1_SMAPCOEF_Q_LLR12 0xf500017f + +/* P1_SMAPCOEF6 */ +#define RSTV0910_P1_SMAPCOEF6 0xf501 +#define FSTV0910_P1_DIS_AGC2SCALE 0xf5010080 +#define FSTV0910_P1_ADJ_8PSKLLR1 0xf5010004 +#define FSTV0910_P1_OLD_8PSKLLR1 0xf5010002 +#define FSTV0910_P1_DIS_AB8PSK 0xf5010001 + +/* P1_SMAPCOEF5 */ +#define RSTV0910_P1_SMAPCOEF5 0xf502 +#define FSTV0910_P1_DIS_8SCALE 0xf5020080 +#define FSTV0910_P1_SMAPCOEF_8P_LLR23 0xf502017f + +/* P1_SMAPCOEF4 */ +#define RSTV0910_P1_SMAPCOEF4 0xf503 +#define FSTV0910_P1_SMAPCOEF_16APSK_LLR12 0xf503017f + +/* P1_SMAPCOEF3 */ +#define RSTV0910_P1_SMAPCOEF3 0xf504 +#define FSTV0910_P1_SMAPCOEF_16APSK_LLR34 0xf504017f + +/* P1_SMAPCOEF2 */ +#define RSTV0910_P1_SMAPCOEF2 0xf505 +#define FSTV0910_P1_SMAPCOEF_32APSK_R2R3 0xf50501f0 +#define FSTV0910_P1_SMAPCOEF_32APSK_LLR2 0xf505010f + +/* P1_SMAPCOEF1 */ +#define RSTV0910_P1_SMAPCOEF1 0xf506 +#define FSTV0910_P1_DIS_16SCALE 0xf5060080 +#define FSTV0910_P1_SMAPCOEF_32_LLR34 0xf506017f + +/* P1_SMAPCOEF0 */ +#define RSTV0910_P1_SMAPCOEF0 0xf507 +#define FSTV0910_P1_DIS_32SCALE 0xf5070080 +#define FSTV0910_P1_SMAPCOEF_32_LLR15 0xf507017f + +/* P1_NOSTHRES1 */ +#define RSTV0910_P1_NOSTHRES1 0xf509 +#define FSTV0910_P1_NOS_THRESHOLD1 0xf50900ff + +/* P1_NOSTHRES2 */ +#define RSTV0910_P1_NOSTHRES2 0xf50a +#define FSTV0910_P1_NOS_THRESHOLD2 0xf50a00ff + +/* P1_NOSDIFF1 */ +#define RSTV0910_P1_NOSDIFF1 0xf50b +#define FSTV0910_P1_NOSTHRES1_DIFF 0xf50b00ff + +/* P1_RAINFADE */ +#define RSTV0910_P1_RAINFADE 0xf50c +#define FSTV0910_P1_NOSTHRES_DATAT 0xf50c0080 +#define FSTV0910_P1_RAINFADE_CNLIMIT 0xf50c0070 +#define FSTV0910_P1_RAINFADE_TIMEOUT 0xf50c0007 + +/* P1_NOSRAMCFG */ +#define RSTV0910_P1_NOSRAMCFG 0xf50d +#define FSTV0910_P1_NOSRAM_ACTIVATION 0xf50d0030 +#define FSTV0910_P1_NOSRAM_CNRONLY 0xf50d0008 +#define FSTV0910_P1_NOSRAM_LGNCNR1 0xf50d0007 + +/* P1_NOSRAMPOS */ +#define RSTV0910_P1_NOSRAMPOS 0xf50e +#define FSTV0910_P1_NOSRAM_LGNCNR0 0xf50e00f0 +#define FSTV0910_P1_NOSRAM_VALIDE 0xf50e0004 +#define FSTV0910_P1_NOSRAM_CNRVAL1 0xf50e0003 + +/* P1_NOSRAMVAL */ +#define RSTV0910_P1_NOSRAMVAL 0xf50f +#define FSTV0910_P1_NOSRAM_CNRVAL0 0xf50f00ff + +/* P1_DMDPLHSTAT */ +#define RSTV0910_P1_DMDPLHSTAT 0xf520 +#define FSTV0910_P1_PLH_STATISTIC 0xf52000ff + +/* P1_LOCKTIME3 */ +#define RSTV0910_P1_LOCKTIME3 0xf522 +#define FSTV0910_P1_DEMOD_LOCKTIME3 0xf52200ff + +/* P1_LOCKTIME2 */ +#define RSTV0910_P1_LOCKTIME2 0xf523 +#define FSTV0910_P1_DEMOD_LOCKTIME2 0xf52300ff + +/* P1_LOCKTIME1 */ +#define RSTV0910_P1_LOCKTIME1 0xf524 +#define FSTV0910_P1_DEMOD_LOCKTIME1 0xf52400ff + +/* P1_LOCKTIME0 */ +#define RSTV0910_P1_LOCKTIME0 0xf525 +#define FSTV0910_P1_DEMOD_LOCKTIME0 0xf52500ff + +/* P1_VITSCALE */ +#define RSTV0910_P1_VITSCALE 0xf532 +#define FSTV0910_P1_NVTH_NOSRANGE 0xf5320080 +#define FSTV0910_P1_VERROR_MAXMODE 0xf5320040 +#define FSTV0910_P1_NSLOWSN_LOCKED 0xf5320008 +#define FSTV0910_P1_DIS_RSFLOCK 0xf5320002 + +/* P1_FECM */ +#define RSTV0910_P1_FECM 0xf533 +#define FSTV0910_P1_DSS_DVB 0xf5330080 +#define FSTV0910_P1_DSS_SRCH 0xf5330010 +#define FSTV0910_P1_SYNCVIT 0xf5330002 +#define FSTV0910_P1_IQINV 0xf5330001 + +/* P1_VTH12 */ +#define RSTV0910_P1_VTH12 0xf534 +#define FSTV0910_P1_VTH12 0xf53400ff + +/* P1_VTH23 */ +#define RSTV0910_P1_VTH23 0xf535 +#define FSTV0910_P1_VTH23 0xf53500ff + +/* P1_VTH34 */ +#define RSTV0910_P1_VTH34 0xf536 +#define FSTV0910_P1_VTH34 0xf53600ff + +/* P1_VTH56 */ +#define RSTV0910_P1_VTH56 0xf537 +#define FSTV0910_P1_VTH56 0xf53700ff + +/* P1_VTH67 */ +#define RSTV0910_P1_VTH67 0xf538 +#define FSTV0910_P1_VTH67 0xf53800ff + +/* P1_VTH78 */ +#define RSTV0910_P1_VTH78 0xf539 +#define FSTV0910_P1_VTH78 0xf53900ff + +/* P1_VITCURPUN */ +#define RSTV0910_P1_VITCURPUN 0xf53a +#define FSTV0910_P1_VIT_CURPUN 0xf53a001f + +/* P1_VERROR */ +#define RSTV0910_P1_VERROR 0xf53b +#define FSTV0910_P1_REGERR_VIT 0xf53b00ff + +/* P1_PRVIT */ +#define RSTV0910_P1_PRVIT 0xf53c +#define FSTV0910_P1_DIS_VTHLOCK 0xf53c0040 +#define FSTV0910_P1_E7_8VIT 0xf53c0020 +#define FSTV0910_P1_E6_7VIT 0xf53c0010 +#define FSTV0910_P1_E5_6VIT 0xf53c0008 +#define FSTV0910_P1_E3_4VIT 0xf53c0004 +#define FSTV0910_P1_E2_3VIT 0xf53c0002 +#define FSTV0910_P1_E1_2VIT 0xf53c0001 + +/* P1_VAVSRVIT */ +#define RSTV0910_P1_VAVSRVIT 0xf53d +#define FSTV0910_P1_AMVIT 0xf53d0080 +#define FSTV0910_P1_FROZENVIT 0xf53d0040 +#define FSTV0910_P1_SNVIT 0xf53d0030 +#define FSTV0910_P1_TOVVIT 0xf53d000c +#define FSTV0910_P1_HYPVIT 0xf53d0003 + +/* P1_VSTATUSVIT */ +#define RSTV0910_P1_VSTATUSVIT 0xf53e +#define FSTV0910_P1_PRFVIT 0xf53e0010 +#define FSTV0910_P1_LOCKEDVIT 0xf53e0008 + +/* P1_VTHINUSE */ +#define RSTV0910_P1_VTHINUSE 0xf53f +#define FSTV0910_P1_VIT_INUSE 0xf53f00ff + +/* P1_KDIV12 */ +#define RSTV0910_P1_KDIV12 0xf540 +#define FSTV0910_P1_K_DIVIDER_12 0xf540007f + +/* P1_KDIV23 */ +#define RSTV0910_P1_KDIV23 0xf541 +#define FSTV0910_P1_K_DIVIDER_23 0xf541007f + +/* P1_KDIV34 */ +#define RSTV0910_P1_KDIV34 0xf542 +#define FSTV0910_P1_K_DIVIDER_34 0xf542007f + +/* P1_KDIV56 */ +#define RSTV0910_P1_KDIV56 0xf543 +#define FSTV0910_P1_K_DIVIDER_56 0xf543007f + +/* P1_KDIV67 */ +#define RSTV0910_P1_KDIV67 0xf544 +#define FSTV0910_P1_K_DIVIDER_67 0xf544007f + +/* P1_KDIV78 */ +#define RSTV0910_P1_KDIV78 0xf545 +#define FSTV0910_P1_K_DIVIDER_78 0xf545007f + +/* P1_TSPIDFLT1 */ +#define RSTV0910_P1_TSPIDFLT1 0xf546 +#define FSTV0910_P1_PIDFLT_ADDR 0xf54600ff + +/* P1_TSPIDFLT0 */ +#define RSTV0910_P1_TSPIDFLT0 0xf547 +#define FSTV0910_P1_PIDFLT_DATA 0xf54700ff + +/* P1_PDELCTRL0 */ +#define RSTV0910_P1_PDELCTRL0 0xf54f +#define FSTV0910_P1_ISIOBS_MODE 0xf54f0030 + +/* P1_PDELCTRL1 */ +#define RSTV0910_P1_PDELCTRL1 0xf550 +#define FSTV0910_P1_INV_MISMASK 0xf5500080 +#define FSTV0910_P1_FILTER_EN 0xf5500020 +#define FSTV0910_P1_HYSTEN 0xf5500008 +#define FSTV0910_P1_HYSTSWRST 0xf5500004 +#define FSTV0910_P1_EN_MIS00 0xf5500002 +#define FSTV0910_P1_ALGOSWRST 0xf5500001 + +/* P1_PDELCTRL2 */ +#define RSTV0910_P1_PDELCTRL2 0xf551 +#define FSTV0910_P1_FORCE_CONTINUOUS 0xf5510080 +#define FSTV0910_P1_RESET_UPKO_COUNT 0xf5510040 +#define FSTV0910_P1_USER_PKTDELIN_NB 0xf5510020 +#define FSTV0910_P1_FRAME_MODE 0xf5510002 + +/* P1_HYSTTHRESH */ +#define RSTV0910_P1_HYSTTHRESH 0xf554 +#define FSTV0910_P1_DELIN_LOCKTHRES 0xf55400f0 +#define FSTV0910_P1_DELIN_UNLOCKTHRES 0xf554000f + +/* P1_UPLCCST0 */ +#define RSTV0910_P1_UPLCCST0 0xf558 +#define FSTV0910_P1_UPL_CST0 0xf55800f8 +#define FSTV0910_P1_UPL_MODE 0xf5580007 + +/* P1_ISIENTRY */ +#define RSTV0910_P1_ISIENTRY 0xf55e +#define FSTV0910_P1_ISI_ENTRY 0xf55e00ff + +/* P1_ISIBITENA */ +#define RSTV0910_P1_ISIBITENA 0xf55f +#define FSTV0910_P1_ISI_BIT_EN 0xf55f00ff + +/* P1_MATSTR1 */ +#define RSTV0910_P1_MATSTR1 0xf560 +#define FSTV0910_P1_MATYPE_CURRENT1 0xf56000ff + +/* P1_MATSTR0 */ +#define RSTV0910_P1_MATSTR0 0xf561 +#define FSTV0910_P1_MATYPE_CURRENT0 0xf56100ff + +/* P1_UPLSTR1 */ +#define RSTV0910_P1_UPLSTR1 0xf562 +#define FSTV0910_P1_UPL_CURRENT1 0xf56200ff + +/* P1_UPLSTR0 */ +#define RSTV0910_P1_UPLSTR0 0xf563 +#define FSTV0910_P1_UPL_CURRENT0 0xf56300ff + +/* P1_DFLSTR1 */ +#define RSTV0910_P1_DFLSTR1 0xf564 +#define FSTV0910_P1_DFL_CURRENT1 0xf56400ff + +/* P1_DFLSTR0 */ +#define RSTV0910_P1_DFLSTR0 0xf565 +#define FSTV0910_P1_DFL_CURRENT0 0xf56500ff + +/* P1_SYNCSTR */ +#define RSTV0910_P1_SYNCSTR 0xf566 +#define FSTV0910_P1_SYNC_CURRENT 0xf56600ff + +/* P1_SYNCDSTR1 */ +#define RSTV0910_P1_SYNCDSTR1 0xf567 +#define FSTV0910_P1_SYNCD_CURRENT1 0xf56700ff + +/* P1_SYNCDSTR0 */ +#define RSTV0910_P1_SYNCDSTR0 0xf568 +#define FSTV0910_P1_SYNCD_CURRENT0 0xf56800ff + +/* P1_PDELSTATUS1 */ +#define RSTV0910_P1_PDELSTATUS1 0xf569 +#define FSTV0910_P1_PKTDELIN_DELOCK 0xf5690080 +#define FSTV0910_P1_SYNCDUPDFL_BADDFL 0xf5690040 +#define FSTV0910_P1_UNACCEPTED_STREAM 0xf5690010 +#define FSTV0910_P1_BCH_ERROR_FLAG 0xf5690008 +#define FSTV0910_P1_PKTDELIN_LOCK 0xf5690002 +#define FSTV0910_P1_FIRST_LOCK 0xf5690001 + +/* P1_PDELSTATUS2 */ +#define RSTV0910_P1_PDELSTATUS2 0xf56a +#define FSTV0910_P1_FRAME_MODCOD 0xf56a007c +#define FSTV0910_P1_FRAME_TYPE 0xf56a0003 + +/* P1_BBFCRCKO1 */ +#define RSTV0910_P1_BBFCRCKO1 0xf56b +#define FSTV0910_P1_BBHCRC_KOCNT1 0xf56b00ff + +/* P1_BBFCRCKO0 */ +#define RSTV0910_P1_BBFCRCKO0 0xf56c +#define FSTV0910_P1_BBHCRC_KOCNT0 0xf56c00ff + +/* P1_UPCRCKO1 */ +#define RSTV0910_P1_UPCRCKO1 0xf56d +#define FSTV0910_P1_PKTCRC_KOCNT1 0xf56d00ff + +/* P1_UPCRCKO0 */ +#define RSTV0910_P1_UPCRCKO0 0xf56e +#define FSTV0910_P1_PKTCRC_KOCNT0 0xf56e00ff + +/* P1_PDELCTRL3 */ +#define RSTV0910_P1_PDELCTRL3 0xf56f +#define FSTV0910_P1_NOFIFO_BCHERR 0xf56f0020 +#define FSTV0910_P1_PKTDELIN_DELACMERR 0xf56f0010 + +/* P1_TSSTATEM */ +#define RSTV0910_P1_TSSTATEM 0xf570 +#define FSTV0910_P1_TSDIL_ON 0xf5700080 +#define FSTV0910_P1_TSRS_ON 0xf5700020 +#define FSTV0910_P1_TSDESCRAMB_ON 0xf5700010 +#define FSTV0910_P1_TSFRAME_MODE 0xf5700008 +#define FSTV0910_P1_TS_DISABLE 0xf5700004 +#define FSTV0910_P1_TSACM_MODE 0xf5700002 +#define FSTV0910_P1_TSOUT_NOSYNC 0xf5700001 + +/* P1_TSSTATEL */ +#define RSTV0910_P1_TSSTATEL 0xf571 +#define FSTV0910_P1_TSNOSYNCBYTE 0xf5710080 +#define FSTV0910_P1_TSPARITY_ON 0xf5710040 +#define FSTV0910_P1_TSISSYI_ON 0xf5710008 +#define FSTV0910_P1_TSNPD_ON 0xf5710004 +#define FSTV0910_P1_TSCRC8_ON 0xf5710002 +#define FSTV0910_P1_TSDSS_PACKET 0xf5710001 + +/* P1_TSCFGH */ +#define RSTV0910_P1_TSCFGH 0xf572 +#define FSTV0910_P1_TSFIFO_DVBCI 0xf5720080 +#define FSTV0910_P1_TSFIFO_SERIAL 0xf5720040 +#define FSTV0910_P1_TSFIFO_TEIUPDATE 0xf5720020 +#define FSTV0910_P1_TSFIFO_DUTY50 0xf5720010 +#define FSTV0910_P1_TSFIFO_HSGNLOUT 0xf5720008 +#define FSTV0910_P1_TSFIFO_ERRMODE 0xf5720006 +#define FSTV0910_P1_RST_HWARE 0xf5720001 + +/* P1_TSCFGM */ +#define RSTV0910_P1_TSCFGM 0xf573 +#define FSTV0910_P1_TSFIFO_MANSPEED 0xf57300c0 +#define FSTV0910_P1_TSFIFO_PERMDATA 0xf5730020 +#define FSTV0910_P1_TSFIFO_NONEWSGNL 0xf5730010 +#define FSTV0910_P1_TSFIFO_INVDATA 0xf5730001 + +/* P1_TSCFGL */ +#define RSTV0910_P1_TSCFGL 0xf574 +#define FSTV0910_P1_TSFIFO_BCLKDEL1CK 0xf57400c0 +#define FSTV0910_P1_BCHERROR_MODE 0xf5740030 +#define FSTV0910_P1_TSFIFO_NSGNL2DATA 0xf5740008 +#define FSTV0910_P1_TSFIFO_EMBINDVB 0xf5740004 +#define FSTV0910_P1_TSFIFO_BITSPEED 0xf5740003 + +/* P1_TSSYNC */ +#define RSTV0910_P1_TSSYNC 0xf575 +#define FSTV0910_P1_TSFIFO_SYNCMODE 0xf5750018 + +/* P1_TSINSDELH */ +#define RSTV0910_P1_TSINSDELH 0xf576 +#define FSTV0910_P1_TSDEL_SYNCBYTE 0xf5760080 +#define FSTV0910_P1_TSDEL_XXHEADER 0xf5760040 +#define FSTV0910_P1_TSDEL_DATAFIELD 0xf5760010 +#define FSTV0910_P1_TSINSDEL_RSPARITY 0xf5760002 +#define FSTV0910_P1_TSINSDEL_CRC8 0xf5760001 + +/* P1_TSINSDELM */ +#define RSTV0910_P1_TSINSDELM 0xf577 +#define FSTV0910_P1_TSINS_EMODCOD 0xf5770010 +#define FSTV0910_P1_TSINS_TOKEN 0xf5770008 +#define FSTV0910_P1_TSINS_XXXERR 0xf5770004 +#define FSTV0910_P1_TSINS_MATYPE 0xf5770002 +#define FSTV0910_P1_TSINS_UPL 0xf5770001 + +/* P1_TSINSDELL */ +#define RSTV0910_P1_TSINSDELL 0xf578 +#define FSTV0910_P1_TSINS_DFL 0xf5780080 +#define FSTV0910_P1_TSINS_SYNCD 0xf5780040 +#define FSTV0910_P1_TSINS_BLOCLEN 0xf5780020 +#define FSTV0910_P1_TSINS_SIGPCOUNT 0xf5780010 +#define FSTV0910_P1_TSINS_FIFO 0xf5780008 +#define FSTV0910_P1_TSINS_REALPACK 0xf5780004 +#define FSTV0910_P1_TSINS_TSCONFIG 0xf5780002 +#define FSTV0910_P1_TSINS_LATENCY 0xf5780001 + +/* P1_TSDIVN */ +#define RSTV0910_P1_TSDIVN 0xf579 +#define FSTV0910_P1_TSFIFO_SPEEDMODE 0xf57900c0 +#define FSTV0910_P1_TSFIFO_RISEOK 0xf5790007 + +/* P1_TSCFG4 */ +#define RSTV0910_P1_TSCFG4 0xf57a +#define FSTV0910_P1_TSFIFO_TSSPEEDMODE 0xf57a00c0 + +/* P1_TSSPEED */ +#define RSTV0910_P1_TSSPEED 0xf580 +#define FSTV0910_P1_TSFIFO_OUTSPEED 0xf58000ff + +/* P1_TSSTATUS */ +#define RSTV0910_P1_TSSTATUS 0xf581 +#define FSTV0910_P1_TSFIFO_LINEOK 0xf5810080 +#define FSTV0910_P1_TSFIFO_ERROR 0xf5810040 +#define FSTV0910_P1_TSFIFO_NOSYNC 0xf5810010 +#define FSTV0910_P1_TSREGUL_ERROR 0xf5810004 +#define FSTV0910_P1_DIL_READY 0xf5810001 + +/* P1_TSSTATUS2 */ +#define RSTV0910_P1_TSSTATUS2 0xf582 +#define FSTV0910_P1_TSFIFO_DEMODSEL 0xf5820080 +#define FSTV0910_P1_TSFIFOSPEED_STORE 0xf5820040 +#define FSTV0910_P1_DILXX_RESET 0xf5820020 +#define FSTV0910_P1_SCRAMBDETECT 0xf5820002 + +/* P1_TSBITRATE1 */ +#define RSTV0910_P1_TSBITRATE1 0xf583 +#define FSTV0910_P1_TSFIFO_BITRATE1 0xf58300ff + +/* P1_TSBITRATE0 */ +#define RSTV0910_P1_TSBITRATE0 0xf584 +#define FSTV0910_P1_TSFIFO_BITRATE0 0xf58400ff + +/* P1_TSPACKLEN1 */ +#define RSTV0910_P1_TSPACKLEN1 0xf585 +#define FSTV0910_P1_TSFIFO_PACKCPT 0xf58500e0 + +/* P1_TSDLY2 */ +#define RSTV0910_P1_TSDLY2 0xf589 +#define FSTV0910_P1_SOFFIFO_LATENCY2 0xf589000f + +/* P1_TSDLY1 */ +#define RSTV0910_P1_TSDLY1 0xf58a +#define FSTV0910_P1_SOFFIFO_LATENCY1 0xf58a00ff + +/* P1_TSDLY0 */ +#define RSTV0910_P1_TSDLY0 0xf58b +#define FSTV0910_P1_SOFFIFO_LATENCY0 0xf58b00ff + +/* P1_TSNPDAV */ +#define RSTV0910_P1_TSNPDAV 0xf58c +#define FSTV0910_P1_TSNPD_AVERAGE 0xf58c00ff + +/* P1_TSBUFSTAT2 */ +#define RSTV0910_P1_TSBUFSTAT2 0xf58d +#define FSTV0910_P1_TSISCR_3BYTES 0xf58d0080 +#define FSTV0910_P1_TSISCR_NEWDATA 0xf58d0040 +#define FSTV0910_P1_TSISCR_BUFSTAT2 0xf58d003f + +/* P1_TSBUFSTAT1 */ +#define RSTV0910_P1_TSBUFSTAT1 0xf58e +#define FSTV0910_P1_TSISCR_BUFSTAT1 0xf58e00ff + +/* P1_TSBUFSTAT0 */ +#define RSTV0910_P1_TSBUFSTAT0 0xf58f +#define FSTV0910_P1_TSISCR_BUFSTAT0 0xf58f00ff + +/* P1_TSDEBUGL */ +#define RSTV0910_P1_TSDEBUGL 0xf591 +#define FSTV0910_P1_TSFIFO_ERROR_EVNT 0xf5910004 +#define FSTV0910_P1_TSFIFO_OVERFLOWM 0xf5910001 + +/* P1_TSDLYSET2 */ +#define RSTV0910_P1_TSDLYSET2 0xf592 +#define FSTV0910_P1_SOFFIFO_OFFSET 0xf59200c0 +#define FSTV0910_P1_HYSTERESIS_THRESHOLD 0xf5920030 +#define FSTV0910_P1_SOFFIFO_SYMBOFFS2 0xf592000f + +/* P1_TSDLYSET1 */ +#define RSTV0910_P1_TSDLYSET1 0xf593 +#define FSTV0910_P1_SOFFIFO_SYMBOFFS1 0xf59300ff + +/* P1_TSDLYSET0 */ +#define RSTV0910_P1_TSDLYSET0 0xf594 +#define FSTV0910_P1_SOFFIFO_SYMBOFFS0 0xf59400ff + +/* P1_ERRCTRL1 */ +#define RSTV0910_P1_ERRCTRL1 0xf598 +#define FSTV0910_P1_ERR_SOURCE1 0xf59800f0 +#define FSTV0910_P1_NUM_EVENT1 0xf5980007 + +/* P1_ERRCNT12 */ +#define RSTV0910_P1_ERRCNT12 0xf599 +#define FSTV0910_P1_ERRCNT1_OLDVALUE 0xf5990080 +#define FSTV0910_P1_ERR_CNT12 0xf599007f + +/* P1_ERRCNT11 */ +#define RSTV0910_P1_ERRCNT11 0xf59a +#define FSTV0910_P1_ERR_CNT11 0xf59a00ff + +/* P1_ERRCNT10 */ +#define RSTV0910_P1_ERRCNT10 0xf59b +#define FSTV0910_P1_ERR_CNT10 0xf59b00ff + +/* P1_ERRCTRL2 */ +#define RSTV0910_P1_ERRCTRL2 0xf59c +#define FSTV0910_P1_ERR_SOURCE2 0xf59c00f0 +#define FSTV0910_P1_NUM_EVENT2 0xf59c0007 + +/* P1_ERRCNT22 */ +#define RSTV0910_P1_ERRCNT22 0xf59d +#define FSTV0910_P1_ERRCNT2_OLDVALUE 0xf59d0080 +#define FSTV0910_P1_ERR_CNT22 0xf59d007f + +/* P1_ERRCNT21 */ +#define RSTV0910_P1_ERRCNT21 0xf59e +#define FSTV0910_P1_ERR_CNT21 0xf59e00ff + +/* P1_ERRCNT20 */ +#define RSTV0910_P1_ERRCNT20 0xf59f +#define FSTV0910_P1_ERR_CNT20 0xf59f00ff + +/* P1_FECSPY */ +#define RSTV0910_P1_FECSPY 0xf5a0 +#define FSTV0910_P1_SPY_ENABLE 0xf5a00080 +#define FSTV0910_P1_NO_SYNCBYTE 0xf5a00040 +#define FSTV0910_P1_SERIAL_MODE 0xf5a00020 +#define FSTV0910_P1_UNUSUAL_PACKET 0xf5a00010 +#define FSTV0910_P1_BERMETER_DATAMODE 0xf5a0000c +#define FSTV0910_P1_BERMETER_LMODE 0xf5a00002 +#define FSTV0910_P1_BERMETER_RESET 0xf5a00001 + +/* P1_FSPYCFG */ +#define RSTV0910_P1_FSPYCFG 0xf5a1 +#define FSTV0910_P1_FECSPY_INPUT 0xf5a100c0 +#define FSTV0910_P1_RST_ON_ERROR 0xf5a10020 +#define FSTV0910_P1_ONE_SHOT 0xf5a10010 +#define FSTV0910_P1_I2C_MODE 0xf5a1000c +#define FSTV0910_P1_SPY_HYSTERESIS 0xf5a10003 + +/* P1_FSPYDATA */ +#define RSTV0910_P1_FSPYDATA 0xf5a2 +#define FSTV0910_P1_SPY_STUFFING 0xf5a20080 +#define FSTV0910_P1_SPY_CNULLPKT 0xf5a20020 +#define FSTV0910_P1_SPY_OUTDATA_MODE 0xf5a2001f + +/* P1_FSPYOUT */ +#define RSTV0910_P1_FSPYOUT 0xf5a3 +#define FSTV0910_P1_FSPY_DIRECT 0xf5a30080 +#define FSTV0910_P1_STUFF_MODE 0xf5a30007 + +/* P1_FSTATUS */ +#define RSTV0910_P1_FSTATUS 0xf5a4 +#define FSTV0910_P1_SPY_ENDSIM 0xf5a40080 +#define FSTV0910_P1_VALID_SIM 0xf5a40040 +#define FSTV0910_P1_FOUND_SIGNAL 0xf5a40020 +#define FSTV0910_P1_DSS_SYNCBYTE 0xf5a40010 +#define FSTV0910_P1_RESULT_STATE 0xf5a4000f + +/* P1_FBERCPT4 */ +#define RSTV0910_P1_FBERCPT4 0xf5a8 +#define FSTV0910_P1_FBERMETER_CPT4 0xf5a800ff + +/* P1_FBERCPT3 */ +#define RSTV0910_P1_FBERCPT3 0xf5a9 +#define FSTV0910_P1_FBERMETER_CPT3 0xf5a900ff + +/* P1_FBERCPT2 */ +#define RSTV0910_P1_FBERCPT2 0xf5aa +#define FSTV0910_P1_FBERMETER_CPT2 0xf5aa00ff + +/* P1_FBERCPT1 */ +#define RSTV0910_P1_FBERCPT1 0xf5ab +#define FSTV0910_P1_FBERMETER_CPT1 0xf5ab00ff + +/* P1_FBERCPT0 */ +#define RSTV0910_P1_FBERCPT0 0xf5ac +#define FSTV0910_P1_FBERMETER_CPT0 0xf5ac00ff + +/* P1_FBERERR2 */ +#define RSTV0910_P1_FBERERR2 0xf5ad +#define FSTV0910_P1_FBERMETER_ERR2 0xf5ad00ff + +/* P1_FBERERR1 */ +#define RSTV0910_P1_FBERERR1 0xf5ae +#define FSTV0910_P1_FBERMETER_ERR1 0xf5ae00ff + +/* P1_FBERERR0 */ +#define RSTV0910_P1_FBERERR0 0xf5af +#define FSTV0910_P1_FBERMETER_ERR0 0xf5af00ff + +/* P1_FSPYBER */ +#define RSTV0910_P1_FSPYBER 0xf5b2 +#define FSTV0910_P1_FSPYBER_SYNCBYTE 0xf5b20010 +#define FSTV0910_P1_FSPYBER_UNSYNC 0xf5b20008 +#define FSTV0910_P1_FSPYBER_CTIME 0xf5b20007 + +/* P1_SFERROR */ +#define RSTV0910_P1_SFERROR 0xf5c1 +#define FSTV0910_P1_SFEC_REGERR_VIT 0xf5c100ff + +/* P1_SFECSTATUS */ +#define RSTV0910_P1_SFECSTATUS 0xf5c3 +#define FSTV0910_P1_SFEC_ON 0xf5c30080 +#define FSTV0910_P1_SFEC_OFF 0xf5c30040 +#define FSTV0910_P1_LOCKEDSFEC 0xf5c30008 +#define FSTV0910_P1_SFEC_DELOCK 0xf5c30004 +#define FSTV0910_P1_SFEC_DEMODSEL 0xf5c30002 +#define FSTV0910_P1_SFEC_OVFON 0xf5c30001 + +/* P1_SFKDIV12 */ +#define RSTV0910_P1_SFKDIV12 0xf5c4 +#define FSTV0910_P1_SFECKDIV12_MAN 0xf5c40080 + +/* P1_SFKDIV23 */ +#define RSTV0910_P1_SFKDIV23 0xf5c5 +#define FSTV0910_P1_SFECKDIV23_MAN 0xf5c50080 + +/* P1_SFKDIV34 */ +#define RSTV0910_P1_SFKDIV34 0xf5c6 +#define FSTV0910_P1_SFECKDIV34_MAN 0xf5c60080 + +/* P1_SFKDIV56 */ +#define RSTV0910_P1_SFKDIV56 0xf5c7 +#define FSTV0910_P1_SFECKDIV56_MAN 0xf5c70080 + +/* P1_SFKDIV67 */ +#define RSTV0910_P1_SFKDIV67 0xf5c8 +#define FSTV0910_P1_SFECKDIV67_MAN 0xf5c80080 + +/* P1_SFKDIV78 */ +#define RSTV0910_P1_SFKDIV78 0xf5c9 +#define FSTV0910_P1_SFECKDIV78_MAN 0xf5c90080 + +/* P1_SFSTATUS */ +#define RSTV0910_P1_SFSTATUS 0xf5cc +#define FSTV0910_P1_SFEC_LINEOK 0xf5cc0080 +#define FSTV0910_P1_SFEC_ERROR 0xf5cc0040 +#define FSTV0910_P1_SFEC_DATA7 0xf5cc0020 +#define FSTV0910_P1_SFEC_PKTDNBRFAIL 0xf5cc0010 +#define FSTV0910_P1_TSSFEC_DEMODSEL 0xf5cc0008 +#define FSTV0910_P1_SFEC_NOSYNC 0xf5cc0004 +#define FSTV0910_P1_SFEC_UNREGULA 0xf5cc0002 +#define FSTV0910_P1_SFEC_READY 0xf5cc0001 + +/* P1_SFDLYSET2 */ +#define RSTV0910_P1_SFDLYSET2 0xf5d0 +#define FSTV0910_P1_SFEC_DISABLE 0xf5d00002 + +/* P1_SFERRCTRL */ +#define RSTV0910_P1_SFERRCTRL 0xf5d8 +#define FSTV0910_P1_SFEC_ERR_SOURCE 0xf5d800f0 +#define FSTV0910_P1_SFEC_NUM_EVENT 0xf5d80007 + +/* P1_SFERRCNT2 */ +#define RSTV0910_P1_SFERRCNT2 0xf5d9 +#define FSTV0910_P1_SFERRC_OLDVALUE 0xf5d90080 +#define FSTV0910_P1_SFEC_ERR_CNT2 0xf5d9007f + +/* P1_SFERRCNT1 */ +#define RSTV0910_P1_SFERRCNT1 0xf5da +#define FSTV0910_P1_SFEC_ERR_CNT1 0xf5da00ff + +/* P1_SFERRCNT0 */ +#define RSTV0910_P1_SFERRCNT0 0xf5db +#define FSTV0910_P1_SFEC_ERR_CNT0 0xf5db00ff + +/* RCCFG2 */ +#define RSTV0910_RCCFG2 0xf600 +#define FSTV0910_TSRCFIFO_DVBCI 0xf6000080 +#define FSTV0910_TSRCFIFO_SERIAL 0xf6000040 +#define FSTV0910_TSRCFIFO_DISABLE 0xf6000020 +#define FSTV0910_TSFIFO_2TORC 0xf6000010 +#define FSTV0910_TSRCFIFO_HSGNLOUT 0xf6000008 +#define FSTV0910_TSRCFIFO_ERRMODE 0xf6000006 + +/* RCCFG1 */ +#define RSTV0910_RCCFG1 0xf601 +#define FSTV0910_TSRCFIFO_MANSPEED 0xf60100c0 +#define FSTV0910_TSRCFIFO_PERMDATA 0xf6010020 +#define FSTV0910_TSRCFIFO_NONEWSGNL 0xf6010010 +#define FSTV0910_TSRCFIFO_INVDATA 0xf6010001 + +/* RCCFG0 */ +#define RSTV0910_RCCFG0 0xf602 +#define FSTV0910_TSRCFIFO_BCLKDEL1CK 0xf60200c0 +#define FSTV0910_TSRCFIFO_DUTY50 0xf6020010 +#define FSTV0910_TSRCFIFO_NSGNL2DATA 0xf6020008 +#define FSTV0910_TSRCFIFO_NPDSGNL 0xf6020004 + +/* RCINSDEL2 */ +#define RSTV0910_RCINSDEL2 0xf603 +#define FSTV0910_TSRCDEL_SYNCBYTE 0xf6030080 +#define FSTV0910_TSRCDEL_XXHEADER 0xf6030040 +#define FSTV0910_TSRCDEL_BBHEADER 0xf6030020 +#define FSTV0910_TSRCDEL_DATAFIELD 0xf6030010 +#define FSTV0910_TSRCINSDEL_ISCR 0xf6030008 +#define FSTV0910_TSRCINSDEL_NPD 0xf6030004 +#define FSTV0910_TSRCINSDEL_RSPARITY 0xf6030002 +#define FSTV0910_TSRCINSDEL_CRC8 0xf6030001 + +/* RCINSDEL1 */ +#define RSTV0910_RCINSDEL1 0xf604 +#define FSTV0910_TSRCINS_BBPADDING 0xf6040080 +#define FSTV0910_TSRCINS_BCHFEC 0xf6040040 +#define FSTV0910_TSRCINS_EMODCOD 0xf6040010 +#define FSTV0910_TSRCINS_TOKEN 0xf6040008 +#define FSTV0910_TSRCINS_XXXERR 0xf6040004 +#define FSTV0910_TSRCINS_MATYPE 0xf6040002 +#define FSTV0910_TSRCINS_UPL 0xf6040001 + +/* RCINSDEL0 */ +#define RSTV0910_RCINSDEL0 0xf605 +#define FSTV0910_TSRCINS_DFL 0xf6050080 +#define FSTV0910_TSRCINS_SYNCD 0xf6050040 +#define FSTV0910_TSRCINS_BLOCLEN 0xf6050020 +#define FSTV0910_TSRCINS_SIGPCOUNT 0xf6050010 +#define FSTV0910_TSRCINS_FIFO 0xf6050008 +#define FSTV0910_TSRCINS_REALPACK 0xf6050004 +#define FSTV0910_TSRCINS_TSCONFIG 0xf6050002 +#define FSTV0910_TSRCINS_LATENCY 0xf6050001 + +/* RCSTATUS */ +#define RSTV0910_RCSTATUS 0xf606 +#define FSTV0910_TSRCFIFO_LINEOK 0xf6060080 +#define FSTV0910_TSRCFIFO_ERROR 0xf6060040 +#define FSTV0910_TSRCREGUL_ERROR 0xf6060010 +#define FSTV0910_TSRCFIFO_DEMODSEL 0xf6060008 +#define FSTV0910_TSRCFIFOSPEED_STORE 0xf6060004 +#define FSTV0910_TSRCSPEED_IMPOSSIBLE 0xf6060001 + +/* RCSPEED */ +#define RSTV0910_RCSPEED 0xf607 +#define FSTV0910_TSRCFIFO_OUTSPEED 0xf60700ff + +/* TSGENERAL */ +#define RSTV0910_TSGENERAL 0xf630 +#define FSTV0910_TSFIFO_DISTS2PAR 0xf6300040 +#define FSTV0910_MUXSTREAM_OUTMODE 0xf6300008 +#define FSTV0910_TSFIFO_PERMPARAL 0xf6300006 + +/* P1_DISIRQCFG */ +#define RSTV0910_P1_DISIRQCFG 0xf700 +#define FSTV0910_P1_ENRXEND 0xf7000040 +#define FSTV0910_P1_ENRXFIFO8B 0xf7000020 +#define FSTV0910_P1_ENTRFINISH 0xf7000010 +#define FSTV0910_P1_ENTIMEOUT 0xf7000008 +#define FSTV0910_P1_ENTXEND 0xf7000004 +#define FSTV0910_P1_ENTXFIFO64B 0xf7000002 +#define FSTV0910_P1_ENGAPBURST 0xf7000001 + +/* P1_DISIRQSTAT */ +#define RSTV0910_P1_DISIRQSTAT 0xf701 +#define FSTV0910_P1_IRQRXEND 0xf7010040 +#define FSTV0910_P1_IRQRXFIFO8B 0xf7010020 +#define FSTV0910_P1_IRQTRFINISH 0xf7010010 +#define FSTV0910_P1_IRQTIMEOUT 0xf7010008 +#define FSTV0910_P1_IRQTXEND 0xf7010004 +#define FSTV0910_P1_IRQTXFIFO64B 0xf7010002 +#define FSTV0910_P1_IRQGAPBURST 0xf7010001 + +/* P1_DISTXCFG */ +#define RSTV0910_P1_DISTXCFG 0xf702 +#define FSTV0910_P1_DISTX_RESET 0xf7020080 +#define FSTV0910_P1_TIM_OFF 0xf7020040 +#define FSTV0910_P1_TIM_CMD 0xf7020030 +#define FSTV0910_P1_ENVELOP 0xf7020008 +#define FSTV0910_P1_DIS_PRECHARGE 0xf7020004 +#define FSTV0910_P1_DISEQC_MODE 0xf7020003 + +/* P1_DISTXSTATUS */ +#define RSTV0910_P1_DISTXSTATUS 0xf703 +#define FSTV0910_P1_TX_FIFO_FULL 0xf7030040 +#define FSTV0910_P1_TX_IDLE 0xf7030020 +#define FSTV0910_P1_GAP_BURST 0xf7030010 +#define FSTV0910_P1_TX_FIFO64B 0xf7030008 +#define FSTV0910_P1_TX_END 0xf7030004 +#define FSTV0910_P1_TR_TIMEOUT 0xf7030002 +#define FSTV0910_P1_TR_FINISH 0xf7030001 + +/* P1_DISTXBYTES */ +#define RSTV0910_P1_DISTXBYTES 0xf704 +#define FSTV0910_P1_TXFIFO_BYTES 0xf70400ff + +/* P1_DISTXFIFO */ +#define RSTV0910_P1_DISTXFIFO 0xf705 +#define FSTV0910_P1_DISEQC_TX_FIFO 0xf70500ff + +/* P1_DISTXF22 */ +#define RSTV0910_P1_DISTXF22 0xf706 +#define FSTV0910_P1_F22TX 0xf70600ff + +/* P1_DISTIMEOCFG */ +#define RSTV0910_P1_DISTIMEOCFG 0xf708 +#define FSTV0910_P1_RXCHOICE 0xf7080006 +#define FSTV0910_P1_TIMEOUT_OFF 0xf7080001 + +/* P1_DISTIMEOUT */ +#define RSTV0910_P1_DISTIMEOUT 0xf709 +#define FSTV0910_P1_TIMEOUT_COUNT 0xf70900ff + +/* P1_DISRXCFG */ +#define RSTV0910_P1_DISRXCFG 0xf70a +#define FSTV0910_P1_DISRX_RESET 0xf70a0080 +#define FSTV0910_P1_EXTENVELOP 0xf70a0040 +#define FSTV0910_P1_PINSELECT 0xf70a0038 +#define FSTV0910_P1_IGNORE_SHORT22K 0xf70a0004 +#define FSTV0910_P1_SIGNED_RXIN 0xf70a0002 +#define FSTV0910_P1_DISRX_ON 0xf70a0001 + +/* P1_DISRXSTAT1 */ +#define RSTV0910_P1_DISRXSTAT1 0xf70b +#define FSTV0910_P1_RXEND 0xf70b0080 +#define FSTV0910_P1_RXACTIVE 0xf70b0040 +#define FSTV0910_P1_RXDETECT 0xf70b0020 +#define FSTV0910_P1_CONTTONE 0xf70b0010 +#define FSTV0910_P1_8BFIFOREADY 0xf70b0008 +#define FSTV0910_P1_FIFOEMPTY 0xf70b0004 + +/* P1_DISRXSTAT0 */ +#define RSTV0910_P1_DISRXSTAT0 0xf70c +#define FSTV0910_P1_RXFAIL 0xf70c0080 +#define FSTV0910_P1_FIFOPFAIL 0xf70c0040 +#define FSTV0910_P1_RXNONBYTE 0xf70c0020 +#define FSTV0910_P1_FIFOOVF 0xf70c0010 +#define FSTV0910_P1_SHORT22K 0xf70c0008 +#define FSTV0910_P1_RXMSGLOST 0xf70c0004 + +/* P1_DISRXBYTES */ +#define RSTV0910_P1_DISRXBYTES 0xf70d +#define FSTV0910_P1_RXFIFO_BYTES 0xf70d001f + +/* P1_DISRXPARITY1 */ +#define RSTV0910_P1_DISRXPARITY1 0xf70e +#define FSTV0910_P1_DISRX_PARITY1 0xf70e00ff + +/* P1_DISRXPARITY0 */ +#define RSTV0910_P1_DISRXPARITY0 0xf70f +#define FSTV0910_P1_DISRX_PARITY0 0xf70f00ff + +/* P1_DISRXFIFO */ +#define RSTV0910_P1_DISRXFIFO 0xf710 +#define FSTV0910_P1_DISEQC_RX_FIFO 0xf71000ff + +/* P1_DISRXDC1 */ +#define RSTV0910_P1_DISRXDC1 0xf711 +#define FSTV0910_P1_DC_VALUE1 0xf7110103 + +/* P1_DISRXDC0 */ +#define RSTV0910_P1_DISRXDC0 0xf712 +#define FSTV0910_P1_DC_VALUE0 0xf71200ff + +/* P1_DISRXF221 */ +#define RSTV0910_P1_DISRXF221 0xf714 +#define FSTV0910_P1_F22RX1 0xf714000f + +/* P1_DISRXF220 */ +#define RSTV0910_P1_DISRXF220 0xf715 +#define FSTV0910_P1_F22RX0 0xf71500ff + +/* P1_DISRXF100 */ +#define RSTV0910_P1_DISRXF100 0xf716 +#define FSTV0910_P1_F100RX 0xf71600ff + +/* P1_DISRXSHORT22K */ +#define RSTV0910_P1_DISRXSHORT22K 0xf71c +#define FSTV0910_P1_SHORT22K_LENGTH 0xf71c001f + +/* P1_ACRPRESC */ +#define RSTV0910_P1_ACRPRESC 0xf71e +#define FSTV0910_P1_ACR_PRESC 0xf71e0007 + +/* P1_ACRDIV */ +#define RSTV0910_P1_ACRDIV 0xf71f +#define FSTV0910_P1_ACR_DIV 0xf71f00ff + +/* P2_DISIRQCFG */ +#define RSTV0910_P2_DISIRQCFG 0xf740 +#define FSTV0910_P2_ENRXEND 0xf7400040 +#define FSTV0910_P2_ENRXFIFO8B 0xf7400020 +#define FSTV0910_P2_ENTRFINISH 0xf7400010 +#define FSTV0910_P2_ENTIMEOUT 0xf7400008 +#define FSTV0910_P2_ENTXEND 0xf7400004 +#define FSTV0910_P2_ENTXFIFO64B 0xf7400002 +#define FSTV0910_P2_ENGAPBURST 0xf7400001 + +/* P2_DISIRQSTAT */ +#define RSTV0910_P2_DISIRQSTAT 0xf741 +#define FSTV0910_P2_IRQRXEND 0xf7410040 +#define FSTV0910_P2_IRQRXFIFO8B 0xf7410020 +#define FSTV0910_P2_IRQTRFINISH 0xf7410010 +#define FSTV0910_P2_IRQTIMEOUT 0xf7410008 +#define FSTV0910_P2_IRQTXEND 0xf7410004 +#define FSTV0910_P2_IRQTXFIFO64B 0xf7410002 +#define FSTV0910_P2_IRQGAPBURST 0xf7410001 + +/* P2_DISTXCFG */ +#define RSTV0910_P2_DISTXCFG 0xf742 +#define FSTV0910_P2_DISTX_RESET 0xf7420080 +#define FSTV0910_P2_TIM_OFF 0xf7420040 +#define FSTV0910_P2_TIM_CMD 0xf7420030 +#define FSTV0910_P2_ENVELOP 0xf7420008 +#define FSTV0910_P2_DIS_PRECHARGE 0xf7420004 +#define FSTV0910_P2_DISEQC_MODE 0xf7420003 + +/* P2_DISTXSTATUS */ +#define RSTV0910_P2_DISTXSTATUS 0xf743 +#define FSTV0910_P2_TX_FIFO_FULL 0xf7430040 +#define FSTV0910_P2_TX_IDLE 0xf7430020 +#define FSTV0910_P2_GAP_BURST 0xf7430010 +#define FSTV0910_P2_TX_FIFO64B 0xf7430008 +#define FSTV0910_P2_TX_END 0xf7430004 +#define FSTV0910_P2_TR_TIMEOUT 0xf7430002 +#define FSTV0910_P2_TR_FINISH 0xf7430001 + +/* P2_DISTXBYTES */ +#define RSTV0910_P2_DISTXBYTES 0xf744 +#define FSTV0910_P2_TXFIFO_BYTES 0xf74400ff + +/* P2_DISTXFIFO */ +#define RSTV0910_P2_DISTXFIFO 0xf745 +#define FSTV0910_P2_DISEQC_TX_FIFO 0xf74500ff + +/* P2_DISTXF22 */ +#define RSTV0910_P2_DISTXF22 0xf746 +#define FSTV0910_P2_F22TX 0xf74600ff + +/* P2_DISTIMEOCFG */ +#define RSTV0910_P2_DISTIMEOCFG 0xf748 +#define FSTV0910_P2_RXCHOICE 0xf7480006 +#define FSTV0910_P2_TIMEOUT_OFF 0xf7480001 + +/* P2_DISTIMEOUT */ +#define RSTV0910_P2_DISTIMEOUT 0xf749 +#define FSTV0910_P2_TIMEOUT_COUNT 0xf74900ff + +/* P2_DISRXCFG */ +#define RSTV0910_P2_DISRXCFG 0xf74a +#define FSTV0910_P2_DISRX_RESET 0xf74a0080 +#define FSTV0910_P2_EXTENVELOP 0xf74a0040 +#define FSTV0910_P2_PINSELECT 0xf74a0038 +#define FSTV0910_P2_IGNORE_SHORT22K 0xf74a0004 +#define FSTV0910_P2_SIGNED_RXIN 0xf74a0002 +#define FSTV0910_P2_DISRX_ON 0xf74a0001 + +/* P2_DISRXSTAT1 */ +#define RSTV0910_P2_DISRXSTAT1 0xf74b +#define FSTV0910_P2_RXEND 0xf74b0080 +#define FSTV0910_P2_RXACTIVE 0xf74b0040 +#define FSTV0910_P2_RXDETECT 0xf74b0020 +#define FSTV0910_P2_CONTTONE 0xf74b0010 +#define FSTV0910_P2_8BFIFOREADY 0xf74b0008 +#define FSTV0910_P2_FIFOEMPTY 0xf74b0004 + +/* P2_DISRXSTAT0 */ +#define RSTV0910_P2_DISRXSTAT0 0xf74c +#define FSTV0910_P2_RXFAIL 0xf74c0080 +#define FSTV0910_P2_FIFOPFAIL 0xf74c0040 +#define FSTV0910_P2_RXNONBYTE 0xf74c0020 +#define FSTV0910_P2_FIFOOVF 0xf74c0010 +#define FSTV0910_P2_SHORT22K 0xf74c0008 +#define FSTV0910_P2_RXMSGLOST 0xf74c0004 + +/* P2_DISRXBYTES */ +#define RSTV0910_P2_DISRXBYTES 0xf74d +#define FSTV0910_P2_RXFIFO_BYTES 0xf74d001f + +/* P2_DISRXPARITY1 */ +#define RSTV0910_P2_DISRXPARITY1 0xf74e +#define FSTV0910_P2_DISRX_PARITY1 0xf74e00ff + +/* P2_DISRXPARITY0 */ +#define RSTV0910_P2_DISRXPARITY0 0xf74f +#define FSTV0910_P2_DISRX_PARITY0 0xf74f00ff + +/* P2_DISRXFIFO */ +#define RSTV0910_P2_DISRXFIFO 0xf750 +#define FSTV0910_P2_DISEQC_RX_FIFO 0xf75000ff + +/* P2_DISRXDC1 */ +#define RSTV0910_P2_DISRXDC1 0xf751 +#define FSTV0910_P2_DC_VALUE1 0xf7510103 + +/* P2_DISRXDC0 */ +#define RSTV0910_P2_DISRXDC0 0xf752 +#define FSTV0910_P2_DC_VALUE0 0xf75200ff + +/* P2_DISRXF221 */ +#define RSTV0910_P2_DISRXF221 0xf754 +#define FSTV0910_P2_F22RX1 0xf754000f + +/* P2_DISRXF220 */ +#define RSTV0910_P2_DISRXF220 0xf755 +#define FSTV0910_P2_F22RX0 0xf75500ff + +/* P2_DISRXF100 */ +#define RSTV0910_P2_DISRXF100 0xf756 +#define FSTV0910_P2_F100RX 0xf75600ff + +/* P2_DISRXSHORT22K */ +#define RSTV0910_P2_DISRXSHORT22K 0xf75c +#define FSTV0910_P2_SHORT22K_LENGTH 0xf75c001f + +/* P2_ACRPRESC */ +#define RSTV0910_P2_ACRPRESC 0xf75e +#define FSTV0910_P2_ACR_PRESC 0xf75e0007 + +/* P2_ACRDIV */ +#define RSTV0910_P2_ACRDIV 0xf75f +#define FSTV0910_P2_ACR_DIV 0xf75f00ff + +/* P1_NBITER_NF1 */ +#define RSTV0910_P1_NBITER_NF1 0xfa00 +#define FSTV0910_P1_NBITER_NF_QPSK_1_4 0xfa0000ff + +/* P1_NBITER_NF2 */ +#define RSTV0910_P1_NBITER_NF2 0xfa01 +#define FSTV0910_P1_NBITER_NF_QPSK_1_3 0xfa0100ff + +/* P1_NBITER_NF3 */ +#define RSTV0910_P1_NBITER_NF3 0xfa02 +#define FSTV0910_P1_NBITER_NF_QPSK_2_5 0xfa0200ff + +/* P1_NBITER_NF4 */ +#define RSTV0910_P1_NBITER_NF4 0xfa03 +#define FSTV0910_P1_NBITER_NF_QPSK_1_2 0xfa0300ff + +/* P1_NBITER_NF5 */ +#define RSTV0910_P1_NBITER_NF5 0xfa04 +#define FSTV0910_P1_NBITER_NF_QPSK_3_5 0xfa0400ff + +/* P1_NBITER_NF6 */ +#define RSTV0910_P1_NBITER_NF6 0xfa05 +#define FSTV0910_P1_NBITER_NF_QPSK_2_3 0xfa0500ff + +/* P1_NBITER_NF7 */ +#define RSTV0910_P1_NBITER_NF7 0xfa06 +#define FSTV0910_P1_NBITER_NF_QPSK_3_4 0xfa0600ff + +/* P1_NBITER_NF8 */ +#define RSTV0910_P1_NBITER_NF8 0xfa07 +#define FSTV0910_P1_NBITER_NF_QPSK_4_5 0xfa0700ff + +/* P1_NBITER_NF9 */ +#define RSTV0910_P1_NBITER_NF9 0xfa08 +#define FSTV0910_P1_NBITER_NF_QPSK_5_6 0xfa0800ff + +/* P1_NBITER_NF10 */ +#define RSTV0910_P1_NBITER_NF10 0xfa09 +#define FSTV0910_P1_NBITER_NF_QPSK_8_9 0xfa0900ff + +/* P1_NBITER_NF11 */ +#define RSTV0910_P1_NBITER_NF11 0xfa0a +#define FSTV0910_P1_NBITER_NF_QPSK_9_10 0xfa0a00ff + +/* P1_NBITER_NF12 */ +#define RSTV0910_P1_NBITER_NF12 0xfa0b +#define FSTV0910_P1_NBITER_NF_8PSK_3_5 0xfa0b00ff + +/* P1_NBITER_NF13 */ +#define RSTV0910_P1_NBITER_NF13 0xfa0c +#define FSTV0910_P1_NBITER_NF_8PSK_2_3 0xfa0c00ff + +/* P1_NBITER_NF14 */ +#define RSTV0910_P1_NBITER_NF14 0xfa0d +#define FSTV0910_P1_NBITER_NF_8PSK_3_4 0xfa0d00ff + +/* P1_NBITER_NF15 */ +#define RSTV0910_P1_NBITER_NF15 0xfa0e +#define FSTV0910_P1_NBITER_NF_8PSK_5_6 0xfa0e00ff + +/* P1_NBITER_NF16 */ +#define RSTV0910_P1_NBITER_NF16 0xfa0f +#define FSTV0910_P1_NBITER_NF_8PSK_8_9 0xfa0f00ff + +/* P1_NBITER_NF17 */ +#define RSTV0910_P1_NBITER_NF17 0xfa10 +#define FSTV0910_P1_NBITER_NF_8PSK_9_10 0xfa1000ff + +/* P1_NBITER_NF18 */ +#define RSTV0910_P1_NBITER_NF18 0xfa11 +#define FSTV0910_P1_NBITER_NF_16APSK_2_3 0xfa1100ff + +/* P1_NBITER_NF19 */ +#define RSTV0910_P1_NBITER_NF19 0xfa12 +#define FSTV0910_P1_NBITER_NF_16APSK_3_4 0xfa1200ff + +/* P1_NBITER_NF20 */ +#define RSTV0910_P1_NBITER_NF20 0xfa13 +#define FSTV0910_P1_NBITER_NF_16APSK_4_5 0xfa1300ff + +/* P1_NBITER_NF21 */ +#define RSTV0910_P1_NBITER_NF21 0xfa14 +#define FSTV0910_P1_NBITER_NF_16APSK_5_6 0xfa1400ff + +/* P1_NBITER_NF22 */ +#define RSTV0910_P1_NBITER_NF22 0xfa15 +#define FSTV0910_P1_NBITER_NF_16APSK_8_9 0xfa1500ff + +/* P1_NBITER_NF23 */ +#define RSTV0910_P1_NBITER_NF23 0xfa16 +#define FSTV0910_P1_NBITER_NF_16APSK_9_10 0xfa1600ff + +/* P1_NBITER_NF24 */ +#define RSTV0910_P1_NBITER_NF24 0xfa17 +#define FSTV0910_P1_NBITER_NF_32APSK_3_4 0xfa1700ff + +/* P1_NBITER_NF25 */ +#define RSTV0910_P1_NBITER_NF25 0xfa18 +#define FSTV0910_P1_NBITER_NF_32APSK_4_5 0xfa1800ff + +/* P1_NBITER_NF26 */ +#define RSTV0910_P1_NBITER_NF26 0xfa19 +#define FSTV0910_P1_NBITER_NF_32APSK_5_6 0xfa1900ff + +/* P1_NBITER_NF27 */ +#define RSTV0910_P1_NBITER_NF27 0xfa1a +#define FSTV0910_P1_NBITER_NF_32APSK_8_9 0xfa1a00ff + +/* P1_NBITER_NF28 */ +#define RSTV0910_P1_NBITER_NF28 0xfa1b +#define FSTV0910_P1_NBITER_NF_32APSK_9_10 0xfa1b00ff + +/* P1_NBITER_SF1 */ +#define RSTV0910_P1_NBITER_SF1 0xfa1c +#define FSTV0910_P1_NBITER_SF_QPSK_1_4 0xfa1c00ff + +/* P1_NBITER_SF2 */ +#define RSTV0910_P1_NBITER_SF2 0xfa1d +#define FSTV0910_P1_NBITER_SF_QPSK_1_3 0xfa1d00ff + +/* P1_NBITER_SF3 */ +#define RSTV0910_P1_NBITER_SF3 0xfa1e +#define FSTV0910_P1_NBITER_SF_QPSK_2_5 0xfa1e00ff + +/* P1_NBITER_SF4 */ +#define RSTV0910_P1_NBITER_SF4 0xfa1f +#define FSTV0910_P1_NBITER_SF_QPSK_1_2 0xfa1f00ff + +/* P1_NBITER_SF5 */ +#define RSTV0910_P1_NBITER_SF5 0xfa20 +#define FSTV0910_P1_NBITER_SF_QPSK_3_5 0xfa2000ff + +/* P1_NBITER_SF6 */ +#define RSTV0910_P1_NBITER_SF6 0xfa21 +#define FSTV0910_P1_NBITER_SF_QPSK_2_3 0xfa2100ff + +/* P1_NBITER_SF7 */ +#define RSTV0910_P1_NBITER_SF7 0xfa22 +#define FSTV0910_P1_NBITER_SF_QPSK_3_4 0xfa2200ff + +/* P1_NBITER_SF8 */ +#define RSTV0910_P1_NBITER_SF8 0xfa23 +#define FSTV0910_P1_NBITER_SF_QPSK_4_5 0xfa2300ff + +/* P1_NBITER_SF9 */ +#define RSTV0910_P1_NBITER_SF9 0xfa24 +#define FSTV0910_P1_NBITER_SF_QPSK_5_6 0xfa2400ff + +/* P1_NBITER_SF10 */ +#define RSTV0910_P1_NBITER_SF10 0xfa25 +#define FSTV0910_P1_NBITER_SF_QPSK_8_9 0xfa2500ff + +/* P1_NBITER_SF12 */ +#define RSTV0910_P1_NBITER_SF12 0xfa26 +#define FSTV0910_P1_NBITER_SF_8PSK_3_5 0xfa2600ff + +/* P1_NBITER_SF13 */ +#define RSTV0910_P1_NBITER_SF13 0xfa27 +#define FSTV0910_P1_NBITER_SF_8PSK_2_3 0xfa2700ff + +/* P1_NBITER_SF14 */ +#define RSTV0910_P1_NBITER_SF14 0xfa28 +#define FSTV0910_P1_NBITER_SF_8PSK_3_4 0xfa2800ff + +/* P1_NBITER_SF15 */ +#define RSTV0910_P1_NBITER_SF15 0xfa29 +#define FSTV0910_P1_NBITER_SF_8PSK_5_6 0xfa2900ff + +/* P1_NBITER_SF16 */ +#define RSTV0910_P1_NBITER_SF16 0xfa2a +#define FSTV0910_P1_NBITER_SF_8PSK_8_9 0xfa2a00ff + +/* P1_NBITER_SF18 */ +#define RSTV0910_P1_NBITER_SF18 0xfa2b +#define FSTV0910_P1_NBITER_SF_16APSK_2_3 0xfa2b00ff + +/* P1_NBITER_SF19 */ +#define RSTV0910_P1_NBITER_SF19 0xfa2c +#define FSTV0910_P1_NBITER_SF_16APSK_3_4 0xfa2c00ff + +/* P1_NBITER_SF20 */ +#define RSTV0910_P1_NBITER_SF20 0xfa2d +#define FSTV0910_P1_NBITER_SF_16APSK_4_5 0xfa2d00ff + +/* P1_NBITER_SF21 */ +#define RSTV0910_P1_NBITER_SF21 0xfa2e +#define FSTV0910_P1_NBITER_SF_16APSK_5_6 0xfa2e00ff + +/* P1_NBITER_SF22 */ +#define RSTV0910_P1_NBITER_SF22 0xfa2f +#define FSTV0910_P1_NBITER_SF_16APSK_8_9 0xfa2f00ff + +/* P1_NBITER_SF24 */ +#define RSTV0910_P1_NBITER_SF24 0xfa30 +#define FSTV0910_P1_NBITER_SF_32APSK_3_4 0xfa3000ff + +/* P1_NBITER_SF25 */ +#define RSTV0910_P1_NBITER_SF25 0xfa31 +#define FSTV0910_P1_NBITER_SF_32APSK_4_5 0xfa3100ff + +/* P1_NBITER_SF26 */ +#define RSTV0910_P1_NBITER_SF26 0xfa32 +#define FSTV0910_P1_NBITER_SF_32APSK_5_6 0xfa3200ff + +/* P1_NBITER_SF27 */ +#define RSTV0910_P1_NBITER_SF27 0xfa33 +#define FSTV0910_P1_NBITER_SF_32APSK_8_9 0xfa3300ff + +/* SELSATUR6 */ +#define RSTV0910_SELSATUR6 0xfa34 +#define FSTV0910_SSAT_SF27 0xfa340008 +#define FSTV0910_SSAT_SF26 0xfa340004 +#define FSTV0910_SSAT_SF25 0xfa340002 +#define FSTV0910_SSAT_SF24 0xfa340001 + +/* SELSATUR5 */ +#define RSTV0910_SELSATUR5 0xfa35 +#define FSTV0910_SSAT_SF22 0xfa350080 +#define FSTV0910_SSAT_SF21 0xfa350040 +#define FSTV0910_SSAT_SF20 0xfa350020 +#define FSTV0910_SSAT_SF19 0xfa350010 +#define FSTV0910_SSAT_SF18 0xfa350008 +#define FSTV0910_SSAT_SF16 0xfa350004 +#define FSTV0910_SSAT_SF15 0xfa350002 +#define FSTV0910_SSAT_SF14 0xfa350001 + +/* SELSATUR4 */ +#define RSTV0910_SELSATUR4 0xfa36 +#define FSTV0910_SSAT_SF13 0xfa360080 +#define FSTV0910_SSAT_SF12 0xfa360040 +#define FSTV0910_SSAT_SF10 0xfa360020 +#define FSTV0910_SSAT_SF9 0xfa360010 +#define FSTV0910_SSAT_SF8 0xfa360008 +#define FSTV0910_SSAT_SF7 0xfa360004 +#define FSTV0910_SSAT_SF6 0xfa360002 +#define FSTV0910_SSAT_SF5 0xfa360001 + +/* SELSATUR3 */ +#define RSTV0910_SELSATUR3 0xfa37 +#define FSTV0910_SSAT_SF4 0xfa370080 +#define FSTV0910_SSAT_SF3 0xfa370040 +#define FSTV0910_SSAT_SF2 0xfa370020 +#define FSTV0910_SSAT_SF1 0xfa370010 +#define FSTV0910_SSAT_NF28 0xfa370008 +#define FSTV0910_SSAT_NF27 0xfa370004 +#define FSTV0910_SSAT_NF26 0xfa370002 +#define FSTV0910_SSAT_NF25 0xfa370001 + +/* SELSATUR2 */ +#define RSTV0910_SELSATUR2 0xfa38 +#define FSTV0910_SSAT_NF24 0xfa380080 +#define FSTV0910_SSAT_NF23 0xfa380040 +#define FSTV0910_SSAT_NF22 0xfa380020 +#define FSTV0910_SSAT_NF21 0xfa380010 +#define FSTV0910_SSAT_NF20 0xfa380008 +#define FSTV0910_SSAT_NF19 0xfa380004 +#define FSTV0910_SSAT_NF18 0xfa380002 +#define FSTV0910_SSAT_NF17 0xfa380001 + +/* SELSATUR1 */ +#define RSTV0910_SELSATUR1 0xfa39 +#define FSTV0910_SSAT_NF16 0xfa390080 +#define FSTV0910_SSAT_NF15 0xfa390040 +#define FSTV0910_SSAT_NF14 0xfa390020 +#define FSTV0910_SSAT_NF13 0xfa390010 +#define FSTV0910_SSAT_NF12 0xfa390008 +#define FSTV0910_SSAT_NF11 0xfa390004 +#define FSTV0910_SSAT_NF10 0xfa390002 +#define FSTV0910_SSAT_NF9 0xfa390001 + +/* SELSATUR0 */ +#define RSTV0910_SELSATUR0 0xfa3a +#define FSTV0910_SSAT_NF8 0xfa3a0080 +#define FSTV0910_SSAT_NF7 0xfa3a0040 +#define FSTV0910_SSAT_NF6 0xfa3a0020 +#define FSTV0910_SSAT_NF5 0xfa3a0010 +#define FSTV0910_SSAT_NF4 0xfa3a0008 +#define FSTV0910_SSAT_NF3 0xfa3a0004 +#define FSTV0910_SSAT_NF2 0xfa3a0002 +#define FSTV0910_SSAT_NF1 0xfa3a0001 + +/* GAINLLR_NF1 */ +#define RSTV0910_GAINLLR_NF1 0xfa40 +#define FSTV0910_GAINLLR_NF_QPSK_1_4 0xfa40007f + +/* GAINLLR_NF2 */ +#define RSTV0910_GAINLLR_NF2 0xfa41 +#define FSTV0910_GAINLLR_NF_QPSK_1_3 0xfa41007f + +/* GAINLLR_NF3 */ +#define RSTV0910_GAINLLR_NF3 0xfa42 +#define FSTV0910_GAINLLR_NF_QPSK_2_5 0xfa42007f + +/* GAINLLR_NF4 */ +#define RSTV0910_GAINLLR_NF4 0xfa43 +#define FSTV0910_GAINLLR_NF_QPSK_1_2 0xfa43007f + +/* GAINLLR_NF5 */ +#define RSTV0910_GAINLLR_NF5 0xfa44 +#define FSTV0910_GAINLLR_NF_QPSK_3_5 0xfa44007f + +/* GAINLLR_NF6 */ +#define RSTV0910_GAINLLR_NF6 0xfa45 +#define FSTV0910_GAINLLR_NF_QPSK_2_3 0xfa45007f + +/* GAINLLR_NF7 */ +#define RSTV0910_GAINLLR_NF7 0xfa46 +#define FSTV0910_GAINLLR_NF_QPSK_3_4 0xfa46007f + +/* GAINLLR_NF8 */ +#define RSTV0910_GAINLLR_NF8 0xfa47 +#define FSTV0910_GAINLLR_NF_QPSK_4_5 0xfa47007f + +/* GAINLLR_NF9 */ +#define RSTV0910_GAINLLR_NF9 0xfa48 +#define FSTV0910_GAINLLR_NF_QPSK_5_6 0xfa48007f + +/* GAINLLR_NF10 */ +#define RSTV0910_GAINLLR_NF10 0xfa49 +#define FSTV0910_GAINLLR_NF_QPSK_8_9 0xfa49007f + +/* GAINLLR_NF11 */ +#define RSTV0910_GAINLLR_NF11 0xfa4a +#define FSTV0910_GAINLLR_NF_QPSK_9_10 0xfa4a007f + +/* GAINLLR_NF12 */ +#define RSTV0910_GAINLLR_NF12 0xfa4b +#define FSTV0910_GAINLLR_NF_8PSK_3_5 0xfa4b007f + +/* GAINLLR_NF13 */ +#define RSTV0910_GAINLLR_NF13 0xfa4c +#define FSTV0910_GAINLLR_NF_8PSK_2_3 0xfa4c007f + +/* GAINLLR_NF14 */ +#define RSTV0910_GAINLLR_NF14 0xfa4d +#define FSTV0910_GAINLLR_NF_8PSK_3_4 0xfa4d007f + +/* GAINLLR_NF15 */ +#define RSTV0910_GAINLLR_NF15 0xfa4e +#define FSTV0910_GAINLLR_NF_8PSK_5_6 0xfa4e007f + +/* GAINLLR_NF16 */ +#define RSTV0910_GAINLLR_NF16 0xfa4f +#define FSTV0910_GAINLLR_NF_8PSK_8_9 0xfa4f007f + +/* GAINLLR_NF17 */ +#define RSTV0910_GAINLLR_NF17 0xfa50 +#define FSTV0910_GAINLLR_NF_8PSK_9_10 0xfa50007f + +/* GAINLLR_NF18 */ +#define RSTV0910_GAINLLR_NF18 0xfa51 +#define FSTV0910_GAINLLR_NF_16APSK_2_3 0xfa51007f + +/* GAINLLR_NF19 */ +#define RSTV0910_GAINLLR_NF19 0xfa52 +#define FSTV0910_GAINLLR_NF_16APSK_3_4 0xfa52007f + +/* GAINLLR_NF20 */ +#define RSTV0910_GAINLLR_NF20 0xfa53 +#define FSTV0910_GAINLLR_NF_16APSK_4_5 0xfa53007f + +/* GAINLLR_NF21 */ +#define RSTV0910_GAINLLR_NF21 0xfa54 +#define FSTV0910_GAINLLR_NF_16APSK_5_6 0xfa54007f + +/* GAINLLR_NF22 */ +#define RSTV0910_GAINLLR_NF22 0xfa55 +#define FSTV0910_GAINLLR_NF_16APSK_8_9 0xfa55007f + +/* GAINLLR_NF23 */ +#define RSTV0910_GAINLLR_NF23 0xfa56 +#define FSTV0910_GAINLLR_NF_16APSK_9_10 0xfa56007f + +/* GAINLLR_NF24 */ +#define RSTV0910_GAINLLR_NF24 0xfa57 +#define FSTV0910_GAINLLR_NF_32APSK_3_4 0xfa57007f + +/* GAINLLR_NF25 */ +#define RSTV0910_GAINLLR_NF25 0xfa58 +#define FSTV0910_GAINLLR_NF_32APSK_4_5 0xfa58007f + +/* GAINLLR_NF26 */ +#define RSTV0910_GAINLLR_NF26 0xfa59 +#define FSTV0910_GAINLLR_NF_32APSK_5_6 0xfa59007f + +/* GAINLLR_NF27 */ +#define RSTV0910_GAINLLR_NF27 0xfa5a +#define FSTV0910_GAINLLR_NF_32APSK_8_9 0xfa5a007f + +/* GAINLLR_NF28 */ +#define RSTV0910_GAINLLR_NF28 0xfa5b +#define FSTV0910_GAINLLR_NF_32APSK_9_10 0xfa5b007f + +/* GAINLLR_SF1 */ +#define RSTV0910_GAINLLR_SF1 0xfa5c +#define FSTV0910_GAINLLR_SF_QPSK_1_4 0xfa5c007f + +/* GAINLLR_SF2 */ +#define RSTV0910_GAINLLR_SF2 0xfa5d +#define FSTV0910_GAINLLR_SF_QPSK_1_3 0xfa5d007f + +/* GAINLLR_SF3 */ +#define RSTV0910_GAINLLR_SF3 0xfa5e +#define FSTV0910_GAINLLR_SF_QPSK_2_5 0xfa5e007f + +/* GAINLLR_SF4 */ +#define RSTV0910_GAINLLR_SF4 0xfa5f +#define FSTV0910_GAINLLR_SF_QPSK_1_2 0xfa5f007f + +/* GAINLLR_SF5 */ +#define RSTV0910_GAINLLR_SF5 0xfa60 +#define FSTV0910_GAINLLR_SF_QPSK_3_5 0xfa60007f + +/* GAINLLR_SF6 */ +#define RSTV0910_GAINLLR_SF6 0xfa61 +#define FSTV0910_GAINLLR_SF_QPSK_2_3 0xfa61007f + +/* GAINLLR_SF7 */ +#define RSTV0910_GAINLLR_SF7 0xfa62 +#define FSTV0910_GAINLLR_SF_QPSK_3_4 0xfa62007f + +/* GAINLLR_SF8 */ +#define RSTV0910_GAINLLR_SF8 0xfa63 +#define FSTV0910_GAINLLR_SF_QPSK_4_5 0xfa63007f + +/* GAINLLR_SF9 */ +#define RSTV0910_GAINLLR_SF9 0xfa64 +#define FSTV0910_GAINLLR_SF_QPSK_5_6 0xfa64007f + +/* GAINLLR_SF10 */ +#define RSTV0910_GAINLLR_SF10 0xfa65 +#define FSTV0910_GAINLLR_SF_QPSK_8_9 0xfa65007f + +/* GAINLLR_SF12 */ +#define RSTV0910_GAINLLR_SF12 0xfa66 +#define FSTV0910_GAINLLR_SF_8PSK_3_5 0xfa66007f + +/* GAINLLR_SF13 */ +#define RSTV0910_GAINLLR_SF13 0xfa67 +#define FSTV0910_GAINLLR_SF_8PSK_2_3 0xfa67007f + +/* GAINLLR_SF14 */ +#define RSTV0910_GAINLLR_SF14 0xfa68 +#define FSTV0910_GAINLLR_SF_8PSK_3_4 0xfa68007f + +/* GAINLLR_SF15 */ +#define RSTV0910_GAINLLR_SF15 0xfa69 +#define FSTV0910_GAINLLR_SF_8PSK_5_6 0xfa69007f + +/* GAINLLR_SF16 */ +#define RSTV0910_GAINLLR_SF16 0xfa6a +#define FSTV0910_GAINLLR_SF_8PSK_8_9 0xfa6a007f + +/* GAINLLR_SF18 */ +#define RSTV0910_GAINLLR_SF18 0xfa6b +#define FSTV0910_GAINLLR_SF_16APSK_2_3 0xfa6b007f + +/* GAINLLR_SF19 */ +#define RSTV0910_GAINLLR_SF19 0xfa6c +#define FSTV0910_GAINLLR_SF_16APSK_3_4 0xfa6c007f + +/* GAINLLR_SF20 */ +#define RSTV0910_GAINLLR_SF20 0xfa6d +#define FSTV0910_GAINLLR_SF_16APSK_4_5 0xfa6d007f + +/* GAINLLR_SF21 */ +#define RSTV0910_GAINLLR_SF21 0xfa6e +#define FSTV0910_GAINLLR_SF_16APSK_5_6 0xfa6e007f + +/* GAINLLR_SF22 */ +#define RSTV0910_GAINLLR_SF22 0xfa6f +#define FSTV0910_GAINLLR_SF_16APSK_8_9 0xfa6f007f + +/* GAINLLR_SF24 */ +#define RSTV0910_GAINLLR_SF24 0xfa70 +#define FSTV0910_GAINLLR_SF_32APSK_3_4 0xfa70007f + +/* GAINLLR_SF25 */ +#define RSTV0910_GAINLLR_SF25 0xfa71 +#define FSTV0910_GAINLLR_SF_32APSK_4_5 0xfa71007f + +/* GAINLLR_SF26 */ +#define RSTV0910_GAINLLR_SF26 0xfa72 +#define FSTV0910_GAINLLR_SF_32APSK_5_6 0xfa72007f + +/* GAINLLR_SF27 */ +#define RSTV0910_GAINLLR_SF27 0xfa73 +#define FSTV0910_GAINLLR_SF_32APSK_8_9 0xfa73007f + +/* CFGEXT */ +#define RSTV0910_CFGEXT 0xfa80 +#define FSTV0910_BYPBCH 0xfa800040 +#define FSTV0910_BYPLDPC 0xfa800020 +#define FSTV0910_SHORTMULT 0xfa800004 + +/* GENCFG */ +#define RSTV0910_GENCFG 0xfa86 +#define FSTV0910_BROADCAST 0xfa860010 +#define FSTV0910_CROSSINPUT 0xfa860002 +#define FSTV0910_DDEMOD 0xfa860001 + +/* LDPCERR1 */ +#define RSTV0910_LDPCERR1 0xfa96 +#define FSTV0910_LDPC_ERRORS1 0xfa9600ff + +/* LDPCERR0 */ +#define RSTV0910_LDPCERR0 0xfa97 +#define FSTV0910_LDPC_ERRORS0 0xfa9700ff + +/* BCHERR */ +#define RSTV0910_BCHERR 0xfa98 +#define FSTV0910_ERRORFLAG 0xfa980010 +#define FSTV0910_BCH_ERRORS_COUNTER 0xfa98000f + +/* P1_MAXEXTRAITER */ +#define RSTV0910_P1_MAXEXTRAITER 0xfab1 +#define FSTV0910_P1_MAX_EXTRA_ITER 0xfab100ff + +/* P2_MAXEXTRAITER */ +#define RSTV0910_P2_MAXEXTRAITER 0xfab6 +#define FSTV0910_P2_MAX_EXTRA_ITER 0xfab600ff + +/* P1_STATUSITER */ +#define RSTV0910_P1_STATUSITER 0xfabc +#define FSTV0910_P1_STATUS_ITER 0xfabc00ff + +/* P1_STATUSMAXITER */ +#define RSTV0910_P1_STATUSMAXITER 0xfabd +#define FSTV0910_P1_STATUS_MAX_ITER 0xfabd00ff + +/* P2_STATUSITER */ +#define RSTV0910_P2_STATUSITER 0xfabe +#define FSTV0910_P2_STATUS_ITER 0xfabe00ff + +/* P2_STATUSMAXITER */ +#define RSTV0910_P2_STATUSMAXITER 0xfabf +#define FSTV0910_P2_STATUS_MAX_ITER 0xfabf00ff + +/* P2_NBITER_NF1 */ +#define RSTV0910_P2_NBITER_NF1 0xfac0 +#define FSTV0910_P2_NBITER_NF_QPSK_1_4 0xfac000ff + +/* P2_NBITER_NF2 */ +#define RSTV0910_P2_NBITER_NF2 0xfac1 +#define FSTV0910_P2_NBITER_NF_QPSK_1_3 0xfac100ff + +/* P2_NBITER_NF3 */ +#define RSTV0910_P2_NBITER_NF3 0xfac2 +#define FSTV0910_P2_NBITER_NF_QPSK_2_5 0xfac200ff + +/* P2_NBITER_NF4 */ +#define RSTV0910_P2_NBITER_NF4 0xfac3 +#define FSTV0910_P2_NBITER_NF_QPSK_1_2 0xfac300ff + +/* P2_NBITER_NF5 */ +#define RSTV0910_P2_NBITER_NF5 0xfac4 +#define FSTV0910_P2_NBITER_NF_QPSK_3_5 0xfac400ff + +/* P2_NBITER_NF6 */ +#define RSTV0910_P2_NBITER_NF6 0xfac5 +#define FSTV0910_P2_NBITER_NF_QPSK_2_3 0xfac500ff + +/* P2_NBITER_NF7 */ +#define RSTV0910_P2_NBITER_NF7 0xfac6 +#define FSTV0910_P2_NBITER_NF_QPSK_3_4 0xfac600ff + +/* P2_NBITER_NF8 */ +#define RSTV0910_P2_NBITER_NF8 0xfac7 +#define FSTV0910_P2_NBITER_NF_QPSK_4_5 0xfac700ff + +/* P2_NBITER_NF9 */ +#define RSTV0910_P2_NBITER_NF9 0xfac8 +#define FSTV0910_P2_NBITER_NF_QPSK_5_6 0xfac800ff + +/* P2_NBITER_NF10 */ +#define RSTV0910_P2_NBITER_NF10 0xfac9 +#define FSTV0910_P2_NBITER_NF_QPSK_8_9 0xfac900ff + +/* P2_NBITER_NF11 */ +#define RSTV0910_P2_NBITER_NF11 0xfaca +#define FSTV0910_P2_NBITER_NF_QPSK_9_10 0xfaca00ff + +/* P2_NBITER_NF12 */ +#define RSTV0910_P2_NBITER_NF12 0xfacb +#define FSTV0910_P2_NBITER_NF_8PSK_3_5 0xfacb00ff + +/* P2_NBITER_NF13 */ +#define RSTV0910_P2_NBITER_NF13 0xfacc +#define FSTV0910_P2_NBITER_NF_8PSK_2_3 0xfacc00ff + +/* P2_NBITER_NF14 */ +#define RSTV0910_P2_NBITER_NF14 0xfacd +#define FSTV0910_P2_NBITER_NF_8PSK_3_4 0xfacd00ff + +/* P2_NBITER_NF15 */ +#define RSTV0910_P2_NBITER_NF15 0xface +#define FSTV0910_P2_NBITER_NF_8PSK_5_6 0xface00ff + +/* P2_NBITER_NF16 */ +#define RSTV0910_P2_NBITER_NF16 0xfacf +#define FSTV0910_P2_NBITER_NF_8PSK_8_9 0xfacf00ff + +/* P2_NBITER_NF17 */ +#define RSTV0910_P2_NBITER_NF17 0xfad0 +#define FSTV0910_P2_NBITER_NF_8PSK_9_10 0xfad000ff + +/* P2_NBITER_NF18 */ +#define RSTV0910_P2_NBITER_NF18 0xfad1 +#define FSTV0910_P2_NBITER_NF_16APSK_2_3 0xfad100ff + +/* P2_NBITER_NF19 */ +#define RSTV0910_P2_NBITER_NF19 0xfad2 +#define FSTV0910_P2_NBITER_NF_16APSK_3_4 0xfad200ff + +/* P2_NBITER_NF20 */ +#define RSTV0910_P2_NBITER_NF20 0xfad3 +#define FSTV0910_P2_NBITER_NF_16APSK_4_5 0xfad300ff + +/* P2_NBITER_NF21 */ +#define RSTV0910_P2_NBITER_NF21 0xfad4 +#define FSTV0910_P2_NBITER_NF_16APSK_5_6 0xfad400ff + +/* P2_NBITER_NF22 */ +#define RSTV0910_P2_NBITER_NF22 0xfad5 +#define FSTV0910_P2_NBITER_NF_16APSK_8_9 0xfad500ff + +/* P2_NBITER_NF23 */ +#define RSTV0910_P2_NBITER_NF23 0xfad6 +#define FSTV0910_P2_NBITER_NF_16APSK_9_10 0xfad600ff + +/* P2_NBITER_NF24 */ +#define RSTV0910_P2_NBITER_NF24 0xfad7 +#define FSTV0910_P2_NBITER_NF_32APSK_3_4 0xfad700ff + +/* P2_NBITER_NF25 */ +#define RSTV0910_P2_NBITER_NF25 0xfad8 +#define FSTV0910_P2_NBITER_NF_32APSK_4_5 0xfad800ff + +/* P2_NBITER_NF26 */ +#define RSTV0910_P2_NBITER_NF26 0xfad9 +#define FSTV0910_P2_NBITER_NF_32APSK_5_6 0xfad900ff + +/* P2_NBITER_NF27 */ +#define RSTV0910_P2_NBITER_NF27 0xfada +#define FSTV0910_P2_NBITER_NF_32APSK_8_9 0xfada00ff + +/* P2_NBITER_NF28 */ +#define RSTV0910_P2_NBITER_NF28 0xfadb +#define FSTV0910_P2_NBITER_NF_32APSK_9_10 0xfadb00ff + +/* P2_NBITER_SF1 */ +#define RSTV0910_P2_NBITER_SF1 0xfadc +#define FSTV0910_P2_NBITER_SF_QPSK_1_4 0xfadc00ff + +/* P2_NBITER_SF2 */ +#define RSTV0910_P2_NBITER_SF2 0xfadd +#define FSTV0910_P2_NBITER_SF_QPSK_1_3 0xfadd00ff + +/* P2_NBITER_SF3 */ +#define RSTV0910_P2_NBITER_SF3 0xfade +#define FSTV0910_P2_NBITER_SF_QPSK_2_5 0xfade00ff + +/* P2_NBITER_SF4 */ +#define RSTV0910_P2_NBITER_SF4 0xfadf +#define FSTV0910_P2_NBITER_SF_QPSK_1_2 0xfadf00ff + +/* P2_NBITER_SF5 */ +#define RSTV0910_P2_NBITER_SF5 0xfae0 +#define FSTV0910_P2_NBITER_SF_QPSK_3_5 0xfae000ff + +/* P2_NBITER_SF6 */ +#define RSTV0910_P2_NBITER_SF6 0xfae1 +#define FSTV0910_P2_NBITER_SF_QPSK_2_3 0xfae100ff + +/* P2_NBITER_SF7 */ +#define RSTV0910_P2_NBITER_SF7 0xfae2 +#define FSTV0910_P2_NBITER_SF_QPSK_3_4 0xfae200ff + +/* P2_NBITER_SF8 */ +#define RSTV0910_P2_NBITER_SF8 0xfae3 +#define FSTV0910_P2_NBITER_SF_QPSK_4_5 0xfae300ff + +/* P2_NBITER_SF9 */ +#define RSTV0910_P2_NBITER_SF9 0xfae4 +#define FSTV0910_P2_NBITER_SF_QPSK_5_6 0xfae400ff + +/* P2_NBITER_SF10 */ +#define RSTV0910_P2_NBITER_SF10 0xfae5 +#define FSTV0910_P2_NBITER_SF_QPSK_8_9 0xfae500ff + +/* P2_NBITER_SF12 */ +#define RSTV0910_P2_NBITER_SF12 0xfae6 +#define FSTV0910_P2_NBITER_SF_8PSK_3_5 0xfae600ff + +/* P2_NBITER_SF13 */ +#define RSTV0910_P2_NBITER_SF13 0xfae7 +#define FSTV0910_P2_NBITER_SF_8PSK_2_3 0xfae700ff + +/* P2_NBITER_SF14 */ +#define RSTV0910_P2_NBITER_SF14 0xfae8 +#define FSTV0910_P2_NBITER_SF_8PSK_3_4 0xfae800ff + +/* P2_NBITER_SF15 */ +#define RSTV0910_P2_NBITER_SF15 0xfae9 +#define FSTV0910_P2_NBITER_SF_8PSK_5_6 0xfae900ff + +/* P2_NBITER_SF16 */ +#define RSTV0910_P2_NBITER_SF16 0xfaea +#define FSTV0910_P2_NBITER_SF_8PSK_8_9 0xfaea00ff + +/* P2_NBITER_SF18 */ +#define RSTV0910_P2_NBITER_SF18 0xfaeb +#define FSTV0910_P2_NBITER_SF_16APSK_2_3 0xfaeb00ff + +/* P2_NBITER_SF19 */ +#define RSTV0910_P2_NBITER_SF19 0xfaec +#define FSTV0910_P2_NBITER_SF_16APSK_3_4 0xfaec00ff + +/* P2_NBITER_SF20 */ +#define RSTV0910_P2_NBITER_SF20 0xfaed +#define FSTV0910_P2_NBITER_SF_16APSK_4_5 0xfaed00ff + +/* P2_NBITER_SF21 */ +#define RSTV0910_P2_NBITER_SF21 0xfaee +#define FSTV0910_P2_NBITER_SF_16APSK_5_6 0xfaee00ff + +/* P2_NBITER_SF22 */ +#define RSTV0910_P2_NBITER_SF22 0xfaef +#define FSTV0910_P2_NBITER_SF_16APSK_8_9 0xfaef00ff + +/* P2_NBITER_SF24 */ +#define RSTV0910_P2_NBITER_SF24 0xfaf0 +#define FSTV0910_P2_NBITER_SF_32APSK_3_4 0xfaf000ff + +/* P2_NBITER_SF25 */ +#define RSTV0910_P2_NBITER_SF25 0xfaf1 +#define FSTV0910_P2_NBITER_SF_32APSK_4_5 0xfaf100ff + +/* P2_NBITER_SF26 */ +#define RSTV0910_P2_NBITER_SF26 0xfaf2 +#define FSTV0910_P2_NBITER_SF_32APSK_5_6 0xfaf200ff + +/* P2_NBITER_SF27 */ +#define RSTV0910_P2_NBITER_SF27 0xfaf3 +#define FSTV0910_P2_NBITER_SF_32APSK_8_9 0xfaf300ff + +/* TSTRES0 */ +#define RSTV0910_TSTRES0 0xff11 +#define FSTV0910_FRESFEC 0xff110080 +#define FSTV0910_FRESSYM1 0xff110008 +#define FSTV0910_FRESSYM2 0xff110004 + +/* TSTOUT */ +#define RSTV0910_TSTOUT 0xff12 +#define FSTV0910_TS 0xff12003e +#define FSTV0910_TEST_OUT 0xff120001 + +/* TSTIN */ +#define RSTV0910_TSTIN 0xff13 +#define FSTV0910_TEST_IN 0xff130080 + +/* P2_TSTDMD */ +#define RSTV0910_P2_TSTDMD 0xff20 +#define FSTV0910_P2_CFRINIT_INVZIGZAG 0xff200008 + +/* P2_TCTL1 */ +#define RSTV0910_P2_TCTL1 0xff24 +#define FSTV0910_P2_TST_IQSYMBSEL 0xff24001f + +/* P2_TCTL4 */ +#define RSTV0910_P2_TCTL4 0xff28 +#define FSTV0910_P2_CFR2TOCFR1_DVBS1 0xff2800c0 + +/* P2_TPKTDELIN */ +#define RSTV0910_P2_TPKTDELIN 0xff37 +#define FSTV0910_P2_CFG_RSPARITYON 0xff370080 + +/* P1_TSTDMD */ +#define RSTV0910_P1_TSTDMD 0xff40 +#define FSTV0910_P1_CFRINIT_INVZIGZAG 0xff400008 + +/* P1_TCTL1 */ +#define RSTV0910_P1_TCTL1 0xff44 +#define FSTV0910_P1_TST_IQSYMBSEL 0xff44001f + +/* P1_TCTL4 */ +#define RSTV0910_P1_TCTL4 0xff48 +#define FSTV0910_P1_CFR2TOCFR1_DVBS1 0xff4800c0 + +/* P1_TPKTDELIN */ +#define RSTV0910_P1_TPKTDELIN 0xff57 +#define FSTV0910_P1_CFG_RSPARITYON 0xff570080 + +/* TSTTSRS */ +#define RSTV0910_TSTTSRS 0xff6d +#define FSTV0910_TSTRS_DISRS2 0xff6d0002 +#define FSTV0910_TSTRS_DISRS1 0xff6d0001 + +#define STV0910_NBREGS 975 +#define STV0910_NBFIELDS 1818 diff --git a/drivers/media/dvb-frontends/stv6111.c b/drivers/media/dvb-frontends/stv6111.c new file mode 100644 index 000000000000..e3e90070e293 --- /dev/null +++ b/drivers/media/dvb-frontends/stv6111.c @@ -0,0 +1,681 @@ +/* + * Driver for the ST STV6111 tuner + * + * Copyright (C) 2014 Digital Devices GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/firmware.h> +#include <linux/i2c.h> +#include <asm/div64.h> + +#include "stv6111.h" + +#include "dvb_frontend.h" + +struct stv { + struct i2c_adapter *i2c; + u8 adr; + + u8 reg[11]; + u32 ref_freq; + u32 frequency; +}; + +struct slookup { + s16 value; + u16 reg_value; +}; + +static const struct slookup lnagain_nf_lookup[] = { + /* Gain *100dB // Reg */ + { 2572, 0 }, + { 2575, 1 }, + { 2580, 2 }, + { 2588, 3 }, + { 2596, 4 }, + { 2611, 5 }, + { 2633, 6 }, + { 2664, 7 }, + { 2701, 8 }, + { 2753, 9 }, + { 2816, 10 }, + { 2902, 11 }, + { 2995, 12 }, + { 3104, 13 }, + { 3215, 14 }, + { 3337, 15 }, + { 3492, 16 }, + { 3614, 17 }, + { 3731, 18 }, + { 3861, 19 }, + { 3988, 20 }, + { 4124, 21 }, + { 4253, 22 }, + { 4386, 23 }, + { 4505, 24 }, + { 4623, 25 }, + { 4726, 26 }, + { 4821, 27 }, + { 4903, 28 }, + { 4979, 29 }, + { 5045, 30 }, + { 5102, 31 } +}; + +static const struct slookup lnagain_iip3_lookup[] = { + /* Gain *100dB // reg */ + { 1548, 0 }, + { 1552, 1 }, + { 1569, 2 }, + { 1565, 3 }, + { 1577, 4 }, + { 1594, 5 }, + { 1627, 6 }, + { 1656, 7 }, + { 1700, 8 }, + { 1748, 9 }, + { 1805, 10 }, + { 1896, 11 }, + { 1995, 12 }, + { 2113, 13 }, + { 2233, 14 }, + { 2366, 15 }, + { 2543, 16 }, + { 2687, 17 }, + { 2842, 18 }, + { 2999, 19 }, + { 3167, 20 }, + { 3342, 21 }, + { 3507, 22 }, + { 3679, 23 }, + { 3827, 24 }, + { 3970, 25 }, + { 4094, 26 }, + { 4210, 27 }, + { 4308, 28 }, + { 4396, 29 }, + { 4468, 30 }, + { 4535, 31 } +}; + +static const struct slookup gain_rfagc_lookup[] = { + /* Gain *100dB // reg */ + { 4870, 0x3000 }, + { 4850, 0x3C00 }, + { 4800, 0x4500 }, + { 4750, 0x4800 }, + { 4700, 0x4B00 }, + { 4650, 0x4D00 }, + { 4600, 0x4F00 }, + { 4550, 0x5100 }, + { 4500, 0x5200 }, + { 4420, 0x5500 }, + { 4316, 0x5800 }, + { 4200, 0x5B00 }, + { 4119, 0x5D00 }, + { 3999, 0x6000 }, + { 3950, 0x6100 }, + { 3876, 0x6300 }, + { 3755, 0x6600 }, + { 3641, 0x6900 }, + { 3567, 0x6B00 }, + { 3425, 0x6F00 }, + { 3350, 0x7100 }, + { 3236, 0x7400 }, + { 3118, 0x7700 }, + { 3004, 0x7A00 }, + { 2917, 0x7C00 }, + { 2776, 0x7F00 }, + { 2635, 0x8200 }, + { 2516, 0x8500 }, + { 2406, 0x8800 }, + { 2290, 0x8B00 }, + { 2170, 0x8E00 }, + { 2073, 0x9100 }, + { 1949, 0x9400 }, + { 1836, 0x9700 }, + { 1712, 0x9A00 }, + { 1631, 0x9C00 }, + { 1515, 0x9F00 }, + { 1400, 0xA200 }, + { 1323, 0xA400 }, + { 1203, 0xA700 }, + { 1091, 0xAA00 }, + { 1011, 0xAC00 }, + { 904, 0xAF00 }, + { 787, 0xB200 }, + { 685, 0xB500 }, + { 571, 0xB800 }, + { 464, 0xBB00 }, + { 374, 0xBE00 }, + { 275, 0xC200 }, + { 181, 0xC600 }, + { 102, 0xCC00 }, + { 49, 0xD900 } +}; + +/* + * This table is 6 dB too low comapred to the others (probably created with + * a different BB_MAG setting) + */ +static const struct slookup gain_channel_agc_nf_lookup[] = { + /* Gain *100dB // reg */ + { 7082, 0x3000 }, + { 7052, 0x4000 }, + { 7007, 0x4600 }, + { 6954, 0x4A00 }, + { 6909, 0x4D00 }, + { 6833, 0x5100 }, + { 6753, 0x5400 }, + { 6659, 0x5700 }, + { 6561, 0x5A00 }, + { 6472, 0x5C00 }, + { 6366, 0x5F00 }, + { 6259, 0x6100 }, + { 6151, 0x6400 }, + { 6026, 0x6700 }, + { 5920, 0x6900 }, + { 5835, 0x6B00 }, + { 5770, 0x6C00 }, + { 5681, 0x6E00 }, + { 5596, 0x7000 }, + { 5503, 0x7200 }, + { 5429, 0x7300 }, + { 5319, 0x7500 }, + { 5220, 0x7700 }, + { 5111, 0x7900 }, + { 4983, 0x7B00 }, + { 4876, 0x7D00 }, + { 4755, 0x7F00 }, + { 4635, 0x8100 }, + { 4499, 0x8300 }, + { 4405, 0x8500 }, + { 4323, 0x8600 }, + { 4233, 0x8800 }, + { 4156, 0x8A00 }, + { 4038, 0x8C00 }, + { 3935, 0x8E00 }, + { 3823, 0x9000 }, + { 3712, 0x9200 }, + { 3601, 0x9500 }, + { 3511, 0x9700 }, + { 3413, 0x9900 }, + { 3309, 0x9B00 }, + { 3213, 0x9D00 }, + { 3088, 0x9F00 }, + { 2992, 0xA100 }, + { 2878, 0xA400 }, + { 2769, 0xA700 }, + { 2645, 0xAA00 }, + { 2538, 0xAD00 }, + { 2441, 0xB000 }, + { 2350, 0xB600 }, + { 2237, 0xBA00 }, + { 2137, 0xBF00 }, + { 2039, 0xC500 }, + { 1938, 0xDF00 }, + { 1927, 0xFF00 } +}; + +static const struct slookup gain_channel_agc_iip3_lookup[] = { + /* Gain *100dB // reg */ + { 7070, 0x3000 }, + { 7028, 0x4000 }, + { 7019, 0x4600 }, + { 6900, 0x4A00 }, + { 6811, 0x4D00 }, + { 6763, 0x5100 }, + { 6690, 0x5400 }, + { 6644, 0x5700 }, + { 6617, 0x5A00 }, + { 6598, 0x5C00 }, + { 6462, 0x5F00 }, + { 6348, 0x6100 }, + { 6197, 0x6400 }, + { 6154, 0x6700 }, + { 6098, 0x6900 }, + { 5893, 0x6B00 }, + { 5812, 0x6C00 }, + { 5773, 0x6E00 }, + { 5723, 0x7000 }, + { 5661, 0x7200 }, + { 5579, 0x7300 }, + { 5460, 0x7500 }, + { 5308, 0x7700 }, + { 5099, 0x7900 }, + { 4910, 0x7B00 }, + { 4800, 0x7D00 }, + { 4785, 0x7F00 }, + { 4635, 0x8100 }, + { 4466, 0x8300 }, + { 4314, 0x8500 }, + { 4295, 0x8600 }, + { 4144, 0x8800 }, + { 3920, 0x8A00 }, + { 3889, 0x8C00 }, + { 3771, 0x8E00 }, + { 3655, 0x9000 }, + { 3446, 0x9200 }, + { 3298, 0x9500 }, + { 3083, 0x9700 }, + { 3015, 0x9900 }, + { 2833, 0x9B00 }, + { 2746, 0x9D00 }, + { 2632, 0x9F00 }, + { 2598, 0xA100 }, + { 2480, 0xA400 }, + { 2236, 0xA700 }, + { 2171, 0xAA00 }, + { 2060, 0xAD00 }, + { 1999, 0xB000 }, + { 1974, 0xB600 }, + { 1820, 0xBA00 }, + { 1741, 0xBF00 }, + { 1655, 0xC500 }, + { 1444, 0xDF00 }, + { 1325, 0xFF00 }, +}; + +static inline u32 muldiv32(u32 a, u32 b, u32 c) +{ + u64 tmp64; + + tmp64 = (u64)a * (u64)b; + do_div(tmp64, c); + + return (u32)tmp64; +} + +static int i2c_read(struct i2c_adapter *adap, + u8 adr, u8 *msg, int len, u8 *answ, int alen) +{ + struct i2c_msg msgs[2] = { { .addr = adr, .flags = 0, + .buf = msg, .len = len}, + { .addr = adr, .flags = I2C_M_RD, + .buf = answ, .len = alen } }; + if (i2c_transfer(adap, msgs, 2) != 2) { + dev_err(&adap->dev, "i2c read error\n"); + return -EIO; + } + return 0; +} + +static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) +{ + struct i2c_msg msg = {.addr = adr, .flags = 0, + .buf = data, .len = len}; + + if (i2c_transfer(adap, &msg, 1) != 1) { + dev_err(&adap->dev, "i2c write error\n"); + return -EIO; + } + return 0; +} + +static int write_regs(struct stv *state, int reg, int len) +{ + u8 d[12]; + + memcpy(&d[1], &state->reg[reg], len); + d[0] = reg; + return i2c_write(state->i2c, state->adr, d, len + 1); +} + +static int write_reg(struct stv *state, u8 reg, u8 val) +{ + u8 d[2] = {reg, val}; + + return i2c_write(state->i2c, state->adr, d, 2); +} + +static int read_reg(struct stv *state, u8 reg, u8 *val) +{ + return i2c_read(state->i2c, state->adr, ®, 1, val, 1); +} + +static int wait_for_call_done(struct stv *state, u8 mask) +{ + int status = 0; + u32 lock_retry_count = 10; + + while (lock_retry_count > 0) { + u8 regval; + + status = read_reg(state, 9, ®val); + if (status < 0) + return status; + + if ((regval & mask) == 0) + break; + usleep_range(4000, 6000); + lock_retry_count -= 1; + + status = -EIO; + } + return status; +} + +static void init_state(struct stv *state) +{ + u32 clkdiv = 0; + u32 agcmode = 0; + u32 agcref = 2; + u32 agcset = 0xffffffff; + u32 bbmode = 0xffffffff; + + state->reg[0] = 0x08; + state->reg[1] = 0x41; + state->reg[2] = 0x8f; + state->reg[3] = 0x00; + state->reg[4] = 0xce; + state->reg[5] = 0x54; + state->reg[6] = 0x55; + state->reg[7] = 0x45; + state->reg[8] = 0x46; + state->reg[9] = 0xbd; + state->reg[10] = 0x11; + + state->ref_freq = 16000; + + if (clkdiv <= 3) + state->reg[0x00] |= (clkdiv & 0x03); + if (agcmode <= 3) { + state->reg[0x03] |= (agcmode << 5); + if (agcmode == 0x01) + state->reg[0x01] |= 0x30; + } + if (bbmode <= 3) + state->reg[0x01] = (state->reg[0x01] & ~0x30) | (bbmode << 4); + if (agcref <= 7) + state->reg[0x03] |= agcref; + if (agcset <= 31) + state->reg[0x02] = (state->reg[0x02] & ~0x1F) | agcset | 0x40; +} + +static int attach_init(struct stv *state) +{ + if (write_regs(state, 0, 11)) + return -ENODEV; + return 0; +} + +static void release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + +static int set_bandwidth(struct dvb_frontend *fe, u32 cutoff_frequency) +{ + struct stv *state = fe->tuner_priv; + u32 index = (cutoff_frequency + 999999) / 1000000; + + if (index < 6) + index = 6; + if (index > 50) + index = 50; + if ((state->reg[0x08] & ~0xFC) == ((index - 6) << 2)) + return 0; + + state->reg[0x08] = (state->reg[0x08] & ~0xFC) | ((index - 6) << 2); + state->reg[0x09] = (state->reg[0x09] & ~0x0C) | 0x08; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + write_regs(state, 0x08, 2); + wait_for_call_done(state, 0x08); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + return 0; +} + +static int set_lof(struct stv *state, u32 local_frequency, u32 cutoff_frequency) +{ + u32 index = (cutoff_frequency + 999999) / 1000000; + u32 frequency = (local_frequency + 500) / 1000; + u32 p = 1, psel = 0, fvco, div, frac; + u8 icp, tmp; + + if (index < 6) + index = 6; + if (index > 50) + index = 50; + + if (frequency <= 1300000) { + p = 4; + psel = 1; + } else { + p = 2; + psel = 0; + } + fvco = frequency * p; + div = fvco / state->ref_freq; + frac = fvco % state->ref_freq; + frac = muldiv32(frac, 0x40000, state->ref_freq); + + icp = 0; + if (fvco < 2700000) + icp = 0; + else if (fvco < 2950000) + icp = 1; + else if (fvco < 3300000) + icp = 2; + else if (fvco < 3700000) + icp = 3; + else if (fvco < 4200000) + icp = 5; + else if (fvco < 4800000) + icp = 6; + else + icp = 7; + + state->reg[0x02] |= 0x80; /* LNA IIP3 Mode */ + + state->reg[0x03] = (state->reg[0x03] & ~0x80) | (psel << 7); + state->reg[0x04] = (div & 0xFF); + state->reg[0x05] = (((div >> 8) & 0x01) | ((frac & 0x7F) << 1)) & 0xff; + state->reg[0x06] = ((frac >> 7) & 0xFF); + state->reg[0x07] = (state->reg[0x07] & ~0x07) | ((frac >> 15) & 0x07); + state->reg[0x07] = (state->reg[0x07] & ~0xE0) | (icp << 5); + + state->reg[0x08] = (state->reg[0x08] & ~0xFC) | ((index - 6) << 2); + /* Start cal vco,CF */ + state->reg[0x09] = (state->reg[0x09] & ~0x0C) | 0x0C; + write_regs(state, 2, 8); + + wait_for_call_done(state, 0x0C); + + usleep_range(10000, 12000); + + read_reg(state, 0x03, &tmp); + if (tmp & 0x10) { + state->reg[0x02] &= ~0x80; /* LNA NF Mode */ + write_regs(state, 2, 1); + } + read_reg(state, 0x08, &tmp); + + state->frequency = frequency; + + return 0; +} + +static int set_params(struct dvb_frontend *fe) +{ + struct stv *state = fe->tuner_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 freq, cutoff; + + if (p->delivery_system != SYS_DVBS && p->delivery_system != SYS_DVBS2) + return -EINVAL; + + freq = p->frequency * 1000; + cutoff = 5000000 + muldiv32(p->symbol_rate, 135, 200); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + set_lof(state, freq, cutoff); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + return 0; +} + +static s32 table_lookup(const struct slookup *table, + int table_size, u16 reg_value) +{ + s32 gain; + s32 reg_diff; + int imin = 0; + int imax = table_size - 1; + int i; + + /* Assumes Table[0].RegValue < Table[imax].RegValue */ + if (reg_value <= table[0].reg_value) { + gain = table[0].value; + } else if (reg_value >= table[imax].reg_value) { + gain = table[imax].value; + } else { + while ((imax - imin) > 1) { + i = (imax + imin) / 2; + if ((table[imin].reg_value <= reg_value) && + (reg_value <= table[i].reg_value)) + imax = i; + else + imin = i; + } + reg_diff = table[imax].reg_value - table[imin].reg_value; + gain = table[imin].value; + if (reg_diff != 0) + gain += ((s32)(reg_value - table[imin].reg_value) * + (s32)(table[imax].value + - table[imin].value)) / reg_diff; + } + return gain; +} + +static int get_rf_strength(struct dvb_frontend *fe, u16 *st) +{ + struct stv *state = fe->tuner_priv; + u16 rfagc = *st; + s32 gain; + + if ((state->reg[0x03] & 0x60) == 0) { + /* RF Mode, Read AGC ADC */ + u8 reg = 0; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + write_reg(state, 0x02, state->reg[0x02] | 0x20); + read_reg(state, 2, ®); + if (reg & 0x20) + read_reg(state, 2, ®); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if ((state->reg[0x02] & 0x80) == 0) + /* NF */ + gain = table_lookup(lnagain_nf_lookup, + ARRAY_SIZE(lnagain_nf_lookup), + reg & 0x1F); + else + /* IIP3 */ + gain = table_lookup(lnagain_iip3_lookup, + ARRAY_SIZE(lnagain_iip3_lookup), + reg & 0x1F); + + gain += table_lookup(gain_rfagc_lookup, + ARRAY_SIZE(gain_rfagc_lookup), rfagc); + + gain -= 2400; + } else { + /* Channel Mode */ + if ((state->reg[0x02] & 0x80) == 0) { + /* NF */ + gain = table_lookup( + gain_channel_agc_nf_lookup, + ARRAY_SIZE(gain_channel_agc_nf_lookup), rfagc); + + gain += 600; + } else { + /* IIP3 */ + gain = table_lookup( + gain_channel_agc_iip3_lookup, + ARRAY_SIZE(gain_channel_agc_iip3_lookup), + rfagc); + } + } + + if (state->frequency > 0) + /* Tilt correction ( 0.00016 dB/MHz ) */ + gain -= ((((s32)(state->frequency / 1000) - 1550) * 2) / 12); + + /* + (BBGain * 10); */ + gain += (s32)((state->reg[0x01] & 0xC0) >> 6) * 600 - 1300; + + if (gain < 0) + gain = 0; + else if (gain > 10000) + gain = 10000; + + *st = 10000 - gain; + + return 0; +} + +static const struct dvb_tuner_ops tuner_ops = { + .info = { + .name = "ST STV6111", + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_step = 0 + }, + .set_params = set_params, + .release = release, + .get_rf_strength = get_rf_strength, + .set_bandwidth = set_bandwidth, +}; + +struct dvb_frontend *stv6111_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 adr) +{ + struct stv *state; + int stat; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + state->adr = adr; + state->i2c = i2c; + memcpy(&fe->ops.tuner_ops, &tuner_ops, sizeof(struct dvb_tuner_ops)); + init_state(state); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + stat = attach_init(state); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + if (stat < 0) { + kfree(state); + return NULL; + } + fe->tuner_priv = state; + return fe; +} +EXPORT_SYMBOL_GPL(stv6111_attach); + +MODULE_DESCRIPTION("ST STV6111 satellite tuner driver"); +MODULE_AUTHOR("Ralph Metzler, Manfred Voelkel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/stv6111.h b/drivers/media/dvb-frontends/stv6111.h new file mode 100644 index 000000000000..5bc1228dc9bd --- /dev/null +++ b/drivers/media/dvb-frontends/stv6111.h @@ -0,0 +1,21 @@ +#ifndef _STV6111_H_ +#define _STV6111_H_ + +#if IS_REACHABLE(CONFIG_DVB_STV6111) + +struct dvb_frontend *stv6111_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 adr); + +#else + +static inline struct dvb_frontend *stv6111_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + u8 adr) +{ + pr_warn("%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif /* CONFIG_DVB_STV6111 */ + +#endif /* _STV6111_H_ */ diff --git a/drivers/media/dvb-frontends/zd1301_demod.c b/drivers/media/dvb-frontends/zd1301_demod.c index fcf5f69de0c5..84a2b25a574a 100644 --- a/drivers/media/dvb-frontends/zd1301_demod.c +++ b/drivers/media/dvb-frontends/zd1301_demod.c @@ -445,7 +445,7 @@ static u32 zd1301_demod_i2c_functionality(struct i2c_adapter *adapter) return I2C_FUNC_I2C; } -static struct i2c_algorithm zd1301_demod_i2c_algorithm = { +static const struct i2c_algorithm zd1301_demod_i2c_algorithm = { .master_xfer = zd1301_demod_i2c_master_xfer, .functionality = zd1301_demod_i2c_functionality, }; diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 121b3b5394cb..94153895fcd4 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -204,6 +204,18 @@ config VIDEO_ADV7183 To compile this driver as a module, choose M here: the module will be called adv7183. +config VIDEO_ADV748X + tristate "Analog Devices ADV748x decoder" + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on OF + select REGMAP_I2C + ---help--- + V4L2 subdevice driver for the Analog Devices + ADV7481 and ADV7482 HDMI/Analog video decoders. + + To compile this driver as a module, choose M here: the + module will be called adv748x. + config VIDEO_ADV7604 tristate "Analog Devices ADV7604 decoder" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API @@ -593,6 +605,30 @@ config VIDEO_OV5647 To compile this driver as a module, choose M here: the module will be called ov5647. +config VIDEO_OV6650 + tristate "OmniVision OV6650 sensor support" + depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV6650 camera. + + To compile this driver as a module, choose M here: the + module will be called ov6650. + +config VIDEO_OV5670 + tristate "OmniVision OV5670 sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT + depends on MEDIA_CONTROLLER + select V4L2_FWNODE + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV5670 camera. + + To compile this driver as a module, choose M here: the + module will be called ov5670. + config VIDEO_OV7640 tristate "OmniVision OV7640 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 2c0868fa6034..c843c181dfb9 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o obj-$(CONFIG_VIDEO_ADV7393) += adv7393.o +obj-$(CONFIG_VIDEO_ADV748X) += adv748x/ obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o @@ -62,6 +63,8 @@ obj-$(CONFIG_VIDEO_OV2640) += ov2640.o obj-$(CONFIG_VIDEO_OV5640) += ov5640.o obj-$(CONFIG_VIDEO_OV5645) += ov5645.o obj-$(CONFIG_VIDEO_OV5647) += ov5647.o +obj-$(CONFIG_VIDEO_OV5670) += ov5670.o +obj-$(CONFIG_VIDEO_OV6650) += ov6650.o obj-$(CONFIG_VIDEO_OV7640) += ov7640.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index 50f354144ee7..a056d6cdaaaa 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c @@ -1208,7 +1208,7 @@ static int ad9389b_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static struct i2c_device_id ad9389b_id[] = { +static const struct i2c_device_id ad9389b_id[] = { { "ad9389b", 0 }, { "ad9889b", 0 }, { } diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 78de7ddf5081..3df28f2f9b38 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1402,6 +1402,8 @@ static int adv7180_remove(struct i2c_client *client) 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 }, diff --git a/drivers/media/i2c/adv748x/Makefile b/drivers/media/i2c/adv748x/Makefile new file mode 100644 index 000000000000..c0711e076f1d --- /dev/null +++ b/drivers/media/i2c/adv748x/Makefile @@ -0,0 +1,7 @@ +adv748x-objs := \ + adv748x-afe.o \ + adv748x-core.o \ + adv748x-csi2.o \ + adv748x-hdmi.o + +obj-$(CONFIG_VIDEO_ADV748X) += adv748x.o diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c new file mode 100644 index 000000000000..b33ccfc08708 --- /dev/null +++ b/drivers/media/i2c/adv748x/adv748x-afe.c @@ -0,0 +1,552 @@ +/* + * Driver for Analog Devices ADV748X 8 channel analog front end (AFE) receiver + * with standard definition processor (SDP) + * + * Copyright (C) 2017 Renesas Electronics Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/v4l2-dv-timings.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-dv-timings.h> +#include <media/v4l2-ioctl.h> + +#include "adv748x.h" + +/* ----------------------------------------------------------------------------- + * SDP + */ + +#define ADV748X_AFE_STD_AD_PAL_BG_NTSC_J_SECAM 0x0 +#define ADV748X_AFE_STD_AD_PAL_BG_NTSC_J_SECAM_PED 0x1 +#define ADV748X_AFE_STD_AD_PAL_N_NTSC_J_SECAM 0x2 +#define ADV748X_AFE_STD_AD_PAL_N_NTSC_M_SECAM 0x3 +#define ADV748X_AFE_STD_NTSC_J 0x4 +#define ADV748X_AFE_STD_NTSC_M 0x5 +#define ADV748X_AFE_STD_PAL60 0x6 +#define ADV748X_AFE_STD_NTSC_443 0x7 +#define ADV748X_AFE_STD_PAL_BG 0x8 +#define ADV748X_AFE_STD_PAL_N 0x9 +#define ADV748X_AFE_STD_PAL_M 0xa +#define ADV748X_AFE_STD_PAL_M_PED 0xb +#define ADV748X_AFE_STD_PAL_COMB_N 0xc +#define ADV748X_AFE_STD_PAL_COMB_N_PED 0xd +#define ADV748X_AFE_STD_PAL_SECAM 0xe +#define ADV748X_AFE_STD_PAL_SECAM_PED 0xf + +static int adv748x_afe_read_ro_map(struct adv748x_state *state, u8 reg) +{ + int ret; + + /* Select SDP Read-Only Main Map */ + ret = sdp_write(state, ADV748X_SDP_MAP_SEL, + ADV748X_SDP_MAP_SEL_RO_MAIN); + if (ret < 0) + return ret; + + return sdp_read(state, reg); +} + +static int adv748x_afe_status(struct adv748x_afe *afe, u32 *signal, + v4l2_std_id *std) +{ + struct adv748x_state *state = adv748x_afe_to_state(afe); + int info; + + /* Read status from reg 0x10 of SDP RO Map */ + info = adv748x_afe_read_ro_map(state, ADV748X_SDP_RO_10); + if (info < 0) + return info; + + if (signal) + *signal = info & ADV748X_SDP_RO_10_IN_LOCK ? + 0 : V4L2_IN_ST_NO_SIGNAL; + + if (!std) + return 0; + + /* Standard not valid if there is no signal */ + if (!(info & ADV748X_SDP_RO_10_IN_LOCK)) { + *std = V4L2_STD_UNKNOWN; + return 0; + } + + switch (info & 0x70) { + case 0x00: + *std = V4L2_STD_NTSC; + break; + case 0x10: + *std = V4L2_STD_NTSC_443; + break; + case 0x20: + *std = V4L2_STD_PAL_M; + break; + case 0x30: + *std = V4L2_STD_PAL_60; + break; + case 0x40: + *std = V4L2_STD_PAL; + break; + case 0x50: + *std = V4L2_STD_SECAM; + break; + case 0x60: + *std = V4L2_STD_PAL_Nc | V4L2_STD_PAL_N; + break; + case 0x70: + *std = V4L2_STD_SECAM; + break; + default: + *std = V4L2_STD_UNKNOWN; + break; + } + + return 0; +} + +static void adv748x_afe_fill_format(struct adv748x_afe *afe, + struct v4l2_mbus_framefmt *fmt) +{ + memset(fmt, 0, sizeof(*fmt)); + + fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + fmt->field = V4L2_FIELD_ALTERNATE; + + fmt->width = 720; + fmt->height = afe->curr_norm & V4L2_STD_525_60 ? 480 : 576; + + /* Field height */ + fmt->height /= 2; +} + +static int adv748x_afe_std(v4l2_std_id std) +{ + if (std == V4L2_STD_PAL_60) + return ADV748X_AFE_STD_PAL60; + if (std == V4L2_STD_NTSC_443) + return ADV748X_AFE_STD_NTSC_443; + if (std == V4L2_STD_PAL_N) + return ADV748X_AFE_STD_PAL_N; + if (std == V4L2_STD_PAL_M) + return ADV748X_AFE_STD_PAL_M; + if (std == V4L2_STD_PAL_Nc) + return ADV748X_AFE_STD_PAL_COMB_N; + if (std & V4L2_STD_NTSC) + return ADV748X_AFE_STD_NTSC_M; + if (std & V4L2_STD_PAL) + return ADV748X_AFE_STD_PAL_BG; + if (std & V4L2_STD_SECAM) + return ADV748X_AFE_STD_PAL_SECAM; + + return -EINVAL; +} + +static void adv748x_afe_set_video_standard(struct adv748x_state *state, + int sdpstd) +{ + sdp_clrset(state, ADV748X_SDP_VID_SEL, ADV748X_SDP_VID_SEL_MASK, + (sdpstd & 0xf) << ADV748X_SDP_VID_SEL_SHIFT); +} + +static int adv748x_afe_s_input(struct adv748x_afe *afe, unsigned int input) +{ + struct adv748x_state *state = adv748x_afe_to_state(afe); + + return sdp_write(state, ADV748X_SDP_INSEL, input); +} + +static int adv748x_afe_g_pixelaspect(struct v4l2_subdev *sd, + struct v4l2_fract *aspect) +{ + struct adv748x_afe *afe = adv748x_sd_to_afe(sd); + + if (afe->curr_norm & V4L2_STD_525_60) { + aspect->numerator = 11; + aspect->denominator = 10; + } else { + aspect->numerator = 54; + aspect->denominator = 59; + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_video_ops + */ + +static int adv748x_afe_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) +{ + struct adv748x_afe *afe = adv748x_sd_to_afe(sd); + + *norm = afe->curr_norm; + + return 0; +} + +static int adv748x_afe_s_std(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv748x_afe *afe = adv748x_sd_to_afe(sd); + struct adv748x_state *state = adv748x_afe_to_state(afe); + int afe_std = adv748x_afe_std(std); + + if (afe_std < 0) + return afe_std; + + mutex_lock(&state->mutex); + + adv748x_afe_set_video_standard(state, afe_std); + afe->curr_norm = std; + + mutex_unlock(&state->mutex); + + return 0; +} + +static int adv748x_afe_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + struct adv748x_afe *afe = adv748x_sd_to_afe(sd); + struct adv748x_state *state = adv748x_afe_to_state(afe); + int ret; + + mutex_lock(&state->mutex); + + if (afe->streaming) { + ret = -EBUSY; + goto unlock; + } + + /* Set auto detect mode */ + adv748x_afe_set_video_standard(state, + ADV748X_AFE_STD_AD_PAL_BG_NTSC_J_SECAM); + + msleep(100); + + /* Read detected standard */ + ret = adv748x_afe_status(afe, NULL, std); + + /* Restore original state */ + adv748x_afe_set_video_standard(state, afe->curr_norm); + +unlock: + mutex_unlock(&state->mutex); + + return ret; +} + +static int adv748x_afe_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) +{ + *norm = V4L2_STD_ALL; + + return 0; +} + +static int adv748x_afe_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + struct adv748x_afe *afe = adv748x_sd_to_afe(sd); + struct adv748x_state *state = adv748x_afe_to_state(afe); + int ret; + + mutex_lock(&state->mutex); + + ret = adv748x_afe_status(afe, status, NULL); + + mutex_unlock(&state->mutex); + return ret; +} + +static int adv748x_afe_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct adv748x_afe *afe = adv748x_sd_to_afe(sd); + struct adv748x_state *state = adv748x_afe_to_state(afe); + int ret, signal = V4L2_IN_ST_NO_SIGNAL; + + mutex_lock(&state->mutex); + + if (enable) { + ret = adv748x_afe_s_input(afe, afe->input); + if (ret) + goto unlock; + } + + ret = adv748x_txb_power(state, enable); + if (ret) + goto unlock; + + afe->streaming = enable; + + adv748x_afe_status(afe, &signal, NULL); + if (signal != V4L2_IN_ST_NO_SIGNAL) + adv_dbg(state, "Detected SDP signal\n"); + else + adv_dbg(state, "Couldn't detect SDP video signal\n"); + +unlock: + mutex_unlock(&state->mutex); + + return ret; +} + +static const struct v4l2_subdev_video_ops adv748x_afe_video_ops = { + .g_std = adv748x_afe_g_std, + .s_std = adv748x_afe_s_std, + .querystd = adv748x_afe_querystd, + .g_tvnorms = adv748x_afe_g_tvnorms, + .g_input_status = adv748x_afe_g_input_status, + .s_stream = adv748x_afe_s_stream, + .g_pixelaspect = adv748x_afe_g_pixelaspect, +}; + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_pad_ops + */ + +static int adv748x_afe_propagate_pixelrate(struct adv748x_afe *afe) +{ + struct v4l2_subdev *tx; + unsigned int width, height, fps; + + tx = adv748x_get_remote_sd(&afe->pads[ADV748X_AFE_SOURCE]); + if (!tx) + return -ENOLINK; + + width = 720; + height = afe->curr_norm & V4L2_STD_525_60 ? 480 : 576; + fps = afe->curr_norm & V4L2_STD_525_60 ? 30 : 25; + + return adv748x_csi2_set_pixelrate(tx, width * height * fps); +} + +static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index != 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_UYVY8_2X8; + + return 0; +} + +static int adv748x_afe_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *sdformat) +{ + struct adv748x_afe *afe = adv748x_sd_to_afe(sd); + struct v4l2_mbus_framefmt *mbusformat; + + /* It makes no sense to get the format of the analog sink pads */ + if (sdformat->pad != ADV748X_AFE_SOURCE) + return -EINVAL; + + if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) { + mbusformat = v4l2_subdev_get_try_format(sd, cfg, sdformat->pad); + sdformat->format = *mbusformat; + } else { + adv748x_afe_fill_format(afe, &sdformat->format); + adv748x_afe_propagate_pixelrate(afe); + } + + return 0; +} + +static int adv748x_afe_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *sdformat) +{ + struct v4l2_mbus_framefmt *mbusformat; + + /* It makes no sense to get the format of the analog sink pads */ + if (sdformat->pad != ADV748X_AFE_SOURCE) + return -EINVAL; + + if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return adv748x_afe_get_format(sd, cfg, sdformat); + + mbusformat = v4l2_subdev_get_try_format(sd, cfg, sdformat->pad); + *mbusformat = sdformat->format; + + return 0; +} + +static const struct v4l2_subdev_pad_ops adv748x_afe_pad_ops = { + .enum_mbus_code = adv748x_afe_enum_mbus_code, + .set_fmt = adv748x_afe_set_format, + .get_fmt = adv748x_afe_get_format, +}; + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_ops + */ + +static const struct v4l2_subdev_ops adv748x_afe_ops = { + .video = &adv748x_afe_video_ops, + .pad = &adv748x_afe_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * Controls + */ + +static const char * const afe_ctrl_frp_menu[] = { + "Disabled", + "Solid Blue", + "Color Bars", + "Grey Ramp", + "Cb Ramp", + "Cr Ramp", + "Boundary" +}; + +static int adv748x_afe_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct adv748x_afe *afe = adv748x_ctrl_to_afe(ctrl); + struct adv748x_state *state = adv748x_afe_to_state(afe); + bool enable; + int ret; + + ret = sdp_write(state, 0x0e, 0x00); + if (ret < 0) + return ret; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ret = sdp_write(state, ADV748X_SDP_BRI, ctrl->val); + break; + case V4L2_CID_HUE: + /* Hue is inverted according to HSL chart */ + ret = sdp_write(state, ADV748X_SDP_HUE, -ctrl->val); + break; + case V4L2_CID_CONTRAST: + ret = sdp_write(state, ADV748X_SDP_CON, ctrl->val); + break; + case V4L2_CID_SATURATION: + ret = sdp_write(state, ADV748X_SDP_SD_SAT_U, ctrl->val); + if (ret) + break; + ret = sdp_write(state, ADV748X_SDP_SD_SAT_V, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: + enable = !!ctrl->val; + + /* Enable/Disable Color bar test patterns */ + ret = sdp_clrset(state, ADV748X_SDP_DEF, ADV748X_SDP_DEF_VAL_EN, + enable); + if (ret) + break; + ret = sdp_clrset(state, ADV748X_SDP_FRP, ADV748X_SDP_FRP_MASK, + enable ? ctrl->val - 1 : 0); + break; + default: + return -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops adv748x_afe_ctrl_ops = { + .s_ctrl = adv748x_afe_s_ctrl, +}; + +static int adv748x_afe_init_controls(struct adv748x_afe *afe) +{ + struct adv748x_state *state = adv748x_afe_to_state(afe); + + v4l2_ctrl_handler_init(&afe->ctrl_hdl, 5); + + /* Use our mutex for the controls */ + afe->ctrl_hdl.lock = &state->mutex; + + v4l2_ctrl_new_std(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops, + V4L2_CID_BRIGHTNESS, ADV748X_SDP_BRI_MIN, + ADV748X_SDP_BRI_MAX, 1, ADV748X_SDP_BRI_DEF); + v4l2_ctrl_new_std(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops, + V4L2_CID_CONTRAST, ADV748X_SDP_CON_MIN, + ADV748X_SDP_CON_MAX, 1, ADV748X_SDP_CON_DEF); + v4l2_ctrl_new_std(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops, + V4L2_CID_SATURATION, ADV748X_SDP_SAT_MIN, + ADV748X_SDP_SAT_MAX, 1, ADV748X_SDP_SAT_DEF); + v4l2_ctrl_new_std(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops, + V4L2_CID_HUE, ADV748X_SDP_HUE_MIN, + ADV748X_SDP_HUE_MAX, 1, ADV748X_SDP_HUE_DEF); + + v4l2_ctrl_new_std_menu_items(&afe->ctrl_hdl, &adv748x_afe_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(afe_ctrl_frp_menu) - 1, + 0, 0, afe_ctrl_frp_menu); + + afe->sd.ctrl_handler = &afe->ctrl_hdl; + if (afe->ctrl_hdl.error) { + v4l2_ctrl_handler_free(&afe->ctrl_hdl); + return afe->ctrl_hdl.error; + } + + return v4l2_ctrl_handler_setup(&afe->ctrl_hdl); +} + +int adv748x_afe_init(struct adv748x_afe *afe) +{ + struct adv748x_state *state = adv748x_afe_to_state(afe); + int ret; + unsigned int i; + + afe->input = 0; + afe->streaming = false; + afe->curr_norm = V4L2_STD_NTSC_M; + + adv748x_subdev_init(&afe->sd, state, &adv748x_afe_ops, + MEDIA_ENT_F_ATV_DECODER, "afe"); + + /* Identify the first connector found as a default input if set */ + for (i = ADV748X_PORT_AIN0; i <= ADV748X_PORT_AIN7; i++) { + /* Inputs and ports are 1-indexed to match the data sheet */ + if (state->endpoints[i]) { + afe->input = i; + break; + } + } + + adv748x_afe_s_input(afe, afe->input); + + adv_dbg(state, "AFE Default input set to %d\n", afe->input); + + /* Entity pads and sinks are 0-indexed to match the pads */ + for (i = ADV748X_AFE_SINK_AIN0; i <= ADV748X_AFE_SINK_AIN7; i++) + afe->pads[i].flags = MEDIA_PAD_FL_SINK; + + afe->pads[ADV748X_AFE_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&afe->sd.entity, ADV748X_AFE_NR_PADS, + afe->pads); + if (ret) + return ret; + + ret = adv748x_afe_init_controls(afe); + if (ret) + goto error; + + return 0; + +error: + media_entity_cleanup(&afe->sd.entity); + + return ret; +} + +void adv748x_afe_cleanup(struct adv748x_afe *afe) +{ + v4l2_device_unregister_subdev(&afe->sd); + media_entity_cleanup(&afe->sd.entity); + v4l2_ctrl_handler_free(&afe->ctrl_hdl); +} diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c new file mode 100644 index 000000000000..5ee14f2c2747 --- /dev/null +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -0,0 +1,833 @@ +/* + * Driver for Analog Devices ADV748X HDMI receiver with AFE + * + * Copyright (C) 2017 Renesas Electronics Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Authors: + * Koji Matsuoka <koji.matsuoka.xm@renesas.com> + * Niklas Söderlund <niklas.soderlund@ragnatech.se> + * Kieran Bingham <kieran.bingham@ideasonboard.com> + */ + +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of_graph.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/v4l2-dv-timings.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-dv-timings.h> +#include <media/v4l2-ioctl.h> + +#include "adv748x.h" + +/* ----------------------------------------------------------------------------- + * Register manipulation + */ + +static const struct regmap_config adv748x_regmap_cnf[] = { + { + .name = "io", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "dpll", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "cp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "hdmi", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "edid", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "repeater", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "infoframe", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "cec", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "sdp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + + { + .name = "txb", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "txa", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, +}; + +static int adv748x_configure_regmap(struct adv748x_state *state, int region) +{ + int err; + + if (!state->i2c_clients[region]) + return -ENODEV; + + state->regmap[region] = + devm_regmap_init_i2c(state->i2c_clients[region], + &adv748x_regmap_cnf[region]); + + if (IS_ERR(state->regmap[region])) { + err = PTR_ERR(state->regmap[region]); + adv_err(state, + "Error initializing regmap %d with error %d\n", + region, err); + return -EINVAL; + } + + return 0; +} + +/* Default addresses for the I2C pages */ +static int adv748x_i2c_addresses[ADV748X_PAGE_MAX] = { + ADV748X_I2C_IO, + ADV748X_I2C_DPLL, + ADV748X_I2C_CP, + ADV748X_I2C_HDMI, + ADV748X_I2C_EDID, + ADV748X_I2C_REPEATER, + ADV748X_I2C_INFOFRAME, + ADV748X_I2C_CEC, + ADV748X_I2C_SDP, + ADV748X_I2C_TXB, + ADV748X_I2C_TXA, +}; + +static int adv748x_read_check(struct adv748x_state *state, + int client_page, u8 reg) +{ + struct i2c_client *client = state->i2c_clients[client_page]; + int err; + unsigned int val; + + err = regmap_read(state->regmap[client_page], reg, &val); + + if (err) { + adv_err(state, "error reading %02x, %02x\n", + client->addr, reg); + return err; + } + + return val; +} + +int adv748x_read(struct adv748x_state *state, u8 page, u8 reg) +{ + return adv748x_read_check(state, page, reg); +} + +int adv748x_write(struct adv748x_state *state, u8 page, u8 reg, u8 value) +{ + return regmap_write(state->regmap[page], reg, value); +} + +/* adv748x_write_block(): Write raw data with a maximum of I2C_SMBUS_BLOCK_MAX + * size to one or more registers. + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int adv748x_write_block(struct adv748x_state *state, int client_page, + unsigned int init_reg, const void *val, + size_t val_len) +{ + struct regmap *regmap = state->regmap[client_page]; + + if (val_len > I2C_SMBUS_BLOCK_MAX) + val_len = I2C_SMBUS_BLOCK_MAX; + + return regmap_raw_write(regmap, init_reg, val, val_len); +} + +static struct i2c_client *adv748x_dummy_client(struct adv748x_state *state, + u8 addr, u8 io_reg) +{ + struct i2c_client *client = state->client; + + if (addr) + io_write(state, io_reg, addr << 1); + + return i2c_new_dummy(client->adapter, io_read(state, io_reg) >> 1); +} + +static void adv748x_unregister_clients(struct adv748x_state *state) +{ + unsigned int i; + + for (i = 1; i < ARRAY_SIZE(state->i2c_clients); ++i) { + if (state->i2c_clients[i]) + i2c_unregister_device(state->i2c_clients[i]); + } +} + +static int adv748x_initialise_clients(struct adv748x_state *state) +{ + int i; + int ret; + + for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) { + state->i2c_clients[i] = + adv748x_dummy_client(state, adv748x_i2c_addresses[i], + ADV748X_IO_SLAVE_ADDR_BASE + i); + if (state->i2c_clients[i] == NULL) { + adv_err(state, "failed to create i2c client %u\n", i); + return -ENOMEM; + } + + ret = adv748x_configure_regmap(state, i); + if (ret) + return ret; + } + + return 0; +} + +/** + * struct adv748x_reg_value - Register write instruction + * @page: Regmap page identifier + * @reg: I2C register + * @value: value to write to @page at @reg + */ +struct adv748x_reg_value { + u8 page; + u8 reg; + u8 value; +}; + +static int adv748x_write_regs(struct adv748x_state *state, + const struct adv748x_reg_value *regs) +{ + int ret; + + while (regs->page != ADV748X_PAGE_EOR) { + if (regs->page == ADV748X_PAGE_WAIT) { + msleep(regs->value); + } else { + ret = adv748x_write(state, regs->page, regs->reg, + regs->value); + if (ret < 0) { + adv_err(state, + "Error regs page: 0x%02x reg: 0x%02x\n", + regs->page, regs->reg); + return ret; + } + } + regs++; + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * TXA and TXB + */ + +static const struct adv748x_reg_value adv748x_power_up_txa_4lane[] = { + + {ADV748X_PAGE_TXA, 0x00, 0x84}, /* Enable 4-lane MIPI */ + {ADV748X_PAGE_TXA, 0x00, 0xa4}, /* Set Auto DPHY Timing */ + + {ADV748X_PAGE_TXA, 0x31, 0x82}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0x1e, 0x40}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ + {ADV748X_PAGE_WAIT, 0x00, 0x02},/* delay 2 */ + {ADV748X_PAGE_TXA, 0x00, 0x24 },/* Power-up CSI-TX */ + {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ + {ADV748X_PAGE_TXA, 0xc1, 0x2b}, /* ADI Required Write */ + {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ + {ADV748X_PAGE_TXA, 0x31, 0x80}, /* ADI Required Write */ + + {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ +}; + +static const struct adv748x_reg_value adv748x_power_down_txa_4lane[] = { + + {ADV748X_PAGE_TXA, 0x31, 0x82}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0x1e, 0x00}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0x00, 0x84}, /* Enable 4-lane MIPI */ + {ADV748X_PAGE_TXA, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ + {ADV748X_PAGE_TXA, 0xc1, 0x3b}, /* ADI Required Write */ + + {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ +}; + +static const struct adv748x_reg_value adv748x_power_up_txb_1lane[] = { + + {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */ + {ADV748X_PAGE_TXB, 0x00, 0xa1}, /* Set Auto DPHY Timing */ + + {ADV748X_PAGE_TXB, 0x31, 0x82}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0x1e, 0x40}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ + {ADV748X_PAGE_WAIT, 0x00, 0x02},/* delay 2 */ + {ADV748X_PAGE_TXB, 0x00, 0x21 },/* Power-up CSI-TX */ + {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ + {ADV748X_PAGE_TXB, 0xc1, 0x2b}, /* ADI Required Write */ + {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ + {ADV748X_PAGE_TXB, 0x31, 0x80}, /* ADI Required Write */ + + {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ +}; + +static const struct adv748x_reg_value adv748x_power_down_txb_1lane[] = { + + {ADV748X_PAGE_TXB, 0x31, 0x82}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0x1e, 0x00}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 4-lane MIPI */ + {ADV748X_PAGE_TXB, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ + {ADV748X_PAGE_TXB, 0xc1, 0x3b}, /* ADI Required Write */ + + {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ +}; + +int adv748x_txa_power(struct adv748x_state *state, bool on) +{ + int val; + + val = txa_read(state, ADV748X_CSI_FS_AS_LS); + if (val < 0) + return val; + + /* + * This test against BIT(6) is not documented by the datasheet, but was + * specified in the downstream driver. + * Track with a WARN_ONCE to determine if it is ever set by HW. + */ + WARN_ONCE((on && val & ADV748X_CSI_FS_AS_LS_UNKNOWN), + "Enabling with unknown bit set"); + + if (on) + return adv748x_write_regs(state, adv748x_power_up_txa_4lane); + + return adv748x_write_regs(state, adv748x_power_down_txa_4lane); +} + +int adv748x_txb_power(struct adv748x_state *state, bool on) +{ + int val; + + val = txb_read(state, ADV748X_CSI_FS_AS_LS); + if (val < 0) + return val; + + /* + * This test against BIT(6) is not documented by the datasheet, but was + * specified in the downstream driver. + * Track with a WARN_ONCE to determine if it is ever set by HW. + */ + WARN_ONCE((on && val & ADV748X_CSI_FS_AS_LS_UNKNOWN), + "Enabling with unknown bit set"); + + if (on) + return adv748x_write_regs(state, adv748x_power_up_txb_1lane); + + return adv748x_write_regs(state, adv748x_power_down_txb_1lane); +} + +/* ----------------------------------------------------------------------------- + * Media Operations + */ + +static const struct media_entity_operations adv748x_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* ----------------------------------------------------------------------------- + * HW setup + */ + +static const struct adv748x_reg_value adv748x_sw_reset[] = { + + {ADV748X_PAGE_IO, 0xff, 0xff}, /* SW reset */ + {ADV748X_PAGE_WAIT, 0x00, 0x05},/* delay 5 */ + {ADV748X_PAGE_IO, 0x01, 0x76}, /* ADI Required Write */ + {ADV748X_PAGE_IO, 0xf2, 0x01}, /* Enable I2C Read Auto-Increment */ + {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ +}; + +static const struct adv748x_reg_value adv748x_set_slave_address[] = { + {ADV748X_PAGE_IO, 0xf3, ADV748X_I2C_DPLL << 1}, + {ADV748X_PAGE_IO, 0xf4, ADV748X_I2C_CP << 1}, + {ADV748X_PAGE_IO, 0xf5, ADV748X_I2C_HDMI << 1}, + {ADV748X_PAGE_IO, 0xf6, ADV748X_I2C_EDID << 1}, + {ADV748X_PAGE_IO, 0xf7, ADV748X_I2C_REPEATER << 1}, + {ADV748X_PAGE_IO, 0xf8, ADV748X_I2C_INFOFRAME << 1}, + {ADV748X_PAGE_IO, 0xfa, ADV748X_I2C_CEC << 1}, + {ADV748X_PAGE_IO, 0xfb, ADV748X_I2C_SDP << 1}, + {ADV748X_PAGE_IO, 0xfc, ADV748X_I2C_TXB << 1}, + {ADV748X_PAGE_IO, 0xfd, ADV748X_I2C_TXA << 1}, + {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ +}; + +/* Supported Formats For Script Below */ +/* - 01-29 HDMI to MIPI TxA CSI 4-Lane - RGB888: */ +static const struct adv748x_reg_value adv748x_init_txa_4lane[] = { + /* Disable chip powerdown & Enable HDMI Rx block */ + {ADV748X_PAGE_IO, 0x00, 0x40}, + + {ADV748X_PAGE_REPEATER, 0x40, 0x83}, /* Enable HDCP 1.1 */ + + {ADV748X_PAGE_HDMI, 0x00, 0x08},/* Foreground Channel = A */ + {ADV748X_PAGE_HDMI, 0x98, 0xff},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0x99, 0xa3},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0x9a, 0x00},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0x9b, 0x0a},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0x9d, 0x40},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0xcb, 0x09},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0x3d, 0x10},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0x3e, 0x7b},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0x3f, 0x5e},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0x4e, 0xfe},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0x4f, 0x18},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0x57, 0xa3},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0x58, 0x04},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0x85, 0x10},/* ADI Required Write */ + + {ADV748X_PAGE_HDMI, 0x83, 0x00},/* Enable All Terminations */ + {ADV748X_PAGE_HDMI, 0xa3, 0x01},/* ADI Required Write */ + {ADV748X_PAGE_HDMI, 0xbe, 0x00},/* ADI Required Write */ + + {ADV748X_PAGE_HDMI, 0x6c, 0x01},/* HPA Manual Enable */ + {ADV748X_PAGE_HDMI, 0xf8, 0x01},/* HPA Asserted */ + {ADV748X_PAGE_HDMI, 0x0f, 0x00},/* Audio Mute Speed Set to Fastest */ + /* (Smallest Step Size) */ + + {ADV748X_PAGE_IO, 0x04, 0x02}, /* RGB Out of CP */ + {ADV748X_PAGE_IO, 0x12, 0xf0}, /* CSC Depends on ip Packets, SDR 444 */ + {ADV748X_PAGE_IO, 0x17, 0x80}, /* Luma & Chroma can reach 254d */ + {ADV748X_PAGE_IO, 0x03, 0x86}, /* CP-Insert_AV_Code */ + + {ADV748X_PAGE_CP, 0x7c, 0x00}, /* ADI Required Write */ + + {ADV748X_PAGE_IO, 0x0c, 0xe0}, /* Enable LLC_DLL & Double LLC Timing */ + {ADV748X_PAGE_IO, 0x0e, 0xdd}, /* LLC/PIX/SPI PINS TRISTATED AUD */ + /* Outputs Enabled */ + {ADV748X_PAGE_IO, 0x10, 0xa0}, /* Enable 4-lane CSI Tx & Pixel Port */ + + {ADV748X_PAGE_TXA, 0x00, 0x84}, /* Enable 4-lane MIPI */ + {ADV748X_PAGE_TXA, 0x00, 0xa4}, /* Set Auto DPHY Timing */ + {ADV748X_PAGE_TXA, 0xdb, 0x10}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0xd6, 0x07}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0xc4, 0x0a}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0x71, 0x33}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0x72, 0x11}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0xf0, 0x00}, /* i2c_dphy_pwdn - 1'b0 */ + + {ADV748X_PAGE_TXA, 0x31, 0x82}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0x1e, 0x40}, /* ADI Required Write */ + {ADV748X_PAGE_TXA, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ + {ADV748X_PAGE_WAIT, 0x00, 0x02},/* delay 2 */ + {ADV748X_PAGE_TXA, 0x00, 0x24 },/* Power-up CSI-TX */ + {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ + {ADV748X_PAGE_TXA, 0xc1, 0x2b}, /* ADI Required Write */ + {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ + {ADV748X_PAGE_TXA, 0x31, 0x80}, /* ADI Required Write */ + + {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ +}; + +/* 02-01 Analog CVBS to MIPI TX-B CSI 1-Lane - */ +/* Autodetect CVBS Single Ended In Ain 1 - MIPI Out */ +static const struct adv748x_reg_value adv748x_init_txb_1lane[] = { + + {ADV748X_PAGE_IO, 0x00, 0x30}, /* Disable chip powerdown Rx */ + {ADV748X_PAGE_IO, 0xf2, 0x01}, /* Enable I2C Read Auto-Increment */ + + {ADV748X_PAGE_IO, 0x0e, 0xff}, /* LLC/PIX/AUD/SPI PINS TRISTATED */ + + {ADV748X_PAGE_SDP, 0x0f, 0x00}, /* Exit Power Down Mode */ + {ADV748X_PAGE_SDP, 0x52, 0xcd}, /* ADI Required Write */ + + {ADV748X_PAGE_SDP, 0x0e, 0x80}, /* ADI Required Write */ + {ADV748X_PAGE_SDP, 0x9c, 0x00}, /* ADI Required Write */ + {ADV748X_PAGE_SDP, 0x9c, 0xff}, /* ADI Required Write */ + {ADV748X_PAGE_SDP, 0x0e, 0x00}, /* ADI Required Write */ + + /* ADI recommended writes for improved video quality */ + {ADV748X_PAGE_SDP, 0x80, 0x51}, /* ADI Required Write */ + {ADV748X_PAGE_SDP, 0x81, 0x51}, /* ADI Required Write */ + {ADV748X_PAGE_SDP, 0x82, 0x68}, /* ADI Required Write */ + + {ADV748X_PAGE_SDP, 0x03, 0x42}, /* Tri-S Output , PwrDwn 656 pads */ + {ADV748X_PAGE_SDP, 0x04, 0xb5}, /* ITU-R BT.656-4 compatible */ + {ADV748X_PAGE_SDP, 0x13, 0x00}, /* ADI Required Write */ + + {ADV748X_PAGE_SDP, 0x17, 0x41}, /* Select SH1 */ + {ADV748X_PAGE_SDP, 0x31, 0x12}, /* ADI Required Write */ + {ADV748X_PAGE_SDP, 0xe6, 0x4f}, /* V bit end pos manually in NTSC */ + + /* Enable 1-Lane MIPI Tx, */ + /* enable pixel output and route SD through Pixel port */ + {ADV748X_PAGE_IO, 0x10, 0x70}, + + {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */ + {ADV748X_PAGE_TXB, 0x00, 0xa1}, /* Set Auto DPHY Timing */ + {ADV748X_PAGE_TXB, 0xd2, 0x40}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0xc4, 0x0a}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0x71, 0x33}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0x72, 0x11}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0xf0, 0x00}, /* i2c_dphy_pwdn - 1'b0 */ + {ADV748X_PAGE_TXB, 0x31, 0x82}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0x1e, 0x40}, /* ADI Required Write */ + {ADV748X_PAGE_TXB, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ + + {ADV748X_PAGE_WAIT, 0x00, 0x02},/* delay 2 */ + {ADV748X_PAGE_TXB, 0x00, 0x21 },/* Power-up CSI-TX */ + {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ + {ADV748X_PAGE_TXB, 0xc1, 0x2b}, /* ADI Required Write */ + {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ + {ADV748X_PAGE_TXB, 0x31, 0x80}, /* ADI Required Write */ + + {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ +}; + +static int adv748x_reset(struct adv748x_state *state) +{ + int ret; + + ret = adv748x_write_regs(state, adv748x_sw_reset); + if (ret < 0) + return ret; + + ret = adv748x_write_regs(state, adv748x_set_slave_address); + if (ret < 0) + return ret; + + /* Init and power down TXA */ + ret = adv748x_write_regs(state, adv748x_init_txa_4lane); + if (ret) + return ret; + + adv748x_txa_power(state, 0); + + /* Init and power down TXB */ + ret = adv748x_write_regs(state, adv748x_init_txb_1lane); + if (ret) + return ret; + + adv748x_txb_power(state, 0); + + /* Disable chip powerdown & Enable HDMI Rx block */ + io_write(state, ADV748X_IO_PD, ADV748X_IO_PD_RX_EN); + + /* Enable 4-lane CSI Tx & Pixel Port */ + io_write(state, ADV748X_IO_10, ADV748X_IO_10_CSI4_EN | + ADV748X_IO_10_CSI1_EN | + ADV748X_IO_10_PIX_OUT_EN); + + /* Use vid_std and v_freq as freerun resolution for CP */ + cp_clrset(state, ADV748X_CP_CLMP_POS, ADV748X_CP_CLMP_POS_DIS_AUTO, + ADV748X_CP_CLMP_POS_DIS_AUTO); + + return 0; +} + +static int adv748x_identify_chip(struct adv748x_state *state) +{ + int msb, lsb; + + lsb = io_read(state, ADV748X_IO_CHIP_REV_ID_1); + msb = io_read(state, ADV748X_IO_CHIP_REV_ID_2); + + if (lsb < 0 || msb < 0) { + adv_err(state, "Failed to read chip revision\n"); + return -EIO; + } + + adv_info(state, "chip found @ 0x%02x revision %02x%02x\n", + state->client->addr << 1, lsb, msb); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * i2c driver + */ + +void adv748x_subdev_init(struct v4l2_subdev *sd, struct adv748x_state *state, + const struct v4l2_subdev_ops *ops, u32 function, + const char *ident) +{ + v4l2_subdev_init(sd, ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + /* the owner is the same as the i2c_client's driver owner */ + sd->owner = state->dev->driver->owner; + sd->dev = state->dev; + + v4l2_set_subdevdata(sd, state); + + /* initialize name */ + snprintf(sd->name, sizeof(sd->name), "%s %d-%04x %s", + state->dev->driver->name, + i2c_adapter_id(state->client->adapter), + state->client->addr, ident); + + sd->entity.function = function; + sd->entity.ops = &adv748x_media_ops; +} + +static int adv748x_parse_dt(struct adv748x_state *state) +{ + struct device_node *ep_np = NULL; + struct of_endpoint ep; + bool found = false; + + for_each_endpoint_of_node(state->dev->of_node, ep_np) { + of_graph_parse_endpoint(ep_np, &ep); + adv_info(state, "Endpoint %s on port %d", + of_node_full_name(ep.local_node), + ep.port); + + if (ep.port >= ADV748X_PORT_MAX) { + adv_err(state, "Invalid endpoint %s on port %d", + of_node_full_name(ep.local_node), + ep.port); + + continue; + } + + if (state->endpoints[ep.port]) { + adv_err(state, + "Multiple port endpoints are not supported"); + continue; + } + + of_node_get(ep_np); + state->endpoints[ep.port] = ep_np; + + found = true; + } + + return found ? 0 : -ENODEV; +} + +static void adv748x_dt_cleanup(struct adv748x_state *state) +{ + unsigned int i; + + for (i = 0; i < ADV748X_PORT_MAX; i++) + of_node_put(state->endpoints[i]); +} + +static int adv748x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adv748x_state *state; + int ret; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + state = kzalloc(sizeof(struct adv748x_state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + mutex_init(&state->mutex); + + state->dev = &client->dev; + state->client = client; + state->i2c_clients[ADV748X_PAGE_IO] = client; + i2c_set_clientdata(client, state); + + /* Discover and process ports declared by the Device tree endpoints */ + ret = adv748x_parse_dt(state); + if (ret) { + adv_err(state, "Failed to parse device tree"); + goto err_free_mutex; + } + + /* Configure IO Regmap region */ + ret = adv748x_configure_regmap(state, ADV748X_PAGE_IO); + if (ret) { + adv_err(state, "Error configuring IO regmap region"); + goto err_cleanup_dt; + } + + ret = adv748x_identify_chip(state); + if (ret) { + adv_err(state, "Failed to identify chip"); + goto err_cleanup_clients; + } + + /* Configure remaining pages as I2C clients with regmap access */ + ret = adv748x_initialise_clients(state); + if (ret) { + adv_err(state, "Failed to setup client regmap pages"); + goto err_cleanup_clients; + } + + /* SW reset ADV748X to its default values */ + ret = adv748x_reset(state); + if (ret) { + adv_err(state, "Failed to reset hardware"); + goto err_cleanup_clients; + } + + /* Initialise HDMI */ + ret = adv748x_hdmi_init(&state->hdmi); + if (ret) { + adv_err(state, "Failed to probe HDMI"); + goto err_cleanup_clients; + } + + /* Initialise AFE */ + ret = adv748x_afe_init(&state->afe); + if (ret) { + adv_err(state, "Failed to probe AFE"); + goto err_cleanup_hdmi; + } + + /* Initialise TXA */ + ret = adv748x_csi2_init(state, &state->txa); + if (ret) { + adv_err(state, "Failed to probe TXA"); + goto err_cleanup_afe; + } + + /* Initialise TXB */ + ret = adv748x_csi2_init(state, &state->txb); + if (ret) { + adv_err(state, "Failed to probe TXB"); + goto err_cleanup_txa; + } + + return 0; + +err_cleanup_txa: + adv748x_csi2_cleanup(&state->txa); +err_cleanup_afe: + adv748x_afe_cleanup(&state->afe); +err_cleanup_hdmi: + adv748x_hdmi_cleanup(&state->hdmi); +err_cleanup_clients: + adv748x_unregister_clients(state); +err_cleanup_dt: + adv748x_dt_cleanup(state); +err_free_mutex: + mutex_destroy(&state->mutex); + kfree(state); + + return ret; +} + +static int adv748x_remove(struct i2c_client *client) +{ + struct adv748x_state *state = i2c_get_clientdata(client); + + adv748x_afe_cleanup(&state->afe); + adv748x_hdmi_cleanup(&state->hdmi); + + adv748x_csi2_cleanup(&state->txa); + adv748x_csi2_cleanup(&state->txb); + + adv748x_unregister_clients(state); + adv748x_dt_cleanup(state); + mutex_destroy(&state->mutex); + + kfree(state); + + return 0; +} + +static const struct i2c_device_id adv748x_id[] = { + { "adv7481", 0 }, + { "adv7482", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, adv748x_id); + +static const struct of_device_id adv748x_of_table[] = { + { .compatible = "adi,adv7481", }, + { .compatible = "adi,adv7482", }, + { } +}; +MODULE_DEVICE_TABLE(of, adv748x_of_table); + +static struct i2c_driver adv748x_driver = { + .driver = { + .name = "adv748x", + .of_match_table = adv748x_of_table, + }, + .probe = adv748x_probe, + .remove = adv748x_remove, + .id_table = adv748x_id, +}; + +module_i2c_driver(adv748x_driver); + +MODULE_AUTHOR("Kieran Bingham <kieran.bingham@ideasonboard.com>"); +MODULE_DESCRIPTION("ADV748X video decoder"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c new file mode 100644 index 000000000000..979825d4a419 --- /dev/null +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c @@ -0,0 +1,326 @@ +/* + * Driver for Analog Devices ADV748X CSI-2 Transmitter + * + * Copyright (C) 2017 Renesas Electronics Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/mutex.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> + +#include "adv748x.h" + +static bool is_txa(struct adv748x_csi2 *tx) +{ + return tx == &tx->state->txa; +} + +static int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, + unsigned int vc) +{ + return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT); +} + +/** + * adv748x_csi2_register_link : Register and link internal entities + * + * @tx: CSI2 private entity + * @v4l2_dev: Video registration device + * @src: Source subdevice to establish link + * @src_pad: Pad number of source to link to this @tx + * + * Ensure that the subdevice is registered against the v4l2_device, and link the + * source pad to the sink pad of the CSI2 bus entity. + */ +static int adv748x_csi2_register_link(struct adv748x_csi2 *tx, + struct v4l2_device *v4l2_dev, + struct v4l2_subdev *src, + unsigned int src_pad) +{ + int enabled = MEDIA_LNK_FL_ENABLED; + int ret; + + /* + * Dynamic linking of the AFE is not supported. + * Register the links as immutable. + */ + enabled |= MEDIA_LNK_FL_IMMUTABLE; + + if (!src->v4l2_dev) { + ret = v4l2_device_register_subdev(v4l2_dev, src); + if (ret) + return ret; + } + + return media_create_pad_link(&src->entity, src_pad, + &tx->sd.entity, ADV748X_CSI2_SINK, + enabled); +} + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_internal_ops + * + * We use the internal registered operation to be able to ensure that our + * incremental subdevices (not connected in the forward path) can be registered + * against the resulting video path and media device. + */ + +static int adv748x_csi2_registered(struct v4l2_subdev *sd) +{ + struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); + struct adv748x_state *state = tx->state; + + adv_dbg(state, "Registered %s (%s)", is_txa(tx) ? "TXA":"TXB", + sd->name); + + /* + * The adv748x hardware allows the AFE to route through the TXA, however + * this is not currently supported in this driver. + * + * Link HDMI->TXA, and AFE->TXB directly. + */ + if (is_txa(tx)) { + return adv748x_csi2_register_link(tx, sd->v4l2_dev, + &state->hdmi.sd, + ADV748X_HDMI_SOURCE); + } else { + return adv748x_csi2_register_link(tx, sd->v4l2_dev, + &state->afe.sd, + ADV748X_AFE_SOURCE); + } +} + +static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = { + .registered = adv748x_csi2_registered, +}; + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_video_ops + */ + +static int adv748x_csi2_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); + struct v4l2_subdev *src; + + src = adv748x_get_remote_sd(&tx->pads[ADV748X_CSI2_SINK]); + if (!src) + return -EPIPE; + + return v4l2_subdev_call(src, video, s_stream, enable); +} + +static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = { + .s_stream = adv748x_csi2_s_stream, +}; + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_pad_ops + * + * The CSI2 bus pads are ignorant to the data sizes or formats. + * But we must support setting the pad formats for format propagation. + */ + +static struct v4l2_mbus_framefmt * +adv748x_csi2_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, u32 which) +{ + struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); + + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(sd, cfg, pad); + + return &tx->format; +} + +static int adv748x_csi2_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *sdformat) +{ + struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); + struct adv748x_state *state = tx->state; + struct v4l2_mbus_framefmt *mbusformat; + + mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad, + sdformat->which); + if (!mbusformat) + return -EINVAL; + + mutex_lock(&state->mutex); + + sdformat->format = *mbusformat; + + mutex_unlock(&state->mutex); + + return 0; +} + +static int adv748x_csi2_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *sdformat) +{ + struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); + struct adv748x_state *state = tx->state; + struct v4l2_mbus_framefmt *mbusformat; + int ret = 0; + + mbusformat = adv748x_csi2_get_pad_format(sd, cfg, sdformat->pad, + sdformat->which); + if (!mbusformat) + return -EINVAL; + + mutex_lock(&state->mutex); + + if (sdformat->pad == ADV748X_CSI2_SOURCE) { + const struct v4l2_mbus_framefmt *sink_fmt; + + sink_fmt = adv748x_csi2_get_pad_format(sd, cfg, + ADV748X_CSI2_SINK, + sdformat->which); + + if (!sink_fmt) { + ret = -EINVAL; + goto unlock; + } + + sdformat->format = *sink_fmt; + } + + *mbusformat = sdformat->format; + +unlock: + mutex_unlock(&state->mutex); + + return ret; +} + +static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = { + .get_fmt = adv748x_csi2_get_format, + .set_fmt = adv748x_csi2_set_format, +}; + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_ops + */ + +static const struct v4l2_subdev_ops adv748x_csi2_ops = { + .video = &adv748x_csi2_video_ops, + .pad = &adv748x_csi2_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * Subdev module and controls + */ + +int adv748x_csi2_set_pixelrate(struct v4l2_subdev *sd, s64 rate) +{ + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_PIXEL_RATE); + if (!ctrl) + return -EINVAL; + + return v4l2_ctrl_s_ctrl_int64(ctrl, rate); +} + +static int adv748x_csi2_s_ctrl(struct v4l2_ctrl *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_PIXEL_RATE: + return 0; + default: + return -EINVAL; + } +} + +static const struct v4l2_ctrl_ops adv748x_csi2_ctrl_ops = { + .s_ctrl = adv748x_csi2_s_ctrl, +}; + +static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx) +{ + + v4l2_ctrl_handler_init(&tx->ctrl_hdl, 1); + + v4l2_ctrl_new_std(&tx->ctrl_hdl, &adv748x_csi2_ctrl_ops, + V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); + + tx->sd.ctrl_handler = &tx->ctrl_hdl; + if (tx->ctrl_hdl.error) { + v4l2_ctrl_handler_free(&tx->ctrl_hdl); + return tx->ctrl_hdl.error; + } + + return v4l2_ctrl_handler_setup(&tx->ctrl_hdl); +} + +int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx) +{ + struct device_node *ep; + int ret; + + /* We can not use container_of to get back to the state with two TXs */ + tx->state = state; + tx->page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB; + + ep = state->endpoints[is_txa(tx) ? ADV748X_PORT_TXA : ADV748X_PORT_TXB]; + if (!ep) { + adv_err(state, "No endpoint found for %s\n", + is_txa(tx) ? "txa" : "txb"); + return -ENODEV; + } + + /* Initialise the virtual channel */ + adv748x_csi2_set_virtual_channel(tx, 0); + + adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops, + MEDIA_ENT_F_UNKNOWN, + is_txa(tx) ? "txa" : "txb"); + + /* Ensure that matching is based upon the endpoint fwnodes */ + tx->sd.fwnode = of_fwnode_handle(ep); + + /* Register internal ops for incremental subdev registration */ + tx->sd.internal_ops = &adv748x_csi2_internal_ops; + + tx->pads[ADV748X_CSI2_SINK].flags = MEDIA_PAD_FL_SINK; + tx->pads[ADV748X_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&tx->sd.entity, ADV748X_CSI2_NR_PADS, + tx->pads); + if (ret) + return ret; + + ret = adv748x_csi2_init_controls(tx); + if (ret) + goto err_free_media; + + ret = v4l2_async_register_subdev(&tx->sd); + if (ret) + goto err_free_ctrl; + + return 0; + +err_free_ctrl: + v4l2_ctrl_handler_free(&tx->ctrl_hdl); +err_free_media: + media_entity_cleanup(&tx->sd.entity); + + return ret; +} + +void adv748x_csi2_cleanup(struct adv748x_csi2 *tx) +{ + v4l2_async_unregister_subdev(&tx->sd); + media_entity_cleanup(&tx->sd.entity); + v4l2_ctrl_handler_free(&tx->ctrl_hdl); +} diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c new file mode 100644 index 000000000000..4da4253553fc --- /dev/null +++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c @@ -0,0 +1,768 @@ +/* + * Driver for Analog Devices ADV748X HDMI receiver and Component Processor (CP) + * + * Copyright (C) 2017 Renesas Electronics Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/mutex.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-dv-timings.h> +#include <media/v4l2-ioctl.h> + +#include <uapi/linux/v4l2-dv-timings.h> + +#include "adv748x.h" + +/* ----------------------------------------------------------------------------- + * HDMI and CP + */ + +#define ADV748X_HDMI_MIN_WIDTH 640 +#define ADV748X_HDMI_MAX_WIDTH 1920 +#define ADV748X_HDMI_MIN_HEIGHT 480 +#define ADV748X_HDMI_MAX_HEIGHT 1200 + +/* V4L2_DV_BT_CEA_720X480I59_94 - 0.5 MHz */ +#define ADV748X_HDMI_MIN_PIXELCLOCK 13000000 +/* V4L2_DV_BT_DMT_1600X1200P60 */ +#define ADV748X_HDMI_MAX_PIXELCLOCK 162000000 + +static const struct v4l2_dv_timings_cap adv748x_hdmi_timings_cap = { + .type = V4L2_DV_BT_656_1120, + /* keep this initialization for compatibility with GCC < 4.4.6 */ + .reserved = { 0 }, + + V4L2_INIT_BT_TIMINGS(ADV748X_HDMI_MIN_WIDTH, ADV748X_HDMI_MAX_WIDTH, + ADV748X_HDMI_MIN_HEIGHT, ADV748X_HDMI_MAX_HEIGHT, + ADV748X_HDMI_MIN_PIXELCLOCK, + ADV748X_HDMI_MAX_PIXELCLOCK, + V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT, + V4L2_DV_BT_CAP_PROGRESSIVE) +}; + +struct adv748x_hdmi_video_standards { + struct v4l2_dv_timings timings; + u8 vid_std; + u8 v_freq; +}; + +static const struct adv748x_hdmi_video_standards +adv748x_hdmi_video_standards[] = { + { V4L2_DV_BT_CEA_720X480P59_94, 0x4a, 0x00 }, + { V4L2_DV_BT_CEA_720X576P50, 0x4b, 0x00 }, + { V4L2_DV_BT_CEA_1280X720P60, 0x53, 0x00 }, + { V4L2_DV_BT_CEA_1280X720P50, 0x53, 0x01 }, + { V4L2_DV_BT_CEA_1280X720P30, 0x53, 0x02 }, + { V4L2_DV_BT_CEA_1280X720P25, 0x53, 0x03 }, + { V4L2_DV_BT_CEA_1280X720P24, 0x53, 0x04 }, + { V4L2_DV_BT_CEA_1920X1080P60, 0x5e, 0x00 }, + { V4L2_DV_BT_CEA_1920X1080P50, 0x5e, 0x01 }, + { V4L2_DV_BT_CEA_1920X1080P30, 0x5e, 0x02 }, + { V4L2_DV_BT_CEA_1920X1080P25, 0x5e, 0x03 }, + { V4L2_DV_BT_CEA_1920X1080P24, 0x5e, 0x04 }, + /* SVGA */ + { V4L2_DV_BT_DMT_800X600P56, 0x80, 0x00 }, + { V4L2_DV_BT_DMT_800X600P60, 0x81, 0x00 }, + { V4L2_DV_BT_DMT_800X600P72, 0x82, 0x00 }, + { V4L2_DV_BT_DMT_800X600P75, 0x83, 0x00 }, + { V4L2_DV_BT_DMT_800X600P85, 0x84, 0x00 }, + /* SXGA */ + { V4L2_DV_BT_DMT_1280X1024P60, 0x85, 0x00 }, + { V4L2_DV_BT_DMT_1280X1024P75, 0x86, 0x00 }, + /* VGA */ + { V4L2_DV_BT_DMT_640X480P60, 0x88, 0x00 }, + { V4L2_DV_BT_DMT_640X480P72, 0x89, 0x00 }, + { V4L2_DV_BT_DMT_640X480P75, 0x8a, 0x00 }, + { V4L2_DV_BT_DMT_640X480P85, 0x8b, 0x00 }, + /* XGA */ + { V4L2_DV_BT_DMT_1024X768P60, 0x8c, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P70, 0x8d, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P75, 0x8e, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P85, 0x8f, 0x00 }, + /* UXGA */ + { V4L2_DV_BT_DMT_1600X1200P60, 0x96, 0x00 }, +}; + +static void adv748x_hdmi_fill_format(struct adv748x_hdmi *hdmi, + struct v4l2_mbus_framefmt *fmt) +{ + memset(fmt, 0, sizeof(*fmt)); + + fmt->code = MEDIA_BUS_FMT_RGB888_1X24; + fmt->field = hdmi->timings.bt.interlaced ? + V4L2_FIELD_ALTERNATE : V4L2_FIELD_NONE; + + /* TODO: The colorspace depends on the AVI InfoFrame contents */ + fmt->colorspace = V4L2_COLORSPACE_SRGB; + + fmt->width = hdmi->timings.bt.width; + fmt->height = hdmi->timings.bt.height; +} + +static void adv748x_fill_optional_dv_timings(struct v4l2_dv_timings *timings) +{ + v4l2_find_dv_timings_cap(timings, &adv748x_hdmi_timings_cap, + 250000, NULL, NULL); +} + +static bool adv748x_hdmi_has_signal(struct adv748x_state *state) +{ + int val; + + /* Check that VERT_FILTER and DE_REGEN is locked */ + val = hdmi_read(state, ADV748X_HDMI_LW1); + return (val & ADV748X_HDMI_LW1_VERT_FILTER) && + (val & ADV748X_HDMI_LW1_DE_REGEN); +} + +static int adv748x_hdmi_read_pixelclock(struct adv748x_state *state) +{ + int a, b; + + a = hdmi_read(state, ADV748X_HDMI_TMDS_1); + b = hdmi_read(state, ADV748X_HDMI_TMDS_2); + if (a < 0 || b < 0) + return -ENODATA; + + /* + * The high 9 bits store TMDS frequency measurement in MHz + * The low 7 bits of TMDS_2 store the 7-bit TMDS fractional frequency + * measurement in 1/128 MHz + */ + return ((a << 1) | (b >> 7)) * 1000000 + (b & 0x7f) * 1000000 / 128; +} + +/* + * adv748x_hdmi_set_de_timings: Adjust horizontal picture offset through DE + * + * HDMI CP uses a Data Enable synchronisation timing reference + * + * Vary the leading and trailing edge position of the DE signal output by the CP + * core. Values are stored as signed-twos-complement in one-pixel-clock units + * + * The start and end are shifted equally by the 10-bit shift value. + */ +static void adv748x_hdmi_set_de_timings(struct adv748x_state *state, int shift) +{ + u8 high, low; + + /* POS_HIGH stores bits 8 and 9 of both the start and end */ + high = ADV748X_CP_DE_POS_HIGH_SET; + high |= (shift & 0x300) >> 8; + low = shift & 0xff; + + /* The sequence of the writes is important and must be followed */ + cp_write(state, ADV748X_CP_DE_POS_HIGH, high); + cp_write(state, ADV748X_CP_DE_POS_END_LOW, low); + + high |= (shift & 0x300) >> 6; + + cp_write(state, ADV748X_CP_DE_POS_HIGH, high); + cp_write(state, ADV748X_CP_DE_POS_START_LOW, low); +} + +static int adv748x_hdmi_set_video_timings(struct adv748x_state *state, + const struct v4l2_dv_timings *timings) +{ + const struct adv748x_hdmi_video_standards *stds = + adv748x_hdmi_video_standards; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(adv748x_hdmi_video_standards); i++) { + if (!v4l2_match_dv_timings(timings, &stds[i].timings, 250000, + false)) + continue; + } + + if (i >= ARRAY_SIZE(adv748x_hdmi_video_standards)) + return -EINVAL; + + /* + * When setting cp_vid_std to either 720p, 1080i, or 1080p, the video + * will get shifted horizontally to the left in active video mode. + * The de_h_start and de_h_end controls are used to centre the picture + * correctly + */ + switch (stds[i].vid_std) { + case 0x53: /* 720p */ + adv748x_hdmi_set_de_timings(state, -40); + break; + case 0x54: /* 1080i */ + case 0x5e: /* 1080p */ + adv748x_hdmi_set_de_timings(state, -44); + break; + default: + adv748x_hdmi_set_de_timings(state, 0); + break; + } + + io_write(state, ADV748X_IO_VID_STD, stds[i].vid_std); + io_clrset(state, ADV748X_IO_DATAPATH, ADV748X_IO_DATAPATH_VFREQ_M, + stds[i].v_freq << ADV748X_IO_DATAPATH_VFREQ_SHIFT); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_video_ops + */ + +static int adv748x_hdmi_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd); + struct adv748x_state *state = adv748x_hdmi_to_state(hdmi); + int ret; + + if (!timings) + return -EINVAL; + + if (v4l2_match_dv_timings(&hdmi->timings, timings, 0, false)) + return 0; + + if (!v4l2_valid_dv_timings(timings, &adv748x_hdmi_timings_cap, + NULL, NULL)) + return -ERANGE; + + adv748x_fill_optional_dv_timings(timings); + + mutex_lock(&state->mutex); + + ret = adv748x_hdmi_set_video_timings(state, timings); + if (ret) + goto error; + + hdmi->timings = *timings; + + cp_clrset(state, ADV748X_CP_VID_ADJ_2, ADV748X_CP_VID_ADJ_2_INTERLACED, + timings->bt.interlaced ? + ADV748X_CP_VID_ADJ_2_INTERLACED : 0); + + mutex_unlock(&state->mutex); + + return 0; + +error: + mutex_unlock(&state->mutex); + return ret; +} + +static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd); + struct adv748x_state *state = adv748x_hdmi_to_state(hdmi); + + mutex_lock(&state->mutex); + + *timings = hdmi->timings; + + mutex_unlock(&state->mutex); + + return 0; +} + +static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd); + struct adv748x_state *state = adv748x_hdmi_to_state(hdmi); + struct v4l2_bt_timings *bt = &timings->bt; + int pixelclock; + int polarity; + + if (!timings) + return -EINVAL; + + memset(timings, 0, sizeof(struct v4l2_dv_timings)); + + if (!adv748x_hdmi_has_signal(state)) + return -ENOLINK; + + pixelclock = adv748x_hdmi_read_pixelclock(state); + if (pixelclock < 0) + return -ENODATA; + + timings->type = V4L2_DV_BT_656_1120; + + bt->pixelclock = pixelclock; + bt->interlaced = hdmi_read(state, ADV748X_HDMI_F1H1) & + ADV748X_HDMI_F1H1_INTERLACED ? + V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; + bt->width = hdmi_read16(state, ADV748X_HDMI_LW1, + ADV748X_HDMI_LW1_WIDTH_MASK); + bt->height = hdmi_read16(state, ADV748X_HDMI_F0H1, + ADV748X_HDMI_F0H1_HEIGHT_MASK); + bt->hfrontporch = hdmi_read16(state, ADV748X_HDMI_HFRONT_PORCH, + ADV748X_HDMI_HFRONT_PORCH_MASK); + bt->hsync = hdmi_read16(state, ADV748X_HDMI_HSYNC_WIDTH, + ADV748X_HDMI_HSYNC_WIDTH_MASK); + bt->hbackporch = hdmi_read16(state, ADV748X_HDMI_HBACK_PORCH, + ADV748X_HDMI_HBACK_PORCH_MASK); + bt->vfrontporch = hdmi_read16(state, ADV748X_HDMI_VFRONT_PORCH, + ADV748X_HDMI_VFRONT_PORCH_MASK) / 2; + bt->vsync = hdmi_read16(state, ADV748X_HDMI_VSYNC_WIDTH, + ADV748X_HDMI_VSYNC_WIDTH_MASK) / 2; + bt->vbackporch = hdmi_read16(state, ADV748X_HDMI_VBACK_PORCH, + ADV748X_HDMI_VBACK_PORCH_MASK) / 2; + + polarity = hdmi_read(state, 0x05); + bt->polarities = (polarity & BIT(4) ? V4L2_DV_VSYNC_POS_POL : 0) | + (polarity & BIT(5) ? V4L2_DV_HSYNC_POS_POL : 0); + + if (bt->interlaced == V4L2_DV_INTERLACED) { + bt->height += hdmi_read16(state, 0x0b, 0x1fff); + bt->il_vfrontporch = hdmi_read16(state, 0x2c, 0x3fff) / 2; + bt->il_vsync = hdmi_read16(state, 0x30, 0x3fff) / 2; + bt->il_vbackporch = hdmi_read16(state, 0x34, 0x3fff) / 2; + } + + adv748x_fill_optional_dv_timings(timings); + + /* + * No interrupt handling is implemented yet. + * There should be an IRQ when a cable is plugged and the new timings + * should be figured out and stored to state. + */ + hdmi->timings = *timings; + + return 0; +} + +static int adv748x_hdmi_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd); + struct adv748x_state *state = adv748x_hdmi_to_state(hdmi); + + mutex_lock(&state->mutex); + + *status = adv748x_hdmi_has_signal(state) ? 0 : V4L2_IN_ST_NO_SIGNAL; + + mutex_unlock(&state->mutex); + + return 0; +} + +static int adv748x_hdmi_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd); + struct adv748x_state *state = adv748x_hdmi_to_state(hdmi); + int ret; + + mutex_lock(&state->mutex); + + ret = adv748x_txa_power(state, enable); + if (ret) + goto done; + + if (adv748x_hdmi_has_signal(state)) + adv_dbg(state, "Detected HDMI signal\n"); + else + adv_dbg(state, "Couldn't detect HDMI video signal\n"); + +done: + mutex_unlock(&state->mutex); + return ret; +} + +static int adv748x_hdmi_g_pixelaspect(struct v4l2_subdev *sd, + struct v4l2_fract *aspect) +{ + aspect->numerator = 1; + aspect->denominator = 1; + + return 0; +} + +static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi = { + .s_dv_timings = adv748x_hdmi_s_dv_timings, + .g_dv_timings = adv748x_hdmi_g_dv_timings, + .query_dv_timings = adv748x_hdmi_query_dv_timings, + .g_input_status = adv748x_hdmi_g_input_status, + .s_stream = adv748x_hdmi_s_stream, + .g_pixelaspect = adv748x_hdmi_g_pixelaspect, +}; + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_pad_ops + */ + +static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi *hdmi) +{ + struct v4l2_subdev *tx; + struct v4l2_dv_timings timings; + struct v4l2_bt_timings *bt = &timings.bt; + unsigned int fps; + + tx = adv748x_get_remote_sd(&hdmi->pads[ADV748X_HDMI_SOURCE]); + if (!tx) + return -ENOLINK; + + adv748x_hdmi_query_dv_timings(&hdmi->sd, &timings); + + fps = DIV_ROUND_CLOSEST_ULL(bt->pixelclock, + V4L2_DV_BT_FRAME_WIDTH(bt) * + V4L2_DV_BT_FRAME_HEIGHT(bt)); + + return adv748x_csi2_set_pixelrate(tx, bt->width * bt->height * fps); +} + +static int adv748x_hdmi_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index != 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_RGB888_1X24; + + return 0; +} + +static int adv748x_hdmi_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *sdformat) +{ + struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd); + struct v4l2_mbus_framefmt *mbusformat; + + if (sdformat->pad != ADV748X_HDMI_SOURCE) + return -EINVAL; + + if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) { + mbusformat = v4l2_subdev_get_try_format(sd, cfg, sdformat->pad); + sdformat->format = *mbusformat; + } else { + adv748x_hdmi_fill_format(hdmi, &sdformat->format); + adv748x_hdmi_propagate_pixelrate(hdmi); + } + + return 0; +} + +static int adv748x_hdmi_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *sdformat) +{ + struct v4l2_mbus_framefmt *mbusformat; + + if (sdformat->pad != ADV748X_HDMI_SOURCE) + return -EINVAL; + + if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return adv748x_hdmi_get_format(sd, cfg, sdformat); + + mbusformat = v4l2_subdev_get_try_format(sd, cfg, sdformat->pad); + *mbusformat = sdformat->format; + + return 0; +} + +static int adv748x_hdmi_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +{ + struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd); + + memset(edid->reserved, 0, sizeof(edid->reserved)); + + if (!hdmi->edid.present) + return -ENODATA; + + if (edid->start_block == 0 && edid->blocks == 0) { + edid->blocks = hdmi->edid.blocks; + return 0; + } + + if (edid->start_block >= hdmi->edid.blocks) + return -EINVAL; + + if (edid->start_block + edid->blocks > hdmi->edid.blocks) + edid->blocks = hdmi->edid.blocks - edid->start_block; + + memcpy(edid->edid, hdmi->edid.edid + edid->start_block * 128, + edid->blocks * 128); + + return 0; +} + +static inline int adv748x_hdmi_edid_write_block(struct adv748x_hdmi *hdmi, + unsigned int total_len, const u8 *val) +{ + struct adv748x_state *state = adv748x_hdmi_to_state(hdmi); + int err = 0; + int i = 0; + int len = 0; + + adv_dbg(state, "%s: write EDID block (%d byte)\n", + __func__, total_len); + + while (!err && i < total_len) { + len = (total_len - i) > I2C_SMBUS_BLOCK_MAX ? + I2C_SMBUS_BLOCK_MAX : + (total_len - i); + + err = adv748x_write_block(state, ADV748X_PAGE_EDID, + i, val + i, len); + i += len; + } + + return err; +} + +static int adv748x_hdmi_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +{ + struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd); + struct adv748x_state *state = adv748x_hdmi_to_state(hdmi); + int err; + + memset(edid->reserved, 0, sizeof(edid->reserved)); + + if (edid->start_block != 0) + return -EINVAL; + + if (edid->blocks == 0) { + hdmi->edid.blocks = 0; + hdmi->edid.present = 0; + + /* Fall back to a 16:9 aspect ratio */ + hdmi->aspect_ratio.numerator = 16; + hdmi->aspect_ratio.denominator = 9; + + /* Disable the EDID */ + repeater_write(state, ADV748X_REPEATER_EDID_SZ, + edid->blocks << ADV748X_REPEATER_EDID_SZ_SHIFT); + + repeater_write(state, ADV748X_REPEATER_EDID_CTL, 0); + + return 0; + } + + if (edid->blocks > 4) { + edid->blocks = 4; + return -E2BIG; + } + + memcpy(hdmi->edid.edid, edid->edid, 128 * edid->blocks); + hdmi->edid.blocks = edid->blocks; + hdmi->edid.present = true; + + hdmi->aspect_ratio = v4l2_calc_aspect_ratio(edid->edid[0x15], + edid->edid[0x16]); + + err = adv748x_hdmi_edid_write_block(hdmi, 128 * edid->blocks, + hdmi->edid.edid); + if (err < 0) { + v4l2_err(sd, "error %d writing edid pad %d\n", err, edid->pad); + return err; + } + + repeater_write(state, ADV748X_REPEATER_EDID_SZ, + edid->blocks << ADV748X_REPEATER_EDID_SZ_SHIFT); + + repeater_write(state, ADV748X_REPEATER_EDID_CTL, + ADV748X_REPEATER_EDID_CTL_EN); + + return 0; +} + +static bool adv748x_hdmi_check_dv_timings(const struct v4l2_dv_timings *timings, + void *hdl) +{ + const struct adv748x_hdmi_video_standards *stds = + adv748x_hdmi_video_standards; + unsigned int i; + + for (i = 0; stds[i].timings.bt.width; i++) + if (v4l2_match_dv_timings(timings, &stds[i].timings, 0, false)) + return true; + + return false; +} + +static int adv748x_hdmi_enum_dv_timings(struct v4l2_subdev *sd, + struct v4l2_enum_dv_timings *timings) +{ + return v4l2_enum_dv_timings_cap(timings, &adv748x_hdmi_timings_cap, + adv748x_hdmi_check_dv_timings, NULL); +} + +static int adv748x_hdmi_dv_timings_cap(struct v4l2_subdev *sd, + struct v4l2_dv_timings_cap *cap) +{ + *cap = adv748x_hdmi_timings_cap; + return 0; +} + +static const struct v4l2_subdev_pad_ops adv748x_pad_ops_hdmi = { + .enum_mbus_code = adv748x_hdmi_enum_mbus_code, + .set_fmt = adv748x_hdmi_set_format, + .get_fmt = adv748x_hdmi_get_format, + .get_edid = adv748x_hdmi_get_edid, + .set_edid = adv748x_hdmi_set_edid, + .dv_timings_cap = adv748x_hdmi_dv_timings_cap, + .enum_dv_timings = adv748x_hdmi_enum_dv_timings, +}; + +/* ----------------------------------------------------------------------------- + * v4l2_subdev_ops + */ + +static const struct v4l2_subdev_ops adv748x_ops_hdmi = { + .video = &adv748x_video_ops_hdmi, + .pad = &adv748x_pad_ops_hdmi, +}; + +/* ----------------------------------------------------------------------------- + * Controls + */ + +static const char * const hdmi_ctrl_patgen_menu[] = { + "Disabled", + "Solid Color", + "Color Bars", + "Ramp Grey", + "Ramp Blue", + "Ramp Red", + "Checkered" +}; + +static int adv748x_hdmi_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct adv748x_hdmi *hdmi = adv748x_ctrl_to_hdmi(ctrl); + struct adv748x_state *state = adv748x_hdmi_to_state(hdmi); + int ret; + u8 pattern; + + /* Enable video adjustment first */ + ret = cp_clrset(state, ADV748X_CP_VID_ADJ, + ADV748X_CP_VID_ADJ_ENABLE, + ADV748X_CP_VID_ADJ_ENABLE); + if (ret < 0) + return ret; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ret = cp_write(state, ADV748X_CP_BRI, ctrl->val); + break; + case V4L2_CID_HUE: + ret = cp_write(state, ADV748X_CP_HUE, ctrl->val); + break; + case V4L2_CID_CONTRAST: + ret = cp_write(state, ADV748X_CP_CON, ctrl->val); + break; + case V4L2_CID_SATURATION: + ret = cp_write(state, ADV748X_CP_SAT, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: + pattern = ctrl->val; + + /* Pattern is 0-indexed. Ctrl Menu is 1-indexed */ + if (pattern) { + pattern--; + pattern |= ADV748X_CP_PAT_GEN_EN; + } + + ret = cp_write(state, ADV748X_CP_PAT_GEN, pattern); + + break; + default: + return -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops adv748x_hdmi_ctrl_ops = { + .s_ctrl = adv748x_hdmi_s_ctrl, +}; + +static int adv748x_hdmi_init_controls(struct adv748x_hdmi *hdmi) +{ + struct adv748x_state *state = adv748x_hdmi_to_state(hdmi); + + v4l2_ctrl_handler_init(&hdmi->ctrl_hdl, 5); + + /* Use our mutex for the controls */ + hdmi->ctrl_hdl.lock = &state->mutex; + + v4l2_ctrl_new_std(&hdmi->ctrl_hdl, &adv748x_hdmi_ctrl_ops, + V4L2_CID_BRIGHTNESS, ADV748X_CP_BRI_MIN, + ADV748X_CP_BRI_MAX, 1, ADV748X_CP_BRI_DEF); + v4l2_ctrl_new_std(&hdmi->ctrl_hdl, &adv748x_hdmi_ctrl_ops, + V4L2_CID_CONTRAST, ADV748X_CP_CON_MIN, + ADV748X_CP_CON_MAX, 1, ADV748X_CP_CON_DEF); + v4l2_ctrl_new_std(&hdmi->ctrl_hdl, &adv748x_hdmi_ctrl_ops, + V4L2_CID_SATURATION, ADV748X_CP_SAT_MIN, + ADV748X_CP_SAT_MAX, 1, ADV748X_CP_SAT_DEF); + v4l2_ctrl_new_std(&hdmi->ctrl_hdl, &adv748x_hdmi_ctrl_ops, + V4L2_CID_HUE, ADV748X_CP_HUE_MIN, + ADV748X_CP_HUE_MAX, 1, ADV748X_CP_HUE_DEF); + + /* + * Todo: V4L2_CID_DV_RX_POWER_PRESENT should also be supported when + * interrupts are handled correctly + */ + + v4l2_ctrl_new_std_menu_items(&hdmi->ctrl_hdl, &adv748x_hdmi_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(hdmi_ctrl_patgen_menu) - 1, + 0, 0, hdmi_ctrl_patgen_menu); + + hdmi->sd.ctrl_handler = &hdmi->ctrl_hdl; + if (hdmi->ctrl_hdl.error) { + v4l2_ctrl_handler_free(&hdmi->ctrl_hdl); + return hdmi->ctrl_hdl.error; + } + + return v4l2_ctrl_handler_setup(&hdmi->ctrl_hdl); +} + +int adv748x_hdmi_init(struct adv748x_hdmi *hdmi) +{ + struct adv748x_state *state = adv748x_hdmi_to_state(hdmi); + static const struct v4l2_dv_timings cea1280x720 = + V4L2_DV_BT_CEA_1280X720P30; + int ret; + + hdmi->timings = cea1280x720; + + /* Initialise a default 16:9 aspect ratio */ + hdmi->aspect_ratio.numerator = 16; + hdmi->aspect_ratio.denominator = 9; + + adv748x_subdev_init(&hdmi->sd, state, &adv748x_ops_hdmi, + MEDIA_ENT_F_IO_DTV, "hdmi"); + + hdmi->pads[ADV748X_HDMI_SINK].flags = MEDIA_PAD_FL_SINK; + hdmi->pads[ADV748X_HDMI_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&hdmi->sd.entity, + ADV748X_HDMI_NR_PADS, hdmi->pads); + if (ret) + return ret; + + ret = adv748x_hdmi_init_controls(hdmi); + if (ret) + goto err_free_media; + + return 0; + +err_free_media: + media_entity_cleanup(&hdmi->sd.entity); + + return ret; +} + +void adv748x_hdmi_cleanup(struct adv748x_hdmi *hdmi) +{ + v4l2_device_unregister_subdev(&hdmi->sd); + media_entity_cleanup(&hdmi->sd.entity); + v4l2_ctrl_handler_free(&hdmi->ctrl_hdl); +} diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h new file mode 100644 index 000000000000..cc4151b5b31e --- /dev/null +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -0,0 +1,425 @@ +/* + * Driver for Analog Devices ADV748X video decoder and HDMI receiver + * + * Copyright (C) 2017 Renesas Electronics Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Authors: + * Koji Matsuoka <koji.matsuoka.xm@renesas.com> + * Niklas Söderlund <niklas.soderlund@ragnatech.se> + * Kieran Bingham <kieran.bingham@ideasonboard.com> + * + * The ADV748x range of receivers have the following configurations: + * + * Analog HDMI MHL 4-Lane 1-Lane + * In In CSI CSI + * ADV7480 X X X + * ADV7481 X X X X X + * ADV7482 X X X X + */ + +#include <linux/i2c.h> + +#ifndef _ADV748X_H_ +#define _ADV748X_H_ + +/* I2C slave addresses */ +#define ADV748X_I2C_IO 0x70 /* IO Map */ +#define ADV748X_I2C_DPLL 0x26 /* DPLL Map */ +#define ADV748X_I2C_CP 0x22 /* CP Map */ +#define ADV748X_I2C_HDMI 0x34 /* HDMI Map */ +#define ADV748X_I2C_EDID 0x36 /* EDID Map */ +#define ADV748X_I2C_REPEATER 0x32 /* HDMI RX Repeater Map */ +#define ADV748X_I2C_INFOFRAME 0x31 /* HDMI RX InfoFrame Map */ +#define ADV748X_I2C_CEC 0x41 /* CEC Map */ +#define ADV748X_I2C_SDP 0x79 /* SDP Map */ +#define ADV748X_I2C_TXB 0x48 /* CSI-TXB Map */ +#define ADV748X_I2C_TXA 0x4a /* CSI-TXA Map */ + +enum adv748x_page { + ADV748X_PAGE_IO, + ADV748X_PAGE_DPLL, + ADV748X_PAGE_CP, + ADV748X_PAGE_HDMI, + ADV748X_PAGE_EDID, + ADV748X_PAGE_REPEATER, + ADV748X_PAGE_INFOFRAME, + ADV748X_PAGE_CEC, + ADV748X_PAGE_SDP, + ADV748X_PAGE_TXB, + ADV748X_PAGE_TXA, + ADV748X_PAGE_MAX, + + /* Fake pages for register sequences */ + ADV748X_PAGE_WAIT, /* Wait x msec */ + ADV748X_PAGE_EOR, /* End Mark */ +}; + +/** + * enum adv748x_ports - Device tree port number definitions + * + * The ADV748X ports define the mapping between subdevices + * and the device tree specification + */ +enum adv748x_ports { + ADV748X_PORT_AIN0 = 0, + ADV748X_PORT_AIN1 = 1, + ADV748X_PORT_AIN2 = 2, + ADV748X_PORT_AIN3 = 3, + ADV748X_PORT_AIN4 = 4, + ADV748X_PORT_AIN5 = 5, + ADV748X_PORT_AIN6 = 6, + ADV748X_PORT_AIN7 = 7, + ADV748X_PORT_HDMI = 8, + ADV748X_PORT_TTL = 9, + ADV748X_PORT_TXA = 10, + ADV748X_PORT_TXB = 11, + ADV748X_PORT_MAX = 12, +}; + +enum adv748x_csi2_pads { + ADV748X_CSI2_SINK, + ADV748X_CSI2_SOURCE, + ADV748X_CSI2_NR_PADS, +}; + +/* CSI2 transmitters can have 2 internal connections, HDMI/AFE */ +#define ADV748X_CSI2_MAX_SUBDEVS 2 + +struct adv748x_csi2 { + struct adv748x_state *state; + struct v4l2_mbus_framefmt format; + unsigned int page; + + struct media_pad pads[ADV748X_CSI2_NR_PADS]; + struct v4l2_ctrl_handler ctrl_hdl; + struct v4l2_subdev sd; +}; + +#define notifier_to_csi2(n) container_of(n, struct adv748x_csi2, notifier) +#define adv748x_sd_to_csi2(sd) container_of(sd, struct adv748x_csi2, sd) + +enum adv748x_hdmi_pads { + ADV748X_HDMI_SINK, + ADV748X_HDMI_SOURCE, + ADV748X_HDMI_NR_PADS, +}; + +struct adv748x_hdmi { + struct media_pad pads[ADV748X_HDMI_NR_PADS]; + struct v4l2_ctrl_handler ctrl_hdl; + struct v4l2_subdev sd; + struct v4l2_mbus_framefmt format; + + struct v4l2_dv_timings timings; + struct v4l2_fract aspect_ratio; + + struct { + u8 edid[512]; + u32 present; + unsigned int blocks; + } edid; +}; + +#define adv748x_ctrl_to_hdmi(ctrl) \ + container_of(ctrl->handler, struct adv748x_hdmi, ctrl_hdl) +#define adv748x_sd_to_hdmi(sd) container_of(sd, struct adv748x_hdmi, sd) + +enum adv748x_afe_pads { + ADV748X_AFE_SINK_AIN0, + ADV748X_AFE_SINK_AIN1, + ADV748X_AFE_SINK_AIN2, + ADV748X_AFE_SINK_AIN3, + ADV748X_AFE_SINK_AIN4, + ADV748X_AFE_SINK_AIN5, + ADV748X_AFE_SINK_AIN6, + ADV748X_AFE_SINK_AIN7, + ADV748X_AFE_SOURCE, + ADV748X_AFE_NR_PADS, +}; + +struct adv748x_afe { + struct media_pad pads[ADV748X_AFE_NR_PADS]; + struct v4l2_ctrl_handler ctrl_hdl; + struct v4l2_subdev sd; + struct v4l2_mbus_framefmt format; + + bool streaming; + v4l2_std_id curr_norm; + unsigned int input; +}; + +#define adv748x_ctrl_to_afe(ctrl) \ + container_of(ctrl->handler, struct adv748x_afe, ctrl_hdl) +#define adv748x_sd_to_afe(sd) container_of(sd, struct adv748x_afe, sd) + +/** + * struct adv748x_state - State of ADV748X + * @dev: (OF) device + * @client: I2C client + * @mutex: protect global state + * + * @endpoints: parsed device node endpoints for each port + * + * @i2c_addresses I2C Page addresses + * @i2c_clients I2C clients for the page accesses + * @regmap regmap configuration pages. + * + * @hdmi: state of HDMI receiver context + * @afe: state of AFE receiver context + * @txa: state of TXA transmitter context + * @txb: state of TXB transmitter context + */ +struct adv748x_state { + struct device *dev; + struct i2c_client *client; + struct mutex mutex; + + struct device_node *endpoints[ADV748X_PORT_MAX]; + + struct i2c_client *i2c_clients[ADV748X_PAGE_MAX]; + struct regmap *regmap[ADV748X_PAGE_MAX]; + + struct adv748x_hdmi hdmi; + struct adv748x_afe afe; + struct adv748x_csi2 txa; + struct adv748x_csi2 txb; +}; + +#define adv748x_hdmi_to_state(h) container_of(h, struct adv748x_state, hdmi) +#define adv748x_afe_to_state(a) container_of(a, struct adv748x_state, afe) + +#define adv_err(a, fmt, arg...) dev_err(a->dev, fmt, ##arg) +#define adv_info(a, fmt, arg...) dev_info(a->dev, fmt, ##arg) +#define adv_dbg(a, fmt, arg...) dev_dbg(a->dev, fmt, ##arg) + +/* Register Mappings */ + +/* IO Map */ +#define ADV748X_IO_PD 0x00 /* power down controls */ +#define ADV748X_IO_PD_RX_EN BIT(6) + +#define ADV748X_IO_REG_04 0x04 +#define ADV748X_IO_REG_04_FORCE_FR BIT(0) /* Force CP free-run */ + +#define ADV748X_IO_DATAPATH 0x03 /* datapath cntrl */ +#define ADV748X_IO_DATAPATH_VFREQ_M 0x70 +#define ADV748X_IO_DATAPATH_VFREQ_SHIFT 4 + +#define ADV748X_IO_VID_STD 0x05 + +#define ADV748X_IO_10 0x10 /* io_reg_10 */ +#define ADV748X_IO_10_CSI4_EN BIT(7) +#define ADV748X_IO_10_CSI1_EN BIT(6) +#define ADV748X_IO_10_PIX_OUT_EN BIT(5) + +#define ADV748X_IO_CHIP_REV_ID_1 0xdf +#define ADV748X_IO_CHIP_REV_ID_2 0xe0 + +#define ADV748X_IO_SLAVE_ADDR_BASE 0xf2 + +/* HDMI RX Map */ +#define ADV748X_HDMI_LW1 0x07 /* line width_1 */ +#define ADV748X_HDMI_LW1_VERT_FILTER BIT(7) +#define ADV748X_HDMI_LW1_DE_REGEN BIT(5) +#define ADV748X_HDMI_LW1_WIDTH_MASK 0x1fff + +#define ADV748X_HDMI_F0H1 0x09 /* field0 height_1 */ +#define ADV748X_HDMI_F0H1_HEIGHT_MASK 0x1fff + +#define ADV748X_HDMI_F1H1 0x0b /* field1 height_1 */ +#define ADV748X_HDMI_F1H1_INTERLACED BIT(5) + +#define ADV748X_HDMI_HFRONT_PORCH 0x20 /* hsync_front_porch_1 */ +#define ADV748X_HDMI_HFRONT_PORCH_MASK 0x1fff + +#define ADV748X_HDMI_HSYNC_WIDTH 0x22 /* hsync_pulse_width_1 */ +#define ADV748X_HDMI_HSYNC_WIDTH_MASK 0x1fff + +#define ADV748X_HDMI_HBACK_PORCH 0x24 /* hsync_back_porch_1 */ +#define ADV748X_HDMI_HBACK_PORCH_MASK 0x1fff + +#define ADV748X_HDMI_VFRONT_PORCH 0x2a /* field0_vs_front_porch_1 */ +#define ADV748X_HDMI_VFRONT_PORCH_MASK 0x3fff + +#define ADV748X_HDMI_VSYNC_WIDTH 0x2e /* field0_vs_pulse_width_1 */ +#define ADV748X_HDMI_VSYNC_WIDTH_MASK 0x3fff + +#define ADV748X_HDMI_VBACK_PORCH 0x32 /* field0_vs_back_porch_1 */ +#define ADV748X_HDMI_VBACK_PORCH_MASK 0x3fff + +#define ADV748X_HDMI_TMDS_1 0x51 /* hdmi_reg_51 */ +#define ADV748X_HDMI_TMDS_2 0x52 /* hdmi_reg_52 */ + +/* HDMI RX Repeater Map */ +#define ADV748X_REPEATER_EDID_SZ 0x70 /* primary_edid_size */ +#define ADV748X_REPEATER_EDID_SZ_SHIFT 4 + +#define ADV748X_REPEATER_EDID_CTL 0x74 /* hdcp edid controls */ +#define ADV748X_REPEATER_EDID_CTL_EN BIT(0) /* man_edid_a_enable */ + +/* SDP Main Map */ +#define ADV748X_SDP_INSEL 0x00 /* user_map_rw_reg_00 */ + +#define ADV748X_SDP_VID_SEL 0x02 /* user_map_rw_reg_02 */ +#define ADV748X_SDP_VID_SEL_MASK 0xf0 +#define ADV748X_SDP_VID_SEL_SHIFT 4 + +/* Contrast - Unsigned*/ +#define ADV748X_SDP_CON 0x08 /* user_map_rw_reg_08 */ +#define ADV748X_SDP_CON_MIN 0 +#define ADV748X_SDP_CON_DEF 128 +#define ADV748X_SDP_CON_MAX 255 + +/* Brightness - Signed */ +#define ADV748X_SDP_BRI 0x0a /* user_map_rw_reg_0a */ +#define ADV748X_SDP_BRI_MIN -128 +#define ADV748X_SDP_BRI_DEF 0 +#define ADV748X_SDP_BRI_MAX 127 + +/* Hue - Signed, inverted*/ +#define ADV748X_SDP_HUE 0x0b /* user_map_rw_reg_0b */ +#define ADV748X_SDP_HUE_MIN -127 +#define ADV748X_SDP_HUE_DEF 0 +#define ADV748X_SDP_HUE_MAX 128 + +/* Test Patterns / Default Values */ +#define ADV748X_SDP_DEF 0x0c /* user_map_rw_reg_0c */ +#define ADV748X_SDP_DEF_VAL_EN BIT(0) /* Force free run mode */ +#define ADV748X_SDP_DEF_VAL_AUTO_EN BIT(1) /* Free run when no signal */ + +#define ADV748X_SDP_MAP_SEL 0x0e /* user_map_rw_reg_0e */ +#define ADV748X_SDP_MAP_SEL_RO_MAIN 1 + +/* Free run pattern select */ +#define ADV748X_SDP_FRP 0x14 +#define ADV748X_SDP_FRP_MASK GENMASK(3, 1) + +/* Saturation */ +#define ADV748X_SDP_SD_SAT_U 0xe3 /* user_map_rw_reg_e3 */ +#define ADV748X_SDP_SD_SAT_V 0xe4 /* user_map_rw_reg_e4 */ +#define ADV748X_SDP_SAT_MIN 0 +#define ADV748X_SDP_SAT_DEF 128 +#define ADV748X_SDP_SAT_MAX 255 + +/* SDP RO Main Map */ +#define ADV748X_SDP_RO_10 0x10 +#define ADV748X_SDP_RO_10_IN_LOCK BIT(0) + +/* CP Map */ +#define ADV748X_CP_PAT_GEN 0x37 /* int_pat_gen_1 */ +#define ADV748X_CP_PAT_GEN_EN BIT(7) + +/* Contrast Control - Unsigned */ +#define ADV748X_CP_CON 0x3a /* contrast_cntrl */ +#define ADV748X_CP_CON_MIN 0 /* Minimum contrast */ +#define ADV748X_CP_CON_DEF 128 /* Default */ +#define ADV748X_CP_CON_MAX 255 /* Maximum contrast */ + +/* Saturation Control - Unsigned */ +#define ADV748X_CP_SAT 0x3b /* saturation_cntrl */ +#define ADV748X_CP_SAT_MIN 0 /* Minimum saturation */ +#define ADV748X_CP_SAT_DEF 128 /* Default */ +#define ADV748X_CP_SAT_MAX 255 /* Maximum saturation */ + +/* Brightness Control - Signed */ +#define ADV748X_CP_BRI 0x3c /* brightness_cntrl */ +#define ADV748X_CP_BRI_MIN -128 /* Luma is -512d */ +#define ADV748X_CP_BRI_DEF 0 /* Luma is 0 */ +#define ADV748X_CP_BRI_MAX 127 /* Luma is 508d */ + +/* Hue Control */ +#define ADV748X_CP_HUE 0x3d /* hue_cntrl */ +#define ADV748X_CP_HUE_MIN 0 /* -90 degree */ +#define ADV748X_CP_HUE_DEF 0 /* -90 degree */ +#define ADV748X_CP_HUE_MAX 255 /* +90 degree */ + +#define ADV748X_CP_VID_ADJ 0x3e /* vid_adj_0 */ +#define ADV748X_CP_VID_ADJ_ENABLE BIT(7) /* Enable colour controls */ + +#define ADV748X_CP_DE_POS_HIGH 0x8b /* de_pos_adj_6 */ +#define ADV748X_CP_DE_POS_HIGH_SET BIT(6) +#define ADV748X_CP_DE_POS_END_LOW 0x8c /* de_pos_adj_7 */ +#define ADV748X_CP_DE_POS_START_LOW 0x8d /* de_pos_adj_8 */ + +#define ADV748X_CP_VID_ADJ_2 0x91 +#define ADV748X_CP_VID_ADJ_2_INTERLACED BIT(6) +#define ADV748X_CP_VID_ADJ_2_INTERLACED_3D BIT(4) + +#define ADV748X_CP_CLMP_POS 0xc9 /* clmp_pos_cntrl_4 */ +#define ADV748X_CP_CLMP_POS_DIS_AUTO BIT(0) /* dis_auto_param_buff */ + +/* CSI : TXA/TXB Maps */ +#define ADV748X_CSI_VC_REF 0x0d /* csi_tx_top_reg_0d */ +#define ADV748X_CSI_VC_REF_SHIFT 6 + +#define ADV748X_CSI_FS_AS_LS 0x1e /* csi_tx_top_reg_1e */ +#define ADV748X_CSI_FS_AS_LS_UNKNOWN BIT(6) /* Undocumented bit */ + +/* Register handling */ + +int adv748x_read(struct adv748x_state *state, u8 addr, u8 reg); +int adv748x_write(struct adv748x_state *state, u8 page, u8 reg, u8 value); +int adv748x_write_block(struct adv748x_state *state, int client_page, + unsigned int init_reg, const void *val, + size_t val_len); + +#define io_read(s, r) adv748x_read(s, ADV748X_PAGE_IO, r) +#define io_write(s, r, v) adv748x_write(s, ADV748X_PAGE_IO, r, v) +#define io_clrset(s, r, m, v) io_write(s, r, (io_read(s, r) & ~m) | v) + +#define hdmi_read(s, r) adv748x_read(s, ADV748X_PAGE_HDMI, r) +#define hdmi_read16(s, r, m) (((hdmi_read(s, r) << 8) | hdmi_read(s, r+1)) & m) +#define hdmi_write(s, r, v) adv748x_write(s, ADV748X_PAGE_HDMI, r, v) + +#define repeater_read(s, r) adv748x_read(s, ADV748X_PAGE_REPEATER, r) +#define repeater_write(s, r, v) adv748x_write(s, ADV748X_PAGE_REPEATER, r, v) + +#define sdp_read(s, r) adv748x_read(s, ADV748X_PAGE_SDP, r) +#define sdp_write(s, r, v) adv748x_write(s, ADV748X_PAGE_SDP, r, v) +#define sdp_clrset(s, r, m, v) sdp_write(s, r, (sdp_read(s, r) & ~m) | v) + +#define cp_read(s, r) adv748x_read(s, ADV748X_PAGE_CP, r) +#define cp_write(s, r, v) adv748x_write(s, ADV748X_PAGE_CP, r, v) +#define cp_clrset(s, r, m, v) cp_write(s, r, (cp_read(s, r) & ~m) | v) + +#define txa_read(s, r) adv748x_read(s, ADV748X_PAGE_TXA, r) +#define txb_read(s, r) adv748x_read(s, ADV748X_PAGE_TXB, r) + +#define tx_read(t, r) adv748x_read(t->state, t->page, r) +#define tx_write(t, r, v) adv748x_write(t->state, t->page, r, v) + +static inline struct v4l2_subdev *adv748x_get_remote_sd(struct media_pad *pad) +{ + pad = media_entity_remote_pad(pad); + if (!pad) + return NULL; + + return media_entity_to_v4l2_subdev(pad->entity); +} + +void adv748x_subdev_init(struct v4l2_subdev *sd, struct adv748x_state *state, + const struct v4l2_subdev_ops *ops, u32 function, + const char *ident); + +int adv748x_register_subdevs(struct adv748x_state *state, + struct v4l2_device *v4l2_dev); + +int adv748x_txa_power(struct adv748x_state *state, bool on); +int adv748x_txb_power(struct adv748x_state *state, bool on); + +int adv748x_afe_init(struct adv748x_afe *afe); +void adv748x_afe_cleanup(struct adv748x_afe *afe); + +int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx); +void adv748x_csi2_cleanup(struct adv748x_csi2 *tx); +int adv748x_csi2_set_pixelrate(struct v4l2_subdev *sd, s64 rate); + +int adv748x_hdmi_init(struct adv748x_hdmi *hdmi); +void adv748x_hdmi_cleanup(struct adv748x_hdmi *hdmi); + +#endif /* _ADV748X_H_ */ diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index ccc478605643..2817bafc67bf 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c @@ -1927,8 +1927,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * #if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) state->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops, - state, dev_name(&client->dev), CEC_CAP_TRANSMIT | - CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | CEC_CAP_RC, + state, dev_name(&client->dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS); err = PTR_ERR_OR_ZERO(state->cec_adap); if (err) { @@ -1986,7 +1985,7 @@ static int adv7511_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static struct i2c_device_id adv7511_id[] = { +static const struct i2c_device_id adv7511_id[] = { { "adv7511", 0 }, { } }; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 660bacb8f7d9..f289b8aca1da 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -618,7 +618,7 @@ static int adv76xx_read_reg(struct v4l2_subdev *sd, unsigned int reg) unsigned int val; int err; - if (!(BIT(page) & state->info->page_mask)) + if (page >= ADV76XX_PAGE_MAX || !(BIT(page) & state->info->page_mask)) return -EINVAL; reg &= 0xff; @@ -633,7 +633,7 @@ static int adv76xx_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val) struct adv76xx_state *state = to_state(sd); unsigned int page = reg >> 8; - if (!(BIT(page) & state->info->page_mask)) + if (page >= ADV76XX_PAGE_MAX || !(BIT(page) & state->info->page_mask)) return -EINVAL; reg &= 0xff; @@ -3515,8 +3515,7 @@ static int adv76xx_probe(struct i2c_client *client, #if IS_ENABLED(CONFIG_VIDEO_ADV7604_CEC) state->cec_adap = cec_allocate_adapter(&adv76xx_cec_adap_ops, state, dev_name(&client->dev), - CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | - CEC_CAP_PASSTHROUGH | CEC_CAP_RC, ADV76XX_MAX_ADDRS); + CEC_CAP_DEFAULTS, ADV76XX_MAX_ADDRS); err = PTR_ERR_OR_ZERO(state->cec_adap); if (err) goto err_entity; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 303effda1a2e..65f34e7e146f 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -3568,8 +3568,7 @@ static int adv7842_probe(struct i2c_client *client, #if IS_ENABLED(CONFIG_VIDEO_ADV7842_CEC) state->cec_adap = cec_allocate_adapter(&adv7842_cec_adap_ops, state, dev_name(&client->dev), - CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | - CEC_CAP_PASSTHROUGH | CEC_CAP_RC, ADV7842_MAX_ADDRS); + CEC_CAP_DEFAULTS, ADV7842_MAX_ADDRS); err = PTR_ERR_OR_ZERO(state->cec_adap); if (err) goto err_entity; @@ -3608,7 +3607,7 @@ static int adv7842_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static struct i2c_device_id adv7842_id[] = { +static const struct i2c_device_id adv7842_id[] = { { "adv7842", 0 }, { } }; diff --git a/drivers/media/i2c/dw9714.c b/drivers/media/i2c/dw9714.c index 6a607d7f82de..95af4fc99cd0 100644 --- a/drivers/media/i2c/dw9714.c +++ b/drivers/media/i2c/dw9714.c @@ -11,7 +11,6 @@ * GNU General Public License for more details. */ -#include <linux/acpi.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/module.h> @@ -147,8 +146,7 @@ static int dw9714_init_controls(struct dw9714_device *dev_vcm) return hdl->error; } -static int dw9714_probe(struct i2c_client *client, - const struct i2c_device_id *devid) +static int dw9714_probe(struct i2c_client *client) { struct dw9714_device *dw9714_dev; int rval; @@ -250,20 +248,18 @@ static int __maybe_unused dw9714_vcm_resume(struct device *dev) return 0; } -#ifdef CONFIG_ACPI -static const struct acpi_device_id dw9714_acpi_match[] = { - {}, -}; -MODULE_DEVICE_TABLE(acpi, dw9714_acpi_match); -#endif - static const struct i2c_device_id dw9714_id_table[] = { - {DW9714_NAME, 0}, - {} + { DW9714_NAME, 0 }, + { { 0 } } }; - MODULE_DEVICE_TABLE(i2c, dw9714_id_table); +static const struct of_device_id dw9714_of_table[] = { + { .compatible = "dongwoon,dw9714" }, + { { 0 } } +}; +MODULE_DEVICE_TABLE(of, dw9714_of_table); + static const struct dev_pm_ops dw9714_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(dw9714_vcm_suspend, dw9714_vcm_resume) SET_RUNTIME_PM_OPS(dw9714_vcm_suspend, dw9714_vcm_resume, NULL) @@ -273,9 +269,9 @@ static struct i2c_driver dw9714_i2c_driver = { .driver = { .name = DW9714_NAME, .pm = &dw9714_pm_ops, - .acpi_match_table = ACPI_PTR(dw9714_acpi_match), + .of_match_table = dw9714_of_table, }, - .probe = dw9714_probe, + .probe_new = dw9714_probe, .remove = dw9714_remove, .id_table = dw9714_id_table, }; diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index f39f5179dd95..c14f0fd6ded3 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -43,7 +43,7 @@ #define ET8EK8_NAME "et8ek8" #define ET8EK8_PRIV_MEM_SIZE 128 -#define ET8EK8_MAX_MSG 48 +#define ET8EK8_MAX_MSG 8 struct et8ek8_sensor { struct v4l2_subdev subdev; @@ -220,7 +220,8 @@ static void et8ek8_i2c_create_msg(struct i2c_client *client, u16 len, u16 reg, /* * A buffered write method that puts the wanted register write - * commands in a message list and passes the list to the i2c framework + * commands in smaller number of message lists and passes the lists to + * the i2c framework */ static int et8ek8_i2c_buffered_write_regs(struct i2c_client *client, const struct et8ek8_reg *wnext, @@ -231,11 +232,7 @@ static int et8ek8_i2c_buffered_write_regs(struct i2c_client *client, int wcnt = 0; u16 reg, data_length; u32 val; - - if (WARN_ONCE(cnt > ET8EK8_MAX_MSG, - ET8EK8_NAME ": %s: too many messages.\n", __func__)) { - return -EINVAL; - } + int rval; /* Create new write messages for all writes */ while (wcnt < cnt) { @@ -249,10 +246,21 @@ static int et8ek8_i2c_buffered_write_regs(struct i2c_client *client, /* Update write count */ wcnt++; + + if (wcnt < ET8EK8_MAX_MSG) + continue; + + rval = i2c_transfer(client->adapter, msg, wcnt); + if (rval < 0) + return rval; + + cnt -= wcnt; + wcnt = 0; } - /* Now we send everything ... */ - return i2c_transfer(client->adapter, msg, wcnt); + rval = i2c_transfer(client->adapter, msg, wcnt); + + return rval < 0 ? rval : 0; } /* diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index cee7fd9cf08b..a374e2a0ac3d 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -59,8 +59,8 @@ module_param(debug, int, 0644); /* debug level (0,1,2) */ /* ----------------------------------------------------------------------- */ -static int get_key_haup_common(struct IR_i2c *ir, enum rc_type *protocol, - u32 *scancode, u8 *ptoggle, int size) +static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol, + u32 *scancode, u8 *ptoggle, int size) { unsigned char buf[6]; int start, range, toggle, dev, code, ircode, vendor; @@ -99,7 +99,7 @@ static int get_key_haup_common(struct IR_i2c *ir, enum rc_type *protocol, dprintk(1, "ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", start, range, toggle, dev, code); - *protocol = RC_TYPE_RC5; + *protocol = RC_PROTO_RC5; *scancode = RC_SCANCODE_RC5(dev, code); *ptoggle = toggle; @@ -111,13 +111,13 @@ static int get_key_haup_common(struct IR_i2c *ir, enum rc_type *protocol, if (vendor == 0x800f) { *ptoggle = (dev & 0x80) != 0; - *protocol = RC_TYPE_RC6_MCE; + *protocol = RC_PROTO_RC6_MCE; dev &= 0x7f; dprintk(1, "ir hauppauge (rc6-mce): t%d vendor=%d dev=%d code=%d\n", *ptoggle, vendor, dev, code); } else { *ptoggle = 0; - *protocol = RC_TYPE_RC6_6A_32; + *protocol = RC_PROTO_RC6_6A_32; dprintk(1, "ir hauppauge (rc6-6a-32): vendor=%d dev=%d code=%d\n", vendor, dev, code); } @@ -130,13 +130,13 @@ static int get_key_haup_common(struct IR_i2c *ir, enum rc_type *protocol, return 0; } -static int get_key_haup(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_haup(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { return get_key_haup_common(ir, protocol, scancode, toggle, 3); } -static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { int ret; @@ -155,7 +155,7 @@ static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_type *protocol, return get_key_haup_common(ir, protocol, scancode, toggle, 6); } -static int get_key_pixelview(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char b; @@ -166,13 +166,13 @@ static int get_key_pixelview(struct IR_i2c *ir, enum rc_type *protocol, return -EIO; } - *protocol = RC_TYPE_OTHER; + *protocol = RC_PROTO_OTHER; *scancode = b; *toggle = 0; return 1; } -static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char buf[4]; @@ -191,13 +191,13 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_type *protocol, if(buf[0] != 0x1 || buf[1] != 0xfe) return 0; - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = buf[2]; *toggle = 0; return 1; } -static int get_key_knc1(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char b; @@ -221,13 +221,13 @@ static int get_key_knc1(struct IR_i2c *ir, enum rc_type *protocol, /* keep old data */ return 1; - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = b; *toggle = 0; return 1; } -static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char subaddr, key, keygroup; @@ -262,7 +262,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_type *protocol, } key |= (keygroup & 1) << 6; - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = key; if (ir->c->addr == 0x41) /* AVerMedia EM78P153 */ *scancode |= keygroup << 8; @@ -274,7 +274,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_type *protocol, static int ir_key_poll(struct IR_i2c *ir) { - enum rc_type protocol; + enum rc_proto protocol; u32 scancode; u8 toggle; int rc; @@ -315,7 +315,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) { char *ir_codes = NULL; const char *name = NULL; - u64 rc_type = RC_BIT_UNKNOWN; + u64 rc_proto = RC_PROTO_BIT_UNKNOWN; struct IR_i2c *ir; struct rc_dev *rc = NULL; struct i2c_adapter *adap = client->adapter; @@ -334,7 +334,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) case 0x64: name = "Pixelview"; ir->get_key = get_key_pixelview; - rc_type = RC_BIT_OTHER; + rc_proto = RC_PROTO_BIT_OTHER; ir_codes = RC_MAP_EMPTY; break; case 0x18: @@ -342,38 +342,39 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) case 0x1a: name = "Hauppauge"; ir->get_key = get_key_haup; - rc_type = RC_BIT_RC5; + rc_proto = RC_PROTO_BIT_RC5; ir_codes = RC_MAP_HAUPPAUGE; break; case 0x30: name = "KNC One"; ir->get_key = get_key_knc1; - rc_type = RC_BIT_OTHER; + rc_proto = RC_PROTO_BIT_OTHER; ir_codes = RC_MAP_EMPTY; break; case 0x6b: name = "FusionHDTV"; ir->get_key = get_key_fusionhdtv; - rc_type = RC_BIT_UNKNOWN; + rc_proto = RC_PROTO_BIT_UNKNOWN; ir_codes = RC_MAP_FUSIONHDTV_MCE; break; case 0x40: name = "AVerMedia Cardbus remote"; ir->get_key = get_key_avermedia_cardbus; - rc_type = RC_BIT_OTHER; + rc_proto = RC_PROTO_BIT_OTHER; ir_codes = RC_MAP_AVERMEDIA_CARDBUS; break; case 0x41: name = "AVerMedia EM78P153"; ir->get_key = get_key_avermedia_cardbus; - rc_type = RC_BIT_OTHER; + rc_proto = RC_PROTO_BIT_OTHER; /* RM-KV remote, seems to be same as RM-K6 */ ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6; break; case 0x71: name = "Hauppauge/Zilog Z8"; ir->get_key = get_key_haup_xvr; - rc_type = RC_BIT_RC5 | RC_BIT_RC6_MCE | RC_BIT_RC6_6A_32; + rc_proto = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_RC6_6A_32; ir_codes = RC_MAP_HAUPPAUGE; break; } @@ -388,7 +389,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) name = init_data->name; if (init_data->type) - rc_type = init_data->type; + rc_proto = init_data->type; if (init_data->polling_interval) ir->polling_interval = init_data->polling_interval; @@ -431,7 +432,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->rc = rc; /* Make sure we are all setup before going on */ - if (!name || !ir->get_key || !rc_type || !ir_codes) { + if (!name || !ir->get_key || !rc_proto || !ir_codes) { dprintk(1, ": Unsupported device at address 0x%02x\n", addr); err = -ENODEV; @@ -452,14 +453,14 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) */ rc->input_id.bustype = BUS_I2C; rc->input_phys = ir->phys; - rc->input_name = ir->name; + rc->device_name = ir->name; /* * Initialize the other fields of rc_dev */ rc->map_name = ir->ir_codes; - rc->allowed_protocols = rc_type; - rc->enabled_protocols = rc_type; + rc->allowed_protocols = rc_proto; + rc->enabled_protocols = rc_proto; if (!rc->driver_name) rc->driver_name = MODULE_NAME; diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index 9ccb5ee55fa9..463534d44756 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c @@ -457,7 +457,7 @@ static int m5mols_get_version(struct v4l2_subdev *sd) v4l2_info(sd, "Manufacturer\t[%s]\n", is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? - "Samsung Electro-Machanics" : + "Samsung Electro-Mechanics" : is_manufacturer(info, REG_SAMSUNG_OPTICS) ? "Samsung Fiber-Optics" : is_manufacturer(info, REG_SAMSUNG_TECHWIN) ? diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c index a4736a8a7792..bf0e821a2b93 100644 --- a/drivers/media/i2c/max2175.c +++ b/drivers/media/i2c/max2175.c @@ -1319,7 +1319,7 @@ static int max2175_probe(struct i2c_client *client, if (IS_ERR(clk)) { ret = PTR_ERR(clk); dev_err(&client->dev, "cannot get clock %d\n", ret); - return -ENODEV; + return ret; } regmap = devm_regmap_init_i2c(client, &max2175_regmap_config); diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 72e71b762827..99b992e46702 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -835,7 +835,7 @@ static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = { .s_ctrl = mt9m111_s_ctrl, }; -static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { +static const struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { .s_power = mt9m111_s_power, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9m111_g_register, @@ -865,7 +865,7 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, return 0; } -static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { +static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { .g_mbus_config = mt9m111_g_mbus_config, }; @@ -877,7 +877,7 @@ static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = { .set_fmt = mt9m111_set_fmt, }; -static struct v4l2_subdev_ops mt9m111_subdev_ops = { +static const struct v4l2_subdev_ops mt9m111_subdev_ops = { .core = &mt9m111_subdev_core_ops, .video = &mt9m111_subdev_video_ops, .pad = &mt9m111_subdev_pad_ops, diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c index 842017fa4aab..9d981d9f5686 100644 --- a/drivers/media/i2c/mt9t001.c +++ b/drivers/media/i2c/mt9t001.c @@ -822,15 +822,15 @@ static int mt9t001_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) return mt9t001_set_power(subdev, 0); } -static struct v4l2_subdev_core_ops mt9t001_subdev_core_ops = { +static const struct v4l2_subdev_core_ops mt9t001_subdev_core_ops = { .s_power = mt9t001_set_power, }; -static struct v4l2_subdev_video_ops mt9t001_subdev_video_ops = { +static const struct v4l2_subdev_video_ops mt9t001_subdev_video_ops = { .s_stream = mt9t001_s_stream, }; -static struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = { +static const struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = { .enum_mbus_code = mt9t001_enum_mbus_code, .enum_frame_size = mt9t001_enum_frame_size, .get_fmt = mt9t001_get_format, @@ -839,7 +839,7 @@ static struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = { .set_selection = mt9t001_set_selection, }; -static struct v4l2_subdev_ops mt9t001_subdev_ops = { +static const struct v4l2_subdev_ops mt9t001_subdev_ops = { .core = &mt9t001_subdev_core_ops, .video = &mt9t001_subdev_video_ops, .pad = &mt9t001_subdev_pad_ops, diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 86550d8ddfee..af7af0d14c69 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -57,16 +57,14 @@ #define OV13858_VTS_30FPS 0x0c8e /* 30 fps */ #define OV13858_VTS_60FPS 0x0648 /* 60 fps */ #define OV13858_VTS_MAX 0x7fff -#define OV13858_VBLANK_MIN 56 /* HBLANK control - read only */ -#define OV13858_PPL_540MHZ 2244 -#define OV13858_PPL_1080MHZ 4488 +#define OV13858_PPL_270MHZ 2244 +#define OV13858_PPL_540MHZ 4488 /* Exposure control */ #define OV13858_REG_EXPOSURE 0x3500 #define OV13858_EXPOSURE_MIN 4 -#define OV13858_EXPOSURE_MAX (OV13858_VTS_MAX - 8) #define OV13858_EXPOSURE_STEP 1 #define OV13858_EXPOSURE_DEFAULT 0x640 @@ -78,13 +76,13 @@ #define OV13858_ANA_GAIN_DEFAULT 0x80 /* Digital gain control */ -#define OV13858_REG_DIGITAL_GAIN 0x350a -#define OV13858_DGTL_GAIN_MASK 0xf3 -#define OV13858_DGTL_GAIN_SHIFT 2 -#define OV13858_DGTL_GAIN_MIN 1 -#define OV13858_DGTL_GAIN_MAX 4 -#define OV13858_DGTL_GAIN_STEP 1 -#define OV13858_DGTL_GAIN_DEFAULT 1 +#define OV13858_REG_B_MWB_GAIN 0x5100 +#define OV13858_REG_G_MWB_GAIN 0x5102 +#define OV13858_REG_R_MWB_GAIN 0x5104 +#define OV13858_DGTL_GAIN_MIN 0 +#define OV13858_DGTL_GAIN_MAX 16384 /* Max = 16 X */ +#define OV13858_DGTL_GAIN_DEFAULT 1024 /* Default gain = 1 X */ +#define OV13858_DGTL_GAIN_STEP 1 /* Each step = 1/1024 */ /* Test Pattern Control */ #define OV13858_REG_TEST_PATTERN 0x4503 @@ -121,7 +119,8 @@ struct ov13858_mode { u32 height; /* V-timing */ - u32 vts; + u32 vts_def; + u32 vts_min; /* Index of Link frequency config to be used */ u32 link_freq_index; @@ -944,31 +943,33 @@ static const char * const ov13858_test_pattern_menu[] = { /* Configurations for supported link frequencies */ #define OV13858_NUM_OF_LINK_FREQS 2 -#define OV13858_LINK_FREQ_1080MBPS 1080000000 -#define OV13858_LINK_FREQ_540MBPS 540000000 +#define OV13858_LINK_FREQ_540MHZ 540000000ULL +#define OV13858_LINK_FREQ_270MHZ 270000000ULL #define OV13858_LINK_FREQ_INDEX_0 0 #define OV13858_LINK_FREQ_INDEX_1 1 /* Menu items for LINK_FREQ V4L2 control */ static const s64 link_freq_menu_items[OV13858_NUM_OF_LINK_FREQS] = { - OV13858_LINK_FREQ_1080MBPS, - OV13858_LINK_FREQ_540MBPS + OV13858_LINK_FREQ_540MHZ, + OV13858_LINK_FREQ_270MHZ }; /* Link frequency configs */ static const struct ov13858_link_freq_config link_freq_configs[OV13858_NUM_OF_LINK_FREQS] = { { - .pixel_rate = 864000000, - .pixels_per_line = OV13858_PPL_1080MHZ, + /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ + .pixel_rate = (OV13858_LINK_FREQ_540MHZ * 2 * 4) / 10, + .pixels_per_line = OV13858_PPL_540MHZ, .reg_list = { .num_of_regs = ARRAY_SIZE(mipi_data_rate_1080mbps), .regs = mipi_data_rate_1080mbps, } }, { - .pixel_rate = 432000000, - .pixels_per_line = OV13858_PPL_540MHZ, + /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ + .pixel_rate = (OV13858_LINK_FREQ_270MHZ * 2 * 4) / 10, + .pixels_per_line = OV13858_PPL_270MHZ, .reg_list = { .num_of_regs = ARRAY_SIZE(mipi_data_rate_540mbps), .regs = mipi_data_rate_540mbps, @@ -981,7 +982,8 @@ static const struct ov13858_mode supported_modes[] = { { .width = 4224, .height = 3136, - .vts = OV13858_VTS_30FPS, + .vts_def = OV13858_VTS_30FPS, + .vts_min = OV13858_VTS_30FPS, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_4224x3136_regs), .regs = mode_4224x3136_regs, @@ -991,7 +993,8 @@ static const struct ov13858_mode supported_modes[] = { { .width = 2112, .height = 1568, - .vts = OV13858_VTS_30FPS, + .vts_def = OV13858_VTS_30FPS, + .vts_min = 1608, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_2112x1568_regs), .regs = mode_2112x1568_regs, @@ -1001,7 +1004,8 @@ static const struct ov13858_mode supported_modes[] = { { .width = 2112, .height = 1188, - .vts = OV13858_VTS_30FPS, + .vts_def = OV13858_VTS_30FPS, + .vts_min = 1608, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_2112x1188_regs), .regs = mode_2112x1188_regs, @@ -1011,7 +1015,8 @@ static const struct ov13858_mode supported_modes[] = { { .width = 1056, .height = 784, - .vts = OV13858_VTS_30FPS, + .vts_def = OV13858_VTS_30FPS, + .vts_min = 804, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1056x784_regs), .regs = mode_1056x784_regs, @@ -1161,21 +1166,21 @@ static int ov13858_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static int ov13858_update_digital_gain(struct ov13858 *ov13858, u32 d_gain) { int ret; - u32 val; - if (d_gain == 3) - return -EINVAL; + ret = ov13858_write_reg(ov13858, OV13858_REG_B_MWB_GAIN, + OV13858_REG_VALUE_16BIT, d_gain); + if (ret) + return ret; - ret = ov13858_read_reg(ov13858, OV13858_REG_DIGITAL_GAIN, - OV13858_REG_VALUE_08BIT, &val); + ret = ov13858_write_reg(ov13858, OV13858_REG_G_MWB_GAIN, + OV13858_REG_VALUE_16BIT, d_gain); if (ret) return ret; - val &= OV13858_DGTL_GAIN_MASK; - val |= (d_gain - 1) << OV13858_DGTL_GAIN_SHIFT; + ret = ov13858_write_reg(ov13858, OV13858_REG_R_MWB_GAIN, + OV13858_REG_VALUE_16BIT, d_gain); - return ov13858_write_reg(ov13858, OV13858_REG_DIGITAL_GAIN, - OV13858_REG_VALUE_08BIT, val); + return ret; } static int ov13858_enable_test_pattern(struct ov13858 *ov13858, u32 pattern) @@ -1377,6 +1382,8 @@ ov13858_set_pad_format(struct v4l2_subdev *sd, struct ov13858 *ov13858 = to_ov13858(sd); const struct ov13858_mode *mode; struct v4l2_mbus_framefmt *framefmt; + s32 vblank_def; + s32 vblank_min; s64 h_blank; mutex_lock(&ov13858->mutex); @@ -1397,10 +1404,15 @@ ov13858_set_pad_format(struct v4l2_subdev *sd, ov13858->pixel_rate, link_freq_configs[mode->link_freq_index].pixel_rate); /* Update limits and set FPS to default */ + vblank_def = ov13858->cur_mode->vts_def - + ov13858->cur_mode->height; + vblank_min = ov13858->cur_mode->vts_min - + ov13858->cur_mode->height; __v4l2_ctrl_modify_range( - ov13858->vblank, OV13858_VBLANK_MIN, + ov13858->vblank, vblank_min, OV13858_VTS_MAX - ov13858->cur_mode->height, 1, - ov13858->cur_mode->vts - ov13858->cur_mode->height); + vblank_def); + __v4l2_ctrl_s_ctrl(ov13858->vblank, vblank_def); h_blank = link_freq_configs[mode->link_freq_index].pixels_per_line - ov13858->cur_mode->width; @@ -1602,6 +1614,9 @@ static int ov13858_init_controls(struct ov13858 *ov13858) { struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); struct v4l2_ctrl_handler *ctrl_hdlr; + s64 exposure_max; + s64 vblank_def; + s64 vblank_min; int ret; ctrl_hdlr = &ov13858->ctrl_handler; @@ -1625,25 +1640,27 @@ static int ov13858_init_controls(struct ov13858 *ov13858) link_freq_configs[0].pixel_rate, 1, link_freq_configs[0].pixel_rate); + vblank_def = ov13858->cur_mode->vts_def - ov13858->cur_mode->height; + vblank_min = ov13858->cur_mode->vts_min - ov13858->cur_mode->height; ov13858->vblank = v4l2_ctrl_new_std( ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_VBLANK, - OV13858_VBLANK_MIN, + vblank_min, OV13858_VTS_MAX - ov13858->cur_mode->height, 1, - ov13858->cur_mode->vts - - ov13858->cur_mode->height); + vblank_def); ov13858->hblank = v4l2_ctrl_new_std( ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_HBLANK, - OV13858_PPL_1080MHZ - ov13858->cur_mode->width, - OV13858_PPL_1080MHZ - ov13858->cur_mode->width, + OV13858_PPL_540MHZ - ov13858->cur_mode->width, + OV13858_PPL_540MHZ - ov13858->cur_mode->width, 1, - OV13858_PPL_1080MHZ - ov13858->cur_mode->width); + OV13858_PPL_540MHZ - ov13858->cur_mode->width); ov13858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + exposure_max = ov13858->cur_mode->vts_def - 8; ov13858->exposure = v4l2_ctrl_new_std( ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_EXPOSURE, OV13858_EXPOSURE_MIN, - OV13858_EXPOSURE_MAX, OV13858_EXPOSURE_STEP, + exposure_max, OV13858_EXPOSURE_STEP, OV13858_EXPOSURE_DEFAULT); v4l2_ctrl_new_std(ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 1f5b483cf334..39a2269c0bee 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -1524,8 +1524,7 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor) static void ov5640_power(struct ov5640_dev *sensor, bool enable) { - if (sensor->pwdn_gpio) - gpiod_set_value(sensor->pwdn_gpio, enable ? 0 : 1); + gpiod_set_value(sensor->pwdn_gpio, enable ? 0 : 1); } static void ov5640_reset(struct ov5640_dev *sensor) diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index d1e844f7f03f..d28845f7356f 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -80,6 +80,8 @@ struct ov5645_mode_info { u32 height; const struct reg_value *data; u32 data_size; + u32 pixel_clock; + u32 link_freq; }; struct ov5645 { @@ -99,6 +101,8 @@ struct ov5645 { const struct ov5645_mode_info *current_mode; struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *pixel_clock; + struct v4l2_ctrl *link_freq; /* Cached register values */ u8 aec_pk_manual; @@ -505,24 +509,35 @@ static const struct reg_value ov5645_setting_full[] = { { 0x4202, 0x00 } }; +static const s64 link_freq[] = { + 222880000, + 334320000 +}; + static const struct ov5645_mode_info ov5645_mode_info_data[] = { { .width = 1280, .height = 960, .data = ov5645_setting_sxga, - .data_size = ARRAY_SIZE(ov5645_setting_sxga) + .data_size = ARRAY_SIZE(ov5645_setting_sxga), + .pixel_clock = 111440000, + .link_freq = 0 /* an index in link_freq[] */ }, { .width = 1920, .height = 1080, .data = ov5645_setting_1080p, - .data_size = ARRAY_SIZE(ov5645_setting_1080p) + .data_size = ARRAY_SIZE(ov5645_setting_1080p), + .pixel_clock = 167160000, + .link_freq = 1 /* an index in link_freq[] */ }, { .width = 2592, .height = 1944, .data = ov5645_setting_full, - .data_size = ARRAY_SIZE(ov5645_setting_full) + .data_size = ARRAY_SIZE(ov5645_setting_full), + .pixel_clock = 167160000, + .link_freq = 1 /* an index in link_freq[] */ }, }; @@ -969,6 +984,7 @@ static int ov5645_set_format(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *__format; struct v4l2_rect *__crop; const struct ov5645_mode_info *new_mode; + int ret; __crop = __ov5645_get_pad_crop(ov5645, cfg, format->pad, format->which); @@ -978,8 +994,19 @@ static int ov5645_set_format(struct v4l2_subdev *sd, __crop->width = new_mode->width; __crop->height = new_mode->height; - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + ret = v4l2_ctrl_s_ctrl_int64(ov5645->pixel_clock, + new_mode->pixel_clock); + if (ret < 0) + return ret; + + ret = v4l2_ctrl_s_ctrl(ov5645->link_freq, + new_mode->link_freq); + if (ret < 0) + return ret; + ov5645->current_mode = new_mode; + } __format = __ov5645_get_pad_format(ov5645, cfg, format->pad, format->which); @@ -1197,7 +1224,7 @@ static int ov5645_probe(struct i2c_client *client, mutex_init(&ov5645->power_lock); - v4l2_ctrl_handler_init(&ov5645->ctrls, 7); + v4l2_ctrl_handler_init(&ov5645->ctrls, 9); v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops, V4L2_CID_SATURATION, -4, 4, 1, 0); v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops, @@ -1215,6 +1242,17 @@ static int ov5645_probe(struct i2c_client *client, V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov5645_test_pattern_menu) - 1, 0, 0, ov5645_test_pattern_menu); + ov5645->pixel_clock = v4l2_ctrl_new_std(&ov5645->ctrls, + &ov5645_ctrl_ops, + V4L2_CID_PIXEL_RATE, + 1, INT_MAX, 1, 1); + ov5645->link_freq = v4l2_ctrl_new_int_menu(&ov5645->ctrls, + &ov5645_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq) - 1, + 0, link_freq); + if (ov5645->link_freq) + ov5645->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; ov5645->sd.ctrl_handler = &ov5645->ctrls; @@ -1229,6 +1267,7 @@ static int ov5645_probe(struct i2c_client *client, ov5645->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov5645->pad.flags = MEDIA_PAD_FL_SOURCE; ov5645->sd.dev = &client->dev; + ov5645->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&ov5645->sd.entity, 1, &ov5645->pad); if (ret < 0) { diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c new file mode 100644 index 000000000000..6f7a1d6d2200 --- /dev/null +++ b/drivers/media/i2c/ov5670.c @@ -0,0 +1,2601 @@ +/* + * Copyright (c) 2017 Intel Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/acpi.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> + +#define OV5670_REG_CHIP_ID 0x300a +#define OV5670_CHIP_ID 0x005670 + +#define OV5670_REG_MODE_SELECT 0x0100 +#define OV5670_MODE_STANDBY 0x00 +#define OV5670_MODE_STREAMING 0x01 + +#define OV5670_REG_SOFTWARE_RST 0x0103 +#define OV5670_SOFTWARE_RST 0x01 + +/* vertical-timings from sensor */ +#define OV5670_REG_VTS 0x380e +#define OV5670_VTS_30FPS 0x0808 /* default for 30 fps */ +#define OV5670_VTS_MAX 0xffff + +/* horizontal-timings from sensor */ +#define OV5670_REG_HTS 0x380c + +/* + * Pixels-per-line(PPL) = Time-per-line * pixel-rate + * In OV5670, Time-per-line = HTS/SCLK. + * HTS is fixed for all resolutions, not recommended to change. + */ +#define OV5670_FIXED_PPL 2724 /* Pixels per line */ + +/* Exposure controls from sensor */ +#define OV5670_REG_EXPOSURE 0x3500 +#define OV5670_EXPOSURE_MIN 4 +#define OV5670_EXPOSURE_STEP 1 + +/* Analog gain controls from sensor */ +#define OV5670_REG_ANALOG_GAIN 0x3508 +#define ANALOG_GAIN_MIN 0 +#define ANALOG_GAIN_MAX 8191 +#define ANALOG_GAIN_STEP 1 +#define ANALOG_GAIN_DEFAULT 128 + +/* Digital gain controls from sensor */ +#define OV5670_REG_R_DGTL_GAIN 0x5032 +#define OV5670_REG_G_DGTL_GAIN 0x5034 +#define OV5670_REG_B_DGTL_GAIN 0x5036 +#define OV5670_DGTL_GAIN_MIN 0 +#define OV5670_DGTL_GAIN_MAX 4095 +#define OV5670_DGTL_GAIN_STEP 1 +#define OV5670_DGTL_GAIN_DEFAULT 1024 + +/* Test Pattern Control */ +#define OV5670_REG_TEST_PATTERN 0x4303 +#define OV5670_TEST_PATTERN_ENABLE BIT(3) +#define OV5670_REG_TEST_PATTERN_CTRL 0x4320 + +#define OV5670_REG_VALUE_08BIT 1 +#define OV5670_REG_VALUE_16BIT 2 +#define OV5670_REG_VALUE_24BIT 3 + +/* Initial number of frames to skip to avoid possible garbage */ +#define OV5670_NUM_OF_SKIP_FRAMES 2 + +struct ov5670_reg { + u16 address; + u8 val; +}; + +struct ov5670_reg_list { + u32 num_of_regs; + const struct ov5670_reg *regs; +}; + +struct ov5670_link_freq_config { + u32 pixel_rate; + const struct ov5670_reg_list reg_list; +}; + +struct ov5670_mode { + /* Frame width in pixels */ + u32 width; + + /* Frame height in pixels */ + u32 height; + + /* Default vertical timining size */ + u32 vts_def; + + /* Min vertical timining size */ + u32 vts_min; + + /* Link frequency needed for this resolution */ + u32 link_freq_index; + + /* Sensor register settings for this resolution */ + const struct ov5670_reg_list reg_list; +}; + +static const struct ov5670_reg mipi_data_rate_840mbps[] = { + {0x0300, 0x04}, + {0x0301, 0x00}, + {0x0302, 0x84}, + {0x0303, 0x00}, + {0x0304, 0x03}, + {0x0305, 0x01}, + {0x0306, 0x01}, + {0x030a, 0x00}, + {0x030b, 0x00}, + {0x030c, 0x00}, + {0x030d, 0x26}, + {0x030e, 0x00}, + {0x030f, 0x06}, + {0x0312, 0x01}, + {0x3031, 0x0a}, +}; + +static const struct ov5670_reg mode_2592x1944_regs[] = { + {0x3000, 0x00}, + {0x3002, 0x21}, + {0x3005, 0xf0}, + {0x3007, 0x00}, + {0x3015, 0x0f}, + {0x3018, 0x32}, + {0x301a, 0xf0}, + {0x301b, 0xf0}, + {0x301c, 0xf0}, + {0x301d, 0xf0}, + {0x301e, 0xf0}, + {0x3030, 0x00}, + {0x3031, 0x0a}, + {0x303c, 0xff}, + {0x303e, 0xff}, + {0x3040, 0xf0}, + {0x3041, 0x00}, + {0x3042, 0xf0}, + {0x3106, 0x11}, + {0x3500, 0x00}, + {0x3501, 0x80}, + {0x3502, 0x00}, + {0x3503, 0x04}, + {0x3504, 0x03}, + {0x3505, 0x83}, + {0x3508, 0x04}, + {0x3509, 0x00}, + {0x350e, 0x04}, + {0x350f, 0x00}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3601, 0xc8}, + {0x3610, 0x88}, + {0x3612, 0x48}, + {0x3614, 0x5b}, + {0x3615, 0x96}, + {0x3621, 0xd0}, + {0x3622, 0x00}, + {0x3623, 0x00}, + {0x3633, 0x13}, + {0x3634, 0x13}, + {0x3635, 0x13}, + {0x3636, 0x13}, + {0x3645, 0x13}, + {0x3646, 0x82}, + {0x3650, 0x00}, + {0x3652, 0xff}, + {0x3655, 0x20}, + {0x3656, 0xff}, + {0x365a, 0xff}, + {0x365e, 0xff}, + {0x3668, 0x00}, + {0x366a, 0x07}, + {0x366e, 0x10}, + {0x366d, 0x00}, + {0x366f, 0x80}, + {0x3700, 0x28}, + {0x3701, 0x10}, + {0x3702, 0x3a}, + {0x3703, 0x19}, + {0x3704, 0x10}, + {0x3705, 0x00}, + {0x3706, 0x66}, + {0x3707, 0x08}, + {0x3708, 0x34}, + {0x3709, 0x40}, + {0x370a, 0x01}, + {0x370b, 0x1b}, + {0x3714, 0x24}, + {0x371a, 0x3e}, + {0x3733, 0x00}, + {0x3734, 0x00}, + {0x373a, 0x05}, + {0x373b, 0x06}, + {0x373c, 0x0a}, + {0x373f, 0xa0}, + {0x3755, 0x00}, + {0x3758, 0x00}, + {0x375b, 0x0e}, + {0x3766, 0x5f}, + {0x3768, 0x00}, + {0x3769, 0x22}, + {0x3773, 0x08}, + {0x3774, 0x1f}, + {0x3776, 0x06}, + {0x37a0, 0x88}, + {0x37a1, 0x5c}, + {0x37a7, 0x88}, + {0x37a8, 0x70}, + {0x37aa, 0x88}, + {0x37ab, 0x48}, + {0x37b3, 0x66}, + {0x37c2, 0x04}, + {0x37c5, 0x00}, + {0x37c8, 0x00}, + {0x3800, 0x00}, + {0x3801, 0x0c}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x0a}, + {0x3805, 0x33}, + {0x3806, 0x07}, + {0x3807, 0xa3}, + {0x3808, 0x0a}, + {0x3809, 0x20}, + {0x380a, 0x07}, + {0x380b, 0x98}, + {0x380c, 0x06}, + {0x380d, 0x90}, + {0x380e, 0x08}, + {0x380f, 0x08}, + {0x3811, 0x04}, + {0x3813, 0x02}, + {0x3814, 0x01}, + {0x3815, 0x01}, + {0x3816, 0x00}, + {0x3817, 0x00}, + {0x3818, 0x00}, + {0x3819, 0x00}, + {0x3820, 0x84}, + {0x3821, 0x46}, + {0x3822, 0x48}, + {0x3826, 0x00}, + {0x3827, 0x08}, + {0x382a, 0x01}, + {0x382b, 0x01}, + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3837, 0x00}, + {0x3838, 0x10}, + {0x3841, 0xff}, + {0x3846, 0x48}, + {0x3861, 0x00}, + {0x3862, 0x04}, + {0x3863, 0x06}, + {0x3a11, 0x01}, + {0x3a12, 0x78}, + {0x3b00, 0x00}, + {0x3b02, 0x00}, + {0x3b03, 0x00}, + {0x3b04, 0x00}, + {0x3b05, 0x00}, + {0x3c00, 0x89}, + {0x3c01, 0xab}, + {0x3c02, 0x01}, + {0x3c03, 0x00}, + {0x3c04, 0x00}, + {0x3c05, 0x03}, + {0x3c06, 0x00}, + {0x3c07, 0x05}, + {0x3c0c, 0x00}, + {0x3c0d, 0x00}, + {0x3c0e, 0x00}, + {0x3c0f, 0x00}, + {0x3c40, 0x00}, + {0x3c41, 0xa3}, + {0x3c43, 0x7d}, + {0x3c45, 0xd7}, + {0x3c47, 0xfc}, + {0x3c50, 0x05}, + {0x3c52, 0xaa}, + {0x3c54, 0x71}, + {0x3c56, 0x80}, + {0x3d85, 0x17}, + {0x3f03, 0x00}, + {0x3f0a, 0x00}, + {0x3f0b, 0x00}, + {0x4001, 0x60}, + {0x4009, 0x0d}, + {0x4020, 0x00}, + {0x4021, 0x00}, + {0x4022, 0x00}, + {0x4023, 0x00}, + {0x4024, 0x00}, + {0x4025, 0x00}, + {0x4026, 0x00}, + {0x4027, 0x00}, + {0x4028, 0x00}, + {0x4029, 0x00}, + {0x402a, 0x00}, + {0x402b, 0x00}, + {0x402c, 0x00}, + {0x402d, 0x00}, + {0x402e, 0x00}, + {0x402f, 0x00}, + {0x4040, 0x00}, + {0x4041, 0x03}, + {0x4042, 0x00}, + {0x4043, 0x7A}, + {0x4044, 0x00}, + {0x4045, 0x7A}, + {0x4046, 0x00}, + {0x4047, 0x7A}, + {0x4048, 0x00}, + {0x4049, 0x7A}, + {0x4307, 0x30}, + {0x4500, 0x58}, + {0x4501, 0x04}, + {0x4502, 0x40}, + {0x4503, 0x10}, + {0x4508, 0xaa}, + {0x4509, 0xaa}, + {0x450a, 0x00}, + {0x450b, 0x00}, + {0x4600, 0x01}, + {0x4601, 0x03}, + {0x4700, 0xa4}, + {0x4800, 0x4c}, + {0x4816, 0x53}, + {0x481f, 0x40}, + {0x4837, 0x13}, + {0x5000, 0x56}, + {0x5001, 0x01}, + {0x5002, 0x28}, + {0x5004, 0x0c}, + {0x5006, 0x0c}, + {0x5007, 0xe0}, + {0x5008, 0x01}, + {0x5009, 0xb0}, + {0x5901, 0x00}, + {0x5a01, 0x00}, + {0x5a03, 0x00}, + {0x5a04, 0x0c}, + {0x5a05, 0xe0}, + {0x5a06, 0x09}, + {0x5a07, 0xb0}, + {0x5a08, 0x06}, + {0x5e00, 0x00}, + {0x3734, 0x40}, + {0x5b00, 0x01}, + {0x5b01, 0x10}, + {0x5b02, 0x01}, + {0x5b03, 0xdb}, + {0x3d8c, 0x71}, + {0x3d8d, 0xea}, + {0x4017, 0x08}, + {0x3618, 0x2a}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x3503, 0x00} +}; + +static const struct ov5670_reg mode_1296x972_regs[] = { + {0x3000, 0x00}, + {0x3002, 0x21}, + {0x3005, 0xf0}, + {0x3007, 0x00}, + {0x3015, 0x0f}, + {0x3018, 0x32}, + {0x301a, 0xf0}, + {0x301b, 0xf0}, + {0x301c, 0xf0}, + {0x301d, 0xf0}, + {0x301e, 0xf0}, + {0x3030, 0x00}, + {0x3031, 0x0a}, + {0x303c, 0xff}, + {0x303e, 0xff}, + {0x3040, 0xf0}, + {0x3041, 0x00}, + {0x3042, 0xf0}, + {0x3106, 0x11}, + {0x3500, 0x00}, + {0x3501, 0x80}, + {0x3502, 0x00}, + {0x3503, 0x04}, + {0x3504, 0x03}, + {0x3505, 0x83}, + {0x3508, 0x07}, + {0x3509, 0x80}, + {0x350e, 0x04}, + {0x350f, 0x00}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3601, 0xc8}, + {0x3610, 0x88}, + {0x3612, 0x48}, + {0x3614, 0x5b}, + {0x3615, 0x96}, + {0x3621, 0xd0}, + {0x3622, 0x00}, + {0x3623, 0x00}, + {0x3633, 0x13}, + {0x3634, 0x13}, + {0x3635, 0x13}, + {0x3636, 0x13}, + {0x3645, 0x13}, + {0x3646, 0x82}, + {0x3650, 0x00}, + {0x3652, 0xff}, + {0x3655, 0x20}, + {0x3656, 0xff}, + {0x365a, 0xff}, + {0x365e, 0xff}, + {0x3668, 0x00}, + {0x366a, 0x07}, + {0x366e, 0x08}, + {0x366d, 0x00}, + {0x366f, 0x80}, + {0x3700, 0x28}, + {0x3701, 0x10}, + {0x3702, 0x3a}, + {0x3703, 0x19}, + {0x3704, 0x10}, + {0x3705, 0x00}, + {0x3706, 0x66}, + {0x3707, 0x08}, + {0x3708, 0x34}, + {0x3709, 0x40}, + {0x370a, 0x01}, + {0x370b, 0x1b}, + {0x3714, 0x24}, + {0x371a, 0x3e}, + {0x3733, 0x00}, + {0x3734, 0x00}, + {0x373a, 0x05}, + {0x373b, 0x06}, + {0x373c, 0x0a}, + {0x373f, 0xa0}, + {0x3755, 0x00}, + {0x3758, 0x00}, + {0x375b, 0x0e}, + {0x3766, 0x5f}, + {0x3768, 0x00}, + {0x3769, 0x22}, + {0x3773, 0x08}, + {0x3774, 0x1f}, + {0x3776, 0x06}, + {0x37a0, 0x88}, + {0x37a1, 0x5c}, + {0x37a7, 0x88}, + {0x37a8, 0x70}, + {0x37aa, 0x88}, + {0x37ab, 0x48}, + {0x37b3, 0x66}, + {0x37c2, 0x04}, + {0x37c5, 0x00}, + {0x37c8, 0x00}, + {0x3800, 0x00}, + {0x3801, 0x0c}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x0a}, + {0x3805, 0x33}, + {0x3806, 0x07}, + {0x3807, 0xa3}, + {0x3808, 0x05}, + {0x3809, 0x10}, + {0x380a, 0x03}, + {0x380b, 0xcc}, + {0x380c, 0x06}, + {0x380d, 0x90}, + {0x380e, 0x08}, + {0x380f, 0x08}, + {0x3811, 0x04}, + {0x3813, 0x04}, + {0x3814, 0x03}, + {0x3815, 0x01}, + {0x3816, 0x00}, + {0x3817, 0x00}, + {0x3818, 0x00}, + {0x3819, 0x00}, + {0x3820, 0x94}, + {0x3821, 0x47}, + {0x3822, 0x48}, + {0x3826, 0x00}, + {0x3827, 0x08}, + {0x382a, 0x03}, + {0x382b, 0x01}, + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3837, 0x00}, + {0x3838, 0x10}, + {0x3841, 0xff}, + {0x3846, 0x48}, + {0x3861, 0x00}, + {0x3862, 0x04}, + {0x3863, 0x06}, + {0x3a11, 0x01}, + {0x3a12, 0x78}, + {0x3b00, 0x00}, + {0x3b02, 0x00}, + {0x3b03, 0x00}, + {0x3b04, 0x00}, + {0x3b05, 0x00}, + {0x3c00, 0x89}, + {0x3c01, 0xab}, + {0x3c02, 0x01}, + {0x3c03, 0x00}, + {0x3c04, 0x00}, + {0x3c05, 0x03}, + {0x3c06, 0x00}, + {0x3c07, 0x05}, + {0x3c0c, 0x00}, + {0x3c0d, 0x00}, + {0x3c0e, 0x00}, + {0x3c0f, 0x00}, + {0x3c40, 0x00}, + {0x3c41, 0xa3}, + {0x3c43, 0x7d}, + {0x3c45, 0xd7}, + {0x3c47, 0xfc}, + {0x3c50, 0x05}, + {0x3c52, 0xaa}, + {0x3c54, 0x71}, + {0x3c56, 0x80}, + {0x3d85, 0x17}, + {0x3f03, 0x00}, + {0x3f0a, 0x00}, + {0x3f0b, 0x00}, + {0x4001, 0x60}, + {0x4009, 0x05}, + {0x4020, 0x00}, + {0x4021, 0x00}, + {0x4022, 0x00}, + {0x4023, 0x00}, + {0x4024, 0x00}, + {0x4025, 0x00}, + {0x4026, 0x00}, + {0x4027, 0x00}, + {0x4028, 0x00}, + {0x4029, 0x00}, + {0x402a, 0x00}, + {0x402b, 0x00}, + {0x402c, 0x00}, + {0x402d, 0x00}, + {0x402e, 0x00}, + {0x402f, 0x00}, + {0x4040, 0x00}, + {0x4041, 0x03}, + {0x4042, 0x00}, + {0x4043, 0x7A}, + {0x4044, 0x00}, + {0x4045, 0x7A}, + {0x4046, 0x00}, + {0x4047, 0x7A}, + {0x4048, 0x00}, + {0x4049, 0x7A}, + {0x4307, 0x30}, + {0x4500, 0x58}, + {0x4501, 0x04}, + {0x4502, 0x48}, + {0x4503, 0x10}, + {0x4508, 0x55}, + {0x4509, 0x55}, + {0x450a, 0x00}, + {0x450b, 0x00}, + {0x4600, 0x00}, + {0x4601, 0x81}, + {0x4700, 0xa4}, + {0x4800, 0x4c}, + {0x4816, 0x53}, + {0x481f, 0x40}, + {0x4837, 0x13}, + {0x5000, 0x56}, + {0x5001, 0x01}, + {0x5002, 0x28}, + {0x5004, 0x0c}, + {0x5006, 0x0c}, + {0x5007, 0xe0}, + {0x5008, 0x01}, + {0x5009, 0xb0}, + {0x5901, 0x00}, + {0x5a01, 0x00}, + {0x5a03, 0x00}, + {0x5a04, 0x0c}, + {0x5a05, 0xe0}, + {0x5a06, 0x09}, + {0x5a07, 0xb0}, + {0x5a08, 0x06}, + {0x5e00, 0x00}, + {0x3734, 0x40}, + {0x5b00, 0x01}, + {0x5b01, 0x10}, + {0x5b02, 0x01}, + {0x5b03, 0xdb}, + {0x3d8c, 0x71}, + {0x3d8d, 0xea}, + {0x4017, 0x10}, + {0x3618, 0x2a}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x04}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x3503, 0x00} +}; + +static const struct ov5670_reg mode_648x486_regs[] = { + {0x3000, 0x00}, + {0x3002, 0x21}, + {0x3005, 0xf0}, + {0x3007, 0x00}, + {0x3015, 0x0f}, + {0x3018, 0x32}, + {0x301a, 0xf0}, + {0x301b, 0xf0}, + {0x301c, 0xf0}, + {0x301d, 0xf0}, + {0x301e, 0xf0}, + {0x3030, 0x00}, + {0x3031, 0x0a}, + {0x303c, 0xff}, + {0x303e, 0xff}, + {0x3040, 0xf0}, + {0x3041, 0x00}, + {0x3042, 0xf0}, + {0x3106, 0x11}, + {0x3500, 0x00}, + {0x3501, 0x80}, + {0x3502, 0x00}, + {0x3503, 0x04}, + {0x3504, 0x03}, + {0x3505, 0x83}, + {0x3508, 0x04}, + {0x3509, 0x00}, + {0x350e, 0x04}, + {0x350f, 0x00}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3601, 0xc8}, + {0x3610, 0x88}, + {0x3612, 0x48}, + {0x3614, 0x5b}, + {0x3615, 0x96}, + {0x3621, 0xd0}, + {0x3622, 0x00}, + {0x3623, 0x04}, + {0x3633, 0x13}, + {0x3634, 0x13}, + {0x3635, 0x13}, + {0x3636, 0x13}, + {0x3645, 0x13}, + {0x3646, 0x82}, + {0x3650, 0x00}, + {0x3652, 0xff}, + {0x3655, 0x20}, + {0x3656, 0xff}, + {0x365a, 0xff}, + {0x365e, 0xff}, + {0x3668, 0x00}, + {0x366a, 0x07}, + {0x366e, 0x08}, + {0x366d, 0x00}, + {0x366f, 0x80}, + {0x3700, 0x28}, + {0x3701, 0x10}, + {0x3702, 0x3a}, + {0x3703, 0x19}, + {0x3704, 0x10}, + {0x3705, 0x00}, + {0x3706, 0x66}, + {0x3707, 0x08}, + {0x3708, 0x34}, + {0x3709, 0x40}, + {0x370a, 0x01}, + {0x370b, 0x1b}, + {0x3714, 0x24}, + {0x371a, 0x3e}, + {0x3733, 0x00}, + {0x3734, 0x00}, + {0x373a, 0x05}, + {0x373b, 0x06}, + {0x373c, 0x0a}, + {0x373f, 0xa0}, + {0x3755, 0x00}, + {0x3758, 0x00}, + {0x375b, 0x0e}, + {0x3766, 0x5f}, + {0x3768, 0x00}, + {0x3769, 0x22}, + {0x3773, 0x08}, + {0x3774, 0x1f}, + {0x3776, 0x06}, + {0x37a0, 0x88}, + {0x37a1, 0x5c}, + {0x37a7, 0x88}, + {0x37a8, 0x70}, + {0x37aa, 0x88}, + {0x37ab, 0x48}, + {0x37b3, 0x66}, + {0x37c2, 0x04}, + {0x37c5, 0x00}, + {0x37c8, 0x00}, + {0x3800, 0x00}, + {0x3801, 0x0c}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x0a}, + {0x3805, 0x33}, + {0x3806, 0x07}, + {0x3807, 0xa3}, + {0x3808, 0x02}, + {0x3809, 0x88}, + {0x380a, 0x01}, + {0x380b, 0xe6}, + {0x380c, 0x06}, + {0x380d, 0x90}, + {0x380e, 0x08}, + {0x380f, 0x08}, + {0x3811, 0x04}, + {0x3813, 0x02}, + {0x3814, 0x07}, + {0x3815, 0x01}, + {0x3816, 0x00}, + {0x3817, 0x00}, + {0x3818, 0x00}, + {0x3819, 0x00}, + {0x3820, 0x94}, + {0x3821, 0xc6}, + {0x3822, 0x48}, + {0x3826, 0x00}, + {0x3827, 0x08}, + {0x382a, 0x07}, + {0x382b, 0x01}, + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3837, 0x00}, + {0x3838, 0x10}, + {0x3841, 0xff}, + {0x3846, 0x48}, + {0x3861, 0x00}, + {0x3862, 0x04}, + {0x3863, 0x06}, + {0x3a11, 0x01}, + {0x3a12, 0x78}, + {0x3b00, 0x00}, + {0x3b02, 0x00}, + {0x3b03, 0x00}, + {0x3b04, 0x00}, + {0x3b05, 0x00}, + {0x3c00, 0x89}, + {0x3c01, 0xab}, + {0x3c02, 0x01}, + {0x3c03, 0x00}, + {0x3c04, 0x00}, + {0x3c05, 0x03}, + {0x3c06, 0x00}, + {0x3c07, 0x05}, + {0x3c0c, 0x00}, + {0x3c0d, 0x00}, + {0x3c0e, 0x00}, + {0x3c0f, 0x00}, + {0x3c40, 0x00}, + {0x3c41, 0xa3}, + {0x3c43, 0x7d}, + {0x3c45, 0xd7}, + {0x3c47, 0xfc}, + {0x3c50, 0x05}, + {0x3c52, 0xaa}, + {0x3c54, 0x71}, + {0x3c56, 0x80}, + {0x3d85, 0x17}, + {0x3f03, 0x00}, + {0x3f0a, 0x00}, + {0x3f0b, 0x00}, + {0x4001, 0x60}, + {0x4009, 0x05}, + {0x4020, 0x00}, + {0x4021, 0x00}, + {0x4022, 0x00}, + {0x4023, 0x00}, + {0x4024, 0x00}, + {0x4025, 0x00}, + {0x4026, 0x00}, + {0x4027, 0x00}, + {0x4028, 0x00}, + {0x4029, 0x00}, + {0x402a, 0x00}, + {0x402b, 0x00}, + {0x402c, 0x00}, + {0x402d, 0x00}, + {0x402e, 0x00}, + {0x402f, 0x00}, + {0x4040, 0x00}, + {0x4041, 0x03}, + {0x4042, 0x00}, + {0x4043, 0x7A}, + {0x4044, 0x00}, + {0x4045, 0x7A}, + {0x4046, 0x00}, + {0x4047, 0x7A}, + {0x4048, 0x00}, + {0x4049, 0x7A}, + {0x4307, 0x30}, + {0x4500, 0x58}, + {0x4501, 0x04}, + {0x4502, 0x40}, + {0x4503, 0x10}, + {0x4508, 0x55}, + {0x4509, 0x55}, + {0x450a, 0x02}, + {0x450b, 0x00}, + {0x4600, 0x00}, + {0x4601, 0x40}, + {0x4700, 0xa4}, + {0x4800, 0x4c}, + {0x4816, 0x53}, + {0x481f, 0x40}, + {0x4837, 0x13}, + {0x5000, 0x56}, + {0x5001, 0x01}, + {0x5002, 0x28}, + {0x5004, 0x0c}, + {0x5006, 0x0c}, + {0x5007, 0xe0}, + {0x5008, 0x01}, + {0x5009, 0xb0}, + {0x5901, 0x00}, + {0x5a01, 0x00}, + {0x5a03, 0x00}, + {0x5a04, 0x0c}, + {0x5a05, 0xe0}, + {0x5a06, 0x09}, + {0x5a07, 0xb0}, + {0x5a08, 0x06}, + {0x5e00, 0x00}, + {0x3734, 0x40}, + {0x5b00, 0x01}, + {0x5b01, 0x10}, + {0x5b02, 0x01}, + {0x5b03, 0xdb}, + {0x3d8c, 0x71}, + {0x3d8d, 0xea}, + {0x4017, 0x10}, + {0x3618, 0x2a}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x3503, 0x00} +}; + +static const struct ov5670_reg mode_2560x1440_regs[] = { + {0x3000, 0x00}, + {0x3002, 0x21}, + {0x3005, 0xf0}, + {0x3007, 0x00}, + {0x3015, 0x0f}, + {0x3018, 0x32}, + {0x301a, 0xf0}, + {0x301b, 0xf0}, + {0x301c, 0xf0}, + {0x301d, 0xf0}, + {0x301e, 0xf0}, + {0x3030, 0x00}, + {0x3031, 0x0a}, + {0x303c, 0xff}, + {0x303e, 0xff}, + {0x3040, 0xf0}, + {0x3041, 0x00}, + {0x3042, 0xf0}, + {0x3106, 0x11}, + {0x3500, 0x00}, + {0x3501, 0x80}, + {0x3502, 0x00}, + {0x3503, 0x04}, + {0x3504, 0x03}, + {0x3505, 0x83}, + {0x3508, 0x04}, + {0x3509, 0x00}, + {0x350e, 0x04}, + {0x350f, 0x00}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3601, 0xc8}, + {0x3610, 0x88}, + {0x3612, 0x48}, + {0x3614, 0x5b}, + {0x3615, 0x96}, + {0x3621, 0xd0}, + {0x3622, 0x00}, + {0x3623, 0x00}, + {0x3633, 0x13}, + {0x3634, 0x13}, + {0x3635, 0x13}, + {0x3636, 0x13}, + {0x3645, 0x13}, + {0x3646, 0x82}, + {0x3650, 0x00}, + {0x3652, 0xff}, + {0x3655, 0x20}, + {0x3656, 0xff}, + {0x365a, 0xff}, + {0x365e, 0xff}, + {0x3668, 0x00}, + {0x366a, 0x07}, + {0x366e, 0x10}, + {0x366d, 0x00}, + {0x366f, 0x80}, + {0x3700, 0x28}, + {0x3701, 0x10}, + {0x3702, 0x3a}, + {0x3703, 0x19}, + {0x3704, 0x10}, + {0x3705, 0x00}, + {0x3706, 0x66}, + {0x3707, 0x08}, + {0x3708, 0x34}, + {0x3709, 0x40}, + {0x370a, 0x01}, + {0x370b, 0x1b}, + {0x3714, 0x24}, + {0x371a, 0x3e}, + {0x3733, 0x00}, + {0x3734, 0x00}, + {0x373a, 0x05}, + {0x373b, 0x06}, + {0x373c, 0x0a}, + {0x373f, 0xa0}, + {0x3755, 0x00}, + {0x3758, 0x00}, + {0x375b, 0x0e}, + {0x3766, 0x5f}, + {0x3768, 0x00}, + {0x3769, 0x22}, + {0x3773, 0x08}, + {0x3774, 0x1f}, + {0x3776, 0x06}, + {0x37a0, 0x88}, + {0x37a1, 0x5c}, + {0x37a7, 0x88}, + {0x37a8, 0x70}, + {0x37aa, 0x88}, + {0x37ab, 0x48}, + {0x37b3, 0x66}, + {0x37c2, 0x04}, + {0x37c5, 0x00}, + {0x37c8, 0x00}, + {0x3800, 0x00}, + {0x3801, 0x0c}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x0a}, + {0x3805, 0x33}, + {0x3806, 0x07}, + {0x3807, 0xa3}, + {0x3808, 0x0a}, + {0x3809, 0x00}, + {0x380a, 0x05}, + {0x380b, 0xa0}, + {0x380c, 0x06}, + {0x380d, 0x90}, + {0x380e, 0x08}, + {0x380f, 0x08}, + {0x3811, 0x04}, + {0x3813, 0x02}, + {0x3814, 0x01}, + {0x3815, 0x01}, + {0x3816, 0x00}, + {0x3817, 0x00}, + {0x3818, 0x00}, + {0x3819, 0x00}, + {0x3820, 0x84}, + {0x3821, 0x46}, + {0x3822, 0x48}, + {0x3826, 0x00}, + {0x3827, 0x08}, + {0x382a, 0x01}, + {0x382b, 0x01}, + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3837, 0x00}, + {0x3838, 0x10}, + {0x3841, 0xff}, + {0x3846, 0x48}, + {0x3861, 0x00}, + {0x3862, 0x04}, + {0x3863, 0x06}, + {0x3a11, 0x01}, + {0x3a12, 0x78}, + {0x3b00, 0x00}, + {0x3b02, 0x00}, + {0x3b03, 0x00}, + {0x3b04, 0x00}, + {0x3b05, 0x00}, + {0x3c00, 0x89}, + {0x3c01, 0xab}, + {0x3c02, 0x01}, + {0x3c03, 0x00}, + {0x3c04, 0x00}, + {0x3c05, 0x03}, + {0x3c06, 0x00}, + {0x3c07, 0x05}, + {0x3c0c, 0x00}, + {0x3c0d, 0x00}, + {0x3c0e, 0x00}, + {0x3c0f, 0x00}, + {0x3c40, 0x00}, + {0x3c41, 0xa3}, + {0x3c43, 0x7d}, + {0x3c45, 0xd7}, + {0x3c47, 0xfc}, + {0x3c50, 0x05}, + {0x3c52, 0xaa}, + {0x3c54, 0x71}, + {0x3c56, 0x80}, + {0x3d85, 0x17}, + {0x3f03, 0x00}, + {0x3f0a, 0x00}, + {0x3f0b, 0x00}, + {0x4001, 0x60}, + {0x4009, 0x0d}, + {0x4020, 0x00}, + {0x4021, 0x00}, + {0x4022, 0x00}, + {0x4023, 0x00}, + {0x4024, 0x00}, + {0x4025, 0x00}, + {0x4026, 0x00}, + {0x4027, 0x00}, + {0x4028, 0x00}, + {0x4029, 0x00}, + {0x402a, 0x00}, + {0x402b, 0x00}, + {0x402c, 0x00}, + {0x402d, 0x00}, + {0x402e, 0x00}, + {0x402f, 0x00}, + {0x4040, 0x00}, + {0x4041, 0x03}, + {0x4042, 0x00}, + {0x4043, 0x7A}, + {0x4044, 0x00}, + {0x4045, 0x7A}, + {0x4046, 0x00}, + {0x4047, 0x7A}, + {0x4048, 0x00}, + {0x4049, 0x7A}, + {0x4307, 0x30}, + {0x4500, 0x58}, + {0x4501, 0x04}, + {0x4502, 0x40}, + {0x4503, 0x10}, + {0x4508, 0xaa}, + {0x4509, 0xaa}, + {0x450a, 0x00}, + {0x450b, 0x00}, + {0x4600, 0x01}, + {0x4601, 0x00}, + {0x4700, 0xa4}, + {0x4800, 0x4c}, + {0x4816, 0x53}, + {0x481f, 0x40}, + {0x4837, 0x13}, + {0x5000, 0x56}, + {0x5001, 0x01}, + {0x5002, 0x28}, + {0x5004, 0x0c}, + {0x5006, 0x0c}, + {0x5007, 0xe0}, + {0x5008, 0x01}, + {0x5009, 0xb0}, + {0x5901, 0x00}, + {0x5a01, 0x00}, + {0x5a03, 0x00}, + {0x5a04, 0x0c}, + {0x5a05, 0xe0}, + {0x5a06, 0x09}, + {0x5a07, 0xb0}, + {0x5a08, 0x06}, + {0x5e00, 0x00}, + {0x3734, 0x40}, + {0x5b00, 0x01}, + {0x5b01, 0x10}, + {0x5b02, 0x01}, + {0x5b03, 0xdb}, + {0x3d8c, 0x71}, + {0x3d8d, 0xea}, + {0x4017, 0x08}, + {0x3618, 0x2a}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3} +}; + +static const struct ov5670_reg mode_1280x720_regs[] = { + {0x3000, 0x00}, + {0x3002, 0x21}, + {0x3005, 0xf0}, + {0x3007, 0x00}, + {0x3015, 0x0f}, + {0x3018, 0x32}, + {0x301a, 0xf0}, + {0x301b, 0xf0}, + {0x301c, 0xf0}, + {0x301d, 0xf0}, + {0x301e, 0xf0}, + {0x3030, 0x00}, + {0x3031, 0x0a}, + {0x303c, 0xff}, + {0x303e, 0xff}, + {0x3040, 0xf0}, + {0x3041, 0x00}, + {0x3042, 0xf0}, + {0x3106, 0x11}, + {0x3500, 0x00}, + {0x3501, 0x80}, + {0x3502, 0x00}, + {0x3503, 0x04}, + {0x3504, 0x03}, + {0x3505, 0x83}, + {0x3508, 0x04}, + {0x3509, 0x00}, + {0x350e, 0x04}, + {0x350f, 0x00}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3601, 0xc8}, + {0x3610, 0x88}, + {0x3612, 0x48}, + {0x3614, 0x5b}, + {0x3615, 0x96}, + {0x3621, 0xd0}, + {0x3622, 0x00}, + {0x3623, 0x00}, + {0x3633, 0x13}, + {0x3634, 0x13}, + {0x3635, 0x13}, + {0x3636, 0x13}, + {0x3645, 0x13}, + {0x3646, 0x82}, + {0x3650, 0x00}, + {0x3652, 0xff}, + {0x3655, 0x20}, + {0x3656, 0xff}, + {0x365a, 0xff}, + {0x365e, 0xff}, + {0x3668, 0x00}, + {0x366a, 0x07}, + {0x366e, 0x08}, + {0x366d, 0x00}, + {0x366f, 0x80}, + {0x3700, 0x28}, + {0x3701, 0x10}, + {0x3702, 0x3a}, + {0x3703, 0x19}, + {0x3704, 0x10}, + {0x3705, 0x00}, + {0x3706, 0x66}, + {0x3707, 0x08}, + {0x3708, 0x34}, + {0x3709, 0x40}, + {0x370a, 0x01}, + {0x370b, 0x1b}, + {0x3714, 0x24}, + {0x371a, 0x3e}, + {0x3733, 0x00}, + {0x3734, 0x00}, + {0x373a, 0x05}, + {0x373b, 0x06}, + {0x373c, 0x0a}, + {0x373f, 0xa0}, + {0x3755, 0x00}, + {0x3758, 0x00}, + {0x375b, 0x0e}, + {0x3766, 0x5f}, + {0x3768, 0x00}, + {0x3769, 0x22}, + {0x3773, 0x08}, + {0x3774, 0x1f}, + {0x3776, 0x06}, + {0x37a0, 0x88}, + {0x37a1, 0x5c}, + {0x37a7, 0x88}, + {0x37a8, 0x70}, + {0x37aa, 0x88}, + {0x37ab, 0x48}, + {0x37b3, 0x66}, + {0x37c2, 0x04}, + {0x37c5, 0x00}, + {0x37c8, 0x00}, + {0x3800, 0x00}, + {0x3801, 0x0c}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x0a}, + {0x3805, 0x33}, + {0x3806, 0x07}, + {0x3807, 0xa3}, + {0x3808, 0x05}, + {0x3809, 0x00}, + {0x380a, 0x02}, + {0x380b, 0xd0}, + {0x380c, 0x06}, + {0x380d, 0x90}, + {0x380e, 0x08}, + {0x380f, 0x08}, + {0x3811, 0x04}, + {0x3813, 0x02}, + {0x3814, 0x03}, + {0x3815, 0x01}, + {0x3816, 0x00}, + {0x3817, 0x00}, + {0x3818, 0x00}, + {0x3819, 0x00}, + {0x3820, 0x94}, + {0x3821, 0x47}, + {0x3822, 0x48}, + {0x3826, 0x00}, + {0x3827, 0x08}, + {0x382a, 0x03}, + {0x382b, 0x01}, + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3837, 0x00}, + {0x3838, 0x10}, + {0x3841, 0xff}, + {0x3846, 0x48}, + {0x3861, 0x00}, + {0x3862, 0x04}, + {0x3863, 0x06}, + {0x3a11, 0x01}, + {0x3a12, 0x78}, + {0x3b00, 0x00}, + {0x3b02, 0x00}, + {0x3b03, 0x00}, + {0x3b04, 0x00}, + {0x3b05, 0x00}, + {0x3c00, 0x89}, + {0x3c01, 0xab}, + {0x3c02, 0x01}, + {0x3c03, 0x00}, + {0x3c04, 0x00}, + {0x3c05, 0x03}, + {0x3c06, 0x00}, + {0x3c07, 0x05}, + {0x3c0c, 0x00}, + {0x3c0d, 0x00}, + {0x3c0e, 0x00}, + {0x3c0f, 0x00}, + {0x3c40, 0x00}, + {0x3c41, 0xa3}, + {0x3c43, 0x7d}, + {0x3c45, 0xd7}, + {0x3c47, 0xfc}, + {0x3c50, 0x05}, + {0x3c52, 0xaa}, + {0x3c54, 0x71}, + {0x3c56, 0x80}, + {0x3d85, 0x17}, + {0x3f03, 0x00}, + {0x3f0a, 0x00}, + {0x3f0b, 0x00}, + {0x4001, 0x60}, + {0x4009, 0x05}, + {0x4020, 0x00}, + {0x4021, 0x00}, + {0x4022, 0x00}, + {0x4023, 0x00}, + {0x4024, 0x00}, + {0x4025, 0x00}, + {0x4026, 0x00}, + {0x4027, 0x00}, + {0x4028, 0x00}, + {0x4029, 0x00}, + {0x402a, 0x00}, + {0x402b, 0x00}, + {0x402c, 0x00}, + {0x402d, 0x00}, + {0x402e, 0x00}, + {0x402f, 0x00}, + {0x4040, 0x00}, + {0x4041, 0x03}, + {0x4042, 0x00}, + {0x4043, 0x7A}, + {0x4044, 0x00}, + {0x4045, 0x7A}, + {0x4046, 0x00}, + {0x4047, 0x7A}, + {0x4048, 0x00}, + {0x4049, 0x7A}, + {0x4307, 0x30}, + {0x4500, 0x58}, + {0x4501, 0x04}, + {0x4502, 0x48}, + {0x4503, 0x10}, + {0x4508, 0x55}, + {0x4509, 0x55}, + {0x450a, 0x00}, + {0x450b, 0x00}, + {0x4600, 0x00}, + {0x4601, 0x80}, + {0x4700, 0xa4}, + {0x4800, 0x4c}, + {0x4816, 0x53}, + {0x481f, 0x40}, + {0x4837, 0x13}, + {0x5000, 0x56}, + {0x5001, 0x01}, + {0x5002, 0x28}, + {0x5004, 0x0c}, + {0x5006, 0x0c}, + {0x5007, 0xe0}, + {0x5008, 0x01}, + {0x5009, 0xb0}, + {0x5901, 0x00}, + {0x5a01, 0x00}, + {0x5a03, 0x00}, + {0x5a04, 0x0c}, + {0x5a05, 0xe0}, + {0x5a06, 0x09}, + {0x5a07, 0xb0}, + {0x5a08, 0x06}, + {0x5e00, 0x00}, + {0x3734, 0x40}, + {0x5b00, 0x01}, + {0x5b01, 0x10}, + {0x5b02, 0x01}, + {0x5b03, 0xdb}, + {0x3d8c, 0x71}, + {0x3d8d, 0xea}, + {0x4017, 0x10}, + {0x3618, 0x2a}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x3503, 0x00} +}; + +static const struct ov5670_reg mode_640x360_regs[] = { + {0x3000, 0x00}, + {0x3002, 0x21}, + {0x3005, 0xf0}, + {0x3007, 0x00}, + {0x3015, 0x0f}, + {0x3018, 0x32}, + {0x301a, 0xf0}, + {0x301b, 0xf0}, + {0x301c, 0xf0}, + {0x301d, 0xf0}, + {0x301e, 0xf0}, + {0x3030, 0x00}, + {0x3031, 0x0a}, + {0x303c, 0xff}, + {0x303e, 0xff}, + {0x3040, 0xf0}, + {0x3041, 0x00}, + {0x3042, 0xf0}, + {0x3106, 0x11}, + {0x3500, 0x00}, + {0x3501, 0x80}, + {0x3502, 0x00}, + {0x3503, 0x04}, + {0x3504, 0x03}, + {0x3505, 0x83}, + {0x3508, 0x04}, + {0x3509, 0x00}, + {0x350e, 0x04}, + {0x350f, 0x00}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3601, 0xc8}, + {0x3610, 0x88}, + {0x3612, 0x48}, + {0x3614, 0x5b}, + {0x3615, 0x96}, + {0x3621, 0xd0}, + {0x3622, 0x00}, + {0x3623, 0x04}, + {0x3633, 0x13}, + {0x3634, 0x13}, + {0x3635, 0x13}, + {0x3636, 0x13}, + {0x3645, 0x13}, + {0x3646, 0x82}, + {0x3650, 0x00}, + {0x3652, 0xff}, + {0x3655, 0x20}, + {0x3656, 0xff}, + {0x365a, 0xff}, + {0x365e, 0xff}, + {0x3668, 0x00}, + {0x366a, 0x07}, + {0x366e, 0x08}, + {0x366d, 0x00}, + {0x366f, 0x80}, + {0x3700, 0x28}, + {0x3701, 0x10}, + {0x3702, 0x3a}, + {0x3703, 0x19}, + {0x3704, 0x10}, + {0x3705, 0x00}, + {0x3706, 0x66}, + {0x3707, 0x08}, + {0x3708, 0x34}, + {0x3709, 0x40}, + {0x370a, 0x01}, + {0x370b, 0x1b}, + {0x3714, 0x24}, + {0x371a, 0x3e}, + {0x3733, 0x00}, + {0x3734, 0x00}, + {0x373a, 0x05}, + {0x373b, 0x06}, + {0x373c, 0x0a}, + {0x373f, 0xa0}, + {0x3755, 0x00}, + {0x3758, 0x00}, + {0x375b, 0x0e}, + {0x3766, 0x5f}, + {0x3768, 0x00}, + {0x3769, 0x22}, + {0x3773, 0x08}, + {0x3774, 0x1f}, + {0x3776, 0x06}, + {0x37a0, 0x88}, + {0x37a1, 0x5c}, + {0x37a7, 0x88}, + {0x37a8, 0x70}, + {0x37aa, 0x88}, + {0x37ab, 0x48}, + {0x37b3, 0x66}, + {0x37c2, 0x04}, + {0x37c5, 0x00}, + {0x37c8, 0x00}, + {0x3800, 0x00}, + {0x3801, 0x0c}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x0a}, + {0x3805, 0x33}, + {0x3806, 0x07}, + {0x3807, 0xa3}, + {0x3808, 0x02}, + {0x3809, 0x80}, + {0x380a, 0x01}, + {0x380b, 0x68}, + {0x380c, 0x06}, + {0x380d, 0x90}, + {0x380e, 0x08}, + {0x380f, 0x08}, + {0x3811, 0x04}, + {0x3813, 0x02}, + {0x3814, 0x07}, + {0x3815, 0x01}, + {0x3816, 0x00}, + {0x3817, 0x00}, + {0x3818, 0x00}, + {0x3819, 0x00}, + {0x3820, 0x94}, + {0x3821, 0xc6}, + {0x3822, 0x48}, + {0x3826, 0x00}, + {0x3827, 0x08}, + {0x382a, 0x07}, + {0x382b, 0x01}, + {0x3830, 0x08}, + {0x3836, 0x02}, + {0x3837, 0x00}, + {0x3838, 0x10}, + {0x3841, 0xff}, + {0x3846, 0x48}, + {0x3861, 0x00}, + {0x3862, 0x04}, + {0x3863, 0x06}, + {0x3a11, 0x01}, + {0x3a12, 0x78}, + {0x3b00, 0x00}, + {0x3b02, 0x00}, + {0x3b03, 0x00}, + {0x3b04, 0x00}, + {0x3b05, 0x00}, + {0x3c00, 0x89}, + {0x3c01, 0xab}, + {0x3c02, 0x01}, + {0x3c03, 0x00}, + {0x3c04, 0x00}, + {0x3c05, 0x03}, + {0x3c06, 0x00}, + {0x3c07, 0x05}, + {0x3c0c, 0x00}, + {0x3c0d, 0x00}, + {0x3c0e, 0x00}, + {0x3c0f, 0x00}, + {0x3c40, 0x00}, + {0x3c41, 0xa3}, + {0x3c43, 0x7d}, + {0x3c45, 0xd7}, + {0x3c47, 0xfc}, + {0x3c50, 0x05}, + {0x3c52, 0xaa}, + {0x3c54, 0x71}, + {0x3c56, 0x80}, + {0x3d85, 0x17}, + {0x3f03, 0x00}, + {0x3f0a, 0x00}, + {0x3f0b, 0x00}, + {0x4001, 0x60}, + {0x4009, 0x05}, + {0x4020, 0x00}, + {0x4021, 0x00}, + {0x4022, 0x00}, + {0x4023, 0x00}, + {0x4024, 0x00}, + {0x4025, 0x00}, + {0x4026, 0x00}, + {0x4027, 0x00}, + {0x4028, 0x00}, + {0x4029, 0x00}, + {0x402a, 0x00}, + {0x402b, 0x00}, + {0x402c, 0x00}, + {0x402d, 0x00}, + {0x402e, 0x00}, + {0x402f, 0x00}, + {0x4040, 0x00}, + {0x4041, 0x03}, + {0x4042, 0x00}, + {0x4043, 0x7A}, + {0x4044, 0x00}, + {0x4045, 0x7A}, + {0x4046, 0x00}, + {0x4047, 0x7A}, + {0x4048, 0x00}, + {0x4049, 0x7A}, + {0x4307, 0x30}, + {0x4500, 0x58}, + {0x4501, 0x04}, + {0x4502, 0x40}, + {0x4503, 0x10}, + {0x4508, 0x55}, + {0x4509, 0x55}, + {0x450a, 0x02}, + {0x450b, 0x00}, + {0x4600, 0x00}, + {0x4601, 0x40}, + {0x4700, 0xa4}, + {0x4800, 0x4c}, + {0x4816, 0x53}, + {0x481f, 0x40}, + {0x4837, 0x13}, + {0x5000, 0x56}, + {0x5001, 0x01}, + {0x5002, 0x28}, + {0x5004, 0x0c}, + {0x5006, 0x0c}, + {0x5007, 0xe0}, + {0x5008, 0x01}, + {0x5009, 0xb0}, + {0x5901, 0x00}, + {0x5a01, 0x00}, + {0x5a03, 0x00}, + {0x5a04, 0x0c}, + {0x5a05, 0xe0}, + {0x5a06, 0x09}, + {0x5a07, 0xb0}, + {0x5a08, 0x06}, + {0x5e00, 0x00}, + {0x3734, 0x40}, + {0x5b00, 0x01}, + {0x5b01, 0x10}, + {0x5b02, 0x01}, + {0x5b03, 0xdb}, + {0x3d8c, 0x71}, + {0x3d8d, 0xea}, + {0x4017, 0x10}, + {0x3618, 0x2a}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x06}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x3503, 0x00} +}; + +static const char * const ov5670_test_pattern_menu[] = { + "Disabled", + "Vertical Color Bar Type 1", +}; + +/* Supported link frequencies */ +#define OV5670_LINK_FREQ_422MHZ 422400000 +#define OV5670_LINK_FREQ_422MHZ_INDEX 0 +static const struct ov5670_link_freq_config link_freq_configs[] = { + { + /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ + .pixel_rate = (OV5670_LINK_FREQ_422MHZ * 2 * 2) / 10, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mipi_data_rate_840mbps), + .regs = mipi_data_rate_840mbps, + } + } +}; + +static const s64 link_freq_menu_items[] = { + OV5670_LINK_FREQ_422MHZ +}; + +/* + * OV5670 sensor supports following resolutions with full FOV: + * 4:3 ==> {2592x1944, 1296x972, 648x486} + * 16:9 ==> {2560x1440, 1280x720, 640x360} + */ +static const struct ov5670_mode supported_modes[] = { + { + .width = 2592, + .height = 1944, + .vts_def = OV5670_VTS_30FPS, + .vts_min = OV5670_VTS_30FPS, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_2592x1944_regs), + .regs = mode_2592x1944_regs, + }, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + }, + { + .width = 1296, + .height = 972, + .vts_def = OV5670_VTS_30FPS, + .vts_min = 996, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1296x972_regs), + .regs = mode_1296x972_regs, + }, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + }, + { + .width = 648, + .height = 486, + .vts_def = OV5670_VTS_30FPS, + .vts_min = 516, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_648x486_regs), + .regs = mode_648x486_regs, + }, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + }, + { + .width = 2560, + .height = 1440, + .vts_def = OV5670_VTS_30FPS, + .vts_min = OV5670_VTS_30FPS, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_2560x1440_regs), + .regs = mode_2560x1440_regs, + }, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + }, + { + .width = 1280, + .height = 720, + .vts_def = OV5670_VTS_30FPS, + .vts_min = 1020, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), + .regs = mode_1280x720_regs, + }, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + }, + { + .width = 640, + .height = 360, + .vts_def = OV5670_VTS_30FPS, + .vts_min = 510, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_640x360_regs), + .regs = mode_640x360_regs, + }, + .link_freq_index = OV5670_LINK_FREQ_422MHZ_INDEX, + } +}; + +struct ov5670 { + struct v4l2_subdev sd; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrl_handler; + /* V4L2 Controls */ + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *exposure; + + /* Current mode */ + const struct ov5670_mode *cur_mode; + + /* To serialize asynchronus callbacks */ + struct mutex mutex; + + /* Streaming on/off */ + bool streaming; +}; + +#define to_ov5670(_sd) container_of(_sd, struct ov5670, sd) + +/* Read registers up to 4 at a time */ +static int ov5670_read_reg(struct ov5670 *ov5670, u16 reg, unsigned int len, + u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); + struct i2c_msg msgs[2]; + u8 *data_be_p; + u32 data_be = 0; + u16 reg_addr_be = cpu_to_be16(reg); + int ret; + + if (len > 4) + return -EINVAL; + + data_be_p = (u8 *)&data_be; + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = (u8 *)®_addr_be; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_be_p[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = be32_to_cpu(data_be); + + return 0; +} + +/* Write registers up to 4 at a time */ +static int ov5670_write_reg(struct ov5670 *ov5670, u16 reg, unsigned int len, + u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); + int buf_i; + int val_i; + u8 buf[6]; + u8 *val_p; + + if (len > 4) + return -EINVAL; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + + val = cpu_to_be32(val); + val_p = (u8 *)&val; + buf_i = 2; + val_i = 4 - len; + + while (val_i < 4) + buf[buf_i++] = val_p[val_i++]; + + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +/* Write a list of registers */ +static int ov5670_write_regs(struct ov5670 *ov5670, + const struct ov5670_reg *regs, unsigned int len) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); + unsigned int i; + int ret; + + for (i = 0; i < len; i++) { + ret = ov5670_write_reg(ov5670, regs[i].address, 1, regs[i].val); + if (ret) { + dev_err_ratelimited( + &client->dev, + "Failed to write reg 0x%4.4x. error = %d\n", + regs[i].address, ret); + + return ret; + } + } + + return 0; +} + +static int ov5670_write_reg_list(struct ov5670 *ov5670, + const struct ov5670_reg_list *r_list) +{ + return ov5670_write_regs(ov5670, r_list->regs, r_list->num_of_regs); +} + +/* Open sub-device */ +static int ov5670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ov5670 *ov5670 = to_ov5670(sd); + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(sd, fh->pad, 0); + + mutex_lock(&ov5670->mutex); + + /* Initialize try_fmt */ + try_fmt->width = ov5670->cur_mode->width; + try_fmt->height = ov5670->cur_mode->height; + try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + try_fmt->field = V4L2_FIELD_NONE; + + /* No crop or compose */ + mutex_unlock(&ov5670->mutex); + + return 0; +} + +static int ov5670_update_digital_gain(struct ov5670 *ov5670, u32 d_gain) +{ + int ret; + + ret = ov5670_write_reg(ov5670, OV5670_REG_R_DGTL_GAIN, + OV5670_REG_VALUE_16BIT, d_gain); + if (ret) + return ret; + + ret = ov5670_write_reg(ov5670, OV5670_REG_G_DGTL_GAIN, + OV5670_REG_VALUE_16BIT, d_gain); + if (ret) + return ret; + + return ov5670_write_reg(ov5670, OV5670_REG_B_DGTL_GAIN, + OV5670_REG_VALUE_16BIT, d_gain); +} + +static int ov5670_enable_test_pattern(struct ov5670 *ov5670, u32 pattern) +{ + u32 val; + int ret; + + /* Set the bayer order that we support */ + ret = ov5670_write_reg(ov5670, OV5670_REG_TEST_PATTERN_CTRL, + OV5670_REG_VALUE_08BIT, 0); + if (ret) + return ret; + + ret = ov5670_read_reg(ov5670, OV5670_REG_TEST_PATTERN, + OV5670_REG_VALUE_08BIT, &val); + if (ret) + return ret; + + if (pattern) + val |= OV5670_TEST_PATTERN_ENABLE; + else + val &= ~OV5670_TEST_PATTERN_ENABLE; + + return ov5670_write_reg(ov5670, OV5670_REG_TEST_PATTERN, + OV5670_REG_VALUE_08BIT, val); +} + +/* Initialize control handlers */ +static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov5670 *ov5670 = container_of(ctrl->handler, + struct ov5670, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); + s64 max; + int ret = 0; + + /* Propagate change of current control to all related controls */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update max exposure while meeting expected vblanking */ + max = ov5670->cur_mode->height + ctrl->val - 8; + __v4l2_ctrl_modify_range(ov5670->exposure, + ov5670->exposure->minimum, max, + ov5670->exposure->step, max); + break; + } + + /* V4L2 controls values will be applied only when power is already up */ + if (pm_runtime_get_if_in_use(&client->dev) <= 0) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = ov5670_write_reg(ov5670, OV5670_REG_ANALOG_GAIN, + OV5670_REG_VALUE_16BIT, ctrl->val); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = ov5670_update_digital_gain(ov5670, ctrl->val); + break; + case V4L2_CID_EXPOSURE: + /* 4 least significant bits of expsoure are fractional part */ + ret = ov5670_write_reg(ov5670, OV5670_REG_EXPOSURE, + OV5670_REG_VALUE_24BIT, ctrl->val << 4); + break; + case V4L2_CID_VBLANK: + /* Update VTS that meets expected vertical blanking */ + ret = ov5670_write_reg(ov5670, OV5670_REG_VTS, + OV5670_REG_VALUE_16BIT, + ov5670->cur_mode->height + ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov5670_enable_test_pattern(ov5670, ctrl->val); + break; + default: + dev_info(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", + __func__, ctrl->id, ctrl->val); + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov5670_ctrl_ops = { + .s_ctrl = ov5670_set_ctrl, +}; + +/* Initialize control handlers */ +static int ov5670_init_controls(struct ov5670 *ov5670) +{ + struct v4l2_ctrl_handler *ctrl_hdlr; + s64 vblank_max; + s64 vblank_def; + s64 vblank_min; + s64 exposure_max; + int ret; + + ctrl_hdlr = &ov5670->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); + if (ret) + return ret; + + ctrl_hdlr->lock = &ov5670->mutex; + ov5670->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, + &ov5670_ctrl_ops, + V4L2_CID_LINK_FREQ, + 0, 0, link_freq_menu_items); + if (ov5670->link_freq) + ov5670->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* By default, V4L2_CID_PIXEL_RATE is read only */ + ov5670->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov5670_ctrl_ops, + V4L2_CID_PIXEL_RATE, 0, + link_freq_configs[0].pixel_rate, + 1, + link_freq_configs[0].pixel_rate); + + vblank_max = OV5670_VTS_MAX - ov5670->cur_mode->height; + vblank_def = ov5670->cur_mode->vts_def - ov5670->cur_mode->height; + vblank_min = ov5670->cur_mode->vts_min - ov5670->cur_mode->height; + ov5670->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov5670_ctrl_ops, + V4L2_CID_VBLANK, vblank_min, + vblank_max, 1, vblank_def); + + ov5670->hblank = v4l2_ctrl_new_std( + ctrl_hdlr, &ov5670_ctrl_ops, V4L2_CID_HBLANK, + OV5670_FIXED_PPL - ov5670->cur_mode->width, + OV5670_FIXED_PPL - ov5670->cur_mode->width, 1, + OV5670_FIXED_PPL - ov5670->cur_mode->width); + if (ov5670->hblank) + ov5670->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* Get min, max, step, default from sensor */ + v4l2_ctrl_new_std(ctrl_hdlr, &ov5670_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + ANALOG_GAIN_MIN, ANALOG_GAIN_MAX, ANALOG_GAIN_STEP, + ANALOG_GAIN_DEFAULT); + + /* Digital gain */ + v4l2_ctrl_new_std(ctrl_hdlr, &ov5670_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + OV5670_DGTL_GAIN_MIN, OV5670_DGTL_GAIN_MAX, + OV5670_DGTL_GAIN_STEP, OV5670_DGTL_GAIN_DEFAULT); + + /* Get min, max, step, default from sensor */ + exposure_max = ov5670->cur_mode->vts_def - 8; + ov5670->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov5670_ctrl_ops, + V4L2_CID_EXPOSURE, + OV5670_EXPOSURE_MIN, + exposure_max, OV5670_EXPOSURE_STEP, + exposure_max); + + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov5670_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov5670_test_pattern_menu) - 1, + 0, 0, ov5670_test_pattern_menu); + + if (ctrl_hdlr->error) { + ret = ctrl_hdlr->error; + goto error; + } + + ov5670->sd.ctrl_handler = ctrl_hdlr; + + return 0; + +error: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ret; +} + +static int ov5670_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + /* Only one bayer order GRBG is supported */ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int ov5670_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + 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; +} + +/* Calculate resolution distance */ +static int ov5670_get_reso_dist(const struct ov5670_mode *mode, + struct v4l2_mbus_framefmt *framefmt) +{ + return abs(mode->width - framefmt->width) + + abs(mode->height - framefmt->height); +} + +/* Find the closest supported resolution to the requested resolution */ +static const struct ov5670_mode *ov5670_find_best_fit( + struct ov5670 *ov5670, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *framefmt = &fmt->format; + int dist; + int cur_best_fit = 0; + int cur_best_fit_dist = -1; + int i; + + for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { + dist = ov5670_get_reso_dist(&supported_modes[i], framefmt); + if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { + cur_best_fit_dist = dist; + cur_best_fit = i; + } + } + + return &supported_modes[cur_best_fit]; +} + +static void ov5670_update_pad_format(const struct ov5670_mode *mode, + struct v4l2_subdev_format *fmt) +{ + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; + fmt->format.field = V4L2_FIELD_NONE; +} + +static int ov5670_do_get_pad_format(struct ov5670 *ov5670, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + fmt->format = *v4l2_subdev_get_try_format(&ov5670->sd, cfg, + fmt->pad); + else + ov5670_update_pad_format(ov5670->cur_mode, fmt); + + return 0; +} + +static int ov5670_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov5670 *ov5670 = to_ov5670(sd); + int ret; + + mutex_lock(&ov5670->mutex); + ret = ov5670_do_get_pad_format(ov5670, cfg, fmt); + mutex_unlock(&ov5670->mutex); + + return ret; +} + +static int ov5670_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov5670 *ov5670 = to_ov5670(sd); + const struct ov5670_mode *mode; + s32 vblank_def; + s32 h_blank; + + mutex_lock(&ov5670->mutex); + + fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; + + mode = ov5670_find_best_fit(ov5670, fmt); + ov5670_update_pad_format(mode, fmt); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; + } else { + ov5670->cur_mode = mode; + __v4l2_ctrl_s_ctrl(ov5670->link_freq, mode->link_freq_index); + __v4l2_ctrl_s_ctrl_int64( + ov5670->pixel_rate, + link_freq_configs[mode->link_freq_index].pixel_rate); + /* Update limits and set FPS to default */ + vblank_def = ov5670->cur_mode->vts_def - + ov5670->cur_mode->height; + __v4l2_ctrl_modify_range( + ov5670->vblank, + ov5670->cur_mode->vts_min - ov5670->cur_mode->height, + OV5670_VTS_MAX - ov5670->cur_mode->height, 1, + vblank_def); + __v4l2_ctrl_s_ctrl(ov5670->vblank, vblank_def); + h_blank = OV5670_FIXED_PPL - ov5670->cur_mode->width; + __v4l2_ctrl_modify_range(ov5670->hblank, h_blank, h_blank, 1, + h_blank); + } + + mutex_unlock(&ov5670->mutex); + + return 0; +} + +static int ov5670_get_skip_frames(struct v4l2_subdev *sd, u32 *frames) +{ + *frames = OV5670_NUM_OF_SKIP_FRAMES; + + return 0; +} + +/* Prepare streaming by writing default values and customized values */ +static int ov5670_start_streaming(struct ov5670 *ov5670) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); + const struct ov5670_reg_list *reg_list; + int link_freq_index; + int ret; + + /* Get out of from software reset */ + ret = ov5670_write_reg(ov5670, OV5670_REG_SOFTWARE_RST, + OV5670_REG_VALUE_08BIT, OV5670_SOFTWARE_RST); + if (ret) { + dev_err(&client->dev, "%s failed to set powerup registers\n", + __func__); + return ret; + } + + /* Setup PLL */ + link_freq_index = ov5670->cur_mode->link_freq_index; + reg_list = &link_freq_configs[link_freq_index].reg_list; + ret = ov5670_write_reg_list(ov5670, reg_list); + if (ret) { + dev_err(&client->dev, "%s failed to set plls\n", __func__); + return ret; + } + + /* Apply default values of current mode */ + reg_list = &ov5670->cur_mode->reg_list; + ret = ov5670_write_reg_list(ov5670, reg_list); + if (ret) { + dev_err(&client->dev, "%s failed to set mode\n", __func__); + return ret; + } + + ret = __v4l2_ctrl_handler_setup(ov5670->sd.ctrl_handler); + if (ret) + return ret; + + /* Write stream on list */ + ret = ov5670_write_reg(ov5670, OV5670_REG_MODE_SELECT, + OV5670_REG_VALUE_08BIT, OV5670_MODE_STREAMING); + if (ret) { + dev_err(&client->dev, "%s failed to set stream\n", __func__); + return ret; + } + + ov5670->streaming = true; + + return 0; +} + +static int ov5670_stop_streaming(struct ov5670 *ov5670) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); + int ret; + + ret = ov5670_write_reg(ov5670, OV5670_REG_MODE_SELECT, + OV5670_REG_VALUE_08BIT, OV5670_MODE_STANDBY); + if (ret) + dev_err(&client->dev, "%s failed to set stream\n", __func__); + + ov5670->streaming = false; + + /* Return success even if it was an error, as there is nothing the + * caller can do about it. + */ + return 0; +} + +static int ov5670_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov5670 *ov5670 = to_ov5670(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + mutex_lock(&ov5670->mutex); + if (ov5670->streaming == enable) + goto unlock_and_return; + + if (enable) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + + ret = ov5670_start_streaming(ov5670); + if (ret) + goto error; + } else { + ret = ov5670_stop_streaming(ov5670); + pm_runtime_put(&client->dev); + } + goto unlock_and_return; + +error: + pm_runtime_put(&client->dev); + +unlock_and_return: + mutex_unlock(&ov5670->mutex); + + return ret; +} + +static int __maybe_unused ov5670_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + 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 i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + 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; +} + +/* Verify chip ID */ +static int ov5670_identify_module(struct ov5670 *ov5670) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); + int ret; + u32 val; + + ret = ov5670_read_reg(ov5670, OV5670_REG_CHIP_ID, + OV5670_REG_VALUE_24BIT, &val); + if (ret) + return ret; + + if (val != OV5670_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + OV5670_CHIP_ID, val); + return -ENXIO; + } + + return 0; +} + +static const struct v4l2_subdev_video_ops ov5670_video_ops = { + .s_stream = ov5670_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ov5670_pad_ops = { + .enum_mbus_code = ov5670_enum_mbus_code, + .get_fmt = ov5670_get_pad_format, + .set_fmt = ov5670_set_pad_format, + .enum_frame_size = ov5670_enum_frame_size, +}; + +static const struct v4l2_subdev_sensor_ops ov5670_sensor_ops = { + .g_skip_frames = ov5670_get_skip_frames, +}; + +static const struct v4l2_subdev_ops ov5670_subdev_ops = { + .video = &ov5670_video_ops, + .pad = &ov5670_pad_ops, + .sensor = &ov5670_sensor_ops, +}; + +static const struct media_entity_operations ov5670_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops ov5670_internal_ops = { + .open = ov5670_open, +}; + +static int ov5670_probe(struct i2c_client *client) +{ + struct ov5670 *ov5670; + const char *err_msg; + u32 input_clk = 0; + int ret; + + device_property_read_u32(&client->dev, "clock-frequency", &input_clk); + if (input_clk != 19200000) + return -EINVAL; + + ov5670 = devm_kzalloc(&client->dev, sizeof(*ov5670), GFP_KERNEL); + if (!ov5670) { + ret = -ENOMEM; + err_msg = "devm_kzalloc() error"; + goto error_print; + } + + /* Initialize subdev */ + v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops); + + /* Check module identity */ + ret = ov5670_identify_module(ov5670); + if (ret) { + err_msg = "ov5670_identify_module() error"; + goto error_print; + } + + mutex_init(&ov5670->mutex); + + /* Set default mode to max resolution */ + ov5670->cur_mode = &supported_modes[0]; + + ret = ov5670_init_controls(ov5670); + if (ret) { + err_msg = "ov5670_init_controls() error"; + goto error_mutex_destroy; + } + + ov5670->sd.internal_ops = &ov5670_internal_ops; + ov5670->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov5670->sd.entity.ops = &ov5670_subdev_entity_ops; + ov5670->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* Source pad initialization */ + ov5670->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&ov5670->sd.entity, 1, &ov5670->pad); + if (ret) { + err_msg = "media_entity_pads_init() error"; + goto error_handler_free; + } + + /* Async register for subdev */ + ret = v4l2_async_register_subdev(&ov5670->sd); + if (ret < 0) { + err_msg = "v4l2_async_register_subdev() error"; + goto error_entity_cleanup; + } + + ov5670->streaming = false; + + /* + * Device is already turned on by i2c-core with ACPI domain PM. + * Enable runtime PM and turn off the device. + */ + pm_runtime_get_noresume(&client->dev); + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_put(&client->dev); + + return 0; + +error_entity_cleanup: + media_entity_cleanup(&ov5670->sd.entity); + +error_handler_free: + v4l2_ctrl_handler_free(ov5670->sd.ctrl_handler); + +error_mutex_destroy: + mutex_destroy(&ov5670->mutex); + +error_print: + dev_err(&client->dev, "%s: %s %d\n", __func__, err_msg, ret); + + return ret; +} + +static int ov5670_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5670 *ov5670 = to_ov5670(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + mutex_destroy(&ov5670->mutex); + + /* + * Disable runtime PM but keep the device turned on. + * i2c-core with ACPI domain PM will turn off the device. + */ + pm_runtime_get_sync(&client->dev); + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + + return 0; +} + +static const struct dev_pm_ops ov5670_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ov5670_suspend, ov5670_resume) +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id ov5670_acpi_ids[] = { + {"INT3479"}, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(acpi, ov5670_acpi_ids); +#endif + +static struct i2c_driver ov5670_i2c_driver = { + .driver = { + .name = "ov5670", + .pm = &ov5670_pm_ops, + .acpi_match_table = ACPI_PTR(ov5670_acpi_ids), + }, + .probe_new = ov5670_probe, + .remove = ov5670_remove, +}; + +module_i2c_driver(ov5670_i2c_driver); + +MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>"); +MODULE_AUTHOR("Yang, Hyungwoo <hyungwoo.yang@intel.com>"); +MODULE_DESCRIPTION("Omnivision ov5670 sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/ov6650.c index d2be64d54b22..768f2950ea36 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -1,5 +1,5 @@ /* - * V4L2 SoC Camera driver for OmniVision OV6650 Camera Sensor + * V4L2 subdevice driver for OmniVision OV6650 Camera Sensor * * Copyright (C) 2010 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> * @@ -31,9 +31,9 @@ #include <linux/v4l2-mediabus.h> #include <linux/module.h> -#include <media/soc_camera.h> #include <media/v4l2-clk.h> #include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> /* Register definitions */ #define REG_GAIN 0x00 /* range 00 - 3F */ @@ -426,10 +426,15 @@ static int ov6650_set_register(struct v4l2_subdev *sd, static int ov6650_s_power(struct v4l2_subdev *sd, int on) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct ov6650 *priv = to_ov6650(client); + int ret = 0; - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); + if (on) + ret = v4l2_clk_enable(priv->clk); + else + v4l2_clk_disable(priv->clk); + + return ret; } static int ov6650_get_selection(struct v4l2_subdev *sd, @@ -471,14 +476,13 @@ static int ov6650_set_selection(struct v4l2_subdev *sd, sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - rect.left = ALIGN(rect.left, 2); - rect.width = ALIGN(rect.width, 2); - rect.top = ALIGN(rect.top, 2); - rect.height = ALIGN(rect.height, 2); - soc_camera_limit_side(&rect.left, &rect.width, - DEF_HSTRT << 1, 2, W_CIF); - soc_camera_limit_side(&rect.top, &rect.height, - DEF_VSTRT << 1, 2, H_CIF); + v4l_bound_align_image(&rect.width, 2, W_CIF, 1, + &rect.height, 2, H_CIF, 1, 0); + v4l_bound_align_image(&rect.left, DEF_HSTRT << 1, + (DEF_HSTRT << 1) + W_CIF - (__s32)rect.width, 1, + &rect.top, DEF_VSTRT << 1, + (DEF_VSTRT << 1) + H_CIF - (__s32)rect.height, 1, + 0); ret = ov6650_reg_write(client, REG_HSTRT, rect.left >> 1); if (!ret) { @@ -547,8 +551,6 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe, static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd); - struct soc_camera_sense *sense = icd->sense; struct ov6650 *priv = to_ov6650(client); bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); struct v4l2_subdev_selection sel = { @@ -640,32 +642,10 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) } priv->half_scale = half_scale; - if (sense) { - if (sense->master_clock == 8000000) { - dev_dbg(&client->dev, "8MHz input clock\n"); - clkrc = CLKRC_6MHz; - } else if (sense->master_clock == 12000000) { - dev_dbg(&client->dev, "12MHz input clock\n"); - clkrc = CLKRC_12MHz; - } else if (sense->master_clock == 16000000) { - dev_dbg(&client->dev, "16MHz input clock\n"); - clkrc = CLKRC_16MHz; - } else if (sense->master_clock == 24000000) { - dev_dbg(&client->dev, "24MHz input clock\n"); - clkrc = CLKRC_24MHz; - } else { - dev_err(&client->dev, - "unsupported input clock, check platform data\n"); - return -EINVAL; - } - mclk = sense->master_clock; - priv->pclk_limit = sense->pixel_clock_max; - } else { - clkrc = CLKRC_24MHz; - mclk = 24000000; - priv->pclk_limit = 0; - dev_dbg(&client->dev, "using default 24MHz input clock\n"); - } + clkrc = CLKRC_12MHz; + mclk = 12000000; + priv->pclk_limit = 1334000; + dev_dbg(&client->dev, "using 12MHz input clock\n"); clkrc |= to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max); @@ -899,8 +879,6 @@ static const struct v4l2_subdev_core_ops ov6650_core_ops = { static int ov6650_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | @@ -908,7 +886,6 @@ static int ov6650_g_mbus_config(struct v4l2_subdev *sd, V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH; cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); return 0; } @@ -918,25 +895,23 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg); int ret; - if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + if (cfg->flags & V4L2_MBUS_PCLK_SAMPLE_RISING) ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0); else ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING); if (ret) return ret; - if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + if (cfg->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0); else ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW); if (ret) return ret; - if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) + if (cfg->flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0); else ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH); @@ -973,14 +948,8 @@ static int ov6650_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov6650 *priv; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); int ret; - if (!ssdd) { - dev_err(&client->dev, "Missing platform_data for driver\n"); - return -EINVAL; - } - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(&client->dev, diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 7270c68ed18a..e88549f0e704 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -1614,8 +1614,10 @@ static int ov7670_probe(struct i2c_client *client, info->clk = devm_clk_get(&client->dev, "xclk"); if (IS_ERR(info->clk)) - return -EPROBE_DEFER; - clk_prepare_enable(info->clk); + return PTR_ERR(info->clk); + ret = clk_prepare_enable(info->clk); + if (ret) + return ret; ret = ov7670_init_gpio(client, info); if (ret) diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 2de2fbb13b85..6ffb460e8589 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -484,6 +484,7 @@ static int ov965x_set_default_gamma_curve(struct ov965x *ov965x) for (i = 0; i < ARRAY_SIZE(gamma_curve); i++) { int ret = ov965x_write(ov965x->client, addr, gamma_curve[i]); + if (ret < 0) return ret; addr++; @@ -503,6 +504,7 @@ static int ov965x_set_color_matrix(struct ov965x *ov965x) for (i = 0; i < ARRAY_SIZE(mtx); i++) { int ret = ov965x_write(ov965x->client, addr, mtx[i]); + if (ret < 0) return ret; addr++; @@ -611,7 +613,7 @@ static int ov965x_set_banding_filter(struct ov965x *ov965x, int value) } if (value == V4L2_CID_POWER_LINE_FREQUENCY_DISABLED) return 0; - if (WARN_ON(ov965x->fiv == NULL)) + if (WARN_ON(!ov965x->fiv)) return -EINVAL; /* Set minimal exposure time for 50/60 HZ lighting */ if (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) @@ -999,44 +1001,47 @@ static int ov965x_initialize_controls(struct ov965x *ov965x) /* Auto/manual white balance */ ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops, - V4L2_CID_AUTO_WHITE_BALANCE, - 0, 1, 1, 1); + V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 1); ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, 0x80); ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE, - 0, 0xff, 1, 0x80); + 0, 0xff, 1, 0x80); /* Auto/manual exposure */ - ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, - V4L2_CID_EXPOSURE_AUTO, - V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); + ctrls->auto_exp = + v4l2_ctrl_new_std_menu(hdl, ops, + V4L2_CID_EXPOSURE_AUTO, + V4L2_EXPOSURE_MANUAL, 0, + V4L2_EXPOSURE_AUTO); /* Exposure time, in 100 us units. min/max is updated dynamically. */ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, - V4L2_CID_EXPOSURE_ABSOLUTE, - 2, 1500, 1, 500); + V4L2_CID_EXPOSURE_ABSOLUTE, + 2, 1500, 1, 500); /* Auto/manual gain */ ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN, - 0, 1, 1, 1); + 0, 1, 1, 1); ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, - 16, 64 * (16 + 15), 1, 64 * 16); + 16, 64 * (16 + 15), 1, 64 * 16); ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, - -2, 2, 1, 0); + -2, 2, 1, 0); ctrls->brightness = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, - -3, 3, 1, 0); + -3, 3, 1, 0); ctrls->sharpness = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, - 0, 32, 1, 6); + 0, 32, 1, 6); ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); - ctrls->light_freq = v4l2_ctrl_new_std_menu(hdl, ops, - V4L2_CID_POWER_LINE_FREQUENCY, - V4L2_CID_POWER_LINE_FREQUENCY_60HZ, ~0x7, - V4L2_CID_POWER_LINE_FREQUENCY_50HZ); + ctrls->light_freq = + v4l2_ctrl_new_std_menu(hdl, ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, ~0x7, + V4L2_CID_POWER_LINE_FREQUENCY_50HZ); v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(test_pattern_menu) - 1, 0, 0, - test_pattern_menu); + ARRAY_SIZE(test_pattern_menu) - 1, 0, 0, + test_pattern_menu); if (hdl->error) { ret = hdl->error; v4l2_ctrl_handler_free(hdl); @@ -1121,7 +1126,6 @@ static int __ov965x_set_frame_interval(struct ov965x *ov965x, u64 req_int, err, min_err = ~0ULL; unsigned int i; - if (fi->interval.denominator == 0) return -EINVAL; @@ -1165,7 +1169,8 @@ static int ov965x_s_frame_interval(struct v4l2_subdev *sd, return ret; } -static int ov965x_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, +static int ov965x_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct ov965x *ov965x = to_ov965x(sd); @@ -1209,7 +1214,8 @@ static void __ov965x_try_frame_size(struct v4l2_mbus_framefmt *mf, *size = match; } -static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, +static int ov965x_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { unsigned int index = ARRAY_SIZE(ov965x_formats); @@ -1231,7 +1237,7 @@ static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config mutex_lock(&ov965x->lock); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - if (cfg != NULL) { + if (cfg) { mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; } @@ -1362,7 +1368,8 @@ static int ov965x_s_stream(struct v4l2_subdev *sd, int on) */ static int ov965x_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0); + struct v4l2_mbus_framefmt *mf = + v4l2_subdev_get_try_format(sd, fh->pad, 0); ov965x_get_default_format(mf); return 0; @@ -1470,7 +1477,7 @@ static int ov965x_probe(struct i2c_client *client, struct ov965x *ov965x; int ret; - if (pdata == NULL) { + if (!pdata) { dev_err(&client->dev, "platform data not specified\n"); return -EINVAL; } @@ -1498,13 +1505,13 @@ static int ov965x_probe(struct i2c_client *client, ret = ov965x_configure_gpios(ov965x, pdata); if (ret < 0) - return ret; + goto err_mutex; ov965x->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &ov965x->pad); if (ret < 0) - return ret; + goto err_mutex; ret = ov965x_initialize_controls(ov965x); if (ret < 0) @@ -1530,16 +1537,20 @@ err_ctrls: v4l2_ctrl_handler_free(sd->ctrl_handler); err_me: media_entity_cleanup(&sd->entity); +err_mutex: + mutex_destroy(&ov965x->lock); return ret; } static int ov965x_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov965x *ov965x = to_ov965x(sd); v4l2_async_unregister_subdev(sd); v4l2_ctrl_handler_free(sd->ctrl_handler); media_entity_cleanup(&sd->entity); + mutex_destroy(&ov965x->lock); return 0; } diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index f434fb2ee6fc..cdc4f2392ef9 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1635,8 +1635,7 @@ static int s5c73m3_get_platform_data(struct s5c73m3 *state) node_ep = of_graph_get_next_endpoint(node, NULL); if (!node_ep) { - dev_warn(dev, "no endpoint defined for node: %s\n", - node->full_name); + dev_warn(dev, "no endpoint defined for node: %pOF\n", node); return 0; } diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 962051b9939d..ff46d2c96cea 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -1374,7 +1374,7 @@ static int s5k5baf_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { - static enum selection_rect rtype; + enum selection_rect rtype; struct s5k5baf *state = to_s5k5baf(sd); rtype = s5k5baf_get_sel_rect(sel->pad, sel->target); @@ -1863,8 +1863,7 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev) node_ep = of_graph_get_next_endpoint(node, NULL); if (!node_ep) { - dev_err(dev, "no endpoint defined at node %s\n", - node->full_name); + dev_err(dev, "no endpoint defined at node %pOF\n", node); return -EINVAL; } @@ -1882,8 +1881,8 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev) case V4L2_MBUS_PARALLEL: break; default: - dev_err(dev, "unsupported bus in endpoint defined at node %s\n", - node->full_name); + dev_err(dev, "unsupported bus in endpoint defined at node %pOF\n", + node); return -EINVAL; } diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c index 99c303002e90..01784d441ae6 100644 --- a/drivers/media/i2c/saa7127.c +++ b/drivers/media/i2c/saa7127.c @@ -806,7 +806,7 @@ static int saa7127_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static struct i2c_device_id saa7127_id[] = { +static const struct i2c_device_id saa7127_id[] = { { "saa7127_auto", 0 }, /* auto-detection */ { "saa7126", SAA7127 }, { "saa7127", SAA7127 }, diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index e1f6bc219c64..102467e00fb3 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -1069,7 +1069,7 @@ static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std) struct saa717x_state *decoder = to_state(sd); v4l2_dbg(1, debug, sd, "decoder set norm "); - v4l2_dbg(1, debug, sd, "(not yet implementd)\n"); + v4l2_dbg(1, debug, sd, "(not yet implemented)\n"); decoder->radio = 0; decoder->std = std; diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index e0b0c032c4ac..700f433261d0 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -841,6 +841,8 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) &client->dev, compressed_max_bpp - sensor->compressed_min_bpp + 1, sizeof(*sensor->valid_link_freqs), GFP_KERNEL); + if (!sensor->valid_link_freqs) + return -ENOMEM; for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) { const struct smiapp_csi_data_format *f = @@ -2809,13 +2811,19 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) switch (bus_cfg->bus_type) { case V4L2_MBUS_CSI2: hwcfg->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2; + hwcfg->lanes = bus_cfg->bus.mipi_csi2.num_data_lanes; + break; + case V4L2_MBUS_CCP2: + hwcfg->csi_signalling_mode = (bus_cfg->bus.mipi_csi1.strobe) ? + SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE : + SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK; + hwcfg->lanes = 1; break; - /* FIXME: add CCP2 support. */ default: + dev_err(dev, "unsupported bus %u\n", bus_cfg->bus_type); goto out_err; } - hwcfg->lanes = bus_cfg->bus.mipi_csi2.num_data_lanes; dev_dbg(dev, "lanes %u\n", hwcfg->lanes); /* NVM size is not mandatory */ @@ -2828,8 +2836,8 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) goto out_err; } - dev_dbg(dev, "nvm %d, clk %d, csi %d\n", hwcfg->nvm_size, - hwcfg->ext_clk, hwcfg->csi_signalling_mode); + dev_dbg(dev, "nvm %d, clk %d, mode %d\n", + hwcfg->nvm_size, hwcfg->ext_clk, hwcfg->csi_signalling_mode); if (!bus_cfg->nr_of_link_frequencies) { dev_warn(dev, "no link frequencies defined\n"); diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index cb128eae9c54..95c0272bb014 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c @@ -71,7 +71,7 @@ static int jt8ew9_limits(struct smiapp_sensor *sensor) static int jt8ew9_post_poweron(struct smiapp_sensor *sensor) { - const struct smiapp_reg_8 regs[] = { + static const struct smiapp_reg_8 regs[] = { { 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */ { 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ { 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ @@ -115,7 +115,7 @@ const struct smiapp_quirk smiapp_jt8ew9_quirk = { static int imx125es_post_poweron(struct smiapp_sensor *sensor) { /* Taken from v02. No idea what the other two are. */ - const struct smiapp_reg_8 regs[] = { + static const struct smiapp_reg_8 regs[] = { /* * 0x3302: clk during frame blanking: * 0x00 - HS mode, 0x01 - LP11 @@ -145,7 +145,7 @@ static int jt8ev1_post_poweron(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); int rval; - const struct smiapp_reg_8 regs[] = { + static const struct smiapp_reg_8 regs[] = { { 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */ { 0x30a3, 0xd0 }, /* FLASH STROBE enable */ { 0x3237, 0x00 }, /* For control of pulse timing for ADC */ @@ -166,7 +166,7 @@ static int jt8ev1_post_poweron(struct smiapp_sensor *sensor) { 0x33cf, 0xec }, /* For Black sun */ { 0x3328, 0x80 }, /* Ugh. No idea what's this. */ }; - const struct smiapp_reg_8 regs_96[] = { + static const struct smiapp_reg_8 regs_96[] = { { 0x30ae, 0x00 }, /* For control of ADC clock */ { 0x30af, 0xd0 }, { 0x30b0, 0x01 }, diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index 96859f37cb1c..72b369895b37 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig @@ -47,12 +47,6 @@ config SOC_CAMERA_OV5642 help This is a V4L2 camera driver for the OmniVision OV5642 sensor -config SOC_CAMERA_OV6650 - tristate "ov6650 sensor support" - depends on SOC_CAMERA && I2C - ---help--- - This is a V4L2 SoC camera driver for the OmniVision OV6650 sensor - config SOC_CAMERA_OV772X tristate "ov772x camera support" depends on SOC_CAMERA && I2C diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile index 974bdb721dbe..78532a7fb8e2 100644 --- a/drivers/media/i2c/soc_camera/Makefile +++ b/drivers/media/i2c/soc_camera/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o -obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index 714fb3555b34..4802d30e47de 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c @@ -592,7 +592,7 @@ static const struct dev_pm_ops mt9t031_dev_pm_ops = { .runtime_resume = mt9t031_runtime_resume, }; -static struct device_type mt9t031_dev_type = { +static const struct device_type mt9t031_dev_type = { .name = "MT9T031", .pm = &mt9t031_dev_pm_ops, }; diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 5788af238b86..e6f5c363ccab 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -2013,7 +2013,7 @@ static int tc358743_remove(struct i2c_client *client) return 0; } -static struct i2c_device_id tc358743_id[] = { +static const struct i2c_device_id tc358743_id[] = { {"tc358743", 0}, {} }; diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c index 42340e364cea..498ad2368cbc 100644 --- a/drivers/media/i2c/ths8200.c +++ b/drivers/media/i2c/ths8200.c @@ -483,7 +483,7 @@ static int ths8200_remove(struct i2c_client *client) return 0; } -static struct i2c_device_id ths8200_id[] = { +static const struct i2c_device_id ths8200_id[] = { { "ths8200", 0 }, {}, }; diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index f0741ab338df..560738213c00 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -58,7 +58,7 @@ static const struct vs6624_format { }, }; -static struct v4l2_mbus_framefmt vs6624_default_fmt = { +static const struct v4l2_mbus_framefmt vs6624_default_fmt = { .width = VGA_WIDTH, .height = VGA_HEIGHT, .code = MEDIA_BUS_FMT_UYVY8_2X8, diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 760e3e424e23..e79f72b8b858 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -69,9 +69,9 @@ static int media_device_get_info(struct media_device *dev, strlcpy(info->serial, dev->serial, sizeof(info->serial)); strlcpy(info->bus_info, dev->bus_info, sizeof(info->bus_info)); - info->media_version = MEDIA_API_VERSION; + info->media_version = LINUX_VERSION_CODE; + info->driver_version = info->media_version; info->hw_revision = dev->hw_revision; - info->driver_version = dev->driver_version; return 0; } @@ -537,9 +537,9 @@ static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); * Registration/unregistration */ -static void media_device_release(struct media_devnode *mdev) +static void media_device_release(struct media_devnode *devnode) { - dev_dbg(mdev->parent, "Media device released\n"); + dev_dbg(devnode->parent, "Media device released\n"); } /** @@ -591,9 +591,8 @@ int __must_check media_device_register_entity(struct media_device *mdev, &entity->pads[i].graph_obj); /* invoke entity_notify callbacks */ - list_for_each_entry_safe(notify, next, &mdev->entity_notify, list) { - (notify)->notify(entity, notify->notify_data); - } + list_for_each_entry_safe(notify, next, &mdev->entity_notify, list) + notify->notify(entity, notify->notify_data); if (mdev->entity_internal_idx_max >= mdev->pm_count_walk.ent_enum.idx_max) { @@ -834,8 +833,6 @@ void media_device_pci_init(struct media_device *mdev, mdev->hw_revision = (pci_dev->subsystem_vendor << 16) | pci_dev->subsystem_device; - mdev->driver_version = LINUX_VERSION_CODE; - media_device_init(mdev); } EXPORT_SYMBOL_GPL(media_device_pci_init); @@ -863,7 +860,6 @@ void __media_device_usb_init(struct media_device *mdev, strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial)); usb_make_path(udev, mdev->bus_info, sizeof(mdev->bus_info)); mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); - mdev->driver_version = LINUX_VERSION_CODE; media_device_init(mdev); } diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index dd0f0ead9516..2ace0410d277 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -917,7 +917,7 @@ media_entity_find_link(struct media_pad *source, struct media_pad *sink) } EXPORT_SYMBOL_GPL(media_entity_find_link); -struct media_pad *media_entity_remote_pad(struct media_pad *pad) +struct media_pad *media_entity_remote_pad(const struct media_pad *pad) { struct media_link *link; diff --git a/drivers/media/pci/b2c2/flexcop-pci.c b/drivers/media/pci/b2c2/flexcop-pci.c index 6e60decb2198..cc6527e35537 100644 --- a/drivers/media/pci/b2c2/flexcop-pci.c +++ b/drivers/media/pci/b2c2/flexcop-pci.c @@ -415,7 +415,7 @@ static void flexcop_pci_remove(struct pci_dev *pdev) flexcop_device_kfree(fc_pci->fc_dev); } -static struct pci_device_id flexcop_pci_tbl[] = { +static const struct pci_device_id flexcop_pci_tbl[] = { { PCI_DEVICE(0x13d0, 0x2103) }, { }, }; diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c index 8aa726651630..a5f52137d306 100644 --- a/drivers/media/pci/bt8xx/bt878.c +++ b/drivers/media/pci/bt8xx/bt878.c @@ -383,7 +383,7 @@ EXPORT_SYMBOL(bt878_device_control); .driver_data = (unsigned long) name \ } -static struct pci_device_id bt878_pci_tbl[] = { +static const struct pci_device_id bt878_pci_tbl[] = { BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"), BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"), BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"), diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index ed319f18ba48..227086a2e99c 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1702,7 +1702,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) bttv_dma_free(q,fh->btv,buf); } -static struct videobuf_queue_ops bttv_video_qops = { +static const struct videobuf_queue_ops bttv_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, @@ -4388,7 +4388,7 @@ static int bttv_resume(struct pci_dev *pci_dev) } #endif -static struct pci_device_id bttv_pci_tbl[] = { +static const struct pci_device_id bttv_pci_tbl[] = { {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0}, {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0}, {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0}, diff --git a/drivers/media/pci/bt8xx/bttv-i2c.c b/drivers/media/pci/bt8xx/bttv-i2c.c index 274fd036b306..eccd1e3d717a 100644 --- a/drivers/media/pci/bt8xx/bttv-i2c.c +++ b/drivers/media/pci/bt8xx/bttv-i2c.c @@ -97,7 +97,7 @@ static int bttv_bit_getsda(void *data) return state; } -static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = { +static const struct i2c_algo_bit_data bttv_i2c_algo_bit_template = { .setsda = bttv_bit_setsda, .setscl = bttv_bit_setscl, .getsda = bttv_bit_getsda, diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index 2fd07a8afcd2..73d655d073d6 100644 --- a/drivers/media/pci/bt8xx/bttv-input.c +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -69,12 +69,13 @@ static void ir_handle_key(struct bttv *btv) if ((ir->mask_keydown && (gpio & ir->mask_keydown)) || (ir->mask_keyup && !(gpio & ir->mask_keyup))) { - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 0); } else { /* HACK: Probably, ir->mask_keydown is missing for this board */ if (btv->c.type == BTTV_BOARD_WINFAST2000) - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); rc_keyup(ir->dev); } @@ -99,7 +100,7 @@ static void ir_enltv_handle_key(struct bttv *btv) gpio, data, (gpio & ir->mask_keyup) ? " up" : "up/down"); - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 0); if (keyup) rc_keyup(ir->dev); } else { @@ -113,7 +114,8 @@ static void ir_enltv_handle_key(struct bttv *btv) if (keyup) rc_keyup(ir->dev); else - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); } ir->last_gpio = data | keyup; @@ -235,7 +237,7 @@ static void bttv_rc5_timer_end(unsigned long data) } scancode = RC_SCANCODE_RC5(system, command); - rc_keydown(ir->dev, RC_TYPE_RC5, scancode, toggle); + rc_keydown(ir->dev, RC_PROTO_RC5, scancode, toggle); dprintk("scancode %x, toggle %x\n", scancode, toggle); } @@ -327,7 +329,7 @@ static void bttv_ir_stop(struct bttv *btv) * Get_key functions used by I2C remotes */ -static int get_key_pv951(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_pv951(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char b; @@ -355,7 +357,7 @@ static int get_key_pv951(struct IR_i2c *ir, enum rc_type *protocol, * the device is bound to the vendor-provided RC. */ - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = b; *toggle = 0; return 1; @@ -535,7 +537,7 @@ int bttv_input_init(struct bttv *btv) snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(btv->c.pci)); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype = BUS_PCI; rc->input_id.version = 1; diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c index 90f4263452d3..530b3e9764ce 100644 --- a/drivers/media/pci/bt8xx/dst_ca.c +++ b/drivers/media/pci/bt8xx/dst_ca.c @@ -57,20 +57,6 @@ static unsigned int verbose = 5; module_param(verbose, int, 0644); MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); -/* Need some more work */ -static int ca_set_slot_descr(void) -{ - /* We could make this more graceful ? */ - return -EOPNOTSUPP; -} - -/* Need some more work */ -static int ca_set_pid(void) -{ - /* We could make this more graceful ? */ - return -EOPNOTSUPP; -} - static void put_command_and_length(u8 *data, int command, int length) { data[0] = (command >> 16) & 0xff; @@ -144,7 +130,7 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, } if(dst_ca_comm_err == RETRIES) - return -1; + return -EIO; return 0; } @@ -159,7 +145,7 @@ static int ca_get_app_info(struct dst_state *state) put_checksum(&command[0], command[0]); if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; + return -EIO; } dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================"); @@ -198,7 +184,7 @@ static int ca_get_ca_info(struct dst_state *state) put_checksum(&slot_command[0], slot_command[0]); if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; + return -EIO; } dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); @@ -242,7 +228,7 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, put_checksum(&slot_command[0], slot_command[0]); if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; + return -EIO; } dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !"); @@ -282,7 +268,7 @@ static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_s put_checksum(&slot_command[0], 7); if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; + return -EIO; } dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); @@ -354,7 +340,7 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, } else { if (length > 247) { dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !"); - return -1; + return -EIO; } hw_buffer->msg[0] = (length & 0xff) + 7; hw_buffer->msg[1] = 0x40; @@ -380,7 +366,7 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 l dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed."); dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST."); rdc_reset_state(state); - return -1; + return -EIO; } dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success."); @@ -453,7 +439,7 @@ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message if (ca_pmt_reply_test) { if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); - return -1; + return -EIO; } /* Process CA PMT Reply */ @@ -464,7 +450,7 @@ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message if (!ca_pmt_reply_test) { if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); - return -1; + return -EIO; } dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !"); /* put a dummy message */ @@ -573,17 +559,18 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct switch (cmd) { case CA_SEND_MSG: dprintk(verbose, DST_CA_INFO, 1, " Sending message"); - if ((ca_send_message(state, p_ca_message, arg)) < 0) { + result = ca_send_message(state, p_ca_message, arg); + + if (result < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !"); - result = -1; goto free_mem_and_exit; } break; case CA_GET_MSG: dprintk(verbose, DST_CA_INFO, 1, " Getting message"); - if ((ca_get_message(state, p_ca_message, arg)) < 0) { + result = ca_get_message(state, p_ca_message, arg); + if (result < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !"); - result = -1; goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !"); @@ -595,7 +582,8 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct break; case CA_GET_SLOT_INFO: dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info"); - if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { + result = ca_get_slot_info(state, p_ca_slot_info, arg); + if (result < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !"); result = -1; goto free_mem_and_exit; @@ -604,40 +592,22 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct break; case CA_GET_CAP: dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities"); - if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { + result = ca_get_slot_caps(state, p_ca_caps, arg); + if (result < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !"); - result = -1; goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !"); break; case CA_GET_DESCR_INFO: dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description"); - if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { + result = ca_get_slot_descr(state, p_ca_message, arg); + if (result < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !"); - result = -1; goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !"); break; - case CA_SET_DESCR: - dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler"); - if ((ca_set_slot_descr()) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !"); - break; - case CA_SET_PID: - dprintk(verbose, DST_CA_INFO, 1, " Setting PID"); - if ((ca_set_pid()) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); - break; default: result = -EOPNOTSUPP; } diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c index 49013c6b8646..b69b258d39b9 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c +++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c @@ -43,7 +43,7 @@ MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); pr_info("cobalt-alsa-pcm %s: " fmt, __func__, ##arg); \ } while (0) -static struct snd_pcm_hardware snd_cobalt_hdmi_capture = { +static const struct snd_pcm_hardware snd_cobalt_hdmi_capture = { .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -64,7 +64,7 @@ static struct snd_pcm_hardware snd_cobalt_hdmi_capture = { .periods_max = 4, }; -static struct snd_pcm_hardware snd_cobalt_playback = { +static const struct snd_pcm_hardware snd_cobalt_playback = { .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index f8e173f3e9e2..98b6cb9505d1 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -36,7 +36,7 @@ #include "cobalt-omnitek.h" /* add your revision and whatnot here */ -static struct pci_device_id cobalt_pci_tbl[] = { +static const struct pci_device_id cobalt_pci_tbl[] = { {PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_COBALT, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0,} diff --git a/drivers/media/pci/cobalt/cobalt-i2c.c b/drivers/media/pci/cobalt/cobalt-i2c.c index ad16b89b8d0c..1a5c55673ea8 100644 --- a/drivers/media/pci/cobalt/cobalt-i2c.c +++ b/drivers/media/pci/cobalt/cobalt-i2c.c @@ -301,7 +301,7 @@ static u32 cobalt_func(struct i2c_adapter *adap) } /* template for i2c-bit-algo */ -static struct i2c_adapter cobalt_i2c_adap_template = { +static const struct i2c_adapter cobalt_i2c_adap_template = { .name = "cobalt i2c driver", .algo = NULL, /* set by i2c-algo-bit */ .algo_data = NULL, /* filled from template */ diff --git a/drivers/media/pci/cx18/cx18-alsa-mixer.c b/drivers/media/pci/cx18/cx18-alsa-mixer.c index 06b066bc9301..cb04c3d820e2 100644 --- a/drivers/media/pci/cx18/cx18-alsa-mixer.c +++ b/drivers/media/pci/cx18/cx18-alsa-mixer.c @@ -161,7 +161,7 @@ int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc) strlcpy(sc->mixername, "CX23418 Mixer", sizeof(sc->mixername)); - ret = snd_ctl_add(sc, snd_ctl_new1(snd_cx18_mixer_tv_vol, cxsc)); + ret = snd_ctl_add(sc, snd_ctl_new1(&snd_cx18_mixer_tv_vol, cxsc)); if (ret) { CX18_ALSA_WARN("%s: failed to add %s control, err %d\n", __func__, snd_cx18_mixer_tv_vol.name, ret); diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.c b/drivers/media/pci/cx18/cx18-alsa-pcm.c index f68ee57a9ae2..aadd76466aec 100644 --- a/drivers/media/pci/cx18/cx18-alsa-pcm.c +++ b/drivers/media/pci/cx18/cx18-alsa-pcm.c @@ -44,7 +44,7 @@ MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); __func__, ##arg); \ } while (0) -static struct snd_pcm_hardware snd_cx18_hw_capture = { +static const struct snd_pcm_hardware snd_cx18_hw_capture = { .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 8bce49cdad46..8654710464cc 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -48,7 +48,7 @@ int (*cx18_ext_init)(struct cx18 *); EXPORT_SYMBOL(cx18_ext_init); /* add your revision and whatnot here */ -static struct pci_device_id cx18_pci_tbl[] = { +static const struct pci_device_id cx18_pci_tbl[] = { {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0,} diff --git a/drivers/media/pci/cx18/cx18-i2c.c b/drivers/media/pci/cx18/cx18-i2c.c index eabdd4c5520a..7f588eeac60f 100644 --- a/drivers/media/pci/cx18/cx18-i2c.c +++ b/drivers/media/pci/cx18/cx18-i2c.c @@ -93,8 +93,8 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw, case CX18_HW_Z8F0811_IR_RX_HAUP: init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_BIT_RC5 | RC_BIT_RC6_MCE | - RC_BIT_RC6_6A_32; + init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_RC6_6A_32; init_data->name = cx->card_name; info.platform_data = init_data; break; @@ -206,7 +206,7 @@ static int cx18_getsda(void *data) } /* template for i2c-bit-algo */ -static struct i2c_adapter cx18_i2c_adap_template = { +static const struct i2c_adapter cx18_i2c_adap_template = { .name = "cx18 i2c driver", .algo = NULL, /* set by i2c-algo-bit */ .algo_data = NULL, /* filled from template */ @@ -216,7 +216,7 @@ static struct i2c_adapter cx18_i2c_adap_template = { #define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */ #define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */ -static struct i2c_algo_bit_data cx18_i2c_algo_template = { +static const struct i2c_algo_bit_data cx18_i2c_algo_template = { .setsda = cx18_setsda, .setscl = cx18_setscl, .getsda = cx18_getsda, diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 3c45e0071530..8385411af641 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -31,7 +31,7 @@ #define CX18_DSP0_INTERRUPT_MASK 0xd0004C -static struct v4l2_file_operations cx18_v4l2_enc_fops = { +static const struct v4l2_file_operations cx18_v4l2_enc_fops = { .owner = THIS_MODULE, .read = cx18_v4l2_read, .open = cx18_v4l2_open, @@ -240,7 +240,7 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) list_add_tail(&buf->vb.queue, &s->vb_capture); } -static struct videobuf_queue_ops cx18_videobuf_qops = { +static const struct videobuf_queue_ops cx18_videobuf_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 2ff1d1e274be..a71f3c7569ce 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1416,7 +1416,7 @@ static int vidioc_log_status(struct file *file, void *priv) return 0; } -static struct v4l2_file_operations mpeg_fops = { +static const struct v4l2_file_operations mpeg_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vb2_fop_release, diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index c148f9a4a9ac..d8c3637e492e 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -293,7 +293,7 @@ static int dsp_buffer_free(struct cx23885_audio_dev *chip) */ #define DEFAULT_FIFO_SIZE 4096 -static struct snd_pcm_hardware snd_cx23885_digital_hw = { +static const struct snd_pcm_hardware snd_cx23885_digital_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index c48fa8e25a70..78a8836d03e4 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -1278,6 +1278,12 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) case 85721: /* WinTV-HVR1290 (PCIe, OEM, RCA in, IR, Dual channel ATSC and Basic analog */ + case 121019: + /* WinTV-HVR4400 (PCIe, DVB-S2, DVB-C/T) */ + break; + case 121029: + /* WinTV-HVR5500 (PCIe, DVB-S2, DVB-C/T) */ + break; case 150329: /* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */ break; diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 02b5ec549369..8f63df1cb418 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -2056,7 +2056,7 @@ static void cx23885_finidev(struct pci_dev *pci_dev) kfree(dev); } -static struct pci_device_id cx23885_pci_tbl[] = { +static const struct pci_device_id cx23885_pci_tbl[] = { { /* CX23885 */ .vendor = 0x14f1, diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 979b66627f60..e795ddeb7fe2 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -2637,6 +2637,11 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) struct vb2_dvb_frontend *fe0; struct i2c_client *client; + fe0 = vb2_dvb_get_frontend(&port->frontends, 1); + + if (fe0 && fe0->dvb.frontend) + vb2_dvb_unregister_bus(&port->frontends); + /* remove I2C client for CI */ client = port->i2c_client_ci; if (client) { @@ -2665,11 +2670,6 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) i2c_unregister_device(client); } - fe0 = vb2_dvb_get_frontend(&port->frontends, 1); - - if (fe0 && fe0->dvb.frontend) - vb2_dvb_unregister_bus(&port->frontends); - switch (port->dev->board) { case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: netup_ci_exit(port); diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c index 8528032090f2..0f21467ae88e 100644 --- a/drivers/media/pci/cx23885/cx23885-i2c.c +++ b/drivers/media/pci/cx23885/cx23885-i2c.c @@ -264,7 +264,7 @@ static const struct i2c_algorithm cx23885_i2c_algo_template = { /* ----------------------------------------------------------------------- */ -static struct i2c_adapter cx23885_i2c_adap_template = { +static const struct i2c_adapter cx23885_i2c_adap_template = { .name = "cx23885", .owner = THIS_MODULE, .algo = &cx23885_i2c_algo_template, diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c index 4367cb3162b6..944b70831f12 100644 --- a/drivers/media/pci/cx23885/cx23885-input.c +++ b/drivers/media/pci/cx23885/cx23885-input.c @@ -284,32 +284,32 @@ int cx23885_input_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_HAUPPAUGE_HVR1250: /* Integrated CX2388[58] IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; /* The grey Hauppauge RC-5 remote */ rc_map = RC_MAP_HAUPPAUGE; break; case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: /* Integrated CX23885 IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; /* The grey Terratec remote with orange buttons */ rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS; break; case CX23885_BOARD_TEVII_S470: /* Integrated CX23885 IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; /* A guess at the remote */ rc_map = RC_MAP_TEVII_NEC; break; case CX23885_BOARD_MYGICA_X8507: /* Integrated CX23885 IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; /* A guess at the remote */ rc_map = RC_MAP_TOTAL_MEDIA_IN_HAND_02; break; case CX23885_BOARD_TBS_6980: case CX23885_BOARD_TBS_6981: /* Integrated CX23885 IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; /* A guess at the remote */ rc_map = RC_MAP_TBS_NEC; break; @@ -320,12 +320,12 @@ int cx23885_input_init(struct cx23885_dev *dev) case CX23885_BOARD_DVBSKY_S952: case CX23885_BOARD_DVBSKY_T982: /* Integrated CX23885 IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; rc_map = RC_MAP_DVBSKY; break; case CX23885_BOARD_TT_CT2_4500_CI: /* Integrated CX23885 IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; rc_map = RC_MAP_TT_1500; break; default: @@ -351,7 +351,7 @@ int cx23885_input_init(struct cx23885_dev *dev) } kernel_ir->rc = rc; - rc->input_name = kernel_ir->name; + rc->device_name = kernel_ir->name; rc->input_phys = kernel_ir->phys; rc->input_id.bustype = BUS_PCI; rc->input_id.version = 1; diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 519b81c0c837..2b34990e86f2 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -428,7 +428,7 @@ static int dsp_buffer_free(struct cx25821_audio_dev *chip) * Digital hardware definition */ #define DEFAULT_FIFO_SIZE 384 -static struct snd_pcm_hardware snd_cx25821_digital_hw = { +static const struct snd_pcm_hardware snd_cx25821_digital_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, .formats = SNDRV_PCM_FMTBIT_S16_LE, diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index fbc0229183bd..04aa4a68a0ae 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -1390,10 +1390,7 @@ static struct pci_driver cx25821_pci_driver = { static int __init cx25821_init(void) { - pr_info("driver version %d.%d.%d loaded\n", - (CX25821_VERSION_CODE >> 16) & 0xff, - (CX25821_VERSION_CODE >> 8) & 0xff, - CX25821_VERSION_CODE & 0xff); + pr_info("driver loaded\n"); return pci_register_driver(&cx25821_pci_driver); } diff --git a/drivers/media/pci/cx25821/cx25821-i2c.c b/drivers/media/pci/cx25821/cx25821-i2c.c index 263a1cf36ef1..000049d3c71b 100644 --- a/drivers/media/pci/cx25821/cx25821-i2c.c +++ b/drivers/media/pci/cx25821/cx25821-i2c.c @@ -285,7 +285,7 @@ static const struct i2c_algorithm cx25821_i2c_algo_template = { #endif }; -static struct i2c_adapter cx25821_i2c_adap_template = { +static const struct i2c_adapter cx25821_i2c_adap_template = { .name = "cx25821", .owner = THIS_MODULE, .algo = &cx25821_i2c_algo_template, diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 0f20e89b0cde..b3eb2dabb30b 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -41,8 +41,6 @@ #include <linux/version.h> #include <linux/mutex.h> -#define CX25821_VERSION_CODE KERNEL_VERSION(0, 0, 106) - #define UNSET (-1U) #define NO_SYNC_LINE (-1U) diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index c81fe4681d14..9740326bc93f 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -799,7 +799,7 @@ static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_cx88_alc_switch = { +static const struct snd_kcontrol_new snd_cx88_alc_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line-In ALC Switch", .info = snd_ctl_boolean_mono_info, diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index aa49c9597d9c..e3101f04941c 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -1075,7 +1075,7 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static struct video_device cx8802_mpeg_template = { +static const struct video_device cx8802_mpeg_template = { .name = "cx8802", .fops = &mpeg_fops, .ioctl_ops = &mpeg_ioctl_ops, diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index 01f2e472a2a0..e02449bf2041 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -132,7 +132,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) data = (data << 4) | ((gpio_key & 0xf0) >> 4); - rc_keydown(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown(ir->dev, RC_PROTO_UNKNOWN, data, 0); } else if (ir->core->boardnr == CX88_BOARD_PROLINK_PLAYTVPVR || ir->core->boardnr == CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO) { @@ -146,7 +146,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) scancode = RC_SCANCODE_NECX(addr, cmd); if (0 == (gpio & ir->mask_keyup)) - rc_keydown_notimeout(ir->dev, RC_TYPE_NECX, scancode, + rc_keydown_notimeout(ir->dev, RC_PROTO_NECX, scancode, 0); else rc_keyup(ir->dev); @@ -154,20 +154,22 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) } else if (ir->mask_keydown) { /* bit set on keydown */ if (gpio & ir->mask_keydown) - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); else rc_keyup(ir->dev); } else if (ir->mask_keyup) { /* bit cleared on keydown */ if (0 == (gpio & ir->mask_keyup)) - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); else rc_keyup(ir->dev); } else { /* can't distinguish keydown/up :-/ */ - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 0); rc_keyup(ir->dev); } } @@ -267,7 +269,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) struct cx88_IR *ir; struct rc_dev *dev; char *ir_codes = NULL; - u64 rc_type = RC_BIT_OTHER; + u64 rc_proto = RC_PROTO_BIT_OTHER; int err = -ENOMEM; u32 hardware_mask = 0; /* For devices with a hardware mask, when * used with a full-code IR table @@ -348,7 +350,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) * 002-T mini RC, provided with newer PV hardware */ ir_codes = RC_MAP_PIXELVIEW_MK12; - rc_type = RC_BIT_NECX; + rc_proto = RC_PROTO_BIT_NECX; ir->gpio_addr = MO_GP1_IO; ir->mask_keyup = 0x80; ir->polling = 10; /* ms */ @@ -464,7 +466,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); - dev->input_name = ir->name; + dev->device_name = ir->name; dev->input_phys = ir->phys; dev->input_id.bustype = BUS_PCI; dev->input_id.version = 1; @@ -487,7 +489,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) dev->timeout = 10 * 1000 * 1000; /* 10 ms */ } else { dev->driver_type = RC_DRIVER_SCANCODE; - dev->allowed_protocols = rc_type; + dev->allowed_protocols = rc_proto; } ir->core = core; @@ -557,7 +559,7 @@ void cx88_ir_irq(struct cx88_core *core) ir_raw_event_handle(ir->dev); } -static int get_key_pvr2000(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_pvr2000(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { int flags, code; @@ -582,7 +584,7 @@ static int get_key_pvr2000(struct IR_i2c *ir, enum rc_type *protocol, dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", code & 0xff, flags & 0xff); - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = code & 0xff; *toggle = 0; return 1; @@ -612,7 +614,7 @@ void cx88_i2c_init_ir(struct cx88_core *core) case CX88_BOARD_LEADTEK_PVR2000: addr_list = pvr2000_addr_list; core->init_data.name = "cx88 Leadtek PVR 2000 remote"; - core->init_data.type = RC_BIT_UNKNOWN; + core->init_data.type = RC_PROTO_BIT_UNKNOWN; core->init_data.get_key = get_key_pvr2000; core->init_data.ir_codes = RC_MAP_EMPTY; break; @@ -633,8 +635,8 @@ void cx88_i2c_init_ir(struct cx88_core *core) /* Hauppauge XVR */ core->init_data.name = "cx88 Hauppauge XVR remote"; core->init_data.ir_codes = RC_MAP_HAUPPAUGE; - core->init_data.type = RC_BIT_RC5 | RC_BIT_RC6_MCE | - RC_BIT_RC6_6A_32; + core->init_data.type = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_RC6_6A_32; core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; info.platform_data = &core->init_data; diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig index ffed78c2ffb4..f43d0b83fc0c 100644 --- a/drivers/media/pci/ddbridge/Kconfig +++ b/drivers/media/pci/ddbridge/Kconfig @@ -8,7 +8,11 @@ config DVB_DDBRIDGE select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0910 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6111 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT + select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for cards with the Digital Devices PCI express bridge: - Octopus PCIe Bridge @@ -20,5 +24,22 @@ config DVB_DDBRIDGE - CineCTv6 and DuoFlex CT (STV0367-based) - CineCTv7 and DuoFlex CT2/C2T2/C2T2I (Sony CXD28xx-based) - MaxA8 series + - CineS2 V7/V7A and DuoFlex S2 V4 (ST STV0910-based) + - Max S4/8 Say Y if you own such a card and want to use it. + +config DVB_DDBRIDGE_MSIENABLE + bool "Enable Message Signaled Interrupts (MSI) per default (EXPERIMENTAL)" + depends on DVB_DDBRIDGE + depends on PCI_MSI + default n + ---help--- + Use PCI MSI (Message Signaled Interrupts) per default. Enabling this + might lead to I2C errors originating from the bridge in conjunction + with certain SATA controllers, requiring a reload of the ddbridge + module. MSI can still be disabled by passing msi=0 as option, as + this will just change the msi option default value. + + If you're unsure, concerned about stability and don't want to pass + module options in case of troubles, say N. diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile index 7446c8b677b5..09703312a3f1 100644 --- a/drivers/media/pci/ddbridge/Makefile +++ b/drivers/media/pci/ddbridge/Makefile @@ -2,7 +2,8 @@ # Makefile for the ddbridge device driver # -ddbridge-objs := ddbridge-core.o +ddbridge-objs := ddbridge-main.o ddbridge-core.o ddbridge-hw.o \ + ddbridge-i2c.o ddbridge-maxs8.o obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index cd1723e79a07..f4bd4908acdd 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -1,7 +1,10 @@ /* - * ddbridge.c: Digital Devices PCIe bridge driver + * ddbridge-core.c: Digital Devices bridge core functions + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Marcus Metzler <mocm@metzlerbros.de> + * Ralph Metzler <rjkm@metzlerbros.de> * - * Copyright (C) 2010-2011 Digital Devices GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -17,8 +20,6 @@ * http://www.gnu.org/copyleft/gpl.html */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -32,9 +33,12 @@ #include <linux/i2c.h> #include <linux/swab.h> #include <linux/vmalloc.h> -#include "ddbridge.h" +#include "ddbridge.h" +#include "ddbridge-i2c.h" #include "ddbridge-regs.h" +#include "ddbridge-maxs8.h" +#include "ddbridge-io.h" #include "tda18271c2dd.h" #include "stv6110x.h" @@ -45,446 +49,511 @@ #include "stv0367_priv.h" #include "cxd2841er.h" #include "tda18212.h" +#include "stv0910.h" +#include "stv6111.h" +#include "lnbh25.h" +#include "cxd2099.h" -static int xo2_speed = 2; -module_param(xo2_speed, int, 0444); -MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +/****************************************************************************/ -/* MSI had problems with lost interrupts, fixed but needs testing */ -#undef CONFIG_PCI_MSI +#define DDB_MAX_ADAPTER 64 -/******************************************************************************/ +/****************************************************************************/ -static int i2c_io(struct i2c_adapter *adapter, u8 adr, - u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = wbuf, .len = wlen }, - {.addr = adr, .flags = I2C_M_RD, - .buf = rbuf, .len = rlen } }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -} +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) -{ - struct i2c_msg msg = {.addr = adr, .flags = 0, - .buf = data, .len = len}; +static int adapter_alloc; +module_param(adapter_alloc, int, 0444); +MODULE_PARM_DESC(adapter_alloc, + "0-one adapter per io, 1-one per tab with io, 2-one per tab, 3-one for all"); - return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; -} +/****************************************************************************/ -static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) -{ - struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1 } }; - return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; -} +static DEFINE_MUTEX(redirect_lock); -static int i2c_read_regs(struct i2c_adapter *adapter, - u8 adr, u8 reg, u8 *val, u8 len) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1 }, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = len } }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -} +struct workqueue_struct *ddb_wq; -static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) -{ - return i2c_read_regs(adapter, adr, reg, val, 1); -} +static struct ddb *ddbs[DDB_MAX_ADAPTER]; -static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, - u16 reg, u8 *val) -{ - u8 msg[2] = {reg>>8, reg&0xff}; - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = msg, .len = 2}, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1} }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -} +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ -static int i2c_write_reg(struct i2c_adapter *adap, u8 adr, - u8 reg, u8 val) +static void ddb_set_dma_table(struct ddb_io *io) { - u8 msg[2] = {reg, val}; + struct ddb *dev = io->port->dev; + struct ddb_dma *dma = io->dma; + u32 i; + u64 mem; - return i2c_write(adap, adr, msg, 2); + if (!dma) + return; + for (i = 0; i < dma->num; i++) { + mem = dma->pbuf[i]; + ddbwritel(dev, mem & 0xffffffff, dma->bufregs + i * 8); + ddbwritel(dev, mem >> 32, dma->bufregs + i * 8 + 4); + } + dma->bufval = ((dma->div & 0x0f) << 16) | + ((dma->num & 0x1f) << 11) | + ((dma->size >> 7) & 0x7ff); } -static inline u32 safe_ddbreadl(struct ddb *dev, u32 adr) +static void ddb_set_dma_tables(struct ddb *dev) { - u32 val = ddbreadl(adr); + u32 i; - /* (ddb)readl returns (uint)-1 (all bits set) on failure, catch that */ - if (val == ~0) { - dev_err(&dev->pdev->dev, "ddbreadl failure, adr=%08x\n", adr); - return 0; + for (i = 0; i < DDB_MAX_PORT; i++) { + if (dev->port[i].input[0]) + ddb_set_dma_table(dev->port[i].input[0]); + if (dev->port[i].input[1]) + ddb_set_dma_table(dev->port[i].input[1]); + if (dev->port[i].output) + ddb_set_dma_table(dev->port[i].output); } - - return val; } -static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void ddb_redirect_dma(struct ddb *dev, + struct ddb_dma *sdma, + struct ddb_dma *ddma) { - struct ddb *dev = i2c->dev; - long stat; - u32 val; + u32 i, base; + u64 mem; - i2c->done = 0; - ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND); - stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ); - if (stat == 0) { - dev_err(&dev->pdev->dev, "I2C timeout\n"); - { /* MSI debugging*/ - u32 istat = ddbreadl(INTERRUPT_STATUS); - dev_err(&dev->pdev->dev, "IRS %08x\n", istat); - ddbwritel(istat, INTERRUPT_ACK); - } - return -EIO; + sdma->bufval = ddma->bufval; + base = sdma->bufregs; + for (i = 0; i < ddma->num; i++) { + mem = ddma->pbuf[i]; + ddbwritel(dev, mem & 0xffffffff, base + i * 8); + ddbwritel(dev, mem >> 32, base + i * 8 + 4); } - val = ddbreadl(i2c->regs+I2C_COMMAND); - if (val & 0x70000) - return -EIO; - return 0; } -static int ddb_i2c_master_xfer(struct i2c_adapter *adapter, - struct i2c_msg msg[], int num) +static int ddb_unredirect(struct ddb_port *port) { - struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter); - struct ddb *dev = i2c->dev; - u8 addr = 0; - - if (num) - addr = msg[0].addr; - - if (num == 2 && msg[1].flags & I2C_M_RD && - !(msg[0].flags & I2C_M_RD)) { - memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf, - msg[0].buf, msg[0].len); - ddbwritel(msg[0].len|(msg[1].len << 16), - i2c->regs+I2C_TASKLENGTH); - if (!ddb_i2c_cmd(i2c, addr, 1)) { - memcpy_fromio(msg[1].buf, - dev->regs + I2C_TASKMEM_BASE + i2c->rbuf, - msg[1].len); - return num; - } - } + struct ddb_input *oredi, *iredi = NULL; + struct ddb_output *iredo = NULL; - if (num == 1 && !(msg[0].flags & I2C_M_RD)) { - ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len); - ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH); - if (!ddb_i2c_cmd(i2c, addr, 2)) - return num; + /* dev_info(port->dev->dev, + * "unredirect %d.%d\n", port->dev->nr, port->nr); + */ + mutex_lock(&redirect_lock); + if (port->output->dma->running) { + mutex_unlock(&redirect_lock); + return -EBUSY; } - if (num == 1 && (msg[0].flags & I2C_M_RD)) { - ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH); - if (!ddb_i2c_cmd(i2c, addr, 3)) { - ddbcpyfrom(msg[0].buf, - I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len); - return num; + oredi = port->output->redi; + if (!oredi) + goto done; + if (port->input[0]) { + iredi = port->input[0]->redi; + iredo = port->input[0]->redo; + + if (iredo) { + iredo->port->output->redi = oredi; + if (iredo->port->input[0]) { + iredo->port->input[0]->redi = iredi; + ddb_redirect_dma(oredi->port->dev, + oredi->dma, iredo->dma); + } + port->input[0]->redo = NULL; + ddb_set_dma_table(port->input[0]); } + oredi->redi = iredi; + port->input[0]->redi = NULL; } - return -EIO; -} - - -static u32 ddb_i2c_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static struct i2c_algorithm ddb_i2c_algo = { - .master_xfer = ddb_i2c_master_xfer, - .functionality = ddb_i2c_functionality, -}; - -static void ddb_i2c_release(struct ddb *dev) -{ - int i; - struct ddb_i2c *i2c; - struct i2c_adapter *adap; + oredi->redo = NULL; + port->output->redi = NULL; - for (i = 0; i < dev->info->port_num; i++) { - i2c = &dev->i2c[i]; - adap = &i2c->adap; - i2c_del_adapter(adap); - } + ddb_set_dma_table(oredi); +done: + mutex_unlock(&redirect_lock); + return 0; } -static int ddb_i2c_init(struct ddb *dev) +static int ddb_redirect(u32 i, u32 p) { - int i, j, stat = 0; - struct ddb_i2c *i2c; - struct i2c_adapter *adap; - - for (i = 0; i < dev->info->port_num; i++) { - i2c = &dev->i2c[i]; - i2c->dev = dev; - i2c->nr = i; - i2c->wbuf = i * (I2C_TASKMEM_SIZE / 4); - i2c->rbuf = i2c->wbuf + (I2C_TASKMEM_SIZE / 8); - i2c->regs = 0x80 + i * 0x20; - ddbwritel(I2C_SPEED_100, i2c->regs + I2C_TIMING); - ddbwritel((i2c->rbuf << 16) | i2c->wbuf, - i2c->regs + I2C_TASKADDRESS); - init_waitqueue_head(&i2c->wq); - - adap = &i2c->adap; - i2c_set_adapdata(adap, i2c); -#ifdef I2C_ADAP_CLASS_TV_DIGITAL - adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG; -#else -#ifdef I2C_CLASS_TV_ANALOG - adap->class = I2C_CLASS_TV_ANALOG; -#endif -#endif - strcpy(adap->name, "ddbridge"); - adap->algo = &ddb_i2c_algo; - adap->algo_data = (void *)i2c; - adap->dev.parent = &dev->pdev->dev; - stat = i2c_add_adapter(adap); - if (stat) - break; - } - if (stat) - for (j = 0; j < i; j++) { - i2c = &dev->i2c[j]; - adap = &i2c->adap; - i2c_del_adapter(adap); - } - return stat; -} + struct ddb *idev = ddbs[(i >> 4) & 0x3f]; + struct ddb_input *input, *input2; + struct ddb *pdev = ddbs[(p >> 4) & 0x3f]; + struct ddb_port *port; + if (!idev || !pdev) + return -EINVAL; + if (!idev->has_dma || !pdev->has_dma) + return -EINVAL; -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ + port = &pdev->port[p & 0x0f]; + if (!port->output) + return -EINVAL; + if (ddb_unredirect(port)) + return -EBUSY; -#if 0 -static void set_table(struct ddb *dev, u32 off, - dma_addr_t *pbuf, u32 num) -{ - u32 i, base; - u64 mem; + if (i == 8) + return 0; - base = DMA_BASE_ADDRESS_TABLE + off; - for (i = 0; i < num; i++) { - mem = pbuf[i]; - ddbwritel(mem & 0xffffffff, base + i * 8); - ddbwritel(mem >> 32, base + i * 8 + 4); - } -} -#endif + input = &idev->input[i & 7]; + if (!input) + return -EINVAL; -static void ddb_address_table(struct ddb *dev) -{ - u32 i, j, base; - u64 mem; - dma_addr_t *pbuf; - - for (i = 0; i < dev->info->port_num * 2; i++) { - base = DMA_BASE_ADDRESS_TABLE + i * 0x100; - pbuf = dev->input[i].pbuf; - for (j = 0; j < dev->input[i].dma_buf_num; j++) { - mem = pbuf[j]; - ddbwritel(mem & 0xffffffff, base + j * 8); - ddbwritel(mem >> 32, base + j * 8 + 4); - } + mutex_lock(&redirect_lock); + if (port->output->dma->running || input->dma->running) { + mutex_unlock(&redirect_lock); + return -EBUSY; } - for (i = 0; i < dev->info->port_num; i++) { - base = DMA_BASE_ADDRESS_TABLE + 0x800 + i * 0x100; - pbuf = dev->output[i].pbuf; - for (j = 0; j < dev->output[i].dma_buf_num; j++) { - mem = pbuf[j]; - ddbwritel(mem & 0xffffffff, base + j * 8); - ddbwritel(mem >> 32, base + j * 8 + 4); - } + input2 = port->input[0]; + if (input2) { + if (input->redi) { + input2->redi = input->redi; + input->redi = NULL; + } else + input2->redi = input; } + input->redo = port->output; + port->output->redi = input; + + ddb_redirect_dma(input->port->dev, input->dma, port->output->dma); + mutex_unlock(&redirect_lock); + return 0; } -static void io_free(struct pci_dev *pdev, u8 **vbuf, - dma_addr_t *pbuf, u32 size, int num) +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void dma_free(struct pci_dev *pdev, struct ddb_dma *dma, int dir) { int i; - for (i = 0; i < num; i++) { - if (vbuf[i]) { - pci_free_consistent(pdev, size, vbuf[i], pbuf[i]); - vbuf[i] = NULL; + if (!dma) + return; + for (i = 0; i < dma->num; i++) { + if (dma->vbuf[i]) { + if (alt_dma) { + dma_unmap_single(&pdev->dev, dma->pbuf[i], + dma->size, + dir ? DMA_TO_DEVICE : + DMA_FROM_DEVICE); + kfree(dma->vbuf[i]); + dma->vbuf[i] = NULL; + } else { + dma_free_coherent(&pdev->dev, dma->size, + dma->vbuf[i], dma->pbuf[i]); + } + + dma->vbuf[i] = NULL; } } } -static int io_alloc(struct pci_dev *pdev, u8 **vbuf, - dma_addr_t *pbuf, u32 size, int num) +static int dma_alloc(struct pci_dev *pdev, struct ddb_dma *dma, int dir) { int i; - for (i = 0; i < num; i++) { - vbuf[i] = pci_alloc_consistent(pdev, size, &pbuf[i]); - if (!vbuf[i]) - return -ENOMEM; + if (!dma) + return 0; + for (i = 0; i < dma->num; i++) { + if (alt_dma) { + dma->vbuf[i] = kmalloc(dma->size, __GFP_RETRY_MAYFAIL); + if (!dma->vbuf[i]) + return -ENOMEM; + dma->pbuf[i] = dma_map_single(&pdev->dev, + dma->vbuf[i], + dma->size, + dir ? DMA_TO_DEVICE : + DMA_FROM_DEVICE); + if (dma_mapping_error(&pdev->dev, dma->pbuf[i])) { + kfree(dma->vbuf[i]); + dma->vbuf[i] = NULL; + return -ENOMEM; + } + } else { + dma->vbuf[i] = dma_alloc_coherent(&pdev->dev, + dma->size, + &dma->pbuf[i], + GFP_KERNEL); + if (!dma->vbuf[i]) + return -ENOMEM; + } } return 0; } -static int ddb_buffers_alloc(struct ddb *dev) +int ddb_buffers_alloc(struct ddb *dev) { int i; struct ddb_port *port; - for (i = 0; i < dev->info->port_num; i++) { + for (i = 0; i < dev->port_num; i++) { port = &dev->port[i]; switch (port->class) { case DDB_PORT_TUNER: - if (io_alloc(dev->pdev, port->input[0]->vbuf, - port->input[0]->pbuf, - port->input[0]->dma_buf_size, - port->input[0]->dma_buf_num) < 0) - return -1; - if (io_alloc(dev->pdev, port->input[1]->vbuf, - port->input[1]->pbuf, - port->input[1]->dma_buf_size, - port->input[1]->dma_buf_num) < 0) - return -1; + if (port->input[0]->dma) + if (dma_alloc(dev->pdev, port->input[0]->dma, 0) + < 0) + return -1; + if (port->input[1]->dma) + if (dma_alloc(dev->pdev, port->input[1]->dma, 0) + < 0) + return -1; break; case DDB_PORT_CI: - if (io_alloc(dev->pdev, port->input[0]->vbuf, - port->input[0]->pbuf, - port->input[0]->dma_buf_size, - port->input[0]->dma_buf_num) < 0) - return -1; - if (io_alloc(dev->pdev, port->output->vbuf, - port->output->pbuf, - port->output->dma_buf_size, - port->output->dma_buf_num) < 0) - return -1; + case DDB_PORT_LOOP: + if (port->input[0]->dma) + if (dma_alloc(dev->pdev, port->input[0]->dma, 0) + < 0) + return -1; + if (port->output->dma) + if (dma_alloc(dev->pdev, port->output->dma, 1) + < 0) + return -1; break; default: break; } } - ddb_address_table(dev); + ddb_set_dma_tables(dev); return 0; } -static void ddb_buffers_free(struct ddb *dev) +void ddb_buffers_free(struct ddb *dev) { int i; struct ddb_port *port; - for (i = 0; i < dev->info->port_num; i++) { + for (i = 0; i < dev->port_num; i++) { port = &dev->port[i]; - io_free(dev->pdev, port->input[0]->vbuf, - port->input[0]->pbuf, - port->input[0]->dma_buf_size, - port->input[0]->dma_buf_num); - io_free(dev->pdev, port->input[1]->vbuf, - port->input[1]->pbuf, - port->input[1]->dma_buf_size, - port->input[1]->dma_buf_num); - io_free(dev->pdev, port->output->vbuf, - port->output->pbuf, - port->output->dma_buf_size, - port->output->dma_buf_num); + + if (port->input[0] && port->input[0]->dma) + dma_free(dev->pdev, port->input[0]->dma, 0); + if (port->input[1] && port->input[1]->dma) + dma_free(dev->pdev, port->input[1]->dma, 0); + if (port->output && port->output->dma) + dma_free(dev->pdev, port->output->dma, 1); } } -static void ddb_input_start(struct ddb_input *input) +static void calc_con(struct ddb_output *output, u32 *con, u32 *con2, u32 flags) { - struct ddb *dev = input->port->dev; + struct ddb *dev = output->port->dev; + u32 bitrate = output->port->obr, max_bitrate = 72000; + u32 gap = 4, nco = 0; + + *con = 0x1c; + if (output->port->gap != 0xffffffff) { + flags |= 1; + gap = output->port->gap; + max_bitrate = 0; + } + if (dev->link[0].info->type == DDB_OCTOPUS_CI && output->port->nr > 1) { + *con = 0x10c; + if (dev->link[0].ids.regmapid >= 0x10003 && !(flags & 1)) { + if (!(flags & 2)) { + /* NCO */ + max_bitrate = 0; + gap = 0; + if (bitrate != 72000) { + if (bitrate >= 96000) + *con |= 0x800; + else { + *con |= 0x1000; + nco = (bitrate * 8192 + 71999) + / 72000; + } + } + } else { + /* Divider and gap */ + *con |= 0x1810; + if (bitrate <= 64000) { + max_bitrate = 64000; + nco = 8; + } else if (bitrate <= 72000) { + max_bitrate = 72000; + nco = 7; + } else { + max_bitrate = 96000; + nco = 5; + } + } + } else { + if (bitrate > 72000) { + *con |= 0x810; /* 96 MBit/s and gap */ + max_bitrate = 96000; + } + *con |= 0x10; /* enable gap */ + } + } + if (max_bitrate > 0) { + if (bitrate > max_bitrate) + bitrate = max_bitrate; + if (bitrate < 31000) + bitrate = 31000; + gap = ((max_bitrate - bitrate) * 94) / bitrate; + if (gap < 2) + *con &= ~0x10; /* Disable gap */ + else + gap -= 2; + if (gap > 127) + gap = 127; + } + + *con2 = (nco << 16) | gap; +} - spin_lock_irq(&input->lock); - input->cbuf = 0; - input->coff = 0; +static void ddb_output_start(struct ddb_output *output) +{ + struct ddb *dev = output->port->dev; + u32 con = 0x11c, con2 = 0; + + if (output->dma) { + spin_lock_irq(&output->dma->lock); + output->dma->cbuf = 0; + output->dma->coff = 0; + output->dma->stat = 0; + ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma)); + } - /* reset */ - ddbwritel(0, TS_INPUT_CONTROL(input->nr)); - ddbwritel(2, TS_INPUT_CONTROL(input->nr)); - ddbwritel(0, TS_INPUT_CONTROL(input->nr)); + if (output->port->input[0]->port->class == DDB_PORT_LOOP) + con = (1UL << 13) | 0x14; + else + calc_con(output, &con, &con2, 0); + + ddbwritel(dev, 0, TS_CONTROL(output)); + ddbwritel(dev, 2, TS_CONTROL(output)); + ddbwritel(dev, 0, TS_CONTROL(output)); + ddbwritel(dev, con, TS_CONTROL(output)); + ddbwritel(dev, con2, TS_CONTROL2(output)); + + if (output->dma) { + ddbwritel(dev, output->dma->bufval, + DMA_BUFFER_SIZE(output->dma)); + ddbwritel(dev, 0, DMA_BUFFER_ACK(output->dma)); + ddbwritel(dev, 1, DMA_BASE_READ); + ddbwritel(dev, 7, DMA_BUFFER_CONTROL(output->dma)); + } - ddbwritel((1 << 16) | - (input->dma_buf_num << 11) | - (input->dma_buf_size >> 7), - DMA_BUFFER_SIZE(input->nr)); - ddbwritel(0, DMA_BUFFER_ACK(input->nr)); + ddbwritel(dev, con | 1, TS_CONTROL(output)); - ddbwritel(1, DMA_BASE_WRITE); - ddbwritel(3, DMA_BUFFER_CONTROL(input->nr)); - ddbwritel(9, TS_INPUT_CONTROL(input->nr)); - input->running = 1; - spin_unlock_irq(&input->lock); + if (output->dma) { + output->dma->running = 1; + spin_unlock_irq(&output->dma->lock); + } +} + +static void ddb_output_stop(struct ddb_output *output) +{ + struct ddb *dev = output->port->dev; + + if (output->dma) + spin_lock_irq(&output->dma->lock); + + ddbwritel(dev, 0, TS_CONTROL(output)); + + if (output->dma) { + ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma)); + output->dma->running = 0; + spin_unlock_irq(&output->dma->lock); + } } static void ddb_input_stop(struct ddb_input *input) { struct ddb *dev = input->port->dev; + u32 tag = DDB_LINK_TAG(input->port->lnr); + + if (input->dma) + spin_lock_irq(&input->dma->lock); + ddbwritel(dev, 0, tag | TS_CONTROL(input)); + if (input->dma) { + ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma)); + input->dma->running = 0; + spin_unlock_irq(&input->dma->lock); + } +} + +static void ddb_input_start(struct ddb_input *input) +{ + struct ddb *dev = input->port->dev; + + if (input->dma) { + spin_lock_irq(&input->dma->lock); + input->dma->cbuf = 0; + input->dma->coff = 0; + input->dma->stat = 0; + ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma)); + } + ddbwritel(dev, 0, TS_CONTROL(input)); + ddbwritel(dev, 2, TS_CONTROL(input)); + ddbwritel(dev, 0, TS_CONTROL(input)); + + if (input->dma) { + ddbwritel(dev, input->dma->bufval, + DMA_BUFFER_SIZE(input->dma)); + ddbwritel(dev, 0, DMA_BUFFER_ACK(input->dma)); + ddbwritel(dev, 1, DMA_BASE_WRITE); + ddbwritel(dev, 3, DMA_BUFFER_CONTROL(input->dma)); + } - spin_lock_irq(&input->lock); - ddbwritel(0, TS_INPUT_CONTROL(input->nr)); - ddbwritel(0, DMA_BUFFER_CONTROL(input->nr)); - input->running = 0; - spin_unlock_irq(&input->lock); + ddbwritel(dev, 0x09, TS_CONTROL(input)); + + if (input->dma) { + input->dma->running = 1; + spin_unlock_irq(&input->dma->lock); + } } -static void ddb_output_start(struct ddb_output *output) + +static void ddb_input_start_all(struct ddb_input *input) { - struct ddb *dev = output->port->dev; + struct ddb_input *i = input; + struct ddb_output *o; - spin_lock_irq(&output->lock); - output->cbuf = 0; - output->coff = 0; - ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel(2, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel(0x3c, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel((1 << 16) | - (output->dma_buf_num << 11) | - (output->dma_buf_size >> 7), - DMA_BUFFER_SIZE(output->nr + 8)); - ddbwritel(0, DMA_BUFFER_ACK(output->nr + 8)); - - ddbwritel(1, DMA_BASE_READ); - ddbwritel(3, DMA_BUFFER_CONTROL(output->nr + 8)); - /* ddbwritel(0xbd, TS_OUTPUT_CONTROL(output->nr)); */ - ddbwritel(0x1d, TS_OUTPUT_CONTROL(output->nr)); - output->running = 1; - spin_unlock_irq(&output->lock); + mutex_lock(&redirect_lock); + while (i && (o = i->redo)) { + ddb_output_start(o); + i = o->port->input[0]; + if (i) + ddb_input_start(i); + } + ddb_input_start(input); + mutex_unlock(&redirect_lock); } -static void ddb_output_stop(struct ddb_output *output) +static void ddb_input_stop_all(struct ddb_input *input) { - struct ddb *dev = output->port->dev; + struct ddb_input *i = input; + struct ddb_output *o; - spin_lock_irq(&output->lock); - ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel(0, DMA_BUFFER_CONTROL(output->nr + 8)); - output->running = 0; - spin_unlock_irq(&output->lock); + mutex_lock(&redirect_lock); + ddb_input_stop(input); + while (i && (o = i->redo)) { + ddb_output_stop(o); + i = o->port->input[0]; + if (i) + ddb_input_stop(i); + } + mutex_unlock(&redirect_lock); } static u32 ddb_output_free(struct ddb_output *output) { - u32 idx, off, stat = output->stat; + u32 idx, off, stat = output->dma->stat; s32 diff; idx = (stat >> 11) & 0x1f; off = (stat & 0x7ff) << 7; - if (output->cbuf != idx) { - if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && - (output->dma_buf_size - output->coff <= 188)) + if (output->dma->cbuf != idx) { + if ((((output->dma->cbuf + 1) % output->dma->num) == idx) && + (output->dma->size - output->dma->coff <= 188)) return 0; return 188; } - diff = off - output->coff; + diff = off - output->dma->coff; if (diff <= 0 || diff > 188) return 188; return 0; @@ -494,46 +563,51 @@ static ssize_t ddb_output_write(struct ddb_output *output, const __user u8 *buf, size_t count) { struct ddb *dev = output->port->dev; - u32 idx, off, stat = output->stat; + u32 idx, off, stat = output->dma->stat; u32 left = count, len; idx = (stat >> 11) & 0x1f; off = (stat & 0x7ff) << 7; while (left) { - len = output->dma_buf_size - output->coff; - if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && + len = output->dma->size - output->dma->coff; + if ((((output->dma->cbuf + 1) % output->dma->num) == idx) && (off == 0)) { if (len <= 188) break; len -= 188; } - if (output->cbuf == idx) { - if (off > output->coff) { -#if 1 - len = off - output->coff; + if (output->dma->cbuf == idx) { + if (off > output->dma->coff) { + len = off - output->dma->coff; len -= (len % 188); if (len <= 188) - -#endif break; len -= 188; } } if (len > left) len = left; - if (copy_from_user(output->vbuf[output->cbuf] + output->coff, + if (copy_from_user(output->dma->vbuf[output->dma->cbuf] + + output->dma->coff, buf, len)) return -EIO; + if (alt_dma) + dma_sync_single_for_device(dev->dev, + output->dma->pbuf[output->dma->cbuf], + output->dma->size, DMA_TO_DEVICE); left -= len; buf += len; - output->coff += len; - if (output->coff == output->dma_buf_size) { - output->coff = 0; - output->cbuf = ((output->cbuf + 1) % output->dma_buf_num); + output->dma->coff += len; + if (output->dma->coff == output->dma->size) { + output->dma->coff = 0; + output->dma->cbuf = ((output->dma->cbuf + 1) % + output->dma->num); } - ddbwritel((output->cbuf << 11) | (output->coff >> 7), - DMA_BUFFER_ACK(output->nr + 8)); + ddbwritel(dev, + (output->dma->cbuf << 11) | + (output->dma->coff >> 7), + DMA_BUFFER_ACK(output->dma)); } return count - left; } @@ -541,81 +615,229 @@ static ssize_t ddb_output_write(struct ddb_output *output, static u32 ddb_input_avail(struct ddb_input *input) { struct ddb *dev = input->port->dev; - u32 idx, off, stat = input->stat; - u32 ctrl = ddbreadl(DMA_BUFFER_CONTROL(input->nr)); + u32 idx, off, stat = input->dma->stat; + u32 ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(input->dma)); idx = (stat >> 11) & 0x1f; off = (stat & 0x7ff) << 7; if (ctrl & 4) { - dev_err(&dev->pdev->dev, "IA %d %d %08x\n", idx, off, ctrl); - ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr)); + dev_err(dev->dev, "IA %d %d %08x\n", idx, off, ctrl); + ddbwritel(dev, stat, DMA_BUFFER_ACK(input->dma)); return 0; } - if (input->cbuf != idx) + if (input->dma->cbuf != idx) return 188; return 0; } -static ssize_t ddb_input_read(struct ddb_input *input, __user u8 *buf, size_t count) +static ssize_t ddb_input_read(struct ddb_input *input, + __user u8 *buf, size_t count) { struct ddb *dev = input->port->dev; u32 left = count; - u32 idx, free, stat = input->stat; + u32 idx, free, stat = input->dma->stat; int ret; idx = (stat >> 11) & 0x1f; while (left) { - if (input->cbuf == idx) + if (input->dma->cbuf == idx) return count - left; - free = input->dma_buf_size - input->coff; + free = input->dma->size - input->dma->coff; if (free > left) free = left; - ret = copy_to_user(buf, input->vbuf[input->cbuf] + - input->coff, free); + if (alt_dma) + dma_sync_single_for_cpu(dev->dev, + input->dma->pbuf[input->dma->cbuf], + input->dma->size, DMA_FROM_DEVICE); + ret = copy_to_user(buf, input->dma->vbuf[input->dma->cbuf] + + input->dma->coff, free); if (ret) return -EFAULT; - input->coff += free; - if (input->coff == input->dma_buf_size) { - input->coff = 0; - input->cbuf = (input->cbuf+1) % input->dma_buf_num; + input->dma->coff += free; + if (input->dma->coff == input->dma->size) { + input->dma->coff = 0; + input->dma->cbuf = (input->dma->cbuf + 1) % + input->dma->num; } left -= free; - ddbwritel((input->cbuf << 11) | (input->coff >> 7), - DMA_BUFFER_ACK(input->nr)); + buf += free; + ddbwritel(dev, + (input->dma->cbuf << 11) | (input->dma->coff >> 7), + DMA_BUFFER_ACK(input->dma)); } return count; } -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ -#if 0 -static struct ddb_input *fe2input(struct ddb *dev, struct dvb_frontend *fe) +static ssize_t ts_write(struct file *file, const __user char *buf, + size_t count, loff_t *ppos) { - int i; + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = dvbdev->priv; + struct ddb *dev = output->port->dev; + size_t left = count; + int stat; - for (i = 0; i < dev->info->port_num * 2; i++) { - if (dev->input[i].fe == fe) - return &dev->input[i]; + if (!dev->has_dma) + return -EINVAL; + while (left) { + if (ddb_output_free(output) < 188) { + if (file->f_flags & O_NONBLOCK) + break; + if (wait_event_interruptible( + output->dma->wq, + ddb_output_free(output) >= 188) < 0) + break; + } + stat = ddb_output_write(output, buf, left); + if (stat < 0) + return stat; + buf += stat; + left -= stat; } - return NULL; + return (left == count) ? -EAGAIN : (count - left); } -#endif -static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) +static ssize_t ts_read(struct file *file, __user char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = dvbdev->priv; + struct ddb_input *input = output->port->input[0]; + struct ddb *dev = output->port->dev; + size_t left = count; + int stat; + + if (!dev->has_dma) + return -EINVAL; + while (left) { + if (ddb_input_avail(input) < 188) { + if (file->f_flags & O_NONBLOCK) + break; + if (wait_event_interruptible( + input->dma->wq, + ddb_input_avail(input) >= 188) < 0) + break; + } + stat = ddb_input_read(input, buf, left); + if (stat < 0) + return stat; + left -= stat; + buf += stat; + } + return (count && (left == count)) ? -EAGAIN : (count - left); +} + +static unsigned int ts_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = dvbdev->priv; + struct ddb_input *input = output->port->input[0]; + + unsigned int mask = 0; + + poll_wait(file, &input->dma->wq, wait); + poll_wait(file, &output->dma->wq, wait); + if (ddb_input_avail(input) >= 188) + mask |= POLLIN | POLLRDNORM; + if (ddb_output_free(output) >= 188) + mask |= POLLOUT | POLLWRNORM; + return mask; +} + +static int ts_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = NULL; + struct ddb_input *input = NULL; + + if (dvbdev) { + output = dvbdev->priv; + input = output->port->input[0]; + } + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if (!input) + return -EINVAL; + ddb_input_stop(input); + } else if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + if (!output) + return -EINVAL; + ddb_output_stop(output); + } + return dvb_generic_release(inode, file); +} + +static int ts_open(struct inode *inode, struct file *file) +{ + int err; + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = NULL; + struct ddb_input *input = NULL; + + if (dvbdev) { + output = dvbdev->priv; + input = output->port->input[0]; + } + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if (!input) + return -EINVAL; + if (input->redo || input->redi) + return -EBUSY; + } else if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + if (!output) + return -EINVAL; + } else + return -EINVAL; + err = dvb_generic_open(inode, file); + if (err < 0) + return err; + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + ddb_input_start(input); + else if ((file->f_flags & O_ACCMODE) == O_WRONLY) + ddb_output_start(output); + return err; +} + +static const struct file_operations ci_fops = { + .owner = THIS_MODULE, + .read = ts_read, + .write = ts_write, + .open = ts_open, + .release = ts_release, + .poll = ts_poll, + .mmap = NULL, +}; + +static struct dvb_device dvbdev_ci = { + .priv = NULL, + .readers = 1, + .writers = 1, + .users = 2, + .fops = &ci_fops, +}; + + +/****************************************************************************/ +/****************************************************************************/ + +static int locked_gate_ctrl(struct dvb_frontend *fe, int enable) { struct ddb_input *input = fe->sec_priv; struct ddb_port *port = input->port; + struct ddb_dvb *dvb = &port->dvb[input->nr & 1]; int status; if (enable) { mutex_lock(&port->i2c_gate_lock); - status = input->gate_ctrl(fe, 1); + status = dvb->i2c_gate_ctrl(fe, 1); } else { - status = input->gate_ctrl(fe, 0); + status = dvb->i2c_gate_ctrl(fe, 0); mutex_unlock(&port->i2c_gate_lock); } return status; @@ -624,41 +846,42 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) static int demod_attach_drxk(struct ddb_input *input) { struct i2c_adapter *i2c = &input->port->i2c->adap; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; struct dvb_frontend *fe; struct drxk_config config; - struct device *dev = &input->port->dev->pdev->dev; memset(&config, 0, sizeof(config)); - config.microcode_name = "drxk_a3.mc"; - config.qam_demod_parameter_count = 4; config.adr = 0x29 + (input->nr & 1); + config.microcode_name = "drxk_a3.mc"; - fe = input->fe = dvb_attach(drxk_attach, &config, i2c); - if (!input->fe) { + fe = dvb->fe = dvb_attach(drxk_attach, &config, i2c); + if (!fe) { dev_err(dev, "No DRXK found!\n"); return -ENODEV; } fe->sec_priv = input; - input->gate_ctrl = fe->ops.i2c_gate_ctrl; - fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + dvb->i2c_gate_ctrl = fe->ops.i2c_gate_ctrl; + fe->ops.i2c_gate_ctrl = locked_gate_ctrl; return 0; } static int tuner_attach_tda18271(struct ddb_input *input) { struct i2c_adapter *i2c = &input->port->i2c->adap; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; struct dvb_frontend *fe; - struct device *dev = &input->port->dev->pdev->dev; - if (input->fe->ops.i2c_gate_ctrl) - input->fe->ops.i2c_gate_ctrl(input->fe, 1); - fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60); + if (dvb->fe->ops.i2c_gate_ctrl) + dvb->fe->ops.i2c_gate_ctrl(dvb->fe, 1); + fe = dvb_attach(tda18271c2dd_attach, dvb->fe, i2c, 0x60); + if (dvb->fe->ops.i2c_gate_ctrl) + dvb->fe->ops.i2c_gate_ctrl(dvb->fe, 0); if (!fe) { dev_err(dev, "No TDA18271 found!\n"); return -ENODEV; } - if (input->fe->ops.i2c_gate_ctrl) - input->fe->ops.i2c_gate_ctrl(input->fe, 0); return 0; } @@ -687,43 +910,43 @@ static struct stv0367_config ddb_stv0367_config[] = { static int demod_attach_stv0367(struct ddb_input *input) { struct i2c_adapter *i2c = &input->port->i2c->adap; - struct device *dev = &input->port->dev->pdev->dev; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; + struct dvb_frontend *fe; /* attach frontend */ - input->fe = dvb_attach(stv0367ddb_attach, + fe = dvb->fe = dvb_attach(stv0367ddb_attach, &ddb_stv0367_config[(input->nr & 1)], i2c); - if (!input->fe) { - dev_err(dev, "stv0367ddb_attach failed (not found?)\n"); + if (!dvb->fe) { + dev_err(dev, "No stv0367 found!\n"); return -ENODEV; } - - input->fe->sec_priv = input; - input->gate_ctrl = input->fe->ops.i2c_gate_ctrl; - input->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; - + fe->sec_priv = input; + dvb->i2c_gate_ctrl = fe->ops.i2c_gate_ctrl; + fe->ops.i2c_gate_ctrl = locked_gate_ctrl; return 0; } static int tuner_tda18212_ping(struct ddb_input *input, unsigned short adr) { struct i2c_adapter *adapter = &input->port->i2c->adap; - struct device *dev = &input->port->dev->pdev->dev; - + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; u8 tda_id[2]; u8 subaddr = 0x00; dev_dbg(dev, "stv0367-tda18212 tuner ping\n"); - if (input->fe->ops.i2c_gate_ctrl) - input->fe->ops.i2c_gate_ctrl(input->fe, 1); + if (dvb->fe->ops.i2c_gate_ctrl) + dvb->fe->ops.i2c_gate_ctrl(dvb->fe, 1); if (i2c_read_regs(adapter, adr, subaddr, tda_id, sizeof(tda_id)) < 0) dev_dbg(dev, "tda18212 ping 1 fail\n"); if (i2c_read_regs(adapter, adr, subaddr, tda_id, sizeof(tda_id)) < 0) dev_warn(dev, "tda18212 ping failed, expect problems\n"); - if (input->fe->ops.i2c_gate_ctrl) - input->fe->ops.i2c_gate_ctrl(input->fe, 0); + if (dvb->fe->ops.i2c_gate_ctrl) + dvb->fe->ops.i2c_gate_ctrl(dvb->fe, 0); return 0; } @@ -731,7 +954,9 @@ static int tuner_tda18212_ping(struct ddb_input *input, unsigned short adr) static int demod_attach_cxd28xx(struct ddb_input *input, int par, int osc24) { struct i2c_adapter *i2c = &input->port->i2c->adap; - struct device *dev = &input->port->dev->pdev->dev; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; + struct dvb_frontend *fe; struct cxd2841er_config cfg; /* the cxd2841er driver expects 8bit/shifted I2C addresses */ @@ -746,27 +971,26 @@ static int demod_attach_cxd28xx(struct ddb_input *input, int par, int osc24) cfg.flags |= CXD2841ER_TS_SERIAL; /* attach frontend */ - input->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c); + fe = dvb->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c); - if (!input->fe) { - dev_err(dev, "No Sony CXD28xx found!\n"); + if (!dvb->fe) { + dev_err(dev, "No cxd2837/38/43/54 found!\n"); return -ENODEV; } - - input->fe->sec_priv = input; - input->gate_ctrl = input->fe->ops.i2c_gate_ctrl; - input->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; - + fe->sec_priv = input; + dvb->i2c_gate_ctrl = fe->ops.i2c_gate_ctrl; + fe->ops.i2c_gate_ctrl = locked_gate_ctrl; return 0; } static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype) { struct i2c_adapter *adapter = &input->port->i2c->adap; - struct device *dev = &input->port->dev->pdev->dev; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; struct i2c_client *client; struct tda18212_config config = { - .fe = input->fe, + .fe = dvb->fe, .if_dvbt_6 = 3550, .if_dvbt_7 = 3700, .if_dvbt_8 = 4150, @@ -804,17 +1028,17 @@ static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype) goto err; } - input->i2c_client[0] = client; + dvb->i2c_client[0] = client; return 0; err: - dev_warn(dev, "TDA18212 tuner not found. Device is not fully operational.\n"); + dev_notice(dev, "TDA18212 tuner not found. Device is not fully operational.\n"); return -ENODEV; } -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ static struct stv090x_config stv0900 = { .device = STV0900, @@ -827,6 +1051,9 @@ static struct stv090x_config stv0900 = { .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts1_tei = 1, + .ts2_tei = 1, + .repeater_level = STV090x_RPTLEVEL_16, .adc1_range = STV090x_ADC_1Vpp, @@ -846,6 +1073,9 @@ static struct stv090x_config stv0900_aa = { .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts1_tei = 1, + .ts2_tei = 1, + .repeater_level = STV090x_RPTLEVEL_16, .adc1_range = STV090x_ADC_1Vpp, @@ -869,17 +1099,18 @@ static struct stv6110x_config stv6110b = { static int demod_attach_stv0900(struct ddb_input *input, int type) { struct i2c_adapter *i2c = &input->port->i2c->adap; - struct device *dev = &input->port->dev->pdev->dev; struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; - input->fe = dvb_attach(stv090x_attach, feconf, i2c, - (input->nr & 1) ? STV090x_DEMODULATOR_1 - : STV090x_DEMODULATOR_0); - if (!input->fe) { + dvb->fe = dvb_attach(stv090x_attach, feconf, i2c, + (input->nr & 1) ? STV090x_DEMODULATOR_1 + : STV090x_DEMODULATOR_0); + if (!dvb->fe) { dev_err(dev, "No STV0900 found!\n"); return -ENODEV; } - if (!dvb_attach(lnbh24_attach, input->fe, i2c, 0, + if (!dvb_attach(lnbh24_attach, dvb->fe, i2c, 0, 0, (input->nr & 1) ? (0x09 - type) : (0x0b - type))) { dev_err(dev, "No LNBH24 found!\n"); @@ -891,19 +1122,20 @@ static int demod_attach_stv0900(struct ddb_input *input, int type) static int tuner_attach_stv6110(struct ddb_input *input, int type) { struct i2c_adapter *i2c = &input->port->i2c->adap; - struct device *dev = &input->port->dev->pdev->dev; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; struct stv6110x_config *tunerconf = (input->nr & 1) ? &stv6110b : &stv6110a; const struct stv6110x_devctl *ctl; - ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c); + ctl = dvb_attach(stv6110x_attach, dvb->fe, tunerconf, i2c); if (!ctl) { dev_err(dev, "No STV6110X found!\n"); return -ENODEV; } dev_info(dev, "attach tuner input %d adr %02x\n", - input->nr, tunerconf->addr); + input->nr, tunerconf->addr); feconf->tuner_init = ctl->tuner_init; feconf->tuner_sleep = ctl->tuner_sleep; @@ -920,388 +1152,1062 @@ static int tuner_attach_stv6110(struct ddb_input *input, int type) return 0; } -static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, - int (*start_feed)(struct dvb_demux_feed *), - int (*stop_feed)(struct dvb_demux_feed *), - void *priv) +static const struct stv0910_cfg stv0910_p = { + .adr = 0x68, + .parallel = 1, + .rptlvl = 4, + .clk = 30000000, +}; + +static const struct lnbh25_config lnbh25_cfg = { + .i2c_address = 0x0c << 1, + .data2_config = LNBH25_TEN +}; + +static int demod_attach_stv0910(struct ddb_input *input, int type) { - dvbdemux->priv = priv; + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; + struct stv0910_cfg cfg = stv0910_p; + struct lnbh25_config lnbcfg = lnbh25_cfg; + + if (stv0910_single) + cfg.single = 1; + + if (type) + cfg.parallel = 2; + dvb->fe = dvb_attach(stv0910_attach, i2c, &cfg, (input->nr & 1)); + if (!dvb->fe) { + cfg.adr = 0x6c; + dvb->fe = dvb_attach(stv0910_attach, i2c, + &cfg, (input->nr & 1)); + } + if (!dvb->fe) { + dev_err(dev, "No STV0910 found!\n"); + return -ENODEV; + } - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = start_feed; - dvbdemux->stop_feed = stop_feed; - dvbdemux->write_to_decoder = NULL; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | - DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - return dvb_dmx_init(dvbdemux); + /* attach lnbh25 - leftshift by one as the lnbh25 driver expects 8bit + * i2c addresses + */ + lnbcfg.i2c_address = (((input->nr & 1) ? 0x0d : 0x0c) << 1); + if (!dvb_attach(lnbh25_attach, dvb->fe, &lnbcfg, i2c)) { + lnbcfg.i2c_address = (((input->nr & 1) ? 0x09 : 0x08) << 1); + if (!dvb_attach(lnbh25_attach, dvb->fe, &lnbcfg, i2c)) { + dev_err(dev, "No LNBH25 found!\n"); + return -ENODEV; + } + } + + return 0; } -static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, - struct dvb_demux *dvbdemux, - struct dmx_frontend *hw_frontend, - struct dmx_frontend *mem_frontend, - struct dvb_adapter *dvb_adapter) +static int tuner_attach_stv6111(struct ddb_input *input, int type) { - int ret; - - dmxdev->filternum = 256; - dmxdev->demux = &dvbdemux->dmx; - dmxdev->capabilities = 0; - ret = dvb_dmxdev_init(dmxdev, dvb_adapter); - if (ret < 0) - return ret; + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; + struct dvb_frontend *fe; + u8 adr = (type ? 0 : 4) + ((input->nr & 1) ? 0x63 : 0x60); - hw_frontend->source = DMX_FRONTEND_0; - dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); - mem_frontend->source = DMX_MEMORY_FE; - dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); - return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); + fe = dvb_attach(stv6111_attach, dvb->fe, i2c, adr); + if (!fe) { + fe = dvb_attach(stv6111_attach, dvb->fe, i2c, adr & ~4); + if (!fe) { + dev_err(dev, "No STV6111 found at 0x%02x!\n", adr); + return -ENODEV; + } + } + return 0; } static int start_feed(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct ddb_input *input = dvbdmx->priv; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; - if (!input->users) - ddb_input_start(input); + if (!dvb->users) + ddb_input_start_all(input); - return ++input->users; + return ++dvb->users; } static int stop_feed(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct ddb_input *input = dvbdmx->priv; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; - if (--input->users) - return input->users; + if (--dvb->users) + return dvb->users; - ddb_input_stop(input); + ddb_input_stop_all(input); return 0; } - static void dvb_input_detach(struct ddb_input *input) { - struct dvb_adapter *adap = &input->adap; - struct dvb_demux *dvbdemux = &input->demux; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct dvb_demux *dvbdemux = &dvb->demux; struct i2c_client *client; - switch (input->attached) { - case 5: - client = input->i2c_client[0]; + switch (dvb->attached) { + case 0x31: + if (dvb->fe2) + dvb_unregister_frontend(dvb->fe2); + if (dvb->fe) + dvb_unregister_frontend(dvb->fe); + /* fallthrough */ + case 0x30: + if (dvb->fe2) + dvb_frontend_detach(dvb->fe2); + if (dvb->fe) + dvb_frontend_detach(dvb->fe); + dvb->fe = dvb->fe2 = NULL; + /* fallthrough */ + case 0x20: + client = dvb->i2c_client[0]; if (client) { module_put(client->dev.driver->owner); i2c_unregister_device(client); } - if (input->fe2) { - dvb_unregister_frontend(input->fe2); - input->fe2 = NULL; - } - if (input->fe) { - dvb_unregister_frontend(input->fe); - dvb_frontend_detach(input->fe); - input->fe = NULL; - } - /* fall-through */ - case 4: - dvb_net_release(&input->dvbnet); - /* fall-through */ - case 3: - dvbdemux->dmx.close(&dvbdemux->dmx); + + dvb_net_release(&dvb->dvbnet); + /* fallthrough */ + case 0x12: dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, - &input->hw_frontend); + &dvb->hw_frontend); dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, - &input->mem_frontend); - dvb_dmxdev_release(&input->dmxdev); - /* fall-through */ - case 2: - dvb_dmx_release(&input->demux); - /* fall-through */ - case 1: - dvb_unregister_adapter(adap); + &dvb->mem_frontend); + /* fallthrough */ + case 0x11: + dvb_dmxdev_release(&dvb->dmxdev); + /* fallthrough */ + case 0x10: + dvb_dmx_release(&dvb->demux); + /* fallthrough */ + case 0x01: + break; + } + dvb->attached = 0x00; +} + +static int dvb_register_adapters(struct ddb *dev) +{ + int i, ret = 0; + struct ddb_port *port; + struct dvb_adapter *adap; + + if (adapter_alloc == 3) { + port = &dev->port[0]; + adap = port->dvb[0].adap; + ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, + port->dev->dev, + adapter_nr); + if (ret < 0) + return ret; + port->dvb[0].adap_registered = 1; + for (i = 0; i < dev->port_num; i++) { + port = &dev->port[i]; + port->dvb[0].adap = adap; + port->dvb[1].adap = adap; + } + return 0; + } + + for (i = 0; i < dev->port_num; i++) { + port = &dev->port[i]; + switch (port->class) { + case DDB_PORT_TUNER: + adap = port->dvb[0].adap; + ret = dvb_register_adapter(adap, "DDBridge", + THIS_MODULE, + port->dev->dev, + adapter_nr); + if (ret < 0) + return ret; + port->dvb[0].adap_registered = 1; + + if (adapter_alloc > 0) { + port->dvb[1].adap = port->dvb[0].adap; + break; + } + adap = port->dvb[1].adap; + ret = dvb_register_adapter(adap, "DDBridge", + THIS_MODULE, + port->dev->dev, + adapter_nr); + if (ret < 0) + return ret; + port->dvb[1].adap_registered = 1; + break; + + case DDB_PORT_CI: + case DDB_PORT_LOOP: + adap = port->dvb[0].adap; + ret = dvb_register_adapter(adap, "DDBridge", + THIS_MODULE, + port->dev->dev, + adapter_nr); + if (ret < 0) + return ret; + port->dvb[0].adap_registered = 1; + break; + default: + if (adapter_alloc < 2) + break; + adap = port->dvb[0].adap; + ret = dvb_register_adapter(adap, "DDBridge", + THIS_MODULE, + port->dev->dev, + adapter_nr); + if (ret < 0) + return ret; + port->dvb[0].adap_registered = 1; + break; + } + } + return ret; +} + +static void dvb_unregister_adapters(struct ddb *dev) +{ + int i; + struct ddb_port *port; + struct ddb_dvb *dvb; + + for (i = 0; i < dev->link[0].info->port_num; i++) { + port = &dev->port[i]; + + dvb = &port->dvb[0]; + if (dvb->adap_registered) + dvb_unregister_adapter(dvb->adap); + dvb->adap_registered = 0; + + dvb = &port->dvb[1]; + if (dvb->adap_registered) + dvb_unregister_adapter(dvb->adap); + dvb->adap_registered = 0; } - input->attached = 0; } static int dvb_input_attach(struct ddb_input *input) { - int ret; + int ret = 0; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; struct ddb_port *port = input->port; - struct dvb_adapter *adap = &input->adap; - struct dvb_demux *dvbdemux = &input->demux; - struct device *dev = &input->port->dev->pdev->dev; - int sony_osc24 = 0, sony_tspar = 0; - - ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, - &input->port->dev->pdev->dev, - adapter_nr); - if (ret < 0) { - dev_err(dev, "Could not register adapter. Check if you enabled enough adapters in dvb-core!\n"); + struct dvb_adapter *adap = dvb->adap; + struct dvb_demux *dvbdemux = &dvb->demux; + int par = 0, osc24 = 0; + + dvb->attached = 0x01; + + dvbdemux->priv = input; + dvbdemux->dmx.capabilities = DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING; + dvbdemux->start_feed = start_feed; + dvbdemux->stop_feed = stop_feed; + dvbdemux->filternum = dvbdemux->feednum = 256; + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) return ret; - } - input->attached = 1; + dvb->attached = 0x10; - ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", - start_feed, - stop_feed, input); + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = &dvbdemux->dmx; + ret = dvb_dmxdev_init(&dvb->dmxdev, adap); if (ret < 0) return ret; - input->attached = 2; + dvb->attached = 0x11; - ret = my_dvb_dmxdev_ts_card_init(&input->dmxdev, &input->demux, - &input->hw_frontend, - &input->mem_frontend, adap); + dvb->mem_frontend.source = DMX_MEMORY_FE; + dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->mem_frontend); + dvb->hw_frontend.source = DMX_FRONTEND_0; + dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->hw_frontend); + ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &dvb->hw_frontend); if (ret < 0) return ret; - input->attached = 3; + dvb->attached = 0x12; - ret = dvb_net_init(adap, &input->dvbnet, input->dmxdev.demux); + ret = dvb_net_init(adap, &dvb->dvbnet, dvb->dmxdev.demux); if (ret < 0) return ret; - input->attached = 4; + dvb->attached = 0x20; - input->fe = NULL; + dvb->fe = dvb->fe2 = NULL; switch (port->type) { + case DDB_TUNER_MXL5XX: + if (fe_attach_mxl5xx(input) < 0) + return -ENODEV; + break; case DDB_TUNER_DVBS_ST: if (demod_attach_stv0900(input, 0) < 0) return -ENODEV; if (tuner_attach_stv6110(input, 0) < 0) return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; - } break; case DDB_TUNER_DVBS_ST_AA: if (demod_attach_stv0900(input, 1) < 0) return -ENODEV; if (tuner_attach_stv6110(input, 1) < 0) return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; - } + break; + case DDB_TUNER_DVBS_STV0910: + if (demod_attach_stv0910(input, 0) < 0) + return -ENODEV; + if (tuner_attach_stv6111(input, 0) < 0) + return -ENODEV; + break; + case DDB_TUNER_DVBS_STV0910_PR: + if (demod_attach_stv0910(input, 1) < 0) + return -ENODEV; + if (tuner_attach_stv6111(input, 1) < 0) + return -ENODEV; + break; + case DDB_TUNER_DVBS_STV0910_P: + if (demod_attach_stv0910(input, 0) < 0) + return -ENODEV; + if (tuner_attach_stv6111(input, 1) < 0) + return -ENODEV; break; case DDB_TUNER_DVBCT_TR: if (demod_attach_drxk(input) < 0) return -ENODEV; if (tuner_attach_tda18271(input) < 0) return -ENODEV; - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; - if (input->fe2) { - if (dvb_register_frontend(adap, input->fe2) < 0) - return -ENODEV; - input->fe2->tuner_priv = input->fe->tuner_priv; - memcpy(&input->fe2->ops.tuner_ops, - &input->fe->ops.tuner_ops, - sizeof(struct dvb_tuner_ops)); - } break; case DDB_TUNER_DVBCT_ST: if (demod_attach_stv0367(input) < 0) return -ENODEV; - if (tuner_attach_tda18212(input, port->type) < 0) + if (tuner_attach_tda18212(input, port->type) < 0) { + if (dvb->fe2) + dvb_frontend_detach(dvb->fe2); + if (dvb->fe) + dvb_frontend_detach(dvb->fe); return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; } break; case DDB_TUNER_DVBC2T2I_SONY_P: + if (input->port->dev->link[input->port->lnr].info->ts_quirks & + TS_QUIRK_ALT_OSC) + osc24 = 0; + else + osc24 = 1; + /* fall-through */ case DDB_TUNER_DVBCT2_SONY_P: case DDB_TUNER_DVBC2T2_SONY_P: case DDB_TUNER_ISDBT_SONY_P: - if (port->type == DDB_TUNER_DVBC2T2I_SONY_P) - sony_osc24 = 1; - if (input->port->dev->info->ts_quirks & TS_QUIRK_ALT_OSC) - sony_osc24 = 0; - if (input->port->dev->info->ts_quirks & TS_QUIRK_SERIAL) - sony_tspar = 0; + if (input->port->dev->link[input->port->lnr].info->ts_quirks + & TS_QUIRK_SERIAL) + par = 0; else - sony_tspar = 1; - - if (demod_attach_cxd28xx(input, sony_tspar, sony_osc24) < 0) + par = 1; + if (demod_attach_cxd28xx(input, par, osc24) < 0) return -ENODEV; - if (tuner_attach_tda18212(input, port->type) < 0) + if (tuner_attach_tda18212(input, port->type) < 0) { + if (dvb->fe2) + dvb_frontend_detach(dvb->fe2); + if (dvb->fe) + dvb_frontend_detach(dvb->fe); return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; } break; - case DDB_TUNER_XO2_DVBC2T2I_SONY: - case DDB_TUNER_XO2_DVBCT2_SONY: - case DDB_TUNER_XO2_DVBC2T2_SONY: - case DDB_TUNER_XO2_ISDBT_SONY: - if (port->type == DDB_TUNER_XO2_DVBC2T2I_SONY) - sony_osc24 = 1; - - if (demod_attach_cxd28xx(input, 0, sony_osc24) < 0) + case DDB_TUNER_DVBC2T2I_SONY: + osc24 = 1; + /* fall-through */ + case DDB_TUNER_DVBCT2_SONY: + case DDB_TUNER_DVBC2T2_SONY: + case DDB_TUNER_ISDBT_SONY: + if (demod_attach_cxd28xx(input, 0, osc24) < 0) return -ENODEV; - if (tuner_attach_tda18212(input, port->type) < 0) + if (tuner_attach_tda18212(input, port->type) < 0) { + if (dvb->fe2) + dvb_frontend_detach(dvb->fe2); + if (dvb->fe) + dvb_frontend_detach(dvb->fe); return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; } break; + default: + return 0; + } + dvb->attached = 0x30; + + if (dvb->fe) { + if (dvb_register_frontend(adap, dvb->fe) < 0) + return -ENODEV; + + if (dvb->fe2) { + if (dvb_register_frontend(adap, dvb->fe2) < 0) + return -ENODEV; + dvb->fe2->tuner_priv = dvb->fe->tuner_priv; + memcpy(&dvb->fe2->ops.tuner_ops, + &dvb->fe->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + } } - input->attached = 5; + dvb->attached = 0x31; return 0; } -/****************************************************************************/ -/****************************************************************************/ +static int port_has_encti(struct ddb_port *port) +{ + struct device *dev = port->dev->dev; + u8 val; + int ret = i2c_read_reg(&port->i2c->adap, 0x20, 0, &val); -static ssize_t ts_write(struct file *file, const __user char *buf, - size_t count, loff_t *ppos) + if (!ret) + dev_info(dev, "[0x20]=0x%02x\n", val); + return ret ? 0 : 1; +} + +static int port_has_cxd(struct ddb_port *port, u8 *type) { - struct dvb_device *dvbdev = file->private_data; - struct ddb_output *output = dvbdev->priv; - size_t left = count; - int stat; + u8 val; + u8 probe[4] = { 0xe0, 0x00, 0x00, 0x00 }, data[4]; + struct i2c_msg msgs[2] = {{ .addr = 0x40, .flags = 0, + .buf = probe, .len = 4 }, + { .addr = 0x40, .flags = I2C_M_RD, + .buf = data, .len = 4 } }; + val = i2c_transfer(&port->i2c->adap, msgs, 2); + if (val != 2) + return 0; - while (left) { - if (ddb_output_free(output) < 188) { - if (file->f_flags & O_NONBLOCK) - break; - if (wait_event_interruptible( - output->wq, ddb_output_free(output) >= 188) < 0) - break; - } - stat = ddb_output_write(output, buf, left); - if (stat < 0) - break; - buf += stat; - left -= stat; + if (data[0] == 0x02 && data[1] == 0x2b && data[3] == 0x43) + *type = 2; + else + *type = 1; + return 1; +} + +static int port_has_xo2(struct ddb_port *port, u8 *type, u8 *id) +{ + u8 probe[1] = { 0x00 }, data[4]; + + if (i2c_io(&port->i2c->adap, 0x10, probe, 1, data, 4)) + return 0; + if (data[0] == 'D' && data[1] == 'F') { + *id = data[2]; + *type = 1; + return 1; } - return (left == count) ? -EAGAIN : (count - left); + if (data[0] == 'C' && data[1] == 'I') { + *id = data[2]; + *type = 2; + return 1; + } + return 0; } -static ssize_t ts_read(struct file *file, __user char *buf, - size_t count, loff_t *ppos) +static int port_has_stv0900(struct ddb_port *port) { - struct dvb_device *dvbdev = file->private_data; - struct ddb_output *output = dvbdev->priv; - struct ddb_input *input = output->port->input[0]; - int left, read; + u8 val; - count -= count % 188; - left = count; - while (left) { - if (ddb_input_avail(input) < 188) { - if (file->f_flags & O_NONBLOCK) - break; - if (wait_event_interruptible( - input->wq, ddb_input_avail(input) >= 188) < 0) - break; - } - read = ddb_input_read(input, buf, left); - if (read < 0) - return read; - left -= read; - buf += read; + if (i2c_read_reg16(&port->i2c->adap, 0x69, 0xf100, &val) < 0) + return 0; + return 1; +} + +static int port_has_stv0900_aa(struct ddb_port *port, u8 *id) +{ + if (i2c_read_reg16(&port->i2c->adap, 0x68, 0xf100, id) < 0) + return 0; + return 1; +} + +static int port_has_drxks(struct ddb_port *port) +{ + u8 val; + + if (i2c_read(&port->i2c->adap, 0x29, &val) < 0) + return 0; + if (i2c_read(&port->i2c->adap, 0x2a, &val) < 0) + return 0; + return 1; +} + +static int port_has_stv0367(struct ddb_port *port) +{ + u8 val; + + if (i2c_read_reg16(&port->i2c->adap, 0x1e, 0xf000, &val) < 0) + return 0; + if (val != 0x60) + return 0; + if (i2c_read_reg16(&port->i2c->adap, 0x1f, 0xf000, &val) < 0) + return 0; + if (val != 0x60) + return 0; + return 1; +} + +static int init_xo2(struct ddb_port *port) +{ + struct i2c_adapter *i2c = &port->i2c->adap; + struct ddb *dev = port->dev; + u8 val, data[2]; + int res; + + res = i2c_read_regs(i2c, 0x10, 0x04, data, 2); + if (res < 0) + return res; + + if (data[0] != 0x01) { + dev_info(dev->dev, "Port %d: invalid XO2\n", port->nr); + return -1; } - return (left == count) ? -EAGAIN : (count - left); + + i2c_read_reg(i2c, 0x10, 0x08, &val); + if (val != 0) { + i2c_write_reg(i2c, 0x10, 0x08, 0x00); + msleep(100); + } + /* Enable tuner power, disable pll, reset demods */ + i2c_write_reg(i2c, 0x10, 0x08, 0x04); + usleep_range(2000, 3000); + /* Release demod resets */ + i2c_write_reg(i2c, 0x10, 0x08, 0x07); + + /* speed: 0=55,1=75,2=90,3=104 MBit/s */ + i2c_write_reg(i2c, 0x10, 0x09, xo2_speed); + + if (dev->link[port->lnr].info->con_clock) { + dev_info(dev->dev, "Setting continuous clock for XO2\n"); + i2c_write_reg(i2c, 0x10, 0x0a, 0x03); + i2c_write_reg(i2c, 0x10, 0x0b, 0x03); + } else { + i2c_write_reg(i2c, 0x10, 0x0a, 0x01); + i2c_write_reg(i2c, 0x10, 0x0b, 0x01); + } + + usleep_range(2000, 3000); + /* Start XO2 PLL */ + i2c_write_reg(i2c, 0x10, 0x08, 0x87); + + return 0; } -static unsigned int ts_poll(struct file *file, poll_table *wait) +static int init_xo2_ci(struct ddb_port *port) { - /* - struct dvb_device *dvbdev = file->private_data; - struct ddb_output *output = dvbdev->priv; - struct ddb_input *input = output->port->input[0]; - */ - unsigned int mask = 0; + struct i2c_adapter *i2c = &port->i2c->adap; + struct ddb *dev = port->dev; + u8 val, data[2]; + int res; -#if 0 - if (data_avail_to_read) - mask |= POLLIN | POLLRDNORM; - if (data_avail_to_write) - mask |= POLLOUT | POLLWRNORM; + res = i2c_read_regs(i2c, 0x10, 0x04, data, 2); + if (res < 0) + return res; - poll_wait(file, &read_queue, wait); - poll_wait(file, &write_queue, wait); -#endif - return mask; + if (data[0] > 1) { + dev_info(dev->dev, "Port %d: invalid XO2 CI %02x\n", + port->nr, data[0]); + return -1; + } + dev_info(dev->dev, "Port %d: DuoFlex CI %u.%u\n", + port->nr, data[0], data[1]); + + i2c_read_reg(i2c, 0x10, 0x08, &val); + if (val != 0) { + i2c_write_reg(i2c, 0x10, 0x08, 0x00); + msleep(100); + } + /* Enable both CI */ + i2c_write_reg(i2c, 0x10, 0x08, 3); + usleep_range(2000, 3000); + + + /* speed: 0=55,1=75,2=90,3=104 MBit/s */ + i2c_write_reg(i2c, 0x10, 0x09, 1); + + i2c_write_reg(i2c, 0x10, 0x08, 0x83); + usleep_range(2000, 3000); + + if (dev->link[port->lnr].info->con_clock) { + dev_info(dev->dev, "Setting continuous clock for DuoFlex CI\n"); + i2c_write_reg(i2c, 0x10, 0x0a, 0x03); + i2c_write_reg(i2c, 0x10, 0x0b, 0x03); + } else { + i2c_write_reg(i2c, 0x10, 0x0a, 0x01); + i2c_write_reg(i2c, 0x10, 0x0b, 0x01); + } + return 0; } -static const struct file_operations ci_fops = { - .owner = THIS_MODULE, - .read = ts_read, - .write = ts_write, - .open = dvb_generic_open, - .release = dvb_generic_release, - .poll = ts_poll, +static int port_has_cxd28xx(struct ddb_port *port, u8 *id) +{ + struct i2c_adapter *i2c = &port->i2c->adap; + int status; + + status = i2c_write_reg(&port->i2c->adap, 0x6e, 0, 0); + if (status) + return 0; + status = i2c_read_reg(i2c, 0x6e, 0xfd, id); + if (status) + return 0; + return 1; +} + +static char *xo2names[] = { + "DUAL DVB-S2", "DUAL DVB-C/T/T2", + "DUAL DVB-ISDBT", "DUAL DVB-C/C2/T/T2", + "DUAL ATSC", "DUAL DVB-C/C2/T/T2,ISDB-T", + "", "" }; -static struct dvb_device dvbdev_ci = { - .readers = -1, - .writers = -1, - .users = -1, - .fops = &ci_fops, +static char *xo2types[] = { + "DVBS_ST", "DVBCT2_SONY", + "ISDBT_SONY", "DVBC2T2_SONY", + "ATSC_ST", "DVBC2T2I_SONY" }; +static void ddb_port_probe(struct ddb_port *port) +{ + struct ddb *dev = port->dev; + u32 l = port->lnr; + u8 id, type; + + port->name = "NO MODULE"; + port->type_name = "NONE"; + port->class = DDB_PORT_NONE; + + /* Handle missing ports and ports without I2C */ + + if (port->nr == ts_loop) { + port->name = "TS LOOP"; + port->class = DDB_PORT_LOOP; + return; + } + + if (port->nr == 1 && dev->link[l].info->type == DDB_OCTOPUS_CI && + dev->link[l].info->i2c_mask == 1) { + port->name = "NO TAB"; + port->class = DDB_PORT_NONE; + return; + } + + if (dev->link[l].info->type == DDB_OCTOPUS_MAX) { + port->name = "DUAL DVB-S2 MAX"; + port->type_name = "MXL5XX"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_MXL5XX; + if (port->i2c) + ddbwritel(dev, I2C_SPEED_400, + port->i2c->regs + I2C_TIMING); + return; + } + + if (port->nr > 1 && dev->link[l].info->type == DDB_OCTOPUS_CI) { + port->name = "CI internal"; + port->type_name = "INTERNAL"; + port->class = DDB_PORT_CI; + port->type = DDB_CI_INTERNAL; + } + + if (!port->i2c) + return; + + /* Probe ports with I2C */ + + if (port_has_cxd(port, &id)) { + if (id == 1) { + port->name = "CI"; + port->type_name = "CXD2099"; + port->class = DDB_PORT_CI; + port->type = DDB_CI_EXTERNAL_SONY; + ddbwritel(dev, I2C_SPEED_400, + port->i2c->regs + I2C_TIMING); + } else { + dev_info(dev->dev, "Port %d: Uninitialized DuoFlex\n", + port->nr); + return; + } + } else if (port_has_xo2(port, &type, &id)) { + ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + /*dev_info(dev->dev, "XO2 ID %02x\n", id);*/ + if (type == 2) { + port->name = "DuoFlex CI"; + port->class = DDB_PORT_CI; + port->type = DDB_CI_EXTERNAL_XO2; + port->type_name = "CI_XO2"; + init_xo2_ci(port); + return; + } + id >>= 2; + if (id > 5) { + port->name = "unknown XO2 DuoFlex"; + port->type_name = "UNKNOWN"; + } else { + port->name = xo2names[id]; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_XO2 + id; + port->type_name = xo2types[id]; + init_xo2(port); + } + } else if (port_has_cxd28xx(port, &id)) { + switch (id) { + case 0xa4: + port->name = "DUAL DVB-C2T2 CXD2843"; + port->type = DDB_TUNER_DVBC2T2_SONY_P; + port->type_name = "DVBC2T2_SONY"; + break; + case 0xb1: + port->name = "DUAL DVB-CT2 CXD2837"; + port->type = DDB_TUNER_DVBCT2_SONY_P; + port->type_name = "DVBCT2_SONY"; + break; + case 0xb0: + port->name = "DUAL ISDB-T CXD2838"; + port->type = DDB_TUNER_ISDBT_SONY_P; + port->type_name = "ISDBT_SONY"; + break; + case 0xc1: + port->name = "DUAL DVB-C2T2 ISDB-T CXD2854"; + port->type = DDB_TUNER_DVBC2T2I_SONY_P; + port->type_name = "DVBC2T2I_ISDBT_SONY"; + break; + default: + return; + } + port->class = DDB_PORT_TUNER; + ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + } else if (port_has_stv0900(port)) { + port->name = "DUAL DVB-S2"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBS_ST; + port->type_name = "DVBS_ST"; + ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + } else if (port_has_stv0900_aa(port, &id)) { + port->name = "DUAL DVB-S2"; + port->class = DDB_PORT_TUNER; + if (id == 0x51) { + if (port->nr == 0 && + dev->link[l].info->ts_quirks & TS_QUIRK_REVERSED) + port->type = DDB_TUNER_DVBS_STV0910_PR; + else + port->type = DDB_TUNER_DVBS_STV0910_P; + port->type_name = "DVBS_ST_0910"; + } else { + port->type = DDB_TUNER_DVBS_ST_AA; + port->type_name = "DVBS_ST_AA"; + } + ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + } else if (port_has_drxks(port)) { + port->name = "DUAL DVB-C/T"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBCT_TR; + port->type_name = "DVBCT_TR"; + ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + } else if (port_has_stv0367(port)) { + port->name = "DUAL DVB-C/T"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBCT_ST; + port->type_name = "DVBCT_ST"; + ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + } else if (port_has_encti(port)) { + port->name = "ENCTI"; + port->class = DDB_PORT_LOOP; + } +} + + /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ -static void input_tasklet(unsigned long data) +static int wait_ci_ready(struct ddb_ci *ci) { - struct ddb_input *input = (struct ddb_input *) data; - struct ddb *dev = input->port->dev; + u32 count = 10; + + ndelay(500); + do { + if (ddbreadl(ci->port->dev, + CI_CONTROL(ci->nr)) & CI_READY) + break; + usleep_range(1, 2); + if ((--count) == 0) + return -1; + } while (1); + return 0; +} + +static int read_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, int address) +{ + struct ddb_ci *ci = ca->data; + u32 val, off = (address >> 1) & (CI_BUFFER_SIZE - 1); + + if (address > CI_BUFFER_SIZE) + return -1; + ddbwritel(ci->port->dev, CI_READ_CMD | (1 << 16) | address, + CI_DO_READ_ATTRIBUTES(ci->nr)); + wait_ci_ready(ci); + val = 0xff & ddbreadl(ci->port->dev, CI_BUFFER(ci->nr) + off); + return val; +} + +static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, + int address, u8 value) +{ + struct ddb_ci *ci = ca->data; + + ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address, + CI_DO_ATTRIBUTE_RW(ci->nr)); + wait_ci_ready(ci); + return 0; +} - spin_lock(&input->lock); - if (!input->running) { - spin_unlock(&input->lock); +static int read_cam_control(struct dvb_ca_en50221 *ca, + int slot, u8 address) +{ + u32 count = 100; + struct ddb_ci *ci = ca->data; + u32 res; + + ddbwritel(ci->port->dev, CI_READ_CMD | address, + CI_DO_IO_RW(ci->nr)); + ndelay(500); + do { + res = ddbreadl(ci->port->dev, CI_READDATA(ci->nr)); + if (res & CI_READY) + break; + usleep_range(1, 2); + if ((--count) == 0) + return -1; + } while (1); + return 0xff & res; +} + +static int write_cam_control(struct dvb_ca_en50221 *ca, int slot, + u8 address, u8 value) +{ + struct ddb_ci *ci = ca->data; + + ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address, + CI_DO_IO_RW(ci->nr)); + wait_ci_ready(ci); + return 0; +} + +static int slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct ddb_ci *ci = ca->data; + + ddbwritel(ci->port->dev, CI_POWER_ON, + CI_CONTROL(ci->nr)); + msleep(100); + ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM, + CI_CONTROL(ci->nr)); + ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM, + CI_CONTROL(ci->nr)); + udelay(20); + ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON, + CI_CONTROL(ci->nr)); + return 0; +} + +static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + struct ddb_ci *ci = ca->data; + + ddbwritel(ci->port->dev, 0, CI_CONTROL(ci->nr)); + msleep(300); + return 0; +} + +static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct ddb_ci *ci = ca->data; + u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr)); + + ddbwritel(ci->port->dev, val | CI_BYPASS_DISABLE, + CI_CONTROL(ci->nr)); + return 0; +} + +static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct ddb_ci *ci = ca->data; + u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr)); + int stat = 0; + + if (val & CI_CAM_DETECT) + stat |= DVB_CA_EN50221_POLL_CAM_PRESENT; + if (val & CI_CAM_READY) + stat |= DVB_CA_EN50221_POLL_CAM_READY; + return stat; +} + +static struct dvb_ca_en50221 en_templ = { + .read_attribute_mem = read_attribute_mem, + .write_attribute_mem = write_attribute_mem, + .read_cam_control = read_cam_control, + .write_cam_control = write_cam_control, + .slot_reset = slot_reset, + .slot_shutdown = slot_shutdown, + .slot_ts_enable = slot_ts_enable, + .poll_slot_status = poll_slot_status, +}; + +static void ci_attach(struct ddb_port *port) +{ + struct ddb_ci *ci = NULL; + + ci = kzalloc(sizeof(*ci), GFP_KERNEL); + if (!ci) return; - } - input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); + memcpy(&ci->en, &en_templ, sizeof(en_templ)); + ci->en.data = ci; + port->en = &ci->en; + ci->port = port; + ci->nr = port->nr - 2; +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ - if (input->port->class == DDB_PORT_TUNER) { - if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr))) - dev_err(&dev->pdev->dev, "Overflow input %d\n", input->nr); - while (input->cbuf != ((input->stat >> 11) & 0x1f) - || (4 & safe_ddbreadl(dev, DMA_BUFFER_CONTROL(input->nr)))) { - dvb_dmx_swfilter_packets(&input->demux, - input->vbuf[input->cbuf], - input->dma_buf_size / 188); +static int write_creg(struct ddb_ci *ci, u8 data, u8 mask) +{ + struct i2c_adapter *i2c = &ci->port->i2c->adap; + u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; - input->cbuf = (input->cbuf + 1) % input->dma_buf_num; - ddbwritel((input->cbuf << 11), - DMA_BUFFER_ACK(input->nr)); - input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); - } - } - if (input->port->class == DDB_PORT_CI) - wake_up(&input->wq); - spin_unlock(&input->lock); + ci->port->creg = (ci->port->creg & ~mask) | data; + return i2c_write_reg(i2c, adr, 0x02, ci->port->creg); } -static void output_tasklet(unsigned long data) +static int read_attribute_mem_xo2(struct dvb_ca_en50221 *ca, + int slot, int address) { - struct ddb_output *output = (struct ddb_output *) data; - struct ddb *dev = output->port->dev; + struct ddb_ci *ci = ca->data; + struct i2c_adapter *i2c = &ci->port->i2c->adap; + u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; + int res; + u8 val; - spin_lock(&output->lock); - if (!output->running) { - spin_unlock(&output->lock); + res = i2c_read_reg16(i2c, adr, 0x8000 | address, &val); + return res ? res : val; +} + +static int write_attribute_mem_xo2(struct dvb_ca_en50221 *ca, int slot, + int address, u8 value) +{ + struct ddb_ci *ci = ca->data; + struct i2c_adapter *i2c = &ci->port->i2c->adap; + u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; + + return i2c_write_reg16(i2c, adr, 0x8000 | address, value); +} + +static int read_cam_control_xo2(struct dvb_ca_en50221 *ca, + int slot, u8 address) +{ + struct ddb_ci *ci = ca->data; + struct i2c_adapter *i2c = &ci->port->i2c->adap; + u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; + u8 val; + int res; + + res = i2c_read_reg(i2c, adr, 0x20 | (address & 3), &val); + return res ? res : val; +} + +static int write_cam_control_xo2(struct dvb_ca_en50221 *ca, int slot, + u8 address, u8 value) +{ + struct ddb_ci *ci = ca->data; + struct i2c_adapter *i2c = &ci->port->i2c->adap; + u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; + + return i2c_write_reg(i2c, adr, 0x20 | (address & 3), value); +} + +static int slot_reset_xo2(struct dvb_ca_en50221 *ca, int slot) +{ + struct ddb_ci *ci = ca->data; + + dev_dbg(ci->port->dev->dev, "%s\n", __func__); + write_creg(ci, 0x01, 0x01); + write_creg(ci, 0x04, 0x04); + msleep(20); + write_creg(ci, 0x02, 0x02); + write_creg(ci, 0x00, 0x04); + write_creg(ci, 0x18, 0x18); + return 0; +} + +static int slot_shutdown_xo2(struct dvb_ca_en50221 *ca, int slot) +{ + struct ddb_ci *ci = ca->data; + + dev_dbg(ci->port->dev->dev, "%s\n", __func__); + write_creg(ci, 0x10, 0xff); + write_creg(ci, 0x08, 0x08); + return 0; +} + +static int slot_ts_enable_xo2(struct dvb_ca_en50221 *ca, int slot) +{ + struct ddb_ci *ci = ca->data; + + dev_info(ci->port->dev->dev, "%s\n", __func__); + write_creg(ci, 0x00, 0x10); + return 0; +} + +static int poll_slot_status_xo2(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct ddb_ci *ci = ca->data; + struct i2c_adapter *i2c = &ci->port->i2c->adap; + u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; + u8 val = 0; + int stat = 0; + + i2c_read_reg(i2c, adr, 0x01, &val); + + if (val & 2) + stat |= DVB_CA_EN50221_POLL_CAM_PRESENT; + if (val & 1) + stat |= DVB_CA_EN50221_POLL_CAM_READY; + return stat; +} + +static struct dvb_ca_en50221 en_xo2_templ = { + .read_attribute_mem = read_attribute_mem_xo2, + .write_attribute_mem = write_attribute_mem_xo2, + .read_cam_control = read_cam_control_xo2, + .write_cam_control = write_cam_control_xo2, + .slot_reset = slot_reset_xo2, + .slot_shutdown = slot_shutdown_xo2, + .slot_ts_enable = slot_ts_enable_xo2, + .poll_slot_status = poll_slot_status_xo2, +}; + +static void ci_xo2_attach(struct ddb_port *port) +{ + struct ddb_ci *ci; + + ci = kzalloc(sizeof(*ci), GFP_KERNEL); + if (!ci) return; - } - output->stat = ddbreadl(DMA_BUFFER_CURRENT(output->nr + 8)); - wake_up(&output->wq); - spin_unlock(&output->lock); + memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ)); + ci->en.data = ci; + port->en = &ci->en; + ci->port = port; + ci->nr = port->nr - 2; + ci->port->creg = 0; + write_creg(ci, 0x10, 0xff); + write_creg(ci, 0x08, 0x08); } +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ static struct cxd2099_cfg cxd_cfg = { - .bitrate = 62000, + .bitrate = 72000, .adr = 0x40, .polarity = 1, .clock_mode = 1, @@ -1310,33 +2216,36 @@ static struct cxd2099_cfg cxd_cfg = { static int ddb_ci_attach(struct ddb_port *port) { - int ret; + switch (port->type) { + case DDB_CI_EXTERNAL_SONY: + cxd_cfg.bitrate = ci_bitrate; + port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); + if (!port->en) + return -ENODEV; + dvb_ca_en50221_init(port->dvb[0].adap, + port->en, 0, 1); + break; - ret = dvb_register_adapter(&port->output->adap, - "DDBridge", - THIS_MODULE, - &port->dev->pdev->dev, - adapter_nr); - if (ret < 0) - return ret; - port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); - if (!port->en) { - dvb_unregister_adapter(&port->output->adap); - return -ENODEV; + case DDB_CI_EXTERNAL_XO2: + case DDB_CI_EXTERNAL_XO2_B: + ci_xo2_attach(port); + if (!port->en) + return -ENODEV; + dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1); + break; + + case DDB_CI_INTERNAL: + ci_attach(port); + if (!port->en) + return -ENODEV; + dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1); + break; } - ddb_input_start(port->input[0]); - ddb_output_start(port->output); - dvb_ca_en50221_init(&port->output->adap, - port->en, 0, 1); - ret = dvb_register_device(&port->output->adap, &port->output->dev, - &dvbdev_ci, (void *) port->output, - DVB_DEVICE_SEC, 0); - return ret; + return 0; } static int ddb_port_attach(struct ddb_port *port) { - struct device *dev = &port->dev->pdev->dev; int ret = 0; switch (port->class) { @@ -1345,371 +2254,429 @@ static int ddb_port_attach(struct ddb_port *port) if (ret < 0) break; ret = dvb_input_attach(port->input[1]); + if (ret < 0) + break; + port->input[0]->redi = port->input[0]; + port->input[1]->redi = port->input[1]; break; case DDB_PORT_CI: ret = ddb_ci_attach(port); + if (ret < 0) + break; + /* fall-through */ + case DDB_PORT_LOOP: + ret = dvb_register_device(port->dvb[0].adap, + &port->dvb[0].dev, + &dvbdev_ci, (void *) port->output, + DVB_DEVICE_SEC, 0); break; default: break; } if (ret < 0) - dev_err(dev, "port_attach on port %d failed\n", port->nr); + dev_err(port->dev->dev, "port_attach on port %d failed\n", + port->nr); return ret; } -static int ddb_ports_attach(struct ddb *dev) +int ddb_ports_attach(struct ddb *dev) { int i, ret = 0; struct ddb_port *port; - for (i = 0; i < dev->info->port_num; i++) { + if (dev->port_num) { + ret = dvb_register_adapters(dev); + if (ret < 0) { + dev_err(dev->dev, "Registering adapters failed. Check DVB_MAX_ADAPTERS in config.\n"); + return ret; + } + } + for (i = 0; i < dev->port_num; i++) { port = &dev->port[i]; ret = ddb_port_attach(port); - if (ret < 0) - break; } return ret; } -static void ddb_ports_detach(struct ddb *dev) +void ddb_ports_detach(struct ddb *dev) { int i; struct ddb_port *port; - for (i = 0; i < dev->info->port_num; i++) { + for (i = 0; i < dev->port_num; i++) { port = &dev->port[i]; + switch (port->class) { case DDB_PORT_TUNER: dvb_input_detach(port->input[0]); dvb_input_detach(port->input[1]); break; case DDB_PORT_CI: - dvb_unregister_device(port->output->dev); + case DDB_PORT_LOOP: + if (port->dvb[0].dev) + dvb_unregister_device(port->dvb[0].dev); if (port->en) { - ddb_input_stop(port->input[0]); - ddb_output_stop(port->output); dvb_ca_en50221_release(port->en); kfree(port->en); port->en = NULL; - dvb_unregister_adapter(&port->output->adap); } break; } } + dvb_unregister_adapters(dev); } -/****************************************************************************/ -/****************************************************************************/ -static int init_xo2(struct ddb_port *port) +/* Copy input DMA pointers to output DMA and ACK. */ + +static void input_write_output(struct ddb_input *input, + struct ddb_output *output) { - struct i2c_adapter *i2c = &port->i2c->adap; - struct device *dev = &port->dev->pdev->dev; - u8 val, data[2]; - int res; + ddbwritel(output->port->dev, + input->dma->stat, DMA_BUFFER_ACK(output->dma)); + output->dma->cbuf = (input->dma->stat >> 11) & 0x1f; + output->dma->coff = (input->dma->stat & 0x7ff) << 7; +} - res = i2c_read_regs(i2c, 0x10, 0x04, data, 2); - if (res < 0) - return res; +static void output_ack_input(struct ddb_output *output, + struct ddb_input *input) +{ + ddbwritel(input->port->dev, + output->dma->stat, DMA_BUFFER_ACK(input->dma)); +} - if (data[0] != 0x01) { - dev_info(dev, "Port %d: invalid XO2\n", port->nr); - return -1; +static void input_write_dvb(struct ddb_input *input, + struct ddb_input *input2) +{ + struct ddb_dvb *dvb = &input2->port->dvb[input2->nr & 1]; + struct ddb_dma *dma, *dma2; + struct ddb *dev = input->port->dev; + int ack = 1; + + dma = dma2 = input->dma; + /* if there also is an output connected, do not ACK. + * input_write_output will ACK. + */ + if (input->redo) { + dma2 = input->redo->dma; + ack = 0; + } + while (dma->cbuf != ((dma->stat >> 11) & 0x1f) + || (4 & dma->ctrl)) { + if (4 & dma->ctrl) { + /* dev_err(dev->dev, "Overflow dma %d\n", dma->nr); */ + ack = 1; + } + if (alt_dma) + dma_sync_single_for_cpu(dev->dev, dma2->pbuf[dma->cbuf], + dma2->size, DMA_FROM_DEVICE); + dvb_dmx_swfilter_packets(&dvb->demux, + dma2->vbuf[dma->cbuf], + dma2->size / 188); + dma->cbuf = (dma->cbuf + 1) % dma2->num; + if (ack) + ddbwritel(dev, (dma->cbuf << 11), + DMA_BUFFER_ACK(dma)); + dma->stat = safe_ddbreadl(dev, DMA_BUFFER_CURRENT(dma)); + dma->ctrl = safe_ddbreadl(dev, DMA_BUFFER_CONTROL(dma)); } +} - i2c_read_reg(i2c, 0x10, 0x08, &val); - if (val != 0) { - i2c_write_reg(i2c, 0x10, 0x08, 0x00); - msleep(100); +static void input_work(struct work_struct *work) +{ + struct ddb_dma *dma = container_of(work, struct ddb_dma, work); + struct ddb_input *input = (struct ddb_input *) dma->io; + struct ddb *dev = input->port->dev; + unsigned long flags; + + spin_lock_irqsave(&dma->lock, flags); + if (!dma->running) { + spin_unlock_irqrestore(&dma->lock, flags); + return; } - /* Enable tuner power, disable pll, reset demods */ - i2c_write_reg(i2c, 0x10, 0x08, 0x04); - usleep_range(2000, 3000); - /* Release demod resets */ - i2c_write_reg(i2c, 0x10, 0x08, 0x07); + dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma)); + dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma)); - /* speed: 0=55,1=75,2=90,3=104 MBit/s */ - i2c_write_reg(i2c, 0x10, 0x09, - ((xo2_speed >= 0 && xo2_speed <= 3) ? xo2_speed : 2)); + if (input->redi) + input_write_dvb(input, input->redi); + if (input->redo) + input_write_output(input, input->redo); + wake_up(&dma->wq); + spin_unlock_irqrestore(&dma->lock, flags); +} - i2c_write_reg(i2c, 0x10, 0x0a, 0x01); - i2c_write_reg(i2c, 0x10, 0x0b, 0x01); +static void input_handler(unsigned long data) +{ + struct ddb_input *input = (struct ddb_input *) data; + struct ddb_dma *dma = input->dma; - usleep_range(2000, 3000); - /* Start XO2 PLL */ - i2c_write_reg(i2c, 0x10, 0x08, 0x87); - return 0; + /* If there is no input connected, input_tasklet() will + * just copy pointers and ACK. So, there is no need to go + * through the tasklet scheduler. + */ + if (input->redi) + queue_work(ddb_wq, &dma->work); + else + input_work(&dma->work); } -static int port_has_xo2(struct ddb_port *port, u8 *type, u8 *id) +static void output_handler(unsigned long data) { - u8 probe[1] = { 0x00 }, data[4]; - - *type = DDB_XO2_TYPE_NONE; + struct ddb_output *output = (struct ddb_output *) data; + struct ddb_dma *dma = output->dma; + struct ddb *dev = output->port->dev; - if (i2c_io(&port->i2c->adap, 0x10, probe, 1, data, 4)) - return 0; - if (data[0] == 'D' && data[1] == 'F') { - *id = data[2]; - *type = DDB_XO2_TYPE_DUOFLEX; - return 1; - } - if (data[0] == 'C' && data[1] == 'I') { - *id = data[2]; - *type = DDB_XO2_TYPE_CI; - return 1; + spin_lock(&dma->lock); + if (!dma->running) { + spin_unlock(&dma->lock); + return; } - return 0; + dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma)); + dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma)); + if (output->redi) + output_ack_input(output, output->redi); + wake_up(&dma->wq); + spin_unlock(&dma->lock); } /****************************************************************************/ /****************************************************************************/ -static int port_has_ci(struct ddb_port *port) +static const struct ddb_regmap *io_regmap(struct ddb_io *io, int link) { - u8 val; - return i2c_read_reg(&port->i2c->adap, 0x40, 0, &val) ? 0 : 1; -} + const struct ddb_info *info; -static int port_has_stv0900(struct ddb_port *port) -{ - u8 val; - if (i2c_read_reg16(&port->i2c->adap, 0x69, 0xf100, &val) < 0) - return 0; - return 1; -} + if (link) + info = io->port->dev->link[io->port->lnr].info; + else + info = io->port->dev->link[0].info; -static int port_has_stv0900_aa(struct ddb_port *port) -{ - u8 val; - if (i2c_read_reg16(&port->i2c->adap, 0x68, 0xf100, &val) < 0) - return 0; - return 1; -} + if (!info) + return NULL; -static int port_has_drxks(struct ddb_port *port) -{ - u8 val; - if (i2c_read(&port->i2c->adap, 0x29, &val) < 0) - return 0; - if (i2c_read(&port->i2c->adap, 0x2a, &val) < 0) - return 0; - return 1; + return info->regmap; } -static int port_has_stv0367(struct ddb_port *port) +static void ddb_dma_init(struct ddb_io *io, int nr, int out) { - u8 val; - if (i2c_read_reg16(&port->i2c->adap, 0x1e, 0xf000, &val) < 0) - return 0; - if (val != 0x60) - return 0; - if (i2c_read_reg16(&port->i2c->adap, 0x1f, 0xf000, &val) < 0) - return 0; - if (val != 0x60) - return 0; - return 1; + struct ddb_dma *dma; + const struct ddb_regmap *rm = io_regmap(io, 0); + + dma = out ? &io->port->dev->odma[nr] : &io->port->dev->idma[nr]; + io->dma = dma; + dma->io = io; + + spin_lock_init(&dma->lock); + init_waitqueue_head(&dma->wq); + if (out) { + dma->regs = rm->odma->base + rm->odma->size * nr; + dma->bufregs = rm->odma_buf->base + rm->odma_buf->size * nr; + dma->num = OUTPUT_DMA_BUFS; + dma->size = OUTPUT_DMA_SIZE; + dma->div = OUTPUT_DMA_IRQ_DIV; + } else { + INIT_WORK(&dma->work, input_work); + dma->regs = rm->idma->base + rm->idma->size * nr; + dma->bufregs = rm->idma_buf->base + rm->idma_buf->size * nr; + dma->num = INPUT_DMA_BUFS; + dma->size = INPUT_DMA_SIZE; + dma->div = INPUT_DMA_IRQ_DIV; + } + ddbwritel(io->port->dev, 0, DMA_BUFFER_ACK(dma)); + dev_dbg(io->port->dev->dev, "init link %u, io %u, dma %u, dmaregs %08x bufregs %08x\n", + io->port->lnr, io->nr, nr, dma->regs, dma->bufregs); } -static int port_has_cxd28xx(struct ddb_port *port, u8 *id) +static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr) { - struct i2c_adapter *i2c = &port->i2c->adap; - int status; + struct ddb *dev = port->dev; + struct ddb_input *input = &dev->input[anr]; + const struct ddb_regmap *rm; - status = i2c_write_reg(&port->i2c->adap, 0x6e, 0, 0); - if (status) - return 0; - status = i2c_read_reg(i2c, 0x6e, 0xfd, id); - if (status) - return 0; - return 1; + port->input[pnr] = input; + input->nr = nr; + input->port = port; + rm = io_regmap(input, 1); + input->regs = DDB_LINK_TAG(port->lnr) | + (rm->input->base + rm->input->size * nr); + dev_dbg(dev->dev, "init link %u, input %u, regs %08x\n", + port->lnr, nr, input->regs); + + if (dev->has_dma) { + const struct ddb_regmap *rm0 = io_regmap(input, 0); + u32 base = rm0->irq_base_idma; + u32 dma_nr = nr; + + if (port->lnr) + dma_nr += 32 + (port->lnr - 1) * 8; + + dev_dbg(dev->dev, "init link %u, input %u, handler %u\n", + port->lnr, nr, dma_nr + base); + + dev->handler[0][dma_nr + base] = input_handler; + dev->handler_data[0][dma_nr + base] = (unsigned long) input; + ddb_dma_init(input, dma_nr, 0); + } } -static void ddb_port_probe(struct ddb_port *port) +static void ddb_output_init(struct ddb_port *port, int nr) { struct ddb *dev = port->dev; - char *modname = "NO MODULE"; - u8 xo2_type, xo2_id, cxd_id; + struct ddb_output *output = &dev->output[nr]; + const struct ddb_regmap *rm; - port->class = DDB_PORT_NONE; + port->output = output; + output->nr = nr; + output->port = port; + rm = io_regmap(output, 1); + output->regs = DDB_LINK_TAG(port->lnr) | + (rm->output->base + rm->output->size * nr); - if (port_has_ci(port)) { - modname = "CI"; - port->class = DDB_PORT_CI; - ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); - } else if (port_has_xo2(port, &xo2_type, &xo2_id)) { - dev_dbg(&dev->pdev->dev, "Port %d (TAB %d): XO2 type: %d, id: %d\n", - port->nr, port->nr+1, xo2_type, xo2_id); + dev_dbg(dev->dev, "init link %u, output %u, regs %08x\n", + port->lnr, nr, output->regs); - ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + if (dev->has_dma) { + const struct ddb_regmap *rm0 = io_regmap(output, 0); + u32 base = rm0->irq_base_odma; - switch (xo2_type) { - case DDB_XO2_TYPE_DUOFLEX: - init_xo2(port); - switch (xo2_id >> 2) { - case 0: - modname = "DUAL DVB-S2 (unsupported)"; - port->class = DDB_PORT_NONE; - port->type = DDB_TUNER_XO2_DVBS_STV0910; - break; - case 1: - modname = "DUAL DVB-C/T/T2"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_XO2_DVBCT2_SONY; - break; - case 2: - modname = "DUAL DVB-ISDBT"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_XO2_ISDBT_SONY; - break; - case 3: - modname = "DUAL DVB-C/C2/T/T2"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_XO2_DVBC2T2_SONY; - break; - case 4: - modname = "DUAL ATSC (unsupported)"; - port->class = DDB_PORT_NONE; - port->type = DDB_TUNER_XO2_ATSC_ST; - break; - case 5: - modname = "DUAL DVB-C/C2/T/T2/ISDBT"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_XO2_DVBC2T2I_SONY; - break; - default: - modname = "Unknown XO2 DuoFlex module\n"; - break; - } - break; - case DDB_XO2_TYPE_CI: - dev_info(&dev->pdev->dev, "DuoFlex CI modules not supported\n"); - break; - default: - dev_info(&dev->pdev->dev, "Unknown XO2 DuoFlex module\n"); - break; - } - } else if (port_has_cxd28xx(port, &cxd_id)) { - switch (cxd_id) { - case 0xa4: - modname = "DUAL DVB-C2T2 CXD2843"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBC2T2_SONY_P; - break; - case 0xb1: - modname = "DUAL DVB-CT2 CXD2837"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBCT2_SONY_P; - break; - case 0xb0: - modname = "DUAL ISDB-T CXD2838"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_ISDBT_SONY_P; - break; - case 0xc1: - modname = "DUAL DVB-C2T2 ISDB-T CXD2854"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBC2T2I_SONY_P; - break; - default: - modname = "Unknown CXD28xx tuner"; - break; - } - ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); - } else if (port_has_stv0900(port)) { - modname = "DUAL DVB-S2"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBS_ST; - ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); - } else if (port_has_stv0900_aa(port)) { - modname = "DUAL DVB-S2"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBS_ST_AA; - ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); - } else if (port_has_drxks(port)) { - modname = "DUAL DVB-C/T"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBCT_TR; - ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); - } else if (port_has_stv0367(port)) { - modname = "DUAL DVB-C/T"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBCT_ST; - ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + dev->handler[0][nr + base] = output_handler; + dev->handler_data[0][nr + base] = (unsigned long) output; + ddb_dma_init(output, nr, 1); } - - dev_info(&dev->pdev->dev, "Port %d (TAB %d): %s\n", - port->nr, port->nr+1, modname); } -static void ddb_input_init(struct ddb_port *port, int nr) +static int ddb_port_match_i2c(struct ddb_port *port) { struct ddb *dev = port->dev; - struct ddb_input *input = &dev->input[nr]; + u32 i; - input->nr = nr; - input->port = port; - input->dma_buf_num = INPUT_DMA_BUFS; - input->dma_buf_size = INPUT_DMA_SIZE; - ddbwritel(0, TS_INPUT_CONTROL(nr)); - ddbwritel(2, TS_INPUT_CONTROL(nr)); - ddbwritel(0, TS_INPUT_CONTROL(nr)); - ddbwritel(0, DMA_BUFFER_ACK(nr)); - tasklet_init(&input->tasklet, input_tasklet, (unsigned long) input); - spin_lock_init(&input->lock); - init_waitqueue_head(&input->wq); + for (i = 0; i < dev->i2c_num; i++) { + if (dev->i2c[i].link == port->lnr && + dev->i2c[i].nr == port->nr) { + port->i2c = &dev->i2c[i]; + return 1; + } + } + return 0; } -static void ddb_output_init(struct ddb_port *port, int nr) +static int ddb_port_match_link_i2c(struct ddb_port *port) { struct ddb *dev = port->dev; - struct ddb_output *output = &dev->output[nr]; - output->nr = nr; - output->port = port; - output->dma_buf_num = OUTPUT_DMA_BUFS; - output->dma_buf_size = OUTPUT_DMA_SIZE; + u32 i; - ddbwritel(0, TS_OUTPUT_CONTROL(nr)); - ddbwritel(2, TS_OUTPUT_CONTROL(nr)); - ddbwritel(0, TS_OUTPUT_CONTROL(nr)); - tasklet_init(&output->tasklet, output_tasklet, (unsigned long) output); - init_waitqueue_head(&output->wq); + for (i = 0; i < dev->i2c_num; i++) { + if (dev->i2c[i].link == port->lnr) { + port->i2c = &dev->i2c[i]; + return 1; + } + } + return 0; } -static void ddb_ports_init(struct ddb *dev) +void ddb_ports_init(struct ddb *dev) { - int i; + u32 i, l, p; struct ddb_port *port; + const struct ddb_info *info; + const struct ddb_regmap *rm; + + for (p = l = 0; l < DDB_MAX_LINK; l++) { + info = dev->link[l].info; + if (!info) + continue; + rm = info->regmap; + if (!rm) + continue; + for (i = 0; i < info->port_num; i++, p++) { + port = &dev->port[p]; + port->dev = dev; + port->nr = i; + port->lnr = l; + port->pnr = p; + port->gap = 0xffffffff; + port->obr = ci_bitrate; + mutex_init(&port->i2c_gate_lock); + + if (!ddb_port_match_i2c(port)) { + if (info->type == DDB_OCTOPUS_MAX) + ddb_port_match_link_i2c(port); + } - for (i = 0; i < dev->info->port_num; i++) { - port = &dev->port[i]; - port->dev = dev; - port->nr = i; - port->i2c = &dev->i2c[i]; - port->input[0] = &dev->input[2 * i]; - port->input[1] = &dev->input[2 * i + 1]; - port->output = &dev->output[i]; + ddb_port_probe(port); + + port->dvb[0].adap = &dev->adap[2 * p]; + port->dvb[1].adap = &dev->adap[2 * p + 1]; + + if ((port->class == DDB_PORT_NONE) && i && p && + dev->port[p - 1].type == DDB_CI_EXTERNAL_XO2) { + port->class = DDB_PORT_CI; + port->type = DDB_CI_EXTERNAL_XO2_B; + port->name = "DuoFlex CI_B"; + port->i2c = dev->port[p - 1].i2c; + } + + dev_info(dev->dev, "Port %u: Link %u, Link Port %u (TAB %u): %s\n", + port->pnr, port->lnr, port->nr, port->nr + 1, + port->name); - mutex_init(&port->i2c_gate_lock); - ddb_port_probe(port); - ddb_input_init(port, 2 * i); - ddb_input_init(port, 2 * i + 1); - ddb_output_init(port, i); + if (port->class == DDB_PORT_CI && + port->type == DDB_CI_EXTERNAL_XO2) { + ddb_input_init(port, 2 * i, 0, 2 * i); + ddb_output_init(port, i); + continue; + } + + if (port->class == DDB_PORT_CI && + port->type == DDB_CI_EXTERNAL_XO2_B) { + ddb_input_init(port, 2 * i - 1, 0, 2 * i - 1); + ddb_output_init(port, i); + continue; + } + + if (port->class == DDB_PORT_NONE) + continue; + + switch (dev->link[l].info->type) { + case DDB_OCTOPUS_CI: + if (i >= 2) { + ddb_input_init(port, 2 + i, 0, 2 + i); + ddb_input_init(port, 4 + i, 1, 4 + i); + ddb_output_init(port, i); + break; + } /* fallthrough */ + case DDB_OCTOPUS: + ddb_input_init(port, 2 * i, 0, 2 * i); + ddb_input_init(port, 2 * i + 1, 1, 2 * i + 1); + ddb_output_init(port, i); + break; + case DDB_OCTOPUS_MAX: + case DDB_OCTOPUS_MAX_CT: + ddb_input_init(port, 2 * i, 0, 2 * p); + ddb_input_init(port, 2 * i + 1, 1, 2 * p + 1); + break; + default: + break; + } + } } + dev->port_num = p; } -static void ddb_ports_release(struct ddb *dev) +void ddb_ports_release(struct ddb *dev) { int i; struct ddb_port *port; - for (i = 0; i < dev->info->port_num; i++) { + for (i = 0; i < dev->port_num; i++) { port = &dev->port[i]; - port->dev = dev; - tasklet_kill(&port->input[0]->tasklet); - tasklet_kill(&port->input[1]->tasklet); - tasklet_kill(&port->output->tasklet); + if (port->input[0] && port->input[0]->dma) + cancel_work_sync(&port->input[0]->dma->work); + if (port->input[1] && port->input[1]->dma) + cancel_work_sync(&port->input[1]->dma->work); + if (port->output && port->output->dma) + cancel_work_sync(&port->output->dma->work); } } @@ -1717,90 +2684,158 @@ static void ddb_ports_release(struct ddb *dev) /****************************************************************************/ /****************************************************************************/ -static void irq_handle_i2c(struct ddb *dev, int n) +#define IRQ_HANDLE(_nr) \ + do { if ((s & (1UL << ((_nr) & 0x1f))) && dev->handler[0][_nr]) \ + dev->handler[0][_nr](dev->handler_data[0][_nr]); } \ + while (0) + +static void irq_handle_msg(struct ddb *dev, u32 s) { - struct ddb_i2c *i2c = &dev->i2c[n]; + dev->i2c_irq++; + IRQ_HANDLE(0); + IRQ_HANDLE(1); + IRQ_HANDLE(2); + IRQ_HANDLE(3); +} - i2c->done = 1; - wake_up(&i2c->wq); +static void irq_handle_io(struct ddb *dev, u32 s) +{ + dev->ts_irq++; + if ((s & 0x000000f0)) { + IRQ_HANDLE(4); + IRQ_HANDLE(5); + IRQ_HANDLE(6); + IRQ_HANDLE(7); + } + if ((s & 0x0000ff00)) { + IRQ_HANDLE(8); + IRQ_HANDLE(9); + IRQ_HANDLE(10); + IRQ_HANDLE(11); + IRQ_HANDLE(12); + IRQ_HANDLE(13); + IRQ_HANDLE(14); + IRQ_HANDLE(15); + } + if ((s & 0x00ff0000)) { + IRQ_HANDLE(16); + IRQ_HANDLE(17); + IRQ_HANDLE(18); + IRQ_HANDLE(19); + IRQ_HANDLE(20); + IRQ_HANDLE(21); + IRQ_HANDLE(22); + IRQ_HANDLE(23); + } + if ((s & 0xff000000)) { + IRQ_HANDLE(24); + IRQ_HANDLE(25); + IRQ_HANDLE(26); + IRQ_HANDLE(27); + IRQ_HANDLE(28); + IRQ_HANDLE(29); + IRQ_HANDLE(30); + IRQ_HANDLE(31); + } } -static irqreturn_t irq_handler(int irq, void *dev_id) +irqreturn_t ddb_irq_handler0(int irq, void *dev_id) { struct ddb *dev = (struct ddb *) dev_id; - u32 s = ddbreadl(INTERRUPT_STATUS); + u32 s = ddbreadl(dev, INTERRUPT_STATUS); - if (!s) - return IRQ_NONE; + do { + if (s & 0x80000000) + return IRQ_NONE; + if (!(s & 0xfffff00)) + return IRQ_NONE; + ddbwritel(dev, s & 0xfffff00, INTERRUPT_ACK); + irq_handle_io(dev, s); + } while ((s = ddbreadl(dev, INTERRUPT_STATUS))); + + return IRQ_HANDLED; +} + +irqreturn_t ddb_irq_handler1(int irq, void *dev_id) +{ + struct ddb *dev = (struct ddb *) dev_id; + u32 s = ddbreadl(dev, INTERRUPT_STATUS); do { - ddbwritel(s, INTERRUPT_ACK); - - if (s & 0x00000001) - irq_handle_i2c(dev, 0); - if (s & 0x00000002) - irq_handle_i2c(dev, 1); - if (s & 0x00000004) - irq_handle_i2c(dev, 2); - if (s & 0x00000008) - irq_handle_i2c(dev, 3); - - if (s & 0x00000100) - tasklet_schedule(&dev->input[0].tasklet); - if (s & 0x00000200) - tasklet_schedule(&dev->input[1].tasklet); - if (s & 0x00000400) - tasklet_schedule(&dev->input[2].tasklet); - if (s & 0x00000800) - tasklet_schedule(&dev->input[3].tasklet); - if (s & 0x00001000) - tasklet_schedule(&dev->input[4].tasklet); - if (s & 0x00002000) - tasklet_schedule(&dev->input[5].tasklet); - if (s & 0x00004000) - tasklet_schedule(&dev->input[6].tasklet); - if (s & 0x00008000) - tasklet_schedule(&dev->input[7].tasklet); - - if (s & 0x00010000) - tasklet_schedule(&dev->output[0].tasklet); - if (s & 0x00020000) - tasklet_schedule(&dev->output[1].tasklet); - if (s & 0x00040000) - tasklet_schedule(&dev->output[2].tasklet); - if (s & 0x00080000) - tasklet_schedule(&dev->output[3].tasklet); - - /* if (s & 0x000f0000) printk(KERN_DEBUG "%08x\n", istat); */ - } while ((s = ddbreadl(INTERRUPT_STATUS))); + if (s & 0x80000000) + return IRQ_NONE; + if (!(s & 0x0000f)) + return IRQ_NONE; + ddbwritel(dev, s & 0x0000f, INTERRUPT_ACK); + irq_handle_msg(dev, s); + } while ((s = ddbreadl(dev, INTERRUPT_STATUS))); return IRQ_HANDLED; } -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ +irqreturn_t ddb_irq_handler(int irq, void *dev_id) +{ + struct ddb *dev = (struct ddb *) dev_id; + u32 s = ddbreadl(dev, INTERRUPT_STATUS); + int ret = IRQ_HANDLED; + + if (!s) + return IRQ_NONE; + do { + if (s & 0x80000000) + return IRQ_NONE; + ddbwritel(dev, s, INTERRUPT_ACK); + + if (s & 0x0000000f) + irq_handle_msg(dev, s); + if (s & 0x0fffff00) + irq_handle_io(dev, s); + } while ((s = ddbreadl(dev, INTERRUPT_STATUS))); + + return ret; +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static int reg_wait(struct ddb *dev, u32 reg, u32 bit) +{ + u32 count = 0; + + while (safe_ddbreadl(dev, reg) & bit) { + ndelay(10); + if (++count == 100) + return -1; + } + return 0; +} -static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) +static int flashio(struct ddb *dev, u32 lnr, u8 *wbuf, u32 wlen, u8 *rbuf, + u32 rlen) { u32 data, shift; + u32 tag = DDB_LINK_TAG(lnr); + struct ddb_link *link = &dev->link[lnr]; + mutex_lock(&link->flash_mutex); if (wlen > 4) - ddbwritel(1, SPI_CONTROL); + ddbwritel(dev, 1, tag | SPI_CONTROL); while (wlen > 4) { /* FIXME: check for big-endian */ - data = swab32(*(u32 *)wbuf); + data = swab32(*(u32 *) wbuf); wbuf += 4; wlen -= 4; - ddbwritel(data, SPI_DATA); - while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004) - ; + ddbwritel(dev, data, tag | SPI_DATA); + if (reg_wait(dev, tag | SPI_CONTROL, 4)) + goto fail; } - if (rlen) - ddbwritel(0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); + ddbwritel(dev, 0x0001 | ((wlen << (8 + 3)) & 0x1f00), + tag | SPI_CONTROL); else - ddbwritel(0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); + ddbwritel(dev, 0x0003 | ((wlen << (8 + 3)) & 0x1f00), + tag | SPI_CONTROL); data = 0; shift = ((4 - wlen) * 8); @@ -1812,33 +2847,34 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) } if (shift) data <<= shift; - ddbwritel(data, SPI_DATA); - while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004) - ; + ddbwritel(dev, data, tag | SPI_DATA); + if (reg_wait(dev, tag | SPI_CONTROL, 4)) + goto fail; if (!rlen) { - ddbwritel(0, SPI_CONTROL); - return 0; + ddbwritel(dev, 0, tag | SPI_CONTROL); + goto exit; } if (rlen > 4) - ddbwritel(1, SPI_CONTROL); + ddbwritel(dev, 1, tag | SPI_CONTROL); while (rlen > 4) { - ddbwritel(0xffffffff, SPI_DATA); - while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004) - ; - data = ddbreadl(SPI_DATA); + ddbwritel(dev, 0xffffffff, tag | SPI_DATA); + if (reg_wait(dev, tag | SPI_CONTROL, 4)) + goto fail; + data = ddbreadl(dev, tag | SPI_DATA); *(u32 *) rbuf = swab32(data); rbuf += 4; rlen -= 4; } - ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL); - ddbwritel(0xffffffff, SPI_DATA); - while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004) - ; + ddbwritel(dev, 0x0003 | ((rlen << (8 + 3)) & 0x1F00), + tag | SPI_CONTROL); + ddbwritel(dev, 0xffffffff, tag | SPI_DATA); + if (reg_wait(dev, tag | SPI_CONTROL, 4)) + goto fail; - data = ddbreadl(SPI_DATA); - ddbwritel(0, SPI_CONTROL); + data = ddbreadl(dev, tag | SPI_DATA); + ddbwritel(dev, 0, tag | SPI_CONTROL); if (rlen < 4) data <<= ((4 - rlen) * 8); @@ -1849,31 +2885,47 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) rbuf++; rlen--; } +exit: + mutex_unlock(&link->flash_mutex); return 0; +fail: + mutex_unlock(&link->flash_mutex); + return -1; } -#define DDB_MAGIC 'd' +int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len) +{ + u8 cmd[4] = {0x03, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff}; -struct ddb_flashio { - __user __u8 *write_buf; - __u32 write_len; - __user __u8 *read_buf; - __u32 read_len; -}; + return flashio(dev, link, cmd, 4, buf, len); +} -#define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio) +/* + * TODO/FIXME: add/implement IOCTLs from upstream driver + */ #define DDB_NAME "ddbridge" static u32 ddb_num; -static struct ddb *ddbs[32]; -static struct class *ddb_class; static int ddb_major; +static DEFINE_MUTEX(ddb_mutex); + +static int ddb_release(struct inode *inode, struct file *file) +{ + struct ddb *dev = file->private_data; + + dev->ddb_dev_users--; + return 0; +} static int ddb_open(struct inode *inode, struct file *file) { struct ddb *dev = ddbs[iminor(inode)]; + if (dev->ddb_dev_users) + return -EBUSY; + dev->ddb_dev_users++; file->private_data = dev; return 0; } @@ -1881,44 +2933,17 @@ static int ddb_open(struct inode *inode, struct file *file) static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ddb *dev = file->private_data; - __user void *parg = (__user void *)arg; - int res; - switch (cmd) { - case IOCTL_DDB_FLASHIO: - { - struct ddb_flashio fio; - u8 *rbuf, *wbuf; + dev_warn(dev->dev, "DDB IOCTLs unsupported (cmd: %d, arg: %lu)\n", + cmd, arg); - if (copy_from_user(&fio, parg, sizeof(fio))) - return -EFAULT; - - if (fio.write_len > 1028 || fio.read_len > 1028) - return -EINVAL; - if (fio.write_len + fio.read_len > 1028) - return -EINVAL; - - wbuf = &dev->iobuf[0]; - rbuf = wbuf + fio.write_len; - - if (copy_from_user(wbuf, fio.write_buf, fio.write_len)) - return -EFAULT; - res = flashio(dev, wbuf, fio.write_len, rbuf, fio.read_len); - if (res) - return res; - if (copy_to_user(fio.read_buf, rbuf, fio.read_len)) - return -EFAULT; - break; - } - default: - return -ENOTTY; - } - return 0; + return -ENOTTY; } static const struct file_operations ddb_fops = { .unlocked_ioctl = ddb_ioctl, .open = ddb_open, + .release = ddb_release, }; static char *ddb_devnode(struct device *device, umode_t *mode) @@ -1928,369 +2953,684 @@ static char *ddb_devnode(struct device *device, umode_t *mode) return kasprintf(GFP_KERNEL, "ddbridge/card%d", dev->nr); } -static int ddb_class_create(void) +#define __ATTR_MRO(_name, _show) { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = _show, \ +} + +#define __ATTR_MWO(_name, _store) { \ + .attr = { .name = __stringify(_name), .mode = 0222 }, \ + .store = _store, \ +} + +static ssize_t ports_show(struct device *device, + struct device_attribute *attr, char *buf) { - ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops); - if (ddb_major < 0) - return ddb_major; + struct ddb *dev = dev_get_drvdata(device); - ddb_class = class_create(THIS_MODULE, DDB_NAME); - if (IS_ERR(ddb_class)) { - unregister_chrdev(ddb_major, DDB_NAME); - return PTR_ERR(ddb_class); - } - ddb_class->devnode = ddb_devnode; - return 0; + return sprintf(buf, "%d\n", dev->port_num); } -static void ddb_class_destroy(void) +static ssize_t ts_irq_show(struct device *device, + struct device_attribute *attr, char *buf) { - class_destroy(ddb_class); - unregister_chrdev(ddb_major, DDB_NAME); + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "%d\n", dev->ts_irq); } -static int ddb_device_create(struct ddb *dev) +static ssize_t i2c_irq_show(struct device *device, + struct device_attribute *attr, char *buf) { - dev->nr = ddb_num++; - dev->ddb_dev = device_create(ddb_class, NULL, - MKDEV(ddb_major, dev->nr), - dev, "ddbridge%d", dev->nr); - ddbs[dev->nr] = dev; - if (IS_ERR(dev->ddb_dev)) - return -1; - return 0; + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "%d\n", dev->i2c_irq); } -static void ddb_device_destroy(struct ddb *dev) +static ssize_t fan_show(struct device *device, + struct device_attribute *attr, char *buf) { - ddb_num--; - if (IS_ERR(dev->ddb_dev)) - return; - device_destroy(ddb_class, MKDEV(ddb_major, 0)); + struct ddb *dev = dev_get_drvdata(device); + u32 val; + + val = ddbreadl(dev, GPIO_OUTPUT) & 1; + return sprintf(buf, "%d\n", val); } +static ssize_t fan_store(struct device *device, struct device_attribute *d, + const char *buf, size_t count) +{ + struct ddb *dev = dev_get_drvdata(device); + u32 val; -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ + if (sscanf(buf, "%u\n", &val) != 1) + return -EINVAL; + ddbwritel(dev, 1, GPIO_DIRECTION); + ddbwritel(dev, val & 1, GPIO_OUTPUT); + return count; +} -static void ddb_unmap(struct ddb *dev) +static ssize_t fanspeed_show(struct device *device, + struct device_attribute *attr, char *buf) { - if (dev->regs) - iounmap(dev->regs); - vfree(dev); + struct ddb *dev = dev_get_drvdata(device); + int num = attr->attr.name[8] - 0x30; + struct ddb_link *link = &dev->link[num]; + u32 spd; + + spd = ddblreadl(link, TEMPMON_FANCONTROL) & 0xff; + return sprintf(buf, "%u\n", spd * 100); } +static ssize_t temp_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + struct ddb_link *link = &dev->link[0]; + struct i2c_adapter *adap; + int temp, temp2; + u8 tmp[2]; + + if (!link->info->temp_num) + return sprintf(buf, "no sensor\n"); + adap = &dev->i2c[link->info->temp_bus].adap; + if (i2c_read_regs(adap, 0x48, 0, tmp, 2) < 0) + return sprintf(buf, "read_error\n"); + temp = (tmp[0] << 3) | (tmp[1] >> 5); + temp *= 125; + if (link->info->temp_num == 2) { + if (i2c_read_regs(adap, 0x49, 0, tmp, 2) < 0) + return sprintf(buf, "read_error\n"); + temp2 = (tmp[0] << 3) | (tmp[1] >> 5); + temp2 *= 125; + return sprintf(buf, "%d %d\n", temp, temp2); + } + return sprintf(buf, "%d\n", temp); +} -static void ddb_remove(struct pci_dev *pdev) +static ssize_t ctemp_show(struct device *device, + struct device_attribute *attr, char *buf) { - struct ddb *dev = pci_get_drvdata(pdev); + struct ddb *dev = dev_get_drvdata(device); + struct i2c_adapter *adap; + int temp; + u8 tmp[2]; + int num = attr->attr.name[4] - 0x30; - ddb_ports_detach(dev); - ddb_i2c_release(dev); + adap = &dev->i2c[num].adap; + if (!adap) + return 0; + if (i2c_read_regs(adap, 0x49, 0, tmp, 2) < 0) + if (i2c_read_regs(adap, 0x4d, 0, tmp, 2) < 0) + return sprintf(buf, "no sensor\n"); + temp = tmp[0] * 1000; + return sprintf(buf, "%d\n", temp); +} - ddbwritel(0, INTERRUPT_ENABLE); - free_irq(dev->pdev->irq, dev); -#ifdef CONFIG_PCI_MSI - if (dev->msi) - pci_disable_msi(dev->pdev); -#endif - ddb_ports_release(dev); - ddb_buffers_free(dev); - ddb_device_destroy(dev); +static ssize_t led_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + int num = attr->attr.name[3] - 0x30; - ddb_unmap(dev); - pci_set_drvdata(pdev, NULL); - pci_disable_device(pdev); + return sprintf(buf, "%d\n", dev->leds & (1 << num) ? 1 : 0); } -static int ddb_probe(struct pci_dev *pdev, const struct pci_device_id *id) +static void ddb_set_led(struct ddb *dev, int num, int val) { - struct ddb *dev; - int stat = 0; - int irq_flag = IRQF_SHARED; + if (!dev->link[0].info->led_num) + return; + switch (dev->port[num].class) { + case DDB_PORT_TUNER: + switch (dev->port[num].type) { + case DDB_TUNER_DVBS_ST: + i2c_write_reg16(&dev->i2c[num].adap, + 0x69, 0xf14c, val ? 2 : 0); + break; + case DDB_TUNER_DVBCT_ST: + i2c_write_reg16(&dev->i2c[num].adap, + 0x1f, 0xf00e, 0); + i2c_write_reg16(&dev->i2c[num].adap, + 0x1f, 0xf00f, val ? 1 : 0); + break; + case DDB_TUNER_XO2 ... DDB_TUNER_DVBC2T2I_SONY: + { + u8 v; - if (pci_enable_device(pdev) < 0) - return -ENODEV; + i2c_read_reg(&dev->i2c[num].adap, 0x10, 0x08, &v); + v = (v & ~0x10) | (val ? 0x10 : 0); + i2c_write_reg(&dev->i2c[num].adap, 0x10, 0x08, v); + break; + } + default: + break; + } + break; + } +} - dev = vzalloc(sizeof(struct ddb)); - if (dev == NULL) - return -ENOMEM; +static ssize_t led_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ddb *dev = dev_get_drvdata(device); + int num = attr->attr.name[3] - 0x30; + u32 val; - dev->pdev = pdev; - pci_set_drvdata(pdev, dev); - dev->info = (struct ddb_info *) id->driver_data; - dev_info(&pdev->dev, "Detected %s\n", dev->info->name); + if (sscanf(buf, "%u\n", &val) != 1) + return -EINVAL; + if (val) + dev->leds |= (1 << num); + else + dev->leds &= ~(1 << num); + ddb_set_led(dev, num, val); + return count; +} - dev->regs = ioremap(pci_resource_start(dev->pdev, 0), - pci_resource_len(dev->pdev, 0)); - if (!dev->regs) { - stat = -ENOMEM; - goto fail; - } - dev_info(&pdev->dev, "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4)); +static ssize_t snr_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + char snr[32]; + int num = attr->attr.name[3] - 0x30; -#ifdef CONFIG_PCI_MSI - if (pci_msi_enabled()) - stat = pci_enable_msi(dev->pdev); - if (stat) { - dev_info(&pdev->dev, "MSI not available.\n"); + if (dev->port[num].type >= DDB_TUNER_XO2) { + if (i2c_read_regs(&dev->i2c[num].adap, 0x10, 0x10, snr, 16) < 0) + return sprintf(buf, "NO SNR\n"); + snr[16] = 0; } else { - irq_flag = 0; - dev->msi = 1; - } -#endif - stat = request_irq(dev->pdev->irq, irq_handler, - irq_flag, "DDBridge", (void *) dev); - if (stat < 0) - goto fail1; - ddbwritel(0, DMA_BASE_WRITE); - ddbwritel(0, DMA_BASE_READ); - ddbwritel(0xffffffff, INTERRUPT_ACK); - ddbwritel(0xfff0f, INTERRUPT_ENABLE); - ddbwritel(0, MSI1_ENABLE); - - /* board control */ - if (dev->info->board_control) { - ddbwritel(0, DDB_LINK_TAG(0) | BOARD_CONTROL); - msleep(100); - ddbwritel(dev->info->board_control_2, - DDB_LINK_TAG(0) | BOARD_CONTROL); - usleep_range(2000, 3000); - ddbwritel(dev->info->board_control_2 - | dev->info->board_control, - DDB_LINK_TAG(0) | BOARD_CONTROL); - usleep_range(2000, 3000); + /* serial number at 0x100-0x11f */ + if (i2c_read_regs16(&dev->i2c[num].adap, + 0x57, 0x100, snr, 32) < 0) + if (i2c_read_regs16(&dev->i2c[num].adap, + 0x50, 0x100, snr, 32) < 0) + return sprintf(buf, "NO SNR\n"); + snr[31] = 0; /* in case it is not terminated on EEPROM */ } + return sprintf(buf, "%s\n", snr); +} - if (ddb_i2c_init(dev) < 0) - goto fail1; - ddb_ports_init(dev); - if (ddb_buffers_alloc(dev) < 0) { - dev_err(&pdev->dev, "Could not allocate buffer memory\n"); - goto fail2; - } - if (ddb_ports_attach(dev) < 0) - goto fail3; - ddb_device_create(dev); +static ssize_t bsnr_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + char snr[16]; + + ddbridge_flashread(dev, 0, snr, 0x10, 15); + snr[15] = 0; /* in case it is not terminated on EEPROM */ + return sprintf(buf, "%s\n", snr); +} + +static ssize_t bpsnr_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + unsigned char snr[32]; + + if (!dev->i2c_num) + return 0; + + if (i2c_read_regs16(&dev->i2c[0].adap, + 0x50, 0x0000, snr, 32) < 0 || + snr[0] == 0xff) + return sprintf(buf, "NO SNR\n"); + snr[31] = 0; /* in case it is not terminated on EEPROM */ + return sprintf(buf, "%s\n", snr); +} + +static ssize_t redirect_show(struct device *device, + struct device_attribute *attr, char *buf) +{ return 0; +} -fail3: - ddb_ports_detach(dev); - dev_err(&pdev->dev, "fail3\n"); - ddb_ports_release(dev); -fail2: - dev_err(&pdev->dev, "fail2\n"); - ddb_buffers_free(dev); -fail1: - dev_err(&pdev->dev, "fail1\n"); - if (dev->msi) - pci_disable_msi(dev->pdev); - if (stat == 0) - free_irq(dev->pdev->irq, dev); -fail: - dev_err(&pdev->dev, "fail\n"); - ddb_unmap(dev); - pci_set_drvdata(pdev, NULL); - pci_disable_device(pdev); - return -1; +static ssize_t redirect_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int i, p; + int res; + + if (sscanf(buf, "%x %x\n", &i, &p) != 2) + return -EINVAL; + res = ddb_redirect(i, p); + if (res < 0) + return res; + dev_info(device, "redirect: %02x, %02x\n", i, p); + return count; } -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ +static ssize_t gap_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + int num = attr->attr.name[3] - 0x30; -static const struct ddb_info ddb_none = { - .type = DDB_NONE, - .name = "Digital Devices PCIe bridge", -}; + return sprintf(buf, "%d\n", dev->port[num].gap); -static const struct ddb_info ddb_octopus = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus DVB adapter", - .port_num = 4, -}; +} -static const struct ddb_info ddb_octopus_le = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus LE DVB adapter", - .port_num = 2, -}; +static ssize_t gap_store(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ddb *dev = dev_get_drvdata(device); + int num = attr->attr.name[3] - 0x30; + unsigned int val; + + if (sscanf(buf, "%u\n", &val) != 1) + return -EINVAL; + if (val > 128) + return -EINVAL; + if (val == 128) + val = 0xffffffff; + dev->port[num].gap = val; + return count; +} + +static ssize_t version_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "%08x %08x\n", + dev->link[0].ids.hwid, dev->link[0].ids.regmapid); +} + +static ssize_t hwid_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "0x%08X\n", dev->link[0].ids.hwid); +} + +static ssize_t regmap_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "0x%08X\n", dev->link[0].ids.regmapid); +} + +static ssize_t fmode_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + int num = attr->attr.name[5] - 0x30; + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "%u\n", dev->link[num].lnb.fmode); +} -static const struct ddb_info ddb_octopus_oem = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus OEM", - .port_num = 4, +static ssize_t devid_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + int num = attr->attr.name[5] - 0x30; + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "%08x\n", dev->link[num].ids.devid); +} + +static ssize_t fmode_store(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ddb *dev = dev_get_drvdata(device); + int num = attr->attr.name[5] - 0x30; + unsigned int val; + + if (sscanf(buf, "%u\n", &val) != 1) + return -EINVAL; + if (val > 3) + return -EINVAL; + lnb_init_fmode(dev, &dev->link[num], val); + return count; +} + +static struct device_attribute ddb_attrs[] = { + __ATTR_RO(version), + __ATTR_RO(ports), + __ATTR_RO(ts_irq), + __ATTR_RO(i2c_irq), + __ATTR(gap0, 0664, gap_show, gap_store), + __ATTR(gap1, 0664, gap_show, gap_store), + __ATTR(gap2, 0664, gap_show, gap_store), + __ATTR(gap3, 0664, gap_show, gap_store), + __ATTR(fmode0, 0664, fmode_show, fmode_store), + __ATTR(fmode1, 0664, fmode_show, fmode_store), + __ATTR(fmode2, 0664, fmode_show, fmode_store), + __ATTR(fmode3, 0664, fmode_show, fmode_store), + __ATTR_MRO(devid0, devid_show), + __ATTR_MRO(devid1, devid_show), + __ATTR_MRO(devid2, devid_show), + __ATTR_MRO(devid3, devid_show), + __ATTR_RO(hwid), + __ATTR_RO(regmap), + __ATTR(redirect, 0664, redirect_show, redirect_store), + __ATTR_MRO(snr, bsnr_show), + __ATTR_RO(bpsnr), + __ATTR_NULL, }; -static const struct ddb_info ddb_octopus_mini = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus Mini", - .port_num = 4, +static struct device_attribute ddb_attrs_temp[] = { + __ATTR_RO(temp), }; -static const struct ddb_info ddb_v6 = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Cine S2 V6 DVB adapter", - .port_num = 3, +static struct device_attribute ddb_attrs_fan[] = { + __ATTR(fan, 0664, fan_show, fan_store), }; -static const struct ddb_info ddb_v6_5 = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Cine S2 V6.5 DVB adapter", - .port_num = 4, + +static struct device_attribute ddb_attrs_snr[] = { + __ATTR_MRO(snr0, snr_show), + __ATTR_MRO(snr1, snr_show), + __ATTR_MRO(snr2, snr_show), + __ATTR_MRO(snr3, snr_show), }; -static const struct ddb_info ddb_dvbct = { - .type = DDB_OCTOPUS, - .name = "Digital Devices DVBCT V6.1 DVB adapter", - .port_num = 3, +static struct device_attribute ddb_attrs_ctemp[] = { + __ATTR_MRO(temp0, ctemp_show), + __ATTR_MRO(temp1, ctemp_show), + __ATTR_MRO(temp2, ctemp_show), + __ATTR_MRO(temp3, ctemp_show), }; -static const struct ddb_info ddb_ctv7 = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Cine CT V7 DVB adapter", - .port_num = 4, - .board_control = 3, - .board_control_2 = 4, +static struct device_attribute ddb_attrs_led[] = { + __ATTR(led0, 0664, led_show, led_store), + __ATTR(led1, 0664, led_show, led_store), + __ATTR(led2, 0664, led_show, led_store), + __ATTR(led3, 0664, led_show, led_store), }; -static const struct ddb_info ddb_satixS2v3 = { - .type = DDB_OCTOPUS, - .name = "Mystique SaTiX-S2 V3 DVB adapter", - .port_num = 3, +static struct device_attribute ddb_attrs_fanspeed[] = { + __ATTR_MRO(fanspeed0, fanspeed_show), + __ATTR_MRO(fanspeed1, fanspeed_show), + __ATTR_MRO(fanspeed2, fanspeed_show), + __ATTR_MRO(fanspeed3, fanspeed_show), }; -static const struct ddb_info ddb_octopusv3 = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus V3 DVB adapter", - .port_num = 4, +static struct class ddb_class = { + .name = "ddbridge", + .owner = THIS_MODULE, + .devnode = ddb_devnode, }; -/*** MaxA8 adapters ***********************************************************/ +int ddb_class_create(void) +{ + ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops); + if (ddb_major < 0) + return ddb_major; + if (class_register(&ddb_class) < 0) + return -1; + return 0; +} -static struct ddb_info ddb_ct2_8 = { - .type = DDB_OCTOPUS_MAX_CT, - .name = "Digital Devices MAX A8 CT2", - .port_num = 4, - .board_control = 0x0ff, - .board_control_2 = 0xf00, - .ts_quirks = TS_QUIRK_SERIAL, -}; +void ddb_class_destroy(void) +{ + class_unregister(&ddb_class); + unregister_chrdev(ddb_major, DDB_NAME); +} -static struct ddb_info ddb_c2t2_8 = { - .type = DDB_OCTOPUS_MAX_CT, - .name = "Digital Devices MAX A8 C2T2", - .port_num = 4, - .board_control = 0x0ff, - .board_control_2 = 0xf00, - .ts_quirks = TS_QUIRK_SERIAL, -}; +static void ddb_device_attrs_del(struct ddb *dev) +{ + int i; -static struct ddb_info ddb_isdbt_8 = { - .type = DDB_OCTOPUS_MAX_CT, - .name = "Digital Devices MAX A8 ISDBT", - .port_num = 4, - .board_control = 0x0ff, - .board_control_2 = 0xf00, - .ts_quirks = TS_QUIRK_SERIAL, -}; + for (i = 0; i < 4; i++) + if (dev->link[i].info && dev->link[i].info->tempmon_irq) + device_remove_file(dev->ddb_dev, + &ddb_attrs_fanspeed[i]); + for (i = 0; i < dev->link[0].info->temp_num; i++) + device_remove_file(dev->ddb_dev, &ddb_attrs_temp[i]); + for (i = 0; i < dev->link[0].info->fan_num; i++) + device_remove_file(dev->ddb_dev, &ddb_attrs_fan[i]); + for (i = 0; i < dev->i2c_num && i < 4; i++) { + if (dev->link[0].info->led_num) + device_remove_file(dev->ddb_dev, &ddb_attrs_led[i]); + device_remove_file(dev->ddb_dev, &ddb_attrs_snr[i]); + device_remove_file(dev->ddb_dev, &ddb_attrs_ctemp[i]); + } + for (i = 0; ddb_attrs[i].attr.name != NULL; i++) + device_remove_file(dev->ddb_dev, &ddb_attrs[i]); +} -static struct ddb_info ddb_c2t2i_v0_8 = { - .type = DDB_OCTOPUS_MAX_CT, - .name = "Digital Devices MAX A8 C2T2I V0", - .port_num = 4, - .board_control = 0x0ff, - .board_control_2 = 0xf00, - .ts_quirks = TS_QUIRK_SERIAL | TS_QUIRK_ALT_OSC, -}; +static int ddb_device_attrs_add(struct ddb *dev) +{ + int i; -static struct ddb_info ddb_c2t2i_8 = { - .type = DDB_OCTOPUS_MAX_CT, - .name = "Digital Devices MAX A8 C2T2I", - .port_num = 4, - .board_control = 0x0ff, - .board_control_2 = 0xf00, - .ts_quirks = TS_QUIRK_SERIAL, -}; + for (i = 0; ddb_attrs[i].attr.name != NULL; i++) + if (device_create_file(dev->ddb_dev, &ddb_attrs[i])) + goto fail; + for (i = 0; i < dev->link[0].info->temp_num; i++) + if (device_create_file(dev->ddb_dev, &ddb_attrs_temp[i])) + goto fail; + for (i = 0; i < dev->link[0].info->fan_num; i++) + if (device_create_file(dev->ddb_dev, &ddb_attrs_fan[i])) + goto fail; + for (i = 0; (i < dev->i2c_num) && (i < 4); i++) { + if (device_create_file(dev->ddb_dev, &ddb_attrs_snr[i])) + goto fail; + if (device_create_file(dev->ddb_dev, &ddb_attrs_ctemp[i])) + goto fail; + if (dev->link[0].info->led_num) + if (device_create_file(dev->ddb_dev, + &ddb_attrs_led[i])) + goto fail; + } + for (i = 0; i < 4; i++) + if (dev->link[i].info && dev->link[i].info->tempmon_irq) + if (device_create_file(dev->ddb_dev, + &ddb_attrs_fanspeed[i])) + goto fail; + return 0; +fail: + return -1; +} -/******************************************************************************/ +int ddb_device_create(struct ddb *dev) +{ + int res = 0; -#define DDVID 0xdd01 /* Digital Devices Vendor ID */ - -#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \ - .vendor = _vend, .device = _dev, \ - .subvendor = _subvend, .subdevice = _subdev, \ - .driver_data = (unsigned long)&_driverdata } - -static const struct pci_device_id ddb_id_tbl[] = { - DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus), - DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus), - DDB_ID(DDVID, 0x0005, DDVID, 0x0004, ddb_octopusv3), - DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le), - DDB_ID(DDVID, 0x0003, DDVID, 0x0003, ddb_octopus_oem), - DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus_mini), - DDB_ID(DDVID, 0x0005, DDVID, 0x0011, ddb_octopus_mini), - DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6), - DDB_ID(DDVID, 0x0003, DDVID, 0x0021, ddb_v6_5), - DDB_ID(DDVID, 0x0003, DDVID, 0x0030, ddb_dvbct), - DDB_ID(DDVID, 0x0003, DDVID, 0xdb03, ddb_satixS2v3), - DDB_ID(DDVID, 0x0006, DDVID, 0x0031, ddb_ctv7), - DDB_ID(DDVID, 0x0006, DDVID, 0x0032, ddb_ctv7), - DDB_ID(DDVID, 0x0006, DDVID, 0x0033, ddb_ctv7), - DDB_ID(DDVID, 0x0008, DDVID, 0x0034, ddb_ct2_8), - DDB_ID(DDVID, 0x0008, DDVID, 0x0035, ddb_c2t2_8), - DDB_ID(DDVID, 0x0008, DDVID, 0x0036, ddb_isdbt_8), - DDB_ID(DDVID, 0x0008, DDVID, 0x0037, ddb_c2t2i_v0_8), - DDB_ID(DDVID, 0x0008, DDVID, 0x0038, ddb_c2t2i_8), - DDB_ID(DDVID, 0x0006, DDVID, 0x0039, ddb_ctv7), - /* in case sub-ids got deleted in flash */ - DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0005, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0006, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0007, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0008, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0011, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0013, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0201, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0320, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - {0} -}; -MODULE_DEVICE_TABLE(pci, ddb_id_tbl); + if (ddb_num == DDB_MAX_ADAPTER) + return -ENOMEM; + mutex_lock(&ddb_mutex); + dev->nr = ddb_num; + ddbs[dev->nr] = dev; + dev->ddb_dev = device_create(&ddb_class, dev->dev, + MKDEV(ddb_major, dev->nr), + dev, "ddbridge%d", dev->nr); + if (IS_ERR(dev->ddb_dev)) { + res = PTR_ERR(dev->ddb_dev); + dev_info(dev->dev, "Could not create ddbridge%d\n", dev->nr); + goto fail; + } + res = ddb_device_attrs_add(dev); + if (res) { + ddb_device_attrs_del(dev); + device_destroy(&ddb_class, MKDEV(ddb_major, dev->nr)); + ddbs[dev->nr] = NULL; + dev->ddb_dev = ERR_PTR(-ENODEV); + } else + ddb_num++; +fail: + mutex_unlock(&ddb_mutex); + return res; +} +void ddb_device_destroy(struct ddb *dev) +{ + if (IS_ERR(dev->ddb_dev)) + return; + ddb_device_attrs_del(dev); + device_destroy(&ddb_class, MKDEV(ddb_major, dev->nr)); +} -static struct pci_driver ddb_pci_driver = { - .name = "DDBridge", - .id_table = ddb_id_tbl, - .probe = ddb_probe, - .remove = ddb_remove, -}; +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ -static __init int module_init_ddbridge(void) +static void tempmon_setfan(struct ddb_link *link) { - int ret; + u32 temp, temp2, pwm; + + if ((ddblreadl(link, TEMPMON_CONTROL) & + TEMPMON_CONTROL_OVERTEMP) != 0) { + dev_info(link->dev->dev, "Over temperature condition\n"); + link->overtemperature_error = 1; + } + temp = (ddblreadl(link, TEMPMON_SENSOR0) >> 8) & 0xFF; + if (temp & 0x80) + temp = 0; + temp2 = (ddblreadl(link, TEMPMON_SENSOR1) >> 8) & 0xFF; + if (temp2 & 0x80) + temp2 = 0; + if (temp2 > temp) + temp = temp2; + + pwm = (ddblreadl(link, TEMPMON_FANCONTROL) >> 8) & 0x0F; + if (pwm > 10) + pwm = 10; + + if (temp >= link->temp_tab[pwm]) { + while (pwm < 10 && temp >= link->temp_tab[pwm + 1]) + pwm += 1; + } else { + while (pwm > 1 && temp < link->temp_tab[pwm - 2]) + pwm -= 1; + } + ddblwritel(link, (pwm << 8), TEMPMON_FANCONTROL); +} - pr_info("Digital Devices PCIE bridge driver, Copyright (C) 2010-11 Digital Devices GmbH\n"); +static void temp_handler(unsigned long data) +{ + struct ddb_link *link = (struct ddb_link *) data; - ret = ddb_class_create(); - if (ret < 0) - return ret; - ret = pci_register_driver(&ddb_pci_driver); - if (ret < 0) - ddb_class_destroy(); - return ret; + spin_lock(&link->temp_lock); + tempmon_setfan(link); + spin_unlock(&link->temp_lock); +} + +static int tempmon_init(struct ddb_link *link, int first_time) +{ + struct ddb *dev = link->dev; + int status = 0; + u32 l = link->nr; + + spin_lock_irq(&link->temp_lock); + if (first_time) { + static u8 temperature_table[11] = { + 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80 }; + + memcpy(link->temp_tab, temperature_table, + sizeof(temperature_table)); + } + dev->handler[l][link->info->tempmon_irq] = temp_handler; + dev->handler_data[l][link->info->tempmon_irq] = (unsigned long) link; + ddblwritel(link, (TEMPMON_CONTROL_OVERTEMP | TEMPMON_CONTROL_AUTOSCAN | + TEMPMON_CONTROL_INTENABLE), + TEMPMON_CONTROL); + ddblwritel(link, (3 << 8), TEMPMON_FANCONTROL); + + link->overtemperature_error = + ((ddblreadl(link, TEMPMON_CONTROL) & + TEMPMON_CONTROL_OVERTEMP) != 0); + if (link->overtemperature_error) { + dev_info(link->dev->dev, "Over temperature condition\n"); + status = -1; + } + tempmon_setfan(link); + spin_unlock_irq(&link->temp_lock); + return status; } -static __exit void module_exit_ddbridge(void) +static int ddb_init_tempmon(struct ddb_link *link) { - pci_unregister_driver(&ddb_pci_driver); - ddb_class_destroy(); + const struct ddb_info *info = link->info; + + if (!info->tempmon_irq) + return 0; + if (info->type == DDB_OCTOPUS_MAX_CT) + if (link->ids.regmapid < 0x00010002) + return 0; + spin_lock_init(&link->temp_lock); + dev_dbg(link->dev->dev, "init_tempmon\n"); + return tempmon_init(link, 1); +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static int ddb_init_boards(struct ddb *dev) +{ + const struct ddb_info *info; + struct ddb_link *link; + u32 l; + + for (l = 0; l < DDB_MAX_LINK; l++) { + link = &dev->link[l]; + info = link->info; + + if (!info) + continue; + if (info->board_control) { + ddbwritel(dev, 0, DDB_LINK_TAG(l) | BOARD_CONTROL); + msleep(100); + ddbwritel(dev, info->board_control_2, + DDB_LINK_TAG(l) | BOARD_CONTROL); + usleep_range(2000, 3000); + ddbwritel(dev, + info->board_control_2 | info->board_control, + DDB_LINK_TAG(l) | BOARD_CONTROL); + usleep_range(2000, 3000); + } + ddb_init_tempmon(link); + } + return 0; } -module_init(module_init_ddbridge); -module_exit(module_exit_ddbridge); +int ddb_init(struct ddb *dev) +{ + mutex_init(&dev->link[0].lnb.lock); + mutex_init(&dev->link[0].flash_mutex); + if (no_init) { + ddb_device_create(dev); + return 0; + } + + ddb_init_boards(dev); + + if (ddb_i2c_init(dev) < 0) + goto fail; + ddb_ports_init(dev); + if (ddb_buffers_alloc(dev) < 0) { + dev_info(dev->dev, "Could not allocate buffer memory\n"); + goto fail2; + } + if (ddb_ports_attach(dev) < 0) + goto fail3; + + ddb_device_create(dev); + + if (dev->link[0].info->fan_num) { + ddbwritel(dev, 1, GPIO_DIRECTION); + ddbwritel(dev, 1, GPIO_OUTPUT); + } + return 0; + +fail3: + ddb_ports_detach(dev); + dev_err(dev->dev, "fail3\n"); + ddb_ports_release(dev); +fail2: + dev_err(dev->dev, "fail2\n"); + ddb_buffers_free(dev); + ddb_i2c_release(dev); +fail: + dev_err(dev->dev, "fail1\n"); + return -1; +} -MODULE_DESCRIPTION("Digital Devices PCIe Bridge"); -MODULE_AUTHOR("Ralph Metzler"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.5"); +void ddb_unmap(struct ddb *dev) +{ + if (dev->regs) + iounmap(dev->regs); + vfree(dev); +} diff --git a/drivers/media/pci/ddbridge/ddbridge-hw.c b/drivers/media/pci/ddbridge/ddbridge-hw.c new file mode 100644 index 000000000000..48248bcd59c2 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-hw.c @@ -0,0 +1,376 @@ +/* + * ddbridge-hw.c: Digital Devices bridge hardware maps + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ddbridge.h" +#include "ddbridge-hw.h" + +/******************************************************************************/ + +static const struct ddb_regset octopus_input = { + .base = 0x200, + .num = 0x08, + .size = 0x10, +}; + +static const struct ddb_regset octopus_output = { + .base = 0x280, + .num = 0x08, + .size = 0x10, +}; + +static const struct ddb_regset octopus_idma = { + .base = 0x300, + .num = 0x08, + .size = 0x10, +}; + +static const struct ddb_regset octopus_idma_buf = { + .base = 0x2000, + .num = 0x08, + .size = 0x100, +}; + +static const struct ddb_regset octopus_odma = { + .base = 0x380, + .num = 0x04, + .size = 0x10, +}; + +static const struct ddb_regset octopus_odma_buf = { + .base = 0x2800, + .num = 0x04, + .size = 0x100, +}; + +static const struct ddb_regset octopus_i2c = { + .base = 0x80, + .num = 0x04, + .size = 0x20, +}; + +static const struct ddb_regset octopus_i2c_buf = { + .base = 0x1000, + .num = 0x04, + .size = 0x200, +}; + +/****************************************************************************/ + +static const struct ddb_regmap octopus_map = { + .irq_base_i2c = 0, + .irq_base_idma = 8, + .irq_base_odma = 16, + .i2c = &octopus_i2c, + .i2c_buf = &octopus_i2c_buf, + .idma = &octopus_idma, + .idma_buf = &octopus_idma_buf, + .odma = &octopus_odma, + .odma_buf = &octopus_odma_buf, + .input = &octopus_input, + .output = &octopus_output, +}; + +/****************************************************************************/ + +static const struct ddb_info ddb_none = { + .type = DDB_NONE, + .name = "unknown Digital Devices PCIe card, install newer driver", + .regmap = &octopus_map, +}; + +static const struct ddb_info ddb_octopus = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus DVB adapter", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, +}; + +static const struct ddb_info ddb_octopusv3 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus V3 DVB adapter", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, +}; + +static const struct ddb_info ddb_octopus_le = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus LE DVB adapter", + .regmap = &octopus_map, + .port_num = 2, + .i2c_mask = 0x03, +}; + +static const struct ddb_info ddb_octopus_oem = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus OEM", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .led_num = 1, + .fan_num = 1, + .temp_num = 1, + .temp_bus = 0, +}; + +static const struct ddb_info ddb_octopus_mini = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus Mini", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, +}; + +static const struct ddb_info ddb_v6 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine S2 V6 DVB adapter", + .regmap = &octopus_map, + .port_num = 3, + .i2c_mask = 0x07, +}; + +static const struct ddb_info ddb_v6_5 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine S2 V6.5 DVB adapter", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, +}; + +static const struct ddb_info ddb_v7 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine S2 V7 DVB adapter", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 2, + .board_control_2 = 4, + .ts_quirks = TS_QUIRK_REVERSED, +}; + +static const struct ddb_info ddb_v7a = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine S2 V7 Advanced DVB adapter", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 2, + .board_control_2 = 4, + .ts_quirks = TS_QUIRK_REVERSED, +}; + +static const struct ddb_info ddb_ctv7 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine CT V7 DVB adapter", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 3, + .board_control_2 = 4, +}; + +static const struct ddb_info ddb_satixS2v3 = { + .type = DDB_OCTOPUS, + .name = "Mystique SaTiX-S2 V3 DVB adapter", + .regmap = &octopus_map, + .port_num = 3, + .i2c_mask = 0x07, +}; + +static const struct ddb_info ddb_ci = { + .type = DDB_OCTOPUS_CI, + .name = "Digital Devices Octopus CI", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x03, +}; + +static const struct ddb_info ddb_cis = { + .type = DDB_OCTOPUS_CI, + .name = "Digital Devices Octopus CI single", + .regmap = &octopus_map, + .port_num = 3, + .i2c_mask = 0x03, +}; + +static const struct ddb_info ddb_ci_s2_pro = { + .type = DDB_OCTOPUS_CI, + .name = "Digital Devices Octopus CI S2 Pro", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x01, + .board_control = 2, + .board_control_2 = 4, +}; + +static const struct ddb_info ddb_ci_s2_pro_a = { + .type = DDB_OCTOPUS_CI, + .name = "Digital Devices Octopus CI S2 Pro Advanced", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x01, + .board_control = 2, + .board_control_2 = 4, +}; + +static const struct ddb_info ddb_dvbct = { + .type = DDB_OCTOPUS, + .name = "Digital Devices DVBCT V6.1 DVB adapter", + .regmap = &octopus_map, + .port_num = 3, + .i2c_mask = 0x07, +}; + +/****************************************************************************/ + +static const struct ddb_info ddb_ct2_8 = { + .type = DDB_OCTOPUS_MAX_CT, + .name = "Digital Devices MAX A8 CT2", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 0x0ff, + .board_control_2 = 0xf00, + .ts_quirks = TS_QUIRK_SERIAL, + .tempmon_irq = 24, +}; + +static const struct ddb_info ddb_c2t2_8 = { + .type = DDB_OCTOPUS_MAX_CT, + .name = "Digital Devices MAX A8 C2T2", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 0x0ff, + .board_control_2 = 0xf00, + .ts_quirks = TS_QUIRK_SERIAL, + .tempmon_irq = 24, +}; + +static const struct ddb_info ddb_isdbt_8 = { + .type = DDB_OCTOPUS_MAX_CT, + .name = "Digital Devices MAX A8 ISDBT", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 0x0ff, + .board_control_2 = 0xf00, + .ts_quirks = TS_QUIRK_SERIAL, + .tempmon_irq = 24, +}; + +static const struct ddb_info ddb_c2t2i_v0_8 = { + .type = DDB_OCTOPUS_MAX_CT, + .name = "Digital Devices MAX A8 C2T2I V0", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 0x0ff, + .board_control_2 = 0xf00, + .ts_quirks = TS_QUIRK_SERIAL | TS_QUIRK_ALT_OSC, + .tempmon_irq = 24, +}; + +static const struct ddb_info ddb_c2t2i_8 = { + .type = DDB_OCTOPUS_MAX_CT, + .name = "Digital Devices MAX A8 C2T2I", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 0x0ff, + .board_control_2 = 0xf00, + .ts_quirks = TS_QUIRK_SERIAL, + .tempmon_irq = 24, +}; + +/****************************************************************************/ + +static const struct ddb_info ddb_s2_48 = { + .type = DDB_OCTOPUS_MAX, + .name = "Digital Devices MAX S8 4/8", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x01, + .board_control = 1, + .tempmon_irq = 24, +}; + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +#define DDB_DEVID(_device, _subdevice, _info) { \ + .vendor = DDVID, \ + .device = _device, \ + .subvendor = DDVID, \ + .subdevice = _subdevice, \ + .info = &_info } + +static const struct ddb_device_id ddb_device_ids[] = { + /* PCIe devices */ + DDB_DEVID(0x0002, 0x0001, ddb_octopus), + DDB_DEVID(0x0003, 0x0001, ddb_octopus), + DDB_DEVID(0x0005, 0x0004, ddb_octopusv3), + DDB_DEVID(0x0003, 0x0002, ddb_octopus_le), + DDB_DEVID(0x0003, 0x0003, ddb_octopus_oem), + DDB_DEVID(0x0003, 0x0010, ddb_octopus_mini), + DDB_DEVID(0x0005, 0x0011, ddb_octopus_mini), + DDB_DEVID(0x0003, 0x0020, ddb_v6), + DDB_DEVID(0x0003, 0x0021, ddb_v6_5), + DDB_DEVID(0x0006, 0x0022, ddb_v7), + DDB_DEVID(0x0006, 0x0024, ddb_v7a), + DDB_DEVID(0x0003, 0x0030, ddb_dvbct), + DDB_DEVID(0x0003, 0xdb03, ddb_satixS2v3), + DDB_DEVID(0x0006, 0x0031, ddb_ctv7), + DDB_DEVID(0x0006, 0x0032, ddb_ctv7), + DDB_DEVID(0x0006, 0x0033, ddb_ctv7), + DDB_DEVID(0x0007, 0x0023, ddb_s2_48), + DDB_DEVID(0x0008, 0x0034, ddb_ct2_8), + DDB_DEVID(0x0008, 0x0035, ddb_c2t2_8), + DDB_DEVID(0x0008, 0x0036, ddb_isdbt_8), + DDB_DEVID(0x0008, 0x0037, ddb_c2t2i_v0_8), + DDB_DEVID(0x0008, 0x0038, ddb_c2t2i_8), + DDB_DEVID(0x0006, 0x0039, ddb_ctv7), + DDB_DEVID(0x0011, 0x0040, ddb_ci), + DDB_DEVID(0x0011, 0x0041, ddb_cis), + DDB_DEVID(0x0012, 0x0042, ddb_ci), + DDB_DEVID(0x0013, 0x0043, ddb_ci_s2_pro), + DDB_DEVID(0x0013, 0x0044, ddb_ci_s2_pro_a), +}; + +/****************************************************************************/ + +const struct ddb_info *get_ddb_info(u16 vendor, u16 device, + u16 subvendor, u16 subdevice) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ddb_device_ids); i++) { + const struct ddb_device_id *id = &ddb_device_ids[i]; + + if (vendor == id->vendor && + device == id->device && + subvendor == id->subvendor && + ((subdevice == id->subdevice) || + (id->subdevice == 0xffff))) + return id->info; + } + + return &ddb_none; +} diff --git a/drivers/media/pci/ddbridge/ddbridge-hw.h b/drivers/media/pci/ddbridge/ddbridge-hw.h new file mode 100644 index 000000000000..7c142419419c --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-hw.h @@ -0,0 +1,43 @@ +/* + * ddbridge-hw.h: Digital Devices bridge hardware maps + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _DDBRIDGE_HW_H_ +#define _DDBRIDGE_HW_H_ + +#include "ddbridge.h" + +/******************************************************************************/ + +#define DDVID 0xdd01 /* Digital Devices Vendor ID */ + +/******************************************************************************/ + +struct ddb_device_id { + u16 vendor; + u16 device; + u16 subvendor; + u16 subdevice; + const struct ddb_info *info; +}; + +/******************************************************************************/ + +const struct ddb_info *get_ddb_info(u16 vendor, u16 device, + u16 subvendor, u16 subdevice); + +#endif /* _DDBRIDGE_HW_H */ diff --git a/drivers/media/pci/ddbridge/ddbridge-i2c.c b/drivers/media/pci/ddbridge/ddbridge-i2c.c new file mode 100644 index 000000000000..e4d39c3270ae --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-i2c.c @@ -0,0 +1,230 @@ +/* + * ddbridge-i2c.c: Digital Devices bridge i2c driver + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/io.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/timer.h> +#include <linux/i2c.h> +#include <linux/swab.h> +#include <linux/vmalloc.h> + +#include "ddbridge.h" +#include "ddbridge-i2c.h" +#include "ddbridge-regs.h" +#include "ddbridge-io.h" + +/******************************************************************************/ + +static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) +{ + struct ddb *dev = i2c->dev; + unsigned long stat; + u32 val; + + ddbwritel(dev, (adr << 9) | cmd, i2c->regs + I2C_COMMAND); + stat = wait_for_completion_timeout(&i2c->completion, HZ); + val = ddbreadl(dev, i2c->regs + I2C_COMMAND); + if (stat == 0) { + dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n", + dev->nr, i2c->nr, i2c->link); + { + u32 istat = ddbreadl(dev, INTERRUPT_STATUS); + + dev_err(dev->dev, "DDBridge IRS %08x\n", istat); + if (i2c->link) { + u32 listat = ddbreadl(dev, + DDB_LINK_TAG(i2c->link) | + INTERRUPT_STATUS); + + dev_err(dev->dev, "DDBridge link %u IRS %08x\n", + i2c->link, listat); + } + if (istat & 1) { + ddbwritel(dev, istat & 1, INTERRUPT_ACK); + } else { + u32 mon = ddbreadl(dev, + i2c->regs + I2C_MONITOR); + + dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n", + val, mon); + } + } + return -EIO; + } + if (val & 0x70000) + return -EIO; + return 0; +} + +static int ddb_i2c_master_xfer(struct i2c_adapter *adapter, + struct i2c_msg msg[], int num) +{ + struct ddb_i2c *i2c = (struct ddb_i2c *) i2c_get_adapdata(adapter); + struct ddb *dev = i2c->dev; + u8 addr = 0; + + addr = msg[0].addr; + if (msg[0].len > i2c->bsize) + return -EIO; + switch (num) { + case 1: + if (msg[0].flags & I2C_M_RD) { + ddbwritel(dev, msg[0].len << 16, + i2c->regs + I2C_TASKLENGTH); + if (ddb_i2c_cmd(i2c, addr, 3)) + break; + ddbcpyfrom(dev, msg[0].buf, + i2c->rbuf, msg[0].len); + return num; + } + ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len); + ddbwritel(dev, msg[0].len, i2c->regs + I2C_TASKLENGTH); + if (ddb_i2c_cmd(i2c, addr, 2)) + break; + return num; + case 2: + if ((msg[0].flags & I2C_M_RD) == I2C_M_RD) + break; + if ((msg[1].flags & I2C_M_RD) != I2C_M_RD) + break; + if (msg[1].len > i2c->bsize) + break; + ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len); + ddbwritel(dev, msg[0].len | (msg[1].len << 16), + i2c->regs + I2C_TASKLENGTH); + if (ddb_i2c_cmd(i2c, addr, 1)) + break; + ddbcpyfrom(dev, msg[1].buf, + i2c->rbuf, + msg[1].len); + return num; + default: + break; + } + return -EIO; +} + +static u32 ddb_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm ddb_i2c_algo = { + .master_xfer = ddb_i2c_master_xfer, + .functionality = ddb_i2c_functionality, +}; + +void ddb_i2c_release(struct ddb *dev) +{ + int i; + struct ddb_i2c *i2c; + + for (i = 0; i < dev->i2c_num; i++) { + i2c = &dev->i2c[i]; + i2c_del_adapter(&i2c->adap); + } +} + +static void i2c_handler(unsigned long priv) +{ + struct ddb_i2c *i2c = (struct ddb_i2c *) priv; + + complete(&i2c->completion); +} + +static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c, + const struct ddb_regmap *regmap, int link, + int i, int num) +{ + struct i2c_adapter *adap; + + i2c->nr = i; + i2c->dev = dev; + i2c->link = link; + i2c->bsize = regmap->i2c_buf->size; + i2c->wbuf = DDB_LINK_TAG(link) | + (regmap->i2c_buf->base + i2c->bsize * i); + i2c->rbuf = i2c->wbuf; /* + i2c->bsize / 2 */ + i2c->regs = DDB_LINK_TAG(link) | + (regmap->i2c->base + regmap->i2c->size * i); + ddbwritel(dev, I2C_SPEED_100, i2c->regs + I2C_TIMING); + ddbwritel(dev, ((i2c->rbuf & 0xffff) << 16) | (i2c->wbuf & 0xffff), + i2c->regs + I2C_TASKADDRESS); + init_completion(&i2c->completion); + + adap = &i2c->adap; + i2c_set_adapdata(adap, i2c); +#ifdef I2C_ADAP_CLASS_TV_DIGITAL + adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG; +#else +#ifdef I2C_CLASS_TV_ANALOG + adap->class = I2C_CLASS_TV_ANALOG; +#endif +#endif + snprintf(adap->name, I2C_NAME_SIZE, "ddbridge_%02x.%x.%x", + dev->nr, i2c->link, i); + adap->algo = &ddb_i2c_algo; + adap->algo_data = (void *)i2c; + adap->dev.parent = dev->dev; + return i2c_add_adapter(adap); +} + +int ddb_i2c_init(struct ddb *dev) +{ + int stat = 0; + u32 i, j, num = 0, l, base; + struct ddb_i2c *i2c; + struct i2c_adapter *adap; + const struct ddb_regmap *regmap; + + for (l = 0; l < DDB_MAX_LINK; l++) { + if (!dev->link[l].info) + continue; + regmap = dev->link[l].info->regmap; + if (!regmap || !regmap->i2c) + continue; + base = regmap->irq_base_i2c; + for (i = 0; i < regmap->i2c->num; i++) { + if (!(dev->link[l].info->i2c_mask & (1 << i))) + continue; + i2c = &dev->i2c[num]; + dev->handler_data[l][i + base] = (unsigned long) i2c; + dev->handler[l][i + base] = i2c_handler; + stat = ddb_i2c_add(dev, i2c, regmap, l, i, num); + if (stat) + break; + num++; + } + } + if (stat) { + for (j = 0; j < num; j++) { + i2c = &dev->i2c[j]; + adap = &i2c->adap; + i2c_del_adapter(adap); + } + } else + dev->i2c_num = num; + return stat; +} diff --git a/drivers/media/pci/ddbridge/ddbridge-i2c.h b/drivers/media/pci/ddbridge/ddbridge-i2c.h new file mode 100644 index 000000000000..7ed220506c05 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-i2c.h @@ -0,0 +1,112 @@ +/* + * ddbridge-i2c.c: Digital Devices bridge i2c driver + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __DDBRIDGE_I2C_H__ +#define __DDBRIDGE_I2C_H__ + +#include <linux/i2c.h> + +#include "ddbridge.h" + +/******************************************************************************/ + +void ddb_i2c_release(struct ddb *dev); +int ddb_i2c_init(struct ddb *dev); + +/******************************************************************************/ + +static int __maybe_unused i2c_io(struct i2c_adapter *adapter, u8 adr, + u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) +{ + struct i2c_msg msgs[2] = { { .addr = adr, .flags = 0, + .buf = wbuf, .len = wlen }, + { .addr = adr, .flags = I2C_M_RD, + .buf = rbuf, .len = rlen } }; + + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int __maybe_unused i2c_write(struct i2c_adapter *adap, u8 adr, + u8 *data, int len) +{ + struct i2c_msg msg = { .addr = adr, .flags = 0, + .buf = data, .len = len }; + + return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; +} + +static int __maybe_unused i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) +{ + struct i2c_msg msgs[1] = { { .addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; +} + +static int __maybe_unused i2c_read_regs(struct i2c_adapter *adapter, + u8 adr, u8 reg, u8 *val, u8 len) +{ + struct i2c_msg msgs[2] = { { .addr = adr, .flags = 0, + .buf = ®, .len = 1 }, + { .addr = adr, .flags = I2C_M_RD, + .buf = val, .len = len } }; + + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int __maybe_unused i2c_read_regs16(struct i2c_adapter *adapter, + u8 adr, u16 reg, u8 *val, u8 len) +{ + u8 msg[2] = { reg >> 8, reg & 0xff }; + struct i2c_msg msgs[2] = { { .addr = adr, .flags = 0, + .buf = msg, .len = 2 }, + { .addr = adr, .flags = I2C_M_RD, + .buf = val, .len = len } }; + + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int __maybe_unused i2c_write_reg16(struct i2c_adapter *adap, + u8 adr, u16 reg, u8 val) +{ + u8 msg[3] = { reg >> 8, reg & 0xff, val }; + + return i2c_write(adap, adr, msg, 3); +} + +static int __maybe_unused i2c_write_reg(struct i2c_adapter *adap, + u8 adr, u8 reg, u8 val) +{ + u8 msg[2] = { reg, val }; + + return i2c_write(adap, adr, msg, 2); +} + +static int __maybe_unused i2c_read_reg16(struct i2c_adapter *adapter, + u8 adr, u16 reg, u8 *val) +{ + return i2c_read_regs16(adapter, adr, reg, val, 1); +} + +static int __maybe_unused i2c_read_reg(struct i2c_adapter *adapter, + u8 adr, u8 reg, u8 *val) +{ + return i2c_read_regs(adapter, adr, reg, val, 1); +} + +#endif /* __DDBRIDGE_I2C_H__ */ diff --git a/drivers/media/pci/ddbridge/ddbridge-io.h b/drivers/media/pci/ddbridge/ddbridge-io.h new file mode 100644 index 000000000000..a4c6bbe09168 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-io.h @@ -0,0 +1,71 @@ +/* + * ddbridge-io.h: Digital Devices bridge I/O inline functions + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __DDBRIDGE_IO_H__ +#define __DDBRIDGE_IO_H__ + +#include <linux/io.h> + +#include "ddbridge.h" + +/******************************************************************************/ + +static inline u32 ddblreadl(struct ddb_link *link, u32 adr) +{ + return readl(link->dev->regs + adr); +} + +static inline void ddblwritel(struct ddb_link *link, u32 val, u32 adr) +{ + writel(val, link->dev->regs + adr); +} + +static inline u32 ddbreadl(struct ddb *dev, u32 adr) +{ + return readl(dev->regs + adr); +} + +static inline void ddbwritel(struct ddb *dev, u32 val, u32 adr) +{ + writel(val, dev->regs + adr); +} + +static inline void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count) +{ + return memcpy_toio(dev->regs + adr, src, count); +} + +static inline void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count) +{ + return memcpy_fromio(dst, dev->regs + adr, count); +} + +static inline u32 safe_ddbreadl(struct ddb *dev, u32 adr) +{ + u32 val = ddbreadl(dev, adr); + + /* (ddb)readl returns (uint)-1 (all bits set) on failure, catch that */ + if (val == ~0) { + dev_err(&dev->pdev->dev, "ddbreadl failure, adr=%08x\n", adr); + return 0; + } + + return val; +} + +#endif /* __DDBRIDGE_IO_H__ */ diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c new file mode 100644 index 000000000000..ccac7fe31336 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-main.c @@ -0,0 +1,346 @@ +/* + * ddbridge.c: Digital Devices PCIe bridge driver + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/io.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/timer.h> +#include <linux/i2c.h> +#include <linux/swab.h> +#include <linux/vmalloc.h> + +#include "ddbridge.h" +#include "ddbridge-i2c.h" +#include "ddbridge-regs.h" +#include "ddbridge-hw.h" +#include "ddbridge-io.h" + +/****************************************************************************/ +/* module parameters */ + +#ifdef CONFIG_PCI_MSI +#ifdef CONFIG_DVB_DDBRIDGE_MSIENABLE +static int msi = 1; +#else +static int msi; +#endif +module_param(msi, int, 0444); +#ifdef CONFIG_DVB_DDBRIDGE_MSIENABLE +MODULE_PARM_DESC(msi, "Control MSI interrupts: 0-disable, 1-enable (default)"); +#else +MODULE_PARM_DESC(msi, "Control MSI interrupts: 0-disable (default), 1-enable"); +#endif +#endif + +int ci_bitrate = 70000; +module_param(ci_bitrate, int, 0444); +MODULE_PARM_DESC(ci_bitrate, " Bitrate in KHz for output to CI."); + +int ts_loop = -1; +module_param(ts_loop, int, 0444); +MODULE_PARM_DESC(ts_loop, "TS in/out test loop on port ts_loop"); + +int xo2_speed = 2; +module_param(xo2_speed, int, 0444); +MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards"); + +#ifdef __arm__ +int alt_dma = 1; +#else +int alt_dma; +#endif +module_param(alt_dma, int, 0444); +MODULE_PARM_DESC(alt_dma, "use alternative DMA buffer handling"); + +int no_init; +module_param(no_init, int, 0444); +MODULE_PARM_DESC(no_init, "do not initialize most devices"); + +int stv0910_single; +module_param(stv0910_single, int, 0444); +MODULE_PARM_DESC(stv0910_single, "use stv0910 cards as single demods"); + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void ddb_irq_disable(struct ddb *dev) +{ + ddbwritel(dev, 0, INTERRUPT_ENABLE); + ddbwritel(dev, 0, MSI1_ENABLE); +} + +static void ddb_irq_exit(struct ddb *dev) +{ + ddb_irq_disable(dev); + if (dev->msi == 2) + free_irq(dev->pdev->irq + 1, dev); + free_irq(dev->pdev->irq, dev); +#ifdef CONFIG_PCI_MSI + if (dev->msi) + pci_disable_msi(dev->pdev); +#endif +} + +static void ddb_remove(struct pci_dev *pdev) +{ + struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev); + + ddb_device_destroy(dev); + ddb_ports_detach(dev); + ddb_i2c_release(dev); + + ddb_irq_exit(dev); + ddb_ports_release(dev); + ddb_buffers_free(dev); + + ddb_unmap(dev); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); +} + +#ifdef CONFIG_PCI_MSI +static void ddb_irq_msi(struct ddb *dev, int nr) +{ + int stat; + + if (msi && pci_msi_enabled()) { + stat = pci_alloc_irq_vectors(dev->pdev, 1, nr, PCI_IRQ_MSI); + if (stat >= 1) { + dev->msi = stat; + dev_info(dev->dev, "using %d MSI interrupt(s)\n", + dev->msi); + } else + dev_info(dev->dev, "MSI not available.\n"); + } +} +#endif + +static int ddb_irq_init(struct ddb *dev) +{ + int stat; + int irq_flag = IRQF_SHARED; + + ddbwritel(dev, 0x00000000, INTERRUPT_ENABLE); + ddbwritel(dev, 0x00000000, MSI1_ENABLE); + ddbwritel(dev, 0x00000000, MSI2_ENABLE); + ddbwritel(dev, 0x00000000, MSI3_ENABLE); + ddbwritel(dev, 0x00000000, MSI4_ENABLE); + ddbwritel(dev, 0x00000000, MSI5_ENABLE); + ddbwritel(dev, 0x00000000, MSI6_ENABLE); + ddbwritel(dev, 0x00000000, MSI7_ENABLE); + +#ifdef CONFIG_PCI_MSI + ddb_irq_msi(dev, 2); + + if (dev->msi) + irq_flag = 0; + if (dev->msi == 2) { + stat = request_irq(dev->pdev->irq, ddb_irq_handler0, + irq_flag, "ddbridge", (void *) dev); + if (stat < 0) + return stat; + stat = request_irq(dev->pdev->irq + 1, ddb_irq_handler1, + irq_flag, "ddbridge", (void *) dev); + if (stat < 0) { + free_irq(dev->pdev->irq, dev); + return stat; + } + } else +#endif + { + stat = request_irq(dev->pdev->irq, ddb_irq_handler, + irq_flag, "ddbridge", (void *) dev); + if (stat < 0) + return stat; + } + if (dev->msi == 2) { + ddbwritel(dev, 0x0fffff00, INTERRUPT_ENABLE); + ddbwritel(dev, 0x0000000f, MSI1_ENABLE); + } else { + ddbwritel(dev, 0x0fffff0f, INTERRUPT_ENABLE); + ddbwritel(dev, 0x00000000, MSI1_ENABLE); + } + return stat; +} + +static int ddb_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct ddb *dev; + int stat = 0; + + if (pci_enable_device(pdev) < 0) + return -ENODEV; + + pci_set_master(pdev); + + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) + return -ENODEV; + + dev = vzalloc(sizeof(struct ddb)); + if (dev == NULL) + return -ENOMEM; + + mutex_init(&dev->mutex); + dev->has_dma = 1; + dev->pdev = pdev; + dev->dev = &pdev->dev; + pci_set_drvdata(pdev, dev); + + dev->link[0].ids.vendor = id->vendor; + dev->link[0].ids.device = id->device; + dev->link[0].ids.subvendor = id->subvendor; + dev->link[0].ids.subdevice = pdev->subsystem_device; + + dev->link[0].dev = dev; + dev->link[0].info = get_ddb_info(id->vendor, id->device, + id->subvendor, pdev->subsystem_device); + + dev_info(&pdev->dev, "detected %s\n", dev->link[0].info->name); + + dev->regs_len = pci_resource_len(dev->pdev, 0); + dev->regs = ioremap(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); + + if (!dev->regs) { + dev_err(&pdev->dev, "not enough memory for register map\n"); + stat = -ENOMEM; + goto fail; + } + if (ddbreadl(dev, 0) == 0xffffffff) { + dev_err(&pdev->dev, "cannot read registers\n"); + stat = -ENODEV; + goto fail; + } + + dev->link[0].ids.hwid = ddbreadl(dev, 0); + dev->link[0].ids.regmapid = ddbreadl(dev, 4); + + dev_info(&pdev->dev, "HW %08x REGMAP %08x\n", + dev->link[0].ids.hwid, dev->link[0].ids.regmapid); + + ddbwritel(dev, 0, DMA_BASE_READ); + ddbwritel(dev, 0, DMA_BASE_WRITE); + + stat = ddb_irq_init(dev); + if (stat < 0) + goto fail0; + + if (ddb_init(dev) == 0) + return 0; + + ddb_irq_exit(dev); +fail0: + dev_err(&pdev->dev, "fail0\n"); + if (dev->msi) + pci_disable_msi(dev->pdev); +fail: + dev_err(&pdev->dev, "fail\n"); + + ddb_unmap(dev); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); + return -1; +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +#define DDB_DEVICE_ANY(_device) \ + { PCI_DEVICE_SUB(DDVID, _device, DDVID, PCI_ANY_ID) } + +static const struct pci_device_id ddb_id_table[] = { + DDB_DEVICE_ANY(0x0002), + DDB_DEVICE_ANY(0x0003), + DDB_DEVICE_ANY(0x0005), + DDB_DEVICE_ANY(0x0006), + DDB_DEVICE_ANY(0x0007), + DDB_DEVICE_ANY(0x0008), + DDB_DEVICE_ANY(0x0011), + DDB_DEVICE_ANY(0x0012), + DDB_DEVICE_ANY(0x0013), + DDB_DEVICE_ANY(0x0201), + DDB_DEVICE_ANY(0x0203), + DDB_DEVICE_ANY(0x0210), + DDB_DEVICE_ANY(0x0220), + DDB_DEVICE_ANY(0x0320), + DDB_DEVICE_ANY(0x0321), + DDB_DEVICE_ANY(0x0322), + DDB_DEVICE_ANY(0x0323), + DDB_DEVICE_ANY(0x0328), + DDB_DEVICE_ANY(0x0329), + {0} +}; + +MODULE_DEVICE_TABLE(pci, ddb_id_table); + +static struct pci_driver ddb_pci_driver = { + .name = "ddbridge", + .id_table = ddb_id_table, + .probe = ddb_probe, + .remove = ddb_remove, +}; + +static __init int module_init_ddbridge(void) +{ + int stat = -1; + + pr_info("Digital Devices PCIE bridge driver " + DDBRIDGE_VERSION + ", Copyright (C) 2010-17 Digital Devices GmbH\n"); + if (ddb_class_create() < 0) + return -1; + ddb_wq = create_workqueue("ddbridge"); + if (ddb_wq == NULL) + goto exit1; + stat = pci_register_driver(&ddb_pci_driver); + if (stat < 0) + goto exit2; + return stat; +exit2: + destroy_workqueue(ddb_wq); +exit1: + ddb_class_destroy(); + return stat; +} + +static __exit void module_exit_ddbridge(void) +{ + pci_unregister_driver(&ddb_pci_driver); + destroy_workqueue(ddb_wq); + ddb_class_destroy(); +} + +module_init(module_init_ddbridge); +module_exit(module_exit_ddbridge); + +MODULE_DESCRIPTION("Digital Devices PCIe Bridge"); +MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DDBRIDGE_VERSION); diff --git a/drivers/media/pci/ddbridge/ddbridge-maxs8.c b/drivers/media/pci/ddbridge/ddbridge-maxs8.c new file mode 100644 index 000000000000..f8a53bc7c86c --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-maxs8.c @@ -0,0 +1,444 @@ +/* + * ddbridge-maxs8.c: Digital Devices bridge MaxS4/8 support + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/io.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/timer.h> +#include <linux/i2c.h> +#include <linux/swab.h> +#include <linux/vmalloc.h> + +#include "ddbridge.h" +#include "ddbridge-regs.h" +#include "ddbridge-io.h" + +#include "ddbridge-maxs8.h" +#include "mxl5xx.h" + +/******************************************************************************/ + +/* MaxS4/8 related modparams */ +static int fmode; +module_param(fmode, int, 0444); +MODULE_PARM_DESC(fmode, "frontend emulation mode"); + +static int fmode_sat = -1; +module_param(fmode_sat, int, 0444); +MODULE_PARM_DESC(fmode_sat, "set frontend emulation mode sat"); + +static int old_quattro; +module_param(old_quattro, int, 0444); +MODULE_PARM_DESC(old_quattro, "old quattro LNB input order "); + +/******************************************************************************/ + +static int lnb_command(struct ddb *dev, u32 link, u32 lnb, u32 cmd) +{ + u32 c, v = 0, tag = DDB_LINK_TAG(link); + + v = LNB_TONE & (dev->link[link].lnb.tone << (15 - lnb)); + ddbwritel(dev, cmd | v, tag | LNB_CONTROL(lnb)); + for (c = 0; c < 10; c++) { + v = ddbreadl(dev, tag | LNB_CONTROL(lnb)); + if ((v & LNB_BUSY) == 0) + break; + msleep(20); + } + if (c == 10) + dev_info(dev->dev, "%s lnb = %08x cmd = %08x\n", + __func__, lnb, cmd); + return 0; +} + +static int max_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + struct ddb_input *input = fe->sec_priv; + struct ddb_port *port = input->port; + struct ddb *dev = port->dev; + struct ddb_dvb *dvb = &port->dvb[input->nr & 1]; + u32 tag = DDB_LINK_TAG(port->lnr); + int i; + u32 fmode = dev->link[port->lnr].lnb.fmode; + + if (fmode == 2 || fmode == 1) + return 0; + if (dvb->diseqc_send_master_cmd) + dvb->diseqc_send_master_cmd(fe, cmd); + + mutex_lock(&dev->link[port->lnr].lnb.lock); + ddbwritel(dev, 0, tag | LNB_BUF_LEVEL(dvb->input)); + for (i = 0; i < cmd->msg_len; i++) + ddbwritel(dev, cmd->msg[i], tag | LNB_BUF_WRITE(dvb->input)); + lnb_command(dev, port->lnr, dvb->input, LNB_CMD_DISEQC); + mutex_unlock(&dev->link[port->lnr].lnb.lock); + return 0; +} + +static int lnb_send_diseqc(struct ddb *dev, u32 link, u32 input, + struct dvb_diseqc_master_cmd *cmd) +{ + u32 tag = DDB_LINK_TAG(link); + int i; + + ddbwritel(dev, 0, tag | LNB_BUF_LEVEL(input)); + for (i = 0; i < cmd->msg_len; i++) + ddbwritel(dev, cmd->msg[i], tag | LNB_BUF_WRITE(input)); + lnb_command(dev, link, input, LNB_CMD_DISEQC); + return 0; +} + +static int lnb_set_sat(struct ddb *dev, u32 link, u32 input, u32 sat, u32 band, + u32 hor) +{ + struct dvb_diseqc_master_cmd cmd = { + .msg = {0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, + .msg_len = 4 + }; + cmd.msg[3] = 0xf0 | (((sat << 2) & 0x0c) | (band ? 1 : 0) | + (hor ? 2 : 0)); + return lnb_send_diseqc(dev, link, input, &cmd); +} + +static int lnb_set_tone(struct ddb *dev, u32 link, u32 input, + enum fe_sec_tone_mode tone) +{ + int s = 0; + u32 mask = (1ULL << input); + + switch (tone) { + case SEC_TONE_OFF: + if (!(dev->link[link].lnb.tone & mask)) + return 0; + dev->link[link].lnb.tone &= ~(1ULL << input); + break; + case SEC_TONE_ON: + if (dev->link[link].lnb.tone & mask) + return 0; + dev->link[link].lnb.tone |= (1ULL << input); + break; + default: + s = -EINVAL; + break; + } + if (!s) + s = lnb_command(dev, link, input, LNB_CMD_NOP); + return s; +} + +static int lnb_set_voltage(struct ddb *dev, u32 link, u32 input, + enum fe_sec_voltage voltage) +{ + int s = 0; + + if (dev->link[link].lnb.oldvoltage[input] == voltage) + return 0; + switch (voltage) { + case SEC_VOLTAGE_OFF: + if (dev->link[link].lnb.voltage[input]) + return 0; + lnb_command(dev, link, input, LNB_CMD_OFF); + break; + case SEC_VOLTAGE_13: + lnb_command(dev, link, input, LNB_CMD_LOW); + break; + case SEC_VOLTAGE_18: + lnb_command(dev, link, input, LNB_CMD_HIGH); + break; + default: + s = -EINVAL; + break; + } + dev->link[link].lnb.oldvoltage[input] = voltage; + return s; +} + +static int max_set_input_unlocked(struct dvb_frontend *fe, int in) +{ + struct ddb_input *input = fe->sec_priv; + struct ddb_port *port = input->port; + struct ddb *dev = port->dev; + struct ddb_dvb *dvb = &port->dvb[input->nr & 1]; + int res = 0; + + if (in > 3) + return -EINVAL; + if (dvb->input != in) { + u32 bit = (1ULL << input->nr); + u32 obit = + dev->link[port->lnr].lnb.voltage[dvb->input & 3] & bit; + + dev->link[port->lnr].lnb.voltage[dvb->input & 3] &= ~bit; + dvb->input = in; + dev->link[port->lnr].lnb.voltage[dvb->input & 3] |= obit; + } + res = dvb->set_input(fe, in); + return res; +} + +static int max_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) +{ + struct ddb_input *input = fe->sec_priv; + struct ddb_port *port = input->port; + struct ddb *dev = port->dev; + struct ddb_dvb *dvb = &port->dvb[input->nr & 1]; + int tuner = 0; + int res = 0; + u32 fmode = dev->link[port->lnr].lnb.fmode; + + mutex_lock(&dev->link[port->lnr].lnb.lock); + dvb->tone = tone; + switch (fmode) { + default: + case 0: + case 3: + res = lnb_set_tone(dev, port->lnr, dvb->input, tone); + break; + case 1: + case 2: + if (old_quattro) { + if (dvb->tone == SEC_TONE_ON) + tuner |= 2; + if (dvb->voltage == SEC_VOLTAGE_18) + tuner |= 1; + } else { + if (dvb->tone == SEC_TONE_ON) + tuner |= 1; + if (dvb->voltage == SEC_VOLTAGE_18) + tuner |= 2; + } + res = max_set_input_unlocked(fe, tuner); + break; + } + mutex_unlock(&dev->link[port->lnr].lnb.lock); + return res; +} + +static int max_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) +{ + struct ddb_input *input = fe->sec_priv; + struct ddb_port *port = input->port; + struct ddb *dev = port->dev; + struct ddb_dvb *dvb = &port->dvb[input->nr & 1]; + int tuner = 0; + u32 nv, ov = dev->link[port->lnr].lnb.voltages; + int res = 0; + u32 fmode = dev->link[port->lnr].lnb.fmode; + + mutex_lock(&dev->link[port->lnr].lnb.lock); + dvb->voltage = voltage; + + switch (fmode) { + case 3: + default: + case 0: + if (fmode == 3) + max_set_input_unlocked(fe, 0); + if (voltage == SEC_VOLTAGE_OFF) + dev->link[port->lnr].lnb.voltage[dvb->input] &= + ~(1ULL << input->nr); + else + dev->link[port->lnr].lnb.voltage[dvb->input] |= + (1ULL << input->nr); + + res = lnb_set_voltage(dev, port->lnr, dvb->input, voltage); + break; + case 1: + case 2: + if (voltage == SEC_VOLTAGE_OFF) + dev->link[port->lnr].lnb.voltages &= + ~(1ULL << input->nr); + else + dev->link[port->lnr].lnb.voltages |= + (1ULL << input->nr); + + nv = dev->link[port->lnr].lnb.voltages; + + if (old_quattro) { + if (dvb->tone == SEC_TONE_ON) + tuner |= 2; + if (dvb->voltage == SEC_VOLTAGE_18) + tuner |= 1; + } else { + if (dvb->tone == SEC_TONE_ON) + tuner |= 1; + if (dvb->voltage == SEC_VOLTAGE_18) + tuner |= 2; + } + res = max_set_input_unlocked(fe, tuner); + + if (nv != ov) { + if (nv) { + lnb_set_voltage(dev, + port->lnr, 0, SEC_VOLTAGE_13); + if (fmode == 1) { + lnb_set_voltage(dev, port->lnr, + 0, SEC_VOLTAGE_13); + if (old_quattro) { + lnb_set_voltage(dev, port->lnr, + 1, SEC_VOLTAGE_18); + lnb_set_voltage(dev, port->lnr, + 2, SEC_VOLTAGE_13); + } else { + lnb_set_voltage(dev, port->lnr, + 1, SEC_VOLTAGE_13); + lnb_set_voltage(dev, port->lnr, + 2, SEC_VOLTAGE_18); + } + lnb_set_voltage(dev, port->lnr, + 3, SEC_VOLTAGE_18); + } + } else { + lnb_set_voltage(dev, port->lnr, + 0, SEC_VOLTAGE_OFF); + if (fmode == 1) { + lnb_set_voltage(dev, port->lnr, + 1, SEC_VOLTAGE_OFF); + lnb_set_voltage(dev, port->lnr, + 2, SEC_VOLTAGE_OFF); + lnb_set_voltage(dev, port->lnr, + 3, SEC_VOLTAGE_OFF); + } + } + } + break; + } + mutex_unlock(&dev->link[port->lnr].lnb.lock); + return res; +} + +static int max_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) +{ + + return 0; +} + +static int max_send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst) +{ + return 0; +} + +static int mxl_fw_read(void *priv, u8 *buf, u32 len) +{ + struct ddb_link *link = priv; + struct ddb *dev = link->dev; + + dev_info(dev->dev, "Read mxl_fw from link %u\n", link->nr); + + return ddbridge_flashread(dev, link->nr, buf, 0xc0000, len); +} + +int lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm) +{ + u32 l = link->nr; + + if (link->lnb.fmode == fm) + return 0; + dev_info(dev->dev, "Set fmode link %u = %u\n", l, fm); + mutex_lock(&link->lnb.lock); + if (fm == 2 || fm == 1) { + if (fmode_sat >= 0) { + lnb_set_sat(dev, l, 0, fmode_sat, 0, 0); + if (old_quattro) { + lnb_set_sat(dev, l, 1, fmode_sat, 0, 1); + lnb_set_sat(dev, l, 2, fmode_sat, 1, 0); + } else { + lnb_set_sat(dev, l, 1, fmode_sat, 1, 0); + lnb_set_sat(dev, l, 2, fmode_sat, 0, 1); + } + lnb_set_sat(dev, l, 3, fmode_sat, 1, 1); + } + lnb_set_tone(dev, l, 0, SEC_TONE_OFF); + if (old_quattro) { + lnb_set_tone(dev, l, 1, SEC_TONE_OFF); + lnb_set_tone(dev, l, 2, SEC_TONE_ON); + } else { + lnb_set_tone(dev, l, 1, SEC_TONE_ON); + lnb_set_tone(dev, l, 2, SEC_TONE_OFF); + } + lnb_set_tone(dev, l, 3, SEC_TONE_ON); + } + link->lnb.fmode = fm; + mutex_unlock(&link->lnb.lock); + return 0; +} + +static struct mxl5xx_cfg mxl5xx = { + .adr = 0x60, + .type = 0x01, + .clk = 27000000, + .ts_clk = 139, + .cap = 12, + .fw_read = mxl_fw_read, +}; + +int fe_attach_mxl5xx(struct ddb_input *input) +{ + struct ddb *dev = input->port->dev; + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct ddb_port *port = input->port; + struct ddb_link *link = &dev->link[port->lnr]; + struct mxl5xx_cfg cfg; + int demod, tuner; + + cfg = mxl5xx; + cfg.fw_priv = link; + dvb->set_input = NULL; + + demod = input->nr; + tuner = demod & 3; + if (fmode == 3) + tuner = 0; + + dvb->fe = dvb_attach(mxl5xx_attach, i2c, &cfg, + demod, tuner, &dvb->set_input); + + if (!dvb->fe) { + dev_err(dev->dev, "No MXL5XX found!\n"); + return -ENODEV; + } + + if (!dvb->set_input) { + dev_err(dev->dev, "No mxl5xx_set_input function pointer!\n"); + return -ENODEV; + } + + if (input->nr < 4) { + lnb_command(dev, port->lnr, input->nr, LNB_CMD_INIT); + lnb_set_voltage(dev, port->lnr, input->nr, SEC_VOLTAGE_OFF); + } + lnb_init_fmode(dev, link, fmode); + + dvb->fe->ops.set_voltage = max_set_voltage; + dvb->fe->ops.enable_high_lnb_voltage = max_enable_high_lnb_voltage; + dvb->fe->ops.set_tone = max_set_tone; + dvb->diseqc_send_master_cmd = dvb->fe->ops.diseqc_send_master_cmd; + dvb->fe->ops.diseqc_send_master_cmd = max_send_master_cmd; + dvb->fe->ops.diseqc_send_burst = max_send_burst; + dvb->fe->sec_priv = input; + dvb->input = tuner; + return 0; +} diff --git a/drivers/media/pci/ddbridge/ddbridge-maxs8.h b/drivers/media/pci/ddbridge/ddbridge-maxs8.h new file mode 100644 index 000000000000..bb8884811a46 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-maxs8.h @@ -0,0 +1,29 @@ +/* + * ddbridge-maxs8.h: Digital Devices bridge MaxS4/8 support + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _DDBRIDGE_MAXS8_H_ +#define _DDBRIDGE_MAXS8_H_ + +#include "ddbridge.h" + +/******************************************************************************/ + +int lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm); +int fe_attach_mxl5xx(struct ddb_input *input); + +#endif /* _DDBRIDGE_MAXS8_H */ diff --git a/drivers/media/pci/ddbridge/ddbridge-regs.h b/drivers/media/pci/ddbridge/ddbridge-regs.h index 98cebb97d64f..9d44f8d3af75 100644 --- a/drivers/media/pci/ddbridge/ddbridge-regs.h +++ b/drivers/media/pci/ddbridge/ddbridge-regs.h @@ -1,7 +1,7 @@ /* * ddbridge-regs.h: Digital Devices PCIe bridge driver * - * Copyright (C) 2010-2011 Digital Devices GmbH + * Copyright (C) 2010-2017 Digital Devices GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -17,20 +17,26 @@ * http://www.gnu.org/copyleft/gpl.html */ -/* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */ +/* ------------------------------------------------------------------------- */ +/* SPI Controller */ -/* Register Definitions */ +#define SPI_CONTROL 0x10 +#define SPI_DATA 0x14 -#define CUR_REGISTERMAP_VERSION 0x10000 +/* ------------------------------------------------------------------------- */ +/* GPIO */ -#define HARDWARE_VERSION 0x00 -#define REGISTERMAP_VERSION 0x04 +#define GPIO_OUTPUT 0x20 +#define GPIO_INPUT 0x24 +#define GPIO_DIRECTION 0x28 /* ------------------------------------------------------------------------- */ -/* SPI Controller */ +/* MDIO */ -#define SPI_CONTROL 0x10 -#define SPI_DATA 0x14 +#define MDIO_CTRL 0x20 +#define MDIO_ADR 0x24 +#define MDIO_REG 0x28 +#define MDIO_VAL 0x2C /* ------------------------------------------------------------------------- */ @@ -38,14 +44,14 @@ /* ------------------------------------------------------------------------- */ -/* Interrupt controller */ -/* How many MSI's are available depends on HW (Min 2 max 8) */ -/* How many are usable also depends on Host platform */ +/* Interrupt controller + * How many MSI's are available depends on HW (Min 2 max 8) + * How many are usable also depends on Host platform + */ #define INTERRUPT_BASE (0x40) #define INTERRUPT_ENABLE (INTERRUPT_BASE + 0x00) -#define MSI0_ENABLE (INTERRUPT_BASE + 0x00) #define MSI1_ENABLE (INTERRUPT_BASE + 0x04) #define MSI2_ENABLE (INTERRUPT_BASE + 0x08) #define MSI3_ENABLE (INTERRUPT_BASE + 0x0C) @@ -57,59 +63,31 @@ #define INTERRUPT_STATUS (INTERRUPT_BASE + 0x20) #define INTERRUPT_ACK (INTERRUPT_BASE + 0x20) -#define INTMASK_I2C1 (0x00000001) -#define INTMASK_I2C2 (0x00000002) -#define INTMASK_I2C3 (0x00000004) -#define INTMASK_I2C4 (0x00000008) - -#define INTMASK_CIRQ1 (0x00000010) -#define INTMASK_CIRQ2 (0x00000020) -#define INTMASK_CIRQ3 (0x00000040) -#define INTMASK_CIRQ4 (0x00000080) - -#define INTMASK_TSINPUT1 (0x00000100) -#define INTMASK_TSINPUT2 (0x00000200) -#define INTMASK_TSINPUT3 (0x00000400) -#define INTMASK_TSINPUT4 (0x00000800) -#define INTMASK_TSINPUT5 (0x00001000) -#define INTMASK_TSINPUT6 (0x00002000) -#define INTMASK_TSINPUT7 (0x00004000) -#define INTMASK_TSINPUT8 (0x00008000) - -#define INTMASK_TSOUTPUT1 (0x00010000) -#define INTMASK_TSOUTPUT2 (0x00020000) -#define INTMASK_TSOUTPUT3 (0x00040000) -#define INTMASK_TSOUTPUT4 (0x00080000) +/* Temperature Monitor ( 2x LM75A @ 0x90,0x92 I2c ) */ +#define TEMPMON_BASE (0x1c0) +#define TEMPMON_CONTROL (TEMPMON_BASE + 0x00) + +#define TEMPMON_CONTROL_AUTOSCAN (0x00000002) +#define TEMPMON_CONTROL_INTENABLE (0x00000004) +#define TEMPMON_CONTROL_OVERTEMP (0x00008000) + +/* SHORT Temperature in Celsius x 256 */ +#define TEMPMON_SENSOR0 (TEMPMON_BASE + 0x04) +#define TEMPMON_SENSOR1 (TEMPMON_BASE + 0x08) + +#define TEMPMON_FANCONTROL (TEMPMON_BASE + 0x10) /* ------------------------------------------------------------------------- */ /* I2C Master Controller */ -#define I2C_BASE (0x80) /* Byte offset */ - #define I2C_COMMAND (0x00) #define I2C_TIMING (0x04) #define I2C_TASKLENGTH (0x08) /* High read, low write */ #define I2C_TASKADDRESS (0x0C) /* High read, low write */ - #define I2C_MONITOR (0x1C) -#define I2C_BASE_1 (I2C_BASE + 0x00) -#define I2C_BASE_2 (I2C_BASE + 0x20) -#define I2C_BASE_3 (I2C_BASE + 0x40) -#define I2C_BASE_4 (I2C_BASE + 0x60) - -#define I2C_BASE_N(i) (I2C_BASE + (i) * 0x20) - -#define I2C_TASKMEM_BASE (0x1000) /* Byte offset */ -#define I2C_TASKMEM_SIZE (0x1000) - #define I2C_SPEED_400 (0x04030404) -#define I2C_SPEED_200 (0x09080909) -#define I2C_SPEED_154 (0x0C0B0C0C) #define I2C_SPEED_100 (0x13121313) -#define I2C_SPEED_77 (0x19181919) -#define I2C_SPEED_50 (0x27262727) - /* ------------------------------------------------------------------------- */ /* DMA Controller */ @@ -117,35 +95,62 @@ #define DMA_BASE_WRITE (0x100) #define DMA_BASE_READ (0x140) -#define DMA_CONTROL (0x00) /* 64 */ -#define DMA_ERROR (0x04) /* 65 ( only read instance ) */ - -#define DMA_DIAG_CONTROL (0x1C) /* 71 */ -#define DMA_DIAG_PACKETCOUNTER_LOW (0x20) /* 72 */ -#define DMA_DIAG_PACKETCOUNTER_HIGH (0x24) /* 73 */ -#define DMA_DIAG_TIMECOUNTER_LOW (0x28) /* 74 */ -#define DMA_DIAG_TIMECOUNTER_HIGH (0x2C) /* 75 */ -#define DMA_DIAG_RECHECKCOUNTER (0x30) /* 76 ( Split completions on read ) */ -#define DMA_DIAG_WAITTIMEOUTINIT (0x34) /* 77 */ -#define DMA_DIAG_WAITOVERFLOWCOUNTER (0x38) /* 78 */ -#define DMA_DIAG_WAITCOUNTER (0x3C) /* 79 */ +#define TS_CONTROL(_io) (_io->regs + 0x00) +#define TS_CONTROL2(_io) (_io->regs + 0x04) /* ------------------------------------------------------------------------- */ /* DMA Buffer */ -#define TS_INPUT_BASE (0x200) -#define TS_INPUT_CONTROL(i) (TS_INPUT_BASE + (i) * 16 + 0x00) +#define DMA_BUFFER_CONTROL(_dma) (_dma->regs + 0x00) +#define DMA_BUFFER_ACK(_dma) (_dma->regs + 0x04) +#define DMA_BUFFER_CURRENT(_dma) (_dma->regs + 0x08) +#define DMA_BUFFER_SIZE(_dma) (_dma->regs + 0x0c) + +/* ------------------------------------------------------------------------- */ +/* CI Interface (only CI-Bridge) */ + +#define CI_BASE (0x400) +#define CI_CONTROL(i) (CI_BASE + (i) * 32 + 0x00) + +#define CI_DO_ATTRIBUTE_RW(i) (CI_BASE + (i) * 32 + 0x04) +#define CI_DO_IO_RW(i) (CI_BASE + (i) * 32 + 0x08) +#define CI_READDATA(i) (CI_BASE + (i) * 32 + 0x0c) +#define CI_DO_READ_ATTRIBUTES(i) (CI_BASE + (i) * 32 + 0x10) + +#define CI_RESET_CAM (0x00000001) +#define CI_POWER_ON (0x00000002) +#define CI_ENABLE (0x00000004) +#define CI_BYPASS_DISABLE (0x00000010) + +#define CI_CAM_READY (0x00010000) +#define CI_CAM_DETECT (0x00020000) +#define CI_READY (0x80000000) + +#define CI_READ_CMD (0x40000000) +#define CI_WRITE_CMD (0x80000000) + +#define CI_BUFFER_BASE (0x3000) +#define CI_BUFFER_SIZE (0x0800) + +#define CI_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE) + +/* ------------------------------------------------------------------------- */ +/* LNB commands (mxl5xx / Max S8) */ -#define TS_OUTPUT_BASE (0x280) -#define TS_OUTPUT_CONTROL(i) (TS_OUTPUT_BASE + (i) * 16 + 0x00) +#define LNB_BASE (0x400) +#define LNB_CONTROL(i) (LNB_BASE + (i) * 0x20 + 0x00) -#define DMA_BUFFER_BASE (0x300) +#define LNB_CMD (7ULL << 0) +#define LNB_CMD_NOP 0 +#define LNB_CMD_INIT 1 +#define LNB_CMD_LOW 3 +#define LNB_CMD_HIGH 4 +#define LNB_CMD_OFF 5 +#define LNB_CMD_DISEQC 6 -#define DMA_BUFFER_CONTROL(i) (DMA_BUFFER_BASE + (i) * 16 + 0x00) -#define DMA_BUFFER_ACK(i) (DMA_BUFFER_BASE + (i) * 16 + 0x04) -#define DMA_BUFFER_CURRENT(i) (DMA_BUFFER_BASE + (i) * 16 + 0x08) -#define DMA_BUFFER_SIZE(i) (DMA_BUFFER_BASE + (i) * 16 + 0x0c) +#define LNB_BUSY (1ULL << 4) +#define LNB_TONE (1ULL << 15) -#define DMA_BASE_ADDRESS_TABLE (0x2000) -#define DMA_BASE_ADDRESS_TABLE_ENTRIES (512) +#define LNB_BUF_LEVEL(i) (LNB_BASE + (i) * 0x20 + 0x10) +#define LNB_BUF_WRITE(i) (LNB_BASE + (i) * 0x20 + 0x14) diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h index 4a0e3283d646..e9afa96bd9df 100644 --- a/drivers/media/pci/ddbridge/ddbridge.h +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -1,7 +1,8 @@ /* * ddbridge.h: Digital Devices PCIe bridge driver * - * Copyright (C) 2010-2011 Digital Devices GmbH + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rmetzler@digitaldevices.de> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,15 +21,39 @@ #ifndef _DDBRIDGE_H_ #define _DDBRIDGE_H_ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/io.h> +#include <linux/pci.h> +#include <linux/timer.h> +#include <linux/i2c.h> +#include <linux/swab.h> +#include <linux/vmalloc.h> +#include <linux/workqueue.h> +#include <linux/kthread.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/spi/spi.h> +#include <linux/gpio.h> +#include <linux/completion.h> + #include <linux/types.h> #include <linux/sched.h> #include <linux/interrupt.h> -#include <linux/i2c.h> #include <linux/mutex.h> #include <asm/dma.h> -#include <linux/dvb/frontend.h> +#include <asm/irq.h> +#include <linux/io.h> +#include <linux/uaccess.h> + #include <linux/dvb/ca.h> #include <linux/socket.h> +#include <linux/device.h> +#include <linux/io.h> #include "dmxdev.h" #include "dvbdev.h" @@ -37,69 +62,122 @@ #include "dvb_ringbuffer.h" #include "dvb_ca_en50221.h" #include "dvb_net.h" -#include "cxd2099.h" -#define DDB_MAX_I2C 4 -#define DDB_MAX_PORT 4 -#define DDB_MAX_INPUT 8 -#define DDB_MAX_OUTPUT 4 +#define DDBRIDGE_VERSION "0.9.31intermediate-integrated" + +#define DDB_MAX_I2C 32 +#define DDB_MAX_PORT 32 +#define DDB_MAX_INPUT 64 +#define DDB_MAX_OUTPUT 32 #define DDB_MAX_LINK 4 #define DDB_LINK_SHIFT 28 #define DDB_LINK_TAG(_x) (_x << DDB_LINK_SHIFT) -#define DDB_XO2_TYPE_NONE 0 -#define DDB_XO2_TYPE_DUOFLEX 1 -#define DDB_XO2_TYPE_CI 2 +struct ddb_regset { + u32 base; + u32 num; + u32 size; +}; + +struct ddb_regmap { + u32 irq_base_i2c; + u32 irq_base_idma; + u32 irq_base_odma; + + const struct ddb_regset *i2c; + const struct ddb_regset *i2c_buf; + const struct ddb_regset *idma; + const struct ddb_regset *idma_buf; + const struct ddb_regset *odma; + const struct ddb_regset *odma_buf; + + const struct ddb_regset *input; + const struct ddb_regset *output; + + const struct ddb_regset *channel; +}; + +struct ddb_ids { + u16 vendor; + u16 device; + u16 subvendor; + u16 subdevice; + + u32 hwid; + u32 regmapid; + u32 devid; + u32 mac; +}; struct ddb_info { int type; -#define DDB_NONE 0 -#define DDB_OCTOPUS 1 -#define DDB_OCTOPUS_MAX_CT 6 +#define DDB_NONE 0 +#define DDB_OCTOPUS 1 +#define DDB_OCTOPUS_CI 2 +#define DDB_OCTOPUS_MAX 5 +#define DDB_OCTOPUS_MAX_CT 6 char *name; - int port_num; - u32 port_type[DDB_MAX_PORT]; + u32 i2c_mask; + u8 port_num; + u8 led_num; + u8 fan_num; + u8 temp_num; + u8 temp_bus; u32 board_control; u32 board_control_2; + u8 mdio_num; + u8 con_clock; /* use a continuous clock */ u8 ts_quirks; #define TS_QUIRK_SERIAL 1 #define TS_QUIRK_REVERSED 2 #define TS_QUIRK_ALT_OSC 8 + u32 tempmon_irq; + const struct ddb_regmap *regmap; }; -/* DMA_SIZE MUST be divisible by 188 and 128 !!! */ +/* DMA_SIZE MUST be smaller than 256k and + * MUST be divisible by 188 and 128 !!! + */ + +#define DMA_MAX_BUFS 32 /* hardware table limit */ -#define INPUT_DMA_MAX_BUFS 32 /* hardware table limit */ #define INPUT_DMA_BUFS 8 #define INPUT_DMA_SIZE (128*47*21) +#define INPUT_DMA_IRQ_DIV 1 -#define OUTPUT_DMA_MAX_BUFS 32 #define OUTPUT_DMA_BUFS 8 #define OUTPUT_DMA_SIZE (128*47*21) +#define OUTPUT_DMA_IRQ_DIV 1 struct ddb; struct ddb_port; -struct ddb_input { - struct ddb_port *port; - u32 nr; - int attached; +struct ddb_dma { + void *io; + u32 regs; + u32 bufregs; - dma_addr_t pbuf[INPUT_DMA_MAX_BUFS]; - u8 *vbuf[INPUT_DMA_MAX_BUFS]; - u32 dma_buf_num; - u32 dma_buf_size; + dma_addr_t pbuf[DMA_MAX_BUFS]; + u8 *vbuf[DMA_MAX_BUFS]; + u32 num; + u32 size; + u32 div; + u32 bufval; - struct tasklet_struct tasklet; + struct work_struct work; spinlock_t lock; wait_queue_head_t wq; int running; u32 stat; + u32 ctrl; u32 cbuf; u32 coff; +}; - struct dvb_adapter adap; +struct ddb_dvb { + struct dvb_adapter *adap; + int adap_registered; struct dvb_device *dev; struct i2c_client *i2c_client[1]; struct dvb_frontend *fe; @@ -110,97 +188,210 @@ struct ddb_input { struct dmx_frontend hw_frontend; struct dmx_frontend mem_frontend; int users; - int (*gate_ctrl)(struct dvb_frontend *, int); + u32 attached; + u8 input; + + enum fe_sec_tone_mode tone; + enum fe_sec_voltage voltage; + + int (*i2c_gate_ctrl)(struct dvb_frontend *, int); + int (*set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); + int (*set_input)(struct dvb_frontend *fe, int input); + int (*diseqc_send_master_cmd)(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd); }; -struct ddb_output { +struct ddb_ci { + struct dvb_ca_en50221 en; struct ddb_port *port; u32 nr; - dma_addr_t pbuf[OUTPUT_DMA_MAX_BUFS]; - u8 *vbuf[OUTPUT_DMA_MAX_BUFS]; - u32 dma_buf_num; - u32 dma_buf_size; - struct tasklet_struct tasklet; - spinlock_t lock; - wait_queue_head_t wq; - int running; - u32 stat; - u32 cbuf; - u32 coff; + struct mutex lock; +}; - struct dvb_adapter adap; - struct dvb_device *dev; +struct ddb_io { + struct ddb_port *port; + u32 nr; + u32 regs; + struct ddb_dma *dma; + struct ddb_io *redo; + struct ddb_io *redi; }; +#define ddb_output ddb_io +#define ddb_input ddb_io + struct ddb_i2c { struct ddb *dev; u32 nr; - struct i2c_adapter adap; - struct i2c_adapter adap2; u32 regs; + u32 link; + struct i2c_adapter adap; u32 rbuf; u32 wbuf; - int done; - wait_queue_head_t wq; + u32 bsize; + struct completion completion; }; struct ddb_port { struct ddb *dev; u32 nr; + u32 pnr; + u32 regs; + u32 lnr; struct ddb_i2c *i2c; struct mutex i2c_gate_lock; u32 class; #define DDB_PORT_NONE 0 #define DDB_PORT_CI 1 #define DDB_PORT_TUNER 2 - u32 type; -#define DDB_TUNER_NONE 0 -#define DDB_TUNER_DVBS_ST 1 -#define DDB_TUNER_DVBS_ST_AA 2 -#define DDB_TUNER_DVBCT2_SONY_P 7 -#define DDB_TUNER_DVBC2T2_SONY_P 8 -#define DDB_TUNER_ISDBT_SONY_P 9 -#define DDB_TUNER_DVBC2T2I_SONY_P 15 -#define DDB_TUNER_DVBCT_TR 16 -#define DDB_TUNER_DVBCT_ST 17 -#define DDB_TUNER_XO2_DVBS_STV0910 32 -#define DDB_TUNER_XO2_DVBCT2_SONY 33 -#define DDB_TUNER_XO2_ISDBT_SONY 34 -#define DDB_TUNER_XO2_DVBC2T2_SONY 35 -#define DDB_TUNER_XO2_ATSC_ST 36 -#define DDB_TUNER_XO2_DVBC2T2I_SONY 37 - - u32 adr; +#define DDB_PORT_LOOP 3 + char *name; + char *type_name; + u32 type; +#define DDB_TUNER_NONE 0 +#define DDB_TUNER_DVBS_ST 1 +#define DDB_TUNER_DVBS_ST_AA 2 +#define DDB_TUNER_DVBCT_TR 3 +#define DDB_TUNER_DVBCT_ST 4 +#define DDB_CI_INTERNAL 5 +#define DDB_CI_EXTERNAL_SONY 6 +#define DDB_TUNER_DVBCT2_SONY_P 7 +#define DDB_TUNER_DVBC2T2_SONY_P 8 +#define DDB_TUNER_ISDBT_SONY_P 9 +#define DDB_TUNER_DVBS_STV0910_P 10 +#define DDB_TUNER_MXL5XX 11 +#define DDB_CI_EXTERNAL_XO2 12 +#define DDB_CI_EXTERNAL_XO2_B 13 +#define DDB_TUNER_DVBS_STV0910_PR 14 +#define DDB_TUNER_DVBC2T2I_SONY_P 15 + +#define DDB_TUNER_XO2 32 +#define DDB_TUNER_DVBS_STV0910 (DDB_TUNER_XO2 + 0) +#define DDB_TUNER_DVBCT2_SONY (DDB_TUNER_XO2 + 1) +#define DDB_TUNER_ISDBT_SONY (DDB_TUNER_XO2 + 2) +#define DDB_TUNER_DVBC2T2_SONY (DDB_TUNER_XO2 + 3) +#define DDB_TUNER_ATSC_ST (DDB_TUNER_XO2 + 4) +#define DDB_TUNER_DVBC2T2I_SONY (DDB_TUNER_XO2 + 5) struct ddb_input *input[2]; struct ddb_output *output; struct dvb_ca_en50221 *en; + struct ddb_dvb dvb[2]; + u32 gap; + u32 obr; + u8 creg; +}; + +#define CM_STARTUP_DELAY 2 +#define CM_AVERAGE 20 +#define CM_GAIN 10 + +#define HW_LSB_SHIFT 12 +#define HW_LSB_MASK 0x1000 + +#define CM_IDLE 0 +#define CM_STARTUP 1 +#define CM_ADJUST 2 + +#define TS_CAPTURE_LEN (4096) + +struct ddb_lnb { + struct mutex lock; + u32 tone; + enum fe_sec_voltage oldvoltage[4]; + u32 voltage[4]; + u32 voltages; + u32 fmode; +}; + +struct ddb_link { + struct ddb *dev; + const struct ddb_info *info; + u32 nr; + u32 regs; + spinlock_t lock; + struct mutex flash_mutex; + struct ddb_lnb lnb; + struct tasklet_struct tasklet; + struct ddb_ids ids; + + spinlock_t temp_lock; + int overtemperature_error; + u8 temp_tab[11]; }; struct ddb { struct pci_dev *pdev; + struct platform_device *pfdev; + struct device *dev; + + int msi; + struct workqueue_struct *wq; + u32 has_dma; + + struct ddb_link link[DDB_MAX_LINK]; unsigned char __iomem *regs; + u32 regs_len; + u32 port_num; struct ddb_port port[DDB_MAX_PORT]; + u32 i2c_num; struct ddb_i2c i2c[DDB_MAX_I2C]; struct ddb_input input[DDB_MAX_INPUT]; struct ddb_output output[DDB_MAX_OUTPUT]; + struct dvb_adapter adap[DDB_MAX_INPUT]; + struct ddb_dma idma[DDB_MAX_INPUT]; + struct ddb_dma odma[DDB_MAX_OUTPUT]; + + void (*handler[4][256])(unsigned long); + unsigned long handler_data[4][256]; struct device *ddb_dev; - int nr; + u32 ddb_dev_users; + u32 nr; u8 iobuf[1028]; - struct ddb_info *info; - int msi; + u8 leds; + u32 ts_irq; + u32 i2c_irq; + + struct mutex mutex; + + u8 tsbuf[TS_CAPTURE_LEN]; }; /****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ -#define ddbwritel(_val, _adr) writel((_val), \ - dev->regs+(_adr)) -#define ddbreadl(_adr) readl(dev->regs+(_adr)) -#define ddbcpyto(_adr, _src, _count) memcpy_toio(dev->regs+(_adr), (_src), (_count)) -#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), dev->regs+(_adr), (_count)) +int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len); /****************************************************************************/ -#endif +/* ddbridge-main.c (modparams) */ +extern int ci_bitrate; +extern int ts_loop; +extern int xo2_speed; +extern int alt_dma; +extern int no_init; +extern int stv0910_single; +extern struct workqueue_struct *ddb_wq; + +/* ddbridge-core.c */ +void ddb_ports_detach(struct ddb *dev); +void ddb_ports_release(struct ddb *dev); +void ddb_buffers_free(struct ddb *dev); +void ddb_device_destroy(struct ddb *dev); +irqreturn_t ddb_irq_handler0(int irq, void *dev_id); +irqreturn_t ddb_irq_handler1(int irq, void *dev_id); +irqreturn_t ddb_irq_handler(int irq, void *dev_id); +void ddb_ports_init(struct ddb *dev); +int ddb_buffers_alloc(struct ddb *dev); +int ddb_ports_attach(struct ddb *dev); +int ddb_device_create(struct ddb *dev); +int ddb_class_create(void); +void ddb_class_destroy(void); +int ddb_init(struct ddb *dev); +void ddb_unmap(struct ddb *dev); + +#endif /* DDBRIDGE_H */ diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index 1d41934cfaf5..7c3900dec368 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -571,7 +571,7 @@ static u32 functionality(struct i2c_adapter *adap) return I2C_FUNC_I2C; } -static struct i2c_algorithm dm1105_algo = { +static const struct i2c_algorithm dm1105_algo = { .master_xfer = dm1105_i2c_xfer, .functionality = functionality, }; @@ -675,7 +675,7 @@ static void dm1105_emit_key(struct work_struct *work) data = (ircom >> 8) & 0x7f; /* FIXME: UNKNOWN because we don't generate a full NEC scancode (yet?) */ - rc_keydown(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown(ir->dev, RC_PROTO_UNKNOWN, data, 0); } /* work handler */ @@ -748,7 +748,7 @@ static int dm1105_ir_init(struct dm1105_dev *dm1105) dev->driver_name = MODULE_NAME; dev->map_name = RC_MAP_DM1105_NEC; - dev->input_name = "DVB on-card IR receiver"; + dev->device_name = "DVB on-card IR receiver"; dev->input_phys = dm1105->ir.input_phys; dev->input_id.bustype = BUS_PCI; dev->input_id.version = 1; @@ -1208,7 +1208,7 @@ static void dm1105_remove(struct pci_dev *pdev) kfree(dev); } -static struct pci_device_id dm1105_id_table[] = { +static const struct pci_device_id dm1105_id_table[] = { { .vendor = PCI_VENDOR_ID_TRIGEM, .device = PCI_DEVICE_ID_DM1105, diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index 6a219694b225..1775c36891ae 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -499,7 +499,7 @@ static int dt3155_init_board(struct dt3155_priv *pd) return 0; } -static struct video_device dt3155_vdev = { +static const struct video_device dt3155_vdev = { .name = DT3155_NAME, .fops = &dt3155_fops, .ioctl_ops = &dt3155_ioctl_ops, diff --git a/drivers/media/pci/ivtv/ivtv-alsa-mixer.c b/drivers/media/pci/ivtv/ivtv-alsa-mixer.c index ba372a23eb5c..aee453fcff37 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-mixer.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-mixer.c @@ -156,7 +156,7 @@ int __init snd_ivtv_mixer_create(struct snd_ivtv_card *itvsc) strlcpy(sc->mixername, "CX2341[56] Mixer", sizeof(sc->mixername)); - ret = snd_ctl_add(sc, snd_ctl_new1(snd_ivtv_mixer_tv_vol, itvsc)); + ret = snd_ctl_add(sc, snd_ctl_new1(&snd_ivtv_mixer_tv_vol, itvsc)); if (ret) { IVTV_ALSA_WARN("%s: failed to add %s control, err %d\n", __func__, snd_ivtv_mixer_tv_vol.name, ret); diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c index 417d03da01f0..5326d86fa375 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c @@ -41,7 +41,7 @@ MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); pr_info("ivtv-alsa-pcm %s: " fmt, __func__, ##arg); \ } while (0) -static struct snd_pcm_hardware snd_ivtv_hw_capture = { +static const struct snd_pcm_hardware snd_ivtv_hw_capture = { .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index e8fa99b6c7b4..54dcac4b2229 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -73,7 +73,7 @@ int (*ivtv_ext_init)(struct ivtv *); EXPORT_SYMBOL(ivtv_ext_init); /* add your revision and whatnot here */ -static struct pci_device_id ivtv_pci_tbl[] = { +static const struct pci_device_id ivtv_pci_tbl[] = { {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16, diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c index dea80efd5836..5a35e366f4c0 100644 --- a/drivers/media/pci/ivtv/ivtv-i2c.c +++ b/drivers/media/pci/ivtv/ivtv-i2c.c @@ -148,7 +148,7 @@ static const char * const hw_devicenames[] = { "ir_video", /* IVTV_HW_I2C_IR_RX_ADAPTEC */ }; -static int get_key_adaptec(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_adaptec(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char keybuf[4]; @@ -168,7 +168,7 @@ static int get_key_adaptec(struct IR_i2c *ir, enum rc_type *protocol, keybuf[2] &= 0x7f; keybuf[3] |= 0x80; - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24; *toggle = 0; return 1; @@ -201,22 +201,22 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) init_data->ir_codes = RC_MAP_AVERMEDIA_CARDBUS; init_data->internal_get_key_func = IR_KBD_GET_KEY_AVERMEDIA_CARDBUS; - init_data->type = RC_BIT_OTHER; + init_data->type = RC_PROTO_BIT_OTHER; init_data->name = "AVerMedia AVerTV card"; break; case IVTV_HW_I2C_IR_RX_HAUP_EXT: case IVTV_HW_I2C_IR_RX_HAUP_INT: init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; - init_data->type = RC_BIT_RC5; + init_data->type = RC_PROTO_BIT_RC5; init_data->name = itv->card_name; break; case IVTV_HW_Z8F0811_IR_RX_HAUP: /* Default to grey remote */ init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_BIT_RC5 | RC_BIT_RC6_MCE | - RC_BIT_RC6_6A_32; + init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_RC6_6A_32; init_data->name = itv->card_name; break; case IVTV_HW_I2C_IR_RX_ADAPTEC: @@ -224,7 +224,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) init_data->name = itv->card_name; /* FIXME: The protocol and RC_MAP needs to be corrected */ init_data->ir_codes = RC_MAP_EMPTY; - init_data->type = RC_BIT_UNKNOWN; + init_data->type = RC_PROTO_BIT_UNKNOWN; break; } @@ -632,7 +632,7 @@ static const struct i2c_algorithm ivtv_algo = { }; /* template for our-bit banger */ -static struct i2c_adapter ivtv_i2c_adap_hw_template = { +static const struct i2c_adapter ivtv_i2c_adap_hw_template = { .name = "ivtv i2c driver", .algo = &ivtv_algo, .algo_data = NULL, /* filled from template */ @@ -682,7 +682,7 @@ static int ivtv_getsda_old(void *data) } /* template for i2c-bit-algo */ -static struct i2c_adapter ivtv_i2c_adap_template = { +static const struct i2c_adapter ivtv_i2c_adap_template = { .name = "ivtv i2c driver", .algo = NULL, /* set by i2c-algo-bit */ .algo_data = NULL, /* filled from template */ diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c index 68b5800030b7..11e987860b23 100644 --- a/drivers/media/pci/mantis/hopper_cards.c +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -255,7 +255,7 @@ static void hopper_pci_remove(struct pci_dev *pdev) } -static struct pci_device_id hopper_pci_table[] = { +static const struct pci_device_id hopper_pci_table[] = { MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config, NULL), { } diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c index cdefffc16d9e..adc980d33711 100644 --- a/drivers/media/pci/mantis/mantis_cards.c +++ b/drivers/media/pci/mantis/mantis_cards.c @@ -281,7 +281,7 @@ static void mantis_pci_remove(struct pci_dev *pdev) return; } -static struct pci_device_id mantis_pci_table[] = { +static const struct pci_device_id mantis_pci_table[] = { MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config, RC_MAP_TECHNISAT_TS35), MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config, diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h index d48778a366a9..a664c319ef0a 100644 --- a/drivers/media/pci/mantis/mantis_common.h +++ b/drivers/media/pci/mantis/mantis_common.h @@ -176,7 +176,7 @@ struct mantis_pci { struct work_struct uart_work; struct rc_dev *rc; - char input_name[80]; + char device_name[80]; char input_phys[80]; char *rc_map_name; }; diff --git a/drivers/media/pci/mantis/mantis_i2c.c b/drivers/media/pci/mantis/mantis_i2c.c index d72ee47dc6e4..496c10dfc4df 100644 --- a/drivers/media/pci/mantis/mantis_i2c.c +++ b/drivers/media/pci/mantis/mantis_i2c.c @@ -212,7 +212,7 @@ static u32 mantis_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_SMBUS_EMUL; } -static struct i2c_algorithm mantis_algo = { +static const struct i2c_algorithm mantis_algo = { .master_xfer = mantis_i2c_xfer, .functionality = mantis_i2c_func, }; diff --git a/drivers/media/pci/mantis/mantis_input.c b/drivers/media/pci/mantis/mantis_input.c index 50d10cb7d49d..7519dcc934dd 100644 --- a/drivers/media/pci/mantis/mantis_input.c +++ b/drivers/media/pci/mantis/mantis_input.c @@ -31,7 +31,7 @@ void mantis_input_process(struct mantis_pci *mantis, int scancode) { if (mantis->rc) - rc_keydown(mantis->rc, RC_TYPE_UNKNOWN, scancode, 0); + rc_keydown(mantis->rc, RC_PROTO_UNKNOWN, scancode, 0); } int mantis_input_init(struct mantis_pci *mantis) @@ -46,12 +46,12 @@ int mantis_input_init(struct mantis_pci *mantis) goto out; } - snprintf(mantis->input_name, sizeof(mantis->input_name), + snprintf(mantis->device_name, sizeof(mantis->device_name), "Mantis %s IR receiver", mantis->hwconfig->model_name); snprintf(mantis->input_phys, sizeof(mantis->input_phys), "pci-%s/ir0", pci_name(mantis->pdev)); - dev->input_name = mantis->input_name; + dev->device_name = mantis->device_name; dev->input_phys = mantis->input_phys; dev->input_id.bustype = BUS_PCI; dev->input_id.vendor = mantis->vendor_id; diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index 9c4a024745de..49e047e4a81e 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1533,7 +1533,7 @@ static const struct v4l2_ioctl_ops meye_ioctl_ops = { .vidioc_default = vidioc_default, }; -static struct video_device meye_template = { +static const struct video_device meye_template = { .name = "meye", .fops = &meye_fops, .ioctl_ops = &meye_ioctl_ops, @@ -1801,7 +1801,7 @@ static void meye_remove(struct pci_dev *pcidev) printk(KERN_INFO "meye: removed\n"); } -static struct pci_device_id meye_pci_tbl[] = { +static const struct pci_device_id meye_pci_tbl[] = { { PCI_VDEVICE(KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002), 0 }, { } }; diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index 5c0a4e614413..60e6cd5b3a03 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -1014,7 +1014,7 @@ static void netup_unidvb_finidev(struct pci_dev *pci_dev) } -static struct pci_device_id netup_unidvb_pci_tbl[] = { +static const struct pci_device_id netup_unidvb_pci_tbl[] = { { PCI_DEVICE(0x1b55, 0x18f6) }, /* hw rev. 1.3 */ { PCI_DEVICE(0x1b55, 0x18f7) }, /* hw rev. 1.4 */ { 0, } diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c b/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c index b49e4f9788e8..b13e319d24b7 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c @@ -300,7 +300,7 @@ static const struct i2c_algorithm netup_i2c_algorithm = { .functionality = netup_i2c_func, }; -static struct i2c_adapter netup_i2c_adapter = { +static const struct i2c_adapter netup_i2c_adapter = { .owner = THIS_MODULE, .name = NETUP_UNIDVB_NAME, .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c index fbf36353c701..3004947f300b 100644 --- a/drivers/media/pci/ngene/ngene-i2c.c +++ b/drivers/media/pci/ngene/ngene-i2c.c @@ -150,7 +150,7 @@ static u32 ngene_i2c_functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL; } -static struct i2c_algorithm ngene_i2c_algo = { +static const struct i2c_algorithm ngene_i2c_algo = { .master_xfer = ngene_i2c_master_xfer, .functionality = ngene_i2c_functionality, }; diff --git a/drivers/media/pci/pluto2/pluto2.c b/drivers/media/pci/pluto2/pluto2.c index 74838109afe5..39dcba2b620c 100644 --- a/drivers/media/pci/pluto2/pluto2.c +++ b/drivers/media/pci/pluto2/pluto2.c @@ -770,7 +770,7 @@ static void pluto2_remove(struct pci_dev *pdev) #define PCI_DEVICE_ID_PLUTO2 0x0001 #endif -static struct pci_device_id pluto2_id_table[] = { +static const struct pci_device_id pluto2_id_table[] = { { .vendor = PCI_VENDOR_ID_SCM, .device = PCI_DEVICE_ID_PLUTO2, diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c index 3219d2f3271e..b6b1a8d20d86 100644 --- a/drivers/media/pci/pt1/pt1.c +++ b/drivers/media/pci/pt1/pt1.c @@ -1202,7 +1202,7 @@ err: } -static struct pci_device_id pt1_id_table[] = { +static const struct pci_device_id pt1_id_table[] = { { PCI_DEVICE(0x10ee, 0x211a) }, { PCI_DEVICE(0x10ee, 0x222a) }, { }, diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c index e8b5d0992157..34044a45fecc 100644 --- a/drivers/media/pci/pt3/pt3.c +++ b/drivers/media/pci/pt3/pt3.c @@ -472,7 +472,6 @@ static int pt3_fetch_thread(void *data) } dev_dbg(adap->dvb_adap.device, "PT3: [%s] exited\n", adap->thread->comm); - adap->thread = NULL; return 0; } @@ -486,6 +485,7 @@ static int pt3_start_streaming(struct pt3_adapter *adap) if (IS_ERR(thread)) { int ret = PTR_ERR(thread); + adap->thread = NULL; dev_warn(adap->dvb_adap.device, "PT3 (adap:%d, dmx:%d): failed to start kthread\n", adap->dvb_adap.num, adap->dmxdev.dvbdev->id); @@ -508,6 +508,7 @@ static int pt3_stop_streaming(struct pt3_adapter *adap) /* kill the fetching thread */ ret = kthread_stop(adap->thread); + adap->thread = NULL; return ret; } @@ -520,14 +521,8 @@ static int pt3_start_feed(struct dvb_demux_feed *feed) adap = container_of(feed->demux, struct pt3_adapter, demux); adap->num_feeds++; - if (adap->thread) + if (adap->num_feeds > 1) return 0; - if (adap->num_feeds != 1) { - dev_warn(adap->dvb_adap.device, - "%s: unmatched start/stop_feed in adap:%i/dmx:%i\n", - __func__, adap->dvb_adap.num, adap->dmxdev.dvbdev->id); - adap->num_feeds = 1; - } return pt3_start_streaming(adap); diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index bf358ec7aca5..c59b69f1af9d 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -627,7 +627,7 @@ snd_card_saa7134_capture_pointer(struct snd_pcm_substream * substream) * switching to 32kHz without any frequency translation */ -static struct snd_pcm_hardware snd_card_saa7134_capture = +static const struct snd_pcm_hardware snd_card_saa7134_capture = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index b1d3648dcba1..66acfd35ffc6 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -205,7 +205,7 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = { /* ----------------------------------------------------------- */ -static struct video_device saa7134_empress_template = { +static const struct video_device saa7134_empress_template = { .name = "saa7134-empress", .fops = &ts_fops, .ioctl_ops = &ts_ioctl_ops, diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c index 9d0e69eae036..8f2ed632840f 100644 --- a/drivers/media/pci/saa7134/saa7134-i2c.c +++ b/drivers/media/pci/saa7134/saa7134-i2c.c @@ -339,7 +339,7 @@ static const struct i2c_algorithm saa7134_algo = { .functionality = functionality, }; -static struct i2c_adapter saa7134_adap_template = { +static const struct i2c_adapter saa7134_adap_template = { .owner = THIS_MODULE, .name = "saa7134", .algo = &saa7134_algo, diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c index 78849c19f68a..9337e4615519 100644 --- a/drivers/media/pci/saa7134/saa7134-input.c +++ b/drivers/media/pci/saa7134/saa7134-input.c @@ -83,14 +83,16 @@ static int build_key(struct saa7134_dev *dev) if (data == ir->mask_keycode) rc_keyup(ir->dev); else - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); return 0; } if (ir->polling) { if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) || (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); } else { rc_keyup(ir->dev); } @@ -98,7 +100,8 @@ static int build_key(struct saa7134_dev *dev) else { /* IRQ driven mode - handle key press and release in one go */ if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) || (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); rc_keyup(ir->dev); } } @@ -108,7 +111,7 @@ static int build_key(struct saa7134_dev *dev) /* --------------------- Chip specific I2C key builders ----------------- */ -static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { int gpio; @@ -154,13 +157,14 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_type *protocol, return -EIO; } - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = b; *toggle = 0; return 1; } -static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, + enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char b; @@ -201,14 +205,14 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol /* Button pressed */ input_dbg("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b); - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = b; *toggle = 0; return 1; } /* copied and modified from get_key_msi_tvanywhere_plus() */ -static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char b; @@ -249,13 +253,13 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol, /* Button pressed */ input_dbg("get_key_kworld_pc150u: Key = 0x%02X\n", b); - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = b; *toggle = 0; return 1; } -static int get_key_purpletv(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_purpletv(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char b; @@ -274,13 +278,13 @@ static int get_key_purpletv(struct IR_i2c *ir, enum rc_type *protocol, if (b & 0x80) return 1; - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = b; *toggle = 0; return 1; } -static int get_key_hvr1110(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_hvr1110(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char buf[5]; @@ -304,14 +308,14 @@ static int get_key_hvr1110(struct IR_i2c *ir, enum rc_type *protocol, * * FIXME: start bits could maybe be used...? */ - *protocol = RC_TYPE_RC5; + *protocol = RC_PROTO_RC5; *scancode = RC_SCANCODE_RC5(buf[3] & 0x1f, buf[4] >> 2); *toggle = !!(buf[3] & 0x40); return 1; } -static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char data[12]; @@ -338,7 +342,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol, if (data[9] != (unsigned char)(~data[8])) return 0; - *protocol = RC_TYPE_NECX; + *protocol = RC_PROTO_NECX; *scancode = RC_SCANCODE_NECX(data[11] << 8 | data[10], data[9]); *toggle = 0; return 1; @@ -347,7 +351,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol, /* Common (grey or coloured) pinnacle PCTV remote handling * */ -static int get_key_pinnacle(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_pinnacle(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle, int parity_offset, int marker, int code_modulo) { @@ -384,7 +388,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, enum rc_type *protocol, code %= code_modulo; - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = code; *toggle = 0; @@ -401,7 +405,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, enum rc_type *protocol, * * Sylvain Pasche <sylvain.pasche@gmail.com> */ -static int get_key_pinnacle_grey(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_pinnacle_grey(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { @@ -413,7 +417,7 @@ static int get_key_pinnacle_grey(struct IR_i2c *ir, enum rc_type *protocol, * * Ricardo Cerqueira <v4l@cerqueira.org> */ -static int get_key_pinnacle_color(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_pinnacle_color(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE @@ -452,13 +456,6 @@ static void saa7134_input_timer(unsigned long data) mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); } -static void ir_raw_decode_timer_end(unsigned long data) -{ - struct saa7134_dev *dev = (struct saa7134_dev *)data; - - ir_raw_event_handle(dev->remote->dev); -} - static int __saa7134_ir_start(void *priv) { struct saa7134_dev *dev = priv; @@ -514,10 +511,6 @@ static int __saa7134_ir_start(void *priv) (unsigned long)dev); ir->timer.expires = jiffies + HZ; add_timer(&ir->timer); - } else if (ir->raw_decode) { - /* set timer_end for code completion */ - setup_timer(&ir->timer, ir_raw_decode_timer_end, - (unsigned long)dev); } return 0; @@ -535,7 +528,7 @@ static void __saa7134_ir_stop(void *priv) if (!ir->running) return; - if (ir->polling || ir->raw_decode) + if (ir->polling) del_timer_sync(&ir->timer); ir->running = false; @@ -867,10 +860,12 @@ int saa7134_input_init1(struct saa7134_dev *dev) rc->priv = dev; rc->open = saa7134_ir_open; rc->close = saa7134_ir_close; - if (raw_decode) + if (raw_decode) { rc->driver_type = RC_DRIVER_IR_RAW; + rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + } - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype = BUS_PCI; rc->input_id.version = 1; @@ -884,6 +879,9 @@ int saa7134_input_init1(struct saa7134_dev *dev) rc->dev.parent = &dev->pci->dev; rc->map_name = ir_codes; rc->driver_name = MODULE_NAME; + rc->min_timeout = 1; + rc->timeout = IR_DEFAULT_TIMEOUT; + rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; err = rc_register_device(rc); if (err) @@ -1028,7 +1026,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) dev->init_data.name = "BeholdTV"; dev->init_data.get_key = get_key_beholdm6xx; dev->init_data.ir_codes = RC_MAP_BEHOLD; - dev->init_data.type = RC_BIT_NECX; + dev->init_data.type = RC_PROTO_BIT_NECX; info.addr = 0x2d; break; case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: @@ -1057,26 +1055,13 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) static int saa7134_raw_decode_irq(struct saa7134_dev *dev) { struct saa7134_card_ir *ir = dev->remote; - unsigned long timeout; int space; /* Generate initial event */ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); space = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown; - ir_raw_event_store_edge(dev->remote->dev, space ? IR_SPACE : IR_PULSE); - - /* - * Wait 15 ms from the start of the first IR event before processing - * the event. This time is enough for NEC protocol. May need adjustments - * to work with other protocols. - */ - smp_mb(); - - if (!timer_pending(&ir->timer)) { - timeout = jiffies + msecs_to_jiffies(15); - mod_timer(&ir->timer, timeout); - } + ir_raw_event_store_edge(dev->remote->dev, !space); return 1; } diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index c889ec9f8a5a..f708cab01fef 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -363,7 +363,7 @@ static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = { .ext = &hexium_extension, }; -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7146, diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index c306a92e8909..01f01580c7ca 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -427,7 +427,7 @@ static struct saa7146_pci_extension_data hexium_orion_4bnc = { .ext = &extension, }; -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7146, diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 504d78807639..930218cc2de1 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -819,7 +819,7 @@ static struct saa7146_pci_extension_data mxb = { .ext = &extension, }; -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7146, diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 75eed4cc4823..fca36a4910c2 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -1490,7 +1490,7 @@ static void saa7164_finidev(struct pci_dev *pci_dev) kfree(dev); } -static struct pci_device_id saa7164_pci_tbl[] = { +static const struct pci_device_id saa7164_pci_tbl[] = { { /* SAA7164 */ .vendor = 0x1131, diff --git a/drivers/media/pci/saa7164/saa7164-i2c.c b/drivers/media/pci/saa7164/saa7164-i2c.c index 430f6789f222..4bcde7c79dc3 100644 --- a/drivers/media/pci/saa7164/saa7164-i2c.c +++ b/drivers/media/pci/saa7164/saa7164-i2c.c @@ -78,7 +78,7 @@ static const struct i2c_algorithm saa7164_i2c_algo_template = { /* ----------------------------------------------------------------------- */ -static struct i2c_adapter saa7164_i2c_adap_template = { +static const struct i2c_adapter saa7164_i2c_adap_template = { .name = "saa7164", .owner = THIS_MODULE, .algo = &saa7164_i2c_algo_template, diff --git a/drivers/media/pci/smipcie/smipcie-ir.c b/drivers/media/pci/smipcie/smipcie-ir.c index d2730c3fdbae..c5595af6b976 100644 --- a/drivers/media/pci/smipcie/smipcie-ir.c +++ b/drivers/media/pci/smipcie/smipcie-ir.c @@ -144,7 +144,7 @@ static void smi_ir_decode(struct work_struct *work) rc5_system = (dwIRCode & 0x7C0) >> 6; toggle = (dwIRCode & 0x800) ? 1 : 0; scancode = rc5_system << 8 | rc5_command; - rc_keydown(rc_dev, RC_TYPE_RC5, scancode, toggle); + rc_keydown(rc_dev, RC_PROTO_RC5, scancode, toggle); } } end_ir_decode: @@ -188,14 +188,14 @@ int smi_ir_init(struct smi_dev *dev) return -ENOMEM; /* init input device */ - snprintf(ir->input_name, sizeof(ir->input_name), "IR (%s)", + snprintf(ir->device_name, sizeof(ir->device_name), "IR (%s)", dev->info->name); snprintf(ir->input_phys, sizeof(ir->input_phys), "pci-%s/ir0", pci_name(dev->pci_dev)); rc_dev->driver_name = "SMI_PCIe"; rc_dev->input_phys = ir->input_phys; - rc_dev->input_name = ir->input_name; + rc_dev->device_name = ir->device_name; rc_dev->input_id.bustype = BUS_PCI; rc_dev->input_id.version = 1; rc_dev->input_id.vendor = dev->pci_dev->subsystem_vendor; diff --git a/drivers/media/pci/smipcie/smipcie.h b/drivers/media/pci/smipcie/smipcie.h index 611e4f02cadd..c8368c78ddd5 100644 --- a/drivers/media/pci/smipcie/smipcie.h +++ b/drivers/media/pci/smipcie/smipcie.h @@ -240,7 +240,7 @@ struct smi_rc { struct smi_dev *dev; struct rc_dev *rc_dev; char input_phys[64]; - char input_name[64]; + char device_name[64]; struct work_struct work; u8 irData[256]; diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 3ca947092775..81be1b8df758 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -319,7 +319,7 @@ static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new snd_solo_capture_volume = { +static const struct snd_kcontrol_new snd_solo_capture_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Volume", .info = snd_solo_capture_volume_info, diff --git a/drivers/media/pci/solo6x10/solo6x10-gpio.c b/drivers/media/pci/solo6x10/solo6x10-gpio.c index 6d3b4a36bc11..3d0d1aa2f6a8 100644 --- a/drivers/media/pci/solo6x10/solo6x10-gpio.c +++ b/drivers/media/pci/solo6x10/solo6x10-gpio.c @@ -57,6 +57,9 @@ static void solo_gpio_mode(struct solo_dev *solo_dev, ret |= 1 << port; } + /* Enable GPIO[31:16] */ + ret |= 0xffff0000; + solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret); } @@ -90,16 +93,110 @@ static void solo_gpio_config(struct solo_dev *solo_dev) /* Initially set relay status to 0 */ solo_gpio_clear(solo_dev, 0xff00); + + /* Set input pins direction */ + solo_gpio_mode(solo_dev, 0xffff0000, 0); +} + +#ifdef CONFIG_GPIOLIB +/* Pins 0-7 are not exported, because it seems from code above they are + * used for internal purposes. So offset 0 corresponds to pin 8, therefore + * offsets 0-7 are relay GPIOs, 8-23 - input GPIOs. + */ +static int solo_gpiochip_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + int ret, mode; + struct solo_dev *solo_dev = gpiochip_get_data(chip); + + if (offset < 8) { + ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0); + mode = 3 & (ret >> ((offset + 8) * 2)); + } else { + ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1); + mode = 1 & (ret >> (offset - 8)); + } + + if (!mode) + return 1; + else if (mode == 1) + return 0; + + return -1; } +static int solo_gpiochip_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + return -1; +} + +static int solo_gpiochip_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + return -1; +} + +static int solo_gpiochip_get(struct gpio_chip *chip, + unsigned int offset) +{ + int ret; + struct solo_dev *solo_dev = gpiochip_get_data(chip); + + ret = solo_reg_read(solo_dev, SOLO_GPIO_DATA_IN); + + return 1 & (ret >> (offset + 8)); +} + +static void solo_gpiochip_set(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct solo_dev *solo_dev = gpiochip_get_data(chip); + + if (value) + solo_gpio_set(solo_dev, 1 << (offset + 8)); + else + solo_gpio_clear(solo_dev, 1 << (offset + 8)); +} +#endif + int solo_gpio_init(struct solo_dev *solo_dev) { + int ret; + solo_gpio_config(solo_dev); +#ifdef CONFIG_GPIOLIB + solo_dev->gpio_dev.label = SOLO6X10_NAME"_gpio"; + solo_dev->gpio_dev.parent = &solo_dev->pdev->dev; + solo_dev->gpio_dev.owner = THIS_MODULE; + solo_dev->gpio_dev.base = -1; + solo_dev->gpio_dev.ngpio = 24; + solo_dev->gpio_dev.can_sleep = 0; + + solo_dev->gpio_dev.get_direction = solo_gpiochip_get_direction; + solo_dev->gpio_dev.direction_input = solo_gpiochip_direction_input; + solo_dev->gpio_dev.direction_output = solo_gpiochip_direction_output; + solo_dev->gpio_dev.get = solo_gpiochip_get; + solo_dev->gpio_dev.set = solo_gpiochip_set; + + ret = gpiochip_add_data(&solo_dev->gpio_dev, solo_dev); + + if (ret) { + solo_dev->gpio_dev.label = NULL; + return -1; + } +#endif return 0; } void solo_gpio_exit(struct solo_dev *solo_dev) { +#ifdef CONFIG_GPIOLIB + if (solo_dev->gpio_dev.label) { + gpiochip_remove(&solo_dev->gpio_dev); + solo_dev->gpio_dev.label = NULL; + } +#endif solo_gpio_clear(solo_dev, 0x30); solo_gpio_config(solo_dev); } diff --git a/drivers/media/pci/solo6x10/solo6x10-tw28.c b/drivers/media/pci/solo6x10/solo6x10-tw28.c index 0632d3f7c73c..7ecb725b6dd2 100644 --- a/drivers/media/pci/solo6x10/solo6x10-tw28.c +++ b/drivers/media/pci/solo6x10/solo6x10-tw28.c @@ -532,7 +532,7 @@ static void saa712x_write_regs(struct solo_dev *dev, const u8 *vals, static void saa712x_setup(struct solo_dev *dev) { const int reg_start = 0x26; - const u8 saa7128_regs_ntsc[] = { + static const u8 saa7128_regs_ntsc[] = { /* :0x26 */ 0x0d, 0x00, /* :0x28 */ @@ -606,6 +606,7 @@ int solo_tw28_init(struct solo_dev *solo_dev) solo_dev->tw28_cnt++; break; case 0x0c: + case 0x0d: solo_dev->tw2864 |= 1 << i; solo_dev->tw28_cnt++; break; diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index 3266fc21825f..99ffd1ed4a73 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -630,7 +630,7 @@ static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static struct video_device solo_v4l2_template = { +static const struct video_device solo_v4l2_template = { .name = SOLO6X10_NAME, .fops = &solo_v4l2_fops, .ioctl_ops = &solo_v4l2_ioctl_ops, diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h index 3f8da5e8c430..3a1893ae2dad 100644 --- a/drivers/media/pci/solo6x10/solo6x10.h +++ b/drivers/media/pci/solo6x10/solo6x10.h @@ -31,6 +31,7 @@ #include <linux/atomic.h> #include <linux/slab.h> #include <linux/videodev2.h> +#include <linux/gpio/driver.h> #include <media/v4l2-dev.h> #include <media/v4l2-device.h> @@ -199,6 +200,10 @@ struct solo_dev { u32 irq_mask; u32 motion_mask; struct v4l2_device v4l2_dev; +#ifdef CONFIG_GPIOLIB + /* GPIO */ + struct gpio_chip gpio_dev; +#endif /* tw28xx accounting */ u8 tw2865, tw2864, tw2815; diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 6343d24eb1d5..eb5a9eae7c8e 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -754,7 +754,7 @@ static const struct v4l2_ioctl_ops vip_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static struct video_device video_dev_template = { +static const struct video_device video_dev_template = { .name = KBUILD_MODNAME, .release = video_device_release_empty, .fops = &vip_fops, diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index f2905bd80366..f46947d8adf8 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -2872,7 +2872,7 @@ MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C"); MAKE_AV7110_INFO(fss, "Fujitsu Siemens DVB-S rev1.6"); MAKE_AV7110_INFO(gxs_1_3, "Galaxis DVB-S rev1.3"); -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), MAKE_EXTENSION_PCI(tts_1_X_fsc, 0x13c2, 0x0000), MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h index 824c1e262fbb..347827925c14 100644 --- a/drivers/media/pci/ttpci/av7110.h +++ b/drivers/media/pci/ttpci/av7110.h @@ -177,7 +177,7 @@ struct av7110 { /* CA */ - ca_slot_info_t ci_slot[2]; + struct ca_slot_info ci_slot[2]; enum av7110_video_mode vidmode; struct dmxdev dmxdev; diff --git a/drivers/media/pci/ttpci/av7110_ca.c b/drivers/media/pci/ttpci/av7110_ca.c index f64723aea56b..1fe49171d823 100644 --- a/drivers/media/pci/ttpci/av7110_ca.c +++ b/drivers/media/pci/ttpci/av7110_ca.c @@ -119,7 +119,7 @@ static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer * } static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file, - int slots, ca_slot_info_t *slot) + int slots, struct ca_slot_info *slot) { int i; int len = 0; @@ -264,7 +264,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) break; case CA_GET_CAP: { - ca_caps_t cap; + struct ca_caps cap; cap.slot_num = 2; cap.slot_type = (FW_CI_LL_SUPPORT(av7110->arm_app) ? @@ -277,7 +277,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) case CA_GET_SLOT_INFO: { - ca_slot_info_t *info=(ca_slot_info_t *)parg; + struct ca_slot_info *info=(struct ca_slot_info *)parg; if (info->num < 0 || info->num > 1) { mutex_unlock(&av7110->ioctl_mutex); @@ -286,7 +286,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) av7110->ci_slot[info->num].num = info->num; av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? CA_CI_LINK : CA_CI; - memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); + memcpy(info, &av7110->ci_slot[info->num], sizeof(struct ca_slot_info)); break; } @@ -298,7 +298,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) case CA_GET_DESCR_INFO: { - ca_descr_info_t info; + struct ca_descr_info info; info.num = 16; info.type = CA_ECD; @@ -308,7 +308,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) case CA_SET_DESCR: { - ca_descr_t *descr = (ca_descr_t*) parg; + struct ca_descr *descr = (struct ca_descr*) parg; if (descr->index >= 16 || descr->parity > 1) { mutex_unlock(&av7110->ioctl_mutex); diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c index 397fe146dedd..e4cf42c32284 100644 --- a/drivers/media/pci/ttpci/av7110_v4l.c +++ b/drivers/media/pci/ttpci/av7110_v4l.c @@ -218,7 +218,7 @@ static struct saa7146_standard analog_standard[]; static struct saa7146_standard dvb_standard[]; static struct saa7146_standard standard[]; -static struct v4l2_audio msp3400_v4l2_audio = { +static const struct v4l2_audio msp3400_v4l2_audio = { .index = 0, .name = "Television", .capability = V4L2_AUDCAP_STEREO diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c index dc7be8fac9a3..ac83fff9fe0b 100644 --- a/drivers/media/pci/ttpci/budget-av.c +++ b/drivers/media/pci/ttpci/budget-av.c @@ -1567,7 +1567,7 @@ MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3); MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010), MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010), diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c index 11b9227307bf..57af11804fd6 100644 --- a/drivers/media/pci/ttpci/budget-ci.c +++ b/drivers/media/pci/ttpci/budget-ci.c @@ -158,14 +158,15 @@ static void msp430_ir_interrupt(unsigned long data) return; if (budget_ci->ir.full_rc5) { - rc_keydown(dev, RC_TYPE_RC5, + rc_keydown(dev, RC_PROTO_RC5, RC_SCANCODE_RC5(budget_ci->ir.rc5_device, budget_ci->ir.ir_key), !!(command & 0x20)); return; } /* FIXME: We should generate complete scancodes for all devices */ - rc_keydown(dev, RC_TYPE_UNKNOWN, budget_ci->ir.ir_key, !!(command & 0x20)); + rc_keydown(dev, RC_PROTO_UNKNOWN, budget_ci->ir.ir_key, + !!(command & 0x20)); } static int msp430_ir_init(struct budget_ci *budget_ci) @@ -186,7 +187,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) "pci-%s/ir0", pci_name(saa->pci)); dev->driver_name = MODULE_NAME; - dev->input_name = budget_ci->ir.name; + dev->device_name = budget_ci->ir.name; dev->input_phys = budget_ci->ir.phys; dev->input_id.bustype = BUS_PCI; dev->input_id.version = 1; @@ -1538,7 +1539,7 @@ MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT); MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT); -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010), diff --git a/drivers/media/pci/ttpci/budget-patch.c b/drivers/media/pci/ttpci/budget-patch.c index 442992372008..a738018cdca8 100644 --- a/drivers/media/pci/ttpci/budget-patch.c +++ b/drivers/media/pci/ttpci/budget-patch.c @@ -45,7 +45,7 @@ static struct saa7146_extension budget_extension; MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH); //MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC); -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000), // MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), { diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c index 81fe35cedd10..f59eadb7a5eb 100644 --- a/drivers/media/pci/ttpci/budget.c +++ b/drivers/media/pci/ttpci/budget.c @@ -845,7 +845,7 @@ MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1 MAKE_BUDGET_INFO(omicom, "Omicom S2 PCI", BUDGET_TT); MAKE_BUDGET_INFO(sylt, "Philips Semi Sylt PCI", BUDGET_TT_HW_DISEQC); -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 58c4dd75bfa1..8c1f4a049764 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -916,7 +916,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { #endif }; -static struct video_device tw68_video_template = { +static const struct video_device tw68_video_template = { .name = "tw68_video", .fops = &video_fops, .ioctl_ops = &video_ioctl_ops, diff --git a/drivers/media/pci/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c index 4680f001653a..a6b9ebd20263 100644 --- a/drivers/media/pci/zoran/zoran_card.c +++ b/drivers/media/pci/zoran/zoran_card.c @@ -130,7 +130,7 @@ MODULE_VERSION(ZORAN_VERSION); .vendor = PCI_VENDOR_ID_ZORAN, .device = PCI_DEVICE_ID_ZORAN_36057, \ .subvendor = (subven), .subdevice = (subdev), .driver_data = (data) } -static struct pci_device_id zr36067_pci_tbl[] = { +static const struct pci_device_id zr36067_pci_tbl[] = { ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC10PLUS, DC10plus), ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC30PLUS, DC30plus), ZR_DEVICE(PCI_VENDOR_ID_ELECTRONICDESIGNGMBH, PCI_DEVICE_ID_LML_33R10, LML33R10), diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index fb1fa0b82077..7e7cc49b8674 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -76,7 +76,8 @@ config VIDEO_M32R_AR_M64278 config VIDEO_MUX tristate "Video Multiplexer" - depends on OF && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER + select MULTIPLEXER + depends on VIDEO_V4L2 && OF && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER select REGMAP help This driver provides support for N:1 video bus multiplexers. @@ -109,6 +110,13 @@ config VIDEO_PXA27x ---help--- This is a v4l2 driver for the PXA27x Quick Capture Interface +config VIDEO_QCOM_CAMSS + tristate "Qualcomm 8x16 V4L2 Camera Subsystem driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST + select VIDEOBUF2_DMA_SG + select V4L2_FWNODE + config VIDEO_S3C_CAMIF tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API @@ -536,6 +544,17 @@ menuconfig CEC_PLATFORM_DRIVERS if CEC_PLATFORM_DRIVERS +config VIDEO_MESON_AO_CEC + tristate "Amlogic Meson AO CEC driver" + depends on ARCH_MESON || COMPILE_TEST + select CEC_CORE + select CEC_NOTIFIER + ---help--- + This is a driver for Amlogic Meson SoCs AO CEC interface. It uses the + generic CEC framework interface. + CEC bus is present in the HDMI connector and enables communication + between compatible devices. + config VIDEO_SAMSUNG_S5P_CEC tristate "Samsung S5P CEC driver" depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 9beadc760467..c1ef946bf032 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -85,4 +85,8 @@ obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp/ obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk-jpeg/ +obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom/camss-8x16/ + obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/ + +obj-y += meson/ diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 466aba8b0e00..dfcc484cab89 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -2490,8 +2490,8 @@ vpfe_get_pdata(struct platform_device *pdev) rem = of_graph_get_remote_port_parent(endpoint); if (!rem) { - dev_err(&pdev->dev, "Remote device at %s not found\n", - endpoint->full_name); + dev_err(&pdev->dev, "Remote device at %pOF not found\n", + endpoint); goto done; } diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index d6534252cdcd..d7103c5f92c3 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -873,7 +873,7 @@ static void isc_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&isc->dma_queue_lock, flags); } -static struct vb2_ops isc_vb2_ops = { +static const struct vb2_ops isc_vb2_ops = { .queue_setup = isc_queue_setup, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, @@ -1700,8 +1700,8 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc) rem = of_graph_get_remote_port_parent(epn); if (!rem) { - dev_notice(dev, "Remote device at %s not found\n", - of_node_full_name(epn)); + dev_notice(dev, "Remote device at %pOF not found\n", + epn); continue; } diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 1c5166df46f5..41f179117fb0 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -375,7 +375,7 @@ static void bcap_stop_streaming(struct vb2_queue *vq) } } -static struct vb2_ops bcap_video_qops = { +static const struct vb2_ops bcap_video_qops = { .queue_setup = bcap_queue_setup, .buf_prepare = bcap_buffer_prepare, .buf_cleanup = bcap_buffer_cleanup, @@ -769,7 +769,7 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = { .vidioc_log_status = bcap_log_status, }; -static struct v4l2_file_operations bcap_fops = { +static const struct v4l2_file_operations bcap_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vb2_fop_release, diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index bba1eb43b5d8..291c40933935 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -394,7 +394,8 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, int i; if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || - ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264) { + ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 || + ctx->codec->dst_fourcc == V4L2_PIX_FMT_MPEG4) { width = round_up(q_data->width, 16); height = round_up(q_data->height, 16); } else { @@ -702,6 +703,8 @@ static u32 coda_supported_firmwares[] = { CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), + CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10), + CODA_FIRMWARE_VERNUM(CODA_960, 3, 1, 1), }; static bool coda_firmware_supported(u32 vernum) @@ -1006,7 +1009,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) break; } coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); - value = ctx->params.gop_size & CODA_GOP_SIZE_MASK; + value = ctx->params.gop_size; coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); } @@ -1250,7 +1253,8 @@ static int coda_prepare_encode(struct coda_ctx *ctx) force_ipicture = ctx->params.force_ipicture; if (force_ipicture) ctx->params.force_ipicture = false; - else if ((src_buf->sequence % ctx->params.gop_size) == 0) + else if (ctx->params.gop_size != 0 && + (src_buf->sequence % ctx->params.gop_size) == 0) force_ipicture = 1; /* @@ -1411,6 +1415,7 @@ static void coda_finish_encode(struct coda_ctx *ctx) } dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; + dst_buf->field = src_buf->field; dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; @@ -1634,9 +1639,6 @@ static int __coda_start_decoding(struct coda_ctx *ctx) ctx->frm_dis_flg = 0; coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); - coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE, - CODA_REG_BIT_BIT_STREAM_PARAM); - coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); val = 0; @@ -1652,6 +1654,10 @@ static int __coda_start_decoding(struct coda_ctx *ctx) ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4; else ctx->params.codec_mode_aux = 0; + if (src_fourcc == V4L2_PIX_FMT_MPEG4) { + coda_write(dev, CODA_MP4_CLASS_MPEG4, + CODA_CMD_DEC_SEQ_MP4_ASP_CLASS); + } if (src_fourcc == V4L2_PIX_FMT_H264) { if (dev->devtype->product == CODA_7541) { coda_write(dev, ctx->psbuf.paddr, @@ -1667,18 +1673,18 @@ static int __coda_start_decoding(struct coda_ctx *ctx) if (dev->devtype->product != CODA_960) coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE); - if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) { + ctx->bit_stream_param = CODA_BIT_DEC_SEQ_INIT_ESCAPE; + ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); + ctx->bit_stream_param = 0; + if (ret) { v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); - coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); - return -ETIMEDOUT; + return ret; } ctx->initialized = 1; /* Update kfifo out pointer from coda bitstream read pointer */ coda_kfifo_sync_from_device(ctx); - coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); - if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT failed, error code = %d\n", @@ -2153,6 +2159,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); dst_buf->sequence = ctx->osequence++; + dst_buf->field = V4L2_FIELD_NONE; dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 829c7895a98a..15eb5dc4dff9 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -73,7 +73,7 @@ MODULE_PARM_DESC(disable_vdoa, "Disable Video Data Order Adapter tiled to raster static int enable_bwb = 0; module_param(enable_bwb, int, 0644); -MODULE_PARM_DESC(enable_bwb, "Enable BWB unit, may crash on certain streams"); +MODULE_PARM_DESC(enable_bwb, "Enable BWB unit for decoding, may crash on certain streams"); void coda_write(struct coda_dev *dev, u32 data, u32 reg) { @@ -714,9 +714,10 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; break; case V4L2_PIX_FMT_NV12: - ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; - if (!disable_tiling) + if (!disable_tiling) { + ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; break; + } /* else fall through */ case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: @@ -932,7 +933,7 @@ static int coda_encoder_cmd(struct file *file, void *fh, ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; /* If there is no buffer in flight, wake up */ - if (ctx->qsequence == ctx->osequence) { + if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) { dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); dst_vq->last_buffer_dequeued = true; @@ -1683,12 +1684,23 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) ctx->params.h264_deblk_enabled = (ctrl->val == V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + /* TODO: switch between baseline and constrained baseline */ + ctx->params.h264_profile_idc = 66; + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + /* nothing to do, this is set by the encoder */ + break; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: ctx->params.mpeg4_intra_qp = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: ctx->params.mpeg4_inter_qp = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: + case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: + /* nothing to do, these are fixed */ + break; case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: ctx->params.slice_mode = ctrl->val; break; @@ -1734,10 +1746,12 @@ static const struct v4l2_ctrl_ops coda_ctrl_ops = { static void coda_encode_ctrls(struct coda_ctx *ctx) { + int max_gop_size = (ctx->dev->devtype->product == CODA_DX6) ? 60 : 99; + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1000, 0); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16); + V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, max_gop_size, 1, 16); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, @@ -1756,11 +1770,47 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE); + if (ctx->dev->devtype->product == CODA_7541) { + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + V4L2_MPEG_VIDEO_H264_LEVEL_3_1, + ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1)), + V4L2_MPEG_VIDEO_H264_LEVEL_3_1); + } + if (ctx->dev->devtype->product == CODA_960) { + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + V4L2_MPEG_VIDEO_H264_LEVEL_4_0, + ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0)), + V4L2_MPEG_VIDEO_H264_LEVEL_4_0); + } v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2); v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, + V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, 0x0, + V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE); + if (ctx->dev->devtype->product == CODA_7541 || + ctx->dev->devtype->product == CODA_960) { + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, + V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, + ~(1 << V4L2_MPEG_VIDEO_MPEG4_LEVEL_5), + V4L2_MPEG_VIDEO_MPEG4_LEVEL_5); + } + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); @@ -1938,7 +1988,13 @@ static int coda_open(struct file *file) ctx->idx = idx; switch (dev->devtype->product) { case CODA_960: - if (enable_bwb) + /* + * Enabling the BWB when decoding can hang the firmware with + * certain streams. The issue was tracked as ENGR00293425 by + * Freescale. As a workaround, disable BWB for all decoders. + * The enable_bwb module parameter allows to override this. + */ + if (enable_bwb || ctx->inst_type == CODA_INST_ENCODER) ctx->frame_mem_ctrl = CODA9_FRAME_ENABLE_BWB; /* fallthrough */ case CODA_7541: @@ -2142,7 +2198,8 @@ static int coda_hw_init(struct coda_dev *dev) CODA_REG_BIT_STREAM_CTRL); } if (dev->devtype->product == CODA_960) - coda_write(dev, 1 << 12, CODA_REG_BIT_FRAME_MEM_CTRL); + coda_write(dev, CODA9_FRAME_ENABLE_BWB, + CODA_REG_BIT_FRAME_MEM_CTRL); else coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL); @@ -2386,11 +2443,11 @@ static const struct coda_devtype coda_devdata[] = { .num_vdevs = ARRAY_SIZE(coda9_video_devices), .workbuf_size = 80 * 1024, .tempbuf_size = 204 * 1024, - .iram_size = 0x20000, + .iram_size = 0x1f000, /* leave 4k for suspend code */ }, }; -static struct platform_device_id coda_platform_ids[] = { +static const struct platform_device_id coda_platform_ids[] = { { .name = "coda-imx27", .driver_data = CODA_IMX27 }, { /* sentinel */ } }; @@ -2470,7 +2527,8 @@ static int coda_probe(struct platform_device *pdev) return ret; } - dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL); + dev->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, + NULL); if (IS_ERR(dev->rstc)) { ret = PTR_ERR(dev->rstc); dev_err(&pdev->dev, "failed get reset control: %d\n", ret); diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index 77ee46a93427..38df5fd9a2fa 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h @@ -158,6 +158,7 @@ #define CODA_CMD_DEC_SEQ_PS_BB_START 0x194 #define CODA_CMD_DEC_SEQ_PS_BB_SIZE 0x198 #define CODA_CMD_DEC_SEQ_MP4_ASP_CLASS 0x19c +#define CODA_MP4_CLASS_MPEG4 0 #define CODA_CMD_DEC_SEQ_X264_MV_EN 0x19c #define CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE 0x1a0 diff --git a/drivers/media/platform/coda/imx-vdoa.c b/drivers/media/platform/coda/imx-vdoa.c index df9b71621420..8eb3e0c05473 100644 --- a/drivers/media/platform/coda/imx-vdoa.c +++ b/drivers/media/platform/coda/imx-vdoa.c @@ -314,6 +314,8 @@ static int vdoa_probe(struct platform_device *pdev) return PTR_ERR(vdoa->regs); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) + return -EINVAL; vdoa->irq = devm_request_threaded_irq(&pdev->dev, res->start, NULL, vdoa_irq_handler, IRQF_ONESHOT, "vdoa", vdoa); diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 3679b1e7b39e..7f6462562579 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -790,7 +790,7 @@ static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) vpss_enable_clock(VPSS_VPBE_CLOCK, 0); } -static struct vpbe_device_ops vpbe_dev_ops = { +static const struct vpbe_device_ops vpbe_dev_ops = { .g_cropcap = vpbe_g_cropcap, .enum_outputs = vpbe_enum_outputs, .set_output = vpbe_set_output, diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index a9bc0175e4d3..13d027031ff0 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -355,7 +355,7 @@ static void vpbe_stop_streaming(struct vb2_queue *vq) spin_unlock_irqrestore(&disp->dma_queue_lock, flags); } -static struct vb2_ops video_qops = { +static const struct vb2_ops video_qops = { .queue_setup = vpbe_buffer_queue_setup, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, @@ -1275,7 +1275,7 @@ static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { .vidioc_enum_dv_timings = vpbe_display_enum_dv_timings, }; -static struct v4l2_file_operations vpbe_fops = { +static const struct v4l2_file_operations vpbe_fops = { .owner = THIS_MODULE, .open = vpbe_display_open, .release = vpbe_display_release, diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c index df042e84a678..66449791c70c 100644 --- a/drivers/media/platform/davinci/vpbe_osd.c +++ b/drivers/media/platform/davinci/vpbe_osd.c @@ -37,7 +37,7 @@ #define MODULE_NAME "davinci-vpbe-osd" -static struct platform_device_id vpbe_osd_devtype[] = { +static const struct platform_device_id vpbe_osd_devtype[] = { { .name = DM644X_VPBE_OSD_SUBDEV_NAME, .driver_data = VPBE_VERSION_1, diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c index 8bfe90a24681..3a4e78595149 100644 --- a/drivers/media/platform/davinci/vpbe_venc.c +++ b/drivers/media/platform/davinci/vpbe_venc.c @@ -36,7 +36,7 @@ #define MODULE_NAME "davinci-vpbe-venc" -static struct platform_device_id vpbe_venc_devtype[] = { +static const struct platform_device_id vpbe_venc_devtype[] = { { .name = DM644X_VPBE_VENC_SUBDEV_NAME, .driver_data = VPBE_VERSION_1, diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index b1bf4a7e8eb7..6792da16d9c7 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1288,7 +1288,7 @@ static void vpfe_videobuf_release(struct videobuf_queue *vq, vb->state = VIDEOBUF_NEEDS_INIT; } -static struct videobuf_queue_ops vpfe_videobuf_qops = { +static const struct videobuf_queue_ops vpfe_videobuf_qops = { .buf_setup = vpfe_videobuf_setup, .buf_prepare = vpfe_videobuf_prepare, .buf_queue = vpfe_videobuf_queue, diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 4be6554c56c5..0ef36cec21d1 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -312,7 +312,7 @@ static void vpif_stop_streaming(struct vb2_queue *vq) spin_unlock_irqrestore(&common->irqlock, flags); } -static struct vb2_ops video_qops = { +static const struct vb2_ops video_qops = { .queue_setup = vpif_buffer_queue_setup, .buf_prepare = vpif_buffer_prepare, .start_streaming = vpif_start_streaming, @@ -1344,7 +1344,7 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = { }; /* vpif file operations */ -static struct v4l2_file_operations vpif_fops = { +static const struct v4l2_file_operations vpif_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vb2_fop_release, @@ -1397,9 +1397,9 @@ static int vpif_async_bound(struct v4l2_async_notifier *notifier, vpif_obj.config->chan_config->inputs[i].subdev_name = (char *)to_of_node(subdev->fwnode)->full_name; vpif_dbg(2, debug, - "%s: setting input %d subdev_name = %s\n", + "%s: setting input %d subdev_name = %pOF\n", __func__, i, - to_of_node(subdev->fwnode)->full_name); + to_of_node(subdev->fwnode)); return 0; } } @@ -1557,8 +1557,8 @@ vpif_capture_get_pdata(struct platform_device *pdev) dev_err(&pdev->dev, "Could not parse the endpoint\n"); goto done; } - dev_dbg(&pdev->dev, "Endpoint %s, bus_width = %d\n", - endpoint->full_name, bus_cfg.bus.parallel.bus_width); + dev_dbg(&pdev->dev, "Endpoint %pOF, bus_width = %d\n", + endpoint, bus_cfg.bus.parallel.bus_width); flags = bus_cfg.bus.parallel.flags; if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) @@ -1569,13 +1569,13 @@ vpif_capture_get_pdata(struct platform_device *pdev) rem = of_graph_get_remote_port_parent(endpoint); if (!rem) { - dev_dbg(&pdev->dev, "Remote device at %s not found\n", - endpoint->full_name); + dev_dbg(&pdev->dev, "Remote device at %pOF not found\n", + endpoint); goto done; } - dev_dbg(&pdev->dev, "Remote device %s, %s found\n", - rem->name, rem->full_name); + dev_dbg(&pdev->dev, "Remote device %s, %pOF found\n", + rem->name, rem); sdinfo->name = rem->full_name; pdata->asd[i] = devm_kzalloc(&pdev->dev, @@ -1593,9 +1593,11 @@ vpif_capture_get_pdata(struct platform_device *pdev) } done: - pdata->asd_sizes[0] = i; - pdata->subdev_count = i; - pdata->card_name = "DA850/OMAP-L138 Video Capture"; + if (pdata) { + pdata->asd_sizes[0] = i; + pdata->subdev_count = i; + pdata->card_name = "DA850/OMAP-L138 Video Capture"; + } return pdata; } diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index bf982bf86542..56fe4e5b396e 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -290,7 +290,7 @@ static void vpif_stop_streaming(struct vb2_queue *vq) spin_unlock_irqrestore(&common->irqlock, flags); } -static struct vb2_ops video_qops = { +static const struct vb2_ops video_qops = { .queue_setup = vpif_buffer_queue_setup, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 33611a46ce35..2a2994ef15d5 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -747,7 +747,7 @@ static const struct v4l2_file_operations gsc_m2m_fops = { .mmap = gsc_m2m_mmap, }; -static struct v4l2_m2m_ops gsc_m2m_ops = { +static const struct v4l2_m2m_ops gsc_m2m_ops = { .device_run = gsc_m2m_device_run, .job_abort = gsc_m2m_job_abort, }; diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c index 2f559663e51e..70dd4852b2b9 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-i2c.c +++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.c @@ -130,7 +130,7 @@ static int fimc_is_i2c_resume(struct device *dev) } #endif -static struct dev_pm_ops fimc_is_i2c_pm_ops = { +static const struct dev_pm_ops fimc_is_i2c_pm_ops = { SET_RUNTIME_PM_OPS(fimc_is_i2c_runtime_suspend, fimc_is_i2c_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(fimc_is_i2c_suspend, fimc_is_i2c_resume) diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 340d906db370..5ddb2321e9e4 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -174,8 +174,8 @@ static int fimc_is_parse_sensor_config(struct fimc_is *is, unsigned int index, sensor->drvdata = fimc_is_sensor_get_drvdata(node); if (!sensor->drvdata) { - dev_err(&is->pdev->dev, "no driver data found for: %s\n", - node->full_name); + dev_err(&is->pdev->dev, "no driver data found for: %pOF\n", + node); return -EINVAL; } @@ -191,8 +191,8 @@ static int fimc_is_parse_sensor_config(struct fimc_is *is, unsigned int index, /* Use MIPI-CSIS channel id to determine the ISP I2C bus index. */ ret = of_property_read_u32(port, "reg", &tmp); if (ret < 0) { - dev_err(&is->pdev->dev, "reg property not found at: %s\n", - port->full_name); + dev_err(&is->pdev->dev, "reg property not found at: %pOF\n", + port); of_node_put(port); return ret; } diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 8efe9160ab34..fd793d3ac072 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -433,7 +433,7 @@ static const struct v4l2_subdev_core_ops fimc_is_core_ops = { .s_power = fimc_isp_subdev_s_power, }; -static struct v4l2_subdev_ops fimc_is_subdev_ops = { +static const struct v4l2_subdev_ops fimc_is_subdev_ops = { .core = &fimc_is_core_ops, .video = &fimc_is_subdev_video_ops, .pad = &fimc_is_subdev_pad_ops, diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 7d3ec5cc6608..4a3c9948ca54 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -1361,7 +1361,7 @@ static const struct v4l2_subdev_core_ops fimc_lite_core_ops = { .log_status = fimc_lite_log_status, }; -static struct v4l2_subdev_ops fimc_lite_subdev_ops = { +static const struct v4l2_subdev_ops fimc_lite_subdev_ops = { .core = &fimc_lite_core_ops, .video = &fimc_lite_subdev_video_ops, .pad = &fimc_lite_subdev_pad_ops, @@ -1493,8 +1493,7 @@ static int fimc_lite_probe(struct platform_device *pdev) if (!drv_data || fimc->index >= drv_data->num_instances || fimc->index < 0) { - dev_err(dev, "Wrong %s node alias\n", - dev->of_node->full_name); + dev_err(dev, "Wrong %pOF node alias\n", dev->of_node); return -EINVAL; } diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index d8724fe9e9da..9027d0b0d2bd 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -704,7 +704,7 @@ static const struct v4l2_file_operations fimc_m2m_fops = { .mmap = v4l2_m2m_fop_mmap, }; -static struct v4l2_m2m_ops m2m_ops = { +static const struct v4l2_m2m_ops m2m_ops = { .device_run = fimc_device_run, .job_abort = fimc_job_abort, }; diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 7d1cf78846c4..d4656d5175d7 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -412,8 +412,8 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, rem = of_graph_get_remote_port_parent(ep); of_node_put(ep); if (rem == NULL) { - v4l2_info(&fmd->v4l2_dev, "Remote device at %s not found\n", - ep->full_name); + v4l2_info(&fmd->v4l2_dev, "Remote device at %pOF not found\n", + ep); return 0; } @@ -430,8 +430,8 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, */ pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2; } else { - v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n", - endpoint.base.port, rem->full_name); + v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %pOF\n", + endpoint.base.port, rem); } /* * For FIMC-IS handled sensors, that are placed under i2c-isp device diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 98c89873c2dc..560aadabcb11 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -730,8 +730,8 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, node = of_graph_get_next_endpoint(node, NULL); if (!node) { - dev_err(&pdev->dev, "No port node at %s\n", - pdev->dev.of_node->full_name); + dev_err(&pdev->dev, "No port node at %pOF\n", + pdev->dev.of_node); return -EINVAL; } /* Get port node and validate MIPI-CSI channel id. */ diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index 97e164b2075a..fb43025df573 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -549,7 +549,7 @@ static void buffer_release(struct videobuf_queue *vq, free_buffer(vq, buf); } -static struct videobuf_queue_ops viu_video_qops = { +static const struct videobuf_queue_ops viu_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, @@ -1340,7 +1340,7 @@ static int viu_mmap(struct file *file, struct vm_area_struct *vma) return ret; } -static struct v4l2_file_operations viu_fops = { +static const struct v4l2_file_operations viu_fops = { .owner = THIS_MODULE, .open = viu_open, .release = viu_release, @@ -1380,7 +1380,7 @@ static const struct v4l2_ioctl_ops viu_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static struct video_device viu_template = { +static const struct video_device viu_template = { .name = "FSL viu", .fops = &viu_fops, .minor = -1, diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 980066b8d32a..c8a12493f395 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -979,7 +979,7 @@ static const struct v4l2_file_operations deinterlace_fops = { .mmap = deinterlace_mmap, }; -static struct video_device deinterlace_videodev = { +static const struct video_device deinterlace_videodev = { .name = MEM2MEM_NAME, .fops = &deinterlace_fops, .ioctl_ops = &deinterlace_ioctl_ops, @@ -988,7 +988,7 @@ static struct video_device deinterlace_videodev = { .vfl_dir = VFL_DIR_M2M, }; -static struct v4l2_m2m_ops m2m_ops = { +static const struct v4l2_m2m_ops m2m_ops = { .device_run = deinterlace_device_run, .job_ready = deinterlace_job_ready, .job_abort = deinterlace_job_abort, diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c index 77890bd0deab..57d2c483ad09 100644 --- a/drivers/media/platform/marvell-ccic/cafe-driver.c +++ b/drivers/media/platform/marvell-ccic/cafe-driver.c @@ -326,7 +326,7 @@ static u32 cafe_smbus_func(struct i2c_adapter *adapter) I2C_FUNC_SMBUS_WRITE_BYTE_DATA; } -static struct i2c_algorithm cafe_smbus_algo = { +static const struct i2c_algorithm cafe_smbus_algo = { .smbus_xfer = cafe_smbus_xfer, .functionality = cafe_smbus_func }; @@ -612,7 +612,7 @@ static int cafe_pci_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ -static struct pci_device_id cafe_ids[] = { +static const struct pci_device_id cafe_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) }, { 0, } diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 8cac2f202099..b07a251e8857 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1639,7 +1639,7 @@ static const struct v4l2_file_operations mcam_v4l_fops = { * This template device holds all of those v4l2 methods; we * clone it for specific real devices. */ -static struct video_device mcam_v4l_template = { +static const struct video_device mcam_v4l_template = { .name = "mcam", .fops = &mcam_v4l_fops, .ioctl_ops = &mcam_v4l_ioctl_ops, diff --git a/drivers/media/platform/meson/Makefile b/drivers/media/platform/meson/Makefile new file mode 100644 index 000000000000..597beb8f34d1 --- /dev/null +++ b/drivers/media/platform/meson/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_VIDEO_MESON_AO_CEC) += ao-cec.o diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c new file mode 100644 index 000000000000..8040a6285c3f --- /dev/null +++ b/drivers/media/platform/meson/ao-cec.c @@ -0,0 +1,744 @@ +/* + * Driver for Amlogic Meson AO CEC Controller + * + * Copyright (C) 2015 Amlogic, Inc. All rights reserved + * Copyright (C) 2017 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/reset.h> +#include <media/cec.h> +#include <media/cec-notifier.h> + +/* CEC Registers */ + +/* + * [2:1] cntl_clk + * - 0 = Disable clk (Power-off mode) + * - 1 = Enable gated clock (Normal mode) + * - 2 = Enable free-run clk (Debug mode) + */ +#define CEC_GEN_CNTL_REG 0x00 + +#define CEC_GEN_CNTL_RESET BIT(0) +#define CEC_GEN_CNTL_CLK_DISABLE 0 +#define CEC_GEN_CNTL_CLK_ENABLE 1 +#define CEC_GEN_CNTL_CLK_ENABLE_DBG 2 +#define CEC_GEN_CNTL_CLK_CTRL_MASK GENMASK(2, 1) + +/* + * [7:0] cec_reg_addr + * [15:8] cec_reg_wrdata + * [16] cec_reg_wr + * - 0 = Read + * - 1 = Write + * [23] bus free + * [31:24] cec_reg_rddata + */ +#define CEC_RW_REG 0x04 + +#define CEC_RW_ADDR GENMASK(7, 0) +#define CEC_RW_WR_DATA GENMASK(15, 8) +#define CEC_RW_WRITE_EN BIT(16) +#define CEC_RW_BUS_BUSY BIT(23) +#define CEC_RW_RD_DATA GENMASK(31, 24) + +/* + * [1] tx intr + * [2] rx intr + */ +#define CEC_INTR_MASKN_REG 0x08 +#define CEC_INTR_CLR_REG 0x0c +#define CEC_INTR_STAT_REG 0x10 + +#define CEC_INTR_TX BIT(1) +#define CEC_INTR_RX BIT(2) + +/* CEC Commands */ + +#define CEC_TX_MSG_0_HEADER 0x00 +#define CEC_TX_MSG_1_OPCODE 0x01 +#define CEC_TX_MSG_2_OP1 0x02 +#define CEC_TX_MSG_3_OP2 0x03 +#define CEC_TX_MSG_4_OP3 0x04 +#define CEC_TX_MSG_5_OP4 0x05 +#define CEC_TX_MSG_6_OP5 0x06 +#define CEC_TX_MSG_7_OP6 0x07 +#define CEC_TX_MSG_8_OP7 0x08 +#define CEC_TX_MSG_9_OP8 0x09 +#define CEC_TX_MSG_A_OP9 0x0A +#define CEC_TX_MSG_B_OP10 0x0B +#define CEC_TX_MSG_C_OP11 0x0C +#define CEC_TX_MSG_D_OP12 0x0D +#define CEC_TX_MSG_E_OP13 0x0E +#define CEC_TX_MSG_F_OP14 0x0F +#define CEC_TX_MSG_LENGTH 0x10 +#define CEC_TX_MSG_CMD 0x11 +#define CEC_TX_WRITE_BUF 0x12 +#define CEC_TX_CLEAR_BUF 0x13 +#define CEC_RX_MSG_CMD 0x14 +#define CEC_RX_CLEAR_BUF 0x15 +#define CEC_LOGICAL_ADDR0 0x16 +#define CEC_LOGICAL_ADDR1 0x17 +#define CEC_LOGICAL_ADDR2 0x18 +#define CEC_LOGICAL_ADDR3 0x19 +#define CEC_LOGICAL_ADDR4 0x1A +#define CEC_CLOCK_DIV_H 0x1B +#define CEC_CLOCK_DIV_L 0x1C +#define CEC_QUIESCENT_25MS_BIT7_0 0x20 +#define CEC_QUIESCENT_25MS_BIT11_8 0x21 +#define CEC_STARTBITMINL2H_3MS5_BIT7_0 0x22 +#define CEC_STARTBITMINL2H_3MS5_BIT8 0x23 +#define CEC_STARTBITMAXL2H_3MS9_BIT7_0 0x24 +#define CEC_STARTBITMAXL2H_3MS9_BIT8 0x25 +#define CEC_STARTBITMINH_0MS6_BIT7_0 0x26 +#define CEC_STARTBITMINH_0MS6_BIT8 0x27 +#define CEC_STARTBITMAXH_1MS0_BIT7_0 0x28 +#define CEC_STARTBITMAXH_1MS0_BIT8 0x29 +#define CEC_STARTBITMINTOT_4MS3_BIT7_0 0x2A +#define CEC_STARTBITMINTOT_4MS3_BIT9_8 0x2B +#define CEC_STARTBITMAXTOT_4MS7_BIT7_0 0x2C +#define CEC_STARTBITMAXTOT_4MS7_BIT9_8 0x2D +#define CEC_LOGIC1MINL2H_0MS4_BIT7_0 0x2E +#define CEC_LOGIC1MINL2H_0MS4_BIT8 0x2F +#define CEC_LOGIC1MAXL2H_0MS8_BIT7_0 0x30 +#define CEC_LOGIC1MAXL2H_0MS8_BIT8 0x31 +#define CEC_LOGIC0MINL2H_1MS3_BIT7_0 0x32 +#define CEC_LOGIC0MINL2H_1MS3_BIT8 0x33 +#define CEC_LOGIC0MAXL2H_1MS7_BIT7_0 0x34 +#define CEC_LOGIC0MAXL2H_1MS7_BIT8 0x35 +#define CEC_LOGICMINTOTAL_2MS05_BIT7_0 0x36 +#define CEC_LOGICMINTOTAL_2MS05_BIT9_8 0x37 +#define CEC_LOGICMAXHIGH_2MS8_BIT7_0 0x38 +#define CEC_LOGICMAXHIGH_2MS8_BIT8 0x39 +#define CEC_LOGICERRLOW_3MS4_BIT7_0 0x3A +#define CEC_LOGICERRLOW_3MS4_BIT8 0x3B +#define CEC_NOMSMPPOINT_1MS05 0x3C +#define CEC_DELCNTR_LOGICERR 0x3E +#define CEC_TXTIME_17MS_BIT7_0 0x40 +#define CEC_TXTIME_17MS_BIT10_8 0x41 +#define CEC_TXTIME_2BIT_BIT7_0 0x42 +#define CEC_TXTIME_2BIT_BIT10_8 0x43 +#define CEC_TXTIME_4BIT_BIT7_0 0x44 +#define CEC_TXTIME_4BIT_BIT10_8 0x45 +#define CEC_STARTBITNOML2H_3MS7_BIT7_0 0x46 +#define CEC_STARTBITNOML2H_3MS7_BIT8 0x47 +#define CEC_STARTBITNOMH_0MS8_BIT7_0 0x48 +#define CEC_STARTBITNOMH_0MS8_BIT8 0x49 +#define CEC_LOGIC1NOML2H_0MS6_BIT7_0 0x4A +#define CEC_LOGIC1NOML2H_0MS6_BIT8 0x4B +#define CEC_LOGIC0NOML2H_1MS5_BIT7_0 0x4C +#define CEC_LOGIC0NOML2H_1MS5_BIT8 0x4D +#define CEC_LOGIC1NOMH_1MS8_BIT7_0 0x4E +#define CEC_LOGIC1NOMH_1MS8_BIT8 0x4F +#define CEC_LOGIC0NOMH_0MS9_BIT7_0 0x50 +#define CEC_LOGIC0NOMH_0MS9_BIT8 0x51 +#define CEC_LOGICERRLOW_3MS6_BIT7_0 0x52 +#define CEC_LOGICERRLOW_3MS6_BIT8 0x53 +#define CEC_CHKCONTENTION_0MS1 0x54 +#define CEC_PREPARENXTBIT_0MS05_BIT7_0 0x56 +#define CEC_PREPARENXTBIT_0MS05_BIT8 0x57 +#define CEC_NOMSMPACKPOINT_0MS45 0x58 +#define CEC_ACK0NOML2H_1MS5_BIT7_0 0x5A +#define CEC_ACK0NOML2H_1MS5_BIT8 0x5B +#define CEC_BUGFIX_DISABLE_0 0x60 +#define CEC_BUGFIX_DISABLE_1 0x61 +#define CEC_RX_MSG_0_HEADER 0x80 +#define CEC_RX_MSG_1_OPCODE 0x81 +#define CEC_RX_MSG_2_OP1 0x82 +#define CEC_RX_MSG_3_OP2 0x83 +#define CEC_RX_MSG_4_OP3 0x84 +#define CEC_RX_MSG_5_OP4 0x85 +#define CEC_RX_MSG_6_OP5 0x86 +#define CEC_RX_MSG_7_OP6 0x87 +#define CEC_RX_MSG_8_OP7 0x88 +#define CEC_RX_MSG_9_OP8 0x89 +#define CEC_RX_MSG_A_OP9 0x8A +#define CEC_RX_MSG_B_OP10 0x8B +#define CEC_RX_MSG_C_OP11 0x8C +#define CEC_RX_MSG_D_OP12 0x8D +#define CEC_RX_MSG_E_OP13 0x8E +#define CEC_RX_MSG_F_OP14 0x8F +#define CEC_RX_MSG_LENGTH 0x90 +#define CEC_RX_MSG_STATUS 0x91 +#define CEC_RX_NUM_MSG 0x92 +#define CEC_TX_MSG_STATUS 0x93 +#define CEC_TX_NUM_MSG 0x94 + + +/* CEC_TX_MSG_CMD definition */ +#define TX_NO_OP 0 /* No transaction */ +#define TX_REQ_CURRENT 1 /* Transmit earliest message in buffer */ +#define TX_ABORT 2 /* Abort transmitting earliest message */ +#define TX_REQ_NEXT 3 /* Overwrite earliest msg, transmit next */ + +/* tx_msg_status definition */ +#define TX_IDLE 0 /* No transaction */ +#define TX_BUSY 1 /* Transmitter is busy */ +#define TX_DONE 2 /* Message successfully transmitted */ +#define TX_ERROR 3 /* Message transmitted with error */ + +/* rx_msg_cmd */ +#define RX_NO_OP 0 /* No transaction */ +#define RX_ACK_CURRENT 1 /* Read earliest message in buffer */ +#define RX_DISABLE 2 /* Disable receiving latest message */ +#define RX_ACK_NEXT 3 /* Clear earliest msg, read next */ + +/* rx_msg_status */ +#define RX_IDLE 0 /* No transaction */ +#define RX_BUSY 1 /* Receiver is busy */ +#define RX_DONE 2 /* Message has been received successfully */ +#define RX_ERROR 3 /* Message has been received with error */ + +/* RX_CLEAR_BUF options */ +#define CLEAR_START 1 +#define CLEAR_STOP 0 + +/* CEC_LOGICAL_ADDRx options */ +#define LOGICAL_ADDR_MASK 0xf +#define LOGICAL_ADDR_VALID BIT(4) +#define LOGICAL_ADDR_DISABLE 0 + +#define CEC_CLK_RATE 32768 + +struct meson_ao_cec_device { + struct platform_device *pdev; + void __iomem *base; + struct clk *core; + spinlock_t cec_reg_lock; + struct cec_notifier *notify; + struct cec_adapter *adap; + struct cec_msg rx_msg; +}; + +#define writel_bits_relaxed(mask, val, addr) \ + writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr) + +static inline int meson_ao_cec_wait_busy(struct meson_ao_cec_device *ao_cec) +{ + ktime_t timeout = ktime_add_us(ktime_get(), 5000); + + while (readl_relaxed(ao_cec->base + CEC_RW_REG) & CEC_RW_BUS_BUSY) { + if (ktime_compare(ktime_get(), timeout) > 0) + return -ETIMEDOUT; + } + + return 0; +} + +static void meson_ao_cec_read(struct meson_ao_cec_device *ao_cec, + unsigned long address, u8 *data, + int *res) +{ + unsigned long flags; + u32 reg = FIELD_PREP(CEC_RW_ADDR, address); + int ret = 0; + + if (res && *res) + return; + + spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); + + ret = meson_ao_cec_wait_busy(ao_cec); + if (ret) + goto read_out; + + writel_relaxed(reg, ao_cec->base + CEC_RW_REG); + + ret = meson_ao_cec_wait_busy(ao_cec); + if (ret) + goto read_out; + + *data = FIELD_GET(CEC_RW_RD_DATA, + readl_relaxed(ao_cec->base + CEC_RW_REG)); + +read_out: + spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); + + if (res) + *res = ret; +} + +static void meson_ao_cec_write(struct meson_ao_cec_device *ao_cec, + unsigned long address, u8 data, + int *res) +{ + unsigned long flags; + u32 reg = FIELD_PREP(CEC_RW_ADDR, address) | + FIELD_PREP(CEC_RW_WR_DATA, data) | + CEC_RW_WRITE_EN; + int ret = 0; + + if (res && *res) + return; + + spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); + + ret = meson_ao_cec_wait_busy(ao_cec); + if (ret) + goto write_out; + + writel_relaxed(reg, ao_cec->base + CEC_RW_REG); + +write_out: + spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); + + if (res) + *res = ret; +} + +static inline void meson_ao_cec_irq_setup(struct meson_ao_cec_device *ao_cec, + bool enable) +{ + u32 cfg = CEC_INTR_TX | CEC_INTR_RX; + + writel_bits_relaxed(cfg, enable ? cfg : 0, + ao_cec->base + CEC_INTR_MASKN_REG); +} + +static inline int meson_ao_cec_clear(struct meson_ao_cec_device *ao_cec) +{ + int ret = 0; + + meson_ao_cec_write(ao_cec, CEC_RX_MSG_CMD, RX_DISABLE, &ret); + meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_ABORT, &ret); + meson_ao_cec_write(ao_cec, CEC_RX_CLEAR_BUF, 1, &ret); + meson_ao_cec_write(ao_cec, CEC_TX_CLEAR_BUF, 1, &ret); + if (ret) + return ret; + + udelay(100); + + meson_ao_cec_write(ao_cec, CEC_RX_CLEAR_BUF, 0, &ret); + meson_ao_cec_write(ao_cec, CEC_TX_CLEAR_BUF, 0, &ret); + if (ret) + return ret; + + udelay(100); + + meson_ao_cec_write(ao_cec, CEC_RX_MSG_CMD, RX_NO_OP, &ret); + meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_NO_OP, &ret); + + return ret; +} + +static int meson_ao_cec_arbit_bit_time_set(struct meson_ao_cec_device *ao_cec, + unsigned int bit_set, + unsigned int time_set) +{ + int ret = 0; + + switch (bit_set) { + case CEC_SIGNAL_FREE_TIME_RETRY: + meson_ao_cec_write(ao_cec, CEC_TXTIME_4BIT_BIT7_0, + time_set & 0xff, &ret); + meson_ao_cec_write(ao_cec, CEC_TXTIME_4BIT_BIT10_8, + (time_set >> 8) & 0x7, &ret); + break; + + case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR: + meson_ao_cec_write(ao_cec, CEC_TXTIME_2BIT_BIT7_0, + time_set & 0xff, &ret); + meson_ao_cec_write(ao_cec, CEC_TXTIME_2BIT_BIT10_8, + (time_set >> 8) & 0x7, &ret); + break; + + case CEC_SIGNAL_FREE_TIME_NEXT_XFER: + meson_ao_cec_write(ao_cec, CEC_TXTIME_17MS_BIT7_0, + time_set & 0xff, &ret); + meson_ao_cec_write(ao_cec, CEC_TXTIME_17MS_BIT10_8, + (time_set >> 8) & 0x7, &ret); + break; + } + + return ret; +} + +static irqreturn_t meson_ao_cec_irq(int irq, void *data) +{ + struct meson_ao_cec_device *ao_cec = data; + u32 stat = readl_relaxed(ao_cec->base + CEC_INTR_STAT_REG); + + if (stat) + return IRQ_WAKE_THREAD; + + return IRQ_NONE; +} + +static void meson_ao_cec_irq_tx(struct meson_ao_cec_device *ao_cec) +{ + unsigned long tx_status = 0; + u8 stat; + int ret = 0; + + meson_ao_cec_read(ao_cec, CEC_TX_MSG_STATUS, &stat, &ret); + if (ret) + goto tx_reg_err; + + switch (stat) { + case TX_DONE: + tx_status = CEC_TX_STATUS_OK; + break; + + case TX_BUSY: + tx_status = CEC_TX_STATUS_ARB_LOST; + break; + + case TX_IDLE: + tx_status = CEC_TX_STATUS_LOW_DRIVE; + break; + + case TX_ERROR: + default: + tx_status = CEC_TX_STATUS_NACK; + break; + } + + /* Clear Interruption */ + writel_relaxed(CEC_INTR_TX, ao_cec->base + CEC_INTR_CLR_REG); + + /* Stop TX */ + meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_NO_OP, &ret); + if (ret) + goto tx_reg_err; + + cec_transmit_attempt_done(ao_cec->adap, tx_status); + return; + +tx_reg_err: + cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR); +} + +static void meson_ao_cec_irq_rx(struct meson_ao_cec_device *ao_cec) +{ + int i, ret = 0; + u8 reg; + + meson_ao_cec_read(ao_cec, CEC_RX_MSG_STATUS, ®, &ret); + if (reg != RX_DONE) + goto rx_out; + + meson_ao_cec_read(ao_cec, CEC_RX_NUM_MSG, ®, &ret); + if (reg != 1) + goto rx_out; + + meson_ao_cec_read(ao_cec, CEC_RX_MSG_LENGTH, ®, &ret); + + ao_cec->rx_msg.len = reg + 1; + if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE) + ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE; + + for (i = 0; i < ao_cec->rx_msg.len; i++) { + u8 byte; + + meson_ao_cec_read(ao_cec, CEC_RX_MSG_0_HEADER + i, &byte, &ret); + + ao_cec->rx_msg.msg[i] = byte; + } + + if (ret) + goto rx_out; + + cec_received_msg(ao_cec->adap, &ao_cec->rx_msg); + +rx_out: + /* Clear Interruption */ + writel_relaxed(CEC_INTR_RX, ao_cec->base + CEC_INTR_CLR_REG); + + /* Ack RX message */ + meson_ao_cec_write(ao_cec, CEC_RX_MSG_CMD, RX_ACK_CURRENT, &ret); + meson_ao_cec_write(ao_cec, CEC_RX_MSG_CMD, RX_NO_OP, &ret); + + /* Clear RX buffer */ + meson_ao_cec_write(ao_cec, CEC_RX_CLEAR_BUF, CLEAR_START, &ret); + meson_ao_cec_write(ao_cec, CEC_RX_CLEAR_BUF, CLEAR_STOP, &ret); +} + +static irqreturn_t meson_ao_cec_irq_thread(int irq, void *data) +{ + struct meson_ao_cec_device *ao_cec = data; + u32 stat = readl_relaxed(ao_cec->base + CEC_INTR_STAT_REG); + + if (stat & CEC_INTR_TX) + meson_ao_cec_irq_tx(ao_cec); + + meson_ao_cec_irq_rx(ao_cec); + + return IRQ_HANDLED; +} + +static int meson_ao_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) +{ + struct meson_ao_cec_device *ao_cec = adap->priv; + int ret = 0; + + meson_ao_cec_write(ao_cec, CEC_LOGICAL_ADDR0, + LOGICAL_ADDR_DISABLE, &ret); + if (ret) + return ret; + + ret = meson_ao_cec_clear(ao_cec); + if (ret) + return ret; + + if (logical_addr == CEC_LOG_ADDR_INVALID) + return 0; + + meson_ao_cec_write(ao_cec, CEC_LOGICAL_ADDR0, + logical_addr & LOGICAL_ADDR_MASK, &ret); + if (ret) + return ret; + + udelay(100); + + meson_ao_cec_write(ao_cec, CEC_LOGICAL_ADDR0, + (logical_addr & LOGICAL_ADDR_MASK) | + LOGICAL_ADDR_VALID, &ret); + + return ret; +} + +static int meson_ao_cec_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct meson_ao_cec_device *ao_cec = adap->priv; + int i, ret = 0; + u8 reg; + + meson_ao_cec_read(ao_cec, CEC_TX_MSG_STATUS, ®, &ret); + if (ret) + return ret; + + if (reg == TX_BUSY) { + dev_err(&ao_cec->pdev->dev, "%s: busy TX: aborting\n", + __func__); + meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_ABORT, &ret); + } + + for (i = 0; i < msg->len; i++) { + meson_ao_cec_write(ao_cec, CEC_TX_MSG_0_HEADER + i, + msg->msg[i], &ret); + } + + meson_ao_cec_write(ao_cec, CEC_TX_MSG_LENGTH, msg->len - 1, &ret); + meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_REQ_CURRENT, &ret); + + return ret; +} + +static int meson_ao_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct meson_ao_cec_device *ao_cec = adap->priv; + int ret; + + meson_ao_cec_irq_setup(ao_cec, false); + + writel_bits_relaxed(CEC_GEN_CNTL_RESET, CEC_GEN_CNTL_RESET, + ao_cec->base + CEC_GEN_CNTL_REG); + + if (!enable) + return 0; + + /* Enable gated clock (Normal mode). */ + writel_bits_relaxed(CEC_GEN_CNTL_CLK_CTRL_MASK, + FIELD_PREP(CEC_GEN_CNTL_CLK_CTRL_MASK, + CEC_GEN_CNTL_CLK_ENABLE), + ao_cec->base + CEC_GEN_CNTL_REG); + + udelay(100); + + /* Release Reset */ + writel_bits_relaxed(CEC_GEN_CNTL_RESET, 0, + ao_cec->base + CEC_GEN_CNTL_REG); + + /* Clear buffers */ + ret = meson_ao_cec_clear(ao_cec); + if (ret) + return ret; + + /* CEC arbitration 3/5/7 bit time set. */ + ret = meson_ao_cec_arbit_bit_time_set(ao_cec, + CEC_SIGNAL_FREE_TIME_RETRY, + 0x118); + if (ret) + return ret; + ret = meson_ao_cec_arbit_bit_time_set(ao_cec, + CEC_SIGNAL_FREE_TIME_NEW_INITIATOR, + 0x000); + if (ret) + return ret; + ret = meson_ao_cec_arbit_bit_time_set(ao_cec, + CEC_SIGNAL_FREE_TIME_NEXT_XFER, + 0x2aa); + if (ret) + return ret; + + meson_ao_cec_irq_setup(ao_cec, true); + + return 0; +} + +static const struct cec_adap_ops meson_ao_cec_ops = { + .adap_enable = meson_ao_cec_adap_enable, + .adap_log_addr = meson_ao_cec_set_log_addr, + .adap_transmit = meson_ao_cec_transmit, +}; + +static int meson_ao_cec_probe(struct platform_device *pdev) +{ + struct meson_ao_cec_device *ao_cec; + struct platform_device *hdmi_dev; + struct device_node *np; + struct resource *res; + int ret, irq; + + np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); + if (!np) { + dev_err(&pdev->dev, "Failed to find hdmi node\n"); + return -ENODEV; + } + + hdmi_dev = of_find_device_by_node(np); + if (hdmi_dev == NULL) + return -EPROBE_DEFER; + + ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); + if (!ao_cec) + return -ENOMEM; + + spin_lock_init(&ao_cec->cec_reg_lock); + + ao_cec->notify = cec_notifier_get(&hdmi_dev->dev); + if (!ao_cec->notify) + return -ENOMEM; + + ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_ops, ao_cec, + "meson_ao_cec", + CEC_CAP_LOG_ADDRS | + CEC_CAP_TRANSMIT | + CEC_CAP_RC | + CEC_CAP_PASSTHROUGH, + 1); /* Use 1 for now */ + if (IS_ERR(ao_cec->adap)) { + ret = PTR_ERR(ao_cec->adap); + goto out_probe_notify; + } + + ao_cec->adap->owner = THIS_MODULE; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ao_cec->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ao_cec->base)) { + ret = PTR_ERR(ao_cec->base); + goto out_probe_adapter; + } + + irq = platform_get_irq(pdev, 0); + ret = devm_request_threaded_irq(&pdev->dev, irq, + meson_ao_cec_irq, + meson_ao_cec_irq_thread, + 0, NULL, ao_cec); + if (ret) { + dev_err(&pdev->dev, "irq request failed\n"); + goto out_probe_adapter; + } + + ao_cec->core = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(ao_cec->core)) { + dev_err(&pdev->dev, "core clock request failed\n"); + ret = PTR_ERR(ao_cec->core); + goto out_probe_adapter; + } + + ret = clk_prepare_enable(ao_cec->core); + if (ret) { + dev_err(&pdev->dev, "core clock enable failed\n"); + goto out_probe_adapter; + } + + ret = clk_set_rate(ao_cec->core, CEC_CLK_RATE); + if (ret) { + dev_err(&pdev->dev, "core clock set rate failed\n"); + goto out_probe_clk; + } + + device_reset_optional(&pdev->dev); + + ao_cec->pdev = pdev; + platform_set_drvdata(pdev, ao_cec); + + ret = cec_register_adapter(ao_cec->adap, &pdev->dev); + if (ret < 0) { + cec_notifier_put(ao_cec->notify); + goto out_probe_clk; + } + + /* Setup Hardware */ + writel_relaxed(CEC_GEN_CNTL_RESET, + ao_cec->base + CEC_GEN_CNTL_REG); + + cec_register_cec_notifier(ao_cec->adap, ao_cec->notify); + + return 0; + +out_probe_clk: + clk_disable_unprepare(ao_cec->core); + +out_probe_adapter: + cec_delete_adapter(ao_cec->adap); + +out_probe_notify: + cec_notifier_put(ao_cec->notify); + + dev_err(&pdev->dev, "CEC controller registration failed\n"); + + return ret; +} + +static int meson_ao_cec_remove(struct platform_device *pdev) +{ + struct meson_ao_cec_device *ao_cec = platform_get_drvdata(pdev); + + clk_disable_unprepare(ao_cec->core); + + cec_unregister_adapter(ao_cec->adap); + + cec_notifier_put(ao_cec->notify); + + return 0; +} + +static const struct of_device_id meson_ao_cec_of_match[] = { + { .compatible = "amlogic,meson-gx-ao-cec", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, meson_ao_cec_of_match); + +static struct platform_driver meson_ao_cec_driver = { + .probe = meson_ao_cec_probe, + .remove = meson_ao_cec_remove, + .driver = { + .name = "meson-ao-cec", + .of_match_table = of_match_ptr(meson_ao_cec_of_match), + }, +}; + +module_platform_driver(meson_ao_cec_driver); + +MODULE_DESCRIPTION("Meson AO CEC Controller driver"); +MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c index 451a54039e65..226f90886484 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c @@ -756,7 +756,7 @@ static void mtk_jpeg_stop_streaming(struct vb2_queue *q) pm_runtime_put_sync(ctx->jpeg->dev); } -static struct vb2_ops mtk_jpeg_qops = { +static const struct vb2_ops mtk_jpeg_qops = { .queue_setup = mtk_jpeg_queue_setup, .buf_prepare = mtk_jpeg_buf_prepare, .buf_queue = mtk_jpeg_buf_queue, @@ -865,7 +865,7 @@ static void mtk_jpeg_job_abort(void *priv) { } -static struct v4l2_m2m_ops mtk_jpeg_m2m_ops = { +static const struct v4l2_m2m_ops mtk_jpeg_m2m_ops = { .device_run = mtk_jpeg_device_run, .job_ready = mtk_jpeg_job_ready, .job_abort = mtk_jpeg_job_abort, diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c index aa8f9fd1f1a2..03aba03a24c8 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c @@ -75,7 +75,7 @@ void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp) } for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { - if (!comp->clk[i]) + if (IS_ERR(comp->clk[i])) continue; err = clk_prepare_enable(comp->clk[i]); if (err) @@ -90,7 +90,7 @@ void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp) int i; for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { - if (!comp->clk[i]) + if (IS_ERR(comp->clk[i])) continue; clk_disable_unprepare(comp->clk[i]); } @@ -134,15 +134,13 @@ int mtk_mdp_comp_init(struct device *dev, struct device_node *node, larb_node = of_parse_phandle(node, "mediatek,larb", 0); if (!larb_node) { dev_err(dev, - "Missing mediadek,larb phandle in %s node\n", - node->full_name); + "Missing mediadek,larb phandle in %pOF node\n", node); return -EINVAL; } larb_pdev = of_find_device_by_node(larb_node); if (!larb_pdev) { - dev_warn(dev, "Waiting for larb device %s\n", - larb_node->full_name); + dev_warn(dev, "Waiting for larb device %pOF\n", larb_node); of_node_put(larb_node); return -EPROBE_DEFER; } diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c index 81347558b24a..bbb24fb95b95 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c @@ -137,16 +137,16 @@ static int mtk_mdp_probe(struct platform_device *pdev) continue; if (!of_device_is_available(node)) { - dev_err(dev, "Skipping disabled component %s\n", - node->full_name); + dev_err(dev, "Skipping disabled component %pOF\n", + node); continue; } comp_type = (enum mtk_mdp_comp_type)of_id->data; comp_id = mtk_mdp_comp_get_id(dev, node, comp_type); if (comp_id < 0) { - dev_warn(dev, "Skipping unknown component %s\n", - node->full_name); + dev_warn(dev, "Skipping unknown component %pOF\n", + node); continue; } diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c index 13afe48b9dc5..583d47724ee8 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c @@ -621,7 +621,7 @@ static void mtk_mdp_m2m_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); } -static struct vb2_ops mtk_mdp_m2m_qops = { +static const struct vb2_ops mtk_mdp_m2m_qops = { .queue_setup = mtk_mdp_m2m_queue_setup, .buf_prepare = mtk_mdp_m2m_buf_prepare, .buf_queue = mtk_mdp_m2m_buf_queue, @@ -1225,7 +1225,7 @@ static const struct v4l2_file_operations mtk_mdp_m2m_fops = { .mmap = v4l2_m2m_fop_mmap, }; -static struct v4l2_m2m_ops mtk_mdp_m2m_ops = { +static const struct v4l2_m2m_ops mtk_mdp_m2m_ops = { .device_run = mtk_mdp_m2m_device_run, .job_abort = mtk_mdp_m2m_job_abort, }; diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c index 1daee1207469..bc8349bc2e80 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c @@ -31,6 +31,7 @@ #define MAX_NUM_REF_FRAMES 8 #define VP9_MAX_FRM_BUF_NUM 9 #define VP9_MAX_FRM_BUF_NODE_NUM (VP9_MAX_FRM_BUF_NUM * 2) +#define VP9_SEG_ID_SZ 0x12000 /** * struct vp9_dram_buf - contains buffer info for vpu @@ -132,6 +133,7 @@ struct vp9_sf_ref_fb { * @frm_num : decoded frame number, include sub-frame count (AP-R, VPU-W) * @mv_buf : motion vector working buffer (AP-W, VPU-R) * @frm_refs : maintain three reference buffer info (AP-R/W, VPU-R/W) + * @seg_id_buf : segmentation map working buffer (AP-W, VPU-R) */ struct vdec_vp9_vsi { unsigned char sf_bs_buf[VP9_SUPER_FRAME_BS_SZ]; @@ -167,11 +169,14 @@ struct vdec_vp9_vsi { struct vp9_dram_buf mv_buf; struct vp9_ref_buf frm_refs[REFS_PER_FRAME]; + struct vp9_dram_buf seg_id_buf; + }; /* * struct vdec_vp9_inst - vp9 decode instance * @mv_buf : working buffer for mv + * @seg_id_buf : working buffer for segmentation map * @dec_fb : vdec_fb node to link fb to different fb_xxx_list * @available_fb_node_list : current available vdec_fb node * @fb_use_list : current used or referenced vdec_fb @@ -187,6 +192,7 @@ struct vdec_vp9_vsi { */ struct vdec_vp9_inst { struct mtk_vcodec_mem mv_buf; + struct mtk_vcodec_mem seg_id_buf; struct vdec_fb_node dec_fb[VP9_MAX_FRM_BUF_NODE_NUM]; struct list_head available_fb_node_list; @@ -388,13 +394,11 @@ static bool vp9_alloc_work_buf(struct vdec_vp9_inst *inst) vsi->buf_h); mem = &inst->mv_buf; - if (mem->va) mtk_vcodec_mem_free(inst->ctx, mem); mem->size = ((vsi->buf_w / 64) * (vsi->buf_h / 64) + 2) * 36 * 16; - result = mtk_vcodec_mem_alloc(inst->ctx, mem); if (result) { mem->size = 0; @@ -406,6 +410,24 @@ static bool vp9_alloc_work_buf(struct vdec_vp9_inst *inst) vsi->mv_buf.pa = (unsigned long)mem->dma_addr; vsi->mv_buf.sz = (unsigned int)mem->size; + + mem = &inst->seg_id_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + + mem->size = VP9_SEG_ID_SZ; + result = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (result) { + mem->size = 0; + mtk_vcodec_err(inst, "Cannot allocate seg_id_buf"); + return false; + } + /* Set the va again */ + vsi->seg_id_buf.va = (unsigned long)mem->va; + vsi->seg_id_buf.pa = (unsigned long)mem->dma_addr; + vsi->seg_id_buf.sz = (unsigned int)mem->size; + + vp9_free_all_sf_ref_fb(inst); vsi->sf_next_ref_fb_idx = vp9_get_sf_ref_fb(inst); @@ -653,6 +675,12 @@ static void vp9_reset(struct vdec_vp9_inst *inst) inst->vsi->mv_buf.va = (unsigned long)inst->mv_buf.va; inst->vsi->mv_buf.pa = (unsigned long)inst->mv_buf.dma_addr; inst->vsi->mv_buf.sz = (unsigned long)inst->mv_buf.size; + + /* Set the va again, since vpu_dec_reset will clear seg_id_buf in vpu */ + inst->vsi->seg_id_buf.va = (unsigned long)inst->seg_id_buf.va; + inst->vsi->seg_id_buf.pa = (unsigned long)inst->seg_id_buf.dma_addr; + inst->vsi->seg_id_buf.sz = (unsigned long)inst->seg_id_buf.size; + } static void init_all_fb_lists(struct vdec_vp9_inst *inst) @@ -752,6 +780,10 @@ static void vdec_vp9_deinit(unsigned long h_vdec) if (mem->va) mtk_vcodec_mem_free(inst->ctx, mem); + mem = &inst->seg_id_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + vp9_free_all_sf_ref_fb(inst); vp9_free_inst(inst); } @@ -848,6 +880,7 @@ static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, vsi->sf_frm_sz[idx]); } } + memset(inst->seg_id_buf.va, 0, inst->seg_id_buf.size); ret = vpu_dec_start(&inst->vpu, data, 3); if (ret) { mtk_vcodec_err(inst, "vpu_dec_start failed"); diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index 03e47e0f778d..4a2b1afa19c4 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -873,7 +873,7 @@ static const struct v4l2_file_operations emmaprp_fops = { .mmap = emmaprp_mmap, }; -static struct video_device emmaprp_videodev = { +static const struct video_device emmaprp_videodev = { .name = MEM2MEM_NAME, .fops = &emmaprp_fops, .ioctl_ops = &emmaprp_ioctl_ops, @@ -882,7 +882,7 @@ static struct video_device emmaprp_videodev = { .vfl_dir = VFL_DIR_M2M, }; -static struct v4l2_m2m_ops m2m_ops = { +static const struct v4l2_m2m_ops m2m_ops = { .device_run = emmaprp_device_run, .job_abort = emmaprp_job_abort, .lock = emmaprp_lock, @@ -942,6 +942,8 @@ static int emmaprp_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pcdev); irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; ret = devm_request_irq(&pdev->dev, irq, emmaprp_irq, 0, dev_name(&pdev->dev), pcdev); if (ret) diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index 45a553d4f5b2..123c2b26a933 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c @@ -12,6 +12,7 @@ #include <linux/sched.h> #include <linux/platform_device.h> #include <linux/videodev2.h> +#include <linux/slab.h> #include <media/videobuf-dma-contig.h> #include <media/v4l2-device.h> @@ -233,7 +234,7 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout, struct videobuf_buffer *vb) { struct dma_async_tx_descriptor *tx; - enum dma_ctrl_flags flags; + enum dma_ctrl_flags flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; struct dma_chan *chan = vout->vrfb_dma_tx.chan; struct dma_device *dmadev = chan->device; struct dma_interleaved_template *xt = vout->vrfb_dma_tx.xt; diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 9df64c189883..1a428fe9f070 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -1859,6 +1859,7 @@ static void isp_cleanup_modules(struct isp_device *isp) omap3isp_ccdc_cleanup(isp); omap3isp_ccp2_cleanup(isp); omap3isp_csi2_cleanup(isp); + omap3isp_csiphy_cleanup(isp); } static int isp_initialize_modules(struct isp_device *isp) @@ -1868,7 +1869,7 @@ static int isp_initialize_modules(struct isp_device *isp) ret = omap3isp_csiphy_init(isp); if (ret < 0) { dev_err(isp->dev, "CSI PHY initialization failed\n"); - goto error_csiphy; + return ret; } ret = omap3isp_csi2_init(isp); @@ -1879,7 +1880,8 @@ static int isp_initialize_modules(struct isp_device *isp) ret = omap3isp_ccp2_init(isp); if (ret < 0) { - dev_err(isp->dev, "CCP2 initialization failed\n"); + if (ret != -EPROBE_DEFER) + dev_err(isp->dev, "CCP2 initialization failed\n"); goto error_ccp2; } @@ -1936,7 +1938,8 @@ error_ccdc: error_ccp2: omap3isp_csi2_cleanup(isp); error_csi2: -error_csiphy: + omap3isp_csiphy_cleanup(isp); + return ret; } @@ -2015,13 +2018,14 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint vep; unsigned int i; int ret; + bool csi1 = false; ret = v4l2_fwnode_endpoint_parse(fwnode, &vep); if (ret) return ret; - dev_dbg(dev, "parsing endpoint %s, interface %u\n", - to_of_node(fwnode)->full_name, vep.base.port); + dev_dbg(dev, "parsing endpoint %pOF, interface %u\n", + to_of_node(fwnode), vep.base.port); switch (vep.base.port) { case ISP_OF_PHY_PARALLEL: @@ -2039,48 +2043,102 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode, !!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW); buscfg->bus.parallel.data_pol = !!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW); + buscfg->bus.parallel.bt656 = vep.bus_type == V4L2_MBUS_BT656; break; case ISP_OF_PHY_CSIPHY1: case ISP_OF_PHY_CSIPHY2: - /* FIXME: always assume CSI-2 for now. */ + switch (vep.bus_type) { + case V4L2_MBUS_CCP2: + case V4L2_MBUS_CSI1: + dev_dbg(dev, "CSI-1/CCP-2 configuration\n"); + csi1 = true; + break; + case V4L2_MBUS_CSI2: + dev_dbg(dev, "CSI-2 configuration\n"); + csi1 = false; + break; + default: + dev_err(dev, "unsupported bus type %u\n", + vep.bus_type); + return -EINVAL; + } + switch (vep.base.port) { case ISP_OF_PHY_CSIPHY1: - buscfg->interface = ISP_INTERFACE_CSI2C_PHY1; + if (csi1) + buscfg->interface = ISP_INTERFACE_CCP2B_PHY1; + else + buscfg->interface = ISP_INTERFACE_CSI2C_PHY1; break; case ISP_OF_PHY_CSIPHY2: - buscfg->interface = ISP_INTERFACE_CSI2A_PHY2; + if (csi1) + buscfg->interface = ISP_INTERFACE_CCP2B_PHY2; + else + buscfg->interface = ISP_INTERFACE_CSI2A_PHY2; break; } - buscfg->bus.csi2.lanecfg.clk.pos = vep.bus.mipi_csi2.clock_lane; - buscfg->bus.csi2.lanecfg.clk.pol = - vep.bus.mipi_csi2.lane_polarities[0]; - dev_dbg(dev, "clock lane polarity %u, pos %u\n", - buscfg->bus.csi2.lanecfg.clk.pol, - buscfg->bus.csi2.lanecfg.clk.pos); - - for (i = 0; i < ISP_CSIPHY2_NUM_DATA_LANES; i++) { - buscfg->bus.csi2.lanecfg.data[i].pos = - vep.bus.mipi_csi2.data_lanes[i]; - buscfg->bus.csi2.lanecfg.data[i].pol = - vep.bus.mipi_csi2.lane_polarities[i + 1]; - dev_dbg(dev, "data lane %u polarity %u, pos %u\n", i, - buscfg->bus.csi2.lanecfg.data[i].pol, - buscfg->bus.csi2.lanecfg.data[i].pos); + if (csi1) { + buscfg->bus.ccp2.lanecfg.clk.pos = + vep.bus.mipi_csi1.clock_lane; + buscfg->bus.ccp2.lanecfg.clk.pol = + vep.bus.mipi_csi1.lane_polarity[0]; + dev_dbg(dev, "clock lane polarity %u, pos %u\n", + buscfg->bus.ccp2.lanecfg.clk.pol, + buscfg->bus.ccp2.lanecfg.clk.pos); + + buscfg->bus.ccp2.lanecfg.data[0].pos = + vep.bus.mipi_csi1.data_lane; + buscfg->bus.ccp2.lanecfg.data[0].pol = + vep.bus.mipi_csi1.lane_polarity[1]; + + dev_dbg(dev, "data lane polarity %u, pos %u\n", + buscfg->bus.ccp2.lanecfg.data[0].pol, + buscfg->bus.ccp2.lanecfg.data[0].pos); + + buscfg->bus.ccp2.strobe_clk_pol = + vep.bus.mipi_csi1.clock_inv; + buscfg->bus.ccp2.phy_layer = vep.bus.mipi_csi1.strobe; + buscfg->bus.ccp2.ccp2_mode = + vep.bus_type == V4L2_MBUS_CCP2; + buscfg->bus.ccp2.vp_clk_pol = 1; + + buscfg->bus.ccp2.crc = 1; + } else { + buscfg->bus.csi2.lanecfg.clk.pos = + vep.bus.mipi_csi2.clock_lane; + buscfg->bus.csi2.lanecfg.clk.pol = + vep.bus.mipi_csi2.lane_polarities[0]; + dev_dbg(dev, "clock lane polarity %u, pos %u\n", + buscfg->bus.csi2.lanecfg.clk.pol, + buscfg->bus.csi2.lanecfg.clk.pos); + + buscfg->bus.csi2.num_data_lanes = + vep.bus.mipi_csi2.num_data_lanes; + + for (i = 0; i < buscfg->bus.csi2.num_data_lanes; i++) { + buscfg->bus.csi2.lanecfg.data[i].pos = + vep.bus.mipi_csi2.data_lanes[i]; + buscfg->bus.csi2.lanecfg.data[i].pol = + vep.bus.mipi_csi2.lane_polarities[i + 1]; + dev_dbg(dev, + "data lane %u polarity %u, pos %u\n", i, + buscfg->bus.csi2.lanecfg.data[i].pol, + buscfg->bus.csi2.lanecfg.data[i].pos); + } + /* + * FIXME: now we assume the CRC is always there. + * Implement a way to obtain this information from the + * sensor. Frame descriptors, perhaps? + */ + buscfg->bus.csi2.crc = 1; } - - /* - * FIXME: now we assume the CRC is always there. - * Implement a way to obtain this information from the - * sensor. Frame descriptors, perhaps? - */ - buscfg->bus.csi2.crc = 1; break; default: - dev_warn(dev, "%s: invalid interface %u\n", - to_of_node(fwnode)->full_name, vep.base.port); - break; + dev_warn(dev, "%pOF: invalid interface %u\n", + to_of_node(fwnode), vep.base.port); + return -EINVAL; } return 0; @@ -2105,10 +2163,12 @@ static int isp_fwnodes_parse(struct device *dev, if (!isd) goto error; - notifier->subdevs[notifier->num_subdevs] = &isd->asd; + if (isp_fwnode_parse(dev, fwnode, isd)) { + devm_kfree(dev, isd); + continue; + } - if (isp_fwnode_parse(dev, fwnode, isd)) - goto error; + notifier->subdevs[notifier->num_subdevs] = &isd->asd; isd->asd.match.fwnode.fwnode = fwnode_graph_get_remote_port_parent(fwnode); @@ -2128,26 +2188,12 @@ error: return -EINVAL; } -static int isp_subdev_notifier_bound(struct v4l2_async_notifier *async, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd) -{ - struct isp_async_subdev *isd = - container_of(asd, struct isp_async_subdev, asd); - - isd->sd = subdev; - isd->sd->host_priv = &isd->bus; - - return 0; -} - static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) { struct isp_device *isp = container_of(async, struct isp_device, notifier); struct v4l2_device *v4l2_dev = &isp->v4l2_dev; struct v4l2_subdev *sd; - struct isp_bus_cfg *bus; int ret; ret = media_entity_enum_init(&isp->crashed, &isp->media_dev); @@ -2155,13 +2201,13 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) return ret; list_for_each_entry(sd, &v4l2_dev->subdevs, list) { - /* Only try to link entities whose interface was set on bound */ - if (sd->host_priv) { - bus = (struct isp_bus_cfg *)sd->host_priv; - ret = isp_link_entity(isp, &sd->entity, bus->interface); - if (ret < 0) - return ret; - } + if (!sd->asd) + continue; + + ret = isp_link_entity(isp, &sd->entity, + v4l2_subdev_to_bus_cfg(sd)->interface); + if (ret < 0) + return ret; } ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); @@ -2339,7 +2385,6 @@ static int isp_probe(struct platform_device *pdev) if (ret < 0) goto error_register_entities; - isp->notifier.bound = isp_subdev_notifier_bound; isp->notifier.complete = isp_subdev_notifier_complete; ret = v4l2_async_notifier_register(&isp->v4l2_dev, &isp->notifier); diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 2f2ae609c548..e528df6efc09 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -226,11 +226,13 @@ struct isp_device { }; struct isp_async_subdev { - struct v4l2_subdev *sd; struct isp_bus_cfg bus; struct v4l2_async_subdev asd; }; +#define v4l2_subdev_to_bus_cfg(sd) \ + (&container_of((sd)->asd, struct isp_async_subdev, asd)->bus) + #define v4l2_dev_to_isp_device(dev) \ container_of(dev, struct isp_device, v4l2_dev) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 7207558d722c..b66276ab5765 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1139,15 +1139,11 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); if (ccdc->input == CCDC_INPUT_PARALLEL) { - struct v4l2_mbus_config cfg; - int ret; + struct v4l2_subdev *sd = + to_isp_pipeline(&ccdc->subdev.entity)->external; - ret = v4l2_subdev_call(sensor, video, g_mbus_config, &cfg); - if (!ret) - ccdc->bt656 = cfg.type == V4L2_MBUS_BT656; - - parcfg = &((struct isp_bus_cfg *)sensor->host_priv) - ->bus.parallel; + parcfg = &v4l2_subdev_to_bus_cfg(sd)->bus.parallel; + ccdc->bt656 = parcfg->bt656; } /* CCDC_PAD_SINK */ @@ -2418,11 +2414,11 @@ static int ccdc_link_validate(struct v4l2_subdev *sd, /* We've got a parallel sensor here. */ if (ccdc->input == CCDC_INPUT_PARALLEL) { - struct isp_parallel_cfg *parcfg = - &((struct isp_bus_cfg *) - media_entity_to_v4l2_subdev(link->source->entity) - ->host_priv)->bus.parallel; - parallel_shift = parcfg->data_lane_shift; + struct v4l2_subdev *sd = + media_entity_to_v4l2_subdev(link->source->entity); + struct isp_bus_cfg *bus_cfg = v4l2_subdev_to_bus_cfg(sd); + + parallel_shift = bus_cfg->bus.parallel.data_lane_shift; } else { parallel_shift = 0; } diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index ca095238510d..e062939d0d05 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -213,14 +213,17 @@ static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, struct isp_device *isp = to_isp_device(ccp2); u32 val; - /* CCP2B mode */ val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL) | - ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE; + ISPCCP2_CTRL_MODE; /* Data/strobe physical layer */ BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK, buscfg->phy_layer); + BIT_SET(val, ISPCCP2_CTRL_IO_OUT_SEL_SHIFT, + ISPCCP2_CTRL_IO_OUT_SEL_MASK, buscfg->ccp2_mode); BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK, buscfg->strobe_clk_pol); + BIT_SET(val, ISPCCP2_CTRL_VP_CLK_POL_SHIFT, + ISPCCP2_CTRL_VP_CLK_POL_MASK, buscfg->vp_clk_pol); isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); @@ -347,6 +350,7 @@ static void ccp2_lcx_config(struct isp_ccp2_device *ccp2, */ static int ccp2_if_configure(struct isp_ccp2_device *ccp2) { + struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); const struct isp_bus_cfg *buscfg; struct v4l2_mbus_framefmt *format; struct media_pad *pad; @@ -358,7 +362,7 @@ static int ccp2_if_configure(struct isp_ccp2_device *ccp2) pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); - buscfg = sensor->host_priv; + buscfg = v4l2_subdev_to_bus_cfg(pipe->external); ret = ccp2_phyif_config(ccp2, &buscfg->bus.ccp2); if (ret < 0) @@ -838,7 +842,7 @@ static int ccp2_s_stream(struct v4l2_subdev *sd, int enable) switch (enable) { case ISP_PIPELINE_STREAM_CONTINUOUS: if (ccp2->phy) { - ret = omap3isp_csiphy_acquire(ccp2->phy); + ret = omap3isp_csiphy_acquire(ccp2->phy, &sd->entity); if (ret < 0) return ret; } @@ -1137,10 +1141,16 @@ int omap3isp_ccp2_init(struct isp_device *isp) if (isp->revision == ISP_REVISION_2_0) { ccp2->vdds_csib = devm_regulator_get(isp->dev, "vdds_csib"); if (IS_ERR(ccp2->vdds_csib)) { + if (PTR_ERR(ccp2->vdds_csib) == -EPROBE_DEFER) { + dev_dbg(isp->dev, + "Can't get regulator vdds_csib, deferring probing\n"); + return -EPROBE_DEFER; + } dev_dbg(isp->dev, "Could not get regulator vdds_csib\n"); ccp2->vdds_csib = NULL; } + ccp2->phy = &isp->isp_csiphy2; } else if (isp->revision == ISP_REVISION_15_0) { ccp2->phy = &isp->isp_csiphy1; } diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 7dae2fe0d42d..a4d3d030e81e 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -490,7 +490,7 @@ int omap3isp_csi2_reset(struct isp_csi2_device *csi2) if (!csi2->available) return -ENODEV; - if (csi2->phy->phy_in_use) + if (csi2->phy->entity) return -EBUSY; isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, @@ -566,7 +566,7 @@ static int csi2_configure(struct isp_csi2_device *csi2) pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); - buscfg = sensor->host_priv; + buscfg = v4l2_subdev_to_bus_cfg(pipe->external); csi2->frame_skip = 0; v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); @@ -1053,7 +1053,7 @@ static int csi2_set_stream(struct v4l2_subdev *sd, int enable) switch (enable) { case ISP_PIPELINE_STREAM_CONTINUOUS: - if (omap3isp_csiphy_acquire(csi2->phy) < 0) + if (omap3isp_csiphy_acquire(csi2->phy, &sd->entity) < 0) return -ENODEV; if (csi2->output & CSI2_OUTPUT_MEMORY) omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE); diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c index 871d4fe09c7f..a28fb79abaac 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.c +++ b/drivers/media/platform/omap3isp/ispcsiphy.c @@ -164,30 +164,28 @@ static int csiphy_set_power(struct isp_csiphy *phy, u32 power) static int omap3isp_csiphy_config(struct isp_csiphy *phy) { - struct isp_csi2_device *csi2 = phy->csi2; - struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); - struct isp_bus_cfg *buscfg = pipe->external->host_priv; + struct isp_pipeline *pipe = to_isp_pipeline(phy->entity); + struct isp_bus_cfg *buscfg = v4l2_subdev_to_bus_cfg(pipe->external); struct isp_csiphy_lanes_cfg *lanes; int csi2_ddrclk_khz; - unsigned int used_lanes = 0; + unsigned int num_data_lanes, used_lanes = 0; unsigned int i; u32 reg; - if (!buscfg) { - struct isp_async_subdev *isd = - container_of(pipe->external->asd, - struct isp_async_subdev, asd); - buscfg = &isd->bus; - } - if (buscfg->interface == ISP_INTERFACE_CCP2B_PHY1 - || buscfg->interface == ISP_INTERFACE_CCP2B_PHY2) + || buscfg->interface == ISP_INTERFACE_CCP2B_PHY2) { lanes = &buscfg->bus.ccp2.lanecfg; - else + num_data_lanes = 1; + } else { lanes = &buscfg->bus.csi2.lanecfg; + num_data_lanes = buscfg->bus.csi2.num_data_lanes; + } + + if (num_data_lanes > phy->num_data_lanes) + return -EINVAL; /* Clock and data lanes verification */ - for (i = 0; i < phy->num_data_lanes; i++) { + for (i = 0; i < num_data_lanes; i++) { if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3) return -EINVAL; @@ -216,7 +214,7 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy) csi2_ddrclk_khz = pipe->external_rate / 1000 / (2 * hweight32(used_lanes)) * pipe->external_width; - reg = isp_reg_readl(csi2->isp, phy->phy_regs, ISPCSIPHY_REG0); + reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG0); reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK | ISPCSIPHY_REG0_THS_SETTLE_MASK); @@ -227,9 +225,9 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy) reg |= (DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3) << ISPCSIPHY_REG0_THS_SETTLE_SHIFT; - isp_reg_writel(csi2->isp, reg, phy->phy_regs, ISPCSIPHY_REG0); + isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG0); - reg = isp_reg_readl(csi2->isp, phy->phy_regs, ISPCSIPHY_REG1); + reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG1); reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK | ISPCSIPHY_REG1_TCLK_MISS_MASK | @@ -238,12 +236,12 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy) reg |= TCLK_MISS << ISPCSIPHY_REG1_TCLK_MISS_SHIFT; reg |= TCLK_SETTLE << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT; - isp_reg_writel(csi2->isp, reg, phy->phy_regs, ISPCSIPHY_REG1); + isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1); /* DPHY lane configuration */ - reg = isp_reg_readl(csi2->isp, phy->cfg_regs, ISPCSI2_PHY_CFG); + reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG); - for (i = 0; i < phy->num_data_lanes; i++) { + for (i = 0; i < num_data_lanes; i++) { reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) | ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1)); reg |= (lanes->data[i].pol << @@ -257,12 +255,12 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy) reg |= lanes->clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT; reg |= lanes->clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT; - isp_reg_writel(csi2->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG); + isp_reg_writel(phy->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG); return 0; } -int omap3isp_csiphy_acquire(struct isp_csiphy *phy) +int omap3isp_csiphy_acquire(struct isp_csiphy *phy, struct media_entity *entity) { int rval; @@ -282,20 +280,25 @@ int omap3isp_csiphy_acquire(struct isp_csiphy *phy) if (rval < 0) goto done; + phy->entity = entity; + rval = omap3isp_csiphy_config(phy); if (rval < 0) goto done; - rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON); - if (rval) { - regulator_disable(phy->vdd); - goto done; - } - - csiphy_power_autoswitch_enable(phy, true); - phy->phy_in_use = 1; + if (phy->isp->revision == ISP_REVISION_15_0) { + rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON); + if (rval) { + regulator_disable(phy->vdd); + goto done; + } + csiphy_power_autoswitch_enable(phy, true); + } done: + if (rval < 0) + phy->entity = NULL; + mutex_unlock(&phy->mutex); return rval; } @@ -303,18 +306,19 @@ done: void omap3isp_csiphy_release(struct isp_csiphy *phy) { mutex_lock(&phy->mutex); - if (phy->phy_in_use) { - struct isp_csi2_device *csi2 = phy->csi2; - struct isp_pipeline *pipe = - to_isp_pipeline(&csi2->subdev.entity); - struct isp_bus_cfg *buscfg = pipe->external->host_priv; + if (phy->entity) { + struct isp_pipeline *pipe = to_isp_pipeline(phy->entity); + struct isp_bus_cfg *buscfg = + v4l2_subdev_to_bus_cfg(pipe->external); csiphy_routing_cfg(phy, buscfg->interface, false, buscfg->bus.ccp2.phy_layer); - csiphy_power_autoswitch_enable(phy, false); - csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF); + if (phy->isp->revision == ISP_REVISION_15_0) { + csiphy_power_autoswitch_enable(phy, false); + csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF); + } regulator_disable(phy->vdd); - phy->phy_in_use = 0; + phy->entity = NULL; } mutex_unlock(&phy->mutex); } @@ -334,14 +338,21 @@ int omap3isp_csiphy_init(struct isp_device *isp) phy2->phy_regs = OMAP3_ISP_IOMEM_CSIPHY2; mutex_init(&phy2->mutex); + phy1->isp = isp; + mutex_init(&phy1->mutex); + if (isp->revision == ISP_REVISION_15_0) { - phy1->isp = isp; phy1->csi2 = &isp->isp_csi2c; phy1->num_data_lanes = ISP_CSIPHY1_NUM_DATA_LANES; phy1->cfg_regs = OMAP3_ISP_IOMEM_CSI2C_REGS1; phy1->phy_regs = OMAP3_ISP_IOMEM_CSIPHY1; - mutex_init(&phy1->mutex); } return 0; } + +void omap3isp_csiphy_cleanup(struct isp_device *isp) +{ + mutex_destroy(&isp->isp_csiphy1.mutex); + mutex_destroy(&isp->isp_csiphy2.mutex); +} diff --git a/drivers/media/platform/omap3isp/ispcsiphy.h b/drivers/media/platform/omap3isp/ispcsiphy.h index 28b63b28f9f7..91543a09b28a 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.h +++ b/drivers/media/platform/omap3isp/ispcsiphy.h @@ -25,9 +25,10 @@ struct regulator; struct isp_csiphy { struct isp_device *isp; struct mutex mutex; /* serialize csiphy configuration */ - u8 phy_in_use; struct isp_csi2_device *csi2; struct regulator *vdd; + /* the entity that acquired the phy */ + struct media_entity *entity; /* mem resources - enums as defined in enum isp_mem_resources */ unsigned int cfg_regs; @@ -36,8 +37,10 @@ struct isp_csiphy { u8 num_data_lanes; /* number of CSI2 Data Lanes supported */ }; -int omap3isp_csiphy_acquire(struct isp_csiphy *phy); +int omap3isp_csiphy_acquire(struct isp_csiphy *phy, + struct media_entity *entity); void omap3isp_csiphy_release(struct isp_csiphy *phy); int omap3isp_csiphy_init(struct isp_device *isp); +void omap3isp_csiphy_cleanup(struct isp_device *isp); #endif /* OMAP3_ISP_CSI_PHY_H */ diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h index b5ea8da0b904..d08483919a77 100644 --- a/drivers/media/platform/omap3isp/ispreg.h +++ b/drivers/media/platform/omap3isp/ispreg.h @@ -87,6 +87,8 @@ #define ISPCCP2_CTRL_PHY_SEL_MASK 0x1 #define ISPCCP2_CTRL_PHY_SEL_SHIFT 1 #define ISPCCP2_CTRL_IO_OUT_SEL (1 << 2) +#define ISPCCP2_CTRL_IO_OUT_SEL_MASK 0x1 +#define ISPCCP2_CTRL_IO_OUT_SEL_SHIFT 2 #define ISPCCP2_CTRL_MODE (1 << 4) #define ISPCCP2_CTRL_VP_CLK_FORCE_ON (1 << 9) #define ISPCCP2_CTRL_INV (1 << 10) @@ -94,6 +96,8 @@ #define ISPCCP2_CTRL_INV_SHIFT 10 #define ISPCCP2_CTRL_VP_ONLY_EN (1 << 11) #define ISPCCP2_CTRL_VP_CLK_POL (1 << 12) +#define ISPCCP2_CTRL_VP_CLK_POL_MASK 0x1 +#define ISPCCP2_CTRL_VP_CLK_POL_SHIFT 12 #define ISPCCP2_CTRL_VPCLK_DIV_SHIFT 15 #define ISPCCP2_CTRL_VPCLK_DIV_MASK 0x1ffff /* [31:15] */ #define ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT 8 /* 3430 bits */ diff --git a/drivers/media/platform/omap3isp/omap3isp.h b/drivers/media/platform/omap3isp/omap3isp.h index 443e8f7673e2..9fb4d5bce004 100644 --- a/drivers/media/platform/omap3isp/omap3isp.h +++ b/drivers/media/platform/omap3isp/omap3isp.h @@ -46,6 +46,7 @@ enum isp_interface_type { * 0 - Positive, 1 - Negative * @data_pol: Data polarity * 0 - Normal, 1 - One's complement + * @bt656: Data contain BT.656 embedded synchronization */ struct isp_parallel_cfg { unsigned int data_lane_shift:3; @@ -54,6 +55,7 @@ struct isp_parallel_cfg { unsigned int vs_pol:1; unsigned int fld_pol:1; unsigned int data_pol:1; + unsigned int bt656:1; }; enum { @@ -108,16 +110,20 @@ struct isp_ccp2_cfg { unsigned int ccp2_mode:1; unsigned int phy_layer:1; unsigned int vpclk_div:2; + unsigned int vp_clk_pol:1; struct isp_csiphy_lanes_cfg lanecfg; }; /** * struct isp_csi2_cfg - CSI2 interface configuration * @crc: Enable the cyclic redundancy check + * @lanecfg: CSI-2 lane configuration + * @num_data_lanes: The number of data lanes in use */ struct isp_csi2_cfg { unsigned crc:1; struct isp_csiphy_lanes_cfg lanecfg; + u8 num_data_lanes; }; struct isp_bus_cfg { diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index 399095170b6e..edca993c2b1f 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -638,6 +638,9 @@ static unsigned int pxa_mbus_config_compatible(const struct v4l2_mbus_config *cf mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK); return (!mipi_lanes || !mipi_clock) ? 0 : common_flags; + default: + WARN_ON(1); + return -EINVAL; } return 0; } @@ -1557,7 +1560,7 @@ static void pxac_vb2_stop_streaming(struct vb2_queue *vq) pxa_camera_wakeup(pcdev, buf, VB2_BUF_STATE_ERROR); } -static struct vb2_ops pxac_vb2_ops = { +static const struct vb2_ops pxac_vb2_ops = { .queue_setup = pxac_vb2_queue_setup, .buf_init = pxac_vb2_init, .buf_prepare = pxac_vb2_prepare, @@ -2097,7 +2100,7 @@ static const struct v4l2_ioctl_ops pxa_camera_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static struct v4l2_clk_ops pxa_camera_mclk_ops = { +static const struct v4l2_clk_ops pxa_camera_mclk_ops = { }; static const struct video_device pxa_camera_videodev_template = { @@ -2328,7 +2331,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev, asd->match.fwnode.fwnode = of_fwnode_handle(remote); of_node_put(remote); } else { - dev_notice(dev, "no remote for %s\n", of_node_full_name(np)); + dev_notice(dev, "no remote for %pOF\n", np); } out: diff --git a/drivers/media/platform/qcom/camss-8x16/Makefile b/drivers/media/platform/qcom/camss-8x16/Makefile new file mode 100644 index 000000000000..3c4024fbb768 --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/Makefile @@ -0,0 +1,11 @@ +# Makefile for Qualcomm CAMSS driver + +qcom-camss-objs += \ + camss.o \ + camss-csid.o \ + camss-csiphy.o \ + camss-ispif.o \ + camss-vfe.o \ + camss-video.o \ + +obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom-camss.o diff --git a/drivers/media/platform/qcom/camss-8x16/camss-csid.c b/drivers/media/platform/qcom/camss-8x16/camss-csid.c new file mode 100644 index 000000000000..64df82817de3 --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/camss-csid.c @@ -0,0 +1,1092 @@ +/* + * camss-csid.c + * + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module + * + * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <media/media-entity.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> + +#include "camss-csid.h" +#include "camss.h" + +#define MSM_CSID_NAME "msm_csid" + +#define CAMSS_CSID_HW_VERSION 0x0 +#define CAMSS_CSID_CORE_CTRL_0 0x004 +#define CAMSS_CSID_CORE_CTRL_1 0x008 +#define CAMSS_CSID_RST_CMD 0x00c +#define CAMSS_CSID_CID_LUT_VC_n(n) (0x010 + 0x4 * (n)) +#define CAMSS_CSID_CID_n_CFG(n) (0x020 + 0x4 * (n)) +#define CAMSS_CSID_IRQ_CLEAR_CMD 0x060 +#define CAMSS_CSID_IRQ_MASK 0x064 +#define CAMSS_CSID_IRQ_STATUS 0x068 +#define CAMSS_CSID_TG_CTRL 0x0a0 +#define CAMSS_CSID_TG_CTRL_DISABLE 0xa06436 +#define CAMSS_CSID_TG_CTRL_ENABLE 0xa06437 +#define CAMSS_CSID_TG_VC_CFG 0x0a4 +#define CAMSS_CSID_TG_VC_CFG_H_BLANKING 0x3ff +#define CAMSS_CSID_TG_VC_CFG_V_BLANKING 0x7f +#define CAMSS_CSID_TG_DT_n_CGG_0(n) (0x0ac + 0xc * (n)) +#define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b0 + 0xc * (n)) +#define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0b4 + 0xc * (n)) + +#define DATA_TYPE_EMBEDDED_DATA_8BIT 0x12 +#define DATA_TYPE_YUV422_8BIT 0x1e +#define DATA_TYPE_RAW_6BIT 0x28 +#define DATA_TYPE_RAW_8BIT 0x2a +#define DATA_TYPE_RAW_10BIT 0x2b +#define DATA_TYPE_RAW_12BIT 0x2c + +#define DECODE_FORMAT_UNCOMPRESSED_6_BIT 0x0 +#define DECODE_FORMAT_UNCOMPRESSED_8_BIT 0x1 +#define DECODE_FORMAT_UNCOMPRESSED_10_BIT 0x2 +#define DECODE_FORMAT_UNCOMPRESSED_12_BIT 0x3 + +#define CSID_RESET_TIMEOUT_MS 500 + +struct csid_fmts { + u32 code; + u8 data_type; + u8 decode_format; + u8 bpp; + u8 spp; /* bus samples per pixel */ +}; + +static const struct csid_fmts csid_input_fmts[] = { + { + MEDIA_BUS_FMT_UYVY8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_VYUY8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_YUYV8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_YVYU8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_SBGGR8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SBGGR10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SBGGR12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + } +}; + +static const struct csid_fmts *csid_get_fmt_entry(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(csid_input_fmts); i++) + if (code == csid_input_fmts[i].code) + return &csid_input_fmts[i]; + + WARN(1, "Unknown format\n"); + + return &csid_input_fmts[0]; +} + +/* + * csid_isr - CSID module interrupt handler + * @irq: Interrupt line + * @dev: CSID device + * + * Return IRQ_HANDLED on success + */ +static irqreturn_t csid_isr(int irq, void *dev) +{ + struct csid_device *csid = dev; + u32 value; + + value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS); + writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD); + + if ((value >> 11) & 0x1) + complete(&csid->reset_complete); + + return IRQ_HANDLED; +} + +/* + * csid_set_clock_rates - Calculate and set clock rates on CSID module + * @csiphy: CSID device + */ +static int csid_set_clock_rates(struct csid_device *csid) +{ + struct device *dev = to_device_index(csid, csid->id); + u32 pixel_clock; + int i, j; + int ret; + + ret = camss_get_pixel_clock(&csid->subdev.entity, &pixel_clock); + if (ret) + pixel_clock = 0; + + for (i = 0; i < csid->nclocks; i++) { + struct camss_clock *clock = &csid->clock[i]; + + if (!strcmp(clock->name, "csi0") || + !strcmp(clock->name, "csi1")) { + u8 bpp = csid_get_fmt_entry( + csid->fmt[MSM_CSIPHY_PAD_SINK].code)->bpp; + u8 num_lanes = csid->phy.lane_cnt; + u64 min_rate = pixel_clock * bpp / (2 * num_lanes * 4); + long rate; + + camss_add_clock_margin(&min_rate); + + for (j = 0; j < clock->nfreqs; j++) + if (min_rate < clock->freq[j]) + break; + + if (j == clock->nfreqs) { + dev_err(dev, + "Pixel clock is too high for CSID\n"); + return -EINVAL; + } + + /* if sensor pixel clock is not available */ + /* set highest possible CSID clock rate */ + if (min_rate == 0) + j = clock->nfreqs - 1; + + rate = clk_round_rate(clock->clk, clock->freq[j]); + if (rate < 0) { + dev_err(dev, "clk round rate failed: %ld\n", + rate); + return -EINVAL; + } + + ret = clk_set_rate(clock->clk, rate); + if (ret < 0) { + dev_err(dev, "clk set rate failed: %d\n", ret); + return ret; + } + } + } + + return 0; +} + +/* + * csid_reset - Trigger reset on CSID module and wait to complete + * @csid: CSID device + * + * Return 0 on success or a negative error code otherwise + */ +static int csid_reset(struct csid_device *csid) +{ + unsigned long time; + + reinit_completion(&csid->reset_complete); + + writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD); + + time = wait_for_completion_timeout(&csid->reset_complete, + msecs_to_jiffies(CSID_RESET_TIMEOUT_MS)); + if (!time) { + dev_err(to_device_index(csid, csid->id), + "CSID reset timeout\n"); + return -EIO; + } + + return 0; +} + +/* + * csid_set_power - Power on/off CSID module + * @sd: CSID V4L2 subdevice + * @on: Requested power state + * + * Return 0 on success or a negative error code otherwise + */ +static int csid_set_power(struct v4l2_subdev *sd, int on) +{ + struct csid_device *csid = v4l2_get_subdevdata(sd); + struct device *dev = to_device_index(csid, csid->id); + int ret; + + if (on) { + u32 hw_version; + + ret = regulator_enable(csid->vdda); + if (ret < 0) + return ret; + + ret = csid_set_clock_rates(csid); + if (ret < 0) { + regulator_disable(csid->vdda); + return ret; + } + + ret = camss_enable_clocks(csid->nclocks, csid->clock, dev); + if (ret < 0) { + regulator_disable(csid->vdda); + return ret; + } + + enable_irq(csid->irq); + + ret = csid_reset(csid); + if (ret < 0) { + disable_irq(csid->irq); + camss_disable_clocks(csid->nclocks, csid->clock); + regulator_disable(csid->vdda); + return ret; + } + + hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION); + dev_dbg(dev, "CSID HW Version = 0x%08x\n", hw_version); + } else { + disable_irq(csid->irq); + camss_disable_clocks(csid->nclocks, csid->clock); + ret = regulator_disable(csid->vdda); + } + + return ret; +} + +/* + * csid_set_stream - Enable/disable streaming on CSID module + * @sd: CSID V4L2 subdevice + * @enable: Requested streaming state + * + * Main configuration of CSID module is also done here. + * + * Return 0 on success or a negative error code otherwise + */ +static int csid_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct csid_device *csid = v4l2_get_subdevdata(sd); + struct csid_testgen_config *tg = &csid->testgen; + u32 val; + + if (enable) { + u8 vc = 0; /* Virtual Channel 0 */ + u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ + u8 dt, dt_shift, df; + int ret; + + ret = v4l2_ctrl_handler_setup(&csid->ctrls); + if (ret < 0) { + dev_err(to_device_index(csid, csid->id), + "could not sync v4l2 controls: %d\n", ret); + return ret; + } + + if (!tg->enabled && + !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK])) + return -ENOLINK; + + dt = csid_get_fmt_entry(csid->fmt[MSM_CSID_PAD_SRC].code)-> + data_type; + + if (tg->enabled) { + /* Config Test Generator */ + struct v4l2_mbus_framefmt *f = + &csid->fmt[MSM_CSID_PAD_SRC]; + u8 bpp = csid_get_fmt_entry(f->code)->bpp; + u8 spp = csid_get_fmt_entry(f->code)->spp; + u32 num_bytes_per_line = f->width * bpp * spp / 8; + u32 num_lines = f->height; + + /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */ + /* 1:0 VC */ + val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) | + ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13); + writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG); + + /* 28:16 bytes per lines, 12:0 num of lines */ + val = ((num_bytes_per_line & 0x1fff) << 16) | + (num_lines & 0x1fff); + writel_relaxed(val, csid->base + + CAMSS_CSID_TG_DT_n_CGG_0(0)); + + /* 5:0 data type */ + val = dt; + writel_relaxed(val, csid->base + + CAMSS_CSID_TG_DT_n_CGG_1(0)); + + /* 2:0 output test pattern */ + val = tg->payload_mode; + writel_relaxed(val, csid->base + + CAMSS_CSID_TG_DT_n_CGG_2(0)); + } else { + struct csid_phy_config *phy = &csid->phy; + + val = phy->lane_cnt - 1; + val |= phy->lane_assign << 4; + + writel_relaxed(val, + csid->base + CAMSS_CSID_CORE_CTRL_0); + + val = phy->csiphy_id << 17; + val |= 0x9; + + writel_relaxed(val, + csid->base + CAMSS_CSID_CORE_CTRL_1); + } + + /* Config LUT */ + + dt_shift = (cid % 4) * 8; + df = csid_get_fmt_entry(csid->fmt[MSM_CSID_PAD_SINK].code)-> + decode_format; + + val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc)); + val &= ~(0xff << dt_shift); + val |= dt << dt_shift; + writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc)); + + val = (df << 4) | 0x3; + writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid)); + + if (tg->enabled) { + val = CAMSS_CSID_TG_CTRL_ENABLE; + writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL); + } + } else { + if (tg->enabled) { + val = CAMSS_CSID_TG_CTRL_DISABLE; + writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL); + } + } + + return 0; +} + +/* + * __csid_get_format - Get pointer to format structure + * @csid: CSID device + * @cfg: V4L2 subdev pad configuration + * @pad: pad from which format is requested + * @which: TRY or ACTIVE format + * + * Return pointer to TRY or ACTIVE format structure + */ +static struct v4l2_mbus_framefmt * +__csid_get_format(struct csid_device *csid, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&csid->subdev, cfg, pad); + + return &csid->fmt[pad]; +} + +/* + * csid_try_format - Handle try format by pad subdev method + * @csid: CSID device + * @cfg: V4L2 subdev pad configuration + * @pad: pad on which format is requested + * @fmt: pointer to v4l2 format structure + * @which: wanted subdev format + */ +static void csid_try_format(struct csid_device *csid, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, + struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + unsigned int i; + + switch (pad) { + case MSM_CSID_PAD_SINK: + /* Set format on sink pad */ + + for (i = 0; i < ARRAY_SIZE(csid_input_fmts); i++) + if (fmt->code == csid_input_fmts[i].code) + break; + + /* If not found, use UYVY as default */ + if (i >= ARRAY_SIZE(csid_input_fmts)) + fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + + fmt->width = clamp_t(u32, fmt->width, 1, 8191); + fmt->height = clamp_t(u32, fmt->height, 1, 8191); + + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + + break; + + case MSM_CSID_PAD_SRC: + if (csid->testgen_mode->cur.val == 0) { + /* Test generator is disabled, keep pad formats */ + /* in sync - set and return a format same as sink pad */ + struct v4l2_mbus_framefmt format; + + format = *__csid_get_format(csid, cfg, + MSM_CSID_PAD_SINK, which); + *fmt = format; + } else { + /* Test generator is enabled, set format on source*/ + /* pad to allow test generator usage */ + + for (i = 0; i < ARRAY_SIZE(csid_input_fmts); i++) + if (csid_input_fmts[i].code == fmt->code) + break; + + /* If not found, use UYVY as default */ + if (i >= ARRAY_SIZE(csid_input_fmts)) + fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + + fmt->width = clamp_t(u32, fmt->width, 1, 8191); + fmt->height = clamp_t(u32, fmt->height, 1, 8191); + + fmt->field = V4L2_FIELD_NONE; + } + break; + } + + fmt->colorspace = V4L2_COLORSPACE_SRGB; +} + +/* + * csid_enum_mbus_code - Handle pixel format enumeration + * @sd: CSID V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @code: pointer to v4l2_subdev_mbus_code_enum structure + * return -EINVAL or zero on success + */ +static int csid_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct csid_device *csid = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + if (code->pad == MSM_CSID_PAD_SINK) { + if (code->index >= ARRAY_SIZE(csid_input_fmts)) + return -EINVAL; + + code->code = csid_input_fmts[code->index].code; + } else { + if (csid->testgen_mode->cur.val == 0) { + if (code->index > 0) + return -EINVAL; + + format = __csid_get_format(csid, cfg, MSM_CSID_PAD_SINK, + code->which); + + code->code = format->code; + } else { + if (code->index >= ARRAY_SIZE(csid_input_fmts)) + return -EINVAL; + + code->code = csid_input_fmts[code->index].code; + } + } + + return 0; +} + +/* + * csid_enum_frame_size - Handle frame size enumeration + * @sd: CSID V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fse: pointer to v4l2_subdev_frame_size_enum structure + * return -EINVAL or zero on success + */ +static int csid_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct csid_device *csid = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt format; + + if (fse->index != 0) + return -EINVAL; + + format.code = fse->code; + format.width = 1; + format.height = 1; + csid_try_format(csid, cfg, fse->pad, &format, fse->which); + fse->min_width = format.width; + fse->min_height = format.height; + + if (format.code != fse->code) + return -EINVAL; + + format.code = fse->code; + format.width = -1; + format.height = -1; + csid_try_format(csid, cfg, fse->pad, &format, fse->which); + fse->max_width = format.width; + fse->max_height = format.height; + + return 0; +} + +/* + * csid_get_format - Handle get format by pads subdev method + * @sd: CSID V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fmt: pointer to v4l2 subdev format structure + * + * Return -EINVAL or zero on success + */ +static int csid_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct csid_device *csid = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __csid_get_format(csid, cfg, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + fmt->format = *format; + + return 0; +} + +/* + * csid_set_format - Handle set format by pads subdev method + * @sd: CSID V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fmt: pointer to v4l2 subdev format structure + * + * Return -EINVAL or zero on success + */ +static int csid_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct csid_device *csid = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __csid_get_format(csid, cfg, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + csid_try_format(csid, cfg, fmt->pad, &fmt->format, fmt->which); + *format = fmt->format; + + /* Propagate the format from sink to source */ + if (fmt->pad == MSM_CSID_PAD_SINK) { + format = __csid_get_format(csid, cfg, MSM_CSID_PAD_SRC, + fmt->which); + + *format = fmt->format; + csid_try_format(csid, cfg, MSM_CSID_PAD_SRC, format, + fmt->which); + } + + return 0; +} + +/* + * csid_init_formats - Initialize formats on all pads + * @sd: CSID V4L2 subdevice + * @fh: V4L2 subdev file handle + * + * Initialize all pad formats with default values. + * + * Return 0 on success or a negative error code otherwise + */ +static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_subdev_format format = { + .pad = MSM_CSID_PAD_SINK, + .which = fh ? V4L2_SUBDEV_FORMAT_TRY : + V4L2_SUBDEV_FORMAT_ACTIVE, + .format = { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 1920, + .height = 1080 + } + }; + + return csid_set_format(sd, fh ? fh->pad : NULL, &format); +} + +static const char * const csid_test_pattern_menu[] = { + "Disabled", + "Incrementing", + "Alternating 0x55/0xAA", + "All Zeros 0x00", + "All Ones 0xFF", + "Pseudo-random Data", +}; + +/* + * csid_set_test_pattern - Set test generator's pattern mode + * @csid: CSID device + * @value: desired test pattern mode + * + * Return 0 on success or a negative error code otherwise + */ +static int csid_set_test_pattern(struct csid_device *csid, s32 value) +{ + struct csid_testgen_config *tg = &csid->testgen; + + /* If CSID is linked to CSIPHY, do not allow to enable test generator */ + if (value && media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK])) + return -EBUSY; + + tg->enabled = !!value; + + switch (value) { + case 1: + tg->payload_mode = CSID_PAYLOAD_MODE_INCREMENTING; + break; + case 2: + tg->payload_mode = CSID_PAYLOAD_MODE_ALTERNATING_55_AA; + break; + case 3: + tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ZEROES; + break; + case 4: + tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ONES; + break; + case 5: + tg->payload_mode = CSID_PAYLOAD_MODE_RANDOM; + break; + } + + return 0; +} + +/* + * csid_s_ctrl - Handle set control subdev method + * @ctrl: pointer to v4l2 control structure + * + * Return 0 on success or a negative error code otherwise + */ +static int csid_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct csid_device *csid = container_of(ctrl->handler, + struct csid_device, ctrls); + int ret = -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_TEST_PATTERN: + ret = csid_set_test_pattern(csid, ctrl->val); + break; + } + + return ret; +} + +static const struct v4l2_ctrl_ops csid_ctrl_ops = { + .s_ctrl = csid_s_ctrl, +}; + +/* + * msm_csid_subdev_init - Initialize CSID device structure and resources + * @csid: CSID device + * @res: CSID module resources table + * @id: CSID module id + * + * Return 0 on success or a negative error code otherwise + */ +int msm_csid_subdev_init(struct csid_device *csid, + const struct resources *res, u8 id) +{ + struct device *dev = to_device_index(csid, id); + struct platform_device *pdev = to_platform_device(dev); + struct resource *r; + int i, j; + int ret; + + csid->id = id; + + /* Memory */ + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]); + csid->base = devm_ioremap_resource(dev, r); + if (IS_ERR(csid->base)) { + dev_err(dev, "could not map memory\n"); + return PTR_ERR(csid->base); + } + + /* Interrupt */ + + r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, + res->interrupt[0]); + if (!r) { + dev_err(dev, "missing IRQ\n"); + return -EINVAL; + } + + csid->irq = r->start; + snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d", + dev_name(dev), MSM_CSID_NAME, csid->id); + ret = devm_request_irq(dev, csid->irq, csid_isr, + IRQF_TRIGGER_RISING, csid->irq_name, csid); + if (ret < 0) { + dev_err(dev, "request_irq failed: %d\n", ret); + return ret; + } + + disable_irq(csid->irq); + + /* Clocks */ + + csid->nclocks = 0; + while (res->clock[csid->nclocks]) + csid->nclocks++; + + csid->clock = devm_kzalloc(dev, csid->nclocks * sizeof(*csid->clock), + GFP_KERNEL); + if (!csid->clock) + return -ENOMEM; + + for (i = 0; i < csid->nclocks; i++) { + struct camss_clock *clock = &csid->clock[i]; + + clock->clk = devm_clk_get(dev, res->clock[i]); + if (IS_ERR(clock->clk)) + return PTR_ERR(clock->clk); + + clock->name = res->clock[i]; + + clock->nfreqs = 0; + while (res->clock_rate[i][clock->nfreqs]) + clock->nfreqs++; + + if (!clock->nfreqs) { + clock->freq = NULL; + continue; + } + + clock->freq = devm_kzalloc(dev, clock->nfreqs * + sizeof(*clock->freq), GFP_KERNEL); + if (!clock->freq) + return -ENOMEM; + + for (j = 0; j < clock->nfreqs; j++) + clock->freq[j] = res->clock_rate[i][j]; + } + + /* Regulator */ + + csid->vdda = devm_regulator_get(dev, res->regulator[0]); + if (IS_ERR(csid->vdda)) { + dev_err(dev, "could not get regulator\n"); + return PTR_ERR(csid->vdda); + } + + init_completion(&csid->reset_complete); + + return 0; +} + +/* + * msm_csid_get_csid_id - Get CSID HW module id + * @entity: Pointer to CSID media entity structure + * @id: Return CSID HW module id here + */ +void msm_csid_get_csid_id(struct media_entity *entity, u8 *id) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct csid_device *csid = v4l2_get_subdevdata(sd); + + *id = csid->id; +} + +/* + * csid_get_lane_assign - Calculate CSI2 lane assign configuration parameter + * @lane_cfg - CSI2 lane configuration + * + * Return lane assign + */ +static u32 csid_get_lane_assign(struct csiphy_lanes_cfg *lane_cfg) +{ + u32 lane_assign = 0; + int i; + + for (i = 0; i < lane_cfg->num_data; i++) + lane_assign |= lane_cfg->data[i].pos << (i * 4); + + return lane_assign; +} + +/* + * csid_link_setup - Setup CSID connections + * @entity: Pointer to media entity structure + * @local: Pointer to local pad + * @remote: Pointer to remote pad + * @flags: Link flags + * + * Return 0 on success + */ +static int csid_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + if (flags & MEDIA_LNK_FL_ENABLED) + if (media_entity_remote_pad(local)) + return -EBUSY; + + if ((local->flags & MEDIA_PAD_FL_SINK) && + (flags & MEDIA_LNK_FL_ENABLED)) { + struct v4l2_subdev *sd; + struct csid_device *csid; + struct csiphy_device *csiphy; + struct csiphy_lanes_cfg *lane_cfg; + struct v4l2_subdev_format format = { 0 }; + + sd = media_entity_to_v4l2_subdev(entity); + csid = v4l2_get_subdevdata(sd); + + /* If test generator is enabled */ + /* do not allow a link from CSIPHY to CSID */ + if (csid->testgen_mode->cur.val != 0) + return -EBUSY; + + sd = media_entity_to_v4l2_subdev(remote->entity); + csiphy = v4l2_get_subdevdata(sd); + + /* If a sensor is not linked to CSIPHY */ + /* do no allow a link from CSIPHY to CSID */ + if (!csiphy->cfg.csi2) + return -EPERM; + + csid->phy.csiphy_id = csiphy->id; + + lane_cfg = &csiphy->cfg.csi2->lane_cfg; + csid->phy.lane_cnt = lane_cfg->num_data; + csid->phy.lane_assign = csid_get_lane_assign(lane_cfg); + + /* Reset format on source pad to sink pad format */ + format.pad = MSM_CSID_PAD_SRC; + format.which = V4L2_SUBDEV_FORMAT_ACTIVE; + csid_set_format(&csid->subdev, NULL, &format); + } + + return 0; +} + +static const struct v4l2_subdev_core_ops csid_core_ops = { + .s_power = csid_set_power, +}; + +static const struct v4l2_subdev_video_ops csid_video_ops = { + .s_stream = csid_set_stream, +}; + +static const struct v4l2_subdev_pad_ops csid_pad_ops = { + .enum_mbus_code = csid_enum_mbus_code, + .enum_frame_size = csid_enum_frame_size, + .get_fmt = csid_get_format, + .set_fmt = csid_set_format, +}; + +static const struct v4l2_subdev_ops csid_v4l2_ops = { + .core = &csid_core_ops, + .video = &csid_video_ops, + .pad = &csid_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops csid_v4l2_internal_ops = { + .open = csid_init_formats, +}; + +static const struct media_entity_operations csid_media_ops = { + .link_setup = csid_link_setup, + .link_validate = v4l2_subdev_link_validate, +}; + +/* + * msm_csid_register_entity - Register subdev node for CSID module + * @csid: CSID device + * @v4l2_dev: V4L2 device + * + * Return 0 on success or a negative error code otherwise + */ +int msm_csid_register_entity(struct csid_device *csid, + struct v4l2_device *v4l2_dev) +{ + struct v4l2_subdev *sd = &csid->subdev; + struct media_pad *pads = csid->pads; + struct device *dev = to_device_index(csid, csid->id); + int ret; + + v4l2_subdev_init(sd, &csid_v4l2_ops); + sd->internal_ops = &csid_v4l2_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d", + MSM_CSID_NAME, csid->id); + v4l2_set_subdevdata(sd, csid); + + ret = v4l2_ctrl_handler_init(&csid->ctrls, 1); + if (ret < 0) { + dev_err(dev, "Failed to init ctrl handler: %d\n", ret); + return ret; + } + + csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls, + &csid_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(csid_test_pattern_menu) - 1, 0, 0, + csid_test_pattern_menu); + + if (csid->ctrls.error) { + dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error); + ret = csid->ctrls.error; + goto free_ctrl; + } + + csid->subdev.ctrl_handler = &csid->ctrls; + + ret = csid_init_formats(sd, NULL); + if (ret < 0) { + dev_err(dev, "Failed to init format: %d\n", ret); + goto free_ctrl; + } + + pads[MSM_CSID_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[MSM_CSID_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; + + sd->entity.function = MEDIA_ENT_F_IO_V4L; + sd->entity.ops = &csid_media_ops; + ret = media_entity_pads_init(&sd->entity, MSM_CSID_PADS_NUM, pads); + if (ret < 0) { + dev_err(dev, "Failed to init media entity: %d\n", ret); + goto free_ctrl; + } + + ret = v4l2_device_register_subdev(v4l2_dev, sd); + if (ret < 0) { + dev_err(dev, "Failed to register subdev: %d\n", ret); + goto media_cleanup; + } + + return 0; + +media_cleanup: + media_entity_cleanup(&sd->entity); +free_ctrl: + v4l2_ctrl_handler_free(&csid->ctrls); + + return ret; +} + +/* + * msm_csid_unregister_entity - Unregister CSID module subdev node + * @csid: CSID device + */ +void msm_csid_unregister_entity(struct csid_device *csid) +{ + v4l2_device_unregister_subdev(&csid->subdev); + media_entity_cleanup(&csid->subdev.entity); + v4l2_ctrl_handler_free(&csid->ctrls); +} diff --git a/drivers/media/platform/qcom/camss-8x16/camss-csid.h b/drivers/media/platform/qcom/camss-8x16/camss-csid.h new file mode 100644 index 000000000000..8682d3081bc3 --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/camss-csid.h @@ -0,0 +1,82 @@ +/* + * camss-csid.h + * + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module + * + * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef QC_MSM_CAMSS_CSID_H +#define QC_MSM_CAMSS_CSID_H + +#include <linux/clk.h> +#include <media/media-entity.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-mediabus.h> +#include <media/v4l2-subdev.h> + +#define MSM_CSID_PAD_SINK 0 +#define MSM_CSID_PAD_SRC 1 +#define MSM_CSID_PADS_NUM 2 + +enum csid_payload_mode { + CSID_PAYLOAD_MODE_INCREMENTING = 0, + CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 1, + CSID_PAYLOAD_MODE_ALL_ZEROES = 2, + CSID_PAYLOAD_MODE_ALL_ONES = 3, + CSID_PAYLOAD_MODE_RANDOM = 4, + CSID_PAYLOAD_MODE_USER_SPECIFIED = 5, +}; + +struct csid_testgen_config { + u8 enabled; + enum csid_payload_mode payload_mode; +}; + +struct csid_phy_config { + u8 csiphy_id; + u8 lane_cnt; + u32 lane_assign; +}; + +struct csid_device { + u8 id; + struct v4l2_subdev subdev; + struct media_pad pads[MSM_CSID_PADS_NUM]; + void __iomem *base; + u32 irq; + char irq_name[30]; + struct camss_clock *clock; + int nclocks; + struct regulator *vdda; + struct completion reset_complete; + struct csid_testgen_config testgen; + struct csid_phy_config phy; + struct v4l2_mbus_framefmt fmt[MSM_CSID_PADS_NUM]; + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *testgen_mode; +}; + +struct resources; + +int msm_csid_subdev_init(struct csid_device *csid, + const struct resources *res, u8 id); + +int msm_csid_register_entity(struct csid_device *csid, + struct v4l2_device *v4l2_dev); + +void msm_csid_unregister_entity(struct csid_device *csid); + +void msm_csid_get_csid_id(struct media_entity *entity, u8 *id); + +#endif /* QC_MSM_CAMSS_CSID_H */ diff --git a/drivers/media/platform/qcom/camss-8x16/camss-csiphy.c b/drivers/media/platform/qcom/camss-8x16/camss-csiphy.c new file mode 100644 index 000000000000..072c6cf053f6 --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/camss-csiphy.c @@ -0,0 +1,890 @@ +/* + * camss-csiphy.c + * + * Qualcomm MSM Camera Subsystem - CSIPHY Module + * + * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2016-2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <media/media-entity.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> + +#include "camss-csiphy.h" +#include "camss.h" + +#define MSM_CSIPHY_NAME "msm_csiphy" + +#define CAMSS_CSI_PHY_LNn_CFG2(n) (0x004 + 0x40 * (n)) +#define CAMSS_CSI_PHY_LNn_CFG3(n) (0x008 + 0x40 * (n)) +#define CAMSS_CSI_PHY_GLBL_RESET 0x140 +#define CAMSS_CSI_PHY_GLBL_PWR_CFG 0x144 +#define CAMSS_CSI_PHY_GLBL_IRQ_CMD 0x164 +#define CAMSS_CSI_PHY_HW_VERSION 0x188 +#define CAMSS_CSI_PHY_INTERRUPT_STATUSn(n) (0x18c + 0x4 * (n)) +#define CAMSS_CSI_PHY_INTERRUPT_MASKn(n) (0x1ac + 0x4 * (n)) +#define CAMSS_CSI_PHY_INTERRUPT_CLEARn(n) (0x1cc + 0x4 * (n)) +#define CAMSS_CSI_PHY_GLBL_T_INIT_CFG0 0x1ec +#define CAMSS_CSI_PHY_T_WAKEUP_CFG0 0x1f4 + +static const struct { + u32 code; + u8 bpp; +} csiphy_formats[] = { + { + 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_SBGGR8_1X8, + 8, + }, + { + MEDIA_BUS_FMT_SGBRG8_1X8, + 8, + }, + { + MEDIA_BUS_FMT_SGRBG8_1X8, + 8, + }, + { + MEDIA_BUS_FMT_SRGGB8_1X8, + 8, + }, + { + MEDIA_BUS_FMT_SBGGR10_1X10, + 10, + }, + { + MEDIA_BUS_FMT_SGBRG10_1X10, + 10, + }, + { + MEDIA_BUS_FMT_SGRBG10_1X10, + 10, + }, + { + MEDIA_BUS_FMT_SRGGB10_1X10, + 10, + }, + { + MEDIA_BUS_FMT_SBGGR12_1X12, + 12, + }, + { + MEDIA_BUS_FMT_SGBRG12_1X12, + 12, + }, + { + MEDIA_BUS_FMT_SGRBG12_1X12, + 12, + }, + { + MEDIA_BUS_FMT_SRGGB12_1X12, + 12, + } +}; + +/* + * csiphy_get_bpp - map media bus format to bits per pixel + * @code: media bus format code + * + * Return number of bits per pixel + */ +static u8 csiphy_get_bpp(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(csiphy_formats); i++) + if (code == csiphy_formats[i].code) + return csiphy_formats[i].bpp; + + WARN(1, "Unknown format\n"); + + return csiphy_formats[0].bpp; +} + +/* + * csiphy_isr - CSIPHY module interrupt handler + * @irq: Interrupt line + * @dev: CSIPHY device + * + * Return IRQ_HANDLED on success + */ +static irqreturn_t csiphy_isr(int irq, void *dev) +{ + struct csiphy_device *csiphy = dev; + u8 i; + + for (i = 0; i < 8; i++) { + u8 val = readl_relaxed(csiphy->base + + CAMSS_CSI_PHY_INTERRUPT_STATUSn(i)); + writel_relaxed(val, csiphy->base + + CAMSS_CSI_PHY_INTERRUPT_CLEARn(i)); + writel_relaxed(0x1, csiphy->base + CAMSS_CSI_PHY_GLBL_IRQ_CMD); + writel_relaxed(0x0, csiphy->base + CAMSS_CSI_PHY_GLBL_IRQ_CMD); + writel_relaxed(0x0, csiphy->base + + CAMSS_CSI_PHY_INTERRUPT_CLEARn(i)); + } + + return IRQ_HANDLED; +} + +/* + * csiphy_set_clock_rates - Calculate and set clock rates on CSIPHY module + * @csiphy: CSIPHY device + */ +static int csiphy_set_clock_rates(struct csiphy_device *csiphy) +{ + struct device *dev = to_device_index(csiphy, csiphy->id); + u32 pixel_clock; + int i, j; + int ret; + + ret = camss_get_pixel_clock(&csiphy->subdev.entity, &pixel_clock); + if (ret) + pixel_clock = 0; + + for (i = 0; i < csiphy->nclocks; i++) { + struct camss_clock *clock = &csiphy->clock[i]; + + if (!strcmp(clock->name, "csiphy0_timer") || + !strcmp(clock->name, "csiphy1_timer")) { + u8 bpp = csiphy_get_bpp( + csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); + u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; + u64 min_rate = pixel_clock * bpp / (2 * num_lanes * 4); + long round_rate; + + camss_add_clock_margin(&min_rate); + + for (j = 0; j < clock->nfreqs; j++) + if (min_rate < clock->freq[j]) + break; + + if (j == clock->nfreqs) { + dev_err(dev, + "Pixel clock is too high for CSIPHY\n"); + return -EINVAL; + } + + /* if sensor pixel clock is not available */ + /* set highest possible CSIPHY clock rate */ + if (min_rate == 0) + j = clock->nfreqs - 1; + + round_rate = clk_round_rate(clock->clk, clock->freq[j]); + if (round_rate < 0) { + dev_err(dev, "clk round rate failed: %ld\n", + round_rate); + return -EINVAL; + } + + csiphy->timer_clk_rate = round_rate; + + ret = clk_set_rate(clock->clk, csiphy->timer_clk_rate); + if (ret < 0) { + dev_err(dev, "clk set rate failed: %d\n", ret); + return ret; + } + } + } + + return 0; +} + +/* + * csiphy_reset - Perform software reset on CSIPHY module + * @csiphy: CSIPHY device + */ +static void csiphy_reset(struct csiphy_device *csiphy) +{ + writel_relaxed(0x1, csiphy->base + CAMSS_CSI_PHY_GLBL_RESET); + usleep_range(5000, 8000); + writel_relaxed(0x0, csiphy->base + CAMSS_CSI_PHY_GLBL_RESET); +} + +/* + * csiphy_set_power - Power on/off CSIPHY module + * @sd: CSIPHY V4L2 subdevice + * @on: Requested power state + * + * Return 0 on success or a negative error code otherwise + */ +static int csiphy_set_power(struct v4l2_subdev *sd, int on) +{ + struct csiphy_device *csiphy = v4l2_get_subdevdata(sd); + struct device *dev = to_device_index(csiphy, csiphy->id); + + if (on) { + u8 hw_version; + int ret; + + ret = csiphy_set_clock_rates(csiphy); + if (ret < 0) + return ret; + + ret = camss_enable_clocks(csiphy->nclocks, csiphy->clock, dev); + if (ret < 0) + return ret; + + enable_irq(csiphy->irq); + + csiphy_reset(csiphy); + + hw_version = readl_relaxed(csiphy->base + + CAMSS_CSI_PHY_HW_VERSION); + dev_dbg(dev, "CSIPHY HW Version = 0x%02x\n", hw_version); + } else { + disable_irq(csiphy->irq); + + camss_disable_clocks(csiphy->nclocks, csiphy->clock); + } + + return 0; +} + +/* + * csiphy_get_lane_mask - Calculate CSI2 lane mask configuration parameter + * @lane_cfg - CSI2 lane configuration + * + * Return lane mask + */ +static u8 csiphy_get_lane_mask(struct csiphy_lanes_cfg *lane_cfg) +{ + u8 lane_mask; + int i; + + lane_mask = 1 << lane_cfg->clk.pos; + + for (i = 0; i < lane_cfg->num_data; i++) + lane_mask |= 1 << lane_cfg->data[i].pos; + + return lane_mask; +} + +/* + * csiphy_settle_cnt_calc - Calculate settle count value + * @csiphy: CSIPHY device + * + * Helper function to calculate settle count value. This is + * based on the CSI2 T_hs_settle parameter which in turn + * is calculated based on the CSI2 transmitter pixel clock + * frequency. + * + * Return settle count value or 0 if the CSI2 pixel clock + * frequency is not available + */ +static u8 csiphy_settle_cnt_calc(struct csiphy_device *csiphy) +{ + u8 bpp = csiphy_get_bpp( + csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); + u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; + u32 pixel_clock; /* Hz */ + u32 mipi_clock; /* Hz */ + u32 ui; /* ps */ + u32 timer_period; /* ps */ + u32 t_hs_prepare_max; /* ps */ + u32 t_hs_prepare_zero_min; /* ps */ + u32 t_hs_settle; /* ps */ + u8 settle_cnt; + int ret; + + ret = camss_get_pixel_clock(&csiphy->subdev.entity, &pixel_clock); + if (ret) { + dev_err(to_device_index(csiphy, csiphy->id), + "Cannot get CSI2 transmitter's pixel clock\n"); + return 0; + } + if (!pixel_clock) { + dev_err(to_device_index(csiphy, csiphy->id), + "Got pixel clock == 0, cannot continue\n"); + return 0; + } + + mipi_clock = pixel_clock * bpp / (2 * num_lanes); + ui = div_u64(1000000000000LL, mipi_clock); + ui /= 2; + t_hs_prepare_max = 85000 + 6 * ui; + t_hs_prepare_zero_min = 145000 + 10 * ui; + t_hs_settle = (t_hs_prepare_max + t_hs_prepare_zero_min) / 2; + + timer_period = div_u64(1000000000000LL, csiphy->timer_clk_rate); + settle_cnt = t_hs_settle / timer_period; + + return settle_cnt; +} + +/* + * csiphy_stream_on - Enable streaming on CSIPHY module + * @csiphy: CSIPHY device + * + * Helper function to enable streaming on CSIPHY module. + * Main configuration of CSIPHY module is also done here. + * + * Return 0 on success or a negative error code otherwise + */ +static int csiphy_stream_on(struct csiphy_device *csiphy) +{ + struct csiphy_config *cfg = &csiphy->cfg; + u8 lane_mask = csiphy_get_lane_mask(&cfg->csi2->lane_cfg); + u8 settle_cnt; + u8 val; + int i = 0; + + settle_cnt = csiphy_settle_cnt_calc(csiphy); + if (!settle_cnt) + return -EINVAL; + + val = readl_relaxed(csiphy->base_clk_mux); + if (cfg->combo_mode && (lane_mask & 0x18) == 0x18) { + val &= ~0xf0; + val |= cfg->csid_id << 4; + } else { + val &= ~0xf; + val |= cfg->csid_id; + } + writel_relaxed(val, csiphy->base_clk_mux); + + writel_relaxed(0x1, csiphy->base + + CAMSS_CSI_PHY_GLBL_T_INIT_CFG0); + writel_relaxed(0x1, csiphy->base + + CAMSS_CSI_PHY_T_WAKEUP_CFG0); + + val = 0x1; + val |= lane_mask << 1; + writel_relaxed(val, csiphy->base + CAMSS_CSI_PHY_GLBL_PWR_CFG); + + val = cfg->combo_mode << 4; + writel_relaxed(val, csiphy->base + CAMSS_CSI_PHY_GLBL_RESET); + + while (lane_mask) { + if (lane_mask & 0x1) { + writel_relaxed(0x10, csiphy->base + + CAMSS_CSI_PHY_LNn_CFG2(i)); + writel_relaxed(settle_cnt, csiphy->base + + CAMSS_CSI_PHY_LNn_CFG3(i)); + writel_relaxed(0x3f, csiphy->base + + CAMSS_CSI_PHY_INTERRUPT_MASKn(i)); + writel_relaxed(0x3f, csiphy->base + + CAMSS_CSI_PHY_INTERRUPT_CLEARn(i)); + } + + lane_mask >>= 1; + i++; + } + + return 0; +} + +/* + * csiphy_stream_off - Disable streaming on CSIPHY module + * @csiphy: CSIPHY device + * + * Helper function to disable streaming on CSIPHY module + */ +static void csiphy_stream_off(struct csiphy_device *csiphy) +{ + u8 lane_mask = csiphy_get_lane_mask(&csiphy->cfg.csi2->lane_cfg); + int i = 0; + + while (lane_mask) { + if (lane_mask & 0x1) + writel_relaxed(0x0, csiphy->base + + CAMSS_CSI_PHY_LNn_CFG2(i)); + + lane_mask >>= 1; + i++; + } + + writel_relaxed(0x0, csiphy->base + CAMSS_CSI_PHY_GLBL_PWR_CFG); +} + + +/* + * csiphy_set_stream - Enable/disable streaming on CSIPHY module + * @sd: CSIPHY V4L2 subdevice + * @enable: Requested streaming state + * + * Return 0 on success or a negative error code otherwise + */ +static int csiphy_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct csiphy_device *csiphy = v4l2_get_subdevdata(sd); + int ret = 0; + + if (enable) + ret = csiphy_stream_on(csiphy); + else + csiphy_stream_off(csiphy); + + return ret; +} + +/* + * __csiphy_get_format - Get pointer to format structure + * @csiphy: CSIPHY device + * @cfg: V4L2 subdev pad configuration + * @pad: pad from which format is requested + * @which: TRY or ACTIVE format + * + * Return pointer to TRY or ACTIVE format structure + */ +static struct v4l2_mbus_framefmt * +__csiphy_get_format(struct csiphy_device *csiphy, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&csiphy->subdev, cfg, pad); + + return &csiphy->fmt[pad]; +} + +/* + * csiphy_try_format - Handle try format by pad subdev method + * @csiphy: CSIPHY device + * @cfg: V4L2 subdev pad configuration + * @pad: pad on which format is requested + * @fmt: pointer to v4l2 format structure + * @which: wanted subdev format + */ +static void csiphy_try_format(struct csiphy_device *csiphy, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, + struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + unsigned int i; + + switch (pad) { + case MSM_CSIPHY_PAD_SINK: + /* Set format on sink pad */ + + for (i = 0; i < ARRAY_SIZE(csiphy_formats); i++) + if (fmt->code == csiphy_formats[i].code) + break; + + /* If not found, use UYVY as default */ + if (i >= ARRAY_SIZE(csiphy_formats)) + fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + + fmt->width = clamp_t(u32, fmt->width, 1, 8191); + fmt->height = clamp_t(u32, fmt->height, 1, 8191); + + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + + break; + + case MSM_CSIPHY_PAD_SRC: + /* Set and return a format same as sink pad */ + + *fmt = *__csiphy_get_format(csiphy, cfg, MSM_CSID_PAD_SINK, + which); + + break; + } +} + +/* + * csiphy_enum_mbus_code - Handle pixel format enumeration + * @sd: CSIPHY V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @code: pointer to v4l2_subdev_mbus_code_enum structure + * return -EINVAL or zero on success + */ +static int csiphy_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct csiphy_device *csiphy = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + if (code->pad == MSM_CSIPHY_PAD_SINK) { + if (code->index >= ARRAY_SIZE(csiphy_formats)) + return -EINVAL; + + code->code = csiphy_formats[code->index].code; + } else { + if (code->index > 0) + return -EINVAL; + + format = __csiphy_get_format(csiphy, cfg, MSM_CSIPHY_PAD_SINK, + code->which); + + code->code = format->code; + } + + return 0; +} + +/* + * csiphy_enum_frame_size - Handle frame size enumeration + * @sd: CSIPHY V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fse: pointer to v4l2_subdev_frame_size_enum structure + * return -EINVAL or zero on success + */ +static int csiphy_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct csiphy_device *csiphy = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt format; + + if (fse->index != 0) + return -EINVAL; + + format.code = fse->code; + format.width = 1; + format.height = 1; + csiphy_try_format(csiphy, cfg, fse->pad, &format, fse->which); + fse->min_width = format.width; + fse->min_height = format.height; + + if (format.code != fse->code) + return -EINVAL; + + format.code = fse->code; + format.width = -1; + format.height = -1; + csiphy_try_format(csiphy, cfg, fse->pad, &format, fse->which); + fse->max_width = format.width; + fse->max_height = format.height; + + return 0; +} + +/* + * csiphy_get_format - Handle get format by pads subdev method + * @sd: CSIPHY V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fmt: pointer to v4l2 subdev format structure + * + * Return -EINVAL or zero on success + */ +static int csiphy_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct csiphy_device *csiphy = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __csiphy_get_format(csiphy, cfg, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + fmt->format = *format; + + return 0; +} + +/* + * csiphy_set_format - Handle set format by pads subdev method + * @sd: CSIPHY V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fmt: pointer to v4l2 subdev format structure + * + * Return -EINVAL or zero on success + */ +static int csiphy_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct csiphy_device *csiphy = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __csiphy_get_format(csiphy, cfg, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + csiphy_try_format(csiphy, cfg, fmt->pad, &fmt->format, fmt->which); + *format = fmt->format; + + /* Propagate the format from sink to source */ + if (fmt->pad == MSM_CSIPHY_PAD_SINK) { + format = __csiphy_get_format(csiphy, cfg, MSM_CSIPHY_PAD_SRC, + fmt->which); + + *format = fmt->format; + csiphy_try_format(csiphy, cfg, MSM_CSIPHY_PAD_SRC, format, + fmt->which); + } + + return 0; +} + +/* + * csiphy_init_formats - Initialize formats on all pads + * @sd: CSIPHY V4L2 subdevice + * @fh: V4L2 subdev file handle + * + * Initialize all pad formats with default values. + * + * Return 0 on success or a negative error code otherwise + */ +static int csiphy_init_formats(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct v4l2_subdev_format format = { + .pad = MSM_CSIPHY_PAD_SINK, + .which = fh ? V4L2_SUBDEV_FORMAT_TRY : + V4L2_SUBDEV_FORMAT_ACTIVE, + .format = { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 1920, + .height = 1080 + } + }; + + return csiphy_set_format(sd, fh ? fh->pad : NULL, &format); +} + +/* + * msm_csiphy_subdev_init - Initialize CSIPHY device structure and resources + * @csiphy: CSIPHY device + * @res: CSIPHY module resources table + * @id: CSIPHY module id + * + * Return 0 on success or a negative error code otherwise + */ +int msm_csiphy_subdev_init(struct csiphy_device *csiphy, + const struct resources *res, u8 id) +{ + struct device *dev = to_device_index(csiphy, id); + struct platform_device *pdev = to_platform_device(dev); + struct resource *r; + int i, j; + int ret; + + csiphy->id = id; + csiphy->cfg.combo_mode = 0; + + /* Memory */ + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]); + csiphy->base = devm_ioremap_resource(dev, r); + if (IS_ERR(csiphy->base)) { + dev_err(dev, "could not map memory\n"); + return PTR_ERR(csiphy->base); + } + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]); + csiphy->base_clk_mux = devm_ioremap_resource(dev, r); + if (IS_ERR(csiphy->base_clk_mux)) { + dev_err(dev, "could not map memory\n"); + return PTR_ERR(csiphy->base_clk_mux); + } + + /* Interrupt */ + + r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, + res->interrupt[0]); + if (!r) { + dev_err(dev, "missing IRQ\n"); + return -EINVAL; + } + + csiphy->irq = r->start; + snprintf(csiphy->irq_name, sizeof(csiphy->irq_name), "%s_%s%d", + dev_name(dev), MSM_CSIPHY_NAME, csiphy->id); + ret = devm_request_irq(dev, csiphy->irq, csiphy_isr, + IRQF_TRIGGER_RISING, csiphy->irq_name, csiphy); + if (ret < 0) { + dev_err(dev, "request_irq failed: %d\n", ret); + return ret; + } + + disable_irq(csiphy->irq); + + /* Clocks */ + + csiphy->nclocks = 0; + while (res->clock[csiphy->nclocks]) + csiphy->nclocks++; + + csiphy->clock = devm_kzalloc(dev, csiphy->nclocks * + sizeof(*csiphy->clock), GFP_KERNEL); + if (!csiphy->clock) + return -ENOMEM; + + for (i = 0; i < csiphy->nclocks; i++) { + struct camss_clock *clock = &csiphy->clock[i]; + + clock->clk = devm_clk_get(dev, res->clock[i]); + if (IS_ERR(clock->clk)) + return PTR_ERR(clock->clk); + + clock->name = res->clock[i]; + + clock->nfreqs = 0; + while (res->clock_rate[i][clock->nfreqs]) + clock->nfreqs++; + + if (!clock->nfreqs) { + clock->freq = NULL; + continue; + } + + clock->freq = devm_kzalloc(dev, clock->nfreqs * + sizeof(*clock->freq), GFP_KERNEL); + if (!clock->freq) + return -ENOMEM; + + for (j = 0; j < clock->nfreqs; j++) + clock->freq[j] = res->clock_rate[i][j]; + } + + return 0; +} + +/* + * csiphy_link_setup - Setup CSIPHY connections + * @entity: Pointer to media entity structure + * @local: Pointer to local pad + * @remote: Pointer to remote pad + * @flags: Link flags + * + * Rreturn 0 on success + */ +static int csiphy_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + if ((local->flags & MEDIA_PAD_FL_SOURCE) && + (flags & MEDIA_LNK_FL_ENABLED)) { + struct v4l2_subdev *sd; + struct csiphy_device *csiphy; + struct csid_device *csid; + + if (media_entity_remote_pad(local)) + return -EBUSY; + + sd = media_entity_to_v4l2_subdev(entity); + csiphy = v4l2_get_subdevdata(sd); + + sd = media_entity_to_v4l2_subdev(remote->entity); + csid = v4l2_get_subdevdata(sd); + + csiphy->cfg.csid_id = csid->id; + } + + return 0; +} + +static const struct v4l2_subdev_core_ops csiphy_core_ops = { + .s_power = csiphy_set_power, +}; + +static const struct v4l2_subdev_video_ops csiphy_video_ops = { + .s_stream = csiphy_set_stream, +}; + +static const struct v4l2_subdev_pad_ops csiphy_pad_ops = { + .enum_mbus_code = csiphy_enum_mbus_code, + .enum_frame_size = csiphy_enum_frame_size, + .get_fmt = csiphy_get_format, + .set_fmt = csiphy_set_format, +}; + +static const struct v4l2_subdev_ops csiphy_v4l2_ops = { + .core = &csiphy_core_ops, + .video = &csiphy_video_ops, + .pad = &csiphy_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops csiphy_v4l2_internal_ops = { + .open = csiphy_init_formats, +}; + +static const struct media_entity_operations csiphy_media_ops = { + .link_setup = csiphy_link_setup, + .link_validate = v4l2_subdev_link_validate, +}; + +/* + * msm_csiphy_register_entity - Register subdev node for CSIPHY module + * @csiphy: CSIPHY device + * @v4l2_dev: V4L2 device + * + * Return 0 on success or a negative error code otherwise + */ +int msm_csiphy_register_entity(struct csiphy_device *csiphy, + struct v4l2_device *v4l2_dev) +{ + struct v4l2_subdev *sd = &csiphy->subdev; + struct media_pad *pads = csiphy->pads; + struct device *dev = to_device_index(csiphy, csiphy->id); + int ret; + + v4l2_subdev_init(sd, &csiphy_v4l2_ops); + sd->internal_ops = &csiphy_v4l2_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d", + MSM_CSIPHY_NAME, csiphy->id); + v4l2_set_subdevdata(sd, csiphy); + + ret = csiphy_init_formats(sd, NULL); + if (ret < 0) { + dev_err(dev, "Failed to init format: %d\n", ret); + return ret; + } + + pads[MSM_CSIPHY_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[MSM_CSIPHY_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; + + sd->entity.function = MEDIA_ENT_F_IO_V4L; + sd->entity.ops = &csiphy_media_ops; + ret = media_entity_pads_init(&sd->entity, MSM_CSIPHY_PADS_NUM, pads); + if (ret < 0) { + dev_err(dev, "Failed to init media entity: %d\n", ret); + return ret; + } + + ret = v4l2_device_register_subdev(v4l2_dev, sd); + if (ret < 0) { + dev_err(dev, "Failed to register subdev: %d\n", ret); + media_entity_cleanup(&sd->entity); + } + + return ret; +} + +/* + * msm_csiphy_unregister_entity - Unregister CSIPHY module subdev node + * @csiphy: CSIPHY device + */ +void msm_csiphy_unregister_entity(struct csiphy_device *csiphy) +{ + v4l2_device_unregister_subdev(&csiphy->subdev); + media_entity_cleanup(&csiphy->subdev.entity); +} diff --git a/drivers/media/platform/qcom/camss-8x16/camss-csiphy.h b/drivers/media/platform/qcom/camss-8x16/camss-csiphy.h new file mode 100644 index 000000000000..ba8781122065 --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/camss-csiphy.h @@ -0,0 +1,77 @@ +/* + * camss-csiphy.h + * + * Qualcomm MSM Camera Subsystem - CSIPHY Module + * + * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2016-2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef QC_MSM_CAMSS_CSIPHY_H +#define QC_MSM_CAMSS_CSIPHY_H + +#include <linux/clk.h> +#include <media/media-entity.h> +#include <media/v4l2-device.h> +#include <media/v4l2-mediabus.h> +#include <media/v4l2-subdev.h> + +#define MSM_CSIPHY_PAD_SINK 0 +#define MSM_CSIPHY_PAD_SRC 1 +#define MSM_CSIPHY_PADS_NUM 2 + +struct csiphy_lane { + u8 pos; + u8 pol; +}; + +struct csiphy_lanes_cfg { + int num_data; + struct csiphy_lane *data; + struct csiphy_lane clk; +}; + +struct csiphy_csi2_cfg { + struct csiphy_lanes_cfg lane_cfg; +}; + +struct csiphy_config { + u8 combo_mode; + u8 csid_id; + struct csiphy_csi2_cfg *csi2; +}; + +struct csiphy_device { + u8 id; + struct v4l2_subdev subdev; + struct media_pad pads[MSM_CSIPHY_PADS_NUM]; + void __iomem *base; + void __iomem *base_clk_mux; + u32 irq; + char irq_name[30]; + struct camss_clock *clock; + int nclocks; + u32 timer_clk_rate; + struct csiphy_config cfg; + struct v4l2_mbus_framefmt fmt[MSM_CSIPHY_PADS_NUM]; +}; + +struct resources; + +int msm_csiphy_subdev_init(struct csiphy_device *csiphy, + const struct resources *res, u8 id); + +int msm_csiphy_register_entity(struct csiphy_device *csiphy, + struct v4l2_device *v4l2_dev); + +void msm_csiphy_unregister_entity(struct csiphy_device *csiphy); + +#endif /* QC_MSM_CAMSS_CSIPHY_H */ diff --git a/drivers/media/platform/qcom/camss-8x16/camss-ispif.c b/drivers/media/platform/qcom/camss-8x16/camss-ispif.c new file mode 100644 index 000000000000..24da529397b5 --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/camss-ispif.c @@ -0,0 +1,1175 @@ +/* + * camss-ispif.c + * + * Qualcomm MSM Camera Subsystem - ISPIF (ISP Interface) Module + * + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <media/media-entity.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> + +#include "camss-ispif.h" +#include "camss.h" + +#define MSM_ISPIF_NAME "msm_ispif" + +#define ispif_line_array(ptr_line) \ + ((const struct ispif_line (*)[]) &(ptr_line[-(ptr_line->id)])) + +#define to_ispif(ptr_line) \ + container_of(ispif_line_array(ptr_line), struct ispif_device, ptr_line) + +#define ISPIF_RST_CMD_0 0x008 +#define ISPIF_RST_CMD_0_STROBED_RST_EN (1 << 0) +#define ISPIF_RST_CMD_0_MISC_LOGIC_RST (1 << 1) +#define ISPIF_RST_CMD_0_SW_REG_RST (1 << 2) +#define ISPIF_RST_CMD_0_PIX_INTF_0_CSID_RST (1 << 3) +#define ISPIF_RST_CMD_0_PIX_INTF_0_VFE_RST (1 << 4) +#define ISPIF_RST_CMD_0_PIX_INTF_1_CSID_RST (1 << 5) +#define ISPIF_RST_CMD_0_PIX_INTF_1_VFE_RST (1 << 6) +#define ISPIF_RST_CMD_0_RDI_INTF_0_CSID_RST (1 << 7) +#define ISPIF_RST_CMD_0_RDI_INTF_0_VFE_RST (1 << 8) +#define ISPIF_RST_CMD_0_RDI_INTF_1_CSID_RST (1 << 9) +#define ISPIF_RST_CMD_0_RDI_INTF_1_VFE_RST (1 << 10) +#define ISPIF_RST_CMD_0_RDI_INTF_2_CSID_RST (1 << 11) +#define ISPIF_RST_CMD_0_RDI_INTF_2_VFE_RST (1 << 12) +#define ISPIF_RST_CMD_0_PIX_OUTPUT_0_MISR_RST (1 << 16) +#define ISPIF_RST_CMD_0_RDI_OUTPUT_0_MISR_RST (1 << 17) +#define ISPIF_RST_CMD_0_RDI_OUTPUT_1_MISR_RST (1 << 18) +#define ISPIF_RST_CMD_0_RDI_OUTPUT_2_MISR_RST (1 << 19) +#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x01c +#define ISPIF_VFE_m_CTRL_0(m) (0x200 + 0x200 * (m)) +#define ISPIF_VFE_m_CTRL_0_PIX0_LINE_BUF_EN (1 << 6) +#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x208 + 0x200 * (m)) +#define ISPIF_VFE_m_IRQ_MASK_0_PIX0_ENABLE 0x00001249 +#define ISPIF_VFE_m_IRQ_MASK_0_PIX0_MASK 0x00001fff +#define ISPIF_VFE_m_IRQ_MASK_0_RDI0_ENABLE 0x02492000 +#define ISPIF_VFE_m_IRQ_MASK_0_RDI0_MASK 0x03ffe000 +#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x20c + 0x200 * (m)) +#define ISPIF_VFE_m_IRQ_MASK_1_PIX1_ENABLE 0x00001249 +#define ISPIF_VFE_m_IRQ_MASK_1_PIX1_MASK 0x00001fff +#define ISPIF_VFE_m_IRQ_MASK_1_RDI1_ENABLE 0x02492000 +#define ISPIF_VFE_m_IRQ_MASK_1_RDI1_MASK 0x03ffe000 +#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x210 + 0x200 * (m)) +#define ISPIF_VFE_m_IRQ_MASK_2_RDI2_ENABLE 0x00001249 +#define ISPIF_VFE_m_IRQ_MASK_2_RDI2_MASK 0x00001fff +#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x21c + 0x200 * (m)) +#define ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW (1 << 12) +#define ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW (1 << 25) +#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x220 + 0x200 * (m)) +#define ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW (1 << 12) +#define ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW (1 << 25) +#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x224 + 0x200 * (m)) +#define ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW (1 << 12) +#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x230 + 0x200 * (m)) +#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x234 + 0x200 * (m)) +#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x238 + 0x200 * (m)) +#define ISPIF_VFE_m_INTF_INPUT_SEL(m) (0x244 + 0x200 * (m)) +#define ISPIF_VFE_m_INTF_CMD_0(m) (0x248 + 0x200 * (m)) +#define ISPIF_VFE_m_INTF_CMD_1(m) (0x24c + 0x200 * (m)) +#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) \ + (0x254 + 0x200 * (m) + 0x4 * (n)) +#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) \ + (0x264 + 0x200 * (m) + 0x4 * (n)) +#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) \ + (0x2c0 + 0x200 * (m) + 0x4 * (n)) +#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) \ + (0x2d0 + 0x200 * (m) + 0x4 * (n)) + +#define CSI_PIX_CLK_MUX_SEL 0x000 +#define CSI_RDI_CLK_MUX_SEL 0x008 + +#define ISPIF_TIMEOUT_SLEEP_US 1000 +#define ISPIF_TIMEOUT_ALL_US 1000000 +#define ISPIF_RESET_TIMEOUT_MS 500 + +enum ispif_intf_cmd { + CMD_DISABLE_FRAME_BOUNDARY = 0x0, + CMD_ENABLE_FRAME_BOUNDARY = 0x1, + CMD_DISABLE_IMMEDIATELY = 0x2, + CMD_ALL_DISABLE_IMMEDIATELY = 0xaaaaaaaa, + CMD_ALL_NO_CHANGE = 0xffffffff, +}; + +static const u32 ispif_formats[] = { + MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SBGGR12_1X12, + MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_SGRBG12_1X12, + MEDIA_BUS_FMT_SRGGB12_1X12, +}; + +/* + * ispif_isr - ISPIF module interrupt handler + * @irq: Interrupt line + * @dev: ISPIF device + * + * Return IRQ_HANDLED on success + */ +static irqreturn_t ispif_isr(int irq, void *dev) +{ + struct ispif_device *ispif = dev; + u32 value0, value1, value2; + + value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0)); + value1 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_1(0)); + value2 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_2(0)); + + writel_relaxed(value0, ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(0)); + writel_relaxed(value1, ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(0)); + writel_relaxed(value2, ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(0)); + + writel(0x1, ispif->base + ISPIF_IRQ_GLOBAL_CLEAR_CMD); + + if ((value0 >> 27) & 0x1) + complete(&ispif->reset_complete); + + if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW)) + dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n"); + + if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW)) + dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n"); + + if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW)) + dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n"); + + if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW)) + dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n"); + + if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW)) + dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n"); + + return IRQ_HANDLED; +} + +/* + * ispif_reset - Trigger reset on ISPIF module and wait to complete + * @ispif: ISPIF device + * + * Return 0 on success or a negative error code otherwise + */ +static int ispif_reset(struct ispif_device *ispif) +{ + unsigned long time; + u32 val; + int ret; + + ret = camss_enable_clocks(ispif->nclocks_for_reset, + ispif->clock_for_reset, + to_device(ispif)); + if (ret < 0) + return ret; + + reinit_completion(&ispif->reset_complete); + + val = ISPIF_RST_CMD_0_STROBED_RST_EN | + ISPIF_RST_CMD_0_MISC_LOGIC_RST | + ISPIF_RST_CMD_0_SW_REG_RST | + ISPIF_RST_CMD_0_PIX_INTF_0_CSID_RST | + ISPIF_RST_CMD_0_PIX_INTF_0_VFE_RST | + ISPIF_RST_CMD_0_PIX_INTF_1_CSID_RST | + ISPIF_RST_CMD_0_PIX_INTF_1_VFE_RST | + ISPIF_RST_CMD_0_RDI_INTF_0_CSID_RST | + ISPIF_RST_CMD_0_RDI_INTF_0_VFE_RST | + ISPIF_RST_CMD_0_RDI_INTF_1_CSID_RST | + ISPIF_RST_CMD_0_RDI_INTF_1_VFE_RST | + ISPIF_RST_CMD_0_RDI_INTF_2_CSID_RST | + ISPIF_RST_CMD_0_RDI_INTF_2_VFE_RST | + ISPIF_RST_CMD_0_PIX_OUTPUT_0_MISR_RST | + ISPIF_RST_CMD_0_RDI_OUTPUT_0_MISR_RST | + ISPIF_RST_CMD_0_RDI_OUTPUT_1_MISR_RST | + ISPIF_RST_CMD_0_RDI_OUTPUT_2_MISR_RST; + + writel_relaxed(val, ispif->base + ISPIF_RST_CMD_0); + + time = wait_for_completion_timeout(&ispif->reset_complete, + msecs_to_jiffies(ISPIF_RESET_TIMEOUT_MS)); + if (!time) { + dev_err(to_device(ispif), "ISPIF reset timeout\n"); + return -EIO; + } + + camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset); + + return 0; +} + +/* + * ispif_set_power - Power on/off ISPIF module + * @sd: ISPIF V4L2 subdevice + * @on: Requested power state + * + * Return 0 on success or a negative error code otherwise + */ +static int ispif_set_power(struct v4l2_subdev *sd, int on) +{ + struct ispif_line *line = v4l2_get_subdevdata(sd); + struct ispif_device *ispif = to_ispif(line); + struct device *dev = to_device(ispif); + int ret = 0; + + mutex_lock(&ispif->power_lock); + + if (on) { + if (ispif->power_count) { + /* Power is already on */ + ispif->power_count++; + goto exit; + } + + ret = camss_enable_clocks(ispif->nclocks, ispif->clock, dev); + if (ret < 0) + goto exit; + + ret = ispif_reset(ispif); + if (ret < 0) { + camss_disable_clocks(ispif->nclocks, ispif->clock); + goto exit; + } + + ispif->intf_cmd[line->vfe_id].cmd_0 = CMD_ALL_NO_CHANGE; + ispif->intf_cmd[line->vfe_id].cmd_1 = CMD_ALL_NO_CHANGE; + + ispif->power_count++; + } else { + if (ispif->power_count == 0) { + dev_err(dev, "ispif power off on power_count == 0\n"); + goto exit; + } else if (ispif->power_count == 1) { + camss_disable_clocks(ispif->nclocks, ispif->clock); + } + + ispif->power_count--; + } + +exit: + mutex_unlock(&ispif->power_lock); + + return ret; +} + +/* + * ispif_select_clk_mux - Select clock for PIX/RDI interface + * @ispif: ISPIF device + * @intf: VFE interface + * @csid: CSID HW module id + * @vfe: VFE HW module id + * @enable: enable or disable the selected clock + */ +static void ispif_select_clk_mux(struct ispif_device *ispif, + enum ispif_intf intf, u8 csid, + u8 vfe, u8 enable) +{ + u32 val; + + switch (intf) { + case PIX0: + val = readl_relaxed(ispif->base_clk_mux + CSI_PIX_CLK_MUX_SEL); + val &= ~(0xf << (vfe * 8)); + if (enable) + val |= (csid << (vfe * 8)); + writel_relaxed(val, ispif->base_clk_mux + CSI_PIX_CLK_MUX_SEL); + break; + + case RDI0: + val = readl_relaxed(ispif->base_clk_mux + CSI_RDI_CLK_MUX_SEL); + val &= ~(0xf << (vfe * 12)); + if (enable) + val |= (csid << (vfe * 12)); + writel_relaxed(val, ispif->base_clk_mux + CSI_RDI_CLK_MUX_SEL); + break; + + case PIX1: + val = readl_relaxed(ispif->base_clk_mux + CSI_PIX_CLK_MUX_SEL); + val &= ~(0xf << (4 + (vfe * 8))); + if (enable) + val |= (csid << (4 + (vfe * 8))); + writel_relaxed(val, ispif->base_clk_mux + CSI_PIX_CLK_MUX_SEL); + break; + + case RDI1: + val = readl_relaxed(ispif->base_clk_mux + CSI_RDI_CLK_MUX_SEL); + val &= ~(0xf << (4 + (vfe * 12))); + if (enable) + val |= (csid << (4 + (vfe * 12))); + writel_relaxed(val, ispif->base_clk_mux + CSI_RDI_CLK_MUX_SEL); + break; + + case RDI2: + val = readl_relaxed(ispif->base_clk_mux + CSI_RDI_CLK_MUX_SEL); + val &= ~(0xf << (8 + (vfe * 12))); + if (enable) + val |= (csid << (8 + (vfe * 12))); + writel_relaxed(val, ispif->base_clk_mux + CSI_RDI_CLK_MUX_SEL); + break; + } + + mb(); +} + +/* + * ispif_validate_intf_status - Validate current status of PIX/RDI interface + * @ispif: ISPIF device + * @intf: VFE interface + * @vfe: VFE HW module id + * + * Return 0 when interface is idle or -EBUSY otherwise + */ +static int ispif_validate_intf_status(struct ispif_device *ispif, + enum ispif_intf intf, u8 vfe) +{ + int ret = 0; + u32 val = 0; + + switch (intf) { + case PIX0: + val = readl_relaxed(ispif->base + + ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe, 0)); + break; + case RDI0: + val = readl_relaxed(ispif->base + + ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe, 0)); + break; + case PIX1: + val = readl_relaxed(ispif->base + + ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe, 1)); + break; + case RDI1: + val = readl_relaxed(ispif->base + + ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe, 1)); + break; + case RDI2: + val = readl_relaxed(ispif->base + + ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe, 2)); + break; + } + + if ((val & 0xf) != 0xf) { + dev_err(to_device(ispif), "%s: ispif is busy: 0x%x\n", + __func__, val); + ret = -EBUSY; + } + + return ret; +} + +/* + * ispif_wait_for_stop - Wait for PIX/RDI interface to stop + * @ispif: ISPIF device + * @intf: VFE interface + * @vfe: VFE HW module id + * + * Return 0 on success or a negative error code otherwise + */ +static int ispif_wait_for_stop(struct ispif_device *ispif, + enum ispif_intf intf, u8 vfe) +{ + u32 addr = 0; + u32 stop_flag = 0; + int ret; + + switch (intf) { + case PIX0: + addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe, 0); + break; + case RDI0: + addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe, 0); + break; + case PIX1: + addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe, 1); + break; + case RDI1: + addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe, 1); + break; + case RDI2: + addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe, 2); + break; + } + + ret = readl_poll_timeout(ispif->base + addr, + stop_flag, + (stop_flag & 0xf) == 0xf, + ISPIF_TIMEOUT_SLEEP_US, + ISPIF_TIMEOUT_ALL_US); + if (ret < 0) + dev_err(to_device(ispif), "%s: ispif stop timeout\n", + __func__); + + return ret; +} + +/* + * ispif_select_csid - Select CSID HW module for input from + * @ispif: ISPIF device + * @intf: VFE interface + * @csid: CSID HW module id + * @vfe: VFE HW module id + * @enable: enable or disable the selected input + */ +static void ispif_select_csid(struct ispif_device *ispif, enum ispif_intf intf, + u8 csid, u8 vfe, u8 enable) +{ + u32 val; + + val = readl_relaxed(ispif->base + ISPIF_VFE_m_INTF_INPUT_SEL(vfe)); + switch (intf) { + case PIX0: + val &= ~(BIT(1) | BIT(0)); + if (enable) + val |= csid; + break; + case RDI0: + val &= ~(BIT(5) | BIT(4)); + if (enable) + val |= (csid << 4); + break; + case PIX1: + val &= ~(BIT(9) | BIT(8)); + if (enable) + val |= (csid << 8); + break; + case RDI1: + val &= ~(BIT(13) | BIT(12)); + if (enable) + val |= (csid << 12); + break; + case RDI2: + val &= ~(BIT(21) | BIT(20)); + if (enable) + val |= (csid << 20); + break; + } + + writel(val, ispif->base + ISPIF_VFE_m_INTF_INPUT_SEL(vfe)); +} + +/* + * ispif_select_cid - Enable/disable desired CID + * @ispif: ISPIF device + * @intf: VFE interface + * @cid: desired CID to enable/disable + * @vfe: VFE HW module id + * @enable: enable or disable the desired CID + */ +static void ispif_select_cid(struct ispif_device *ispif, enum ispif_intf intf, + u8 cid, u8 vfe, u8 enable) +{ + u32 cid_mask = 1 << cid; + u32 addr = 0; + u32 val; + + switch (intf) { + case PIX0: + addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe, 0); + break; + case RDI0: + addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe, 0); + break; + case PIX1: + addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe, 1); + break; + case RDI1: + addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe, 1); + break; + case RDI2: + addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe, 2); + break; + } + + val = readl_relaxed(ispif->base + addr); + if (enable) + val |= cid_mask; + else + val &= ~cid_mask; + + writel(val, ispif->base + addr); +} + +/* + * ispif_config_irq - Enable/disable interrupts for PIX/RDI interface + * @ispif: ISPIF device + * @intf: VFE interface + * @vfe: VFE HW module id + * @enable: enable or disable + */ +static void ispif_config_irq(struct ispif_device *ispif, enum ispif_intf intf, + u8 vfe, u8 enable) +{ + u32 val; + + switch (intf) { + case PIX0: + val = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_MASK_0(vfe)); + val &= ~ISPIF_VFE_m_IRQ_MASK_0_PIX0_MASK; + if (enable) + val |= ISPIF_VFE_m_IRQ_MASK_0_PIX0_ENABLE; + writel_relaxed(val, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(vfe)); + writel_relaxed(ISPIF_VFE_m_IRQ_MASK_0_PIX0_ENABLE, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(vfe)); + break; + case RDI0: + val = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_MASK_0(vfe)); + val &= ~ISPIF_VFE_m_IRQ_MASK_0_RDI0_MASK; + if (enable) + val |= ISPIF_VFE_m_IRQ_MASK_0_RDI0_ENABLE; + writel_relaxed(val, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(vfe)); + writel_relaxed(ISPIF_VFE_m_IRQ_MASK_0_RDI0_ENABLE, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(vfe)); + break; + case PIX1: + val = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_MASK_1(vfe)); + val &= ~ISPIF_VFE_m_IRQ_MASK_1_PIX1_MASK; + if (enable) + val |= ISPIF_VFE_m_IRQ_MASK_1_PIX1_ENABLE; + writel_relaxed(val, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(vfe)); + writel_relaxed(ISPIF_VFE_m_IRQ_MASK_1_PIX1_ENABLE, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(vfe)); + break; + case RDI1: + val = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_MASK_1(vfe)); + val &= ~ISPIF_VFE_m_IRQ_MASK_1_RDI1_MASK; + if (enable) + val |= ISPIF_VFE_m_IRQ_MASK_1_RDI1_ENABLE; + writel_relaxed(val, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(vfe)); + writel_relaxed(ISPIF_VFE_m_IRQ_MASK_1_RDI1_ENABLE, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(vfe)); + break; + case RDI2: + val = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_MASK_2(vfe)); + val &= ~ISPIF_VFE_m_IRQ_MASK_2_RDI2_MASK; + if (enable) + val |= ISPIF_VFE_m_IRQ_MASK_2_RDI2_ENABLE; + writel_relaxed(val, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(vfe)); + writel_relaxed(ISPIF_VFE_m_IRQ_MASK_2_RDI2_ENABLE, + ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(vfe)); + break; + } + + writel(0x1, ispif->base + ISPIF_IRQ_GLOBAL_CLEAR_CMD); +} + +/* + * ispif_set_intf_cmd - Set command to enable/disable interface + * @ispif: ISPIF device + * @cmd: interface command + * @intf: VFE interface + * @vfe: VFE HW module id + * @vc: virtual channel + */ +static void ispif_set_intf_cmd(struct ispif_device *ispif, u8 cmd, + enum ispif_intf intf, u8 vfe, u8 vc) +{ + u32 *val; + + if (intf == RDI2) { + val = &ispif->intf_cmd[vfe].cmd_1; + *val &= ~(0x3 << (vc * 2 + 8)); + *val |= (cmd << (vc * 2 + 8)); + wmb(); + writel_relaxed(*val, ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe)); + wmb(); + } else { + val = &ispif->intf_cmd[vfe].cmd_0; + *val &= ~(0x3 << (vc * 2 + intf * 8)); + *val |= (cmd << (vc * 2 + intf * 8)); + wmb(); + writel_relaxed(*val, ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe)); + wmb(); + } +} + +/* + * ispif_set_stream - Enable/disable streaming on ISPIF module + * @sd: ISPIF V4L2 subdevice + * @enable: Requested streaming state + * + * Main configuration of ISPIF module is also done here. + * + * Return 0 on success or a negative error code otherwise + */ +static int ispif_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ispif_line *line = v4l2_get_subdevdata(sd); + struct ispif_device *ispif = to_ispif(line); + enum ispif_intf intf = line->interface; + u8 csid = line->csid_id; + u8 vfe = line->vfe_id; + u8 vc = 0; /* Virtual Channel 0 */ + u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ + int ret; + + if (enable) { + if (!media_entity_remote_pad(&line->pads[MSM_ISPIF_PAD_SINK])) + return -ENOLINK; + + /* Config */ + + mutex_lock(&ispif->config_lock); + ispif_select_clk_mux(ispif, intf, csid, vfe, 1); + + ret = ispif_validate_intf_status(ispif, intf, vfe); + if (ret < 0) { + mutex_unlock(&ispif->config_lock); + return ret; + } + + ispif_select_csid(ispif, intf, csid, vfe, 1); + ispif_select_cid(ispif, intf, cid, vfe, 1); + ispif_config_irq(ispif, intf, vfe, 1); + ispif_set_intf_cmd(ispif, CMD_ENABLE_FRAME_BOUNDARY, + intf, vfe, vc); + } else { + mutex_lock(&ispif->config_lock); + ispif_set_intf_cmd(ispif, CMD_DISABLE_FRAME_BOUNDARY, + intf, vfe, vc); + mutex_unlock(&ispif->config_lock); + + ret = ispif_wait_for_stop(ispif, intf, vfe); + if (ret < 0) + return ret; + + mutex_lock(&ispif->config_lock); + ispif_config_irq(ispif, intf, vfe, 0); + ispif_select_cid(ispif, intf, cid, vfe, 0); + ispif_select_csid(ispif, intf, csid, vfe, 0); + ispif_select_clk_mux(ispif, intf, csid, vfe, 0); + } + + mutex_unlock(&ispif->config_lock); + + return 0; +} + +/* + * __ispif_get_format - Get pointer to format structure + * @ispif: ISPIF line + * @cfg: V4L2 subdev pad configuration + * @pad: pad from which format is requested + * @which: TRY or ACTIVE format + * + * Return pointer to TRY or ACTIVE format structure + */ +static struct v4l2_mbus_framefmt * +__ispif_get_format(struct ispif_line *line, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&line->subdev, cfg, pad); + + return &line->fmt[pad]; +} + +/* + * ispif_try_format - Handle try format by pad subdev method + * @ispif: ISPIF line + * @cfg: V4L2 subdev pad configuration + * @pad: pad on which format is requested + * @fmt: pointer to v4l2 format structure + * @which: wanted subdev format + */ +static void ispif_try_format(struct ispif_line *line, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, + struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + unsigned int i; + + switch (pad) { + case MSM_ISPIF_PAD_SINK: + /* Set format on sink pad */ + + for (i = 0; i < ARRAY_SIZE(ispif_formats); i++) + if (fmt->code == ispif_formats[i]) + break; + + /* If not found, use UYVY as default */ + if (i >= ARRAY_SIZE(ispif_formats)) + fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + + fmt->width = clamp_t(u32, fmt->width, 1, 8191); + fmt->height = clamp_t(u32, fmt->height, 1, 8191); + + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + + break; + + case MSM_ISPIF_PAD_SRC: + /* Set and return a format same as sink pad */ + + *fmt = *__ispif_get_format(line, cfg, MSM_ISPIF_PAD_SINK, + which); + + break; + } + + fmt->colorspace = V4L2_COLORSPACE_SRGB; +} + +/* + * ispif_enum_mbus_code - Handle pixel format enumeration + * @sd: ISPIF V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @code: pointer to v4l2_subdev_mbus_code_enum structure + * return -EINVAL or zero on success + */ +static int ispif_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct ispif_line *line = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + if (code->pad == MSM_ISPIF_PAD_SINK) { + if (code->index >= ARRAY_SIZE(ispif_formats)) + return -EINVAL; + + code->code = ispif_formats[code->index]; + } else { + if (code->index > 0) + return -EINVAL; + + format = __ispif_get_format(line, cfg, MSM_ISPIF_PAD_SINK, + code->which); + + code->code = format->code; + } + + return 0; +} + +/* + * ispif_enum_frame_size - Handle frame size enumeration + * @sd: ISPIF V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fse: pointer to v4l2_subdev_frame_size_enum structure + * return -EINVAL or zero on success + */ +static int ispif_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct ispif_line *line = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt format; + + if (fse->index != 0) + return -EINVAL; + + format.code = fse->code; + format.width = 1; + format.height = 1; + ispif_try_format(line, cfg, fse->pad, &format, fse->which); + fse->min_width = format.width; + fse->min_height = format.height; + + if (format.code != fse->code) + return -EINVAL; + + format.code = fse->code; + format.width = -1; + format.height = -1; + ispif_try_format(line, cfg, fse->pad, &format, fse->which); + fse->max_width = format.width; + fse->max_height = format.height; + + return 0; +} + +/* + * ispif_get_format - Handle get format by pads subdev method + * @sd: ISPIF V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fmt: pointer to v4l2 subdev format structure + * + * Return -EINVAL or zero on success + */ +static int ispif_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ispif_line *line = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __ispif_get_format(line, cfg, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + fmt->format = *format; + + return 0; +} + +/* + * ispif_set_format - Handle set format by pads subdev method + * @sd: ISPIF V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fmt: pointer to v4l2 subdev format structure + * + * Return -EINVAL or zero on success + */ +static int ispif_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ispif_line *line = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __ispif_get_format(line, cfg, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + ispif_try_format(line, cfg, fmt->pad, &fmt->format, fmt->which); + *format = fmt->format; + + /* Propagate the format from sink to source */ + if (fmt->pad == MSM_ISPIF_PAD_SINK) { + format = __ispif_get_format(line, cfg, MSM_ISPIF_PAD_SRC, + fmt->which); + + *format = fmt->format; + ispif_try_format(line, cfg, MSM_ISPIF_PAD_SRC, format, + fmt->which); + } + + return 0; +} + +/* + * ispif_init_formats - Initialize formats on all pads + * @sd: ISPIF V4L2 subdevice + * @fh: V4L2 subdev file handle + * + * Initialize all pad formats with default values. + * + * Return 0 on success or a negative error code otherwise + */ +static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_subdev_format format = { + .pad = MSM_ISPIF_PAD_SINK, + .which = fh ? V4L2_SUBDEV_FORMAT_TRY : + V4L2_SUBDEV_FORMAT_ACTIVE, + .format = { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 1920, + .height = 1080 + } + }; + + return ispif_set_format(sd, fh ? fh->pad : NULL, &format); +} + +/* + * msm_ispif_subdev_init - Initialize ISPIF device structure and resources + * @ispif: ISPIF device + * @res: ISPIF module resources table + * + * Return 0 on success or a negative error code otherwise + */ +int msm_ispif_subdev_init(struct ispif_device *ispif, + const struct resources_ispif *res) +{ + struct device *dev = to_device(ispif); + struct platform_device *pdev = to_platform_device(dev); + struct resource *r; + int i; + int ret; + + /* Memory */ + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]); + ispif->base = devm_ioremap_resource(dev, r); + if (IS_ERR(ispif->base)) { + dev_err(dev, "could not map memory\n"); + return PTR_ERR(ispif->base); + } + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]); + ispif->base_clk_mux = devm_ioremap_resource(dev, r); + if (IS_ERR(ispif->base_clk_mux)) { + dev_err(dev, "could not map memory\n"); + return PTR_ERR(ispif->base_clk_mux); + } + + /* Interrupt */ + + r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res->interrupt); + + if (!r) { + dev_err(dev, "missing IRQ\n"); + return -EINVAL; + } + + ispif->irq = r->start; + snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s", + dev_name(dev), MSM_ISPIF_NAME); + ret = devm_request_irq(dev, ispif->irq, ispif_isr, + IRQF_TRIGGER_RISING, ispif->irq_name, ispif); + if (ret < 0) { + dev_err(dev, "request_irq failed: %d\n", ret); + return ret; + } + + /* Clocks */ + + ispif->nclocks = 0; + while (res->clock[ispif->nclocks]) + ispif->nclocks++; + + ispif->clock = devm_kzalloc(dev, ispif->nclocks * sizeof(*ispif->clock), + GFP_KERNEL); + if (!ispif->clock) + return -ENOMEM; + + for (i = 0; i < ispif->nclocks; i++) { + struct camss_clock *clock = &ispif->clock[i]; + + clock->clk = devm_clk_get(dev, res->clock[i]); + if (IS_ERR(clock->clk)) + return PTR_ERR(clock->clk); + + clock->freq = NULL; + clock->nfreqs = 0; + } + + ispif->nclocks_for_reset = 0; + while (res->clock_for_reset[ispif->nclocks_for_reset]) + ispif->nclocks_for_reset++; + + ispif->clock_for_reset = devm_kzalloc(dev, ispif->nclocks_for_reset * + sizeof(*ispif->clock_for_reset), GFP_KERNEL); + if (!ispif->clock_for_reset) + return -ENOMEM; + + for (i = 0; i < ispif->nclocks_for_reset; i++) { + struct camss_clock *clock = &ispif->clock_for_reset[i]; + + clock->clk = devm_clk_get(dev, res->clock_for_reset[i]); + if (IS_ERR(clock->clk)) + return PTR_ERR(clock->clk); + + clock->freq = NULL; + clock->nfreqs = 0; + } + + for (i = 0; i < ARRAY_SIZE(ispif->line); i++) + ispif->line[i].id = i; + + mutex_init(&ispif->power_lock); + ispif->power_count = 0; + + mutex_init(&ispif->config_lock); + + init_completion(&ispif->reset_complete); + + return 0; +} + +/* + * ispif_get_intf - Get ISPIF interface to use by VFE line id + * @line_id: VFE line id that the ISPIF line is connected to + * + * Return ISPIF interface to use + */ +static enum ispif_intf ispif_get_intf(enum vfe_line_id line_id) +{ + switch (line_id) { + case (VFE_LINE_RDI0): + return RDI0; + case (VFE_LINE_RDI1): + return RDI1; + case (VFE_LINE_RDI2): + return RDI2; + case (VFE_LINE_PIX): + return PIX0; + default: + return RDI0; + } +} + +/* + * ispif_link_setup - Setup ISPIF connections + * @entity: Pointer to media entity structure + * @local: Pointer to local pad + * @remote: Pointer to remote pad + * @flags: Link flags + * + * Return 0 on success + */ +static int ispif_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + if (flags & MEDIA_LNK_FL_ENABLED) { + if (media_entity_remote_pad(local)) + return -EBUSY; + + if (local->flags & MEDIA_PAD_FL_SINK) { + struct v4l2_subdev *sd; + struct ispif_line *line; + + sd = media_entity_to_v4l2_subdev(entity); + line = v4l2_get_subdevdata(sd); + + msm_csid_get_csid_id(remote->entity, &line->csid_id); + } else { /* MEDIA_PAD_FL_SOURCE */ + struct v4l2_subdev *sd; + struct ispif_line *line; + enum vfe_line_id id; + + sd = media_entity_to_v4l2_subdev(entity); + line = v4l2_get_subdevdata(sd); + + msm_vfe_get_vfe_id(remote->entity, &line->vfe_id); + msm_vfe_get_vfe_line_id(remote->entity, &id); + line->interface = ispif_get_intf(id); + } + } + + return 0; +} + +static const struct v4l2_subdev_core_ops ispif_core_ops = { + .s_power = ispif_set_power, +}; + +static const struct v4l2_subdev_video_ops ispif_video_ops = { + .s_stream = ispif_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ispif_pad_ops = { + .enum_mbus_code = ispif_enum_mbus_code, + .enum_frame_size = ispif_enum_frame_size, + .get_fmt = ispif_get_format, + .set_fmt = ispif_set_format, +}; + +static const struct v4l2_subdev_ops ispif_v4l2_ops = { + .core = &ispif_core_ops, + .video = &ispif_video_ops, + .pad = &ispif_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops ispif_v4l2_internal_ops = { + .open = ispif_init_formats, +}; + +static const struct media_entity_operations ispif_media_ops = { + .link_setup = ispif_link_setup, + .link_validate = v4l2_subdev_link_validate, +}; + +/* + * msm_ispif_register_entities - Register subdev node for ISPIF module + * @ispif: ISPIF device + * @v4l2_dev: V4L2 device + * + * Return 0 on success or a negative error code otherwise + */ +int msm_ispif_register_entities(struct ispif_device *ispif, + struct v4l2_device *v4l2_dev) +{ + struct device *dev = to_device(ispif); + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(ispif->line); i++) { + struct v4l2_subdev *sd = &ispif->line[i].subdev; + struct media_pad *pads = ispif->line[i].pads; + + v4l2_subdev_init(sd, &ispif_v4l2_ops); + sd->internal_ops = &ispif_v4l2_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d", + MSM_ISPIF_NAME, i); + v4l2_set_subdevdata(sd, &ispif->line[i]); + + ret = ispif_init_formats(sd, NULL); + if (ret < 0) { + dev_err(dev, "Failed to init format: %d\n", ret); + goto error; + } + + pads[MSM_ISPIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[MSM_ISPIF_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; + + sd->entity.function = MEDIA_ENT_F_IO_V4L; + sd->entity.ops = &ispif_media_ops; + ret = media_entity_pads_init(&sd->entity, MSM_ISPIF_PADS_NUM, + pads); + if (ret < 0) { + dev_err(dev, "Failed to init media entity: %d\n", ret); + goto error; + } + + ret = v4l2_device_register_subdev(v4l2_dev, sd); + if (ret < 0) { + dev_err(dev, "Failed to register subdev: %d\n", ret); + media_entity_cleanup(&sd->entity); + goto error; + } + } + + return 0; + +error: + for (i--; i >= 0; i--) { + struct v4l2_subdev *sd = &ispif->line[i].subdev; + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + } + + return ret; +} + +/* + * msm_ispif_unregister_entities - Unregister ISPIF module subdev node + * @ispif: ISPIF device + */ +void msm_ispif_unregister_entities(struct ispif_device *ispif) +{ + int i; + + mutex_destroy(&ispif->power_lock); + mutex_destroy(&ispif->config_lock); + + for (i = 0; i < ARRAY_SIZE(ispif->line); i++) { + struct v4l2_subdev *sd = &ispif->line[i].subdev; + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + } +} diff --git a/drivers/media/platform/qcom/camss-8x16/camss-ispif.h b/drivers/media/platform/qcom/camss-8x16/camss-ispif.h new file mode 100644 index 000000000000..f668306020c3 --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/camss-ispif.h @@ -0,0 +1,85 @@ +/* + * camss-ispif.h + * + * Qualcomm MSM Camera Subsystem - ISPIF (ISP Interface) Module + * + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef QC_MSM_CAMSS_ISPIF_H +#define QC_MSM_CAMSS_ISPIF_H + +#include <linux/clk.h> +#include <media/media-entity.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> + +/* Number of ISPIF lines - same as number of CSID hardware modules */ +#define MSM_ISPIF_LINE_NUM 2 + +#define MSM_ISPIF_PAD_SINK 0 +#define MSM_ISPIF_PAD_SRC 1 +#define MSM_ISPIF_PADS_NUM 2 + +#define MSM_ISPIF_VFE_NUM 1 + +enum ispif_intf { + PIX0, + RDI0, + PIX1, + RDI1, + RDI2 +}; + +struct ispif_intf_cmd_reg { + u32 cmd_0; + u32 cmd_1; +}; + +struct ispif_line { + u8 id; + u8 csid_id; + u8 vfe_id; + enum ispif_intf interface; + struct v4l2_subdev subdev; + struct media_pad pads[MSM_ISPIF_PADS_NUM]; + struct v4l2_mbus_framefmt fmt[MSM_ISPIF_PADS_NUM]; +}; + +struct ispif_device { + void __iomem *base; + void __iomem *base_clk_mux; + u32 irq; + char irq_name[30]; + struct camss_clock *clock; + int nclocks; + struct camss_clock *clock_for_reset; + int nclocks_for_reset; + struct completion reset_complete; + int power_count; + struct mutex power_lock; + struct ispif_intf_cmd_reg intf_cmd[MSM_ISPIF_VFE_NUM]; + struct mutex config_lock; + struct ispif_line line[MSM_ISPIF_LINE_NUM]; +}; + +struct resources_ispif; + +int msm_ispif_subdev_init(struct ispif_device *ispif, + const struct resources_ispif *res); + +int msm_ispif_register_entities(struct ispif_device *ispif, + struct v4l2_device *v4l2_dev); + +void msm_ispif_unregister_entities(struct ispif_device *ispif); + +#endif /* QC_MSM_CAMSS_ISPIF_H */ diff --git a/drivers/media/platform/qcom/camss-8x16/camss-vfe.c b/drivers/media/platform/qcom/camss-8x16/camss-vfe.c new file mode 100644 index 000000000000..b21b3c2dc77f --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/camss-vfe.c @@ -0,0 +1,3088 @@ +/* + * camss-vfe.c + * + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module + * + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/iommu.h> +#include <linux/iopoll.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/spinlock_types.h> +#include <linux/spinlock.h> +#include <media/media-entity.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> + +#include "camss-vfe.h" +#include "camss.h" + +#define MSM_VFE_NAME "msm_vfe" + +#define vfe_line_array(ptr_line) \ + ((const struct vfe_line (*)[]) &(ptr_line[-(ptr_line->id)])) + +#define to_vfe(ptr_line) \ + container_of(vfe_line_array(ptr_line), struct vfe_device, ptr_line) + +#define VFE_0_HW_VERSION 0x000 + +#define VFE_0_GLOBAL_RESET_CMD 0x00c +#define VFE_0_GLOBAL_RESET_CMD_CORE (1 << 0) +#define VFE_0_GLOBAL_RESET_CMD_CAMIF (1 << 1) +#define VFE_0_GLOBAL_RESET_CMD_BUS (1 << 2) +#define VFE_0_GLOBAL_RESET_CMD_BUS_BDG (1 << 3) +#define VFE_0_GLOBAL_RESET_CMD_REGISTER (1 << 4) +#define VFE_0_GLOBAL_RESET_CMD_TIMER (1 << 5) +#define VFE_0_GLOBAL_RESET_CMD_PM (1 << 6) +#define VFE_0_GLOBAL_RESET_CMD_BUS_MISR (1 << 7) +#define VFE_0_GLOBAL_RESET_CMD_TESTGEN (1 << 8) + +#define VFE_0_MODULE_CFG 0x018 +#define VFE_0_MODULE_CFG_DEMUX (1 << 2) +#define VFE_0_MODULE_CFG_CHROMA_UPSAMPLE (1 << 3) +#define VFE_0_MODULE_CFG_SCALE_ENC (1 << 23) +#define VFE_0_MODULE_CFG_CROP_ENC (1 << 27) + +#define VFE_0_CORE_CFG 0x01c +#define VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR 0x4 +#define VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB 0x5 +#define VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY 0x6 +#define VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY 0x7 + +#define VFE_0_IRQ_CMD 0x024 +#define VFE_0_IRQ_CMD_GLOBAL_CLEAR (1 << 0) + +#define VFE_0_IRQ_MASK_0 0x028 +#define VFE_0_IRQ_MASK_0_CAMIF_SOF (1 << 0) +#define VFE_0_IRQ_MASK_0_CAMIF_EOF (1 << 1) +#define VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n) (1 << ((n) + 5)) +#define VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(n) \ + ((n) == VFE_LINE_PIX ? (1 << 4) : VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n)) +#define VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(n) (1 << ((n) + 8)) +#define VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(n) (1 << ((n) + 25)) +#define VFE_0_IRQ_MASK_0_RESET_ACK (1 << 31) +#define VFE_0_IRQ_MASK_1 0x02c +#define VFE_0_IRQ_MASK_1_CAMIF_ERROR (1 << 0) +#define VFE_0_IRQ_MASK_1_VIOLATION (1 << 7) +#define VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK (1 << 8) +#define VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n) (1 << ((n) + 9)) +#define VFE_0_IRQ_MASK_1_RDIn_SOF(n) (1 << ((n) + 29)) + +#define VFE_0_IRQ_CLEAR_0 0x030 +#define VFE_0_IRQ_CLEAR_1 0x034 + +#define VFE_0_IRQ_STATUS_0 0x038 +#define VFE_0_IRQ_STATUS_0_CAMIF_SOF (1 << 0) +#define VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n) (1 << ((n) + 5)) +#define VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(n) \ + ((n) == VFE_LINE_PIX ? (1 << 4) : VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n)) +#define VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(n) (1 << ((n) + 8)) +#define VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(n) (1 << ((n) + 25)) +#define VFE_0_IRQ_STATUS_0_RESET_ACK (1 << 31) +#define VFE_0_IRQ_STATUS_1 0x03c +#define VFE_0_IRQ_STATUS_1_VIOLATION (1 << 7) +#define VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK (1 << 8) +#define VFE_0_IRQ_STATUS_1_RDIn_SOF(n) (1 << ((n) + 29)) + +#define VFE_0_IRQ_COMPOSITE_MASK_0 0x40 +#define VFE_0_VIOLATION_STATUS 0x48 + +#define VFE_0_BUS_CMD 0x4c +#define VFE_0_BUS_CMD_Mx_RLD_CMD(x) (1 << (x)) + +#define VFE_0_BUS_CFG 0x050 + +#define VFE_0_BUS_XBAR_CFG_x(x) (0x58 + 0x4 * ((x) / 2)) +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN (1 << 1) +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA (0x3 << 4) +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT 8 +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA 0 +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 5 +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 6 +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 7 + +#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(n) (0x06c + 0x24 * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_WR_PATH_SHIFT 0 +#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_FRM_BASED_SHIFT 1 +#define VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(n) (0x070 + 0x24 * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(n) (0x074 + 0x24 * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(n) (0x078 + 0x24 * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT 2 +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK (0x1F << 2) + +#define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(n) (0x07c + 0x24 * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT 16 +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(n) (0x080 + 0x24 * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(n) (0x084 + 0x24 * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(n) \ + (0x088 + 0x24 * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(n) \ + (0x08c + 0x24 * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF 0xffffffff + +#define VFE_0_BUS_PING_PONG_STATUS 0x268 + +#define VFE_0_BUS_BDG_CMD 0x2c0 +#define VFE_0_BUS_BDG_CMD_HALT_REQ 1 + +#define VFE_0_BUS_BDG_QOS_CFG_0 0x2c4 +#define VFE_0_BUS_BDG_QOS_CFG_0_CFG 0xaaa5aaa5 +#define VFE_0_BUS_BDG_QOS_CFG_1 0x2c8 +#define VFE_0_BUS_BDG_QOS_CFG_2 0x2cc +#define VFE_0_BUS_BDG_QOS_CFG_3 0x2d0 +#define VFE_0_BUS_BDG_QOS_CFG_4 0x2d4 +#define VFE_0_BUS_BDG_QOS_CFG_5 0x2d8 +#define VFE_0_BUS_BDG_QOS_CFG_6 0x2dc +#define VFE_0_BUS_BDG_QOS_CFG_7 0x2e0 +#define VFE_0_BUS_BDG_QOS_CFG_7_CFG 0x0001aaa5 + +#define VFE_0_RDI_CFG_x(x) (0x2e8 + (0x4 * (x))) +#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT 28 +#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK (0xf << 28) +#define VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT 4 +#define VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK (0xf << 4) +#define VFE_0_RDI_CFG_x_RDI_EN_BIT (1 << 2) +#define VFE_0_RDI_CFG_x_MIPI_EN_BITS 0x3 +#define VFE_0_RDI_CFG_x_RDI_Mr_FRAME_BASED_EN(r) (1 << (16 + (r))) + +#define VFE_0_CAMIF_CMD 0x2f4 +#define VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY 0 +#define VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY 1 +#define VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS (1 << 2) +#define VFE_0_CAMIF_CFG 0x2f8 +#define VFE_0_CAMIF_CFG_VFE_OUTPUT_EN (1 << 6) +#define VFE_0_CAMIF_FRAME_CFG 0x300 +#define VFE_0_CAMIF_WINDOW_WIDTH_CFG 0x304 +#define VFE_0_CAMIF_WINDOW_HEIGHT_CFG 0x308 +#define VFE_0_CAMIF_SUBSAMPLE_CFG_0 0x30c +#define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN 0x314 +#define VFE_0_CAMIF_STATUS 0x31c +#define VFE_0_CAMIF_STATUS_HALT (1 << 31) + +#define VFE_0_REG_UPDATE 0x378 +#define VFE_0_REG_UPDATE_RDIn(n) (1 << (1 + (n))) +#define VFE_0_REG_UPDATE_line_n(n) \ + ((n) == VFE_LINE_PIX ? 1 : VFE_0_REG_UPDATE_RDIn(n)) + +#define VFE_0_DEMUX_CFG 0x424 +#define VFE_0_DEMUX_CFG_PERIOD 0x3 +#define VFE_0_DEMUX_GAIN_0 0x428 +#define VFE_0_DEMUX_GAIN_0_CH0_EVEN (0x80 << 0) +#define VFE_0_DEMUX_GAIN_0_CH0_ODD (0x80 << 16) +#define VFE_0_DEMUX_GAIN_1 0x42c +#define VFE_0_DEMUX_GAIN_1_CH1 (0x80 << 0) +#define VFE_0_DEMUX_GAIN_1_CH2 (0x80 << 16) +#define VFE_0_DEMUX_EVEN_CFG 0x438 +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV 0x9cac +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU 0xac9c +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY 0xc9ca +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY 0xcac9 +#define VFE_0_DEMUX_ODD_CFG 0x43c +#define VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV 0x9cac +#define VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU 0xac9c +#define VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY 0xc9ca +#define VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY 0xcac9 + +#define VFE_0_SCALE_ENC_Y_CFG 0x75c +#define VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE 0x760 +#define VFE_0_SCALE_ENC_Y_H_PHASE 0x764 +#define VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE 0x76c +#define VFE_0_SCALE_ENC_Y_V_PHASE 0x770 +#define VFE_0_SCALE_ENC_CBCR_CFG 0x778 +#define VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE 0x77c +#define VFE_0_SCALE_ENC_CBCR_H_PHASE 0x780 +#define VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE 0x790 +#define VFE_0_SCALE_ENC_CBCR_V_PHASE 0x794 + +#define VFE_0_CROP_ENC_Y_WIDTH 0x854 +#define VFE_0_CROP_ENC_Y_HEIGHT 0x858 +#define VFE_0_CROP_ENC_CBCR_WIDTH 0x85c +#define VFE_0_CROP_ENC_CBCR_HEIGHT 0x860 + +#define VFE_0_CLAMP_ENC_MAX_CFG 0x874 +#define VFE_0_CLAMP_ENC_MAX_CFG_CH0 (0xff << 0) +#define VFE_0_CLAMP_ENC_MAX_CFG_CH1 (0xff << 8) +#define VFE_0_CLAMP_ENC_MAX_CFG_CH2 (0xff << 16) +#define VFE_0_CLAMP_ENC_MIN_CFG 0x878 +#define VFE_0_CLAMP_ENC_MIN_CFG_CH0 (0x0 << 0) +#define VFE_0_CLAMP_ENC_MIN_CFG_CH1 (0x0 << 8) +#define VFE_0_CLAMP_ENC_MIN_CFG_CH2 (0x0 << 16) + +#define VFE_0_CGC_OVERRIDE_1 0x974 +#define VFE_0_CGC_OVERRIDE_1_IMAGE_Mx_CGC_OVERRIDE(x) (1 << (x)) + +/* VFE reset timeout */ +#define VFE_RESET_TIMEOUT_MS 50 +/* VFE halt timeout */ +#define VFE_HALT_TIMEOUT_MS 100 +/* Max number of frame drop updates per frame */ +#define VFE_FRAME_DROP_UPDATES 5 +/* Frame drop value. NOTE: VAL + UPDATES should not exceed 31 */ +#define VFE_FRAME_DROP_VAL 20 + +#define VFE_NEXT_SOF_MS 500 + +#define CAMIF_TIMEOUT_SLEEP_US 1000 +#define CAMIF_TIMEOUT_ALL_US 1000000 + +#define SCALER_RATIO_MAX 16 + +static const struct { + u32 code; + u8 bpp; +} vfe_formats[] = { + { + 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_SBGGR8_1X8, + 8, + }, + { + MEDIA_BUS_FMT_SGBRG8_1X8, + 8, + }, + { + MEDIA_BUS_FMT_SGRBG8_1X8, + 8, + }, + { + MEDIA_BUS_FMT_SRGGB8_1X8, + 8, + }, + { + MEDIA_BUS_FMT_SBGGR10_1X10, + 10, + }, + { + MEDIA_BUS_FMT_SGBRG10_1X10, + 10, + }, + { + MEDIA_BUS_FMT_SGRBG10_1X10, + 10, + }, + { + MEDIA_BUS_FMT_SRGGB10_1X10, + 10, + }, + { + MEDIA_BUS_FMT_SBGGR12_1X12, + 12, + }, + { + MEDIA_BUS_FMT_SGBRG12_1X12, + 12, + }, + { + MEDIA_BUS_FMT_SGRBG12_1X12, + 12, + }, + { + MEDIA_BUS_FMT_SRGGB12_1X12, + 12, + } +}; + +/* + * vfe_get_bpp - map media bus format to bits per pixel + * @code: media bus format code + * + * Return number of bits per pixel + */ +static u8 vfe_get_bpp(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(vfe_formats); i++) + if (code == vfe_formats[i].code) + return vfe_formats[i].bpp; + + WARN(1, "Unknown format\n"); + + return vfe_formats[0].bpp; +} + +static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits) +{ + u32 bits = readl_relaxed(vfe->base + reg); + + writel_relaxed(bits & ~clr_bits, vfe->base + reg); +} + +static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits) +{ + u32 bits = readl_relaxed(vfe->base + reg); + + writel_relaxed(bits | set_bits, vfe->base + reg); +} + +static void vfe_global_reset(struct vfe_device *vfe) +{ + u32 reset_bits = VFE_0_GLOBAL_RESET_CMD_TESTGEN | + VFE_0_GLOBAL_RESET_CMD_BUS_MISR | + VFE_0_GLOBAL_RESET_CMD_PM | + VFE_0_GLOBAL_RESET_CMD_TIMER | + VFE_0_GLOBAL_RESET_CMD_REGISTER | + VFE_0_GLOBAL_RESET_CMD_BUS_BDG | + VFE_0_GLOBAL_RESET_CMD_BUS | + VFE_0_GLOBAL_RESET_CMD_CAMIF | + VFE_0_GLOBAL_RESET_CMD_CORE; + + writel_relaxed(reset_bits, vfe->base + VFE_0_GLOBAL_RESET_CMD); +} + +static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable) +{ + if (enable) + vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm), + 1 << VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_WR_PATH_SHIFT); + else + vfe_reg_clr(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm), + 1 << VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_WR_PATH_SHIFT); +} + +static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable) +{ + if (enable) + vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm), + 1 << VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_FRM_BASED_SHIFT); + else + vfe_reg_clr(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm), + 1 << VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_FRM_BASED_SHIFT); +} + +#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N)) + +static int vfe_word_per_line(uint32_t format, uint32_t pixel_per_line) +{ + int val = 0; + + switch (format) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + val = CALC_WORD(pixel_per_line, 1, 8); + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + val = CALC_WORD(pixel_per_line, 2, 8); + break; + } + + return val; +} + +static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane, + u16 *width, u16 *height, u16 *bytesperline) +{ + switch (pix->pixelformat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + *width = pix->width; + *height = pix->height; + *bytesperline = pix->plane_fmt[0].bytesperline; + if (plane == 1) + *height /= 2; + break; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + *width = pix->width; + *height = pix->height; + *bytesperline = pix->plane_fmt[0].bytesperline; + break; + } +} + +static void vfe_wm_line_based(struct vfe_device *vfe, u32 wm, + struct v4l2_pix_format_mplane *pix, + u8 plane, u32 enable) +{ + u32 reg; + + if (enable) { + u16 width = 0, height = 0, bytesperline = 0, wpl; + + vfe_get_wm_sizes(pix, plane, &width, &height, &bytesperline); + + wpl = vfe_word_per_line(pix->pixelformat, width); + + reg = height - 1; + reg |= ((wpl + 1) / 2 - 1) << 16; + + writel_relaxed(reg, vfe->base + + VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm)); + + wpl = vfe_word_per_line(pix->pixelformat, bytesperline); + + reg = 0x3; + reg |= (height - 1) << 4; + reg |= wpl << 16; + + writel_relaxed(reg, vfe->base + + VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm)); + } else { + writel_relaxed(0, vfe->base + + VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm)); + writel_relaxed(0, vfe->base + + VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm)); + } +} + +static void vfe_wm_set_framedrop_period(struct vfe_device *vfe, u8 wm, u8 per) +{ + u32 reg; + + reg = readl_relaxed(vfe->base + + VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm)); + + reg &= ~(VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK); + + reg |= (per << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT) + & VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK; + + writel_relaxed(reg, + vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm)); +} + +static void vfe_wm_set_framedrop_pattern(struct vfe_device *vfe, u8 wm, + u32 pattern) +{ + writel_relaxed(pattern, + vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(wm)); +} + +static void vfe_wm_set_ub_cfg(struct vfe_device *vfe, u8 wm, u16 offset, + u16 depth) +{ + u32 reg; + + reg = (offset << VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT) | + depth; + writel_relaxed(reg, vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(wm)); +} + +static void vfe_bus_reload_wm(struct vfe_device *vfe, u8 wm) +{ + wmb(); + writel_relaxed(VFE_0_BUS_CMD_Mx_RLD_CMD(wm), vfe->base + VFE_0_BUS_CMD); + wmb(); +} + +static void vfe_wm_set_ping_addr(struct vfe_device *vfe, u8 wm, u32 addr) +{ + writel_relaxed(addr, + vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(wm)); +} + +static void vfe_wm_set_pong_addr(struct vfe_device *vfe, u8 wm, u32 addr) +{ + writel_relaxed(addr, + vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(wm)); +} + +static int vfe_wm_get_ping_pong_status(struct vfe_device *vfe, u8 wm) +{ + u32 reg; + + reg = readl_relaxed(vfe->base + VFE_0_BUS_PING_PONG_STATUS); + + return (reg >> wm) & 0x1; +} + +static void vfe_bus_enable_wr_if(struct vfe_device *vfe, u8 enable) +{ + if (enable) + writel_relaxed(0x10000009, vfe->base + VFE_0_BUS_CFG); + else + writel_relaxed(0, vfe->base + VFE_0_BUS_CFG); +} + +static void vfe_bus_connect_wm_to_rdi(struct vfe_device *vfe, u8 wm, + enum vfe_line_id id) +{ + u32 reg; + + reg = VFE_0_RDI_CFG_x_MIPI_EN_BITS; + reg |= VFE_0_RDI_CFG_x_RDI_Mr_FRAME_BASED_EN(id); + vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), reg); + + reg = VFE_0_RDI_CFG_x_RDI_EN_BIT; + reg |= ((3 * id) << VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT) & + VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK; + vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id), reg); + + switch (id) { + case VFE_LINE_RDI0: + default: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + break; + case VFE_LINE_RDI1: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + break; + case VFE_LINE_RDI2: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + break; + } + + if (wm % 2 == 1) + reg <<= 16; + + vfe_reg_set(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg); +} + +static void vfe_wm_set_subsample(struct vfe_device *vfe, u8 wm) +{ + writel_relaxed(VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF, + vfe->base + + VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(wm)); +} + +static void vfe_bus_disconnect_wm_from_rdi(struct vfe_device *vfe, u8 wm, + enum vfe_line_id id) +{ + u32 reg; + + reg = VFE_0_RDI_CFG_x_RDI_Mr_FRAME_BASED_EN(id); + vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(0), reg); + + reg = VFE_0_RDI_CFG_x_RDI_EN_BIT; + vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id), reg); + + switch (id) { + case VFE_LINE_RDI0: + default: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + break; + case VFE_LINE_RDI1: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + break; + case VFE_LINE_RDI2: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + break; + } + + if (wm % 2 == 1) + reg <<= 16; + + vfe_reg_clr(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg); +} + +static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output, + u8 enable) +{ + struct vfe_line *line = container_of(output, struct vfe_line, output); + u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat; + u32 reg; + unsigned int i; + + for (i = 0; i < output->wm_num; i++) { + if (i == 0) { + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + } else if (i == 1) { + reg = VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN; + if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV16) + reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA; + } + + if (output->wm_idx[i] % 2 == 1) + reg <<= 16; + + if (enable) + vfe_reg_set(vfe, + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[i]), + reg); + else + vfe_reg_clr(vfe, + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[i]), + reg); + } +} + +static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid) +{ + vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id), + VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK); + + vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id), + cid << VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT); +} + +static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + vfe->reg_update |= VFE_0_REG_UPDATE_line_n(line_id); + wmb(); + writel_relaxed(vfe->reg_update, vfe->base + VFE_0_REG_UPDATE); + wmb(); +} + +static void vfe_enable_irq_wm_line(struct vfe_device *vfe, u8 wm, + enum vfe_line_id line_id, u8 enable) +{ + u32 irq_en0 = VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(wm) | + VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(line_id); + u32 irq_en1 = VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(wm) | + VFE_0_IRQ_MASK_1_RDIn_SOF(line_id); + + if (enable) { + vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0); + vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1); + } else { + vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0); + vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1); + } +} + +static void vfe_enable_irq_pix_line(struct vfe_device *vfe, u8 comp, + enum vfe_line_id line_id, u8 enable) +{ + struct vfe_output *output = &vfe->line[line_id].output; + unsigned int i; + u32 irq_en0; + u32 irq_en1; + u32 comp_mask = 0; + + irq_en0 = VFE_0_IRQ_MASK_0_CAMIF_SOF; + irq_en0 |= VFE_0_IRQ_MASK_0_CAMIF_EOF; + irq_en0 |= VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(comp); + irq_en0 |= VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(line_id); + irq_en1 = VFE_0_IRQ_MASK_1_CAMIF_ERROR; + for (i = 0; i < output->wm_num; i++) { + irq_en1 |= VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW( + output->wm_idx[i]); + comp_mask |= (1 << output->wm_idx[i]) << comp * 8; + } + + if (enable) { + vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0); + vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1); + vfe_reg_set(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask); + } else { + vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0); + vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1); + vfe_reg_clr(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask); + } +} + +static void vfe_enable_irq_common(struct vfe_device *vfe) +{ + u32 irq_en0 = VFE_0_IRQ_MASK_0_RESET_ACK; + u32 irq_en1 = VFE_0_IRQ_MASK_1_VIOLATION | + VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK; + + vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0); + vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1); +} + +static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line) +{ + u32 val, even_cfg, odd_cfg; + + writel_relaxed(VFE_0_DEMUX_CFG_PERIOD, vfe->base + VFE_0_DEMUX_CFG); + + val = VFE_0_DEMUX_GAIN_0_CH0_EVEN | VFE_0_DEMUX_GAIN_0_CH0_ODD; + writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_0); + + val = VFE_0_DEMUX_GAIN_1_CH1 | VFE_0_DEMUX_GAIN_1_CH2; + writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1); + + switch (line->fmt[MSM_VFE_PAD_SINK].code) { + case MEDIA_BUS_FMT_YUYV8_2X8: + 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: + 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: + 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: + even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY; + odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY; + break; + } + + writel_relaxed(even_cfg, vfe->base + VFE_0_DEMUX_EVEN_CFG); + writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG); +} + +static inline u8 vfe_calc_interp_reso(u16 input, u16 output) +{ + if (input / output >= 16) + return 0; + + if (input / output >= 8) + return 1; + + if (input / output >= 4) + return 2; + + return 3; +} + +static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line) +{ + u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat; + u32 reg; + u16 input, output; + u8 interp_reso; + u32 phase_mult; + + writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_Y_CFG); + + input = line->fmt[MSM_VFE_PAD_SINK].width; + output = line->compose.width; + reg = (output << 16) | input; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE); + + interp_reso = vfe_calc_interp_reso(input, output); + phase_mult = input * (1 << (13 + interp_reso)) / output; + reg = (interp_reso << 20) | phase_mult; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_PHASE); + + input = line->fmt[MSM_VFE_PAD_SINK].height; + output = line->compose.height; + reg = (output << 16) | input; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE); + + interp_reso = vfe_calc_interp_reso(input, output); + phase_mult = input * (1 << (13 + interp_reso)) / output; + reg = (interp_reso << 20) | phase_mult; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_PHASE); + + writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_CBCR_CFG); + + input = line->fmt[MSM_VFE_PAD_SINK].width; + output = line->compose.width / 2; + reg = (output << 16) | input; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE); + + interp_reso = vfe_calc_interp_reso(input, output); + phase_mult = input * (1 << (13 + interp_reso)) / output; + reg = (interp_reso << 20) | phase_mult; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_PHASE); + + input = line->fmt[MSM_VFE_PAD_SINK].height; + output = line->compose.height; + if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21) + output = line->compose.height / 2; + reg = (output << 16) | input; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE); + + interp_reso = vfe_calc_interp_reso(input, output); + phase_mult = input * (1 << (13 + interp_reso)) / output; + reg = (interp_reso << 20) | phase_mult; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_PHASE); +} + +static void vfe_set_crop_cfg(struct vfe_device *vfe, struct vfe_line *line) +{ + u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat; + u32 reg; + u16 first, last; + + first = line->crop.left; + last = line->crop.left + line->crop.width - 1; + reg = (first << 16) | last; + writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_WIDTH); + + first = line->crop.top; + last = line->crop.top + line->crop.height - 1; + reg = (first << 16) | last; + writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_HEIGHT); + + first = line->crop.left / 2; + last = line->crop.left / 2 + line->crop.width / 2 - 1; + reg = (first << 16) | last; + writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_WIDTH); + + first = line->crop.top; + last = line->crop.top + line->crop.height - 1; + if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21) { + first = line->crop.top / 2; + last = line->crop.top / 2 + line->crop.height / 2 - 1; + } + reg = (first << 16) | last; + writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_HEIGHT); +} + +static void vfe_set_clamp_cfg(struct vfe_device *vfe) +{ + u32 val = VFE_0_CLAMP_ENC_MAX_CFG_CH0 | + VFE_0_CLAMP_ENC_MAX_CFG_CH1 | + VFE_0_CLAMP_ENC_MAX_CFG_CH2; + + writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MAX_CFG); + + val = VFE_0_CLAMP_ENC_MIN_CFG_CH0 | + VFE_0_CLAMP_ENC_MIN_CFG_CH1 | + VFE_0_CLAMP_ENC_MIN_CFG_CH2; + + writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG); +} + +/* + * vfe_reset - Trigger reset on VFE module and wait to complete + * @vfe: VFE device + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_reset(struct vfe_device *vfe) +{ + unsigned long time; + + reinit_completion(&vfe->reset_complete); + + vfe_global_reset(vfe); + + time = wait_for_completion_timeout(&vfe->reset_complete, + msecs_to_jiffies(VFE_RESET_TIMEOUT_MS)); + if (!time) { + dev_err(to_device(vfe), "VFE reset timeout\n"); + return -EIO; + } + + return 0; +} + +/* + * vfe_halt - Trigger halt on VFE module and wait to complete + * @vfe: VFE device + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_halt(struct vfe_device *vfe) +{ + unsigned long time; + + reinit_completion(&vfe->halt_complete); + + writel_relaxed(VFE_0_BUS_BDG_CMD_HALT_REQ, + vfe->base + VFE_0_BUS_BDG_CMD); + + time = wait_for_completion_timeout(&vfe->halt_complete, + msecs_to_jiffies(VFE_HALT_TIMEOUT_MS)); + if (!time) { + dev_err(to_device(vfe), "VFE halt timeout\n"); + return -EIO; + } + + return 0; +} + +static void vfe_init_outputs(struct vfe_device *vfe) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vfe->line); i++) { + struct vfe_output *output = &vfe->line[i].output; + + output->state = VFE_OUTPUT_OFF; + output->buf[0] = NULL; + output->buf[1] = NULL; + INIT_LIST_HEAD(&output->pending_bufs); + + output->wm_num = 1; + if (vfe->line[i].id == VFE_LINE_PIX) + output->wm_num = 2; + } +} + +static void vfe_reset_output_maps(struct vfe_device *vfe) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++) + vfe->wm_output_map[i] = VFE_LINE_NONE; +} + +static void vfe_set_qos(struct vfe_device *vfe) +{ + u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG; + u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG; + + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6); + writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7); +} + +static void vfe_set_cgc_override(struct vfe_device *vfe, u8 wm, u8 enable) +{ + u32 val = VFE_0_CGC_OVERRIDE_1_IMAGE_Mx_CGC_OVERRIDE(wm); + + if (enable) + vfe_reg_set(vfe, VFE_0_CGC_OVERRIDE_1, val); + else + vfe_reg_clr(vfe, VFE_0_CGC_OVERRIDE_1, val); + + wmb(); +} + +static void vfe_set_module_cfg(struct vfe_device *vfe, u8 enable) +{ + u32 val = VFE_0_MODULE_CFG_DEMUX | + VFE_0_MODULE_CFG_CHROMA_UPSAMPLE | + VFE_0_MODULE_CFG_SCALE_ENC | + VFE_0_MODULE_CFG_CROP_ENC; + + if (enable) + writel_relaxed(val, vfe->base + VFE_0_MODULE_CFG); + else + writel_relaxed(0x0, vfe->base + VFE_0_MODULE_CFG); +} + +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: + val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR; + break; + case MEDIA_BUS_FMT_YVYU8_2X8: + val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB; + break; + case MEDIA_BUS_FMT_UYVY8_2X8: + default: + val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY; + break; + case MEDIA_BUS_FMT_VYUY8_2X8: + val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY; + break; + } + + writel_relaxed(val, vfe->base + VFE_0_CORE_CFG); + + val = line->fmt[MSM_VFE_PAD_SINK].width * 2; + val |= line->fmt[MSM_VFE_PAD_SINK].height << 16; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_FRAME_CFG); + + val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_WIDTH_CFG); + + val = line->fmt[MSM_VFE_PAD_SINK].height - 1; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_HEIGHT_CFG); + + val = 0xffffffff; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_SUBSAMPLE_CFG_0); + + val = 0xffffffff; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN); + + val = VFE_0_RDI_CFG_x_MIPI_EN_BITS; + vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), val); + + val = VFE_0_CAMIF_CFG_VFE_OUTPUT_EN; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_CFG); +} + +static void vfe_set_camif_cmd(struct vfe_device *vfe, u32 cmd) +{ + writel_relaxed(VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS, + vfe->base + VFE_0_CAMIF_CMD); + + writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD); +} + +static int vfe_camif_wait_for_stop(struct vfe_device *vfe) +{ + u32 val; + int ret; + + ret = readl_poll_timeout(vfe->base + VFE_0_CAMIF_STATUS, + val, + (val & VFE_0_CAMIF_STATUS_HALT), + CAMIF_TIMEOUT_SLEEP_US, + CAMIF_TIMEOUT_ALL_US); + if (ret < 0) + dev_err(to_device(vfe), "%s: camif stop timeout\n", __func__); + + return ret; +} + +static void vfe_output_init_addrs(struct vfe_device *vfe, + struct vfe_output *output, u8 sync) +{ + u32 ping_addr; + u32 pong_addr; + unsigned int i; + + output->active_buf = 0; + + for (i = 0; i < output->wm_num; i++) { + if (output->buf[0]) + ping_addr = output->buf[0]->addr[i]; + else + ping_addr = 0; + + if (output->buf[1]) + pong_addr = output->buf[1]->addr[i]; + else + pong_addr = ping_addr; + + vfe_wm_set_ping_addr(vfe, output->wm_idx[i], ping_addr); + vfe_wm_set_pong_addr(vfe, output->wm_idx[i], pong_addr); + if (sync) + vfe_bus_reload_wm(vfe, output->wm_idx[i]); + } +} + +static void vfe_output_update_ping_addr(struct vfe_device *vfe, + struct vfe_output *output, u8 sync) +{ + u32 addr; + unsigned int i; + + for (i = 0; i < output->wm_num; i++) { + if (output->buf[0]) + addr = output->buf[0]->addr[i]; + else + addr = 0; + + vfe_wm_set_ping_addr(vfe, output->wm_idx[i], addr); + if (sync) + vfe_bus_reload_wm(vfe, output->wm_idx[i]); + } +} + +static void vfe_output_update_pong_addr(struct vfe_device *vfe, + struct vfe_output *output, u8 sync) +{ + u32 addr; + unsigned int i; + + for (i = 0; i < output->wm_num; i++) { + if (output->buf[1]) + addr = output->buf[1]->addr[i]; + else + addr = 0; + + vfe_wm_set_pong_addr(vfe, output->wm_idx[i], addr); + if (sync) + vfe_bus_reload_wm(vfe, output->wm_idx[i]); + } + +} + +static int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + int ret = -EBUSY; + int i; + + for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++) { + if (vfe->wm_output_map[i] == VFE_LINE_NONE) { + vfe->wm_output_map[i] = line_id; + ret = i; + break; + } + } + + return ret; +} + +static int vfe_release_wm(struct vfe_device *vfe, u8 wm) +{ + if (wm >= ARRAY_SIZE(vfe->wm_output_map)) + return -EINVAL; + + vfe->wm_output_map[wm] = VFE_LINE_NONE; + + return 0; +} + +static void vfe_output_frame_drop(struct vfe_device *vfe, + struct vfe_output *output, + u32 drop_pattern) +{ + u8 drop_period; + unsigned int i; + + /* We need to toggle update period to be valid on next frame */ + output->drop_update_idx++; + output->drop_update_idx %= VFE_FRAME_DROP_UPDATES; + drop_period = VFE_FRAME_DROP_VAL + output->drop_update_idx; + + for (i = 0; i < output->wm_num; i++) { + vfe_wm_set_framedrop_period(vfe, output->wm_idx[i], + drop_period); + vfe_wm_set_framedrop_pattern(vfe, output->wm_idx[i], + drop_pattern); + } + vfe_reg_update(vfe, container_of(output, struct vfe_line, output)->id); +} + +static struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output) +{ + struct camss_buffer *buffer = NULL; + + if (!list_empty(&output->pending_bufs)) { + buffer = list_first_entry(&output->pending_bufs, + struct camss_buffer, + queue); + list_del(&buffer->queue); + } + + return buffer; +} + +/* + * vfe_buf_add_pending - Add output buffer to list of pending + * @output: VFE output + * @buffer: Video buffer + */ +static void vfe_buf_add_pending(struct vfe_output *output, + struct camss_buffer *buffer) +{ + INIT_LIST_HEAD(&buffer->queue); + list_add_tail(&buffer->queue, &output->pending_bufs); +} + +/* + * vfe_buf_flush_pending - Flush all pending buffers. + * @output: VFE output + * @state: vb2 buffer state + */ +static void vfe_buf_flush_pending(struct vfe_output *output, + enum vb2_buffer_state state) +{ + struct camss_buffer *buf; + struct camss_buffer *t; + + list_for_each_entry_safe(buf, t, &output->pending_bufs, queue) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->queue); + } +} + +static void vfe_buf_update_wm_on_next(struct vfe_device *vfe, + struct vfe_output *output) +{ + switch (output->state) { + case VFE_OUTPUT_CONTINUOUS: + vfe_output_frame_drop(vfe, output, 3); + break; + case VFE_OUTPUT_SINGLE: + default: + dev_err_ratelimited(to_device(vfe), + "Next buf in wrong state! %d\n", + output->state); + break; + } +} + +static void vfe_buf_update_wm_on_last(struct vfe_device *vfe, + struct vfe_output *output) +{ + switch (output->state) { + case VFE_OUTPUT_CONTINUOUS: + output->state = VFE_OUTPUT_SINGLE; + vfe_output_frame_drop(vfe, output, 1); + break; + case VFE_OUTPUT_SINGLE: + output->state = VFE_OUTPUT_STOPPING; + vfe_output_frame_drop(vfe, output, 0); + break; + default: + dev_err_ratelimited(to_device(vfe), + "Last buff in wrong state! %d\n", + output->state); + break; + } +} + +static void vfe_buf_update_wm_on_new(struct vfe_device *vfe, + struct vfe_output *output, + struct camss_buffer *new_buf) +{ + int inactive_idx; + + switch (output->state) { + case VFE_OUTPUT_SINGLE: + inactive_idx = !output->active_buf; + + if (!output->buf[inactive_idx]) { + output->buf[inactive_idx] = new_buf; + + if (inactive_idx) + vfe_output_update_pong_addr(vfe, output, 0); + else + vfe_output_update_ping_addr(vfe, output, 0); + + vfe_output_frame_drop(vfe, output, 3); + output->state = VFE_OUTPUT_CONTINUOUS; + } else { + vfe_buf_add_pending(output, new_buf); + dev_err_ratelimited(to_device(vfe), + "Inactive buffer is busy\n"); + } + break; + + case VFE_OUTPUT_IDLE: + if (!output->buf[0]) { + output->buf[0] = new_buf; + + vfe_output_init_addrs(vfe, output, 1); + + vfe_output_frame_drop(vfe, output, 1); + output->state = VFE_OUTPUT_SINGLE; + } else { + vfe_buf_add_pending(output, new_buf); + dev_err_ratelimited(to_device(vfe), + "Output idle with buffer set!\n"); + } + break; + + case VFE_OUTPUT_CONTINUOUS: + default: + vfe_buf_add_pending(output, new_buf); + break; + } +} + +static int vfe_get_output(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + struct vfe_output *output; + unsigned long flags; + int i; + int wm_idx; + + spin_lock_irqsave(&vfe->output_lock, flags); + + output = &line->output; + if (output->state != VFE_OUTPUT_OFF) { + dev_err(to_device(vfe), "Output is running\n"); + goto error; + } + output->state = VFE_OUTPUT_RESERVED; + + output->active_buf = 0; + + for (i = 0; i < output->wm_num; i++) { + wm_idx = vfe_reserve_wm(vfe, line->id); + if (wm_idx < 0) { + dev_err(to_device(vfe), "Can not reserve wm\n"); + goto error_get_wm; + } + output->wm_idx[i] = wm_idx; + } + + output->drop_update_idx = 0; + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return 0; + +error_get_wm: + for (i--; i >= 0; i--) + vfe_release_wm(vfe, output->wm_idx[i]); + output->state = VFE_OUTPUT_OFF; +error: + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return -EINVAL; +} + +static int vfe_put_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_release_wm(vfe, output->wm_idx[i]); + + output->state = VFE_OUTPUT_OFF; + + spin_unlock_irqrestore(&vfe->output_lock, flags); + return 0; +} + +static int vfe_enable_output(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + struct vfe_output *output = &line->output; + unsigned long flags; + unsigned int i; + u16 ub_size; + + switch (vfe->id) { + case 0: + ub_size = MSM_VFE_VFE0_UB_SIZE_RDI; + break; + case 1: + ub_size = MSM_VFE_VFE1_UB_SIZE_RDI; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&vfe->output_lock, flags); + + vfe->reg_update &= ~VFE_0_REG_UPDATE_line_n(line->id); + + if (output->state != VFE_OUTPUT_RESERVED) { + dev_err(to_device(vfe), "Output is not in reserved state %d\n", + output->state); + spin_unlock_irqrestore(&vfe->output_lock, flags); + return -EINVAL; + } + output->state = VFE_OUTPUT_IDLE; + + output->buf[0] = vfe_buf_get_pending(output); + output->buf[1] = vfe_buf_get_pending(output); + + if (!output->buf[0] && output->buf[1]) { + output->buf[0] = output->buf[1]; + output->buf[1] = NULL; + } + + if (output->buf[0]) + output->state = VFE_OUTPUT_SINGLE; + + if (output->buf[1]) + output->state = VFE_OUTPUT_CONTINUOUS; + + switch (output->state) { + case VFE_OUTPUT_SINGLE: + vfe_output_frame_drop(vfe, output, 1); + break; + case VFE_OUTPUT_CONTINUOUS: + vfe_output_frame_drop(vfe, output, 3); + break; + default: + vfe_output_frame_drop(vfe, output, 0); + break; + } + + output->sequence = 0; + output->wait_sof = 0; + output->wait_reg_update = 0; + reinit_completion(&output->sof); + reinit_completion(&output->reg_update); + + vfe_output_init_addrs(vfe, output, 0); + + if (line->id != VFE_LINE_PIX) { + vfe_set_cgc_override(vfe, output->wm_idx[0], 1); + vfe_enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 1); + vfe_bus_connect_wm_to_rdi(vfe, output->wm_idx[0], line->id); + vfe_wm_set_subsample(vfe, output->wm_idx[0]); + vfe_set_rdi_cid(vfe, line->id, 0); + vfe_wm_set_ub_cfg(vfe, output->wm_idx[0], + (ub_size + 1) * output->wm_idx[0], ub_size); + vfe_wm_frame_based(vfe, output->wm_idx[0], 1); + vfe_wm_enable(vfe, output->wm_idx[0], 1); + vfe_bus_reload_wm(vfe, output->wm_idx[0]); + } else { + ub_size /= output->wm_num; + for (i = 0; i < output->wm_num; i++) { + vfe_set_cgc_override(vfe, output->wm_idx[i], 1); + vfe_wm_set_subsample(vfe, output->wm_idx[i]); + vfe_wm_set_ub_cfg(vfe, output->wm_idx[i], + (ub_size + 1) * output->wm_idx[i], + ub_size); + vfe_wm_line_based(vfe, output->wm_idx[i], + &line->video_out.active_fmt.fmt.pix_mp, + i, 1); + vfe_wm_enable(vfe, output->wm_idx[i], 1); + vfe_bus_reload_wm(vfe, output->wm_idx[i]); + } + vfe_enable_irq_pix_line(vfe, 0, line->id, 1); + vfe_set_module_cfg(vfe, 1); + vfe_set_camif_cfg(vfe, line); + vfe_set_xbar_cfg(vfe, output, 1); + vfe_set_demux_cfg(vfe, line); + vfe_set_scale_cfg(vfe, line); + vfe_set_crop_cfg(vfe, line); + vfe_set_clamp_cfg(vfe); + vfe_set_camif_cmd(vfe, VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY); + } + + vfe_reg_update(vfe, line->id); + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + 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 long time; + unsigned int i; + + spin_lock_irqsave(&vfe->output_lock, flags); + + output->wait_sof = 1; + spin_unlock_irqrestore(&vfe->output_lock, flags); + + time = wait_for_completion_timeout(&output->sof, + msecs_to_jiffies(VFE_NEXT_SOF_MS)); + if (!time) + dev_err(to_device(vfe), "VFE sof timeout\n"); + + spin_lock_irqsave(&vfe->output_lock, flags); + for (i = 0; i < output->wm_num; i++) + vfe_wm_enable(vfe, output->wm_idx[i], 0); + + vfe_reg_update(vfe, line->id); + output->wait_reg_update = 1; + spin_unlock_irqrestore(&vfe->output_lock, flags); + + time = wait_for_completion_timeout(&output->reg_update, + msecs_to_jiffies(VFE_NEXT_SOF_MS)); + if (!time) + dev_err(to_device(vfe), "VFE reg update timeout\n"); + + spin_lock_irqsave(&vfe->output_lock, flags); + + if (line->id != VFE_LINE_PIX) { + vfe_wm_frame_based(vfe, output->wm_idx[0], 0); + vfe_bus_disconnect_wm_from_rdi(vfe, output->wm_idx[0], line->id); + vfe_enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 0); + vfe_set_cgc_override(vfe, output->wm_idx[0], 0); + spin_unlock_irqrestore(&vfe->output_lock, flags); + } else { + for (i = 0; i < output->wm_num; i++) { + vfe_wm_line_based(vfe, output->wm_idx[i], NULL, i, 0); + vfe_set_cgc_override(vfe, output->wm_idx[i], 0); + } + + vfe_enable_irq_pix_line(vfe, 0, line->id, 0); + vfe_set_module_cfg(vfe, 0); + vfe_set_xbar_cfg(vfe, output, 0); + + vfe_set_camif_cmd(vfe, VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY); + spin_unlock_irqrestore(&vfe->output_lock, flags); + + vfe_camif_wait_for_stop(vfe); + } + + return 0; +} + +/* + * vfe_enable - Enable streaming on VFE line + * @line: VFE line + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_enable(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + int ret; + + mutex_lock(&vfe->stream_lock); + + if (!vfe->stream_count) { + vfe_enable_irq_common(vfe); + + vfe_bus_enable_wr_if(vfe, 1); + + vfe_set_qos(vfe); + } + + vfe->stream_count++; + + mutex_unlock(&vfe->stream_lock); + + ret = vfe_get_output(line); + if (ret < 0) + goto error_get_output; + + ret = vfe_enable_output(line); + if (ret < 0) + goto error_enable_output; + + vfe->was_streaming = 1; + + return 0; + + +error_enable_output: + vfe_put_output(line); + +error_get_output: + mutex_lock(&vfe->stream_lock); + + if (vfe->stream_count == 1) + vfe_bus_enable_wr_if(vfe, 0); + + vfe->stream_count--; + + mutex_unlock(&vfe->stream_lock); + + return ret; +} + +/* + * 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); + + if (vfe->stream_count == 1) + vfe_bus_enable_wr_if(vfe, 0); + + 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 + */ +static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + struct vfe_output *output; + unsigned long flags; + + spin_lock_irqsave(&vfe->output_lock, flags); + output = &vfe->line[line_id].output; + if (output->wait_sof) { + output->wait_sof = 0; + complete(&output->sof); + } + spin_unlock_irqrestore(&vfe->output_lock, flags); +} + +/* + * vfe_isr_reg_update - Process reg update interrupt + * @vfe: VFE Device + * @line_id: VFE line + */ +static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + struct vfe_output *output; + unsigned long flags; + + spin_lock_irqsave(&vfe->output_lock, flags); + vfe->reg_update &= ~VFE_0_REG_UPDATE_line_n(line_id); + + output = &vfe->line[line_id].output; + + if (output->wait_reg_update) { + output->wait_reg_update = 0; + complete(&output->reg_update); + spin_unlock_irqrestore(&vfe->output_lock, flags); + return; + } + + if (output->state == VFE_OUTPUT_STOPPING) { + /* Release last buffer when hw is idle */ + if (output->last_buffer) { + vb2_buffer_done(&output->last_buffer->vb.vb2_buf, + VB2_BUF_STATE_DONE); + output->last_buffer = NULL; + } + output->state = VFE_OUTPUT_IDLE; + + /* Buffers received in stopping state are queued in */ + /* dma pending queue, start next capture here */ + + output->buf[0] = vfe_buf_get_pending(output); + output->buf[1] = vfe_buf_get_pending(output); + + if (!output->buf[0] && output->buf[1]) { + output->buf[0] = output->buf[1]; + output->buf[1] = NULL; + } + + if (output->buf[0]) + output->state = VFE_OUTPUT_SINGLE; + + if (output->buf[1]) + output->state = VFE_OUTPUT_CONTINUOUS; + + switch (output->state) { + case VFE_OUTPUT_SINGLE: + vfe_output_frame_drop(vfe, output, 2); + break; + case VFE_OUTPUT_CONTINUOUS: + vfe_output_frame_drop(vfe, output, 3); + break; + default: + vfe_output_frame_drop(vfe, output, 0); + break; + } + + vfe_output_init_addrs(vfe, output, 1); + } + + spin_unlock_irqrestore(&vfe->output_lock, flags); +} + +/* + * vfe_isr_wm_done - Process write master done interrupt + * @vfe: VFE Device + * @wm: Write master id + */ +static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm) +{ + struct camss_buffer *ready_buf; + struct vfe_output *output; + dma_addr_t *new_addr; + unsigned long flags; + u32 active_index; + u64 ts = ktime_get_ns(); + unsigned int i; + + active_index = vfe_wm_get_ping_pong_status(vfe, wm); + + spin_lock_irqsave(&vfe->output_lock, flags); + + if (vfe->wm_output_map[wm] == VFE_LINE_NONE) { + dev_err_ratelimited(to_device(vfe), + "Received wm done for unmapped index\n"); + goto out_unlock; + } + output = &vfe->line[vfe->wm_output_map[wm]].output; + + if (output->active_buf == active_index) { + dev_err_ratelimited(to_device(vfe), + "Active buffer mismatch!\n"); + goto out_unlock; + } + output->active_buf = active_index; + + ready_buf = output->buf[!active_index]; + if (!ready_buf) { + dev_err_ratelimited(to_device(vfe), + "Missing ready buf %d %d!\n", + !active_index, output->state); + goto out_unlock; + } + + ready_buf->vb.vb2_buf.timestamp = ts; + ready_buf->vb.sequence = output->sequence++; + + /* Get next buffer */ + output->buf[!active_index] = vfe_buf_get_pending(output); + if (!output->buf[!active_index]) { + /* No next buffer - set same address */ + new_addr = ready_buf->addr; + vfe_buf_update_wm_on_last(vfe, output); + } else { + new_addr = output->buf[!active_index]->addr; + vfe_buf_update_wm_on_next(vfe, output); + } + + if (active_index) + for (i = 0; i < output->wm_num; i++) + vfe_wm_set_ping_addr(vfe, output->wm_idx[i], + new_addr[i]); + else + for (i = 0; i < output->wm_num; i++) + vfe_wm_set_pong_addr(vfe, output->wm_idx[i], + new_addr[i]); + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + if (output->state == VFE_OUTPUT_STOPPING) + output->last_buffer = ready_buf; + else + vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + + return; + +out_unlock: + spin_unlock_irqrestore(&vfe->output_lock, flags); +} + +/* + * vfe_isr_wm_done - Process composite image done interrupt + * @vfe: VFE Device + * @comp: Composite image id + */ +static void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++) + if (vfe->wm_output_map[i] == VFE_LINE_PIX) { + vfe_isr_wm_done(vfe, i); + break; + } +} + +/* + * vfe_isr - ISPIF module interrupt handler + * @irq: Interrupt line + * @dev: VFE device + * + * Return IRQ_HANDLED on success + */ +static irqreturn_t vfe_isr(int irq, void *dev) +{ + struct vfe_device *vfe = dev; + u32 value0, value1; + u32 violation; + int i, j; + + value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0); + value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1); + + writel_relaxed(value0, vfe->base + VFE_0_IRQ_CLEAR_0); + writel_relaxed(value1, vfe->base + VFE_0_IRQ_CLEAR_1); + + wmb(); + writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD); + + if (value0 & VFE_0_IRQ_STATUS_0_RESET_ACK) + complete(&vfe->reset_complete); + + if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION) { + violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS); + dev_err_ratelimited(to_device(vfe), + "VFE: violation = 0x%08x\n", violation); + } + + if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK) { + complete(&vfe->halt_complete); + writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD); + } + + for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) + if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i)) + vfe_isr_reg_update(vfe, i); + + if (value0 & VFE_0_IRQ_STATUS_0_CAMIF_SOF) + vfe_isr_sof(vfe, VFE_LINE_PIX); + + for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) + if (value1 & VFE_0_IRQ_STATUS_1_RDIn_SOF(i)) + vfe_isr_sof(vfe, i); + + for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++) + if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(i)) { + vfe_isr_comp_done(vfe, i); + for (j = 0; j < ARRAY_SIZE(vfe->wm_output_map); j++) + if (vfe->wm_output_map[j] == VFE_LINE_PIX) + value0 &= ~VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(j); + } + + for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++) + if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(i)) + vfe_isr_wm_done(vfe, i); + + return IRQ_HANDLED; +} + +/* + * vfe_set_clock_rates - Calculate and set clock rates on VFE module + * @vfe: VFE device + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_set_clock_rates(struct vfe_device *vfe) +{ + struct device *dev = to_device(vfe); + u32 pixel_clock[MSM_VFE_LINE_NUM]; + int i, j; + int ret; + + for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) { + ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity, + &pixel_clock[i]); + if (ret) + pixel_clock[i] = 0; + } + + for (i = 0; i < vfe->nclocks; i++) { + struct camss_clock *clock = &vfe->clock[i]; + + if (!strcmp(clock->name, "camss_vfe_vfe")) { + u64 min_rate = 0; + long rate; + + for (j = VFE_LINE_RDI0; j <= VFE_LINE_PIX; j++) { + u32 tmp; + u8 bpp; + + if (j == VFE_LINE_PIX) { + tmp = pixel_clock[j]; + } else { + bpp = vfe_get_bpp(vfe->line[j]. + fmt[MSM_VFE_PAD_SINK].code); + tmp = pixel_clock[j] * bpp / 64; + } + + if (min_rate < tmp) + min_rate = tmp; + } + + camss_add_clock_margin(&min_rate); + + for (j = 0; j < clock->nfreqs; j++) + if (min_rate < clock->freq[j]) + break; + + if (j == clock->nfreqs) { + dev_err(dev, + "Pixel clock is too high for VFE"); + return -EINVAL; + } + + /* if sensor pixel clock is not available */ + /* set highest possible VFE clock rate */ + if (min_rate == 0) + j = clock->nfreqs - 1; + + rate = clk_round_rate(clock->clk, clock->freq[j]); + if (rate < 0) { + dev_err(dev, "clk round rate failed: %ld\n", + rate); + return -EINVAL; + } + + ret = clk_set_rate(clock->clk, rate); + if (ret < 0) { + dev_err(dev, "clk set rate failed: %d\n", ret); + return ret; + } + } + } + + return 0; +} + +/* + * vfe_check_clock_rates - Check current clock rates on VFE module + * @vfe: VFE device + * + * Return 0 if current clock rates are suitable for a new pipeline + * or a negative error code otherwise + */ +static int vfe_check_clock_rates(struct vfe_device *vfe) +{ + u32 pixel_clock[MSM_VFE_LINE_NUM]; + int i, j; + int ret; + + for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) { + ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity, + &pixel_clock[i]); + if (ret) + pixel_clock[i] = 0; + } + + for (i = 0; i < vfe->nclocks; i++) { + struct camss_clock *clock = &vfe->clock[i]; + + if (!strcmp(clock->name, "camss_vfe_vfe")) { + u64 min_rate = 0; + unsigned long rate; + + for (j = VFE_LINE_RDI0; j <= VFE_LINE_PIX; j++) { + u32 tmp; + u8 bpp; + + if (j == VFE_LINE_PIX) { + tmp = pixel_clock[j]; + } else { + bpp = vfe_get_bpp(vfe->line[j]. + fmt[MSM_VFE_PAD_SINK].code); + tmp = pixel_clock[j] * bpp / 64; + } + + if (min_rate < tmp) + min_rate = tmp; + } + + camss_add_clock_margin(&min_rate); + + rate = clk_get_rate(clock->clk); + if (rate < min_rate) + return -EBUSY; + } + } + + return 0; +} + +/* + * vfe_get - Power up and reset VFE module + * @vfe: VFE Device + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_get(struct vfe_device *vfe) +{ + int ret; + + mutex_lock(&vfe->power_lock); + + if (vfe->power_count == 0) { + ret = vfe_set_clock_rates(vfe); + if (ret < 0) + goto error_clocks; + + ret = camss_enable_clocks(vfe->nclocks, vfe->clock, + to_device(vfe)); + if (ret < 0) + goto error_clocks; + + ret = vfe_reset(vfe); + if (ret < 0) + goto error_reset; + + vfe_reset_output_maps(vfe); + + vfe_init_outputs(vfe); + } else { + ret = vfe_check_clock_rates(vfe); + if (ret < 0) + goto error_clocks; + } + vfe->power_count++; + + mutex_unlock(&vfe->power_lock); + + return 0; + +error_reset: + camss_disable_clocks(vfe->nclocks, vfe->clock); + +error_clocks: + mutex_unlock(&vfe->power_lock); + + return ret; +} + +/* + * vfe_put - Power down VFE module + * @vfe: VFE Device + */ +static void vfe_put(struct vfe_device *vfe) +{ + mutex_lock(&vfe->power_lock); + + if (vfe->power_count == 0) { + dev_err(to_device(vfe), "vfe power off on power_count == 0\n"); + goto exit; + } else if (vfe->power_count == 1) { + if (vfe->was_streaming) { + vfe->was_streaming = 0; + vfe_halt(vfe); + } + camss_disable_clocks(vfe->nclocks, vfe->clock); + } + + vfe->power_count--; + +exit: + mutex_unlock(&vfe->power_lock); +} + +/* + * vfe_video_pad_to_line - Get pointer to VFE line by media pad + * @pad: Media pad + * + * Return pointer to vfe line structure + */ +static struct vfe_line *vfe_video_pad_to_line(struct media_pad *pad) +{ + struct media_pad *vfe_pad; + struct v4l2_subdev *subdev; + + vfe_pad = media_entity_remote_pad(pad); + if (vfe_pad == NULL) + return NULL; + + subdev = media_entity_to_v4l2_subdev(vfe_pad->entity); + + return container_of(subdev, struct vfe_line, subdev); +} + +/* + * vfe_queue_buffer - Add empty buffer + * @vid: Video device structure + * @buf: Buffer to be enqueued + * + * Add an empty buffer - depending on the current number of buffers it will be + * put in pending buffer queue or directly given to the hardware to be filled. + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_queue_buffer(struct camss_video *vid, + struct camss_buffer *buf) +{ + struct vfe_device *vfe = &vid->camss->vfe; + struct vfe_line *line; + struct vfe_output *output; + unsigned long flags; + + line = vfe_video_pad_to_line(&vid->pad); + if (!line) { + dev_err(to_device(vfe), "Can not queue buffer\n"); + return -1; + } + output = &line->output; + + spin_lock_irqsave(&vfe->output_lock, flags); + + vfe_buf_update_wm_on_new(vfe, output, buf); + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return 0; +} + +/* + * vfe_flush_buffers - Return all vb2 buffers + * @vid: Video device structure + * @state: vb2 buffer state of the returned buffers + * + * Return all buffers to vb2. This includes queued pending buffers (still + * unused) and any buffers given to the hardware but again still not used. + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_flush_buffers(struct camss_video *vid, + enum vb2_buffer_state state) +{ + struct vfe_device *vfe = &vid->camss->vfe; + struct vfe_line *line; + struct vfe_output *output; + unsigned long flags; + + line = vfe_video_pad_to_line(&vid->pad); + if (!line) { + dev_err(to_device(vfe), "Can not flush buffers\n"); + return -1; + } + output = &line->output; + + spin_lock_irqsave(&vfe->output_lock, flags); + + vfe_buf_flush_pending(output, state); + + if (output->buf[0]) + vb2_buffer_done(&output->buf[0]->vb.vb2_buf, state); + + if (output->buf[1]) + vb2_buffer_done(&output->buf[1]->vb.vb2_buf, state); + + if (output->last_buffer) { + vb2_buffer_done(&output->last_buffer->vb.vb2_buf, state); + output->last_buffer = NULL; + } + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return 0; +} + +/* + * vfe_set_power - Power on/off VFE module + * @sd: VFE V4L2 subdevice + * @on: Requested power state + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_set_power(struct v4l2_subdev *sd, int on) +{ + struct vfe_line *line = v4l2_get_subdevdata(sd); + struct vfe_device *vfe = to_vfe(line); + int ret; + + if (on) { + u32 hw_version; + + ret = vfe_get(vfe); + if (ret < 0) + return ret; + + hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION); + dev_dbg(to_device(vfe), + "VFE HW Version = 0x%08x\n", hw_version); + } else { + vfe_put(vfe); + } + + return 0; +} + +/* + * vfe_set_stream - Enable/disable streaming on VFE module + * @sd: VFE V4L2 subdevice + * @enable: Requested streaming state + * + * Main configuration of VFE module is triggered here. + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct vfe_line *line = v4l2_get_subdevdata(sd); + struct vfe_device *vfe = to_vfe(line); + int ret; + + if (enable) { + ret = vfe_enable(line); + if (ret < 0) + dev_err(to_device(vfe), + "Failed to enable vfe outputs\n"); + } else { + ret = vfe_disable(line); + if (ret < 0) + dev_err(to_device(vfe), + "Failed to disable vfe outputs\n"); + } + + return ret; +} + +/* + * __vfe_get_format - Get pointer to format structure + * @line: VFE line + * @cfg: V4L2 subdev pad configuration + * @pad: pad from which format is requested + * @which: TRY or ACTIVE format + * + * Return pointer to TRY or ACTIVE format structure + */ +static struct v4l2_mbus_framefmt * +__vfe_get_format(struct vfe_line *line, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&line->subdev, cfg, pad); + + return &line->fmt[pad]; +} + +/* + * __vfe_get_compose - Get pointer to compose selection structure + * @line: VFE line + * @cfg: V4L2 subdev pad configuration + * @which: TRY or ACTIVE format + * + * Return pointer to TRY or ACTIVE compose rectangle structure + */ +static struct v4l2_rect * +__vfe_get_compose(struct vfe_line *line, + struct v4l2_subdev_pad_config *cfg, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_compose(&line->subdev, cfg, + MSM_VFE_PAD_SINK); + + return &line->compose; +} + +/* + * __vfe_get_crop - Get pointer to crop selection structure + * @line: VFE line + * @cfg: V4L2 subdev pad configuration + * @which: TRY or ACTIVE format + * + * Return pointer to TRY or ACTIVE crop rectangle structure + */ +static struct v4l2_rect * +__vfe_get_crop(struct vfe_line *line, + struct v4l2_subdev_pad_config *cfg, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_crop(&line->subdev, cfg, + MSM_VFE_PAD_SRC); + + return &line->crop; +} + +/* + * vfe_try_format - Handle try format by pad subdev method + * @line: VFE line + * @cfg: V4L2 subdev pad configuration + * @pad: pad on which format is requested + * @fmt: pointer to v4l2 format structure + * @which: wanted subdev format + */ +static void vfe_try_format(struct vfe_line *line, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, + struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + unsigned int i; + u32 code; + + switch (pad) { + case MSM_VFE_PAD_SINK: + /* Set format on sink pad */ + + for (i = 0; i < ARRAY_SIZE(vfe_formats); i++) + if (fmt->code == vfe_formats[i].code) + break; + + /* If not found, use UYVY as default */ + if (i >= ARRAY_SIZE(vfe_formats)) + fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + + fmt->width = clamp_t(u32, fmt->width, 1, 8191); + fmt->height = clamp_t(u32, fmt->height, 1, 8191); + + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + + break; + + case MSM_VFE_PAD_SRC: + /* Set and return a format same as sink pad */ + + code = fmt->code; + + *fmt = *__vfe_get_format(line, cfg, MSM_VFE_PAD_SINK, + which); + + if (line->id == VFE_LINE_PIX) { + struct v4l2_rect *rect; + + rect = __vfe_get_crop(line, cfg, which); + + fmt->width = rect->width; + fmt->height = rect->height; + + switch (fmt->code) { + case MEDIA_BUS_FMT_YUYV8_2X8: + if (code == MEDIA_BUS_FMT_YUYV8_1_5X8) + fmt->code = MEDIA_BUS_FMT_YUYV8_1_5X8; + else + fmt->code = MEDIA_BUS_FMT_YUYV8_2X8; + break; + case MEDIA_BUS_FMT_YVYU8_2X8: + if (code == MEDIA_BUS_FMT_YVYU8_1_5X8) + fmt->code = MEDIA_BUS_FMT_YVYU8_1_5X8; + else + fmt->code = MEDIA_BUS_FMT_YVYU8_2X8; + break; + case MEDIA_BUS_FMT_UYVY8_2X8: + default: + if (code == MEDIA_BUS_FMT_UYVY8_1_5X8) + fmt->code = MEDIA_BUS_FMT_UYVY8_1_5X8; + else + fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + break; + case MEDIA_BUS_FMT_VYUY8_2X8: + if (code == MEDIA_BUS_FMT_VYUY8_1_5X8) + fmt->code = MEDIA_BUS_FMT_VYUY8_1_5X8; + else + fmt->code = MEDIA_BUS_FMT_VYUY8_2X8; + break; + } + } + + break; + } + + fmt->colorspace = V4L2_COLORSPACE_SRGB; +} + +/* + * vfe_try_compose - Handle try compose selection by pad subdev method + * @line: VFE line + * @cfg: V4L2 subdev pad configuration + * @rect: pointer to v4l2 rect structure + * @which: wanted subdev format + */ +static void vfe_try_compose(struct vfe_line *line, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_rect *rect, + enum v4l2_subdev_format_whence which) +{ + struct v4l2_mbus_framefmt *fmt; + + fmt = __vfe_get_format(line, cfg, MSM_VFE_PAD_SINK, which); + + if (rect->width > fmt->width) + rect->width = fmt->width; + + if (rect->height > fmt->height) + rect->height = fmt->height; + + if (fmt->width > rect->width * SCALER_RATIO_MAX) + rect->width = (fmt->width + SCALER_RATIO_MAX - 1) / + SCALER_RATIO_MAX; + + rect->width &= ~0x1; + + if (fmt->height > rect->height * SCALER_RATIO_MAX) + rect->height = (fmt->height + SCALER_RATIO_MAX - 1) / + SCALER_RATIO_MAX; + + if (rect->width < 16) + rect->width = 16; + + if (rect->height < 4) + rect->height = 4; +} + +/* + * vfe_try_crop - Handle try crop selection by pad subdev method + * @line: VFE line + * @cfg: V4L2 subdev pad configuration + * @rect: pointer to v4l2 rect structure + * @which: wanted subdev format + */ +static void vfe_try_crop(struct vfe_line *line, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_rect *rect, + enum v4l2_subdev_format_whence which) +{ + struct v4l2_rect *compose; + + compose = __vfe_get_compose(line, cfg, which); + + if (rect->width > compose->width) + rect->width = compose->width; + + if (rect->width + rect->left > compose->width) + rect->left = compose->width - rect->width; + + if (rect->height > compose->height) + rect->height = compose->height; + + if (rect->height + rect->top > compose->height) + rect->top = compose->height - rect->height; + + /* wm in line based mode writes multiple of 16 horizontally */ + rect->left += (rect->width & 0xf) >> 1; + rect->width &= ~0xf; + + if (rect->width < 16) { + rect->left = 0; + rect->width = 16; + } + + if (rect->height < 4) { + rect->top = 0; + rect->height = 4; + } +} + +/* + * vfe_enum_mbus_code - Handle pixel format enumeration + * @sd: VFE V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @code: pointer to v4l2_subdev_mbus_code_enum structure + * + * return -EINVAL or zero on success + */ +static int vfe_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct vfe_line *line = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + if (code->pad == MSM_VFE_PAD_SINK) { + if (code->index >= ARRAY_SIZE(vfe_formats)) + return -EINVAL; + + code->code = vfe_formats[code->index].code; + } else { + if (code->index > 0) + return -EINVAL; + + format = __vfe_get_format(line, cfg, MSM_VFE_PAD_SINK, + code->which); + + code->code = format->code; + } + + return 0; +} + +/* + * vfe_enum_frame_size - Handle frame size enumeration + * @sd: VFE V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fse: pointer to v4l2_subdev_frame_size_enum structure + * + * Return -EINVAL or zero on success + */ +static int vfe_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct vfe_line *line = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt format; + + if (fse->index != 0) + return -EINVAL; + + format.code = fse->code; + format.width = 1; + format.height = 1; + vfe_try_format(line, cfg, fse->pad, &format, fse->which); + fse->min_width = format.width; + fse->min_height = format.height; + + if (format.code != fse->code) + return -EINVAL; + + format.code = fse->code; + format.width = -1; + format.height = -1; + vfe_try_format(line, cfg, fse->pad, &format, fse->which); + fse->max_width = format.width; + fse->max_height = format.height; + + return 0; +} + +/* + * vfe_get_format - Handle get format by pads subdev method + * @sd: VFE V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fmt: pointer to v4l2 subdev format structure + * + * Return -EINVAL or zero on success + */ +static int vfe_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct vfe_line *line = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __vfe_get_format(line, cfg, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + fmt->format = *format; + + return 0; +} + +static int vfe_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel); + +/* + * vfe_set_format - Handle set format by pads subdev method + * @sd: VFE V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fmt: pointer to v4l2 subdev format structure + * + * Return -EINVAL or zero on success + */ +static int vfe_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct vfe_line *line = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __vfe_get_format(line, cfg, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + vfe_try_format(line, cfg, fmt->pad, &fmt->format, fmt->which); + *format = fmt->format; + + if (fmt->pad == MSM_VFE_PAD_SINK) { + struct v4l2_subdev_selection sel = { 0 }; + int ret; + + /* Propagate the format from sink to source */ + format = __vfe_get_format(line, cfg, MSM_VFE_PAD_SRC, + fmt->which); + + *format = fmt->format; + vfe_try_format(line, cfg, MSM_VFE_PAD_SRC, format, + fmt->which); + + if (line->id != VFE_LINE_PIX) + return 0; + + /* Reset sink pad compose selection */ + sel.which = fmt->which; + sel.pad = MSM_VFE_PAD_SINK; + sel.target = V4L2_SEL_TGT_COMPOSE; + sel.r.width = fmt->format.width; + sel.r.height = fmt->format.height; + ret = vfe_set_selection(sd, cfg, &sel); + if (ret < 0) + return ret; + } + + return 0; +} + +/* + * vfe_get_selection - Handle get selection by pads subdev method + * @sd: VFE V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @sel: pointer to v4l2 subdev selection structure + * + * Return -EINVAL or zero on success + */ +static int vfe_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct vfe_line *line = v4l2_get_subdevdata(sd); + struct v4l2_subdev_format fmt = { 0 }; + struct v4l2_rect *rect; + int ret; + + if (line->id != VFE_LINE_PIX) + return -EINVAL; + + if (sel->pad == MSM_VFE_PAD_SINK) + switch (sel->target) { + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + fmt.pad = sel->pad; + fmt.which = sel->which; + ret = vfe_get_format(sd, cfg, &fmt); + if (ret < 0) + return ret; + + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = fmt.format.width; + sel->r.height = fmt.format.height; + break; + case V4L2_SEL_TGT_COMPOSE: + rect = __vfe_get_compose(line, cfg, sel->which); + if (rect == NULL) + return -EINVAL; + + sel->r = *rect; + break; + default: + return -EINVAL; + } + else if (sel->pad == MSM_VFE_PAD_SRC) + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + rect = __vfe_get_compose(line, cfg, sel->which); + if (rect == NULL) + return -EINVAL; + + sel->r.left = rect->left; + sel->r.top = rect->top; + sel->r.width = rect->width; + sel->r.height = rect->height; + break; + case V4L2_SEL_TGT_CROP: + rect = __vfe_get_crop(line, cfg, sel->which); + if (rect == NULL) + return -EINVAL; + + sel->r = *rect; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* + * vfe_set_selection - Handle set selection by pads subdev method + * @sd: VFE V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @sel: pointer to v4l2 subdev selection structure + * + * Return -EINVAL or zero on success + */ +int vfe_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct vfe_line *line = v4l2_get_subdevdata(sd); + struct v4l2_rect *rect; + int ret; + + if (line->id != VFE_LINE_PIX) + return -EINVAL; + + if (sel->target == V4L2_SEL_TGT_COMPOSE && + sel->pad == MSM_VFE_PAD_SINK) { + struct v4l2_subdev_selection crop = { 0 }; + + rect = __vfe_get_compose(line, cfg, sel->which); + if (rect == NULL) + return -EINVAL; + + vfe_try_compose(line, cfg, &sel->r, sel->which); + *rect = sel->r; + + /* Reset source crop selection */ + crop.which = sel->which; + crop.pad = MSM_VFE_PAD_SRC; + crop.target = V4L2_SEL_TGT_CROP; + crop.r = *rect; + ret = vfe_set_selection(sd, cfg, &crop); + } else if (sel->target == V4L2_SEL_TGT_CROP && + sel->pad == MSM_VFE_PAD_SRC) { + struct v4l2_subdev_format fmt = { 0 }; + + rect = __vfe_get_crop(line, cfg, sel->which); + if (rect == NULL) + return -EINVAL; + + vfe_try_crop(line, cfg, &sel->r, sel->which); + *rect = sel->r; + + /* Reset source pad format width and height */ + fmt.which = sel->which; + fmt.pad = MSM_VFE_PAD_SRC; + ret = vfe_get_format(sd, cfg, &fmt); + if (ret < 0) + return ret; + + fmt.format.width = rect->width; + fmt.format.height = rect->height; + ret = vfe_set_format(sd, cfg, &fmt); + } else { + ret = -EINVAL; + } + + return ret; +} + +/* + * vfe_init_formats - Initialize formats on all pads + * @sd: VFE V4L2 subdevice + * @fh: V4L2 subdev file handle + * + * Initialize all pad formats with default values. + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_subdev_format format = { + .pad = MSM_VFE_PAD_SINK, + .which = fh ? V4L2_SUBDEV_FORMAT_TRY : + V4L2_SUBDEV_FORMAT_ACTIVE, + .format = { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 1920, + .height = 1080 + } + }; + + return vfe_set_format(sd, fh ? fh->pad : NULL, &format); +} + +/* + * msm_vfe_subdev_init - Initialize VFE device structure and resources + * @vfe: VFE device + * @res: VFE module resources table + * + * Return 0 on success or a negative error code otherwise + */ +int msm_vfe_subdev_init(struct vfe_device *vfe, const struct resources *res) +{ + struct device *dev = to_device(vfe); + struct platform_device *pdev = to_platform_device(dev); + struct resource *r; + struct camss *camss = to_camss(vfe); + int i, j; + int ret; + + /* Memory */ + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]); + vfe->base = devm_ioremap_resource(dev, r); + if (IS_ERR(vfe->base)) { + dev_err(dev, "could not map memory\n"); + return PTR_ERR(vfe->base); + } + + /* Interrupt */ + + r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, + res->interrupt[0]); + if (!r) { + dev_err(dev, "missing IRQ\n"); + return -EINVAL; + } + + vfe->irq = r->start; + snprintf(vfe->irq_name, sizeof(vfe->irq_name), "%s_%s%d", + dev_name(dev), MSM_VFE_NAME, vfe->id); + ret = devm_request_irq(dev, vfe->irq, vfe_isr, + IRQF_TRIGGER_RISING, vfe->irq_name, vfe); + if (ret < 0) { + dev_err(dev, "request_irq failed: %d\n", ret); + return ret; + } + + /* Clocks */ + + vfe->nclocks = 0; + while (res->clock[vfe->nclocks]) + vfe->nclocks++; + + vfe->clock = devm_kzalloc(dev, vfe->nclocks * sizeof(*vfe->clock), + GFP_KERNEL); + if (!vfe->clock) + return -ENOMEM; + + for (i = 0; i < vfe->nclocks; i++) { + struct camss_clock *clock = &vfe->clock[i]; + + clock->clk = devm_clk_get(dev, res->clock[i]); + if (IS_ERR(clock->clk)) + return PTR_ERR(clock->clk); + + clock->name = res->clock[i]; + + clock->nfreqs = 0; + while (res->clock_rate[i][clock->nfreqs]) + clock->nfreqs++; + + if (!clock->nfreqs) { + clock->freq = NULL; + continue; + } + + clock->freq = devm_kzalloc(dev, clock->nfreqs * + sizeof(*clock->freq), GFP_KERNEL); + if (!clock->freq) + return -ENOMEM; + + for (j = 0; j < clock->nfreqs; j++) + clock->freq[j] = res->clock_rate[i][j]; + } + + mutex_init(&vfe->power_lock); + vfe->power_count = 0; + + mutex_init(&vfe->stream_lock); + vfe->stream_count = 0; + + spin_lock_init(&vfe->output_lock); + + vfe->id = 0; + vfe->reg_update = 0; + + for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) { + vfe->line[i].video_out.type = + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + vfe->line[i].video_out.camss = camss; + vfe->line[i].id = i; + init_completion(&vfe->line[i].output.sof); + init_completion(&vfe->line[i].output.reg_update); + } + + init_completion(&vfe->reset_complete); + init_completion(&vfe->halt_complete); + + return 0; +} + +/* + * msm_vfe_get_vfe_id - Get VFE HW module id + * @entity: Pointer to VFE media entity structure + * @id: Return CSID HW module id here + */ +void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id) +{ + struct v4l2_subdev *sd; + struct vfe_line *line; + struct vfe_device *vfe; + + sd = media_entity_to_v4l2_subdev(entity); + line = v4l2_get_subdevdata(sd); + vfe = to_vfe(line); + + *id = vfe->id; +} + +/* + * msm_vfe_get_vfe_line_id - Get VFE line id by media entity + * @entity: Pointer to VFE media entity structure + * @id: Return VFE line id here + */ +void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id) +{ + struct v4l2_subdev *sd; + struct vfe_line *line; + + sd = media_entity_to_v4l2_subdev(entity); + line = v4l2_get_subdevdata(sd); + + *id = line->id; +} + +/* + * vfe_link_setup - Setup VFE connections + * @entity: Pointer to media entity structure + * @local: Pointer to local pad + * @remote: Pointer to remote pad + * @flags: Link flags + * + * Return 0 on success + */ +static int vfe_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + if (flags & MEDIA_LNK_FL_ENABLED) + if (media_entity_remote_pad(local)) + return -EBUSY; + + return 0; +} + +static const struct v4l2_subdev_core_ops vfe_core_ops = { + .s_power = vfe_set_power, +}; + +static const struct v4l2_subdev_video_ops vfe_video_ops = { + .s_stream = vfe_set_stream, +}; + +static const struct v4l2_subdev_pad_ops vfe_pad_ops = { + .enum_mbus_code = vfe_enum_mbus_code, + .enum_frame_size = vfe_enum_frame_size, + .get_fmt = vfe_get_format, + .set_fmt = vfe_set_format, + .get_selection = vfe_get_selection, + .set_selection = vfe_set_selection, +}; + +static const struct v4l2_subdev_ops vfe_v4l2_ops = { + .core = &vfe_core_ops, + .video = &vfe_video_ops, + .pad = &vfe_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops vfe_v4l2_internal_ops = { + .open = vfe_init_formats, +}; + +static const struct media_entity_operations vfe_media_ops = { + .link_setup = vfe_link_setup, + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct camss_video_ops camss_vfe_video_ops = { + .queue_buffer = vfe_queue_buffer, + .flush_buffers = vfe_flush_buffers, +}; + +void msm_vfe_stop_streaming(struct vfe_device *vfe) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vfe->line); i++) + msm_video_stop_streaming(&vfe->line[i].video_out); +} + +/* + * msm_vfe_register_entities - Register subdev node for VFE module + * @vfe: VFE device + * @v4l2_dev: V4L2 device + * + * Initialize and register a subdev node for the VFE module. Then + * call msm_video_register() to register the video device node which + * will be connected to this subdev node. Then actually create the + * media link between them. + * + * Return 0 on success or a negative error code otherwise + */ +int msm_vfe_register_entities(struct vfe_device *vfe, + struct v4l2_device *v4l2_dev) +{ + struct device *dev = to_device(vfe); + struct v4l2_subdev *sd; + struct media_pad *pads; + struct camss_video *video_out; + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(vfe->line); i++) { + char name[32]; + + sd = &vfe->line[i].subdev; + pads = vfe->line[i].pads; + video_out = &vfe->line[i].video_out; + + v4l2_subdev_init(sd, &vfe_v4l2_ops); + sd->internal_ops = &vfe_v4l2_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + if (i == VFE_LINE_PIX) + snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d_%s", + MSM_VFE_NAME, vfe->id, "pix"); + else + snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d_%s%d", + MSM_VFE_NAME, vfe->id, "rdi", i); + + v4l2_set_subdevdata(sd, &vfe->line[i]); + + ret = vfe_init_formats(sd, NULL); + if (ret < 0) { + dev_err(dev, "Failed to init format: %d\n", ret); + goto error_init; + } + + pads[MSM_VFE_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[MSM_VFE_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; + + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; + sd->entity.ops = &vfe_media_ops; + ret = media_entity_pads_init(&sd->entity, MSM_VFE_PADS_NUM, + pads); + if (ret < 0) { + dev_err(dev, "Failed to init media entity: %d\n", ret); + goto error_init; + } + + ret = v4l2_device_register_subdev(v4l2_dev, sd); + if (ret < 0) { + dev_err(dev, "Failed to register subdev: %d\n", ret); + goto error_reg_subdev; + } + + video_out->ops = &camss_vfe_video_ops; + video_out->bpl_alignment = 8; + video_out->line_based = 0; + if (i == VFE_LINE_PIX) { + video_out->bpl_alignment = 16; + video_out->line_based = 1; + } + snprintf(name, ARRAY_SIZE(name), "%s%d_%s%d", + MSM_VFE_NAME, vfe->id, "video", i); + ret = msm_video_register(video_out, v4l2_dev, name, + i == VFE_LINE_PIX ? 1 : 0); + if (ret < 0) { + dev_err(dev, "Failed to register video node: %d\n", + ret); + goto error_reg_video; + } + + ret = media_create_pad_link( + &sd->entity, MSM_VFE_PAD_SRC, + &video_out->vdev.entity, 0, + MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); + if (ret < 0) { + dev_err(dev, "Failed to link %s->%s entities: %d\n", + sd->entity.name, video_out->vdev.entity.name, + ret); + goto error_link; + } + } + + return 0; + +error_link: + msm_video_unregister(video_out); + +error_reg_video: + v4l2_device_unregister_subdev(sd); + +error_reg_subdev: + media_entity_cleanup(&sd->entity); + +error_init: + for (i--; i >= 0; i--) { + sd = &vfe->line[i].subdev; + video_out = &vfe->line[i].video_out; + + msm_video_unregister(video_out); + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + } + + return ret; +} + +/* + * msm_vfe_unregister_entities - Unregister VFE module subdev node + * @vfe: VFE device + */ +void msm_vfe_unregister_entities(struct vfe_device *vfe) +{ + int i; + + mutex_destroy(&vfe->power_lock); + mutex_destroy(&vfe->stream_lock); + + for (i = 0; i < ARRAY_SIZE(vfe->line); i++) { + struct v4l2_subdev *sd = &vfe->line[i].subdev; + struct camss_video *video_out = &vfe->line[i].video_out; + + msm_video_unregister(video_out); + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + } +} diff --git a/drivers/media/platform/qcom/camss-8x16/camss-vfe.h b/drivers/media/platform/qcom/camss-8x16/camss-vfe.h new file mode 100644 index 000000000000..53d5b66a9dfb --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/camss-vfe.h @@ -0,0 +1,123 @@ +/* + * camss-vfe.h + * + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module + * + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef QC_MSM_CAMSS_VFE_H +#define QC_MSM_CAMSS_VFE_H + +#include <linux/clk.h> +#include <linux/spinlock_types.h> +#include <media/media-entity.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> + +#include "camss-video.h" + +#define MSM_VFE_PAD_SINK 0 +#define MSM_VFE_PAD_SRC 1 +#define MSM_VFE_PADS_NUM 2 + +#define MSM_VFE_LINE_NUM 4 +#define MSM_VFE_IMAGE_MASTERS_NUM 7 +#define MSM_VFE_COMPOSITE_IRQ_NUM 4 + +#define MSM_VFE_VFE0_UB_SIZE 1023 +#define MSM_VFE_VFE0_UB_SIZE_RDI (MSM_VFE_VFE0_UB_SIZE / 3) +#define MSM_VFE_VFE1_UB_SIZE 1535 +#define MSM_VFE_VFE1_UB_SIZE_RDI (MSM_VFE_VFE1_UB_SIZE / 3) + +enum vfe_output_state { + VFE_OUTPUT_OFF, + VFE_OUTPUT_RESERVED, + VFE_OUTPUT_SINGLE, + VFE_OUTPUT_CONTINUOUS, + VFE_OUTPUT_IDLE, + VFE_OUTPUT_STOPPING +}; + +enum vfe_line_id { + VFE_LINE_NONE = -1, + VFE_LINE_RDI0 = 0, + VFE_LINE_RDI1 = 1, + VFE_LINE_RDI2 = 2, + VFE_LINE_PIX = 3 +}; + +struct vfe_output { + u8 wm_num; + u8 wm_idx[3]; + + int active_buf; + struct camss_buffer *buf[2]; + struct camss_buffer *last_buffer; + struct list_head pending_bufs; + + unsigned int drop_update_idx; + + enum vfe_output_state state; + unsigned int sequence; + int wait_sof; + int wait_reg_update; + struct completion sof; + struct completion reg_update; +}; + +struct vfe_line { + enum vfe_line_id id; + struct v4l2_subdev subdev; + struct media_pad pads[MSM_VFE_PADS_NUM]; + struct v4l2_mbus_framefmt fmt[MSM_VFE_PADS_NUM]; + struct v4l2_rect compose; + struct v4l2_rect crop; + struct camss_video video_out; + struct vfe_output output; +}; + +struct vfe_device { + u8 id; + void __iomem *base; + u32 irq; + char irq_name[30]; + struct camss_clock *clock; + int nclocks; + struct completion reset_complete; + struct completion halt_complete; + struct mutex power_lock; + int power_count; + struct mutex stream_lock; + int stream_count; + spinlock_t output_lock; + enum vfe_line_id wm_output_map[MSM_VFE_IMAGE_MASTERS_NUM]; + struct vfe_line line[MSM_VFE_LINE_NUM]; + u32 reg_update; + u8 was_streaming; +}; + +struct resources; + +int msm_vfe_subdev_init(struct vfe_device *vfe, const struct resources *res); + +int msm_vfe_register_entities(struct vfe_device *vfe, + struct v4l2_device *v4l2_dev); + +void msm_vfe_unregister_entities(struct vfe_device *vfe); + +void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id); +void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id); + +void msm_vfe_stop_streaming(struct vfe_device *vfe); + +#endif /* QC_MSM_CAMSS_VFE_H */ diff --git a/drivers/media/platform/qcom/camss-8x16/camss-video.c b/drivers/media/platform/qcom/camss-8x16/camss-video.c new file mode 100644 index 000000000000..cf4219e871bd --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/camss-video.c @@ -0,0 +1,860 @@ +/* + * camss-video.c + * + * Qualcomm MSM Camera Subsystem - V4L2 device node + * + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/slab.h> +#include <media/media-entity.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mc.h> +#include <media/videobuf-core.h> +#include <media/videobuf2-dma-sg.h> + +#include "camss-video.h" +#include "camss.h" + +struct fract { + u8 numerator; + u8 denominator; +}; + +/* + * struct camss_format_info - ISP media bus format information + * @code: V4L2 media bus format code + * @pixelformat: V4L2 pixel format FCC identifier + * @planes: Number of planes + * @hsub: Horizontal subsampling (for each plane) + * @vsub: Vertical subsampling (for each plane) + * @bpp: Bits per pixel when stored in memory (for each plane) + */ +struct camss_format_info { + u32 code; + u32 pixelformat; + u8 planes; + struct fract hsub[3]; + struct fract vsub[3]; + unsigned int bpp[3]; +}; + +static const struct camss_format_info formats_rdi[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_YVYU8_2X8, 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 } }, + { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, +}; + +static const struct camss_format_info formats_pix[] = { + { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1, + { { 1, 1 } }, { { 2, 3 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1, + { { 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, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV16, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV16, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV16, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_NV61, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_NV61, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_NV61, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, + { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_NV61, 1, + { { 1, 1 } }, { { 1, 2 } }, { 8 } }, +}; + +/* ----------------------------------------------------------------------------- + * Helper functions + */ + +static int video_find_format(u32 code, u32 pixelformat, + const struct camss_format_info *formats, + unsigned int nformats) +{ + int i; + + for (i = 0; i < nformats; i++) { + if (formats[i].code == code && + formats[i].pixelformat == pixelformat) + return i; + } + + for (i = 0; i < nformats; i++) + if (formats[i].code == code) + return i; + + WARN_ON(1); + + return -EINVAL; +} + +/* + * video_mbus_to_pix_mp - Convert v4l2_mbus_framefmt to v4l2_pix_format_mplane + * @mbus: v4l2_mbus_framefmt format (input) + * @pix: v4l2_pix_format_mplane format (output) + * @f: a pointer to formats array element to be used for the conversion + * @alignment: bytesperline alignment value + * + * Fill the output pix structure with information from the input mbus format. + * + * Return 0 on success or a negative error code otherwise + */ +static int video_mbus_to_pix_mp(const struct v4l2_mbus_framefmt *mbus, + struct v4l2_pix_format_mplane *pix, + const struct camss_format_info *f, + unsigned int alignment) +{ + unsigned int i; + u32 bytesperline; + + memset(pix, 0, sizeof(*pix)); + v4l2_fill_pix_format_mplane(pix, mbus); + pix->pixelformat = f->pixelformat; + pix->num_planes = f->planes; + for (i = 0; i < pix->num_planes; i++) { + bytesperline = pix->width / f->hsub[i].numerator * + f->hsub[i].denominator * f->bpp[i] / 8; + bytesperline = ALIGN(bytesperline, alignment); + pix->plane_fmt[i].bytesperline = bytesperline; + pix->plane_fmt[i].sizeimage = pix->height / + f->vsub[i].numerator * f->vsub[i].denominator * + bytesperline; + } + + return 0; +} + +static struct v4l2_subdev *video_remote_subdev(struct camss_video *video, + u32 *pad) +{ + struct media_pad *remote; + + remote = media_entity_remote_pad(&video->pad); + + if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) + return NULL; + + if (pad) + *pad = remote->index; + + return media_entity_to_v4l2_subdev(remote->entity); +} + +static int video_get_subdev_format(struct camss_video *video, + struct v4l2_format *format) +{ + struct v4l2_subdev_format fmt; + struct v4l2_subdev *subdev; + u32 pad; + int ret; + + subdev = video_remote_subdev(video, &pad); + if (subdev == NULL) + return -EPIPE; + + fmt.pad = pad; + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); + if (ret) + return ret; + + ret = video_find_format(fmt.format.code, + format->fmt.pix_mp.pixelformat, + video->formats, video->nformats); + if (ret < 0) + return ret; + + format->type = video->type; + + return video_mbus_to_pix_mp(&fmt.format, &format->fmt.pix_mp, + &video->formats[ret], video->bpl_alignment); +} + +/* ----------------------------------------------------------------------------- + * Video queue operations + */ + +static int video_queue_setup(struct vb2_queue *q, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct camss_video *video = vb2_get_drv_priv(q); + const struct v4l2_pix_format_mplane *format = + &video->active_fmt.fmt.pix_mp; + unsigned int i; + + if (*num_planes) { + if (*num_planes != format->num_planes) + return -EINVAL; + + for (i = 0; i < *num_planes; i++) + if (sizes[i] < format->plane_fmt[i].sizeimage) + return -EINVAL; + + return 0; + } + + *num_planes = format->num_planes; + + for (i = 0; i < *num_planes; i++) + sizes[i] = format->plane_fmt[i].sizeimage; + + return 0; +} + +static int video_buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); + struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer, + vb); + const struct v4l2_pix_format_mplane *format = + &video->active_fmt.fmt.pix_mp; + struct sg_table *sgt; + unsigned int i; + + for (i = 0; i < format->num_planes; i++) { + sgt = vb2_dma_sg_plane_desc(vb, i); + if (!sgt) + return -EFAULT; + + buffer->addr[i] = sg_dma_address(sgt->sgl); + } + + if (format->pixelformat == V4L2_PIX_FMT_NV12 || + format->pixelformat == V4L2_PIX_FMT_NV21 || + format->pixelformat == V4L2_PIX_FMT_NV16 || + format->pixelformat == V4L2_PIX_FMT_NV61) + buffer->addr[1] = buffer->addr[0] + + format->plane_fmt[0].bytesperline * + format->height; + + return 0; +} + +static int video_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); + const struct v4l2_pix_format_mplane *format = + &video->active_fmt.fmt.pix_mp; + unsigned int i; + + for (i = 0; i < format->num_planes; i++) { + if (format->plane_fmt[i].sizeimage > vb2_plane_size(vb, i)) + return -EINVAL; + + vb2_set_plane_payload(vb, i, format->plane_fmt[i].sizeimage); + } + + vbuf->field = V4L2_FIELD_NONE; + + return 0; +} + +static void video_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct camss_video *video = vb2_get_drv_priv(vb->vb2_queue); + struct camss_buffer *buffer = container_of(vbuf, struct camss_buffer, + vb); + + video->ops->queue_buffer(video, buffer); +} + +static int video_check_format(struct camss_video *video) +{ + struct v4l2_pix_format_mplane *pix = &video->active_fmt.fmt.pix_mp; + struct v4l2_format format; + struct v4l2_pix_format_mplane *sd_pix = &format.fmt.pix_mp; + int ret; + + sd_pix->pixelformat = pix->pixelformat; + ret = video_get_subdev_format(video, &format); + if (ret < 0) + return ret; + + if (pix->pixelformat != sd_pix->pixelformat || + pix->height != sd_pix->height || + pix->width != sd_pix->width || + pix->num_planes != sd_pix->num_planes || + pix->field != format.fmt.pix_mp.field) + return -EPIPE; + + return 0; +} + +static int video_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct camss_video *video = vb2_get_drv_priv(q); + struct video_device *vdev = &video->vdev; + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + int ret; + + ret = media_pipeline_start(&vdev->entity, &video->pipe); + if (ret < 0) + return ret; + + ret = video_check_format(video); + if (ret < 0) + goto error; + + entity = &vdev->entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + ret = v4l2_subdev_call(subdev, video, s_stream, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) + goto error; + } + + return 0; + +error: + media_pipeline_stop(&vdev->entity); + + video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static void video_stop_streaming(struct vb2_queue *q) +{ + struct camss_video *video = vb2_get_drv_priv(q); + struct video_device *vdev = &video->vdev; + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + + entity = &vdev->entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + v4l2_subdev_call(subdev, video, s_stream, 0); + } + + media_pipeline_stop(&vdev->entity); + + video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR); +} + +static const struct vb2_ops msm_video_vb2_q_ops = { + .queue_setup = video_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_init = video_buf_init, + .buf_prepare = video_buf_prepare, + .buf_queue = video_buf_queue, + .start_streaming = video_start_streaming, + .stop_streaming = video_stop_streaming, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 ioctls + */ + +static int video_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct camss_video *video = video_drvdata(file); + + strlcpy(cap->driver, "qcom-camss", sizeof(cap->driver)); + strlcpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(video->camss->dev)); + + return 0; +} + +static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct camss_video *video = video_drvdata(file); + int i, j, k; + + if (f->type != video->type) + return -EINVAL; + + if (f->index >= video->nformats) + return -EINVAL; + + /* find index "i" of "k"th unique pixelformat in formats array */ + k = -1; + for (i = 0; i < video->nformats; i++) { + for (j = 0; j < i; j++) { + if (video->formats[i].pixelformat == + video->formats[j].pixelformat) + break; + } + + if (j == i) + k++; + + if (k == f->index) + break; + } + + if (k < f->index) + return -EINVAL; + + f->pixelformat = video->formats[i].pixelformat; + + return 0; +} + +static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct camss_video *video = video_drvdata(file); + + *f = video->active_fmt; + + return 0; +} + +static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp; + const struct camss_format_info *fi; + struct v4l2_plane_pix_format *p; + u32 bytesperline[3] = { 0 }; + u32 sizeimage[3] = { 0 }; + u32 width, height; + u32 bpl, lines; + int i, j; + + pix_mp = &f->fmt.pix_mp; + + if (video->line_based) + for (i = 0; i < pix_mp->num_planes && i < 3; i++) { + p = &pix_mp->plane_fmt[i]; + bytesperline[i] = clamp_t(u32, p->bytesperline, + 1, 65528); + sizeimage[i] = clamp_t(u32, p->sizeimage, + bytesperline[i], + bytesperline[i] * 4096); + } + + for (j = 0; j < video->nformats; j++) + if (pix_mp->pixelformat == video->formats[j].pixelformat) + break; + + if (j == video->nformats) + j = 0; /* default format */ + + fi = &video->formats[j]; + width = pix_mp->width; + height = pix_mp->height; + + memset(pix_mp, 0, sizeof(*pix_mp)); + + pix_mp->pixelformat = fi->pixelformat; + pix_mp->width = clamp_t(u32, width, 1, 8191); + pix_mp->height = clamp_t(u32, height, 1, 8191); + pix_mp->num_planes = fi->planes; + for (i = 0; i < pix_mp->num_planes; i++) { + bpl = pix_mp->width / fi->hsub[i].numerator * + fi->hsub[i].denominator * fi->bpp[i] / 8; + bpl = ALIGN(bpl, video->bpl_alignment); + pix_mp->plane_fmt[i].bytesperline = bpl; + pix_mp->plane_fmt[i].sizeimage = pix_mp->height / + fi->vsub[i].numerator * fi->vsub[i].denominator * bpl; + } + + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->colorspace = V4L2_COLORSPACE_SRGB; + pix_mp->flags = 0; + pix_mp->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix_mp->colorspace); + pix_mp->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, + pix_mp->colorspace, pix_mp->ycbcr_enc); + pix_mp->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix_mp->colorspace); + + if (video->line_based) + for (i = 0; i < pix_mp->num_planes; i++) { + p = &pix_mp->plane_fmt[i]; + p->bytesperline = clamp_t(u32, p->bytesperline, + 1, 65528); + p->sizeimage = clamp_t(u32, p->sizeimage, + p->bytesperline, + p->bytesperline * 4096); + lines = p->sizeimage / p->bytesperline; + + if (p->bytesperline < bytesperline[i]) + p->bytesperline = ALIGN(bytesperline[i], 8); + + if (p->sizeimage < p->bytesperline * lines) + p->sizeimage = p->bytesperline * lines; + + if (p->sizeimage < sizeimage[i]) + p->sizeimage = sizeimage[i]; + } + + return 0; +} + +static int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct camss_video *video = video_drvdata(file); + + return __video_try_fmt(video, f); +} + +static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct camss_video *video = video_drvdata(file); + int ret; + + if (vb2_is_busy(&video->vb2_q)) + return -EBUSY; + + ret = __video_try_fmt(video, f); + if (ret < 0) + return ret; + + video->active_fmt = *f; + + return 0; +} + +static int video_enum_input(struct file *file, void *fh, + struct v4l2_input *input) +{ + if (input->index > 0) + return -EINVAL; + + strlcpy(input->name, "camera", sizeof(input->name)); + input->type = V4L2_INPUT_TYPE_CAMERA; + + return 0; +} + +static int video_g_input(struct file *file, void *fh, unsigned int *input) +{ + *input = 0; + + return 0; +} + +static int video_s_input(struct file *file, void *fh, unsigned int input) +{ + return input == 0 ? 0 : -EINVAL; +} + +static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = { + .vidioc_querycap = video_querycap, + .vidioc_enum_fmt_vid_cap_mplane = video_enum_fmt, + .vidioc_g_fmt_vid_cap_mplane = video_g_fmt, + .vidioc_s_fmt_vid_cap_mplane = video_s_fmt, + .vidioc_try_fmt_vid_cap_mplane = video_try_fmt, + .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 = video_enum_input, + .vidioc_g_input = video_g_input, + .vidioc_s_input = video_s_input, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 file operations + */ + +static int video_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct camss_video *video = video_drvdata(file); + struct v4l2_fh *vfh; + int ret; + + mutex_lock(&video->lock); + + vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); + if (vfh == NULL) { + ret = -ENOMEM; + goto error_alloc; + } + + v4l2_fh_init(vfh, vdev); + v4l2_fh_add(vfh); + + file->private_data = vfh; + + ret = v4l2_pipeline_pm_use(&vdev->entity, 1); + if (ret < 0) { + dev_err(video->camss->dev, "Failed to power up pipeline: %d\n", + ret); + goto error_pm_use; + } + + mutex_unlock(&video->lock); + + return 0; + +error_pm_use: + v4l2_fh_release(file); + +error_alloc: + mutex_unlock(&video->lock); + + return ret; +} + +static int video_release(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + + vb2_fop_release(file); + + v4l2_pipeline_pm_use(&vdev->entity, 0); + + file->private_data = NULL; + + return 0; +} + +static const struct v4l2_file_operations msm_vid_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = video_open, + .release = video_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .read = vb2_fop_read, +}; + +/* ----------------------------------------------------------------------------- + * CAMSS video core + */ + +static void msm_video_release(struct video_device *vdev) +{ + struct camss_video *video = video_get_drvdata(vdev); + + media_entity_cleanup(&vdev->entity); + + mutex_destroy(&video->q_lock); + mutex_destroy(&video->lock); + + if (atomic_dec_and_test(&video->camss->ref_count)) + camss_delete(video->camss); +} + +/* + * msm_video_init_format - Helper function to initialize format + * @video: struct camss_video + * + * Initialize pad format with default value. + * + * Return 0 on success or a negative error code otherwise + */ +static int msm_video_init_format(struct camss_video *video) +{ + int ret; + struct v4l2_format format = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .fmt.pix_mp = { + .width = 1920, + .height = 1080, + .pixelformat = video->formats[0].pixelformat, + }, + }; + + ret = __video_try_fmt(video, &format); + if (ret < 0) + return ret; + + video->active_fmt = format; + + return 0; +} + +/* + * msm_video_register - Register a video device node + * @video: struct camss_video + * @v4l2_dev: V4L2 device + * @name: name to be used for the video device node + * + * Initialize and register a video device node to a V4L2 device. Also + * initialize the vb2 queue. + * + * Return 0 on success or a negative error code otherwise + */ + +int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, + const char *name, int is_pix) +{ + struct media_pad *pad = &video->pad; + struct video_device *vdev; + struct vb2_queue *q; + int ret; + + vdev = &video->vdev; + + mutex_init(&video->q_lock); + + q = &video->vb2_q; + q->drv_priv = video; + q->mem_ops = &vb2_dma_sg_memops; + q->ops = &msm_video_vb2_q_ops; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->buf_struct_size = sizeof(struct camss_buffer); + q->dev = video->camss->dev; + q->lock = &video->q_lock; + ret = vb2_queue_init(q); + if (ret < 0) { + dev_err(v4l2_dev->dev, "Failed to init vb2 queue: %d\n", ret); + goto error_vb2_init; + } + + pad->flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vdev->entity, 1, pad); + if (ret < 0) { + dev_err(v4l2_dev->dev, "Failed to init video entity: %d\n", + ret); + goto error_media_init; + } + + mutex_init(&video->lock); + + video->formats = formats_rdi; + video->nformats = ARRAY_SIZE(formats_rdi); + if (is_pix) { + video->formats = formats_pix; + video->nformats = ARRAY_SIZE(formats_pix); + } + + ret = msm_video_init_format(video); + if (ret < 0) { + dev_err(v4l2_dev->dev, "Failed to init format: %d\n", ret); + goto error_video_register; + } + + vdev->fops = &msm_vid_fops; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; + vdev->ioctl_ops = &msm_vid_ioctl_ops; + vdev->release = msm_video_release; + vdev->v4l2_dev = v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + vdev->queue = &video->vb2_q; + vdev->lock = &video->lock; + strlcpy(vdev->name, name, sizeof(vdev->name)); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + dev_err(v4l2_dev->dev, "Failed to register video device: %d\n", + ret); + goto error_video_register; + } + + video_set_drvdata(vdev, video); + atomic_inc(&video->camss->ref_count); + + return 0; + +error_video_register: + media_entity_cleanup(&vdev->entity); + mutex_destroy(&video->lock); +error_media_init: + vb2_queue_release(&video->vb2_q); +error_vb2_init: + mutex_destroy(&video->q_lock); + + return ret; +} + +void msm_video_stop_streaming(struct camss_video *video) +{ + if (vb2_is_streaming(&video->vb2_q)) + vb2_queue_release(&video->vb2_q); +} + +void msm_video_unregister(struct camss_video *video) +{ + atomic_inc(&video->camss->ref_count); + video_unregister_device(&video->vdev); + atomic_dec(&video->camss->ref_count); +} diff --git a/drivers/media/platform/qcom/camss-8x16/camss-video.h b/drivers/media/platform/qcom/camss-8x16/camss-video.h new file mode 100644 index 000000000000..38bd1f2eec54 --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/camss-video.h @@ -0,0 +1,70 @@ +/* + * camss-video.h + * + * Qualcomm MSM Camera Subsystem - V4L2 device node + * + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef QC_MSM_CAMSS_VIDEO_H +#define QC_MSM_CAMSS_VIDEO_H + +#include <linux/mutex.h> +#include <linux/videodev2.h> +#include <media/media-entity.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-mediabus.h> +#include <media/videobuf2-v4l2.h> + +struct camss_buffer { + struct vb2_v4l2_buffer vb; + dma_addr_t addr[3]; + struct list_head queue; +}; + +struct camss_video; + +struct camss_video_ops { + int (*queue_buffer)(struct camss_video *vid, struct camss_buffer *buf); + int (*flush_buffers)(struct camss_video *vid, + enum vb2_buffer_state state); +}; + +struct camss_format_info; + +struct camss_video { + struct camss *camss; + struct vb2_queue vb2_q; + struct video_device vdev; + struct media_pad pad; + struct v4l2_format active_fmt; + enum v4l2_buf_type type; + struct media_pipeline pipe; + const struct camss_video_ops *ops; + struct mutex lock; + struct mutex q_lock; + unsigned int bpl_alignment; + unsigned int line_based; + const struct camss_format_info *formats; + unsigned int nformats; +}; + +void msm_video_stop_streaming(struct camss_video *video); + +int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, + const char *name, int is_pix); + +void msm_video_unregister(struct camss_video *video); + +#endif /* QC_MSM_CAMSS_VIDEO_H */ diff --git a/drivers/media/platform/qcom/camss-8x16/camss.c b/drivers/media/platform/qcom/camss-8x16/camss.c new file mode 100644 index 000000000000..a3760b5dd1d1 --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/camss.c @@ -0,0 +1,746 @@ +/* + * camss.c + * + * Qualcomm MSM Camera Subsystem - Core + * + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/clk.h> +#include <linux/media-bus-format.h> +#include <linux/media.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_graph.h> +#include <linux/slab.h> +#include <linux/videodev2.h> + +#include <media/media-device.h> +#include <media/v4l2-async.h> +#include <media/v4l2-device.h> +#include <media/v4l2-mc.h> +#include <media/v4l2-fwnode.h> + +#include "camss.h" + +#define CAMSS_CLOCK_MARGIN_NUMERATOR 105 +#define CAMSS_CLOCK_MARGIN_DENOMINATOR 100 + +static const struct resources csiphy_res[] = { + /* CSIPHY0 */ + { + .regulator = { NULL }, + .clock = { "camss_top_ahb", "ispif_ahb", + "camss_ahb", "csiphy0_timer" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000 } }, + .reg = { "csiphy0", "csiphy0_clk_mux" }, + .interrupt = { "csiphy0" } + }, + + /* CSIPHY1 */ + { + .regulator = { NULL }, + .clock = { "camss_top_ahb", "ispif_ahb", + "camss_ahb", "csiphy1_timer" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000 } }, + .reg = { "csiphy1", "csiphy1_clk_mux" }, + .interrupt = { "csiphy1" } + } +}; + +static const struct resources csid_res[] = { + /* CSID0 */ + { + .regulator = { "vdda" }, + .clock = { "camss_top_ahb", "ispif_ahb", + "csi0_ahb", "camss_ahb", + "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid0" }, + .interrupt = { "csid0" } + }, + + /* CSID1 */ + { + .regulator = { "vdda" }, + .clock = { "camss_top_ahb", "ispif_ahb", + "csi1_ahb", "camss_ahb", + "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid1" }, + .interrupt = { "csid1" } + }, +}; + +static const struct resources_ispif ispif_res = { + /* ISPIF */ + .clock = { "camss_top_ahb", "camss_ahb", "ispif_ahb", + "csi0", "csi0_pix", "csi0_rdi", + "csi1", "csi1_pix", "csi1_rdi" }, + .clock_for_reset = { "camss_vfe_vfe", "camss_csi_vfe" }, + .reg = { "ispif", "csi_clk_mux" }, + .interrupt = "ispif" + +}; + +static const struct resources vfe_res = { + /* VFE0 */ + .regulator = { NULL }, + .clock = { "camss_top_ahb", "camss_vfe_vfe", "camss_csi_vfe", + "iface", "bus", "camss_ahb" }, + .clock_rate = { { 0 }, + { 50000000, 80000000, 100000000, 160000000, + 177780000, 200000000, 266670000, 320000000, + 400000000, 465000000 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" } +}; + +/* + * camss_add_clock_margin - Add margin to clock frequency rate + * @rate: Clock frequency rate + * + * When making calculations with physical clock frequency values + * some safety margin must be added. Add it. + */ +inline void camss_add_clock_margin(u64 *rate) +{ + *rate *= CAMSS_CLOCK_MARGIN_NUMERATOR; + *rate = div_u64(*rate, CAMSS_CLOCK_MARGIN_DENOMINATOR); +} + +/* + * camss_enable_clocks - Enable multiple clocks + * @nclocks: Number of clocks in clock array + * @clock: Clock array + * @dev: Device + * + * Return 0 on success or a negative error code otherwise + */ +int camss_enable_clocks(int nclocks, struct camss_clock *clock, + struct device *dev) +{ + int ret; + int i; + + for (i = 0; i < nclocks; i++) { + ret = clk_prepare_enable(clock[i].clk); + if (ret) { + dev_err(dev, "clock enable failed: %d\n", ret); + goto error; + } + } + + return 0; + +error: + for (i--; i >= 0; i--) + clk_disable_unprepare(clock[i].clk); + + return ret; +} + +/* + * camss_disable_clocks - Disable multiple clocks + * @nclocks: Number of clocks in clock array + * @clock: Clock array + */ +void camss_disable_clocks(int nclocks, struct camss_clock *clock) +{ + int i; + + for (i = nclocks - 1; i >= 0; i--) + clk_disable_unprepare(clock[i].clk); +} + +/* + * camss_find_sensor - Find a linked media entity which represents a sensor + * @entity: Media entity to start searching from + * + * Return a pointer to sensor media entity or NULL if not found + */ +static struct media_entity *camss_find_sensor(struct media_entity *entity) +{ + struct media_pad *pad; + + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + return NULL; + + pad = media_entity_remote_pad(pad); + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) + return NULL; + + entity = pad->entity; + + if (entity->function == MEDIA_ENT_F_CAM_SENSOR) + return entity; + } +} + +/* + * camss_get_pixel_clock - Get pixel clock rate from sensor + * @entity: Media entity in the current pipeline + * @pixel_clock: Received pixel clock value + * + * Return 0 on success or a negative error code otherwise + */ +int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock) +{ + struct media_entity *sensor; + struct v4l2_subdev *subdev; + struct v4l2_ctrl *ctrl; + + sensor = camss_find_sensor(entity); + if (!sensor) + return -ENODEV; + + subdev = media_entity_to_v4l2_subdev(sensor); + + ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); + + if (!ctrl) + return -EINVAL; + + *pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl); + + return 0; +} + +/* + * camss_of_parse_endpoint_node - Parse port endpoint node + * @dev: Device + * @node: Device node to be parsed + * @csd: Parsed data from port endpoint node + * + * Return 0 on success or a negative error code on failure + */ +static int camss_of_parse_endpoint_node(struct device *dev, + struct device_node *node, + struct camss_async_subdev *csd) +{ + struct csiphy_lanes_cfg *lncfg = &csd->interface.csi2.lane_cfg; + struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2; + struct v4l2_fwnode_endpoint vep = { { 0 } }; + unsigned int i; + + v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep); + + csd->interface.csiphy_id = vep.base.port; + + mipi_csi2 = &vep.bus.mipi_csi2; + lncfg->clk.pos = mipi_csi2->clock_lane; + lncfg->clk.pol = mipi_csi2->lane_polarities[0]; + lncfg->num_data = mipi_csi2->num_data_lanes; + + lncfg->data = devm_kzalloc(dev, lncfg->num_data * sizeof(*lncfg->data), + GFP_KERNEL); + if (!lncfg->data) + return -ENOMEM; + + for (i = 0; i < lncfg->num_data; i++) { + lncfg->data[i].pos = mipi_csi2->data_lanes[i]; + lncfg->data[i].pol = mipi_csi2->lane_polarities[i + 1]; + } + + return 0; +} + +/* + * camss_of_parse_ports - Parse ports node + * @dev: Device + * @notifier: v4l2_device notifier data + * + * Return number of "port" nodes found in "ports" node + */ +static int camss_of_parse_ports(struct device *dev, + struct v4l2_async_notifier *notifier) +{ + struct device_node *node = NULL; + struct device_node *remote = NULL; + unsigned int size, i; + int ret; + + while ((node = of_graph_get_next_endpoint(dev->of_node, node))) + if (of_device_is_available(node)) + notifier->num_subdevs++; + + size = sizeof(*notifier->subdevs) * notifier->num_subdevs; + notifier->subdevs = devm_kzalloc(dev, size, GFP_KERNEL); + if (!notifier->subdevs) { + dev_err(dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + i = 0; + while ((node = of_graph_get_next_endpoint(dev->of_node, node))) { + struct camss_async_subdev *csd; + + if (!of_device_is_available(node)) + continue; + + csd = devm_kzalloc(dev, sizeof(*csd), GFP_KERNEL); + if (!csd) { + of_node_put(node); + dev_err(dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + notifier->subdevs[i++] = &csd->asd; + + ret = camss_of_parse_endpoint_node(dev, node, csd); + if (ret < 0) { + of_node_put(node); + return ret; + } + + remote = of_graph_get_remote_port_parent(node); + of_node_put(node); + + if (!remote) { + dev_err(dev, "Cannot get remote parent\n"); + return -EINVAL; + } + + csd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; + csd->asd.match.fwnode.fwnode = of_fwnode_handle(remote); + } + + return notifier->num_subdevs; +} + +/* + * camss_init_subdevices - Initialize subdev structures and resources + * @camss: CAMSS device + * + * Return 0 on success or a negative error code on failure + */ +static int camss_init_subdevices(struct camss *camss) +{ + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(camss->csiphy); i++) { + ret = msm_csiphy_subdev_init(&camss->csiphy[i], + &csiphy_res[i], i); + if (ret < 0) { + dev_err(camss->dev, + "Failed to init csiphy%d sub-device: %d\n", + i, ret); + return ret; + } + } + + for (i = 0; i < ARRAY_SIZE(camss->csid); i++) { + ret = msm_csid_subdev_init(&camss->csid[i], + &csid_res[i], i); + if (ret < 0) { + dev_err(camss->dev, + "Failed to init csid%d sub-device: %d\n", + i, ret); + return ret; + } + } + + ret = msm_ispif_subdev_init(&camss->ispif, &ispif_res); + if (ret < 0) { + dev_err(camss->dev, "Failed to init ispif sub-device: %d\n", + ret); + return ret; + } + + ret = msm_vfe_subdev_init(&camss->vfe, &vfe_res); + if (ret < 0) { + dev_err(camss->dev, "Fail to init vfe sub-device: %d\n", ret); + return ret; + } + + return 0; +} + +/* + * camss_register_entities - Register subdev nodes and create links + * @camss: CAMSS device + * + * Return 0 on success or a negative error code on failure + */ +static int camss_register_entities(struct camss *camss) +{ + int i, j; + int ret; + + for (i = 0; i < ARRAY_SIZE(camss->csiphy); i++) { + ret = msm_csiphy_register_entity(&camss->csiphy[i], + &camss->v4l2_dev); + if (ret < 0) { + dev_err(camss->dev, + "Failed to register csiphy%d entity: %d\n", + i, ret); + goto err_reg_csiphy; + } + } + + for (i = 0; i < ARRAY_SIZE(camss->csid); i++) { + ret = msm_csid_register_entity(&camss->csid[i], + &camss->v4l2_dev); + if (ret < 0) { + dev_err(camss->dev, + "Failed to register csid%d entity: %d\n", + i, ret); + goto err_reg_csid; + } + } + + ret = msm_ispif_register_entities(&camss->ispif, &camss->v4l2_dev); + if (ret < 0) { + dev_err(camss->dev, "Failed to register ispif entities: %d\n", + ret); + goto err_reg_ispif; + } + + ret = msm_vfe_register_entities(&camss->vfe, &camss->v4l2_dev); + if (ret < 0) { + dev_err(camss->dev, "Failed to register vfe entities: %d\n", + ret); + goto err_reg_vfe; + } + + for (i = 0; i < ARRAY_SIZE(camss->csiphy); i++) { + for (j = 0; j < ARRAY_SIZE(camss->csid); j++) { + ret = media_create_pad_link( + &camss->csiphy[i].subdev.entity, + MSM_CSIPHY_PAD_SRC, + &camss->csid[j].subdev.entity, + MSM_CSID_PAD_SINK, + 0); + if (ret < 0) { + dev_err(camss->dev, + "Failed to link %s->%s entities: %d\n", + camss->csiphy[i].subdev.entity.name, + camss->csid[j].subdev.entity.name, + ret); + goto err_link; + } + } + } + + for (i = 0; i < ARRAY_SIZE(camss->csid); i++) { + for (j = 0; j < ARRAY_SIZE(camss->ispif.line); j++) { + ret = media_create_pad_link( + &camss->csid[i].subdev.entity, + MSM_CSID_PAD_SRC, + &camss->ispif.line[j].subdev.entity, + MSM_ISPIF_PAD_SINK, + 0); + if (ret < 0) { + dev_err(camss->dev, + "Failed to link %s->%s entities: %d\n", + camss->csid[i].subdev.entity.name, + camss->ispif.line[j].subdev.entity.name, + ret); + goto err_link; + } + } + } + + for (i = 0; i < ARRAY_SIZE(camss->ispif.line); i++) { + for (j = 0; j < ARRAY_SIZE(camss->vfe.line); j++) { + ret = media_create_pad_link( + &camss->ispif.line[i].subdev.entity, + MSM_ISPIF_PAD_SRC, + &camss->vfe.line[j].subdev.entity, + MSM_VFE_PAD_SINK, + 0); + if (ret < 0) { + dev_err(camss->dev, + "Failed to link %s->%s entities: %d\n", + camss->ispif.line[i].subdev.entity.name, + camss->vfe.line[j].subdev.entity.name, + ret); + goto err_link; + } + } + } + + return 0; + +err_link: + msm_vfe_unregister_entities(&camss->vfe); +err_reg_vfe: + msm_ispif_unregister_entities(&camss->ispif); +err_reg_ispif: + + i = ARRAY_SIZE(camss->csid); +err_reg_csid: + for (i--; i >= 0; i--) + msm_csid_unregister_entity(&camss->csid[i]); + + i = ARRAY_SIZE(camss->csiphy); +err_reg_csiphy: + for (i--; i >= 0; i--) + msm_csiphy_unregister_entity(&camss->csiphy[i]); + + return ret; +} + +/* + * camss_unregister_entities - Unregister subdev nodes + * @camss: CAMSS device + * + * Return 0 on success or a negative error code on failure + */ +static void camss_unregister_entities(struct camss *camss) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(camss->csiphy); i++) + msm_csiphy_unregister_entity(&camss->csiphy[i]); + + for (i = 0; i < ARRAY_SIZE(camss->csid); i++) + msm_csid_unregister_entity(&camss->csid[i]); + + msm_ispif_unregister_entities(&camss->ispif); + msm_vfe_unregister_entities(&camss->vfe); +} + +static int camss_subdev_notifier_bound(struct v4l2_async_notifier *async, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct camss *camss = container_of(async, struct camss, notifier); + struct camss_async_subdev *csd = + container_of(asd, struct camss_async_subdev, asd); + u8 id = csd->interface.csiphy_id; + struct csiphy_device *csiphy = &camss->csiphy[id]; + + csiphy->cfg.csi2 = &csd->interface.csi2; + subdev->host_priv = csiphy; + + return 0; +} + +static int camss_subdev_notifier_complete(struct v4l2_async_notifier *async) +{ + struct camss *camss = container_of(async, struct camss, notifier); + struct v4l2_device *v4l2_dev = &camss->v4l2_dev; + struct v4l2_subdev *sd; + int ret; + + list_for_each_entry(sd, &v4l2_dev->subdevs, list) { + if (sd->host_priv) { + struct media_entity *sensor = &sd->entity; + struct csiphy_device *csiphy = + (struct csiphy_device *) sd->host_priv; + struct media_entity *input = &csiphy->subdev.entity; + unsigned int i; + + for (i = 0; i < sensor->num_pads; i++) { + if (sensor->pads[i].flags & MEDIA_PAD_FL_SOURCE) + break; + } + if (i == sensor->num_pads) { + dev_err(camss->dev, + "No source pad in external entity\n"); + return -EINVAL; + } + + ret = media_create_pad_link(sensor, i, + input, MSM_CSIPHY_PAD_SINK, + MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); + if (ret < 0) { + dev_err(camss->dev, + "Failed to link %s->%s entities: %d\n", + sensor->name, input->name, ret); + return ret; + } + } + } + + ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev); + if (ret < 0) + return ret; + + return media_device_register(&camss->media_dev); +} + +static const struct media_device_ops camss_media_ops = { + .link_notify = v4l2_pipeline_link_notify, +}; + +/* + * camss_probe - Probe CAMSS platform device + * @pdev: Pointer to CAMSS platform device + * + * Return 0 on success or a negative error code on failure + */ +static int camss_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct camss *camss; + int ret; + + camss = kzalloc(sizeof(*camss), GFP_KERNEL); + if (!camss) + return -ENOMEM; + + atomic_set(&camss->ref_count, 0); + camss->dev = dev; + platform_set_drvdata(pdev, camss); + + ret = camss_of_parse_ports(dev, &camss->notifier); + if (ret < 0) + return ret; + + ret = camss_init_subdevices(camss); + if (ret < 0) + return ret; + + ret = dma_set_mask_and_coherent(dev, 0xffffffff); + if (ret) + return ret; + + camss->media_dev.dev = camss->dev; + strlcpy(camss->media_dev.model, "Qualcomm Camera Subsystem", + sizeof(camss->media_dev.model)); + camss->media_dev.ops = &camss_media_ops; + media_device_init(&camss->media_dev); + + camss->v4l2_dev.mdev = &camss->media_dev; + ret = v4l2_device_register(camss->dev, &camss->v4l2_dev); + if (ret < 0) { + dev_err(dev, "Failed to register V4L2 device: %d\n", ret); + return ret; + } + + ret = camss_register_entities(camss); + if (ret < 0) + goto err_register_entities; + + if (camss->notifier.num_subdevs) { + camss->notifier.bound = camss_subdev_notifier_bound; + camss->notifier.complete = camss_subdev_notifier_complete; + + ret = v4l2_async_notifier_register(&camss->v4l2_dev, + &camss->notifier); + if (ret) { + dev_err(dev, + "Failed to register async subdev nodes: %d\n", + ret); + goto err_register_subdevs; + } + } else { + ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev); + if (ret < 0) { + dev_err(dev, "Failed to register subdev nodes: %d\n", + ret); + goto err_register_subdevs; + } + + ret = media_device_register(&camss->media_dev); + if (ret < 0) { + dev_err(dev, "Failed to register media device: %d\n", + ret); + goto err_register_subdevs; + } + } + + return 0; + +err_register_subdevs: + camss_unregister_entities(camss); +err_register_entities: + v4l2_device_unregister(&camss->v4l2_dev); + + return ret; +} + +void camss_delete(struct camss *camss) +{ + v4l2_device_unregister(&camss->v4l2_dev); + media_device_unregister(&camss->media_dev); + media_device_cleanup(&camss->media_dev); + + kfree(camss); +} + +/* + * camss_remove - Remove CAMSS platform device + * @pdev: Pointer to CAMSS platform device + * + * Always returns 0. + */ +static int camss_remove(struct platform_device *pdev) +{ + struct camss *camss = platform_get_drvdata(pdev); + + msm_vfe_stop_streaming(&camss->vfe); + + v4l2_async_notifier_unregister(&camss->notifier); + camss_unregister_entities(camss); + + if (atomic_read(&camss->ref_count) == 0) + camss_delete(camss); + + return 0; +} + +static const struct of_device_id camss_dt_match[] = { + { .compatible = "qcom,msm8916-camss" }, + { } +}; + +MODULE_DEVICE_TABLE(of, camss_dt_match); + +static struct platform_driver qcom_camss_driver = { + .probe = camss_probe, + .remove = camss_remove, + .driver = { + .name = "qcom-camss", + .of_match_table = camss_dt_match, + }, +}; + +module_platform_driver(qcom_camss_driver); + +MODULE_ALIAS("platform:qcom-camss"); +MODULE_DESCRIPTION("Qualcomm Camera Subsystem driver"); +MODULE_AUTHOR("Todor Tomov <todor.tomov@linaro.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/qcom/camss-8x16/camss.h b/drivers/media/platform/qcom/camss-8x16/camss.h new file mode 100644 index 000000000000..4ad223443e4b --- /dev/null +++ b/drivers/media/platform/qcom/camss-8x16/camss.h @@ -0,0 +1,106 @@ +/* + * camss.h + * + * Qualcomm MSM Camera Subsystem - Core + * + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef QC_MSM_CAMSS_H +#define QC_MSM_CAMSS_H + +#include <linux/types.h> +#include <media/v4l2-async.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> +#include <media/media-device.h> +#include <media/media-entity.h> +#include <linux/device.h> + +#include "camss-csid.h" +#include "camss-csiphy.h" +#include "camss-ispif.h" +#include "camss-vfe.h" + +#define CAMSS_CSID_NUM 2 +#define CAMSS_CSIPHY_NUM 2 + +#define to_camss(ptr_module) \ + container_of(ptr_module, struct camss, ptr_module) + +#define to_device(ptr_module) \ + (to_camss(ptr_module)->dev) + +#define module_pointer(ptr_module, index) \ + ((const struct ptr_module##_device (*)[]) &(ptr_module[-(index)])) + +#define to_camss_index(ptr_module, index) \ + container_of(module_pointer(ptr_module, index), \ + struct camss, ptr_module) + +#define to_device_index(ptr_module, index) \ + (to_camss_index(ptr_module, index)->dev) + +#define CAMSS_RES_MAX 15 + +struct resources { + char *regulator[CAMSS_RES_MAX]; + char *clock[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; +}; + +struct camss { + struct v4l2_device v4l2_dev; + struct v4l2_async_notifier notifier; + struct media_device media_dev; + struct device *dev; + struct csiphy_device csiphy[CAMSS_CSIPHY_NUM]; + struct csid_device csid[CAMSS_CSID_NUM]; + struct ispif_device ispif; + struct vfe_device vfe; + atomic_t ref_count; +}; + +struct camss_camera_interface { + u8 csiphy_id; + struct csiphy_csi2_cfg csi2; +}; + +struct camss_async_subdev { + struct camss_camera_interface interface; + struct v4l2_async_subdev asd; +}; + +struct camss_clock { + struct clk *clk; + const char *name; + u32 *freq; + u32 nfreqs; +}; + +void camss_add_clock_margin(u64 *rate); +int camss_enable_clocks(int nclocks, struct camss_clock *clock, + struct device *dev); +void camss_disable_clocks(int nclocks, struct camss_clock *clock); +int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock); +void camss_delete(struct camss *camss); + +#endif /* QC_MSM_CAMSS_H */ diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 5f4434c0a8f1..68933d208063 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -34,6 +34,55 @@ struct intbuf { unsigned long attrs; }; +bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt) +{ + struct venus_core *core = inst->core; + u32 session_type = inst->session_type; + u32 codec; + + switch (v4l2_pixfmt) { + case V4L2_PIX_FMT_H264: + codec = HFI_VIDEO_CODEC_H264; + break; + case V4L2_PIX_FMT_H263: + codec = HFI_VIDEO_CODEC_H263; + break; + case V4L2_PIX_FMT_MPEG1: + codec = HFI_VIDEO_CODEC_MPEG1; + break; + case V4L2_PIX_FMT_MPEG2: + codec = HFI_VIDEO_CODEC_MPEG2; + break; + case V4L2_PIX_FMT_MPEG4: + codec = HFI_VIDEO_CODEC_MPEG4; + break; + case V4L2_PIX_FMT_VC1_ANNEX_G: + case V4L2_PIX_FMT_VC1_ANNEX_L: + codec = HFI_VIDEO_CODEC_VC1; + break; + case V4L2_PIX_FMT_VP8: + codec = HFI_VIDEO_CODEC_VP8; + break; + case V4L2_PIX_FMT_VP9: + codec = HFI_VIDEO_CODEC_VP9; + break; + case V4L2_PIX_FMT_XVID: + codec = HFI_VIDEO_CODEC_DIVX; + break; + default: + return false; + } + + if (session_type == VIDC_SESSION_TYPE_ENC && core->enc_codecs & codec) + return true; + + if (session_type == VIDC_SESSION_TYPE_DEC && core->dec_codecs & codec) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(venus_helper_check_codec); + static int intbufs_set_buffer(struct venus_inst *inst, u32 type) { struct venus_core *core = inst->core; @@ -243,7 +292,7 @@ static void return_buf_error(struct venus_inst *inst, if (vbuf->vb2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) v4l2_m2m_src_buf_remove_by_buf(m2m_ctx, vbuf); else - v4l2_m2m_src_buf_remove_by_buf(m2m_ctx, vbuf); + v4l2_m2m_dst_buf_remove_by_buf(m2m_ctx, vbuf); v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); } diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h index 6a061b417a93..971392be5df5 100644 --- a/drivers/media/platform/qcom/venus/helpers.h +++ b/drivers/media/platform/qcom/venus/helpers.h @@ -19,6 +19,7 @@ struct venus_inst; +bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt); struct vb2_v4l2_buffer *venus_helper_find_buf(struct venus_inst *inst, unsigned int type, u32 idx); void venus_helper_buffers_done(struct venus_inst *inst, diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index eb0c1c51cfef..da611a5eb670 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -102,7 +102,8 @@ static const struct venus_format vdec_formats[] = { }, }; -static const struct venus_format *find_format(u32 pixfmt, u32 type) +static const struct venus_format * +find_format(struct venus_inst *inst, u32 pixfmt, u32 type) { const struct venus_format *fmt = vdec_formats; unsigned int size = ARRAY_SIZE(vdec_formats); @@ -116,11 +117,15 @@ static const struct venus_format *find_format(u32 pixfmt, u32 type) if (i == size || fmt[i].type != type) return NULL; + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && + !venus_helper_check_codec(inst, fmt[i].pixfmt)) + return NULL; + return &fmt[i]; } static const struct venus_format * -find_format_by_index(unsigned int index, u32 type) +find_format_by_index(struct venus_inst *inst, unsigned int index, u32 type) { const struct venus_format *fmt = vdec_formats; unsigned int size = ARRAY_SIZE(vdec_formats); @@ -140,6 +145,10 @@ find_format_by_index(unsigned int index, u32 type) if (i == size) return NULL; + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && + !venus_helper_check_codec(inst, fmt[i].pixfmt)) + return NULL; + return &fmt[i]; } @@ -154,7 +163,7 @@ vdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved)); memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); - fmt = find_format(pixmp->pixelformat, f->type); + fmt = find_format(inst, pixmp->pixelformat, f->type); if (!fmt) { if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) pixmp->pixelformat = V4L2_PIX_FMT_NV12; @@ -162,7 +171,7 @@ vdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) pixmp->pixelformat = V4L2_PIX_FMT_H264; else return NULL; - fmt = find_format(pixmp->pixelformat, f->type); + fmt = find_format(inst, pixmp->pixelformat, f->type); pixmp->width = 1280; pixmp->height = 720; } @@ -364,11 +373,12 @@ vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) { + struct venus_inst *inst = to_inst(file); const struct venus_format *fmt; memset(f->reserved, 0, sizeof(f->reserved)); - fmt = find_format_by_index(f->index, f->type); + fmt = find_format_by_index(inst, f->index, f->type); if (!fmt) return -EINVAL; @@ -417,10 +427,10 @@ static int vdec_enum_framesizes(struct file *file, void *fh, struct venus_inst *inst = to_inst(file); const struct venus_format *fmt; - fmt = find_format(fsize->pixel_format, + fmt = find_format(inst, fsize->pixel_format, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); if (!fmt) { - fmt = find_format(fsize->pixel_format, + fmt = find_format(inst, fsize->pixel_format, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); if (!fmt) return -EINVAL; @@ -1069,6 +1079,7 @@ static int vdec_probe(struct platform_device *pdev) if (!vdev) return -ENOMEM; + strlcpy(vdev->name, "qcom-venus-decoder", sizeof(vdev->name)); vdev->release = video_device_release; vdev->fops = &vdec_fops; vdev->ioctl_ops = &vdec_ioctl_ops; @@ -1103,8 +1114,7 @@ static int vdec_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int vdec_runtime_suspend(struct device *dev) +static __maybe_unused int vdec_runtime_suspend(struct device *dev) { struct venus_core *core = dev_get_drvdata(dev); @@ -1118,7 +1128,7 @@ static int vdec_runtime_suspend(struct device *dev) return 0; } -static int vdec_runtime_resume(struct device *dev) +static __maybe_unused int vdec_runtime_resume(struct device *dev) { struct venus_core *core = dev_get_drvdata(dev); int ret; @@ -1132,7 +1142,6 @@ static int vdec_runtime_resume(struct device *dev) return ret; } -#endif static const struct dev_pm_ops vdec_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 39748e7a08e4..6f123a387cf9 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -84,14 +84,11 @@ static const struct venus_format venc_formats[] = { .pixfmt = V4L2_PIX_FMT_VP8, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, - }, { - .pixfmt = V4L2_PIX_FMT_VP9, - .num_planes = 1, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, }, }; -static const struct venus_format *find_format(u32 pixfmt, u32 type) +static const struct venus_format * +find_format(struct venus_inst *inst, u32 pixfmt, u32 type) { const struct venus_format *fmt = venc_formats; unsigned int size = ARRAY_SIZE(venc_formats); @@ -105,11 +102,15 @@ static const struct venus_format *find_format(u32 pixfmt, u32 type) if (i == size || fmt[i].type != type) return NULL; + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + !venus_helper_check_codec(inst, fmt[i].pixfmt)) + return NULL; + return &fmt[i]; } static const struct venus_format * -find_format_by_index(unsigned int index, u32 type) +find_format_by_index(struct venus_inst *inst, unsigned int index, u32 type) { const struct venus_format *fmt = venc_formats; unsigned int size = ARRAY_SIZE(venc_formats); @@ -129,6 +130,10 @@ find_format_by_index(unsigned int index, u32 type) if (i == size) return NULL; + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + !venus_helper_check_codec(inst, fmt[i].pixfmt)) + return NULL; + return &fmt[i]; } @@ -246,9 +251,10 @@ venc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) static int venc_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) { + struct venus_inst *inst = to_inst(file); const struct venus_format *fmt; - fmt = find_format_by_index(f->index, f->type); + fmt = find_format_by_index(inst, f->index, f->type); memset(f->reserved, 0, sizeof(f->reserved)); @@ -271,7 +277,7 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved)); memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); - fmt = find_format(pixmp->pixelformat, f->type); + fmt = find_format(inst, pixmp->pixelformat, f->type); if (!fmt) { if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) pixmp->pixelformat = V4L2_PIX_FMT_H264; @@ -279,7 +285,7 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) pixmp->pixelformat = V4L2_PIX_FMT_NV12; else return NULL; - fmt = find_format(pixmp->pixelformat, f->type); + fmt = find_format(inst, pixmp->pixelformat, f->type); pixmp->width = 1280; pixmp->height = 720; } @@ -289,7 +295,7 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) pixmp->height = clamp(pixmp->height, inst->cap_height.min, inst->cap_height.max); - if (inst->core->res->hfi_version == HFI_VERSION_1XX) + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) pixmp->height = ALIGN(pixmp->height, 32); pixmp->width = ALIGN(pixmp->width, 2); @@ -524,10 +530,10 @@ static int venc_enum_framesizes(struct file *file, void *fh, fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fmt = find_format(fsize->pixel_format, + fmt = find_format(inst, fsize->pixel_format, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); if (!fmt) { - fmt = find_format(fsize->pixel_format, + fmt = find_format(inst, fsize->pixel_format, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); if (!fmt) return -EINVAL; @@ -554,10 +560,10 @@ static int venc_enum_frameintervals(struct file *file, void *fh, fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; - fmt = find_format(fival->pixel_format, + fmt = find_format(inst, fival->pixel_format, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); if (!fmt) { - fmt = find_format(fival->pixel_format, + fmt = find_format(inst, fival->pixel_format, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); if (!fmt) return -EINVAL; @@ -747,8 +753,8 @@ static int venc_init_session(struct venus_inst *inst) if (ret) return ret; - ret = venus_helper_set_input_resolution(inst, inst->out_width, - inst->out_height); + ret = venus_helper_set_input_resolution(inst, inst->width, + inst->height); if (ret) goto deinit; @@ -1010,6 +1016,8 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->allow_zero_bytesused = 1; src_vq->min_buffers_needed = 1; src_vq->dev = inst->core->dev; + if (inst->core->res->hfi_version == HFI_VERSION_1XX) + src_vq->bidirectional = 1; ret = vb2_queue_init(src_vq); if (ret) return ret; @@ -1190,6 +1198,7 @@ static int venc_probe(struct platform_device *pdev) if (!vdev) return -ENOMEM; + strlcpy(vdev->name, "qcom-venus-encoder", sizeof(vdev->name)); vdev->release = video_device_release; vdev->fops = &venc_fops; vdev->ioctl_ops = &venc_ioctl_ops; @@ -1224,8 +1233,7 @@ static int venc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int venc_runtime_suspend(struct device *dev) +static __maybe_unused int venc_runtime_suspend(struct device *dev) { struct venus_core *core = dev_get_drvdata(dev); @@ -1239,7 +1247,7 @@ static int venc_runtime_suspend(struct device *dev) return 0; } -static int venc_runtime_resume(struct device *dev) +static __maybe_unused int venc_runtime_resume(struct device *dev) { struct venus_core *core = dev_get_drvdata(dev); int ret; @@ -1253,7 +1261,6 @@ static int venc_runtime_resume(struct device *dev) return ret; } -#endif static const struct dev_pm_ops venc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 77dff047c41c..142de447aaaa 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -222,8 +222,8 @@ static int rvin_digital_graph_init(struct rvin_dev *vin) subdevs[0] = &vin->digital.asd; - vin_dbg(vin, "Found digital subdevice %s\n", - of_node_full_name(to_of_node(subdevs[0]->match.fwnode.fwnode))); + vin_dbg(vin, "Found digital subdevice %pOF\n", + to_of_node(subdevs[0]->match.fwnode.fwnode)); vin->notifier.num_subdevs = 1; vin->notifier.subdevs = subdevs; diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c index 3ee51fc3bb50..3245bc45f4a0 100644 --- a/drivers/media/platform/rcar_fdp1.c +++ b/drivers/media/platform/rcar_fdp1.c @@ -2032,7 +2032,7 @@ static void fdp1_stop_streaming(struct vb2_queue *q) } } -static struct vb2_ops fdp1_qops = { +static const struct vb2_ops fdp1_qops = { .queue_setup = fdp1_queue_setup, .buf_prepare = fdp1_buf_prepare, .buf_queue = fdp1_buf_queue, diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c index d1746ecc645d..070bac36d766 100644 --- a/drivers/media/platform/rcar_jpu.c +++ b/drivers/media/platform/rcar_jpu.c @@ -1506,7 +1506,7 @@ static void jpu_job_abort(void *priv) jpu_cleanup(ctx, true); } -static struct v4l2_m2m_ops jpu_m2m_ops = { +static const struct v4l2_m2m_ops jpu_m2m_ops = { .device_run = jpu_device_run, .job_ready = jpu_job_ready, .job_abort = jpu_job_abort, diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c index ec4001970313..c4ab63986c8f 100644 --- a/drivers/media/platform/s3c-camif/camif-core.c +++ b/drivers/media/platform/s3c-camif/camif-core.c @@ -317,7 +317,6 @@ static int camif_media_dev_init(struct camif_dev *camif) ip_rev == S3C6410_CAMIF_IP_REV ? "6410" : "244X"); strlcpy(md->bus_info, "platform", sizeof(md->bus_info)); md->hw_revision = ip_rev; - md->driver_version = KERNEL_VERSION(1, 0, 0); md->dev = camif->dev; diff --git a/drivers/media/platform/s5p-cec/s5p_cec.c b/drivers/media/platform/s5p-cec/s5p_cec.c index 8e06071a7977..58d200e7c838 100644 --- a/drivers/media/platform/s5p-cec/s5p_cec.c +++ b/drivers/media/platform/s5p-cec/s5p_cec.c @@ -219,11 +219,8 @@ static int s5p_cec_probe(struct platform_device *pdev) if (cec->notifier == NULL) return -ENOMEM; - cec->adap = cec_allocate_adapter(&s5p_cec_adap_ops, cec, - CEC_NAME, - CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | - CEC_CAP_PASSTHROUGH | CEC_CAP_RC | - (needs_hpd ? CEC_CAP_NEEDS_HPD : 0), 1); + cec->adap = cec_allocate_adapter(&s5p_cec_adap_ops, cec, CEC_NAME, + CEC_CAP_DEFAULTS | (needs_hpd ? CEC_CAP_NEEDS_HPD : 0), 1); ret = PTR_ERR_OR_ZERO(cec->adap); if (ret) return ret; diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 81ed5cd5cd5d..66aa8cf1d048 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -602,7 +602,7 @@ static const struct v4l2_ioctl_ops g2d_ioctl_ops = { .vidioc_cropcap = vidioc_cropcap, }; -static struct video_device g2d_videodev = { +static const struct video_device g2d_videodev = { .name = G2D_NAME, .fops = &g2d_fops, .ioctl_ops = &g2d_ioctl_ops, @@ -611,7 +611,7 @@ static struct video_device g2d_videodev = { .vfl_dir = VFL_DIR_M2M, }; -static struct v4l2_m2m_ops g2d_m2m_ops = { +static const struct v4l2_m2m_ops g2d_m2m_ops = { .device_run = device_run, .job_abort = job_abort, }; diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index d1e3ebb22577..faac8161b683 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -24,6 +24,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/string.h> +#include <media/v4l2-event.h> #include <media/v4l2-mem2mem.h> #include <media/v4l2-ioctl.h> #include <media/videobuf2-v4l2.h> @@ -614,24 +615,27 @@ static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh) static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx) { - WARN_ON(ctx->subsampling > 3); - switch (ctx->jpeg->variant->version) { case SJPEG_S5P: + WARN_ON(ctx->subsampling > 3); if (ctx->subsampling > 2) return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; return ctx->subsampling; case SJPEG_EXYNOS3250: case SJPEG_EXYNOS5420: + WARN_ON(ctx->subsampling > 6); if (ctx->subsampling > 3) return V4L2_JPEG_CHROMA_SUBSAMPLING_411; return exynos3250_decoded_subsampling[ctx->subsampling]; case SJPEG_EXYNOS4: - case SJPEG_EXYNOS5433: + WARN_ON(ctx->subsampling > 3); if (ctx->subsampling > 2) return V4L2_JPEG_CHROMA_SUBSAMPLING_420; return exynos4x12_decoded_subsampling[ctx->subsampling]; + case SJPEG_EXYNOS5433: + return ctx->subsampling; /* parsed from header */ default: + WARN_ON(ctx->subsampling > 3); return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; } } @@ -1094,6 +1098,44 @@ static void skip(struct s5p_jpeg_buffer *buf, long len) get_byte(buf); } +static bool s5p_jpeg_subsampling_decode(struct s5p_jpeg_ctx *ctx, + unsigned int subsampling) +{ + unsigned int version; + + switch (subsampling) { + case 0x11: + ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444; + break; + case 0x21: + ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422; + break; + case 0x22: + ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420; + break; + case 0x33: + ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; + break; + case 0x41: + /* + * 4:1:1 subsampling only supported by 3250, 5420, and 5433 + * variants + */ + version = ctx->jpeg->variant->version; + if (version != SJPEG_EXYNOS3250 && + version != SJPEG_EXYNOS5420 && + version != SJPEG_EXYNOS5433) + return false; + + ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_411; + break; + default: + return false; + } + + return true; +} + static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, unsigned long buffer, unsigned long size, struct s5p_jpeg_ctx *ctx) @@ -1204,6 +1246,10 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, break; } } + + if (notfound || !sos || !s5p_jpeg_subsampling_decode(ctx, subsampling)) + return false; + result->w = width; result->h = height; result->sos = sos; @@ -1219,26 +1265,9 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, } result->sof = sof; result->sof_len = sof_len; - result->size = result->components = components; - - switch (subsampling) { - case 0x11: - ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444; - break; - case 0x21: - ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422; - break; - case 0x22: - ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420; - break; - case 0x33: - ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; - break; - default: - return false; - } + result->components = components; - return !notfound && sos; + return true; } static int s5p_jpeg_querycap(struct file *file, void *priv, @@ -1606,8 +1635,12 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f) FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE; q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type); - q_data->w = pix->width; - q_data->h = pix->height; + if (ct->mode == S5P_JPEG_ENCODE || + (ct->mode == S5P_JPEG_DECODE && + q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)) { + q_data->w = pix->width; + q_data->h = pix->height; + } if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) { /* * During encoding Exynos4x12 SoCs access wider memory area @@ -1690,6 +1723,15 @@ static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); } +static int s5p_jpeg_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + if (sub->type == V4L2_EVENT_SOURCE_CHANGE) + return v4l2_src_change_event_subscribe(fh, sub); + + return -EINVAL; +} + static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx, struct v4l2_rect *r) { @@ -2015,6 +2057,9 @@ static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = { .vidioc_g_selection = s5p_jpeg_g_selection, .vidioc_s_selection = s5p_jpeg_s_selection, + + .vidioc_subscribe_event = s5p_jpeg_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; /* @@ -2259,6 +2304,7 @@ static void exynos4_jpeg_device_run(void *priv) exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size); } + exynos4_jpeg_set_sys_int_enable(jpeg->regs, 1); exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode); spin_unlock_irqrestore(&jpeg->slock, flags); @@ -2407,8 +2453,17 @@ static int s5p_jpeg_job_ready(void *priv) { struct s5p_jpeg_ctx *ctx = priv; - if (ctx->mode == S5P_JPEG_DECODE) + if (ctx->mode == S5P_JPEG_DECODE) { + /* + * We have only one input buffer and one output buffer. If there + * is a resolution change event, no need to continue decoding. + */ + if (ctx->state == JPEGCTX_RESOLUTION_CHANGE) + return 0; + return ctx->hdr_parsed; + } + return 1; } @@ -2487,6 +2542,30 @@ static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb) return 0; } +static void s5p_jpeg_set_capture_queue_data(struct s5p_jpeg_ctx *ctx) +{ + struct s5p_jpeg_q_data *q_data = &ctx->cap_q; + + q_data->w = ctx->out_q.w; + q_data->h = ctx->out_q.h; + + /* + * This call to jpeg_bound_align_image() takes care of width and + * height values alignment when user space calls the QBUF of + * OUTPUT buffer after the S_FMT of CAPTURE buffer. + * Please note that on Exynos4x12 SoCs, resigning from executing + * S_FMT on capture buffer for each JPEG image can result in a + * hardware hangup if subsampling is lower than the one of input + * JPEG. + */ + jpeg_bound_align_image(ctx, &q_data->w, S5P_JPEG_MIN_WIDTH, + S5P_JPEG_MAX_WIDTH, q_data->fmt->h_align, + &q_data->h, S5P_JPEG_MIN_HEIGHT, + S5P_JPEG_MAX_HEIGHT, q_data->fmt->v_align); + + q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3; +} + static void s5p_jpeg_buf_queue(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -2494,9 +2573,20 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb) if (ctx->mode == S5P_JPEG_DECODE && vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - struct s5p_jpeg_q_data tmp, *q_data; - - ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp, + static const struct v4l2_event ev_src_ch = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + struct vb2_queue *dst_vq; + u32 ori_w; + u32 ori_h; + + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + ori_w = ctx->out_q.w; + ori_h = ctx->out_q.h; + + ctx->hdr_parsed = s5p_jpeg_parse_hdr(&ctx->out_q, (unsigned long)vb2_plane_vaddr(vb, 0), min((unsigned long)ctx->out_q.size, vb2_get_plane_payload(vb, 0)), ctx); @@ -2505,24 +2595,18 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb) return; } - q_data = &ctx->out_q; - q_data->w = tmp.w; - q_data->h = tmp.h; - q_data->sos = tmp.sos; - memcpy(q_data->dht.marker, tmp.dht.marker, - sizeof(tmp.dht.marker)); - memcpy(q_data->dht.len, tmp.dht.len, sizeof(tmp.dht.len)); - q_data->dht.n = tmp.dht.n; - memcpy(q_data->dqt.marker, tmp.dqt.marker, - sizeof(tmp.dqt.marker)); - memcpy(q_data->dqt.len, tmp.dqt.len, sizeof(tmp.dqt.len)); - q_data->dqt.n = tmp.dqt.n; - q_data->sof = tmp.sof; - q_data->sof_len = tmp.sof_len; - - q_data = &ctx->cap_q; - q_data->w = tmp.w; - q_data->h = tmp.h; + /* + * If there is a resolution change event, only update capture + * queue when it is not streaming. Otherwise, update it in + * STREAMOFF. See s5p_jpeg_stop_streaming for detail. + */ + if (ctx->out_q.w != ori_w || ctx->out_q.h != ori_h) { + v4l2_event_queue_fh(&ctx->fh, &ev_src_ch); + if (vb2_is_streaming(dst_vq)) + ctx->state = JPEGCTX_RESOLUTION_CHANGE; + else + s5p_jpeg_set_capture_queue_data(ctx); + } } v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); @@ -2542,6 +2626,17 @@ static void s5p_jpeg_stop_streaming(struct vb2_queue *q) { struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q); + /* + * STREAMOFF is an acknowledgment for resolution change event. + * Before STREAMOFF, we still have to return the old resolution and + * subsampling. Update capture queue when the stream is off. + */ + if (ctx->state == JPEGCTX_RESOLUTION_CHANGE && + q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + s5p_jpeg_set_capture_queue_data(ctx); + ctx->state = JPEGCTX_RUNNING; + } + pm_runtime_put(ctx->jpeg->dev); } @@ -2662,6 +2757,8 @@ static irqreturn_t exynos4_jpeg_irq(int irq, void *priv) spin_lock(&jpeg->slock); + exynos4_jpeg_set_sys_int_enable(jpeg->regs, 0); + curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); @@ -2710,6 +2807,8 @@ static irqreturn_t exynos4_jpeg_irq(int irq, void *priv) if (jpeg->variant->version == SJPEG_EXYNOS4) curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs); + exynos4_jpeg_set_enc_dec_mode(jpeg->regs, S5P_JPEG_DISABLE); + spin_unlock(&jpeg->slock); v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx); @@ -2724,6 +2823,7 @@ static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id) unsigned long payload_size = 0; enum vb2_buffer_state state = VB2_BUF_STATE_DONE; bool interrupt_timeout = false; + bool stream_error = false; u32 irq_status; spin_lock(&jpeg->slock); @@ -2740,6 +2840,12 @@ static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id) jpeg->irq_status |= irq_status; + if (jpeg->variant->version == SJPEG_EXYNOS5420 && + irq_status & EXYNOS3250_STREAM_STAT) { + stream_error = true; + dev_err(jpeg->dev, "Syntax error or unrecoverable error occurred.\n"); + } + curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); if (!curr_ctx) @@ -2756,7 +2862,7 @@ static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id) EXYNOS3250_RDMA_DONE | EXYNOS3250_RESULT_STAT)) payload_size = exynos3250_jpeg_compressed_size(jpeg->regs); - else if (interrupt_timeout) + else if (interrupt_timeout || stream_error) state = VB2_BUF_STATE_ERROR; else goto exit_unlock; diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h index 4492a3535df5..a46465e10351 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h @@ -63,6 +63,7 @@ #define S5P_JPEG_ENCODE 0 #define S5P_JPEG_DECODE 1 +#define S5P_JPEG_DISABLE -1 #define FMT_TYPE_OUTPUT 0 #define FMT_TYPE_CAPTURE 1 @@ -98,6 +99,11 @@ enum exynos4_jpeg_img_quality_level { QUALITY_LEVEL_4, /* low */ }; +enum s5p_jpeg_ctx_state { + JPEGCTX_RUNNING = 0, + JPEGCTX_RESOLUTION_CHANGE, +}; + /** * struct s5p_jpeg - JPEG IP abstraction * @lock: the mutex protecting this structure @@ -220,6 +226,7 @@ struct s5p_jpeg_q_data { * @hdr_parsed: set if header has been parsed during decompression * @crop_altered: set if crop rectangle has been altered by the user space * @ctrl_handler: controls handler + * @state: state of the context */ struct s5p_jpeg_ctx { struct s5p_jpeg *jpeg; @@ -235,6 +242,7 @@ struct s5p_jpeg_ctx { bool hdr_parsed; bool crop_altered; struct v4l2_ctrl_handler ctrl_handler; + enum s5p_jpeg_ctx_state state; }; /** diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c index a1d823ab0c63..c72789bae6ed 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c @@ -21,6 +21,10 @@ void exynos4_jpeg_sw_reset(void __iomem *base) unsigned int reg; reg = readl(base + EXYNOS4_JPEG_CNTL_REG); + writel(reg & ~(EXYNOS4_DEC_MODE | EXYNOS4_ENC_MODE), + base + EXYNOS4_JPEG_CNTL_REG); + + reg = readl(base + EXYNOS4_JPEG_CNTL_REG); writel(reg & ~EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG); udelay(100); @@ -38,10 +42,13 @@ void exynos4_jpeg_set_enc_dec_mode(void __iomem *base, unsigned int mode) writel((reg & EXYNOS4_ENC_DEC_MODE_MASK) | EXYNOS4_DEC_MODE, base + EXYNOS4_JPEG_CNTL_REG); - } else {/* encode */ + } else if (mode == S5P_JPEG_ENCODE) {/* encode */ writel((reg & EXYNOS4_ENC_DEC_MODE_MASK) | EXYNOS4_ENC_MODE, base + EXYNOS4_JPEG_CNTL_REG); + } else { /* disable both */ + writel(reg & EXYNOS4_ENC_DEC_MODE_MASK, + base + EXYNOS4_JPEG_CNTL_REG); } } diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h index 1870400468b2..df790b10140c 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-regs.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h @@ -371,7 +371,7 @@ #define EXYNOS4_NF_SHIFT 16 #define EXYNOS4_NF_MASK 0xff #define EXYNOS4_NF(x) \ - (((x) << EXYNOS4_NF_SHIFT) & EXYNOS4_NF_MASK) + (((x) & EXYNOS4_NF_MASK) << EXYNOS4_NF_SHIFT) /* JPEG quantizer table register */ #define EXYNOS4_QTBL_CONTENT(n) (0x100 + (n) * 0x40) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 45a0429d75bb..1f3c450c7a69 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -820,7 +820,7 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt) return res; } -static struct v4l2_file_operations soc_camera_fops = { +static const struct v4l2_file_operations soc_camera_fops = { .owner = THIS_MODULE, .open = soc_camera_open, .release = soc_camera_close, @@ -1550,8 +1550,7 @@ static int soc_of_bind(struct soc_camera_host *ici, v4l2_clk_name_i2c(clk_name, sizeof(clk_name), client->adapter->nr, client->addr); else - v4l2_clk_name_of(clk_name, sizeof(clk_name), - of_node_full_name(remote)); + v4l2_clk_name_of(clk_name, sizeof(clk_name), remote); icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { @@ -1590,8 +1589,7 @@ static void scan_of_host(struct soc_camera_host *ici) ren = of_graph_get_remote_port(epn); if (!ren) { - dev_notice(dev, "no remote for %s\n", - of_node_full_name(epn)); + dev_notice(dev, "no remote for %pOF\n", epn); continue; } diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c index 57581f626f4c..0ad4b28266e4 100644 --- a/drivers/media/platform/soc_camera/soc_mediabus.c +++ b/drivers/media/platform/soc_camera/soc_mediabus.c @@ -508,6 +508,9 @@ unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg, mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK); return (!mipi_lanes || !mipi_clock) ? 0 : common_flags; + default: + WARN_ON(1); + return -EINVAL; } return 0; } diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index 7918b928f058..939da6da7644 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -360,7 +360,7 @@ out: bdisp_job_finish(ctx, VB2_BUF_STATE_ERROR); } -static struct v4l2_m2m_ops bdisp_m2m_ops = { +static const struct v4l2_m2m_ops bdisp_m2m_ops = { .device_run = bdisp_device_run, .job_abort = bdisp_job_abort, }; diff --git a/drivers/media/platform/sti/cec/stih-cec.c b/drivers/media/platform/sti/cec/stih-cec.c index dccbdaebb7a8..70160df36de9 100644 --- a/drivers/media/platform/sti/cec/stih-cec.c +++ b/drivers/media/platform/sti/cec/stih-cec.c @@ -351,9 +351,7 @@ static int stih_cec_probe(struct platform_device *pdev) } cec->adap = cec_allocate_adapter(&sti_cec_adap_ops, cec, - CEC_NAME, - CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | - CEC_CAP_TRANSMIT, CEC_MAX_LOG_ADDRS); + CEC_NAME, CEC_CAP_DEFAULTS, CEC_MAX_LOG_ADDRS); ret = PTR_ERR_OR_ZERO(cec->adap); if (ret) return ret; diff --git a/drivers/media/platform/sti/delta/delta-v4l2.c b/drivers/media/platform/sti/delta/delta-v4l2.c index c6f2e244b7a8..b2dc3d223a9c 100644 --- a/drivers/media/platform/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/sti/delta/delta-v4l2.c @@ -1095,7 +1095,7 @@ static int delta_job_ready(void *priv) } /* mem-to-mem ops */ -static struct v4l2_m2m_ops delta_m2m_ops = { +static const struct v4l2_m2m_ops delta_m2m_ops = { .device_run = delta_device_run, .job_ready = delta_job_ready, .job_abort = delta_job_abort, @@ -1574,7 +1574,7 @@ static void delta_vb2_frame_stop_streaming(struct vb2_queue *q) } /* VB2 queue ops */ -static struct vb2_ops delta_vb2_au_ops = { +static const struct vb2_ops delta_vb2_au_ops = { .queue_setup = delta_vb2_au_queue_setup, .buf_prepare = delta_vb2_au_prepare, .buf_queue = delta_vb2_au_queue, @@ -1584,7 +1584,7 @@ static struct vb2_ops delta_vb2_au_ops = { .stop_streaming = delta_vb2_au_stop_streaming, }; -static struct vb2_ops delta_vb2_frame_ops = { +static const struct vb2_ops delta_vb2_frame_ops = { .queue_setup = delta_vb2_frame_queue_setup, .buf_prepare = delta_vb2_frame_prepare, .buf_finish = delta_vb2_frame_finish, diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c index 9ab896b01ee8..0e5aa17bdd40 100644 --- a/drivers/media/platform/stm32/stm32-cec.c +++ b/drivers/media/platform/stm32/stm32-cec.c @@ -246,9 +246,7 @@ static const struct regmap_config stm32_cec_regmap_cfg = { static int stm32_cec_probe(struct platform_device *pdev) { - u32 caps = CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | - CEC_CAP_TRANSMIT | CEC_CAP_RC | CEC_CAP_PHYS_ADDR | - CEC_MODE_MONITOR_ALL; + u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | CEC_MODE_MONITOR_ALL; struct resource *res; struct stm32_cec *cec; void __iomem *mmio; diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 83d32a5d0f40..35ba6f211b79 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -33,6 +33,7 @@ #include <media/v4l2-fwnode.h> #include <media/v4l2-image-sizes.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-rect.h> #include <media/videobuf2-dma-contig.h> #define DRV_NAME "stm32-dcmi" @@ -107,6 +108,11 @@ struct dcmi_format { u8 bpp; }; +struct dcmi_framesize { + u32 width; + u32 height; +}; + struct dcmi_buf { struct vb2_v4l2_buffer vb; bool prepared; @@ -131,10 +137,16 @@ struct stm32_dcmi { struct v4l2_async_notifier notifier; struct dcmi_graph_entity entity; struct v4l2_format fmt; + struct v4l2_rect crop; + bool do_crop; - const struct dcmi_format **user_formats; - unsigned int num_user_formats; - const struct dcmi_format *current_fmt; + const struct dcmi_format **sd_formats; + unsigned int num_of_sd_formats; + const struct dcmi_format *sd_format; + struct dcmi_framesize *sd_framesizes; + unsigned int num_of_sd_framesizes; + struct dcmi_framesize sd_framesize; + struct v4l2_rect sd_bounds; /* Protect this data structure */ struct mutex lock; @@ -295,6 +307,10 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, /* Push current DMA transaction in the pending queue */ dcmi->dma_cookie = dmaengine_submit(desc); + if (dma_submit_error(dcmi->dma_cookie)) { + dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__); + return -ENXIO; + } dma_async_issue_pending(dcmi->dma_chan); @@ -321,6 +337,28 @@ static int dcmi_start_capture(struct stm32_dcmi *dcmi) return 0; } +static void dcmi_set_crop(struct stm32_dcmi *dcmi) +{ + u32 size, start; + + /* Crop resolution */ + size = ((dcmi->crop.height - 1) << 16) | + ((dcmi->crop.width << 1) - 1); + reg_write(dcmi->regs, DCMI_CWSIZE, size); + + /* Crop start point */ + start = ((dcmi->crop.top) << 16) | + ((dcmi->crop.left << 1)); + reg_write(dcmi->regs, DCMI_CWSTRT, start); + + dev_dbg(dcmi->dev, "Cropping to %ux%u@%u:%u\n", + dcmi->crop.width, dcmi->crop.height, + dcmi->crop.left, dcmi->crop.top); + + /* Enable crop */ + reg_set(dcmi->regs, DCMI_CR, CR_CROP); +} + static irqreturn_t dcmi_irq_thread(int irq, void *arg) { struct stm32_dcmi *dcmi = arg; @@ -486,7 +524,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) { struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq); struct dcmi_buf *buf, *node; - u32 val; + u32 val = 0; int ret; ret = clk_enable(dcmi->mclk); @@ -506,22 +544,16 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) spin_lock_irq(&dcmi->irqlock); - val = reg_read(dcmi->regs, DCMI_CR); - - val &= ~(CR_PCKPOL | CR_HSPOL | CR_VSPOL | - CR_EDM_0 | CR_EDM_1 | CR_FCRC_0 | - CR_FCRC_1 | CR_JPEG | CR_ESS); - /* Set bus width */ switch (dcmi->bus.bus_width) { case 14: - val &= CR_EDM_0 + CR_EDM_1; + val |= CR_EDM_0 | CR_EDM_1; break; case 12: - val &= CR_EDM_1; + val |= CR_EDM_1; break; case 10: - val &= CR_EDM_0; + val |= CR_EDM_0; break; default: /* Set bus width to 8 bits by default */ @@ -542,6 +574,10 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) reg_write(dcmi->regs, DCMI_CR, val); + /* Set crop */ + if (dcmi->do_crop) + dcmi_set_crop(dcmi); + /* Enable dcmi */ reg_set(dcmi->regs, DCMI_CR, CR_ENABLE); @@ -662,7 +698,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) dcmi->errors_count, dcmi->buffers_count); } -static struct vb2_ops dcmi_video_qops = { +static const struct vb2_ops dcmi_video_qops = { .queue_setup = dcmi_queue_setup, .buf_init = dcmi_buf_init, .buf_prepare = dcmi_buf_prepare, @@ -686,12 +722,12 @@ static int dcmi_g_fmt_vid_cap(struct file *file, void *priv, static const struct dcmi_format *find_format_by_fourcc(struct stm32_dcmi *dcmi, unsigned int fourcc) { - unsigned int num_formats = dcmi->num_user_formats; + unsigned int num_formats = dcmi->num_of_sd_formats; const struct dcmi_format *fmt; unsigned int i; for (i = 0; i < num_formats; i++) { - fmt = dcmi->user_formats[i]; + fmt = dcmi->sd_formats[i]; if (fmt->fourcc == fourcc) return fmt; } @@ -699,41 +735,108 @@ static const struct dcmi_format *find_format_by_fourcc(struct stm32_dcmi *dcmi, return NULL; } +static void __find_outer_frame_size(struct stm32_dcmi *dcmi, + struct v4l2_pix_format *pix, + struct dcmi_framesize *framesize) +{ + struct dcmi_framesize *match = NULL; + unsigned int i; + unsigned int min_err = UINT_MAX; + + for (i = 0; i < dcmi->num_of_sd_framesizes; i++) { + struct dcmi_framesize *fsize = &dcmi->sd_framesizes[i]; + int w_err = (fsize->width - pix->width); + int h_err = (fsize->height - pix->height); + int err = w_err + h_err; + + if ((w_err >= 0) && (h_err >= 0) && (err < min_err)) { + min_err = err; + match = fsize; + } + } + if (!match) + match = &dcmi->sd_framesizes[0]; + + *framesize = *match; +} + static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, - const struct dcmi_format **current_fmt) + const struct dcmi_format **sd_format, + struct dcmi_framesize *sd_framesize) { - const struct dcmi_format *dcmi_fmt; - struct v4l2_pix_format *pixfmt = &f->fmt.pix; + const struct dcmi_format *sd_fmt; + struct dcmi_framesize sd_fsize; + struct v4l2_pix_format *pix = &f->fmt.pix; struct v4l2_subdev_pad_config pad_cfg; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; int ret; - dcmi_fmt = find_format_by_fourcc(dcmi, pixfmt->pixelformat); - if (!dcmi_fmt) { - dcmi_fmt = dcmi->user_formats[dcmi->num_user_formats - 1]; - pixfmt->pixelformat = dcmi_fmt->fourcc; + sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat); + if (!sd_fmt) { + sd_fmt = dcmi->sd_formats[dcmi->num_of_sd_formats - 1]; + pix->pixelformat = sd_fmt->fourcc; } /* Limit to hardware capabilities */ - pixfmt->width = clamp(pixfmt->width, MIN_WIDTH, MAX_WIDTH); - pixfmt->height = clamp(pixfmt->height, MIN_HEIGHT, MAX_HEIGHT); + pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH); + pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT); - v4l2_fill_mbus_format(&format.format, pixfmt, dcmi_fmt->mbus_code); + if (dcmi->do_crop && dcmi->num_of_sd_framesizes) { + struct dcmi_framesize outer_sd_fsize; + /* + * If crop is requested and sensor have discrete frame sizes, + * select the frame size that is just larger than request + */ + __find_outer_frame_size(dcmi, pix, &outer_sd_fsize); + pix->width = outer_sd_fsize.width; + pix->height = outer_sd_fsize.height; + } + + v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; - v4l2_fill_pix_format(pixfmt, &format.format); + /* Update pix regarding to what sensor can do */ + v4l2_fill_pix_format(pix, &format.format); + + /* Save resolution that sensor can actually do */ + sd_fsize.width = pix->width; + sd_fsize.height = pix->height; - pixfmt->field = V4L2_FIELD_NONE; - pixfmt->bytesperline = pixfmt->width * dcmi_fmt->bpp; - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; + if (dcmi->do_crop) { + struct v4l2_rect c = dcmi->crop; + struct v4l2_rect max_rect; - if (current_fmt) - *current_fmt = dcmi_fmt; + /* + * Adjust crop by making the intersection between + * format resolution request and crop request + */ + max_rect.top = 0; + max_rect.left = 0; + max_rect.width = pix->width; + max_rect.height = pix->height; + v4l2_rect_map_inside(&c, &max_rect); + c.top = clamp_t(s32, c.top, 0, pix->height - c.height); + c.left = clamp_t(s32, c.left, 0, pix->width - c.width); + dcmi->crop = c; + + /* Adjust format resolution request to crop */ + pix->width = dcmi->crop.width; + pix->height = dcmi->crop.height; + } + + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = pix->width * sd_fmt->bpp; + pix->sizeimage = pix->bytesperline * pix->height; + + if (sd_format) + *sd_format = sd_fmt; + if (sd_framesize) + *sd_framesize = sd_fsize; return 0; } @@ -743,22 +846,42 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - const struct dcmi_format *current_fmt; + const struct dcmi_format *sd_format; + struct dcmi_framesize sd_framesize; + struct v4l2_mbus_framefmt *mf = &format.format; + struct v4l2_pix_format *pix = &f->fmt.pix; int ret; - ret = dcmi_try_fmt(dcmi, f, ¤t_fmt); + /* + * Try format, fmt.width/height could have been changed + * to match sensor capability or crop request + * sd_format & sd_framesize will contain what subdev + * can do for this request. + */ + ret = dcmi_try_fmt(dcmi, f, &sd_format, &sd_framesize); if (ret) return ret; - v4l2_fill_mbus_format(&format.format, &f->fmt.pix, - current_fmt->mbus_code); + /* pix to mbus format */ + v4l2_fill_mbus_format(mf, pix, + sd_format->mbus_code); + mf->width = sd_framesize.width; + mf->height = sd_framesize.height; + ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt, NULL, &format); if (ret < 0) return ret; + dev_dbg(dcmi->dev, "Sensor format set to 0x%x %ux%u\n", + mf->code, mf->width, mf->height); + dev_dbg(dcmi->dev, "Buffer format set to %4.4s %ux%u\n", + (char *)&pix->pixelformat, + pix->width, pix->height); + dcmi->fmt = *f; - dcmi->current_fmt = current_fmt; + dcmi->sd_format = sd_format; + dcmi->sd_framesize = sd_framesize; return 0; } @@ -779,7 +902,7 @@ static int dcmi_try_fmt_vid_cap(struct file *file, void *priv, { struct stm32_dcmi *dcmi = video_drvdata(file); - return dcmi_try_fmt(dcmi, f, NULL); + return dcmi_try_fmt(dcmi, f, NULL, NULL); } static int dcmi_enum_fmt_vid_cap(struct file *file, void *priv, @@ -787,10 +910,197 @@ static int dcmi_enum_fmt_vid_cap(struct file *file, void *priv, { struct stm32_dcmi *dcmi = video_drvdata(file); - if (f->index >= dcmi->num_user_formats) + if (f->index >= dcmi->num_of_sd_formats) return -EINVAL; - f->pixelformat = dcmi->user_formats[f->index]->fourcc; + f->pixelformat = dcmi->sd_formats[f->index]->fourcc; + return 0; +} + +static int dcmi_get_sensor_format(struct stm32_dcmi *dcmi, + struct v4l2_pix_format *pix) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + int ret; + + ret = v4l2_subdev_call(dcmi->entity.subdev, pad, get_fmt, NULL, &fmt); + if (ret) + return ret; + + v4l2_fill_pix_format(pix, &fmt.format); + + return 0; +} + +static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi, + struct v4l2_pix_format *pix) +{ + const struct dcmi_format *sd_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_subdev_pad_config pad_cfg; + int ret; + + sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat); + if (!sd_fmt) { + sd_fmt = dcmi->sd_formats[dcmi->num_of_sd_formats - 1]; + pix->pixelformat = sd_fmt->fourcc; + } + + v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); + ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt, + &pad_cfg, &format); + if (ret < 0) + return ret; + + return 0; +} + +static int dcmi_get_sensor_bounds(struct stm32_dcmi *dcmi, + struct v4l2_rect *r) +{ + struct v4l2_subdev_selection bounds = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .target = V4L2_SEL_TGT_CROP_BOUNDS, + }; + unsigned int max_width, max_height, max_pixsize; + struct v4l2_pix_format pix; + unsigned int i; + int ret; + + /* + * Get sensor bounds first + */ + ret = v4l2_subdev_call(dcmi->entity.subdev, pad, get_selection, + NULL, &bounds); + if (!ret) + *r = bounds.r; + if (ret != -ENOIOCTLCMD) + return ret; + + /* + * If selection is not implemented, + * fallback by enumerating sensor frame sizes + * and take the largest one + */ + max_width = 0; + max_height = 0; + max_pixsize = 0; + for (i = 0; i < dcmi->num_of_sd_framesizes; i++) { + struct dcmi_framesize *fsize = &dcmi->sd_framesizes[i]; + unsigned int pixsize = fsize->width * fsize->height; + + if (pixsize > max_pixsize) { + max_pixsize = pixsize; + max_width = fsize->width; + max_height = fsize->height; + } + } + if (max_pixsize > 0) { + r->top = 0; + r->left = 0; + r->width = max_width; + r->height = max_height; + return 0; + } + + /* + * If frame sizes enumeration is not implemented, + * fallback by getting current sensor frame size + */ + ret = dcmi_get_sensor_format(dcmi, &pix); + if (ret) + return ret; + + r->top = 0; + r->left = 0; + r->width = pix.width; + r->height = pix.height; + + return 0; +} + +static int dcmi_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct stm32_dcmi *dcmi = video_drvdata(file); + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + s->r = dcmi->sd_bounds; + return 0; + case V4L2_SEL_TGT_CROP: + if (dcmi->do_crop) { + s->r = dcmi->crop; + } else { + s->r.top = 0; + s->r.left = 0; + s->r.width = dcmi->fmt.fmt.pix.width; + s->r.height = dcmi->fmt.fmt.pix.height; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static int dcmi_s_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct stm32_dcmi *dcmi = video_drvdata(file); + struct v4l2_rect r = s->r; + struct v4l2_rect max_rect; + struct v4l2_pix_format pix; + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + s->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + /* Reset sensor resolution to max resolution */ + pix.pixelformat = dcmi->fmt.fmt.pix.pixelformat; + pix.width = dcmi->sd_bounds.width; + pix.height = dcmi->sd_bounds.height; + dcmi_set_sensor_format(dcmi, &pix); + + /* + * Make the intersection between + * sensor resolution + * and crop request + */ + max_rect.top = 0; + max_rect.left = 0; + max_rect.width = pix.width; + max_rect.height = pix.height; + v4l2_rect_map_inside(&r, &max_rect); + r.top = clamp_t(s32, r.top, 0, pix.height - r.height); + r.left = clamp_t(s32, r.left, 0, pix.width - r.width); + + if (!((r.top == dcmi->sd_bounds.top) && + (r.left == dcmi->sd_bounds.left) && + (r.width == dcmi->sd_bounds.width) && + (r.height == dcmi->sd_bounds.height))) { + /* Crop if request is different than sensor resolution */ + dcmi->do_crop = true; + dcmi->crop = r; + dev_dbg(dcmi->dev, "s_selection: crop %ux%u@(%u,%u) from %ux%u\n", + r.width, r.height, r.left, r.top, + pix.width, pix.height); + } else { + /* Disable crop */ + dcmi->do_crop = false; + dev_dbg(dcmi->dev, "s_selection: crop is disabled\n"); + } + + s->r = r; return 0; } @@ -832,18 +1142,18 @@ static int dcmi_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { struct stm32_dcmi *dcmi = video_drvdata(file); - const struct dcmi_format *dcmi_fmt; + const struct dcmi_format *sd_fmt; struct v4l2_subdev_frame_size_enum fse = { .index = fsize->index, .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; int ret; - dcmi_fmt = find_format_by_fourcc(dcmi, fsize->pixel_format); - if (!dcmi_fmt) + sd_fmt = find_format_by_fourcc(dcmi, fsize->pixel_format); + if (!sd_fmt) return -EINVAL; - fse.code = dcmi_fmt->mbus_code; + fse.code = sd_fmt->mbus_code; ret = v4l2_subdev_call(dcmi->entity.subdev, pad, enum_frame_size, NULL, &fse); @@ -861,7 +1171,7 @@ static int dcmi_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *fival) { struct stm32_dcmi *dcmi = video_drvdata(file); - const struct dcmi_format *dcmi_fmt; + const struct dcmi_format *sd_fmt; struct v4l2_subdev_frame_interval_enum fie = { .index = fival->index, .width = fival->width, @@ -870,11 +1180,11 @@ static int dcmi_enum_frameintervals(struct file *file, void *fh, }; int ret; - dcmi_fmt = find_format_by_fourcc(dcmi, fival->pixel_format); - if (!dcmi_fmt) + sd_fmt = find_format_by_fourcc(dcmi, fival->pixel_format); + if (!sd_fmt) return -EINVAL; - fie.code = dcmi_fmt->mbus_code; + fie.code = sd_fmt->mbus_code; ret = v4l2_subdev_call(dcmi->entity.subdev, pad, enum_frame_interval, NULL, &fie); @@ -952,6 +1262,8 @@ static const struct v4l2_ioctl_ops dcmi_ioctl_ops = { .vidioc_g_fmt_vid_cap = dcmi_g_fmt_vid_cap, .vidioc_s_fmt_vid_cap = dcmi_s_fmt_vid_cap, .vidioc_enum_fmt_vid_cap = dcmi_enum_fmt_vid_cap, + .vidioc_g_selection = dcmi_g_selection, + .vidioc_s_selection = dcmi_s_selection, .vidioc_enum_input = dcmi_enum_input, .vidioc_g_input = dcmi_g_input, @@ -996,15 +1308,15 @@ static int dcmi_set_default_fmt(struct stm32_dcmi *dcmi) .width = CIF_WIDTH, .height = CIF_HEIGHT, .field = V4L2_FIELD_NONE, - .pixelformat = dcmi->user_formats[0]->fourcc, + .pixelformat = dcmi->sd_formats[0]->fourcc, }, }; int ret; - ret = dcmi_try_fmt(dcmi, &f, NULL); + ret = dcmi_try_fmt(dcmi, &f, NULL, NULL); if (ret) return ret; - dcmi->current_fmt = dcmi->user_formats[0]; + dcmi->sd_format = dcmi->sd_formats[0]; dcmi->fmt = f; return 0; } @@ -1027,7 +1339,7 @@ static const struct dcmi_format dcmi_formats[] = { static int dcmi_formats_init(struct stm32_dcmi *dcmi) { - const struct dcmi_format *dcmi_fmts[ARRAY_SIZE(dcmi_formats)]; + const struct dcmi_format *sd_fmts[ARRAY_SIZE(dcmi_formats)]; unsigned int num_fmts = 0, i, j; struct v4l2_subdev *subdev = dcmi->entity.subdev; struct v4l2_subdev_mbus_code_enum mbus_code = { @@ -1042,13 +1354,13 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) /* Code supported, have we got this fourcc yet? */ for (j = 0; j < num_fmts; j++) - if (dcmi_fmts[j]->fourcc == + if (sd_fmts[j]->fourcc == dcmi_formats[i].fourcc) /* Already available */ break; if (j == num_fmts) /* New */ - dcmi_fmts[num_fmts++] = dcmi_formats + i; + sd_fmts[num_fmts++] = dcmi_formats + i; } mbus_code.index++; } @@ -1056,18 +1368,63 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) if (!num_fmts) return -ENXIO; - dcmi->num_user_formats = num_fmts; - dcmi->user_formats = devm_kcalloc(dcmi->dev, - num_fmts, sizeof(struct dcmi_format *), - GFP_KERNEL); - if (!dcmi->user_formats) { - dev_err(dcmi->dev, "could not allocate memory\n"); + dcmi->num_of_sd_formats = num_fmts; + dcmi->sd_formats = devm_kcalloc(dcmi->dev, + num_fmts, sizeof(struct dcmi_format *), + GFP_KERNEL); + if (!dcmi->sd_formats) { + dev_err(dcmi->dev, "Could not allocate memory\n"); return -ENOMEM; } - memcpy(dcmi->user_formats, dcmi_fmts, + memcpy(dcmi->sd_formats, sd_fmts, num_fmts * sizeof(struct dcmi_format *)); - dcmi->current_fmt = dcmi->user_formats[0]; + dcmi->sd_format = dcmi->sd_formats[0]; + + return 0; +} + +static int dcmi_framesizes_init(struct stm32_dcmi *dcmi) +{ + unsigned int num_fsize = 0; + struct v4l2_subdev *subdev = dcmi->entity.subdev; + struct v4l2_subdev_frame_size_enum fse = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .code = dcmi->sd_format->mbus_code, + }; + unsigned int ret; + unsigned int i; + + /* Allocate discrete framesizes array */ + while (!v4l2_subdev_call(subdev, pad, enum_frame_size, + NULL, &fse)) + fse.index++; + + num_fsize = fse.index; + if (!num_fsize) + return 0; + + dcmi->num_of_sd_framesizes = num_fsize; + dcmi->sd_framesizes = devm_kcalloc(dcmi->dev, num_fsize, + sizeof(struct dcmi_framesize), + GFP_KERNEL); + if (!dcmi->sd_framesizes) { + dev_err(dcmi->dev, "Could not allocate memory\n"); + return -ENOMEM; + } + + /* Fill array with sensor supported framesizes */ + dev_dbg(dcmi->dev, "Sensor supports %u frame sizes:\n", num_fsize); + for (i = 0; i < dcmi->num_of_sd_framesizes; i++) { + fse.index = i; + ret = v4l2_subdev_call(subdev, pad, enum_frame_size, + NULL, &fse); + if (ret) + return ret; + dcmi->sd_framesizes[fse.index].width = fse.max_width; + dcmi->sd_framesizes[fse.index].height = fse.max_height; + dev_dbg(dcmi->dev, "%ux%u\n", fse.max_width, fse.max_height); + } return 0; } @@ -1084,6 +1441,18 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier) return ret; } + ret = dcmi_framesizes_init(dcmi); + if (ret) { + dev_err(dcmi->dev, "Could not initialize framesizes\n"); + return ret; + } + + ret = dcmi_get_sensor_bounds(dcmi, &dcmi->sd_bounds); + if (ret) { + dev_err(dcmi->dev, "Could not get sensor bounds\n"); + return ret; + } + ret = dcmi_set_default_fmt(dcmi); if (ret) { dev_err(dcmi->dev, "Could not set default format\n"); @@ -1209,7 +1578,7 @@ static int dcmi_probe(struct platform_device *pdev) if (!dcmi) return -ENOMEM; - dcmi->rstc = devm_reset_control_get(&pdev->dev, NULL); + dcmi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(dcmi->rstc)) { dev_err(&pdev->dev, "Could not get reset control\n"); return -ENODEV; diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 177faa36bc16..42e383a48ffe 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -1420,7 +1420,7 @@ static const struct v4l2_ioctl_ops cal_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static struct video_device cal_videodev = { +static const struct video_device cal_videodev = { .name = CAL_MODULE_NAME, .fops = &cal_fops, .ioctl_ops = &cal_ioctl_ops, @@ -1702,7 +1702,7 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) asd->match_type = V4L2_ASYNC_MATCH_FWNODE; asd->match.fwnode.fwnode = of_fwnode_handle(sensor_node); - remote_ep = of_parse_phandle(ep_node, "remote-endpoint", 0); + remote_ep = of_graph_get_remote_endpoint(ep_node); if (!remote_ep) { ctx_dbg(3, ctx, "can't get remote-endpoint\n"); goto cleanup_exit; diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index c47151495b6f..45bd10544189 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -2421,7 +2421,7 @@ static const struct v4l2_file_operations vpe_fops = { .mmap = v4l2_m2m_fop_mmap, }; -static struct video_device vpe_videodev = { +static const struct video_device vpe_videodev = { .name = VPE_MODULE_NAME, .fops = &vpe_fops, .ioctl_ops = &vpe_ioctl_ops, @@ -2430,7 +2430,7 @@ static struct video_device vpe_videodev = { .vfl_dir = VFL_DIR_M2M, }; -static struct v4l2_m2m_ops m2m_ops = { +static const struct v4l2_m2m_ops m2m_ops = { .device_run = device_run, .job_ready = job_ready, .job_abort = job_abort, diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index e16f70a5df1d..805d4a8fc17e 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -1259,7 +1259,7 @@ static struct viafb_pm_hooks viacam_pm_hooks = { * Setup stuff. */ -static struct video_device viacam_v4l_template = { +static const struct video_device viacam_v4l_template = { .name = "via-camera", .minor = -1, .tvnorms = V4L2_STD_NTSC_M, diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index 665744716f73..ee89ad76bee2 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -17,8 +17,7 @@ #include <linux/err.h> #include <linux/module.h> #include <linux/mutex.h> -#include <linux/regmap.h> -#include <linux/mfd/syscon.h> +#include <linux/mux/consumer.h> #include <linux/of.h> #include <linux/of_graph.h> #include <linux/platform_device.h> @@ -30,7 +29,7 @@ struct video_mux { struct v4l2_subdev subdev; struct media_pad *pads; struct v4l2_mbus_framefmt *format_mbus; - struct regmap_field *field; + struct mux_control *mux; struct mutex lock; int active; }; @@ -71,7 +70,7 @@ static int video_mux_link_setup(struct media_entity *entity, } dev_dbg(sd->dev, "setting %d active\n", local->index); - ret = regmap_field_write(vmux->field, local->index); + ret = mux_control_try_select(vmux->mux, local->index); if (ret < 0) goto out; vmux->active = local->index; @@ -80,6 +79,7 @@ static int video_mux_link_setup(struct media_entity *entity, goto out; dev_dbg(sd->dev, "going inactive\n"); + mux_control_deselect(vmux->mux); vmux->active = -1; } @@ -193,46 +193,6 @@ static const struct v4l2_subdev_ops video_mux_subdev_ops = { .video = &video_mux_subdev_video_ops, }; -static int video_mux_probe_mmio_mux(struct video_mux *vmux) -{ - struct device *dev = vmux->subdev.dev; - struct of_phandle_args args; - struct reg_field field; - struct regmap *regmap; - u32 reg, mask; - int ret; - - ret = of_parse_phandle_with_args(dev->of_node, "mux-controls", - "#mux-control-cells", 0, &args); - if (ret) - return ret; - - if (!of_device_is_compatible(args.np, "mmio-mux")) - return -EINVAL; - - regmap = syscon_node_to_regmap(args.np->parent); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - ret = of_property_read_u32_index(args.np, "mux-reg-masks", - 2 * args.args[0], ®); - if (!ret) - ret = of_property_read_u32_index(args.np, "mux-reg-masks", - 2 * args.args[0] + 1, &mask); - if (ret < 0) - return ret; - - field.reg = reg; - field.msb = fls(mask) - 1; - field.lsb = ffs(mask) - 1; - - vmux->field = devm_regmap_field_alloc(dev, regmap, field); - if (IS_ERR(vmux->field)) - return PTR_ERR(vmux->field); - - return 0; -} - static int video_mux_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -270,8 +230,9 @@ static int video_mux_probe(struct platform_device *pdev) return -EINVAL; } - ret = video_mux_probe_mmio_mux(vmux); - if (ret) { + vmux->mux = devm_mux_control_get(dev, NULL); + if (IS_ERR(vmux->mux)) { + ret = PTR_ERR(vmux->mux); if (ret != -EPROBE_DEFER) dev_err(dev, "Failed to get mux: %d\n", ret); return ret; diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index 970b9b6dab25..b01fba020d5f 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -974,7 +974,7 @@ static const struct v4l2_file_operations vim2m_fops = { .mmap = v4l2_m2m_fop_mmap, }; -static struct video_device vim2m_videodev = { +static const struct video_device vim2m_videodev = { .name = MEM2MEM_NAME, .vfl_dir = VFL_DIR_M2M, .fops = &vim2m_fops, @@ -983,7 +983,7 @@ static struct video_device vim2m_videodev = { .release = video_device_release_empty, }; -static struct v4l2_m2m_ops m2m_ops = { +static const struct v4l2_m2m_ops m2m_ops = { .device_run = device_run, .job_ready = job_ready, .job_abort = job_abort, diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c index 033a131f67af..4d663e89d33f 100644 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ b/drivers/media/platform/vimc/vimc-debayer.c @@ -373,7 +373,7 @@ static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static struct v4l2_subdev_video_ops vimc_deb_video_ops = { +static const struct v4l2_subdev_video_ops vimc_deb_video_ops = { .s_stream = vimc_deb_s_stream, }; diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c index 0a3e086e12f3..e1602e0bc230 100644 --- a/drivers/media/platform/vimc/vimc-scaler.c +++ b/drivers/media/platform/vimc/vimc-scaler.c @@ -267,7 +267,7 @@ static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static struct v4l2_subdev_video_ops vimc_sca_video_ops = { +static const struct v4l2_subdev_video_ops vimc_sca_video_ops = { .s_stream = vimc_sca_s_stream, }; diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 615c2b18dcfc..02e68c8fc02b 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -282,7 +282,7 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static struct v4l2_subdev_video_ops vimc_sen_video_ops = { +static const struct v4l2_subdev_video_ops vimc_sen_video_ops = { .s_stream = vimc_sen_s_stream, }; diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c index e15705758969..b55d278d38a7 100644 --- a/drivers/media/platform/vivid/vivid-cec.c +++ b/drivers/media/platform/vivid/vivid-cec.c @@ -22,6 +22,15 @@ #include "vivid-core.h" #include "vivid-cec.h" +#define CEC_TIM_START_BIT_TOTAL 4500 +#define CEC_TIM_START_BIT_LOW 3700 +#define CEC_TIM_START_BIT_HIGH 800 +#define CEC_TIM_DATA_BIT_TOTAL 2400 +#define CEC_TIM_DATA_BIT_0_LOW 1500 +#define CEC_TIM_DATA_BIT_0_HIGH 900 +#define CEC_TIM_DATA_BIT_1_LOW 600 +#define CEC_TIM_DATA_BIT_1_HIGH 1800 + void vivid_cec_bus_free_work(struct vivid_dev *dev) { spin_lock(&dev->cec_slock); @@ -64,6 +73,58 @@ static bool vivid_cec_find_dest_adap(struct vivid_dev *dev, return false; } +static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts, + const struct cec_msg *msg, bool nacked) +{ + unsigned int len = nacked ? 1 : msg->len; + unsigned int i; + bool bit; + + if (adap == NULL) + return; + ts = ktime_sub_us(ts, (CEC_TIM_START_BIT_TOTAL + + len * 10 * CEC_TIM_DATA_BIT_TOTAL)); + cec_queue_pin_cec_event(adap, false, ts); + ts = ktime_add_us(ts, CEC_TIM_START_BIT_LOW); + cec_queue_pin_cec_event(adap, true, ts); + ts = ktime_add_us(ts, CEC_TIM_START_BIT_HIGH); + + for (i = 0; i < 10 * len; i++) { + switch (i % 10) { + case 0 ... 7: + bit = msg->msg[i / 10] & (0x80 >> (i % 10)); + break; + case 8: /* EOM */ + bit = i / 10 == msg->len - 1; + break; + case 9: /* ACK */ + bit = cec_msg_is_broadcast(msg) ^ nacked; + break; + } + cec_queue_pin_cec_event(adap, false, ts); + if (bit) + ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_LOW); + else + ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_LOW); + cec_queue_pin_cec_event(adap, true, ts); + if (bit) + ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_HIGH); + else + ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_HIGH); + } +} + +static void vivid_cec_pin_events(struct vivid_dev *dev, + const struct cec_msg *msg, bool nacked) +{ + ktime_t ts = ktime_get(); + unsigned int i; + + vivid_cec_pin_adap_events(dev->cec_rx_adap, ts, msg, nacked); + for (i = 0; i < MAX_OUTPUTS; i++) + vivid_cec_pin_adap_events(dev->cec_tx_adap[i], ts, msg, nacked); +} + static void vivid_cec_xfer_done_worker(struct work_struct *work) { struct vivid_cec_work *cw = @@ -84,6 +145,7 @@ static void vivid_cec_xfer_done_worker(struct work_struct *work) dev->cec_xfer_start_jiffies = 0; list_del(&cw->list); spin_unlock(&dev->cec_slock); + vivid_cec_pin_events(dev, &cw->msg, !valid_dest); cec_transmit_attempt_done(cw->adap, cw->tx_status); /* Broadcast message */ @@ -118,6 +180,7 @@ static void vivid_cec_xfer_try_worker(struct work_struct *work) static int vivid_cec_adap_enable(struct cec_adapter *adap, bool enable) { + adap->cec_pin_is_high = true; return 0; } @@ -219,8 +282,7 @@ struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, bool is_source) { char name[sizeof(dev->vid_out_dev.name) + 2]; - u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | - CEC_CAP_PASSTHROUGH | CEC_CAP_RC | CEC_CAP_MONITOR_ALL; + u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN; snprintf(name, sizeof(name), "%s%d", is_source ? dev->vid_out_dev.name : dev->vid_cap_dev.name, diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index ef344b9a48af..5f316a5e38db 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -1201,8 +1201,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) goto unreg_dev; } cec_s_phys_addr(adap, 0, false); - v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input %d\n", - dev_name(&adap->devnode.dev), i); + v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input 0\n", + dev_name(&adap->devnode.dev)); } #endif @@ -1255,13 +1255,13 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->cec_tx_adap[bus_cnt] = NULL; goto unreg_dev; } + v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n", + dev_name(&adap->devnode.dev), bus_cnt); bus_cnt++; if (bus_cnt <= out_type_counter[HDMI]) cec_s_phys_addr(adap, bus_cnt << 12, false); else cec_s_phys_addr(adap, 0x1000, false); - v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n", - dev_name(&adap->devnode.dev), i); } #endif diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 847963b6e9eb..78ef838416b3 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -41,11 +41,11 @@ struct vsp1_rwpf; struct vsp1_sru; struct vsp1_uds; +#define VSP1_MAX_LIF 2 #define VSP1_MAX_RPF 5 #define VSP1_MAX_UDS 3 #define VSP1_MAX_WPF 4 -#define VSP1_HAS_LIF (1 << 0) #define VSP1_HAS_LUT (1 << 1) #define VSP1_HAS_SRU (1 << 2) #define VSP1_HAS_BRU (1 << 3) @@ -54,12 +54,14 @@ struct vsp1_uds; #define VSP1_HAS_WPF_HFLIP (1 << 6) #define VSP1_HAS_HGO (1 << 7) #define VSP1_HAS_HGT (1 << 8) +#define VSP1_HAS_BRS (1 << 9) struct vsp1_device_info { u32 version; const char *model; unsigned int gen; unsigned int features; + unsigned int lif_count; unsigned int rpf_count; unsigned int uds_count; unsigned int wpf_count; @@ -76,13 +78,14 @@ struct vsp1_device { struct rcar_fcp_device *fcp; struct device *bus_master; + struct vsp1_bru *brs; struct vsp1_bru *bru; struct vsp1_clu *clu; struct vsp1_hgo *hgo; struct vsp1_hgt *hgt; struct vsp1_hsit *hsi; struct vsp1_hsit *hst; - struct vsp1_lif *lif; + struct vsp1_lif *lif[VSP1_MAX_LIF]; struct vsp1_lut *lut; struct vsp1_rwpf *rpf[VSP1_MAX_RPF]; struct vsp1_sru *sru; diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index 85362c5ef57a..e8fd2ae3b3eb 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c @@ -33,7 +33,7 @@ static inline void vsp1_bru_write(struct vsp1_bru *bru, struct vsp1_dl_list *dl, u32 reg, u32 data) { - vsp1_dl_list_write(dl, reg, data); + vsp1_dl_list_write(dl, bru->base + reg, data); } /* ----------------------------------------------------------------------------- @@ -332,11 +332,14 @@ static void bru_configure(struct vsp1_entity *entity, /* * Route BRU input 1 as SRC input to the ROP unit and configure the ROP * unit with a NOP operation to make BRU input 1 available as the - * Blend/ROP unit B SRC input. + * Blend/ROP unit B SRC input. Only needed for BRU, the BRS has no ROP + * unit. */ - vsp1_bru_write(bru, dl, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) | - VI6_BRU_ROP_CROP(VI6_ROP_NOP) | - VI6_BRU_ROP_AROP(VI6_ROP_NOP)); + if (entity->type == VSP1_ENTITY_BRU) + vsp1_bru_write(bru, dl, VI6_BRU_ROP, + VI6_BRU_ROP_DSTSEL_BRUIN(1) | + VI6_BRU_ROP_CROP(VI6_ROP_NOP) | + VI6_BRU_ROP_AROP(VI6_ROP_NOP)); for (i = 0; i < bru->entity.source_pad; ++i) { bool premultiplied = false; @@ -366,12 +369,13 @@ static void bru_configure(struct vsp1_entity *entity, ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF; /* - * Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to - * D in that order. The Blend/ROP unit B SRC is hardwired to the - * ROP unit output, the corresponding register bits must be set - * to 0. + * Route inputs 0 to 3 as SRC inputs to Blend/ROP units A to D + * in that order. In the BRU the Blend/ROP unit B SRC is + * hardwired to the ROP unit output, the corresponding register + * bits must be set to 0. The BRS has no ROP unit and doesn't + * need any special processing. */ - if (i != 1) + if (!(entity->type == VSP1_ENTITY_BRU && i == 1)) ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i); vsp1_bru_write(bru, dl, VI6_BRU_CTRL(i), ctrl); @@ -407,20 +411,31 @@ static const struct vsp1_entity_operations bru_entity_ops = { * Initialization and Cleanup */ -struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) +struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1, + enum vsp1_entity_type type) { struct vsp1_bru *bru; + unsigned int num_pads; + const char *name; int ret; bru = devm_kzalloc(vsp1->dev, sizeof(*bru), GFP_KERNEL); if (bru == NULL) return ERR_PTR(-ENOMEM); + bru->base = type == VSP1_ENTITY_BRU ? VI6_BRU_BASE : VI6_BRS_BASE; bru->entity.ops = &bru_entity_ops; - bru->entity.type = VSP1_ENTITY_BRU; + bru->entity.type = type; + + if (type == VSP1_ENTITY_BRU) { + num_pads = vsp1->info->num_bru_inputs + 1; + name = "bru"; + } else { + num_pads = 3; + name = "brs"; + } - ret = vsp1_entity_init(vsp1, &bru->entity, "bru", - vsp1->info->num_bru_inputs + 1, &bru_ops, + ret = vsp1_entity_init(vsp1, &bru->entity, name, num_pads, &bru_ops, MEDIA_ENT_F_PROC_VIDEO_COMPOSER); if (ret < 0) return ERR_PTR(ret); @@ -435,7 +450,7 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) bru->entity.subdev.ctrl_handler = &bru->ctrls; if (bru->ctrls.error) { - dev_err(vsp1->dev, "bru: failed to initialize controls\n"); + dev_err(vsp1->dev, "%s: failed to initialize controls\n", name); ret = bru->ctrls.error; vsp1_entity_destroy(&bru->entity); return ERR_PTR(ret); diff --git a/drivers/media/platform/vsp1/vsp1_bru.h b/drivers/media/platform/vsp1/vsp1_bru.h index 828a3fcadea8..c98ed96d8de6 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.h +++ b/drivers/media/platform/vsp1/vsp1_bru.h @@ -26,6 +26,7 @@ struct vsp1_rwpf; struct vsp1_bru { struct vsp1_entity entity; + unsigned int base; struct v4l2_ctrl_handler ctrls; @@ -41,6 +42,7 @@ static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev) return container_of(subdev, struct vsp1_bru, entity.subdev); } -struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1); +struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1, + enum vsp1_entity_type type); #endif /* __VSP1_BRU_H__ */ diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index aaf17b13fd78..8b5cbb6b7a70 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c @@ -95,6 +95,7 @@ enum vsp1_dl_mode { * struct vsp1_dl_manager - Display List manager * @index: index of the related WPF * @mode: display list operation mode (header or headerless) + * @singleshot: execute the display list in single-shot mode * @vsp1: the VSP1 device * @lock: protects the free, active, queued, pending and gc_fragments lists * @free: array of all free display lists @@ -107,6 +108,7 @@ enum vsp1_dl_mode { struct vsp1_dl_manager { unsigned int index; enum vsp1_dl_mode mode; + bool singleshot; struct vsp1_device *vsp1; spinlock_t lock; @@ -437,6 +439,7 @@ int vsp1_dl_list_add_chain(struct vsp1_dl_list *head, static void vsp1_dl_list_fill_header(struct vsp1_dl_list *dl, bool is_last) { + struct vsp1_dl_manager *dlm = dl->dlm; struct vsp1_dl_header_list *hdr = dl->header->lists; struct vsp1_dl_body *dlb; unsigned int num_lists = 0; @@ -461,106 +464,152 @@ static void vsp1_dl_list_fill_header(struct vsp1_dl_list *dl, bool is_last) dl->header->num_lists = num_lists; - /* - * If this display list's chain is not empty, we are on a list, where - * the next item in the list is the display list entity which should be - * automatically queued by the hardware. - */ if (!list_empty(&dl->chain) && !is_last) { + /* + * If this display list's chain is not empty, we are on a list, + * and the next item is the display list that we must queue for + * automatic processing by the hardware. + */ struct vsp1_dl_list *next = list_next_entry(dl, chain); dl->header->next_header = next->dma; dl->header->flags = VSP1_DLH_AUTO_START; + } else if (!dlm->singleshot) { + /* + * if the display list manager works in continuous mode, the VSP + * should loop over the display list continuously until + * instructed to do otherwise. + */ + dl->header->next_header = dl->dma; + dl->header->flags = VSP1_DLH_INT_ENABLE | VSP1_DLH_AUTO_START; } else { + /* + * Otherwise, in mem-to-mem mode, we work in single-shot mode + * and the next display list must not be started automatically. + */ dl->header->flags = VSP1_DLH_INT_ENABLE; } } -void vsp1_dl_list_commit(struct vsp1_dl_list *dl) +static bool vsp1_dl_list_hw_update_pending(struct vsp1_dl_manager *dlm) { - struct vsp1_dl_manager *dlm = dl->dlm; struct vsp1_device *vsp1 = dlm->vsp1; - unsigned long flags; - bool update; - spin_lock_irqsave(&dlm->lock, flags); + if (!dlm->queued) + return false; - if (dl->dlm->mode == VSP1_DL_MODE_HEADER) { - struct vsp1_dl_list *dl_child; + /* + * Check whether the VSP1 has taken the update. In headerless mode the + * hardware indicates this by clearing the UPD bit in the DL_BODY_SIZE + * register, and in header mode by clearing the UPDHDR bit in the CMD + * register. + */ + if (dlm->mode == VSP1_DL_MODE_HEADERLESS) + return !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) + & VI6_DL_BODY_SIZE_UPD); + else + return !!(vsp1_read(vsp1, VI6_CMD(dlm->index) & VI6_CMD_UPDHDR)); +} +static void vsp1_dl_list_hw_enqueue(struct vsp1_dl_list *dl) +{ + struct vsp1_dl_manager *dlm = dl->dlm; + struct vsp1_device *vsp1 = dlm->vsp1; + + if (dlm->mode == VSP1_DL_MODE_HEADERLESS) { /* - * In header mode the caller guarantees that the hardware is - * idle at this point. + * In headerless mode, program the hardware directly with the + * display list body address and size and set the UPD bit. The + * bit will be cleared by the hardware when the display list + * processing starts. */ - - /* Fill the header for the head and chained display lists. */ - vsp1_dl_list_fill_header(dl, list_empty(&dl->chain)); - - list_for_each_entry(dl_child, &dl->chain, chain) { - bool last = list_is_last(&dl_child->chain, &dl->chain); - - vsp1_dl_list_fill_header(dl_child, last); - } - + vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->body0.dma); + vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD | + (dl->body0.num_entries * sizeof(*dl->header->lists))); + } else { /* - * Commit the head display list to hardware. Chained headers - * will auto-start. + * In header mode, program the display list header address. If + * the hardware is idle (single-shot mode or first frame in + * continuous mode) it will then be started independently. If + * the hardware is operating, the VI6_DL_HDR_REF_ADDR register + * will be updated with the display list address. */ vsp1_write(vsp1, VI6_DL_HDR_ADDR(dlm->index), dl->dma); - - dlm->active = dl; - goto done; } +} + +static void vsp1_dl_list_commit_continuous(struct vsp1_dl_list *dl) +{ + struct vsp1_dl_manager *dlm = dl->dlm; /* - * Once the UPD bit has been set the hardware can start processing the - * display list at any time and we can't touch the address and size - * registers. In that case mark the update as pending, it will be - * queued up to the hardware by the frame end interrupt handler. + * If a previous display list has been queued to the hardware but not + * processed yet, the VSP can start processing it at any time. In that + * case we can't replace the queued list by the new one, as we could + * race with the hardware. We thus mark the update as pending, it will + * be queued up to the hardware by the frame end interrupt handler. */ - update = !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD); - if (update) { + if (vsp1_dl_list_hw_update_pending(dlm)) { __vsp1_dl_list_put(dlm->pending); dlm->pending = dl; - goto done; + return; } /* - * Program the hardware with the display list body address and size. - * The UPD bit will be cleared by the device when the display list is - * processed. + * Pass the new display list to the hardware and mark it as queued. It + * will become active when the hardware starts processing it. */ - vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->body0.dma); - vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD | - (dl->body0.num_entries * sizeof(*dl->header->lists))); + vsp1_dl_list_hw_enqueue(dl); __vsp1_dl_list_put(dlm->queued); dlm->queued = dl; - -done: - spin_unlock_irqrestore(&dlm->lock, flags); } -/* ----------------------------------------------------------------------------- - * Display List Manager - */ - -/* Interrupt Handling */ -void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm) +static void vsp1_dl_list_commit_singleshot(struct vsp1_dl_list *dl) { - spin_lock(&dlm->lock); + struct vsp1_dl_manager *dlm = dl->dlm; /* - * The display start interrupt signals the end of the display list - * processing by the device. The active display list, if any, won't be - * accessed anymore and can be reused. + * When working in single-shot mode, the caller guarantees that the + * hardware is idle at this point. Just commit the head display list + * to hardware. Chained lists will be started automatically. */ - __vsp1_dl_list_put(dlm->active); - dlm->active = NULL; + vsp1_dl_list_hw_enqueue(dl); - spin_unlock(&dlm->lock); + dlm->active = dl; +} + +void vsp1_dl_list_commit(struct vsp1_dl_list *dl) +{ + struct vsp1_dl_manager *dlm = dl->dlm; + struct vsp1_dl_list *dl_child; + unsigned long flags; + + if (dlm->mode == VSP1_DL_MODE_HEADER) { + /* Fill the header for the head and chained display lists. */ + vsp1_dl_list_fill_header(dl, list_empty(&dl->chain)); + + list_for_each_entry(dl_child, &dl->chain, chain) { + bool last = list_is_last(&dl_child->chain, &dl->chain); + + vsp1_dl_list_fill_header(dl_child, last); + } + } + + spin_lock_irqsave(&dlm->lock, flags); + + if (dlm->singleshot) + vsp1_dl_list_commit_singleshot(dl); + else + vsp1_dl_list_commit_continuous(dl); + + spin_unlock_irqrestore(&dlm->lock, flags); } +/* ----------------------------------------------------------------------------- + * Display List Manager + */ + /** * vsp1_dlm_irq_frame_end - Display list handler for the frame end interrupt * @dlm: the display list manager @@ -572,31 +621,28 @@ void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm) */ bool vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) { - struct vsp1_device *vsp1 = dlm->vsp1; bool completed = false; spin_lock(&dlm->lock); - __vsp1_dl_list_put(dlm->active); - dlm->active = NULL; - /* - * Header mode is used for mem-to-mem pipelines only. We don't need to - * perform any operation as there can't be any new display list queued - * in that case. + * The mem-to-mem pipelines work in single-shot mode. No new display + * list can be queued, we don't have to do anything. */ - if (dlm->mode == VSP1_DL_MODE_HEADER) { + if (dlm->singleshot) { + __vsp1_dl_list_put(dlm->active); + dlm->active = NULL; completed = true; goto done; } /* - * The UPD bit set indicates that the commit operation raced with the - * interrupt and occurred after the frame end event and UPD clear but - * before interrupt processing. The hardware hasn't taken the update - * into account yet, we'll thus skip one frame and retry. + * If the commit operation raced with the interrupt and occurred after + * the frame end event but before interrupt processing, the hardware + * hasn't taken the update into account yet. We have to skip one frame + * and retry. */ - if (vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD) + if (vsp1_dl_list_hw_update_pending(dlm)) goto done; /* @@ -604,24 +650,20 @@ bool vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) * frame end interrupt. The display list thus becomes active. */ if (dlm->queued) { + __vsp1_dl_list_put(dlm->active); dlm->active = dlm->queued; dlm->queued = NULL; completed = true; } /* - * Now that the UPD bit has been cleared we can queue the next display - * list to the hardware if one has been prepared. + * Now that the VSP has started processing the queued display list, we + * can queue the pending display list to the hardware if one has been + * prepared. */ if (dlm->pending) { - struct vsp1_dl_list *dl = dlm->pending; - - vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->body0.dma); - vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD | - (dl->body0.num_entries * - sizeof(*dl->header->lists))); - - dlm->queued = dl; + vsp1_dl_list_hw_enqueue(dlm->pending); + dlm->queued = dlm->pending; dlm->pending = NULL; } @@ -714,6 +756,7 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, dlm->index = index; dlm->mode = index == 0 && !vsp1->info->uapi ? VSP1_DL_MODE_HEADERLESS : VSP1_DL_MODE_HEADER; + dlm->singleshot = vsp1->info->uapi; dlm->vsp1 = vsp1; spin_lock_init(&dlm->lock); diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h index 6ec1380a10af..ee3508172f0a 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.h +++ b/drivers/media/platform/vsp1/vsp1_dl.h @@ -27,7 +27,6 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, unsigned int prealloc); void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm); void vsp1_dlm_reset(struct vsp1_dl_manager *dlm); -void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm); bool vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm); struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm); diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index 9377aafa8996..4dfbeac8f42c 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -32,17 +32,13 @@ * Interrupt Handling */ -void vsp1_drm_display_start(struct vsp1_device *vsp1) +static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe, + bool completed) { - vsp1_dlm_irq_display_start(vsp1->drm->pipe.output->dlm); -} - -static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe) -{ - struct vsp1_drm *drm = to_vsp1_drm(pipe); + struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe); - if (drm->du_complete) - drm->du_complete(drm->du_private); + if (drm_pipe->du_complete) + drm_pipe->du_complete(drm_pipe->du_private, completed); } /* ----------------------------------------------------------------------------- @@ -63,29 +59,44 @@ EXPORT_SYMBOL_GPL(vsp1_du_init); /** * vsp1_du_setup_lif - Setup the output part of the VSP pipeline * @dev: the VSP device + * @pipe_index: the DRM pipeline index * @cfg: the LIF configuration * * Configure the output part of VSP DRM pipeline for the given frame @cfg.width - * and @cfg.height. This sets up formats on the BRU source pad, the WPF0 sink - * and source pads, and the LIF sink pad. + * and @cfg.height. This sets up formats on the blend unit (BRU or BRS) source + * pad, the WPF sink and source pads, and the LIF sink pad. + * + * The @pipe_index argument selects which DRM pipeline to setup. The number of + * available pipelines depend on the VSP instance. * - * As the media bus code on the BRU source pad is conditioned by the - * configuration of the BRU sink 0 pad, we also set up the formats on all BRU + * As the media bus code on the blend unit source pad is conditioned by the + * configuration of its sink 0 pad, we also set up the formats on all blend unit * sinks, even if the configuration will be overwritten later by - * vsp1_du_setup_rpf(). This ensures that the BRU configuration is set to a well - * defined state. + * vsp1_du_setup_rpf(). This ensures that the blend unit configuration is set to + * a well defined state. * * Return 0 on success or a negative error code on failure. */ -int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) +int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, + const struct vsp1_du_lif_config *cfg) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); - struct vsp1_pipeline *pipe = &vsp1->drm->pipe; - struct vsp1_bru *bru = vsp1->bru; + struct vsp1_drm_pipeline *drm_pipe; + struct vsp1_pipeline *pipe; + struct vsp1_bru *bru; struct v4l2_subdev_format format; + const char *bru_name; unsigned int i; int ret; + if (pipe_index >= vsp1->info->lif_count) + return -EINVAL; + + drm_pipe = &vsp1->drm->pipe[pipe_index]; + pipe = &drm_pipe->pipe; + bru = to_bru(&pipe->bru->subdev); + bru_name = pipe->bru->type == VSP1_ENTITY_BRU ? "BRU" : "BRS"; + if (!cfg) { /* * NULL configuration means the CRTC is being disabled, stop @@ -97,14 +108,25 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) media_pipeline_stop(&pipe->output->entity.subdev.entity); - for (i = 0; i < bru->entity.source_pad; ++i) { - vsp1->drm->inputs[i].enabled = false; - bru->inputs[i].rpf = NULL; + for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) { + struct vsp1_rwpf *rpf = pipe->inputs[i]; + + if (!rpf) + continue; + + /* + * Remove the RPF from the pipe and the list of BRU + * inputs. + */ + WARN_ON(list_empty(&rpf->entity.list_pipe)); + list_del_init(&rpf->entity.list_pipe); pipe->inputs[i] = NULL; + + bru->inputs[rpf->bru_input].rpf = NULL; } + drm_pipe->du_complete = NULL; pipe->num_inputs = 0; - vsp1->drm->du_complete = NULL; vsp1_dlm_reset(pipe->output->dlm); vsp1_device_put(vsp1); @@ -114,8 +136,8 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) return 0; } - dev_dbg(vsp1->dev, "%s: configuring LIF with format %ux%u\n", - __func__, cfg->width, cfg->height); + dev_dbg(vsp1->dev, "%s: configuring LIF%u with format %ux%u\n", + __func__, pipe_index, cfg->width, cfg->height); /* * Configure the format at the BRU sinks and propagate it through the @@ -124,7 +146,7 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) memset(&format, 0, sizeof(format)); format.which = V4L2_SUBDEV_FORMAT_ACTIVE; - for (i = 0; i < bru->entity.source_pad; ++i) { + for (i = 0; i < pipe->bru->source_pad; ++i) { format.pad = i; format.format.width = cfg->width; @@ -132,60 +154,60 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32; format.format.field = V4L2_FIELD_NONE; - ret = v4l2_subdev_call(&bru->entity.subdev, pad, + ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_fmt, NULL, &format); if (ret < 0) return ret; - dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n", + dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n", __func__, format.format.width, format.format.height, - format.format.code, i); + format.format.code, bru_name, i); } - format.pad = bru->entity.source_pad; + format.pad = pipe->bru->source_pad; format.format.width = cfg->width; format.format.height = cfg->height; format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32; format.format.field = V4L2_FIELD_NONE; - ret = v4l2_subdev_call(&bru->entity.subdev, pad, set_fmt, NULL, + ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_fmt, NULL, &format); if (ret < 0) return ret; - dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n", + dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n", __func__, format.format.width, format.format.height, - format.format.code, i); + format.format.code, bru_name, i); format.pad = RWPF_PAD_SINK; - ret = v4l2_subdev_call(&vsp1->wpf[0]->entity.subdev, pad, set_fmt, NULL, + ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, set_fmt, NULL, &format); if (ret < 0) return ret; - dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on WPF0 sink\n", + dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on WPF%u sink\n", __func__, format.format.width, format.format.height, - format.format.code); + format.format.code, pipe->output->entity.index); format.pad = RWPF_PAD_SOURCE; - ret = v4l2_subdev_call(&vsp1->wpf[0]->entity.subdev, pad, get_fmt, NULL, + ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, get_fmt, NULL, &format); if (ret < 0) return ret; - dev_dbg(vsp1->dev, "%s: got format %ux%u (%x) on WPF0 source\n", + dev_dbg(vsp1->dev, "%s: got format %ux%u (%x) on WPF%u source\n", __func__, format.format.width, format.format.height, - format.format.code); + format.format.code, pipe->output->entity.index); format.pad = LIF_PAD_SINK; - ret = v4l2_subdev_call(&vsp1->lif->entity.subdev, pad, set_fmt, NULL, + ret = v4l2_subdev_call(&pipe->lif->subdev, pad, set_fmt, NULL, &format); if (ret < 0) return ret; - dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on LIF sink\n", + dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on LIF%u sink\n", __func__, format.format.width, format.format.height, - format.format.code); + format.format.code, pipe_index); /* * Verify that the format at the output of the pipeline matches the @@ -213,8 +235,8 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) * Register a callback to allow us to notify the DRM driver of frame * completion events. */ - vsp1->drm->du_complete = cfg->callback; - vsp1->drm->du_private = cfg->callback_data; + drm_pipe->du_complete = cfg->callback; + drm_pipe->du_private = cfg->callback_data; ret = media_pipeline_start(&pipe->output->entity.subdev.entity, &pipe->pipe); @@ -224,6 +246,10 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) return ret; } + /* Disable the display interrupts. */ + vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0); + vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0); + dev_dbg(vsp1->dev, "%s: pipeline enabled\n", __func__); return 0; @@ -233,19 +259,21 @@ EXPORT_SYMBOL_GPL(vsp1_du_setup_lif); /** * vsp1_du_atomic_begin - Prepare for an atomic update * @dev: the VSP device + * @pipe_index: the DRM pipeline index */ -void vsp1_du_atomic_begin(struct device *dev) +void vsp1_du_atomic_begin(struct device *dev, unsigned int pipe_index) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); - struct vsp1_pipeline *pipe = &vsp1->drm->pipe; + struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index]; - vsp1->drm->num_inputs = pipe->num_inputs; + drm_pipe->enabled = drm_pipe->pipe.num_inputs != 0; } EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); /** * vsp1_du_atomic_update - Setup one RPF input of the VSP pipeline * @dev: the VSP device + * @pipe_index: the DRM pipeline index * @rpf_index: index of the RPF to setup (0-based) * @cfg: the RPF configuration * @@ -272,10 +300,12 @@ EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); * * Return 0 on success or a negative error code on failure. */ -int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, +int vsp1_du_atomic_update(struct device *dev, unsigned int pipe_index, + unsigned int rpf_index, const struct vsp1_du_atomic_config *cfg) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); + struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index]; const struct vsp1_format_info *fmtinfo; struct vsp1_rwpf *rpf; @@ -288,7 +318,12 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__, rpf_index); - vsp1->drm->inputs[rpf_index].enabled = false; + /* + * Remove the RPF from the pipe's inputs. The atomic flush + * handler will disable the input and remove the entity from the + * pipe's entities list. + */ + drm_pipe->pipe.inputs[rpf_index] = NULL; return 0; } @@ -324,13 +359,15 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, vsp1->drm->inputs[rpf_index].crop = cfg->src; vsp1->drm->inputs[rpf_index].compose = cfg->dst; vsp1->drm->inputs[rpf_index].zpos = cfg->zpos; - vsp1->drm->inputs[rpf_index].enabled = true; + + drm_pipe->pipe.inputs[rpf_index] = rpf; return 0; } EXPORT_SYMBOL_GPL(vsp1_du_atomic_update); static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, + struct vsp1_pipeline *pipe, struct vsp1_rwpf *rpf, unsigned int bru_input) { struct v4l2_subdev_selection sel; @@ -404,7 +441,7 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, /* BRU sink, propagate the format from the RPF source. */ format.pad = bru_input; - ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_fmt, NULL, + ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_fmt, NULL, &format); if (ret < 0) return ret; @@ -417,8 +454,8 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, sel.target = V4L2_SEL_TGT_COMPOSE; sel.r = vsp1->drm->inputs[rpf->entity.index].compose; - ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_selection, - NULL, &sel); + ret = v4l2_subdev_call(&pipe->bru->subdev, pad, set_selection, NULL, + &sel); if (ret < 0) return ret; @@ -438,18 +475,25 @@ static unsigned int rpf_zpos(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf) /** * vsp1_du_atomic_flush - Commit an atomic update * @dev: the VSP device + * @pipe_index: the DRM pipeline index */ -void vsp1_du_atomic_flush(struct device *dev) +void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); - struct vsp1_pipeline *pipe = &vsp1->drm->pipe; + struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index]; + struct vsp1_pipeline *pipe = &drm_pipe->pipe; struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, }; + struct vsp1_bru *bru = to_bru(&pipe->bru->subdev); struct vsp1_entity *entity; + struct vsp1_entity *next; struct vsp1_dl_list *dl; + const char *bru_name; unsigned long flags; unsigned int i; int ret; + bru_name = pipe->bru->type == VSP1_ENTITY_BRU ? "BRU" : "BRS"; + /* Prepare the display list. */ dl = vsp1_dl_list_get(pipe->output->dlm); @@ -460,12 +504,8 @@ void vsp1_du_atomic_flush(struct device *dev) struct vsp1_rwpf *rpf = vsp1->rpf[i]; unsigned int j; - if (!vsp1->drm->inputs[i].enabled) { - pipe->inputs[i] = NULL; + if (!pipe->inputs[i]) continue; - } - - pipe->inputs[i] = rpf; /* Insert the RPF in the sorted RPFs array. */ for (j = pipe->num_inputs++; j > 0; --j) { @@ -478,22 +518,26 @@ void vsp1_du_atomic_flush(struct device *dev) } /* Setup the RPF input pipeline for every enabled input. */ - for (i = 0; i < vsp1->info->num_bru_inputs; ++i) { + for (i = 0; i < pipe->bru->source_pad; ++i) { struct vsp1_rwpf *rpf = inputs[i]; if (!rpf) { - vsp1->bru->inputs[i].rpf = NULL; + bru->inputs[i].rpf = NULL; continue; } - vsp1->bru->inputs[i].rpf = rpf; + if (list_empty(&rpf->entity.list_pipe)) + list_add_tail(&rpf->entity.list_pipe, &pipe->entities); + + bru->inputs[i].rpf = rpf; rpf->bru_input = i; + rpf->entity.sink = pipe->bru; rpf->entity.sink_pad = i; - dev_dbg(vsp1->dev, "%s: connecting RPF.%u to BRU:%u\n", - __func__, rpf->entity.index, i); + dev_dbg(vsp1->dev, "%s: connecting RPF.%u to %s:%u\n", + __func__, rpf->entity.index, bru_name, i); - ret = vsp1_du_setup_rpf_pipe(vsp1, rpf, i); + ret = vsp1_du_setup_rpf_pipe(vsp1, pipe, rpf, i); if (ret < 0) dev_err(vsp1->dev, "%s: failed to setup RPF.%u\n", @@ -501,16 +545,16 @@ void vsp1_du_atomic_flush(struct device *dev) } /* Configure all entities in the pipeline. */ - list_for_each_entry(entity, &pipe->entities, list_pipe) { + list_for_each_entry_safe(entity, next, &pipe->entities, list_pipe) { /* Disconnect unused RPFs from the pipeline. */ - if (entity->type == VSP1_ENTITY_RPF) { - struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); + if (entity->type == VSP1_ENTITY_RPF && + !pipe->inputs[entity->index]) { + vsp1_dl_list_write(dl, entity->route->reg, + VI6_DPR_NODE_UNUSED); - if (!pipe->inputs[rpf->entity.index]) { - vsp1_dl_list_write(dl, entity->route->reg, - VI6_DPR_NODE_UNUSED); - continue; - } + list_del_init(&entity->list_pipe); + + continue; } vsp1_entity_route_setup(entity, pipe, dl); @@ -528,14 +572,11 @@ void vsp1_du_atomic_flush(struct device *dev) vsp1_dl_list_commit(dl); /* Start or stop the pipeline if needed. */ - if (!vsp1->drm->num_inputs && pipe->num_inputs) { - vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0); - vsp1_write(vsp1, VI6_DISP_IRQ_ENB, VI6_DISP_IRQ_ENB_DSTE); + if (!drm_pipe->enabled && pipe->num_inputs) { spin_lock_irqsave(&pipe->irqlock, flags); vsp1_pipeline_run(pipe); spin_unlock_irqrestore(&pipe->irqlock, flags); - } else if (vsp1->drm->num_inputs && !pipe->num_inputs) { - vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0); + } else if (drm_pipe->enabled && !pipe->num_inputs) { vsp1_pipeline_stop(pipe); } } @@ -568,83 +609,48 @@ EXPORT_SYMBOL_GPL(vsp1_du_unmap_sg); * Initialization */ -int vsp1_drm_create_links(struct vsp1_device *vsp1) -{ - const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; - unsigned int i; - int ret; - - /* - * VSPD instances require a BRU to perform composition and a LIF to - * output to the DU. - */ - if (!vsp1->bru || !vsp1->lif) - return -ENXIO; - - for (i = 0; i < vsp1->info->rpf_count; ++i) { - struct vsp1_rwpf *rpf = vsp1->rpf[i]; - - ret = media_create_pad_link(&rpf->entity.subdev.entity, - RWPF_PAD_SOURCE, - &vsp1->bru->entity.subdev.entity, - i, flags); - if (ret < 0) - return ret; - - rpf->entity.sink = &vsp1->bru->entity.subdev.entity; - rpf->entity.sink_pad = i; - } - - ret = media_create_pad_link(&vsp1->bru->entity.subdev.entity, - vsp1->bru->entity.source_pad, - &vsp1->wpf[0]->entity.subdev.entity, - RWPF_PAD_SINK, flags); - if (ret < 0) - return ret; - - vsp1->bru->entity.sink = &vsp1->wpf[0]->entity.subdev.entity; - vsp1->bru->entity.sink_pad = RWPF_PAD_SINK; - - ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity, - RWPF_PAD_SOURCE, - &vsp1->lif->entity.subdev.entity, - LIF_PAD_SINK, flags); - if (ret < 0) - return ret; - - return 0; -} - int vsp1_drm_init(struct vsp1_device *vsp1) { - struct vsp1_pipeline *pipe; unsigned int i; vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL); if (!vsp1->drm) return -ENOMEM; - pipe = &vsp1->drm->pipe; + /* Create one DRM pipeline per LIF. */ + for (i = 0; i < vsp1->info->lif_count; ++i) { + struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[i]; + struct vsp1_pipeline *pipe = &drm_pipe->pipe; - vsp1_pipeline_init(pipe); + vsp1_pipeline_init(pipe); - /* The DRM pipeline is static, add entities manually. */ + /* + * The DRM pipeline is static, add entities manually. The first + * pipeline uses the BRU and the second pipeline the BRS. + */ + pipe->bru = i == 0 ? &vsp1->bru->entity : &vsp1->brs->entity; + pipe->lif = &vsp1->lif[i]->entity; + pipe->output = vsp1->wpf[i]; + pipe->output->pipe = pipe; + pipe->frame_end = vsp1_du_pipeline_frame_end; + + pipe->bru->sink = &pipe->output->entity; + pipe->bru->sink_pad = 0; + pipe->output->entity.sink = pipe->lif; + pipe->output->entity.sink_pad = 0; + + list_add_tail(&pipe->bru->list_pipe, &pipe->entities); + list_add_tail(&pipe->lif->list_pipe, &pipe->entities); + list_add_tail(&pipe->output->entity.list_pipe, &pipe->entities); + } + + /* Disable all RPFs initially. */ for (i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *input = vsp1->rpf[i]; - list_add_tail(&input->entity.list_pipe, &pipe->entities); + INIT_LIST_HEAD(&input->entity.list_pipe); } - list_add_tail(&vsp1->bru->entity.list_pipe, &pipe->entities); - list_add_tail(&vsp1->wpf[0]->entity.list_pipe, &pipe->entities); - list_add_tail(&vsp1->lif->entity.list_pipe, &pipe->entities); - - pipe->bru = &vsp1->bru->entity; - pipe->lif = &vsp1->lif->entity; - pipe->output = vsp1->wpf[0]; - pipe->output->pipe = pipe; - pipe->frame_end = vsp1_du_pipeline_frame_end; - return 0; } diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h index e9f80727ff92..1cd9db785bf7 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.h +++ b/drivers/media/platform/vsp1/vsp1_drm.h @@ -18,38 +18,44 @@ #include "vsp1_pipe.h" /** - * vsp1_drm - State for the API exposed to the DRM driver + * vsp1_drm_pipeline - State for the API exposed to the DRM driver * @pipe: the VSP1 pipeline used for display - * @num_inputs: number of active pipeline inputs at the beginning of an update - * @inputs: source crop rectangle, destination compose rectangle and z-order - * position for every input + * @enabled: pipeline state at the beginning of an update * @du_complete: frame completion callback for the DU driver (optional) * @du_private: data to be passed to the du_complete callback */ -struct vsp1_drm { +struct vsp1_drm_pipeline { struct vsp1_pipeline pipe; - unsigned int num_inputs; + bool enabled; + + /* Frame synchronisation */ + void (*du_complete)(void *, bool); + void *du_private; +}; + +/** + * vsp1_drm - State for the API exposed to the DRM driver + * @pipe: the VSP1 DRM pipeline used for display + * @inputs: source crop rectangle, destination compose rectangle and z-order + * position for every input (indexed by RPF index) + */ +struct vsp1_drm { + struct vsp1_drm_pipeline pipe[VSP1_MAX_LIF]; + struct { - bool enabled; struct v4l2_rect crop; struct v4l2_rect compose; unsigned int zpos; } inputs[VSP1_MAX_RPF]; - - /* Frame synchronisation */ - void (*du_complete)(void *); - void *du_private; }; -static inline struct vsp1_drm *to_vsp1_drm(struct vsp1_pipeline *pipe) +static inline struct vsp1_drm_pipeline * +to_vsp1_drm_pipeline(struct vsp1_pipeline *pipe) { - return container_of(pipe, struct vsp1_drm, pipe); + return container_of(pipe, struct vsp1_drm_pipeline, pipe); } int vsp1_drm_init(struct vsp1_device *vsp1); void vsp1_drm_cleanup(struct vsp1_device *vsp1); -int vsp1_drm_create_links(struct vsp1_device *vsp1); - -void vsp1_drm_display_start(struct vsp1_device *vsp1); #endif /* __VSP1_DRM_H__ */ diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 95c26edead85..962e4c304076 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -68,14 +68,6 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data) } } - status = vsp1_read(vsp1, VI6_DISP_IRQ_STA); - vsp1_write(vsp1, VI6_DISP_IRQ_STA, ~status & VI6_DISP_IRQ_STA_DST); - - if (status & VI6_DISP_IRQ_STA_DST) { - vsp1_drm_display_start(vsp1); - ret = IRQ_HANDLED; - } - return ret; } @@ -92,6 +84,10 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data) * * - from a UDS to a UDS (UDS entities can't be chained) * - from an entity to itself (no loops are allowed) + * + * Furthermore, the BRS can't be connected to histogram generators, but no + * special check is currently needed as all VSP instances that include a BRS + * have no histogram generator. */ static int vsp1_create_sink_links(struct vsp1_device *vsp1, struct vsp1_entity *sink) @@ -129,7 +125,7 @@ static int vsp1_create_sink_links(struct vsp1_device *vsp1, return ret; if (flags & MEDIA_LNK_FL_ENABLED) - source->sink = entity; + source->sink = sink; } } @@ -172,10 +168,13 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) return ret; } - if (vsp1->lif) { - ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity, + for (i = 0; i < vsp1->info->lif_count; ++i) { + if (!vsp1->lif[i]) + continue; + + ret = media_create_pad_link(&vsp1->wpf[i]->entity.subdev.entity, RWPF_PAD_SOURCE, - &vsp1->lif->entity.subdev.entity, + &vsp1->lif[i]->entity.subdev.entity, LIF_PAD_SINK, 0); if (ret < 0) return ret; @@ -269,8 +268,18 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) } /* Instantiate all the entities. */ + if (vsp1->info->features & VSP1_HAS_BRS) { + vsp1->brs = vsp1_bru_create(vsp1, VSP1_ENTITY_BRS); + if (IS_ERR(vsp1->brs)) { + ret = PTR_ERR(vsp1->brs); + goto done; + } + + list_add_tail(&vsp1->brs->entity.list_dev, &vsp1->entities); + } + if (vsp1->info->features & VSP1_HAS_BRU) { - vsp1->bru = vsp1_bru_create(vsp1); + vsp1->bru = vsp1_bru_create(vsp1, VSP1_ENTITY_BRU); if (IS_ERR(vsp1->bru)) { ret = PTR_ERR(vsp1->bru); goto done; @@ -328,18 +337,23 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) } /* - * The LIF is only supported when used in conjunction with the DU, in + * The LIFs are only supported when used in conjunction with the DU, in * which case the userspace API is disabled. If the userspace API is - * enabled skip the LIF, even when present. + * enabled skip the LIFs, even when present. */ - if (vsp1->info->features & VSP1_HAS_LIF && !vsp1->info->uapi) { - vsp1->lif = vsp1_lif_create(vsp1); - if (IS_ERR(vsp1->lif)) { - ret = PTR_ERR(vsp1->lif); - goto done; - } + if (!vsp1->info->uapi) { + for (i = 0; i < vsp1->info->lif_count; ++i) { + struct vsp1_lif *lif; + + lif = vsp1_lif_create(vsp1, i); + if (IS_ERR(lif)) { + ret = PTR_ERR(lif); + goto done; + } - list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities); + vsp1->lif[i] = lif; + list_add_tail(&lif->entity.list_dev, &vsp1->entities); + } } if (vsp1->info->features & VSP1_HAS_LUT) { @@ -420,7 +434,6 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) } list_add_tail(&video->list, &vsp1->videos); - wpf->entity.sink = &video->video.entity; } } @@ -432,19 +445,15 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) goto done; } - /* Create links. */ - if (vsp1->info->uapi) - ret = vsp1_uapi_create_links(vsp1); - else - ret = vsp1_drm_create_links(vsp1); - if (ret < 0) - goto done; - /* - * Register subdev nodes if the userspace API is enabled or initialize - * the DRM pipeline otherwise. + * Create links and register subdev nodes if the userspace API is + * enabled or initialize the DRM pipeline otherwise. */ if (vsp1->info->uapi) { + ret = vsp1_uapi_create_links(vsp1); + if (ret < 0) + goto done; + ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev); if (ret < 0) goto done; @@ -515,6 +524,9 @@ static int vsp1_device_init(struct vsp1_device *vsp1) vsp1_write(vsp1, VI6_DPR_HSI_ROUTE, VI6_DPR_NODE_UNUSED); vsp1_write(vsp1, VI6_DPR_BRU_ROUTE, VI6_DPR_NODE_UNUSED); + if (vsp1->info->features & VSP1_HAS_BRS) + vsp1_write(vsp1, VI6_DPR_ILV_BRS_ROUTE, VI6_DPR_NODE_UNUSED); + vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) | (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) | @@ -634,8 +646,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = { .version = VI6_IP_VERSION_MODEL_VSPD_GEN2, .model = "VSP1-D", .gen = 2, - .features = VSP1_HAS_BRU | VSP1_HAS_HGO | VSP1_HAS_LIF - | VSP1_HAS_LUT, + .features = VSP1_HAS_BRU | VSP1_HAS_HGO | VSP1_HAS_LUT, + .lif_count = 1, .rpf_count = 4, .uds_count = 1, .wpf_count = 1, @@ -668,8 +680,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = { .version = VI6_IP_VERSION_MODEL_VSPD_V2H, .model = "VSP1V-D", .gen = 2, - .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT - | VSP1_HAS_LIF, + .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT, + .lif_count = 1, .rpf_count = 4, .uds_count = 1, .wpf_count = 1, @@ -706,10 +718,37 @@ static const struct vsp1_device_info vsp1_device_infos[] = { .num_bru_inputs = 5, .uapi = true, }, { + .version = VI6_IP_VERSION_MODEL_VSPBS_GEN3, + .model = "VSP2-BS", + .gen = 3, + .features = VSP1_HAS_BRS | VSP1_HAS_WPF_VFLIP, + .rpf_count = 2, + .wpf_count = 1, + .uapi = true, + }, { .version = VI6_IP_VERSION_MODEL_VSPD_GEN3, .model = "VSP2-D", .gen = 3, - .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_WPF_VFLIP, + .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP, + .lif_count = 1, + .rpf_count = 5, + .wpf_count = 2, + .num_bru_inputs = 5, + }, { + .version = VI6_IP_VERSION_MODEL_VSPD_V3, + .model = "VSP2-D", + .gen = 3, + .features = VSP1_HAS_BRS | VSP1_HAS_BRU, + .lif_count = 1, + .rpf_count = 5, + .wpf_count = 1, + .num_bru_inputs = 5, + }, { + .version = VI6_IP_VERSION_MODEL_VSPDL_GEN3, + .model = "VSP2-DL", + .gen = 3, + .features = VSP1_HAS_BRS | VSP1_HAS_BRU, + .lif_count = 2, .rpf_count = 5, .wpf_count = 2, .num_bru_inputs = 5, diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 4bdb3b141611..54de15095709 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -24,18 +24,12 @@ #include "vsp1_pipe.h" #include "vsp1_rwpf.h" -static inline struct vsp1_entity * -media_entity_to_vsp1_entity(struct media_entity *entity) -{ - return container_of(entity, struct vsp1_entity, subdev.entity); -} - void vsp1_entity_route_setup(struct vsp1_entity *entity, struct vsp1_pipeline *pipe, struct vsp1_dl_list *dl) { struct vsp1_entity *source; - struct vsp1_entity *sink; + u32 route; if (entity->type == VSP1_ENTITY_HGO) { u32 smppt; @@ -44,7 +38,7 @@ void vsp1_entity_route_setup(struct vsp1_entity *entity, * The HGO is a special case, its routing is configured on the * sink pad. */ - source = media_entity_to_vsp1_entity(entity->sources[0]); + source = entity->sources[0]; smppt = (pipe->output->entity.index << VI6_DPR_SMPPT_TGW_SHIFT) | (source->route->output << VI6_DPR_SMPPT_PT_SHIFT); @@ -57,7 +51,7 @@ void vsp1_entity_route_setup(struct vsp1_entity *entity, * The HGT is a special case, its routing is configured on the * sink pad. */ - source = media_entity_to_vsp1_entity(entity->sources[0]); + source = entity->sources[0]; smppt = (pipe->output->entity.index << VI6_DPR_SMPPT_TGW_SHIFT) | (source->route->output << VI6_DPR_SMPPT_PT_SHIFT); @@ -69,9 +63,14 @@ void vsp1_entity_route_setup(struct vsp1_entity *entity, if (source->route->reg == 0) return; - sink = media_entity_to_vsp1_entity(source->sink); - vsp1_dl_list_write(dl, source->route->reg, - sink->route->inputs[source->sink_pad]); + route = source->sink->route->inputs[source->sink_pad]; + /* + * The ILV and BRS share the same data path route. The extra BRSSEL bit + * selects between the ILV and BRS. + */ + if (source->type == VSP1_ENTITY_BRS) + route |= VI6_DPR_ROUTE_BRSSEL; + vsp1_dl_list_write(dl, source->route->reg, route); } /* ----------------------------------------------------------------------------- @@ -316,6 +315,12 @@ done: * Media Operations */ +static inline struct vsp1_entity * +media_entity_to_vsp1_entity(struct media_entity *entity) +{ + return container_of(entity, struct vsp1_entity, subdev.entity); +} + static int vsp1_entity_link_setup_source(const struct media_pad *source_pad, const struct media_pad *sink_pad, u32 flags) @@ -339,7 +344,7 @@ static int vsp1_entity_link_setup_source(const struct media_pad *source_pad, sink->type != VSP1_ENTITY_HGT) { if (source->sink) return -EBUSY; - source->sink = sink_pad->entity; + source->sink = sink; source->sink_pad = sink_pad->index; } } else { @@ -355,15 +360,17 @@ static int vsp1_entity_link_setup_sink(const struct media_pad *source_pad, u32 flags) { struct vsp1_entity *sink; + struct vsp1_entity *source; sink = media_entity_to_vsp1_entity(sink_pad->entity); + source = media_entity_to_vsp1_entity(source_pad->entity); if (flags & MEDIA_LNK_FL_ENABLED) { /* Fan-in is limited to one. */ if (sink->sources[sink_pad->index]) return -EBUSY; - sink->sources[sink_pad->index] = source_pad->entity; + sink->sources[sink_pad->index] = source; } else { sink->sources[sink_pad->index] = NULL; } @@ -450,6 +457,8 @@ struct media_pad *vsp1_entity_remote_pad(struct media_pad *pad) { VI6_DPR_NODE_WPF(idx) }, VI6_DPR_NODE_WPF(idx) } static const struct vsp1_route vsp1_routes[] = { + { VSP1_ENTITY_BRS, 0, VI6_DPR_ILV_BRS_ROUTE, + { VI6_DPR_NODE_BRS_IN(0), VI6_DPR_NODE_BRS_IN(1) }, 0 }, { VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE, { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1), VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), @@ -459,7 +468,8 @@ static const struct vsp1_route vsp1_routes[] = { { VSP1_ENTITY_HGT, 0, 0, { 0, }, 0 }, VSP1_ENTITY_ROUTE(HSI), VSP1_ENTITY_ROUTE(HST), - { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, }, VI6_DPR_NODE_LIF }, + { VSP1_ENTITY_LIF, 0, 0, { 0, }, 0 }, + { VSP1_ENTITY_LIF, 1, 0, { 0, }, 0 }, VSP1_ENTITY_ROUTE(LUT), VSP1_ENTITY_ROUTE_RPF(0), VSP1_ENTITY_ROUTE_RPF(1), diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index c169a060b6d2..408602ebeb97 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -21,8 +21,11 @@ struct vsp1_device; struct vsp1_dl_list; struct vsp1_pipeline; +struct vsp1_partition; +struct vsp1_partition_window; enum vsp1_entity_type { + VSP1_ENTITY_BRS, VSP1_ENTITY_BRU, VSP1_ENTITY_CLU, VSP1_ENTITY_HGO, @@ -81,12 +84,17 @@ struct vsp1_route { * selection rectangles, ...) * @max_width: Return the max supported width of data that the entity can * process in a single operation. + * @partition: Process the partition construction based on this entity's + * configuration. */ struct vsp1_entity_operations { void (*destroy)(struct vsp1_entity *); void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *, struct vsp1_dl_list *, enum vsp1_entity_params); unsigned int (*max_width)(struct vsp1_entity *, struct vsp1_pipeline *); + void (*partition)(struct vsp1_entity *, struct vsp1_pipeline *, + struct vsp1_partition *, unsigned int, + struct vsp1_partition_window *); }; struct vsp1_entity { @@ -104,8 +112,8 @@ struct vsp1_entity { struct media_pad *pads; unsigned int source_pad; - struct media_entity **sources; - struct media_entity *sink; + struct vsp1_entity **sources; + struct vsp1_entity *sink; unsigned int sink_pad; struct v4l2_subdev subdev; diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index 702487f895b3..e6fa16d7fda8 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -30,7 +30,7 @@ static inline void vsp1_lif_write(struct vsp1_lif *lif, struct vsp1_dl_list *dl, u32 reg, u32 data) { - vsp1_dl_list_write(dl, reg, data); + vsp1_dl_list_write(dl, reg + lif->entity.index * VI6_LIF_OFFSET, data); } /* ----------------------------------------------------------------------------- @@ -165,7 +165,7 @@ static const struct vsp1_entity_operations lif_entity_ops = { * Initialization and Cleanup */ -struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1) +struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1, unsigned int index) { struct vsp1_lif *lif; int ret; @@ -176,6 +176,7 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1) lif->entity.ops = &lif_entity_ops; lif->entity.type = VSP1_ENTITY_LIF; + lif->entity.index = index; /* * The LIF is never exposed to userspace, but media entity registration diff --git a/drivers/media/platform/vsp1/vsp1_lif.h b/drivers/media/platform/vsp1/vsp1_lif.h index 7b35879028de..3417339379b1 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.h +++ b/drivers/media/platform/vsp1/vsp1_lif.h @@ -32,6 +32,6 @@ static inline struct vsp1_lif *to_lif(struct v4l2_subdev *subdev) return container_of(subdev, struct vsp1_lif, entity.subdev); } -struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1); +struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1, unsigned int index); #endif /* __VSP1_LIF_H__ */ diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index e817623b84e0..44944ac86d9b 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c @@ -335,16 +335,12 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) if (pipe == NULL) return; + /* + * If the DL commit raced with the frame end interrupt, the commit ends + * up being postponed by one frame. @completed represents whether the + * active frame was finished or postponed. + */ completed = vsp1_dlm_irq_frame_end(pipe->output->dlm); - if (!completed) { - /* - * If the DL commit raced with the frame end interrupt, the - * commit ends up being postponed by one frame. Return - * immediately without calling the pipeline's frame end handler - * or incrementing the sequence number. - */ - return; - } if (pipe->hgo) vsp1_hgo_frame_end(pipe->hgo); @@ -352,8 +348,12 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) if (pipe->hgt) vsp1_hgt_frame_end(pipe->hgt); + /* + * Regardless of frame completion we still need to notify the pipe + * frame_end to account for vblank events. + */ if (pipe->frame_end) - pipe->frame_end(pipe); + pipe->frame_end(pipe, completed); pipe->sequence++; } @@ -373,15 +373,38 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, return; /* - * The BRU background color has a fixed alpha value set to 255, the - * output alpha value is thus always equal to 255. + * The BRU and BRS background color has a fixed alpha value set to 255, + * the output alpha value is thus always equal to 255. */ - if (pipe->uds_input->type == VSP1_ENTITY_BRU) + if (pipe->uds_input->type == VSP1_ENTITY_BRU || + pipe->uds_input->type == VSP1_ENTITY_BRS) alpha = 255; vsp1_uds_set_alpha(pipe->uds, dl, alpha); } +/* + * Propagate the partition calculations through the pipeline + * + * Work backwards through the pipe, allowing each entity to update the partition + * parameters based on its configuration, and the entity connected to its + * source. Each entity must produce the partition required for the previous + * entity in the pipeline. + */ +void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe, + struct vsp1_partition *partition, + unsigned int index, + struct vsp1_partition_window *window) +{ + struct vsp1_entity *entity; + + list_for_each_entry_reverse(entity, &pipe->entities, list_pipe) { + if (entity->ops->partition) + entity->ops->partition(entity, pipe, partition, index, + window); + } +} + void vsp1_pipelines_suspend(struct vsp1_device *vsp1) { unsigned long flags; diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h index 91a784a13422..dfff9b5685fe 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.h +++ b/drivers/media/platform/vsp1/vsp1_pipe.h @@ -58,6 +58,33 @@ enum vsp1_pipeline_state { }; /* + * struct vsp1_partition_window - Partition window coordinates + * @left: horizontal coordinate of the partition start in pixels relative to the + * left edge of the image + * @width: partition width in pixels + */ +struct vsp1_partition_window { + unsigned int left; + unsigned int width; +}; + +/* + * struct vsp1_partition - A description of a slice for the partition algorithm + * @rpf: The RPF partition window configuration + * @uds_sink: The UDS input partition window configuration + * @uds_source: The UDS output partition window configuration + * @sru: The SRU partition window configuration + * @wpf: The WPF partition window configuration + */ +struct vsp1_partition { + struct vsp1_partition_window rpf; + struct vsp1_partition_window uds_sink; + struct vsp1_partition_window uds_source; + struct vsp1_partition_window sru; + struct vsp1_partition_window wpf; +}; + +/* * struct vsp1_pipeline - A VSP1 hardware pipeline * @pipe: the media pipeline * @irqlock: protects the pipeline state @@ -80,9 +107,9 @@ enum vsp1_pipeline_state { * @uds_input: entity at the input of the UDS, if the UDS is present * @entities: list of entities in the pipeline * @dl: display list associated with the pipeline - * @div_size: The maximum allowed partition size for the pipeline * @partitions: The number of partitions used to process one frame - * @current_partition: The partition number currently being configured + * @partition: The current partition for configuration to process + * @part_table: The pre-calculated partitions used by the pipeline */ struct vsp1_pipeline { struct media_pipeline pipe; @@ -91,7 +118,7 @@ struct vsp1_pipeline { enum vsp1_pipeline_state state; wait_queue_head_t wq; - void (*frame_end)(struct vsp1_pipeline *pipe); + void (*frame_end)(struct vsp1_pipeline *pipe, bool completed); struct mutex lock; struct kref kref; @@ -109,14 +136,18 @@ struct vsp1_pipeline { struct vsp1_entity *uds; struct vsp1_entity *uds_input; + /* + * The order of this list must be identical to the order of the entities + * in the pipeline, as it is assumed by the partition algorithm that we + * can walk this list in sequence. + */ struct list_head entities; struct vsp1_dl_list *dl; - unsigned int div_size; unsigned int partitions; - struct v4l2_rect partition; - unsigned int current_partition; + struct vsp1_partition *partition; + struct vsp1_partition *part_table; }; void vsp1_pipeline_reset(struct vsp1_pipeline *pipe); @@ -132,6 +163,11 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe); void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, struct vsp1_dl_list *dl, unsigned int alpha); +void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe, + struct vsp1_partition *partition, + unsigned int index, + struct vsp1_partition_window *window); + void vsp1_pipelines_suspend(struct vsp1_device *vsp1); void vsp1_pipelines_resume(struct vsp1_device *vsp1); diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index cd3e32af6e3b..26c4ffad2f46 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -18,6 +18,7 @@ */ #define VI6_CMD(n) (0x0000 + (n) * 4) +#define VI6_CMD_UPDHDR (1 << 4) #define VI6_CMD_STRCMD (1 << 0) #define VI6_CLK_DCSWT 0x0018 @@ -238,6 +239,10 @@ #define VI6_WPF_SRCRPF_VIRACT_SUB (1 << 28) #define VI6_WPF_SRCRPF_VIRACT_MST (2 << 28) #define VI6_WPF_SRCRPF_VIRACT_MASK (3 << 28) +#define VI6_WPF_SRCRPF_VIRACT2_DIS (0 << 24) +#define VI6_WPF_SRCRPF_VIRACT2_SUB (1 << 24) +#define VI6_WPF_SRCRPF_VIRACT2_MST (2 << 24) +#define VI6_WPF_SRCRPF_VIRACT2_MASK (3 << 24) #define VI6_WPF_SRCRPF_RPF_ACT_DIS(n) (0 << ((n) * 2)) #define VI6_WPF_SRCRPF_RPF_ACT_SUB(n) (1 << ((n) * 2)) #define VI6_WPF_SRCRPF_RPF_ACT_MST(n) (2 << ((n) * 2)) @@ -321,6 +326,8 @@ #define VI6_DPR_HST_ROUTE 0x2044 #define VI6_DPR_HSI_ROUTE 0x2048 #define VI6_DPR_BRU_ROUTE 0x204c +#define VI6_DPR_ILV_BRS_ROUTE 0x2050 +#define VI6_DPR_ROUTE_BRSSEL (1 << 28) #define VI6_DPR_ROUTE_FXA_MASK (0xff << 16) #define VI6_DPR_ROUTE_FXA_SHIFT 16 #define VI6_DPR_ROUTE_FP_MASK (0x3f << 8) @@ -344,7 +351,8 @@ #define VI6_DPR_NODE_CLU 29 #define VI6_DPR_NODE_HST 30 #define VI6_DPR_NODE_HSI 31 -#define VI6_DPR_NODE_LIF 55 +#define VI6_DPR_NODE_BRS_IN(n) (38 + (n)) +#define VI6_DPR_NODE_LIF 55 /* Gen2 only */ #define VI6_DPR_NODE_WPF(n) (56 + (n)) #define VI6_DPR_NODE_UNUSED 63 @@ -388,6 +396,7 @@ #define VI6_UDS_CTRL_NE_RCR (1 << 18) #define VI6_UDS_CTRL_NE_GY (1 << 17) #define VI6_UDS_CTRL_NE_BCB (1 << 16) +#define VI6_UDS_CTRL_AMDSLH (1 << 2) #define VI6_UDS_CTRL_TDIPC (1 << 1) #define VI6_UDS_SCALE 0x2304 @@ -420,11 +429,24 @@ #define VI6_UDS_PASS_BWIDTH_V_MASK (0x7f << 0) #define VI6_UDS_PASS_BWIDTH_V_SHIFT 0 +#define VI6_UDS_HPHASE 0x2314 +#define VI6_UDS_HPHASE_HSTP_MASK (0xfff << 16) +#define VI6_UDS_HPHASE_HSTP_SHIFT 16 +#define VI6_UDS_HPHASE_HEDP_MASK (0xfff << 0) +#define VI6_UDS_HPHASE_HEDP_SHIFT 0 + #define VI6_UDS_IPC 0x2318 #define VI6_UDS_IPC_FIELD (1 << 27) #define VI6_UDS_IPC_VEDP_MASK (0xfff << 0) #define VI6_UDS_IPC_VEDP_SHIFT 0 +#define VI6_UDS_HSZCLIP 0x231c +#define VI6_UDS_HSZCLIP_HCEN (1 << 28) +#define VI6_UDS_HSZCLIP_HCL_OFST_MASK (0xff << 16) +#define VI6_UDS_HSZCLIP_HCL_OFST_SHIFT 16 +#define VI6_UDS_HSZCLIP_HCL_SIZE_MASK (0x1fff << 0) +#define VI6_UDS_HSZCLIP_HCL_SIZE_SHIFT 0 + #define VI6_UDS_CLIP_SIZE 0x2324 #define VI6_UDS_CLIP_SIZE_HSIZE_MASK (0x1fff << 16) #define VI6_UDS_CLIP_SIZE_HSIZE_SHIFT 16 @@ -476,7 +498,7 @@ #define VI6_HSI_CTRL_EN (1 << 0) /* ----------------------------------------------------------------------------- - * BRU Control Registers + * BRS and BRU Control Registers */ #define VI6_ROP_NOP 0 @@ -496,7 +518,10 @@ #define VI6_ROP_NAND 14 #define VI6_ROP_SET 15 -#define VI6_BRU_INCTRL 0x2c00 +#define VI6_BRU_BASE 0x2c00 +#define VI6_BRS_BASE 0x3900 + +#define VI6_BRU_INCTRL 0x0000 #define VI6_BRU_INCTRL_NRM (1 << 28) #define VI6_BRU_INCTRL_DnON (1 << (16 + (n))) #define VI6_BRU_INCTRL_DITHn_OFF (0 << ((n) * 4)) @@ -508,19 +533,19 @@ #define VI6_BRU_INCTRL_DITHn_MASK (7 << ((n) * 4)) #define VI6_BRU_INCTRL_DITHn_SHIFT ((n) * 4) -#define VI6_BRU_VIRRPF_SIZE 0x2c04 +#define VI6_BRU_VIRRPF_SIZE 0x0004 #define VI6_BRU_VIRRPF_SIZE_HSIZE_MASK (0x1fff << 16) #define VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT 16 #define VI6_BRU_VIRRPF_SIZE_VSIZE_MASK (0x1fff << 0) #define VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT 0 -#define VI6_BRU_VIRRPF_LOC 0x2c08 +#define VI6_BRU_VIRRPF_LOC 0x0008 #define VI6_BRU_VIRRPF_LOC_HCOORD_MASK (0x1fff << 16) #define VI6_BRU_VIRRPF_LOC_HCOORD_SHIFT 16 #define VI6_BRU_VIRRPF_LOC_VCOORD_MASK (0x1fff << 0) #define VI6_BRU_VIRRPF_LOC_VCOORD_SHIFT 0 -#define VI6_BRU_VIRRPF_COL 0x2c0c +#define VI6_BRU_VIRRPF_COL 0x000c #define VI6_BRU_VIRRPF_COL_A_MASK (0xff << 24) #define VI6_BRU_VIRRPF_COL_A_SHIFT 24 #define VI6_BRU_VIRRPF_COL_RCR_MASK (0xff << 16) @@ -530,7 +555,7 @@ #define VI6_BRU_VIRRPF_COL_BCB_MASK (0xff << 0) #define VI6_BRU_VIRRPF_COL_BCB_SHIFT 0 -#define VI6_BRU_CTRL(n) (0x2c10 + (n) * 8 + ((n) <= 3 ? 0 : 4)) +#define VI6_BRU_CTRL(n) (0x0010 + (n) * 8 + ((n) <= 3 ? 0 : 4)) #define VI6_BRU_CTRL_RBC (1 << 31) #define VI6_BRU_CTRL_DSTSEL_BRUIN(n) (((n) <= 3 ? (n) : (n)+1) << 20) #define VI6_BRU_CTRL_DSTSEL_VRPF (4 << 20) @@ -543,7 +568,7 @@ #define VI6_BRU_CTRL_AROP(rop) ((rop) << 0) #define VI6_BRU_CTRL_AROP_MASK (0xf << 0) -#define VI6_BRU_BLD(n) (0x2c14 + (n) * 8 + ((n) <= 3 ? 0 : 4)) +#define VI6_BRU_BLD(n) (0x0014 + (n) * 8 + ((n) <= 3 ? 0 : 4)) #define VI6_BRU_BLD_CBES (1 << 31) #define VI6_BRU_BLD_CCMDX_DST_A (0 << 28) #define VI6_BRU_BLD_CCMDX_255_DST_A (1 << 28) @@ -576,7 +601,7 @@ #define VI6_BRU_BLD_COEFY_MASK (0xff << 0) #define VI6_BRU_BLD_COEFY_SHIFT 0 -#define VI6_BRU_ROP 0x2c30 +#define VI6_BRU_ROP 0x0030 /* Only available on BRU */ #define VI6_BRU_ROP_DSTSEL_BRUIN(n) (((n) <= 3 ? (n) : (n)+1) << 20) #define VI6_BRU_ROP_DSTSEL_VRPF (4 << 20) #define VI6_BRU_ROP_DSTSEL_MASK (7 << 20) @@ -653,6 +678,8 @@ * LIF Control Registers */ +#define VI6_LIF_OFFSET (-0x100) + #define VI6_LIF_CTRL 0x3b00 #define VI6_LIF_CTRL_OBTH_MASK (0x7ff << 16) #define VI6_LIF_CTRL_OBTH_SHIFT 16 @@ -689,9 +716,20 @@ #define VI6_IP_VERSION_MODEL_VSPBD_GEN3 (0x15 << 8) #define VI6_IP_VERSION_MODEL_VSPBC_GEN3 (0x16 << 8) #define VI6_IP_VERSION_MODEL_VSPD_GEN3 (0x17 << 8) +#define VI6_IP_VERSION_MODEL_VSPD_V3 (0x18 << 8) +#define VI6_IP_VERSION_MODEL_VSPDL_GEN3 (0x19 << 8) +#define VI6_IP_VERSION_MODEL_VSPBS_GEN3 (0x1a << 8) #define VI6_IP_VERSION_SOC_MASK (0xff << 0) -#define VI6_IP_VERSION_SOC_H (0x01 << 0) -#define VI6_IP_VERSION_SOC_M (0x02 << 0) +#define VI6_IP_VERSION_SOC_H2 (0x01 << 0) +#define VI6_IP_VERSION_SOC_V2H (0x01 << 0) +#define VI6_IP_VERSION_SOC_V3M (0x01 << 0) +#define VI6_IP_VERSION_SOC_M2 (0x02 << 0) +#define VI6_IP_VERSION_SOC_M3W (0x02 << 0) +#define VI6_IP_VERSION_SOC_V3H (0x02 << 0) +#define VI6_IP_VERSION_SOC_H3 (0x03 << 0) +#define VI6_IP_VERSION_SOC_D3 (0x04 << 0) +#define VI6_IP_VERSION_SOC_M3N (0x04 << 0) +#define VI6_IP_VERSION_SOC_E3 (0x04 << 0) /* ----------------------------------------------------------------------------- * RPF CLUT Registers diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 8feddd59cf8d..fe0633da5a5f 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -97,21 +97,8 @@ static void rpf_configure(struct vsp1_entity *entity, * 'width' need to be adjusted. */ if (pipe->partitions > 1) { - const struct v4l2_mbus_framefmt *output; - struct vsp1_entity *wpf = &pipe->output->entity; - unsigned int input_width = crop.width; - - /* - * Scale the partition window based on the configuration - * of the pipeline. - */ - output = vsp1_entity_get_pad_format(wpf, wpf->config, - RWPF_PAD_SINK); - - crop.width = pipe->partition.width * input_width - / output->width; - crop.left += pipe->partition.left * input_width - / output->width; + crop.width = pipe->partition->rpf.width; + crop.left += pipe->partition->rpf.left; } vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE, @@ -260,8 +247,18 @@ static void rpf_configure(struct vsp1_entity *entity, } +static void rpf_partition(struct vsp1_entity *entity, + struct vsp1_pipeline *pipe, + struct vsp1_partition *partition, + unsigned int partition_idx, + struct vsp1_partition_window *window) +{ + partition->rpf = *window; +} + static const struct vsp1_entity_operations rpf_entity_ops = { .configure = rpf_configure, + .partition = rpf_partition, }; /* ----------------------------------------------------------------------------- diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index 30142793dfcd..51e5691187c3 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c @@ -18,6 +18,7 @@ #include "vsp1.h" #include "vsp1_dl.h" +#include "vsp1_pipe.h" #include "vsp1_sru.h" #define SRU_MIN_SIZE 4U @@ -325,9 +326,34 @@ static unsigned int sru_max_width(struct vsp1_entity *entity, return 256; } +static void sru_partition(struct vsp1_entity *entity, + struct vsp1_pipeline *pipe, + struct vsp1_partition *partition, + unsigned int partition_idx, + struct vsp1_partition_window *window) +{ + struct vsp1_sru *sru = to_sru(&entity->subdev); + struct v4l2_mbus_framefmt *input; + struct v4l2_mbus_framefmt *output; + + input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, + SRU_PAD_SINK); + output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, + SRU_PAD_SOURCE); + + /* Adapt if SRUx2 is enabled */ + if (input->width != output->width) { + window->width /= 2; + window->left /= 2; + } + + partition->sru = *window; +} + static const struct vsp1_entity_operations sru_entity_ops = { .configure = sru_configure, .max_width = sru_max_width, + .partition = sru_partition, }; /* ----------------------------------------------------------------------------- diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index 4226403ad235..72f72a9d2152 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c @@ -271,23 +271,32 @@ static void uds_configure(struct vsp1_entity *entity, unsigned int vscale; bool multitap; + input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, + UDS_PAD_SINK); + output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, + UDS_PAD_SOURCE); + if (params == VSP1_ENTITY_PARAMS_PARTITION) { - const struct v4l2_rect *clip = &pipe->partition; + struct vsp1_partition *partition = pipe->partition; + + /* Input size clipping */ + vsp1_uds_write(uds, dl, VI6_UDS_HSZCLIP, VI6_UDS_HSZCLIP_HCEN | + (0 << VI6_UDS_HSZCLIP_HCL_OFST_SHIFT) | + (partition->uds_sink.width + << VI6_UDS_HSZCLIP_HCL_SIZE_SHIFT)); + /* Output size clipping */ vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE, - (clip->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | - (clip->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); + (partition->uds_source.width + << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) | + (output->height + << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT)); return; } if (params != VSP1_ENTITY_PARAMS_INIT) return; - input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, - UDS_PAD_SINK); - output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, - UDS_PAD_SOURCE); - hscale = uds_compute_ratio(input->width, output->width); vscale = uds_compute_ratio(input->height, output->height); @@ -343,9 +352,41 @@ static unsigned int uds_max_width(struct vsp1_entity *entity, return 2048; } +/* ----------------------------------------------------------------------------- + * Partition Algorithm Support + */ + +static void uds_partition(struct vsp1_entity *entity, + struct vsp1_pipeline *pipe, + struct vsp1_partition *partition, + unsigned int partition_idx, + struct vsp1_partition_window *window) +{ + struct vsp1_uds *uds = to_uds(&entity->subdev); + const struct v4l2_mbus_framefmt *output; + const struct v4l2_mbus_framefmt *input; + + /* Initialise the partition state */ + partition->uds_sink = *window; + partition->uds_source = *window; + + input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, + UDS_PAD_SINK); + output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, + UDS_PAD_SOURCE); + + partition->uds_sink.width = window->width * input->width + / output->width; + partition->uds_sink.left = window->left * input->width + / output->width; + + *window = partition->uds_sink; +} + static const struct vsp1_entity_operations uds_entity_ops = { .configure = uds_configure, .max_width = uds_max_width, + .partition = uds_partition, }; /* ----------------------------------------------------------------------------- diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 5af3486afe07..c2d3b8f0f487 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -182,57 +182,21 @@ static int __vsp1_video_try_format(struct vsp1_video *video, * VSP1 Partition Algorithm support */ -static void vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe) -{ - struct vsp1_device *vsp1 = pipe->output->entity.vsp1; - const struct v4l2_mbus_framefmt *format; - struct vsp1_entity *entity; - unsigned int div_size; - - /* - * Partitions are computed on the size before rotation, use the format - * at the WPF sink. - */ - format = vsp1_entity_get_pad_format(&pipe->output->entity, - pipe->output->entity.config, - RWPF_PAD_SINK); - div_size = format->width; - - /* Gen2 hardware doesn't require image partitioning. */ - if (vsp1->info->gen == 2) { - pipe->div_size = div_size; - pipe->partitions = 1; - return; - } - - list_for_each_entry(entity, &pipe->entities, list_pipe) { - unsigned int entity_max = VSP1_VIDEO_MAX_WIDTH; - - if (entity->ops->max_width) { - entity_max = entity->ops->max_width(entity, pipe); - if (entity_max) - div_size = min(div_size, entity_max); - } - } - - pipe->div_size = div_size; - pipe->partitions = DIV_ROUND_UP(format->width, div_size); -} - /** - * vsp1_video_partition - Calculate the active partition output window + * vsp1_video_calculate_partition - Calculate the active partition output window * + * @pipe: the pipeline + * @partition: partition that will hold the calculated values * @div_size: pre-determined maximum partition division size * @index: partition index - * - * Returns a v4l2_rect describing the partition window. */ -static struct v4l2_rect vsp1_video_partition(struct vsp1_pipeline *pipe, - unsigned int div_size, - unsigned int index) +static void vsp1_video_calculate_partition(struct vsp1_pipeline *pipe, + struct vsp1_partition *partition, + unsigned int div_size, + unsigned int index) { const struct v4l2_mbus_framefmt *format; - struct v4l2_rect partition; + struct vsp1_partition_window window; unsigned int modulus; /* @@ -245,18 +209,17 @@ static struct v4l2_rect vsp1_video_partition(struct vsp1_pipeline *pipe, /* A single partition simply processes the output size in full. */ if (pipe->partitions <= 1) { - partition.left = 0; - partition.top = 0; - partition.width = format->width; - partition.height = format->height; - return partition; + window.left = 0; + window.width = format->width; + + vsp1_pipeline_propagate_partition(pipe, partition, index, + &window); + return; } /* Initialise the partition with sane starting conditions. */ - partition.left = index * div_size; - partition.top = 0; - partition.width = div_size; - partition.height = format->height; + window.left = index * div_size; + window.width = div_size; modulus = format->width % div_size; @@ -279,18 +242,65 @@ static struct v4l2_rect vsp1_video_partition(struct vsp1_pipeline *pipe, if (modulus < div_size / 2) { if (index == partitions - 1) { /* Halve the penultimate partition. */ - partition.width = div_size / 2; + window.width = div_size / 2; } else if (index == partitions) { /* Increase the final partition. */ - partition.width = (div_size / 2) + modulus; - partition.left -= div_size / 2; + window.width = (div_size / 2) + modulus; + window.left -= div_size / 2; } } else if (index == partitions) { - partition.width = modulus; + window.width = modulus; } } - return partition; + vsp1_pipeline_propagate_partition(pipe, partition, index, &window); +} + +static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe) +{ + struct vsp1_device *vsp1 = pipe->output->entity.vsp1; + const struct v4l2_mbus_framefmt *format; + struct vsp1_entity *entity; + unsigned int div_size; + unsigned int i; + + /* + * Partitions are computed on the size before rotation, use the format + * at the WPF sink. + */ + format = vsp1_entity_get_pad_format(&pipe->output->entity, + pipe->output->entity.config, + RWPF_PAD_SINK); + div_size = format->width; + + /* + * Only Gen3 hardware requires image partitioning, Gen2 will operate + * with a single partition that covers the whole output. + */ + if (vsp1->info->gen == 3) { + list_for_each_entry(entity, &pipe->entities, list_pipe) { + unsigned int entity_max; + + if (!entity->ops->max_width) + continue; + + entity_max = entity->ops->max_width(entity, pipe); + if (entity_max) + div_size = min(div_size, entity_max); + } + } + + pipe->partitions = DIV_ROUND_UP(format->width, div_size); + pipe->part_table = kcalloc(pipe->partitions, sizeof(*pipe->part_table), + GFP_KERNEL); + if (!pipe->part_table) + return -ENOMEM; + + for (i = 0; i < pipe->partitions; ++i) + vsp1_video_calculate_partition(pipe, &pipe->part_table[i], + div_size, i); + + return 0; } /* ----------------------------------------------------------------------------- @@ -369,12 +379,12 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe, } static void vsp1_video_pipeline_run_partition(struct vsp1_pipeline *pipe, - struct vsp1_dl_list *dl) + struct vsp1_dl_list *dl, + unsigned int partition) { struct vsp1_entity *entity; - pipe->partition = vsp1_video_partition(pipe, pipe->div_size, - pipe->current_partition); + pipe->partition = &pipe->part_table[partition]; list_for_each_entry(entity, &pipe->entities, list_pipe) { if (entity->ops->configure) @@ -387,6 +397,7 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) { struct vsp1_device *vsp1 = pipe->output->entity.vsp1; struct vsp1_entity *entity; + unsigned int partition; if (!pipe->dl) pipe->dl = vsp1_dl_list_get(pipe->output->dlm); @@ -403,20 +414,12 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) } /* Run the first partition */ - pipe->current_partition = 0; - vsp1_video_pipeline_run_partition(pipe, pipe->dl); + vsp1_video_pipeline_run_partition(pipe, pipe->dl, 0); /* Process consecutive partitions as necessary */ - for (pipe->current_partition = 1; - pipe->current_partition < pipe->partitions; - pipe->current_partition++) { + for (partition = 1; partition < pipe->partitions; ++partition) { struct vsp1_dl_list *dl; - /* - * Partition configuration operations will utilise - * the pipe->current_partition variable to determine - * the work they should complete. - */ dl = vsp1_dl_list_get(pipe->output->dlm); /* @@ -429,7 +432,7 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) break; } - vsp1_video_pipeline_run_partition(pipe, dl); + vsp1_video_pipeline_run_partition(pipe, dl, partition); vsp1_dl_list_add_chain(pipe->dl, dl); } @@ -440,13 +443,17 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) vsp1_pipeline_run(pipe); } -static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe) +static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe, + bool completed) { struct vsp1_device *vsp1 = pipe->output->entity.vsp1; enum vsp1_pipeline_state state; unsigned long flags; unsigned int i; + /* M2M Pipelines should never call here with an incomplete frame. */ + WARN_ON_ONCE(!completed); + spin_lock_irqsave(&pipe->irqlock, flags); /* Complete buffers on all video nodes. */ @@ -481,7 +488,7 @@ static int vsp1_video_pipeline_build_branch(struct vsp1_pipeline *pipe, struct media_entity_enum ent_enum; struct vsp1_entity *entity; struct media_pad *pad; - bool bru_found = false; + struct vsp1_bru *bru = NULL; int ret; ret = media_entity_enum_init(&ent_enum, &input->entity.vsp1->media_dev); @@ -511,16 +518,20 @@ static int vsp1_video_pipeline_build_branch(struct vsp1_pipeline *pipe, media_entity_to_v4l2_subdev(pad->entity)); /* - * A BRU is present in the pipeline, store the BRU input pad + * A BRU or BRS is present in the pipeline, store its input pad * number in the input RPF for use when configuring the RPF. */ - if (entity->type == VSP1_ENTITY_BRU) { - struct vsp1_bru *bru = to_bru(&entity->subdev); + if (entity->type == VSP1_ENTITY_BRU || + entity->type == VSP1_ENTITY_BRS) { + /* BRU and BRS can't be chained. */ + if (bru) { + ret = -EPIPE; + goto out; + } + bru = to_bru(&entity->subdev); bru->inputs[pad->index].rpf = input; input->bru_input = pad->index; - - bru_found = true; } /* We've reached the WPF, we're done. */ @@ -542,8 +553,7 @@ static int vsp1_video_pipeline_build_branch(struct vsp1_pipeline *pipe, } pipe->uds = entity; - pipe->uds_input = bru_found ? pipe->bru - : &input->entity; + pipe->uds_input = bru ? &bru->entity : &input->entity; } /* Follow the source link, ignoring any HGO or HGT. */ @@ -589,30 +599,42 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe, e = to_vsp1_entity(subdev); list_add_tail(&e->list_pipe, &pipe->entities); - if (e->type == VSP1_ENTITY_RPF) { + switch (e->type) { + case VSP1_ENTITY_RPF: rwpf = to_rwpf(subdev); pipe->inputs[rwpf->entity.index] = rwpf; rwpf->video->pipe_index = ++pipe->num_inputs; rwpf->pipe = pipe; - } else if (e->type == VSP1_ENTITY_WPF) { + break; + + case VSP1_ENTITY_WPF: rwpf = to_rwpf(subdev); pipe->output = rwpf; rwpf->video->pipe_index = 0; rwpf->pipe = pipe; - } else if (e->type == VSP1_ENTITY_LIF) { + break; + + case VSP1_ENTITY_LIF: pipe->lif = e; - } else if (e->type == VSP1_ENTITY_BRU) { + break; + + case VSP1_ENTITY_BRU: + case VSP1_ENTITY_BRS: pipe->bru = e; - } else if (e->type == VSP1_ENTITY_HGO) { - struct vsp1_hgo *hgo = to_hgo(subdev); + break; + case VSP1_ENTITY_HGO: pipe->hgo = e; - hgo->histo.pipe = pipe; - } else if (e->type == VSP1_ENTITY_HGT) { - struct vsp1_hgt *hgt = to_hgt(subdev); + to_hgo(subdev)->histo.pipe = pipe; + break; + case VSP1_ENTITY_HGT: pipe->hgt = e; - hgt->histo.pipe = pipe; + to_hgt(subdev)->histo.pipe = pipe; + break; + + default: + break; } } @@ -783,9 +805,12 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb) static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) { struct vsp1_entity *entity; + int ret; /* Determine this pipelines sizes for image partitioning support. */ - vsp1_video_pipeline_setup_partitions(pipe); + ret = vsp1_video_pipeline_setup_partitions(pipe); + if (ret < 0) + return ret; /* Prepare the display list. */ pipe->dl = vsp1_dl_list_get(pipe->output->dlm); @@ -796,12 +821,14 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) struct vsp1_uds *uds = to_uds(&pipe->uds->subdev); /* - * If a BRU is present in the pipeline before the UDS, the alpha - * component doesn't need to be scaled as the BRU output alpha - * value is fixed to 255. Otherwise we need to scale the alpha - * component only when available at the input RPF. + * If a BRU or BRS is present in the pipeline before the UDS, + * the alpha component doesn't need to be scaled as the BRU and + * BRS output alpha value is fixed to 255. Otherwise we need to + * scale the alpha component only when available at the input + * RPF. */ - if (pipe->uds_input->type == VSP1_ENTITY_BRU) { + if (pipe->uds_input->type == VSP1_ENTITY_BRU || + pipe->uds_input->type == VSP1_ENTITY_BRS) { uds->scale_alpha = false; } else { struct vsp1_rwpf *rpf = @@ -822,6 +849,26 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) return 0; } +static void vsp1_video_cleanup_pipeline(struct vsp1_pipeline *pipe) +{ + struct vsp1_video *video = pipe->output->video; + struct vsp1_vb2_buffer *buffer; + unsigned long flags; + + /* Remove all buffers from the IRQ queue. */ + spin_lock_irqsave(&video->irqlock, flags); + list_for_each_entry(buffer, &video->irqqueue, queue) + vb2_buffer_done(&buffer->buf.vb2_buf, VB2_BUF_STATE_ERROR); + INIT_LIST_HEAD(&video->irqqueue); + spin_unlock_irqrestore(&video->irqlock, flags); + + /* Release our partition table allocation */ + mutex_lock(&pipe->lock); + kfree(pipe->part_table); + pipe->part_table = NULL; + mutex_unlock(&pipe->lock); +} + static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) { struct vsp1_video *video = vb2_get_drv_priv(vq); @@ -835,6 +882,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) ret = vsp1_video_setup_pipeline(pipe); if (ret < 0) { mutex_unlock(&pipe->lock); + vsp1_video_cleanup_pipeline(pipe); return ret; } @@ -866,7 +914,6 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq) { struct vsp1_video *video = vb2_get_drv_priv(vq); struct vsp1_pipeline *pipe = video->rwpf->pipe; - struct vsp1_vb2_buffer *buffer; unsigned long flags; int ret; @@ -891,14 +938,8 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq) mutex_unlock(&pipe->lock); media_pipeline_stop(&video->video.entity); + vsp1_video_cleanup_pipeline(pipe); vsp1_video_pipeline_put(pipe); - - /* Remove all buffers from the IRQ queue. */ - spin_lock_irqsave(&video->irqlock, flags); - list_for_each_entry(buffer, &video->irqqueue, queue) - vb2_buffer_done(&buffer->buf.vb2_buf, VB2_BUF_STATE_ERROR); - INIT_LIST_HEAD(&video->irqqueue); - spin_unlock_irqrestore(&video->irqlock, flags); } static const struct vb2_ops vsp1_video_queue_qops = { diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 32df109b119f..f7f3b4b2c2de 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -291,7 +291,7 @@ static void wpf_configure(struct vsp1_entity *entity, * multiple slices. */ if (pipe->partitions > 1) - width = pipe->partition.width; + width = pipe->partition->wpf.width; vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN | (0 << VI6_WPF_SZCLIP_OFST_SHIFT) | @@ -320,13 +320,13 @@ static void wpf_configure(struct vsp1_entity *entity, * is applied horizontally or vertically accordingly. */ if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate) - offset = format->width - pipe->partition.left - - pipe->partition.width; + offset = format->width - pipe->partition->wpf.left + - pipe->partition->wpf.width; else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate) - offset = format->height - pipe->partition.left - - pipe->partition.width; + offset = format->height - pipe->partition->wpf.left + - pipe->partition->wpf.width; else - offset = pipe->partition.left; + offset = pipe->partition->wpf.left; for (i = 0; i < format->num_planes; ++i) { unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; @@ -348,7 +348,7 @@ static void wpf_configure(struct vsp1_entity *entity, * image height. */ if (wpf->flip.rotate) - height = pipe->partition.width; + height = pipe->partition->wpf.width; else height = format->height; @@ -453,7 +453,9 @@ static void wpf_configure(struct vsp1_entity *entity, } if (pipe->bru || pipe->num_inputs > 1) - srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST; + srcrpf |= pipe->bru->type == VSP1_ENTITY_BRU + ? VI6_WPF_SRCRPF_VIRACT_MST + : VI6_WPF_SRCRPF_VIRACT2_MST; vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF, srcrpf); @@ -471,10 +473,20 @@ static unsigned int wpf_max_width(struct vsp1_entity *entity, return wpf->flip.rotate ? 256 : wpf->max_width; } +static void wpf_partition(struct vsp1_entity *entity, + struct vsp1_pipeline *pipe, + struct vsp1_partition *partition, + unsigned int partition_idx, + struct vsp1_partition_window *window) +{ + partition->wpf = *window; +} + static const struct vsp1_entity_operations wpf_entity_ops = { .destroy = vsp1_wpf_destroy, .configure = wpf_configure, .max_width = wpf_max_width, + .partition = wpf_partition, }; /* ----------------------------------------------------------------------------- diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index ac4704388920..ebfdf334d99c 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -90,12 +90,12 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev, of_node_put(ep); ep = next; - dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name); + dev_dbg(xdev->dev, "processing endpoint %pOF\n", ep); ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link); if (ret < 0) { - dev_err(xdev->dev, "failed to parse link for %s\n", - ep->full_name); + dev_err(xdev->dev, "failed to parse link for %pOF\n", + ep); continue; } @@ -103,9 +103,9 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev, * the link. */ if (link.local_port >= local->num_pads) { - dev_err(xdev->dev, "invalid port number %u for %s\n", + dev_err(xdev->dev, "invalid port number %u for %pOF\n", link.local_port, - to_of_node(link.local_node)->full_name); + to_of_node(link.local_node)); v4l2_fwnode_put_link(&link); ret = -EINVAL; break; @@ -114,8 +114,8 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev, local_pad = &local->pads[link.local_port]; if (local_pad->flags & MEDIA_PAD_FL_SINK) { - dev_dbg(xdev->dev, "skipping sink port %s:%u\n", - to_of_node(link.local_node)->full_name, + dev_dbg(xdev->dev, "skipping sink port %pOF:%u\n", + to_of_node(link.local_node), link.local_port); v4l2_fwnode_put_link(&link); continue; @@ -123,8 +123,8 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev, /* Skip DMA engines, they will be processed separately. */ if (link.remote_node == of_fwnode_handle(xdev->dev->of_node)) { - dev_dbg(xdev->dev, "skipping DMA port %s:%u\n", - to_of_node(link.local_node)->full_name, + dev_dbg(xdev->dev, "skipping DMA port %pOF:%u\n", + to_of_node(link.local_node), link.local_port); v4l2_fwnode_put_link(&link); continue; @@ -134,8 +134,8 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev, ent = xvip_graph_find_entity(xdev, to_of_node(link.remote_node)); if (ent == NULL) { - dev_err(xdev->dev, "no entity found for %s\n", - to_of_node(link.remote_node)->full_name); + dev_err(xdev->dev, "no entity found for %pOF\n", + to_of_node(link.remote_node)); v4l2_fwnode_put_link(&link); ret = -ENODEV; break; @@ -144,9 +144,8 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev, remote = ent->entity; if (link.remote_port >= remote->num_pads) { - dev_err(xdev->dev, "invalid port number %u on %s\n", - link.remote_port, - to_of_node(link.remote_node)->full_name); + dev_err(xdev->dev, "invalid port number %u on %pOF\n", + link.remote_port, to_of_node(link.remote_node)); v4l2_fwnode_put_link(&link); ret = -EINVAL; break; @@ -216,12 +215,12 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev) of_node_put(ep); ep = next; - dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name); + dev_dbg(xdev->dev, "processing endpoint %pOF\n", ep); ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link); if (ret < 0) { - dev_err(xdev->dev, "failed to parse link for %s\n", - ep->full_name); + dev_err(xdev->dev, "failed to parse link for %pOF\n", + ep); continue; } @@ -242,17 +241,17 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev) ent = xvip_graph_find_entity(xdev, to_of_node(link.remote_node)); if (ent == NULL) { - dev_err(xdev->dev, "no entity found for %s\n", - to_of_node(link.remote_node)->full_name); + dev_err(xdev->dev, "no entity found for %pOF\n", + to_of_node(link.remote_node)); v4l2_fwnode_put_link(&link); ret = -ENODEV; break; } if (link.remote_port >= ent->entity->num_pads) { - dev_err(xdev->dev, "invalid port number %u on %s\n", + dev_err(xdev->dev, "invalid port number %u on %pOF\n", link.remote_port, - to_of_node(link.remote_node)->full_name); + to_of_node(link.remote_node)); v4l2_fwnode_put_link(&link); ret = -EINVAL; break; @@ -337,8 +336,8 @@ static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier, continue; if (entity->subdev) { - dev_err(xdev->dev, "duplicate subdev for node %s\n", - entity->node->full_name); + dev_err(xdev->dev, "duplicate subdev for node %pOF\n", + entity->node); return -EINVAL; } @@ -360,14 +359,14 @@ static int xvip_graph_parse_one(struct xvip_composite_device *xdev, struct device_node *ep = NULL; int ret = 0; - dev_dbg(xdev->dev, "parsing node %s\n", node->full_name); + dev_dbg(xdev->dev, "parsing node %pOF\n", node); while (1) { ep = of_graph_get_next_endpoint(node, ep); if (ep == NULL) break; - dev_dbg(xdev->dev, "handling endpoint %s\n", ep->full_name); + dev_dbg(xdev->dev, "handling endpoint %pOF\n", ep); remote = of_graph_get_remote_port_parent(ep); if (remote == NULL) { @@ -452,8 +451,7 @@ static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev, ret = xvip_dma_init(xdev, dma, type, index); if (ret < 0) { - dev_err(xdev->dev, "%s initialization failed\n", - node->full_name); + dev_err(xdev->dev, "%pOF initialization failed\n", node); return ret; } diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 53bc8c010035..8521bb2825e8 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -408,7 +408,7 @@ err_reg_dev: return retval; } -static struct usb_device_id usb_dsbr100_device_table[] = { +static const struct usb_device_id usb_dsbr100_device_table[] = { { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, { } /* Terminating entry */ }; diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index cbaf850f4791..6888b7db449d 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -528,7 +528,7 @@ static const struct v4l2_ctrl_ops cadet_ctrl_ops = { #ifdef CONFIG_PNP -static struct pnp_device_id cadet_pnp_devices[] = { +static const struct pnp_device_id cadet_pnp_devices[] = { /* ADS Cadet AM/FM Radio Card */ {.id = "MSM0c24", .driver_data = 0}, {.id = ""} diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index ca051ccbc3e4..ddc12b16f77c 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -281,7 +281,7 @@ static const struct radio_isa_ops gemtek_ops = { static const int gemtek_ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; #ifdef CONFIG_PNP -static struct pnp_device_id gemtek_pnp_devices[] = { +static const struct pnp_device_id gemtek_pnp_devices[] = { /* AOpen FX-3D/Pro Radio */ {.id = "ADS7183", .driver_data = 0}, {.id = ""} diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c index 53a7c2e87762..f2ea8bc5f5ee 100644 --- a/drivers/media/radio/radio-keene.c +++ b/drivers/media/radio/radio-keene.c @@ -45,7 +45,7 @@ MODULE_LICENSE("GPL"); #define FREQ_MUL 16000U /* USB Device ID List */ -static struct usb_device_id usb_keene_device_table[] = { +static const struct usb_device_id usb_keene_device_table[] = { {USB_DEVICE_AND_INTERFACE_INFO(USB_KEENE_VENDOR, USB_KEENE_PRODUCT, USB_CLASS_HID, 0, 0) }, { } /* Terminating entry */ diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c index c2010a905a47..fdc481257efd 100644 --- a/drivers/media/radio/radio-ma901.c +++ b/drivers/media/radio/radio-ma901.c @@ -444,7 +444,7 @@ err: } /* USB Device ID List */ -static struct usb_device_id usb_ma901radio_device_table[] = { +static const struct usb_device_id usb_ma901radio_device_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(USB_MA901_VENDOR, USB_MA901_PRODUCT, USB_CLASS_HID, 0, 0) }, { } /* Terminating entry */ diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 8253f79d5d75..3aa5ad391581 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -186,7 +186,7 @@ static void maxiradio_remove(struct pci_dev *pdev) kfree(dev); } -static struct pci_device_id maxiradio_pci_tbl[] = { +static const struct pci_device_id maxiradio_pci_tbl[] = { { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO, PCI_ANY_ID, PCI_ANY_ID, }, { 0 } diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index 95c12532e87a..c9f59129af79 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -587,7 +587,7 @@ err: } /* USB Device ID List */ -static struct usb_device_id usb_amradio_device_table[] = { +static const struct usb_device_id usb_amradio_device_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT, USB_CLASS_HID, 0, 0) }, { } /* Terminating entry */ diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c index bfb3a6d051ba..3c0a22a54113 100644 --- a/drivers/media/radio/radio-raremono.c +++ b/drivers/media/radio/radio-raremono.c @@ -58,7 +58,7 @@ MODULE_LICENSE("GPL v2"); */ /* USB Device ID List */ -static struct usb_device_id usb_raremono_device_table[] = { +static const struct usb_device_id usb_raremono_device_table[] = { {USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, { } /* Terminating entry */ }; diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index dc81d422b394..de79d5569c2a 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -197,7 +197,7 @@ static int fmr2_tea_ext_init(struct snd_tea575x *tea) return 0; } -static struct pnp_device_id fmr2_pnp_ids[] = { +static const struct pnp_device_id fmr2_pnp_ids[] = { { .id = "MFRad13" }, /* tuner subdevice of SF16-FMD2 */ { .id = "" } }; diff --git a/drivers/media/radio/radio-shark.c b/drivers/media/radio/radio-shark.c index 23971f5502a8..22f3466af2b1 100644 --- a/drivers/media/radio/radio-shark.c +++ b/drivers/media/radio/radio-shark.c @@ -392,7 +392,7 @@ static int usb_shark_resume(struct usb_interface *intf) #endif /* Specify the bcdDevice value, as the radioSHARK and radioSHARK2 share ids */ -static struct usb_device_id usb_shark_device_table[] = { +static const struct usb_device_id usb_shark_device_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | USB_DEVICE_ID_MATCH_INT_CLASS, .idVendor = 0x077d, diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c index b50638ec5f09..4d1a4b3d669c 100644 --- a/drivers/media/radio/radio-shark2.c +++ b/drivers/media/radio/radio-shark2.c @@ -358,7 +358,7 @@ static int usb_shark_resume(struct usb_interface *intf) #endif /* Specify the bcdDevice value, as the radioSHARK and radioSHARK2 share ids */ -static struct usb_device_id usb_shark_device_table[] = { +static const struct usb_device_id usb_shark_device_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | USB_DEVICE_ID_MATCH_INT_CLASS, .idVendor = 0x077d, diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 9db8331a0c75..bc7e69e7e32e 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -414,7 +414,7 @@ static const struct v4l2_ioctl_ops tea5764_ioctl_ops = { }; /* V4L2 interface */ -static struct video_device tea5764_radio_template = { +static const struct video_device tea5764_radio_template = { .name = "TEA5764 FM-Radio", .fops = &tea5764_fops, .ioctl_ops = &tea5764_ioctl_ops, diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 17e82a9a0109..903fcd5e99c0 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1982,7 +1982,7 @@ static const struct v4l2_ioctl_ops wl1273_ioctl_ops = { .vidioc_log_status = wl1273_fm_vidioc_log_status, }; -static struct video_device wl1273_viddev_template = { +static const struct video_device wl1273_viddev_template = { .fops = &wl1273_fops, .ioctl_ops = &wl1273_ioctl_ops, .name = WL1273_FM_DRIVER_NAME, diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index 571f29a34bf8..c311f9951d80 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -38,7 +38,7 @@ /* USB Device ID List */ -static struct usb_device_id si470x_usb_driver_id_table[] = { +static const struct usb_device_id si470x_usb_driver_id_table[] = { /* Silicon Labs USB FM Radio Reference Design */ { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, /* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */ diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c index 6f93ef1249a6..27339ec495f6 100644 --- a/drivers/media/radio/si4713/radio-platform-si4713.c +++ b/drivers/media/radio/si4713/radio-platform-si4713.c @@ -135,7 +135,7 @@ static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = { }; /* radio_si4713_vdev_template - video device interface */ -static struct video_device radio_si4713_vdev_template = { +static const struct video_device radio_si4713_vdev_template = { .fops = &radio_si4713_fops, .name = "radio-si4713", .release = video_device_release_empty, diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c index e5e5a1672bdb..a115db24667b 100644 --- a/drivers/media/radio/si4713/radio-usb-si4713.c +++ b/drivers/media/radio/si4713/radio-usb-si4713.c @@ -49,7 +49,7 @@ MODULE_LICENSE("GPL v2"); #define USB_RESP_TIMEOUT 50000 /* USB Device ID List */ -static struct usb_device_id usb_si4713_usb_device_table[] = { +static const struct usb_device_id usb_si4713_usb_device_table[] = { {USB_DEVICE_AND_INTERFACE_INFO(USB_SI4713_VENDOR, USB_SI4713_PRODUCT, USB_CLASS_HID, 0, 0) }, { } /* Terminating entry */ @@ -409,7 +409,7 @@ static const struct i2c_algorithm si4713_algo = { /* This name value shows up in the sysfs filename associated with this I2C adapter */ -static struct i2c_adapter si4713_i2c_adapter_template = { +static const struct i2c_adapter si4713_i2c_adapter_template = { .name = "si4713-i2c", .owner = THIS_MODULE, .algo = &si4713_algo, diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 71423f45c05c..fc5a7abc83d2 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -509,7 +509,7 @@ static const struct v4l2_ioctl_ops fm_drv_ioctl_ops = { }; /* V4L2 RADIO device parent structure */ -static struct video_device fm_viddev_template = { +static const struct video_device fm_viddev_template = { .fops = &fm_drv_fops, .ioctl_ops = &fm_drv_ioctl_ops, .name = FM_DRV_NAME, diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 5e83b76495f7..d9ce8ff55d0c 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -1,9 +1,20 @@ -config RC_CORE - tristate - depends on MEDIA_RC_SUPPORT + +menuconfig RC_CORE + tristate "Remote Controller support" depends on INPUT default y + ---help--- + Enable support for Remote Controllers on Linux. This is + needed in order to support several video capture adapters, + standalone IR receivers/transmitters, and RF receivers. + + Enable this option if you have a video capture board even + if you don't need IR, as otherwise, you may not be able to + compile the driver for your adapter. + Say Y when you have a TV or an IR device. + +if RC_CORE source "drivers/media/rc/keymaps/Kconfig" menuconfig RC_DECODERS @@ -388,6 +399,29 @@ config IR_GPIO_CIR To compile this driver as a module, choose M here: the module will be called gpio-ir-recv. +config IR_GPIO_TX + tristate "GPIO IR Bit Banging Transmitter" + depends on RC_CORE + depends on LIRC + ---help--- + Say Y if you want to a GPIO based IR transmitter. This is a + bit banging driver. + + To compile this driver as a module, choose M here: the module will + be called gpio-ir-tx. + +config IR_PWM_TX + tristate "PWM IR transmitter" + depends on RC_CORE + depends on LIRC + depends on PWM + ---help--- + Say Y if you want to use a PWM based IR transmitter. This is + more power efficient than the bit banging gpio driver. + + To compile this driver as a module, choose M here: the module will + be called pwm-ir-tx. + config RC_ST tristate "ST remote control receiver" depends on RC_CORE @@ -435,4 +469,17 @@ config IR_SIR To compile this driver as a module, choose M here: the module will be called sir-ir. +config IR_ZX + tristate "ZTE ZX IR remote control" + depends on RC_CORE + depends on ARCH_ZX || COMPILE_TEST + ---help--- + Say Y if you want to use the IR remote control available + on ZTE ZX family SoCs. + + To compile this driver as a module, choose M here: the + module will be called zx-irdec. + endif #RC_DEVICES + +endif #RC_CORE diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 245e2c2d0b22..9bc6a3980ed0 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -32,6 +32,8 @@ obj-$(CONFIG_IR_STREAMZAP) += streamzap.o obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o +obj-$(CONFIG_IR_GPIO_TX) += gpio-ir-tx.o +obj-$(CONFIG_IR_PWM_TX) += pwm-ir-tx.o obj-$(CONFIG_IR_IGORPLUGUSB) += igorplugusb.o obj-$(CONFIG_IR_IGUANA) += iguanair.o obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o @@ -41,3 +43,4 @@ obj-$(CONFIG_IR_IMG) += img-ir/ obj-$(CONFIG_IR_SERIAL) += serial_ir.o obj-$(CONFIG_IR_SIR) += sir_ir.o obj-$(CONFIG_IR_MTK) += mtk-cir.o +obj-$(CONFIG_IR_ZX) += zx-irdec.o diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index a4c6ad4f67c1..d0871d60a723 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -622,7 +622,8 @@ static void ati_remote_input_report(struct urb *urb) * it would cause ghost repeats which would be a * regression for this driver. */ - rc_keydown_notimeout(ati_remote->rdev, RC_TYPE_OTHER, + rc_keydown_notimeout(ati_remote->rdev, + RC_PROTO_OTHER, scancode, data[2]); rc_keyup(ati_remote->rdev); } @@ -760,13 +761,13 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote) struct rc_dev *rdev = ati_remote->rdev; rdev->priv = ati_remote; - rdev->allowed_protocols = RC_BIT_OTHER; + rdev->allowed_protocols = RC_PROTO_BIT_OTHER; rdev->driver_name = "ati_remote"; rdev->open = ati_remote_rc_open; rdev->close = ati_remote_rc_close; - rdev->input_name = ati_remote->rc_name; + rdev->device_name = ati_remote->rc_name; rdev->input_phys = ati_remote->rc_phys; usb_to_input_id(ati_remote->udev, &rdev->input_id); diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 60da963f40dc..af7ba23e16e1 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1053,14 +1053,14 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) if (!dev->hw_learning_and_tx_capable) learning_mode_force = false; - rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rdev->priv = dev; rdev->open = ene_open; rdev->close = ene_close; rdev->s_idle = ene_set_idle; rdev->driver_name = ENE_DRIVER_NAME; rdev->map_name = RC_MAP_RC6_MCE; - rdev->input_name = "ENE eHome Infrared Remote Receiver"; + rdev->device_name = "ENE eHome Infrared Remote Receiver"; if (dev->hw_learning_and_tx_capable) { rdev->s_learning_mode = ene_set_learning_mode; @@ -1070,7 +1070,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) rdev->s_tx_carrier = ene_set_tx_carrier; rdev->s_tx_duty_cycle = ene_set_tx_duty_cycle; rdev->s_carrier_report = ene_set_carrier_report; - rdev->input_name = "ENE eHome Infrared Remote Transceiver"; + rdev->device_name = "ENE eHome Infrared Remote Transceiver"; } dev->rdev = rdev; diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index 0d3562712f27..f2639d0c2fca 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -529,10 +529,10 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id /* Set up the rc device */ rdev->priv = fintek; - rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rdev->open = fintek_open; rdev->close = fintek_close; - rdev->input_name = FINTEK_DESCRIPTION; + rdev->device_name = FINTEK_DESCRIPTION; rdev->input_phys = "fintek/cir0"; rdev->input_id.bustype = BUS_HOST; rdev->input_id.vendor = VENDOR_ID_FINTEK; diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index b4f773b9dc1d..7248b3662285 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -30,7 +30,6 @@ struct gpio_rc_dev { struct rc_dev *rcdev; int gpio_nr; bool active_low; - struct timer_list flush_timer; }; #ifdef CONFIG_OF @@ -77,7 +76,6 @@ static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) struct gpio_rc_dev *gpio_dev = dev_id; int gval; int rc = 0; - enum raw_event_type type = IR_SPACE; gval = gpio_get_value(gpio_dev->gpio_nr); @@ -87,33 +85,14 @@ static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) if (gpio_dev->active_low) gval = !gval; - if (gval == 1) - type = IR_PULSE; - - rc = ir_raw_event_store_edge(gpio_dev->rcdev, type); + rc = ir_raw_event_store_edge(gpio_dev->rcdev, gval == 1); if (rc < 0) goto err_get_value; - mod_timer(&gpio_dev->flush_timer, - jiffies + nsecs_to_jiffies(gpio_dev->rcdev->timeout)); - - ir_raw_event_handle(gpio_dev->rcdev); - err_get_value: return IRQ_HANDLED; } -static void flush_timer(unsigned long arg) -{ - struct gpio_rc_dev *gpio_dev = (struct gpio_rc_dev *)arg; - DEFINE_IR_RAW_EVENT(ev); - - ev.timeout = true; - ev.duration = gpio_dev->rcdev->timeout; - ir_raw_event_store(gpio_dev->rcdev, &ev); - ir_raw_event_handle(gpio_dev->rcdev); -} - static int gpio_ir_recv_probe(struct platform_device *pdev) { struct gpio_rc_dev *gpio_dev; @@ -150,7 +129,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) } rcdev->priv = gpio_dev; - rcdev->input_name = GPIO_IR_DEVICE_NAME; + rcdev->device_name = GPIO_IR_DEVICE_NAME; rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0"; rcdev->input_id.bustype = BUS_HOST; rcdev->input_id.vendor = 0x0001; @@ -164,16 +143,13 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) if (pdata->allowed_protos) rcdev->allowed_protocols = pdata->allowed_protos; else - rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY; gpio_dev->rcdev = rcdev; gpio_dev->gpio_nr = pdata->gpio_nr; gpio_dev->active_low = pdata->active_low; - setup_timer(&gpio_dev->flush_timer, flush_timer, - (unsigned long)gpio_dev); - rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv"); if (rc < 0) goto err_gpio_request; @@ -216,7 +192,6 @@ static int gpio_ir_recv_remove(struct platform_device *pdev) struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev); - del_timer_sync(&gpio_dev->flush_timer); rc_unregister_device(gpio_dev->rcdev); gpio_free(gpio_dev->gpio_nr); kfree(gpio_dev); diff --git a/drivers/media/rc/gpio-ir-tx.c b/drivers/media/rc/gpio-ir-tx.c new file mode 100644 index 000000000000..cd476cab9782 --- /dev/null +++ b/drivers/media/rc/gpio-ir-tx.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2017 Sean Young <sean@mess.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/gpio/consumer.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <media/rc-core.h> + +#define DRIVER_NAME "gpio-ir-tx" +#define DEVICE_NAME "GPIO IR Bit Banging Transmitter" + +struct gpio_ir { + struct gpio_desc *gpio; + unsigned int carrier; + unsigned int duty_cycle; + /* we need a spinlock to hold the cpu while transmitting */ + spinlock_t lock; +}; + +static const struct of_device_id gpio_ir_tx_of_match[] = { + { .compatible = "gpio-ir-tx", }, + { }, +}; +MODULE_DEVICE_TABLE(of, gpio_ir_tx_of_match); + +static int gpio_ir_tx_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle) +{ + struct gpio_ir *gpio_ir = dev->priv; + + gpio_ir->duty_cycle = duty_cycle; + + return 0; +} + +static int gpio_ir_tx_set_carrier(struct rc_dev *dev, u32 carrier) +{ + struct gpio_ir *gpio_ir = dev->priv; + + if (!carrier) + return -EINVAL; + + gpio_ir->carrier = carrier; + + return 0; +} + +static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf, + unsigned int count) +{ + struct gpio_ir *gpio_ir = dev->priv; + unsigned long flags; + ktime_t edge; + /* + * delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on + * m68k ndelay(s64) does not compile; so use s32 rather than s64. + */ + s32 delta; + int i; + unsigned int pulse, space; + + /* Ensure the dividend fits into 32 bit */ + pulse = DIV_ROUND_CLOSEST(gpio_ir->duty_cycle * (NSEC_PER_SEC / 100), + gpio_ir->carrier); + space = DIV_ROUND_CLOSEST((100 - gpio_ir->duty_cycle) * + (NSEC_PER_SEC / 100), gpio_ir->carrier); + + spin_lock_irqsave(&gpio_ir->lock, flags); + + edge = ktime_get(); + + for (i = 0; i < count; i++) { + if (i % 2) { + // space + edge = ktime_add_us(edge, txbuf[i]); + delta = ktime_us_delta(edge, ktime_get()); + if (delta > 10) { + spin_unlock_irqrestore(&gpio_ir->lock, flags); + usleep_range(delta, delta + 10); + spin_lock_irqsave(&gpio_ir->lock, flags); + } else if (delta > 0) { + udelay(delta); + } + } else { + // pulse + ktime_t last = ktime_add_us(edge, txbuf[i]); + + while (ktime_before(ktime_get(), last)) { + gpiod_set_value(gpio_ir->gpio, 1); + edge = ktime_add_ns(edge, pulse); + delta = ktime_to_ns(ktime_sub(edge, + ktime_get())); + if (delta > 0) + ndelay(delta); + gpiod_set_value(gpio_ir->gpio, 0); + edge = ktime_add_ns(edge, space); + delta = ktime_to_ns(ktime_sub(edge, + ktime_get())); + if (delta > 0) + ndelay(delta); + } + + edge = last; + } + } + + spin_unlock_irqrestore(&gpio_ir->lock, flags); + + return count; +} + +static int gpio_ir_tx_probe(struct platform_device *pdev) +{ + struct gpio_ir *gpio_ir; + struct rc_dev *rcdev; + int rc; + + gpio_ir = devm_kmalloc(&pdev->dev, sizeof(*gpio_ir), GFP_KERNEL); + if (!gpio_ir) + return -ENOMEM; + + rcdev = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW_TX); + if (!rcdev) + return -ENOMEM; + + gpio_ir->gpio = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW); + if (IS_ERR(gpio_ir->gpio)) { + if (PTR_ERR(gpio_ir->gpio) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get gpio (%ld)\n", + PTR_ERR(gpio_ir->gpio)); + return PTR_ERR(gpio_ir->gpio); + } + + rcdev->priv = gpio_ir; + rcdev->driver_name = DRIVER_NAME; + rcdev->device_name = DEVICE_NAME; + rcdev->tx_ir = gpio_ir_tx; + rcdev->s_tx_duty_cycle = gpio_ir_tx_set_duty_cycle; + rcdev->s_tx_carrier = gpio_ir_tx_set_carrier; + + gpio_ir->carrier = 38000; + gpio_ir->duty_cycle = 50; + spin_lock_init(&gpio_ir->lock); + + rc = devm_rc_register_device(&pdev->dev, rcdev); + if (rc < 0) + dev_err(&pdev->dev, "failed to register rc device\n"); + + return rc; +} + +static struct platform_driver gpio_ir_tx_driver = { + .probe = gpio_ir_tx_probe, + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(gpio_ir_tx_of_match), + }, +}; +module_platform_driver(gpio_ir_tx_driver); + +MODULE_DESCRIPTION("GPIO IR Bit Banging Transmitter"); +MODULE_AUTHOR("Sean Young <sean@mess.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c index cb6d4f1247da..a5ea86be8f44 100644 --- a/drivers/media/rc/igorplugusb.c +++ b/drivers/media/rc/igorplugusb.c @@ -194,7 +194,7 @@ static int igorplugusb_probe(struct usb_interface *intf, if (!rc) goto fail; - rc->input_name = DRIVER_DESC; + rc->device_name = DRIVER_DESC; rc->input_phys = ir->phys; usb_to_input_id(udev, &rc->input_id); rc->dev.parent = &intf->dev; @@ -202,10 +202,11 @@ static int igorplugusb_probe(struct usb_interface *intf, * This device can only store 36 pulses + spaces, which is not enough * for the NEC protocol and many others. */ - rc->allowed_protocols = RC_BIT_ALL_IR_DECODER & ~(RC_BIT_NEC | - RC_BIT_NECX | RC_BIT_NEC32 | RC_BIT_RC6_6A_20 | - RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | - RC_BIT_SONY20 | RC_BIT_SANYO); + rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER & + ~(RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32 | + RC_PROTO_BIT_RC6_6A_20 | RC_PROTO_BIT_RC6_6A_24 | + RC_PROTO_BIT_RC6_6A_32 | RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_SONY20 | RC_PROTO_BIT_SANYO); rc->priv = ir; rc->driver_name = DRIVER_NAME; diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index 8711a7ff55cc..30e24da67226 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -487,11 +487,11 @@ static int iguanair_probe(struct usb_interface *intf, usb_make_path(ir->udev, ir->phys, sizeof(ir->phys)); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; usb_to_input_id(ir->udev, &rc->input_id); rc->dev.parent = &intf->dev; - rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rc->priv = ir; rc->open = iguanair_open; rc->close = iguanair_close; diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 8d1439622533..82fdf4cc0824 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -589,7 +589,7 @@ static void img_ir_set_decoder(struct img_ir_priv *priv, /* clear the wakeup scancode filter */ rdev->scancode_wakeup_filter.data = 0; rdev->scancode_wakeup_filter.mask = 0; - rdev->wakeup_protocol = RC_TYPE_UNKNOWN; + rdev->wakeup_protocol = RC_PROTO_UNKNOWN; /* clear raw filters */ _img_ir_set_filter(priv, NULL); @@ -823,7 +823,7 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw) int ret = IMG_IR_SCANCODE; struct img_ir_scancode_req request; - request.protocol = RC_TYPE_UNKNOWN; + request.protocol = RC_PROTO_UNKNOWN; request.toggle = 0; if (dec->scancode) @@ -1083,7 +1083,7 @@ int img_ir_probe_hw(struct img_ir_priv *priv) rdev->priv = priv; rdev->map_name = RC_MAP_EMPTY; rdev->allowed_protocols = img_ir_allowed_protos(priv); - rdev->input_name = "IMG Infrared Decoder"; + rdev->device_name = "IMG Infrared Decoder"; rdev->s_filter = img_ir_set_normal_filter; rdev->s_wakeup_filter = img_ir_set_wakeup_filter; diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h index 91a297731661..58b68dd6c67d 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.h +++ b/drivers/media/rc/img-ir/img-ir-hw.h @@ -135,13 +135,13 @@ struct img_ir_timing_regvals { /** * struct img_ir_scancode_req - Scancode request data. * @protocol: Protocol code of received message (defaults to - * RC_TYPE_UNKNOWN). + * RC_PROTO_UNKNOWN). * @scancode: Scan code of received message (must be written by * handler if IMG_IR_SCANCODE is returned). * @toggle: Toggle bit (defaults to 0). */ struct img_ir_scancode_req { - enum rc_type protocol; + enum rc_proto protocol; u32 scancode; u8 toggle; }; diff --git a/drivers/media/rc/img-ir/img-ir-jvc.c b/drivers/media/rc/img-ir/img-ir-jvc.c index d3e2fc0bcfe1..4b07c76fbe1b 100644 --- a/drivers/media/rc/img-ir/img-ir-jvc.c +++ b/drivers/media/rc/img-ir/img-ir-jvc.c @@ -23,7 +23,7 @@ static int img_ir_jvc_scancode(int len, u64 raw, u64 enabled_protocols, cust = (raw >> 0) & 0xff; data = (raw >> 8) & 0xff; - request->protocol = RC_TYPE_JVC; + request->protocol = RC_PROTO_JVC; request->scancode = cust << 8 | data; return IMG_IR_SCANCODE; } @@ -52,7 +52,7 @@ static int img_ir_jvc_filter(const struct rc_scancode_filter *in, * http://support.jvc.com/consumer/support/documents/RemoteCodes.pdf */ struct img_ir_decoder img_ir_jvc = { - .type = RC_BIT_JVC, + .type = RC_PROTO_BIT_JVC, .control = { .decoden = 1, .code_type = IMG_IR_CODETYPE_PULSEDIST, diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c index 044fd42b22a0..2fc0678ad2d7 100644 --- a/drivers/media/rc/img-ir/img-ir-nec.c +++ b/drivers/media/rc/img-ir/img-ir-nec.c @@ -35,20 +35,20 @@ static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols, bitrev8(addr_inv) << 16 | bitrev8(data) << 8 | bitrev8(data_inv); - request->protocol = RC_TYPE_NEC32; + request->protocol = RC_PROTO_NEC32; } else if ((addr_inv ^ addr) != 0xff) { /* Extended NEC */ /* scan encoding: AAaaDD */ request->scancode = addr << 16 | addr_inv << 8 | data; - request->protocol = RC_TYPE_NECX; + request->protocol = RC_PROTO_NECX; } else { /* Normal NEC */ /* scan encoding: AADD */ request->scancode = addr << 8 | data; - request->protocol = RC_TYPE_NEC; + request->protocol = RC_PROTO_NEC; } return IMG_IR_SCANCODE; } @@ -63,7 +63,7 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in, data = in->data & 0xff; data_m = in->mask & 0xff; - protocols &= RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32; + protocols &= RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32; /* * If only one bit is set, we were requested to do an exact @@ -72,14 +72,14 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in, */ if (!is_power_of_2(protocols)) { if ((in->data | in->mask) & 0xff000000) - protocols = RC_BIT_NEC32; + protocols = RC_PROTO_BIT_NEC32; else if ((in->data | in->mask) & 0x00ff0000) - protocols = RC_BIT_NECX; + protocols = RC_PROTO_BIT_NECX; else - protocols = RC_BIT_NEC; + protocols = RC_PROTO_BIT_NEC; } - if (protocols == RC_BIT_NEC32) { + if (protocols == RC_PROTO_BIT_NEC32) { /* 32-bit NEC (used by Apple and TiVo remotes) */ /* scan encoding: as transmitted, MSBit = first received bit */ addr = bitrev8(in->data >> 24); @@ -90,7 +90,7 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in, data_m = bitrev8(in->mask >> 8); data_inv = bitrev8(in->data >> 0); data_inv_m = bitrev8(in->mask >> 0); - } else if (protocols == RC_BIT_NECX) { + } else if (protocols == RC_PROTO_BIT_NECX) { /* Extended NEC */ /* scan encoding AAaaDD */ addr = (in->data >> 16) & 0xff; @@ -128,7 +128,7 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in, * http://wiki.altium.com/display/ADOH/NEC+Infrared+Transmission+Protocol */ struct img_ir_decoder img_ir_nec = { - .type = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32, + .type = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32, .control = { .decoden = 1, .code_type = IMG_IR_CODETYPE_PULSEDIST, diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c index 8d2f8e2006e7..64714efc1145 100644 --- a/drivers/media/rc/img-ir/img-ir-raw.c +++ b/drivers/media/rc/img-ir/img-ir-raw.c @@ -40,9 +40,9 @@ static void img_ir_refresh_raw(struct img_ir_priv *priv, u32 irq_status) /* report the edge to the IR raw decoders */ if (ir_status) /* low */ - ir_raw_event_store_edge(rc_dev, IR_SPACE); + ir_raw_event_store_edge(rc_dev, false); else /* high */ - ir_raw_event_store_edge(rc_dev, IR_PULSE); + ir_raw_event_store_edge(rc_dev, true); ir_raw_event_handle(rc_dev); } @@ -117,7 +117,7 @@ int img_ir_probe_raw(struct img_ir_priv *priv) } rdev->priv = priv; rdev->map_name = RC_MAP_EMPTY; - rdev->input_name = "IMG Infrared Decoder Raw"; + rdev->device_name = "IMG Infrared Decoder Raw"; /* Register raw decoder */ error = rc_register_device(rdev); diff --git a/drivers/media/rc/img-ir/img-ir-rc5.c b/drivers/media/rc/img-ir/img-ir-rc5.c index a8a28a377eee..a1bc8705472b 100644 --- a/drivers/media/rc/img-ir/img-ir-rc5.c +++ b/drivers/media/rc/img-ir/img-ir-rc5.c @@ -33,7 +33,7 @@ static int img_ir_rc5_scancode(int len, u64 raw, u64 enabled_protocols, if (!start) return -EINVAL; - request->protocol = RC_TYPE_RC5; + request->protocol = RC_PROTO_RC5; request->scancode = addr << 8 | cmd; request->toggle = tgl; return IMG_IR_SCANCODE; @@ -52,7 +52,7 @@ static int img_ir_rc5_filter(const struct rc_scancode_filter *in, * see http://www.sbprojects.com/knowledge/ir/rc5.php */ struct img_ir_decoder img_ir_rc5 = { - .type = RC_BIT_RC5, + .type = RC_PROTO_BIT_RC5, .control = { .bitoriend2 = 1, .code_type = IMG_IR_CODETYPE_BIPHASE, diff --git a/drivers/media/rc/img-ir/img-ir-rc6.c b/drivers/media/rc/img-ir/img-ir-rc6.c index de1e27534968..5f34f59ca257 100644 --- a/drivers/media/rc/img-ir/img-ir-rc6.c +++ b/drivers/media/rc/img-ir/img-ir-rc6.c @@ -54,7 +54,7 @@ static int img_ir_rc6_scancode(int len, u64 raw, u64 enabled_protocols, if (mode) return -EINVAL; - request->protocol = RC_TYPE_RC6_0; + request->protocol = RC_PROTO_RC6_0; request->scancode = addr << 8 | cmd; request->toggle = trl2; return IMG_IR_SCANCODE; @@ -73,7 +73,7 @@ static int img_ir_rc6_filter(const struct rc_scancode_filter *in, * see http://www.sbprojects.com/knowledge/ir/rc6.php */ struct img_ir_decoder img_ir_rc6 = { - .type = RC_BIT_RC6_0, + .type = RC_PROTO_BIT_RC6_0, .control = { .bitorien = 1, .code_type = IMG_IR_CODETYPE_BIPHASE, diff --git a/drivers/media/rc/img-ir/img-ir-sanyo.c b/drivers/media/rc/img-ir/img-ir-sanyo.c index f394994ffc22..55a755bb437c 100644 --- a/drivers/media/rc/img-ir/img-ir-sanyo.c +++ b/drivers/media/rc/img-ir/img-ir-sanyo.c @@ -44,7 +44,7 @@ static int img_ir_sanyo_scancode(int len, u64 raw, u64 enabled_protocols, return -EINVAL; /* Normal Sanyo */ - request->protocol = RC_TYPE_SANYO; + request->protocol = RC_PROTO_SANYO; request->scancode = addr << 8 | data; return IMG_IR_SCANCODE; } @@ -80,7 +80,7 @@ static int img_ir_sanyo_filter(const struct rc_scancode_filter *in, /* Sanyo decoder */ struct img_ir_decoder img_ir_sanyo = { - .type = RC_BIT_SANYO, + .type = RC_PROTO_BIT_SANYO, .control = { .decoden = 1, .code_type = IMG_IR_CODETYPE_PULSEDIST, diff --git a/drivers/media/rc/img-ir/img-ir-sharp.c b/drivers/media/rc/img-ir/img-ir-sharp.c index fe5acc4f030e..2d2530902cfa 100644 --- a/drivers/media/rc/img-ir/img-ir-sharp.c +++ b/drivers/media/rc/img-ir/img-ir-sharp.c @@ -32,7 +32,7 @@ static int img_ir_sharp_scancode(int len, u64 raw, u64 enabled_protocols, /* probably the second half of the message */ return -EINVAL; - request->protocol = RC_TYPE_SHARP; + request->protocol = RC_PROTO_SHARP; request->scancode = addr << 8 | cmd; return IMG_IR_SCANCODE; } @@ -73,7 +73,7 @@ static int img_ir_sharp_filter(const struct rc_scancode_filter *in, * See also http://www.sbprojects.com/knowledge/ir/sharp.php */ struct img_ir_decoder img_ir_sharp = { - .type = RC_BIT_SHARP, + .type = RC_PROTO_BIT_SHARP, .control = { .decoden = 0, .decodend2 = 1, diff --git a/drivers/media/rc/img-ir/img-ir-sony.c b/drivers/media/rc/img-ir/img-ir-sony.c index 3fcba271a419..a942d0be908c 100644 --- a/drivers/media/rc/img-ir/img-ir-sony.c +++ b/drivers/media/rc/img-ir/img-ir-sony.c @@ -19,32 +19,32 @@ static int img_ir_sony_scancode(int len, u64 raw, u64 enabled_protocols, switch (len) { case 12: - if (!(enabled_protocols & RC_BIT_SONY12)) + if (!(enabled_protocols & RC_PROTO_BIT_SONY12)) return -EINVAL; func = raw & 0x7f; /* first 7 bits */ raw >>= 7; dev = raw & 0x1f; /* next 5 bits */ subdev = 0; - request->protocol = RC_TYPE_SONY12; + request->protocol = RC_PROTO_SONY12; break; case 15: - if (!(enabled_protocols & RC_BIT_SONY15)) + if (!(enabled_protocols & RC_PROTO_BIT_SONY15)) return -EINVAL; func = raw & 0x7f; /* first 7 bits */ raw >>= 7; dev = raw & 0xff; /* next 8 bits */ subdev = 0; - request->protocol = RC_TYPE_SONY15; + request->protocol = RC_PROTO_SONY15; break; case 20: - if (!(enabled_protocols & RC_BIT_SONY20)) + if (!(enabled_protocols & RC_PROTO_BIT_SONY20)) return -EINVAL; func = raw & 0x7f; /* first 7 bits */ raw >>= 7; dev = raw & 0x1f; /* next 5 bits */ raw >>= 5; subdev = raw & 0xff; /* next 8 bits */ - request->protocol = RC_TYPE_SONY20; + request->protocol = RC_PROTO_SONY20; break; default: return -EINVAL; @@ -68,7 +68,8 @@ static int img_ir_sony_filter(const struct rc_scancode_filter *in, func = (in->data >> 0) & 0x7f; func_m = (in->mask >> 0) & 0x7f; - protocols &= RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20; + protocols &= RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | + RC_PROTO_BIT_SONY20; /* * If only one bit is set, we were requested to do an exact @@ -77,20 +78,20 @@ static int img_ir_sony_filter(const struct rc_scancode_filter *in, */ if (!is_power_of_2(protocols)) { if (subdev & subdev_m) - protocols = RC_BIT_SONY20; + protocols = RC_PROTO_BIT_SONY20; else if (dev & dev_m & 0xe0) - protocols = RC_BIT_SONY15; + protocols = RC_PROTO_BIT_SONY15; else - protocols = RC_BIT_SONY12; + protocols = RC_PROTO_BIT_SONY12; } - if (protocols == RC_BIT_SONY20) { + if (protocols == RC_PROTO_BIT_SONY20) { /* can't encode subdev and higher device bits */ if (dev & dev_m & 0xe0) return -EINVAL; len = 20; dev_m &= 0x1f; - } else if (protocols == RC_BIT_SONY15) { + } else if (protocols == RC_PROTO_BIT_SONY15) { len = 15; subdev_m = 0; } else { @@ -128,7 +129,7 @@ static int img_ir_sony_filter(const struct rc_scancode_filter *in, * http://picprojects.org.uk/projects/sirc/sonysirc.pdf */ struct img_ir_decoder img_ir_sony = { - .type = RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20, + .type = RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | RC_PROTO_BIT_SONY20, .control = { .decoden = 1, .code_type = IMG_IR_CODETYPE_PULSELEN, diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index bd76534a2749..7b3f31cc63d2 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -148,7 +148,7 @@ struct imon_context { u32 last_keycode; /* last reported input keycode */ u32 rc_scancode; /* the computed remote scancode */ u8 rc_toggle; /* the computed remote toggle bit */ - u64 rc_type; /* iMON or MCE (RC6) IR protocol? */ + u64 rc_proto; /* iMON or MCE (RC6) IR protocol? */ bool release_code; /* some keys send a release code */ u8 display_type; /* store the display type */ @@ -911,7 +911,7 @@ static struct attribute *imon_display_sysfs_entries[] = { NULL }; -static struct attribute_group imon_display_attr_group = { +static const struct attribute_group imon_display_attr_group = { .attrs = imon_display_sysfs_entries }; @@ -920,7 +920,7 @@ static struct attribute *imon_rf_sysfs_entries[] = { NULL }; -static struct attribute_group imon_rf_attr_group = { +static const struct attribute_group imon_rf_attr_group = { .attrs = imon_rf_sysfs_entries }; @@ -1118,7 +1118,7 @@ static void imon_touch_display_timeout(unsigned long data) * it is not, so we must acquire it prior to calling send_packet, which * requires that the lock is held. */ -static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) +static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto) { int retval; struct imon_context *ictx = rc->priv; @@ -1127,25 +1127,25 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) unsigned char ir_proto_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; - if (*rc_type && !(*rc_type & rc->allowed_protocols)) + if (*rc_proto && !(*rc_proto & rc->allowed_protocols)) dev_warn(dev, "Looks like you're trying to use an IR protocol this device does not support\n"); - if (*rc_type & RC_BIT_RC6_MCE) { + if (*rc_proto & RC_PROTO_BIT_RC6_MCE) { dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); ir_proto_packet[0] = 0x01; - *rc_type = RC_BIT_RC6_MCE; - } else if (*rc_type & RC_BIT_OTHER) { + *rc_proto = RC_PROTO_BIT_RC6_MCE; + } else if (*rc_proto & RC_PROTO_BIT_OTHER) { dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); /* ir_proto_packet[0] = 0x00; // already the default */ - *rc_type = RC_BIT_OTHER; + *rc_proto = RC_PROTO_BIT_OTHER; } else { dev_warn(dev, "Unsupported IR protocol specified, overriding to iMON IR protocol\n"); if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); /* ir_proto_packet[0] = 0x00; // already the default */ - *rc_type = RC_BIT_OTHER; + *rc_proto = RC_PROTO_BIT_OTHER; } memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); @@ -1159,7 +1159,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) if (retval) goto out; - ictx->rc_type = *rc_type; + ictx->rc_proto = *rc_proto; ictx->pad_mouse = false; out: @@ -1435,7 +1435,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) rel_x = buf[2]; rel_y = buf[3]; - if (ictx->rc_type == RC_BIT_OTHER && pad_stabilize) { + if (ictx->rc_proto == RC_PROTO_BIT_OTHER && pad_stabilize) { if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) { dir = stabilize((int)rel_x, (int)rel_y, timeout, threshold); @@ -1502,7 +1502,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) buf[0] = 0x01; buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0; - if (ictx->rc_type == RC_BIT_OTHER && pad_stabilize) { + if (ictx->rc_proto == RC_PROTO_BIT_OTHER && pad_stabilize) { dir = stabilize((int)rel_x, (int)rel_y, timeout, threshold); if (!dir) { @@ -1706,7 +1706,7 @@ static void imon_incoming_scancode(struct imon_context *ictx, ictx->release_code = false; } else { scancode = be32_to_cpu(*((__be32 *)buf)); - if (ictx->rc_type == RC_BIT_RC6_MCE) { + if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE) { ktype = IMON_KEY_IMON; if (buf[0] == 0x80) ktype = IMON_KEY_MCE; @@ -1769,10 +1769,10 @@ static void imon_incoming_scancode(struct imon_context *ictx, if (press_type == 0) rc_keyup(ictx->rdev); else { - if (ictx->rc_type == RC_BIT_RC6_MCE || - ictx->rc_type == RC_BIT_OTHER) + if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE || + ictx->rc_proto == RC_PROTO_BIT_OTHER) rc_keydown(ictx->rdev, - ictx->rc_type == RC_BIT_RC6_MCE ? RC_TYPE_RC6_MCE : RC_TYPE_OTHER, + ictx->rc_proto == RC_PROTO_BIT_RC6_MCE ? RC_PROTO_RC6_MCE : RC_PROTO_OTHER, ictx->rc_scancode, ictx->rc_toggle); spin_lock_irqsave(&ictx->kc_lock, flags); ictx->last_keycode = ictx->kc; @@ -1936,7 +1936,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) { u8 ffdc_cfg_byte = ictx->usb_rx_buf[6]; u8 detected_display_type = IMON_DISPLAY_TYPE_NONE; - u64 allowed_protos = RC_BIT_OTHER; + u64 allowed_protos = RC_PROTO_BIT_OTHER; switch (ffdc_cfg_byte) { /* iMON Knob, no display, iMON IR + vol knob */ @@ -1967,27 +1967,27 @@ static void imon_get_ffdc_type(struct imon_context *ictx) case 0x9e: dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; - allowed_protos = RC_BIT_RC6_MCE; + allowed_protos = RC_PROTO_BIT_RC6_MCE; break; /* iMON LCD, MCE IR */ case 0x9f: dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR"); detected_display_type = IMON_DISPLAY_TYPE_LCD; - allowed_protos = RC_BIT_RC6_MCE; + allowed_protos = RC_PROTO_BIT_RC6_MCE; break; default: dev_info(ictx->dev, "Unknown 0xffdc device, defaulting to VFD and iMON IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; /* We don't know which one it is, allow user to set the * RC6 one from userspace if OTHER wasn't correct. */ - allowed_protos |= RC_BIT_RC6_MCE; + allowed_protos |= RC_PROTO_BIT_RC6_MCE; break; } printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte); ictx->display_type = detected_display_type; - ictx->rc_type = allowed_protos; + ictx->rc_proto = allowed_protos; } static void imon_set_display_type(struct imon_context *ictx) @@ -2063,17 +2063,18 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) sizeof(ictx->phys_rdev)); strlcat(ictx->phys_rdev, "/input0", sizeof(ictx->phys_rdev)); - rdev->input_name = ictx->name_rdev; + rdev->device_name = ictx->name_rdev; rdev->input_phys = ictx->phys_rdev; usb_to_input_id(ictx->usbdev_intf0, &rdev->input_id); rdev->dev.parent = ictx->dev; rdev->priv = ictx; if (ictx->dev_descr->flags & IMON_IR_RAW) - rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; else /* iMON PAD or MCE */ - rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE; + rdev->allowed_protocols = RC_PROTO_BIT_OTHER | + RC_PROTO_BIT_RC6_MCE; rdev->change_protocol = imon_ir_change_protocol; rdev->driver_name = MOD_NAME; @@ -2086,12 +2087,12 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) if (ictx->product == 0xffdc) { imon_get_ffdc_type(ictx); - rdev->allowed_protocols = ictx->rc_type; + rdev->allowed_protocols = ictx->rc_proto; } imon_set_display_type(ictx); - if (ictx->rc_type == RC_BIT_RC6_MCE || + if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE || ictx->dev_descr->flags & IMON_IR_RAW) rdev->map_name = RC_MAP_IMON_MCE; else diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index 50951f686852..0ce11c41dfae 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -242,14 +242,14 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) clk_prepare_enable(priv->clock); priv->rate = clk_get_rate(priv->clock); - rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rdev->priv = priv; rdev->open = hix5hd2_ir_open; rdev->close = hix5hd2_ir_close; rdev->driver_name = IR_HIX5HD2_NAME; map_name = of_get_property(node, "linux,rc-map-name", NULL); rdev->map_name = map_name ?: RC_MAP_EMPTY; - rdev->input_name = IR_HIX5HD2_NAME; + rdev->device_name = IR_HIX5HD2_NAME; rdev->input_phys = IR_HIX5HD2_NAME "/input0"; rdev->input_id.bustype = BUS_HOST; rdev->input_id.vendor = 0x0001; diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c index 674bf156edcb..e2bd68c42edf 100644 --- a/drivers/media/rc/ir-jvc-decoder.c +++ b/drivers/media/rc/ir-jvc-decoder.c @@ -137,7 +137,7 @@ again: scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) | (bitrev8((data->bits >> 0) & 0xff) << 0); IR_dprintk(1, "JVC scancode 0x%04x\n", scancode); - rc_keydown(dev, RC_TYPE_JVC, scancode, data->toggle); + rc_keydown(dev, RC_PROTO_JVC, scancode, data->toggle); data->first = false; data->old_bits = data->bits; } else if (data->bits == data->old_bits) { @@ -193,7 +193,7 @@ static const struct ir_raw_timings_pd ir_jvc_timings = { * -ENOBUFS if there isn't enough space in the array to fit the * encoding. In this case all @max events will have been written. */ -static int ir_jvc_encode(enum rc_type protocol, u32 scancode, +static int ir_jvc_encode(enum rc_proto protocol, u32 scancode, struct ir_raw_event *events, unsigned int max) { struct ir_raw_event *e = events; @@ -209,7 +209,7 @@ static int ir_jvc_encode(enum rc_type protocol, u32 scancode, } static struct ir_raw_handler jvc_handler = { - .protocols = RC_BIT_JVC, + .protocols = RC_PROTO_BIT_JVC, .decode = ir_jvc_decode, .encode = ir_jvc_encode, }; diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 6a4d58b88d91..7c572a643656 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -358,6 +358,9 @@ static int ir_mce_kbd_register(struct rc_dev *dev) struct input_dev *idev; int i, ret; + if (dev->driver_type == RC_DRIVER_IR_RAW_TX) + return 0; + idev = input_allocate_device(); if (!idev) return -ENOMEM; @@ -413,6 +416,9 @@ static int ir_mce_kbd_unregister(struct rc_dev *dev) struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd; struct input_dev *idev = mce_kbd->idev; + if (dev->driver_type == RC_DRIVER_IR_RAW_TX) + return 0; + del_timer_sync(&mce_kbd->rx_timeout); input_unregister_device(idev); @@ -438,14 +444,14 @@ static const struct ir_raw_timings_manchester ir_mce_kbd_timings = { * -ENOBUFS if there isn't enough space in the array to fit the * encoding. In this case all @max events will have been written. */ -static int ir_mce_kbd_encode(enum rc_type protocol, u32 scancode, +static int ir_mce_kbd_encode(enum rc_proto protocol, u32 scancode, struct ir_raw_event *events, unsigned int max) { struct ir_raw_event *e = events; int len, ret; u64 raw; - if (protocol == RC_TYPE_MCIR2_KBD) { + if (protocol == RC_PROTO_MCIR2_KBD) { raw = scancode | ((u64)MCIR2_KEYBOARD_HEADER << MCIR2_KEYBOARD_NBITS); len = MCIR2_KEYBOARD_NBITS + MCIR2_HEADER_NBITS + 1; @@ -463,7 +469,7 @@ static int ir_mce_kbd_encode(enum rc_type protocol, u32 scancode, } static struct ir_raw_handler mce_kbd_handler = { - .protocols = RC_BIT_MCIR2_KBD | RC_BIT_MCIR2_MSE, + .protocols = RC_PROTO_BIT_MCIR2_KBD | RC_PROTO_BIT_MCIR2_MSE, .decode = ir_mce_kbd_decode, .encode = ir_mce_kbd_encode, .raw_register = ir_mce_kbd_register, diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 3ce850314dca..817c18f2ddd1 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -49,9 +49,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct nec_dec *data = &dev->raw->nec; u32 scancode; - enum rc_type rc_type; + enum rc_proto rc_proto; u8 address, not_address, command, not_command; - bool send_32bits = false; if (!is_timing_event(ev)) { if (ev.reset) @@ -88,13 +87,9 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) data->state = STATE_BIT_PULSE; return 0; } else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) { - if (!dev->keypressed) { - IR_dprintk(1, "Discarding last key repeat: event after key up\n"); - } else { - rc_repeat(dev); - IR_dprintk(1, "Repeat last key\n"); - data->state = STATE_TRAILER_PULSE; - } + rc_repeat(dev); + IR_dprintk(1, "Repeat last key\n"); + data->state = STATE_TRAILER_PULSE; return 0; } @@ -161,39 +156,14 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) command = bitrev8((data->bits >> 8) & 0xff); not_command = bitrev8((data->bits >> 0) & 0xff); - if ((command ^ not_command) != 0xff) { - IR_dprintk(1, "NEC checksum error: received 0x%08x\n", - data->bits); - send_32bits = true; - } - - if (send_32bits) { - /* NEC transport, but modified protocol, used by at - * least Apple and TiVo remotes */ - scancode = not_address << 24 | - address << 16 | - not_command << 8 | - command; - IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode); - rc_type = RC_TYPE_NEC32; - } else if ((address ^ not_address) != 0xff) { - /* Extended NEC */ - scancode = address << 16 | - not_address << 8 | - command; - IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode); - rc_type = RC_TYPE_NECX; - } else { - /* Normal NEC */ - scancode = address << 8 | command; - IR_dprintk(1, "NEC scancode 0x%04x\n", scancode); - rc_type = RC_TYPE_NEC; - } + scancode = ir_nec_bytes_to_scancode(address, not_address, + command, not_command, + &rc_proto); if (data->is_nec_x) data->necx_repeat = true; - rc_keydown(dev, rc_type, scancode, 0); + rc_keydown(dev, rc_proto, scancode, 0); data->state = STATE_INACTIVE; return 0; } @@ -210,19 +180,19 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) * @scancode: a single NEC scancode. * @raw: raw data to be modulated. */ -static u32 ir_nec_scancode_to_raw(enum rc_type protocol, u32 scancode) +static u32 ir_nec_scancode_to_raw(enum rc_proto protocol, u32 scancode) { unsigned int addr, addr_inv, data, data_inv; data = scancode & 0xff; - if (protocol == RC_TYPE_NEC32) { + if (protocol == RC_PROTO_NEC32) { /* 32-bit NEC (used by Apple and TiVo remotes) */ /* scan encoding: aaAAddDD */ addr_inv = (scancode >> 24) & 0xff; addr = (scancode >> 16) & 0xff; data_inv = (scancode >> 8) & 0xff; - } else if (protocol == RC_TYPE_NECX) { + } else if (protocol == RC_PROTO_NECX) { /* Extended NEC */ /* scan encoding AAaaDD */ addr = (scancode >> 16) & 0xff; @@ -266,7 +236,7 @@ static const struct ir_raw_timings_pd ir_nec_timings = { * -ENOBUFS if there isn't enough space in the array to fit the * encoding. In this case all @max events will have been written. */ -static int ir_nec_encode(enum rc_type protocol, u32 scancode, +static int ir_nec_encode(enum rc_proto protocol, u32 scancode, struct ir_raw_event *events, unsigned int max) { struct ir_raw_event *e = events; @@ -285,7 +255,8 @@ static int ir_nec_encode(enum rc_type protocol, u32 scancode, } static struct ir_raw_handler nec_handler = { - .protocols = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32, + .protocols = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | + RC_PROTO_BIT_NEC32, .decode = ir_nec_decode, .encode = ir_nec_encode, }; diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index fcfedf95def7..1292f534de43 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -51,7 +51,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) struct rc5_dec *data = &dev->raw->rc5; u8 toggle; u32 scancode; - enum rc_type protocol; + enum rc_proto protocol; if (!is_timing_event(ev)) { if (ev.reset) @@ -124,7 +124,7 @@ again: if (data->is_rc5x && data->count == RC5X_NBITS) { /* RC5X */ u8 xdata, command, system; - if (!(dev->enabled_protocols & RC_BIT_RC5X_20)) { + if (!(dev->enabled_protocols & RC_PROTO_BIT_RC5X_20)) { data->state = STATE_INACTIVE; return 0; } @@ -134,12 +134,12 @@ again: toggle = (data->bits & 0x20000) ? 1 : 0; command += (data->bits & 0x40000) ? 0 : 0x40; scancode = system << 16 | command << 8 | xdata; - protocol = RC_TYPE_RC5X_20; + protocol = RC_PROTO_RC5X_20; } else if (!data->is_rc5x && data->count == RC5_NBITS) { /* RC5 */ u8 command, system; - if (!(dev->enabled_protocols & RC_BIT_RC5)) { + if (!(dev->enabled_protocols & RC_PROTO_BIT_RC5)) { data->state = STATE_INACTIVE; return 0; } @@ -148,12 +148,12 @@ again: toggle = (data->bits & 0x00800) ? 1 : 0; command += (data->bits & 0x01000) ? 0 : 0x40; scancode = system << 8 | command; - protocol = RC_TYPE_RC5; + protocol = RC_PROTO_RC5; } else if (!data->is_rc5x && data->count == RC5_SZ_NBITS) { /* RC5 StreamZap */ u8 command, system; - if (!(dev->enabled_protocols & RC_BIT_RC5_SZ)) { + if (!(dev->enabled_protocols & RC_PROTO_BIT_RC5_SZ)) { data->state = STATE_INACTIVE; return 0; } @@ -161,7 +161,7 @@ again: system = (data->bits & 0x02FC0) >> 6; toggle = (data->bits & 0x01000) ? 1 : 0; scancode = system << 6 | command; - protocol = RC_TYPE_RC5_SZ; + protocol = RC_PROTO_RC5_SZ; } else break; @@ -221,7 +221,7 @@ static const struct ir_raw_timings_manchester ir_rc5_sz_timings = { * encoding. In this case all @max events will have been written. * -EINVAL if the scancode is ambiguous or invalid. */ -static int ir_rc5_encode(enum rc_type protocol, u32 scancode, +static int ir_rc5_encode(enum rc_proto protocol, u32 scancode, struct ir_raw_event *events, unsigned int max) { int ret; @@ -229,7 +229,7 @@ static int ir_rc5_encode(enum rc_type protocol, u32 scancode, unsigned int data, xdata, command, commandx, system, pre_space_data; /* Detect protocol and convert scancode to raw data */ - if (protocol == RC_TYPE_RC5) { + if (protocol == RC_PROTO_RC5) { /* decode scancode */ command = (scancode & 0x003f) >> 0; commandx = (scancode & 0x0040) >> 6; @@ -242,7 +242,7 @@ static int ir_rc5_encode(enum rc_type protocol, u32 scancode, RC5_NBITS, data); if (ret < 0) return ret; - } else if (protocol == RC_TYPE_RC5X_20) { + } else if (protocol == RC_PROTO_RC5X_20) { /* decode scancode */ xdata = (scancode & 0x00003f) >> 0; command = (scancode & 0x003f00) >> 8; @@ -264,7 +264,7 @@ static int ir_rc5_encode(enum rc_type protocol, u32 scancode, data); if (ret < 0) return ret; - } else if (protocol == RC_TYPE_RC5_SZ) { + } else if (protocol == RC_PROTO_RC5_SZ) { /* RC5-SZ scancode is raw enough for Manchester as it is */ ret = ir_raw_gen_manchester(&e, max, &ir_rc5_sz_timings, RC5_SZ_NBITS, scancode & 0x2fff); @@ -278,7 +278,8 @@ static int ir_rc5_encode(enum rc_type protocol, u32 scancode, } static struct ir_raw_handler rc5_handler = { - .protocols = RC_BIT_RC5 | RC_BIT_RC5X_20 | RC_BIT_RC5_SZ, + .protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | + RC_PROTO_BIT_RC5_SZ, .decode = ir_rc5_decode, .encode = ir_rc5_encode, }; diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index 6fe2268dada0..5d0d2fe3b7a7 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -88,7 +88,7 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev) struct rc6_dec *data = &dev->raw->rc6; u32 scancode; u8 toggle; - enum rc_type protocol; + enum rc_proto protocol; if (!is_timing_event(ev)) { if (ev.reset) @@ -229,7 +229,7 @@ again: case RC6_MODE_0: scancode = data->body; toggle = data->toggle; - protocol = RC_TYPE_RC6_0; + protocol = RC_PROTO_RC6_0; IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n", scancode, toggle); break; @@ -244,20 +244,20 @@ again: scancode = data->body; switch (data->count) { case 20: - protocol = RC_TYPE_RC6_6A_20; + protocol = RC_PROTO_RC6_6A_20; toggle = 0; break; case 24: - protocol = RC_TYPE_RC6_6A_24; + protocol = RC_PROTO_RC6_6A_24; toggle = 0; break; case 32: if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) { - protocol = RC_TYPE_RC6_MCE; + protocol = RC_PROTO_RC6_MCE; toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK); scancode &= ~RC6_6A_MCE_TOGGLE_MASK; } else { - protocol = RC_TYPE_RC6_6A_32; + protocol = RC_PROTO_RC6_6A_32; toggle = 0; } break; @@ -322,13 +322,13 @@ static const struct ir_raw_timings_manchester ir_rc6_timings[4] = { * encoding. In this case all @max events will have been written. * -EINVAL if the scancode is ambiguous or invalid. */ -static int ir_rc6_encode(enum rc_type protocol, u32 scancode, +static int ir_rc6_encode(enum rc_proto protocol, u32 scancode, struct ir_raw_event *events, unsigned int max) { int ret; struct ir_raw_event *e = events; - if (protocol == RC_TYPE_RC6_0) { + if (protocol == RC_PROTO_RC6_0) { /* Modulate the preamble */ ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0); if (ret < 0) @@ -358,14 +358,14 @@ static int ir_rc6_encode(enum rc_type protocol, u32 scancode, int bits; switch (protocol) { - case RC_TYPE_RC6_MCE: - case RC_TYPE_RC6_6A_32: + case RC_PROTO_RC6_MCE: + case RC_PROTO_RC6_6A_32: bits = 32; break; - case RC_TYPE_RC6_6A_24: + case RC_PROTO_RC6_6A_24: bits = 24; break; - case RC_TYPE_RC6_6A_20: + case RC_PROTO_RC6_6A_20: bits = 20; break; default: @@ -403,9 +403,9 @@ static int ir_rc6_encode(enum rc_type protocol, u32 scancode, } static struct ir_raw_handler rc6_handler = { - .protocols = RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | - RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | - RC_BIT_RC6_MCE, + .protocols = RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | + RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | + RC_PROTO_BIT_RC6_MCE, .decode = ir_rc6_decode, .encode = ir_rc6_encode, }; diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index 520bb77dcb62..758c60956850 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -110,13 +110,9 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) break; if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) { - if (!dev->keypressed) { - IR_dprintk(1, "SANYO discarding last key repeat: event after key up\n"); - } else { - rc_repeat(dev); - IR_dprintk(1, "SANYO repeat last key\n"); - data->state = STATE_INACTIVE; - } + rc_repeat(dev); + IR_dprintk(1, "SANYO repeat last key\n"); + data->state = STATE_INACTIVE; return 0; } @@ -165,7 +161,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) scancode = address << 8 | command; IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode); - rc_keydown(dev, RC_TYPE_SANYO, scancode, 0); + rc_keydown(dev, RC_PROTO_SANYO, scancode, 0); data->state = STATE_INACTIVE; return 0; } @@ -199,7 +195,7 @@ static const struct ir_raw_timings_pd ir_sanyo_timings = { * -ENOBUFS if there isn't enough space in the array to fit the * encoding. In this case all @max events will have been written. */ -static int ir_sanyo_encode(enum rc_type protocol, u32 scancode, +static int ir_sanyo_encode(enum rc_proto protocol, u32 scancode, struct ir_raw_event *events, unsigned int max) { struct ir_raw_event *e = events; @@ -219,7 +215,7 @@ static int ir_sanyo_encode(enum rc_type protocol, u32 scancode, } static struct ir_raw_handler sanyo_handler = { - .protocols = RC_BIT_SANYO, + .protocols = RC_PROTO_BIT_SANYO, .decode = ir_sanyo_decode, .encode = ir_sanyo_encode, }; diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c index b47e89e2c1bd..ed43a4212479 100644 --- a/drivers/media/rc/ir-sharp-decoder.c +++ b/drivers/media/rc/ir-sharp-decoder.c @@ -161,7 +161,7 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) scancode = address << 8 | command; IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode); - rc_keydown(dev, RC_TYPE_SHARP, scancode, 0); + rc_keydown(dev, RC_PROTO_SHARP, scancode, 0); data->state = STATE_INACTIVE; return 0; } @@ -196,7 +196,7 @@ static const struct ir_raw_timings_pd ir_sharp_timings = { * -ENOBUFS if there isn't enough space in the array to fit the * encoding. In this case all @max events will have been written. */ -static int ir_sharp_encode(enum rc_type protocol, u32 scancode, +static int ir_sharp_encode(enum rc_proto protocol, u32 scancode, struct ir_raw_event *events, unsigned int max) { struct ir_raw_event *e = events; @@ -223,7 +223,7 @@ static int ir_sharp_encode(enum rc_type protocol, u32 scancode, } static struct ir_raw_handler sharp_handler = { - .protocols = RC_BIT_SHARP, + .protocols = RC_PROTO_BIT_SHARP, .decode = ir_sharp_decode, .encode = ir_sharp_encode, }; diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index 355fa8198f5a..a47ced763031 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -42,7 +42,7 @@ enum sony_state { static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct sony_dec *data = &dev->raw->sony; - enum rc_type protocol; + enum rc_proto protocol; u32 scancode; u8 device, subdevice, function; @@ -121,31 +121,31 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) switch (data->count) { case 12: - if (!(dev->enabled_protocols & RC_BIT_SONY12)) + if (!(dev->enabled_protocols & RC_PROTO_BIT_SONY12)) goto finish_state_machine; device = bitrev8((data->bits << 3) & 0xF8); subdevice = 0; function = bitrev8((data->bits >> 4) & 0xFE); - protocol = RC_TYPE_SONY12; + protocol = RC_PROTO_SONY12; break; case 15: - if (!(dev->enabled_protocols & RC_BIT_SONY15)) + if (!(dev->enabled_protocols & RC_PROTO_BIT_SONY15)) goto finish_state_machine; device = bitrev8((data->bits >> 0) & 0xFF); subdevice = 0; function = bitrev8((data->bits >> 7) & 0xFE); - protocol = RC_TYPE_SONY15; + protocol = RC_PROTO_SONY15; break; case 20: - if (!(dev->enabled_protocols & RC_BIT_SONY20)) + if (!(dev->enabled_protocols & RC_PROTO_BIT_SONY20)) goto finish_state_machine; device = bitrev8((data->bits >> 5) & 0xF8); subdevice = bitrev8((data->bits >> 0) & 0xFF); function = bitrev8((data->bits >> 12) & 0xFE); - protocol = RC_TYPE_SONY20; + protocol = RC_PROTO_SONY20; break; default: IR_dprintk(1, "Sony invalid bitcount %u\n", data->count); @@ -190,17 +190,17 @@ static const struct ir_raw_timings_pl ir_sony_timings = { * -ENOBUFS if there isn't enough space in the array to fit the * encoding. In this case all @max events will have been written. */ -static int ir_sony_encode(enum rc_type protocol, u32 scancode, +static int ir_sony_encode(enum rc_proto protocol, u32 scancode, struct ir_raw_event *events, unsigned int max) { struct ir_raw_event *e = events; u32 raw, len; int ret; - if (protocol == RC_TYPE_SONY12) { + if (protocol == RC_PROTO_SONY12) { raw = (scancode & 0x7f) | ((scancode & 0x1f0000) >> 9); len = 12; - } else if (protocol == RC_TYPE_SONY15) { + } else if (protocol == RC_PROTO_SONY15) { raw = (scancode & 0x7f) | ((scancode & 0xff0000) >> 9); len = 15; } else { @@ -217,7 +217,8 @@ static int ir_sony_encode(enum rc_type protocol, u32 scancode, } static struct ir_raw_handler sony_handler = { - .protocols = RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20, + .protocols = RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | + RC_PROTO_BIT_SONY20, .decode = ir_sony_decode, .encode = ir_sony_encode, }; diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c index 7e383b3fedd5..29ed0638cb74 100644 --- a/drivers/media/rc/ir-spi.c +++ b/drivers/media/rc/ir-spi.c @@ -155,6 +155,7 @@ static int ir_spi_probe(struct spi_device *spi) idata->rc->tx_ir = ir_spi_tx; idata->rc->s_tx_carrier = ir_spi_set_tx_carrier; idata->rc->s_tx_duty_cycle = ir_spi_set_duty_cycle; + idata->rc->device_name = "IR SPI"; idata->rc->driver_name = IR_SPI_DRIVER_NAME; idata->rc->priv = idata; idata->spi = spi; diff --git a/drivers/media/rc/ir-xmp-decoder.c b/drivers/media/rc/ir-xmp-decoder.c index 18596190bbb8..6f464be1c8d7 100644 --- a/drivers/media/rc/ir-xmp-decoder.c +++ b/drivers/media/rc/ir-xmp-decoder.c @@ -141,7 +141,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) IR_dprintk(1, "XMP scancode 0x%06x\n", scancode); if (toggle == 0) { - rc_keydown(dev, RC_TYPE_XMP, scancode, 0); + rc_keydown(dev, RC_PROTO_XMP, scancode, 0); } else { rc_repeat(dev); IR_dprintk(1, "Repeat last key\n"); @@ -196,7 +196,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) } static struct ir_raw_handler xmp_handler = { - .protocols = RC_BIT_XMP, + .protocols = RC_PROTO_BIT_XMP, .decode = ir_xmp_decode, }; diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index e9e4befbbebb..65e104c7ddfc 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1556,7 +1556,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id /* set up ir-core props */ rdev->priv = itdev; - rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rdev->open = ite_open; rdev->close = ite_close; rdev->s_idle = ite_s_idle; @@ -1576,7 +1576,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id rdev->s_tx_duty_cycle = ite_set_tx_duty_cycle; } - rdev->input_name = dev_desc->model; + rdev->device_name = dev_desc->model; rdev->input_id.bustype = BUS_HOST; rdev->input_id.vendor = PCI_VENDOR_ID_ITE; rdev->input_id.product = 0; diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 2945f99907b5..af6496d709fb 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -109,4 +109,5 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-videomate-tv-pvr.o \ rc-winfast.o \ rc-winfast-usbii-deluxe.o \ - rc-su3000.o + rc-su3000.o \ + rc-zx-irdec.o 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 01d901fbfc8b..2d303c2cee3b 100644 --- a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c +++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c @@ -66,10 +66,10 @@ static struct rc_map_table adstech_dvb_t_pci[] = { static struct rc_map_list adstech_dvb_t_pci_map = { .map = { - .scan = adstech_dvb_t_pci, - .size = ARRAY_SIZE(adstech_dvb_t_pci), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_ADSTECH_DVB_T_PCI, + .scan = adstech_dvb_t_pci, + .size = ARRAY_SIZE(adstech_dvb_t_pci), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_ADSTECH_DVB_T_PCI, } }; diff --git a/drivers/media/rc/keymaps/rc-alink-dtu-m.c b/drivers/media/rc/keymaps/rc-alink-dtu-m.c index 4e6ade8e616f..3818c33734a1 100644 --- a/drivers/media/rc/keymaps/rc-alink-dtu-m.c +++ b/drivers/media/rc/keymaps/rc-alink-dtu-m.c @@ -45,10 +45,10 @@ static struct rc_map_table alink_dtu_m[] = { static struct rc_map_list alink_dtu_m_map = { .map = { - .scan = alink_dtu_m, - .size = ARRAY_SIZE(alink_dtu_m), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_ALINK_DTU_M, + .scan = alink_dtu_m, + .size = ARRAY_SIZE(alink_dtu_m), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_ALINK_DTU_M, } }; diff --git a/drivers/media/rc/keymaps/rc-anysee.c b/drivers/media/rc/keymaps/rc-anysee.c index c735fe10a390..e75e51b34d29 100644 --- a/drivers/media/rc/keymaps/rc-anysee.c +++ b/drivers/media/rc/keymaps/rc-anysee.c @@ -70,10 +70,10 @@ static struct rc_map_table anysee[] = { static struct rc_map_list anysee_map = { .map = { - .scan = anysee, - .size = ARRAY_SIZE(anysee), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_ANYSEE, + .scan = anysee, + .size = ARRAY_SIZE(anysee), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_ANYSEE, } }; diff --git a/drivers/media/rc/keymaps/rc-apac-viewcomp.c b/drivers/media/rc/keymaps/rc-apac-viewcomp.c index bf9efa007e1c..65bc8957d9c3 100644 --- a/drivers/media/rc/keymaps/rc-apac-viewcomp.c +++ b/drivers/media/rc/keymaps/rc-apac-viewcomp.c @@ -57,10 +57,10 @@ static struct rc_map_table apac_viewcomp[] = { static struct rc_map_list apac_viewcomp_map = { .map = { - .scan = apac_viewcomp, - .size = ARRAY_SIZE(apac_viewcomp), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_APAC_VIEWCOMP, + .scan = apac_viewcomp, + .size = ARRAY_SIZE(apac_viewcomp), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_APAC_VIEWCOMP, } }; diff --git a/drivers/media/rc/keymaps/rc-asus-pc39.c b/drivers/media/rc/keymaps/rc-asus-pc39.c index 9e674ba5dd4f..530e1d1158d1 100644 --- a/drivers/media/rc/keymaps/rc-asus-pc39.c +++ b/drivers/media/rc/keymaps/rc-asus-pc39.c @@ -68,10 +68,10 @@ static struct rc_map_table asus_pc39[] = { static struct rc_map_list asus_pc39_map = { .map = { - .scan = asus_pc39, - .size = ARRAY_SIZE(asus_pc39), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_ASUS_PC39, + .scan = asus_pc39, + .size = ARRAY_SIZE(asus_pc39), + .rc_proto = RC_PROTO_RC5, + .name = RC_MAP_ASUS_PC39, } }; diff --git a/drivers/media/rc/keymaps/rc-asus-ps3-100.c b/drivers/media/rc/keymaps/rc-asus-ps3-100.c index e45de35f528f..c91ba332984c 100644 --- a/drivers/media/rc/keymaps/rc-asus-ps3-100.c +++ b/drivers/media/rc/keymaps/rc-asus-ps3-100.c @@ -67,10 +67,10 @@ static struct rc_map_table asus_ps3_100[] = { static struct rc_map_list asus_ps3_100_map = { .map = { - .scan = asus_ps3_100, - .size = ARRAY_SIZE(asus_ps3_100), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_ASUS_PS3_100, + .scan = asus_ps3_100, + .size = ARRAY_SIZE(asus_ps3_100), + .rc_proto = RC_PROTO_RC5, + .name = RC_MAP_ASUS_PS3_100, } }; 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 91392d4cfd6d..11b4bdd2392b 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 @@ -46,10 +46,10 @@ static struct rc_map_table ati_tv_wonder_hd_600[] = { static struct rc_map_list ati_tv_wonder_hd_600_map = { .map = { - .scan = ati_tv_wonder_hd_600, - .size = ARRAY_SIZE(ati_tv_wonder_hd_600), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_ATI_TV_WONDER_HD_600, + .scan = ati_tv_wonder_hd_600, + .size = ARRAY_SIZE(ati_tv_wonder_hd_600), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_ATI_TV_WONDER_HD_600, } }; diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c index 4bdc709ec54d..11f1eb6ad712 100644 --- a/drivers/media/rc/keymaps/rc-ati-x10.c +++ b/drivers/media/rc/keymaps/rc-ati-x10.c @@ -114,10 +114,10 @@ static struct rc_map_table ati_x10[] = { static struct rc_map_list ati_x10_map = { .map = { - .scan = ati_x10, - .size = ARRAY_SIZE(ati_x10), - .rc_type = RC_TYPE_OTHER, - .name = RC_MAP_ATI_X10, + .scan = ati_x10, + .size = ARRAY_SIZE(ati_x10), + .rc_proto = RC_PROTO_OTHER, + .name = RC_MAP_ATI_X10, } }; diff --git a/drivers/media/rc/keymaps/rc-avermedia-a16d.c b/drivers/media/rc/keymaps/rc-avermedia-a16d.c index ff30a71d623e..510dc90ebf49 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-a16d.c +++ b/drivers/media/rc/keymaps/rc-avermedia-a16d.c @@ -52,10 +52,10 @@ static struct rc_map_table avermedia_a16d[] = { static struct rc_map_list avermedia_a16d_map = { .map = { - .scan = avermedia_a16d, - .size = ARRAY_SIZE(avermedia_a16d), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_AVERMEDIA_A16D, + .scan = avermedia_a16d, + .size = ARRAY_SIZE(avermedia_a16d), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_AVERMEDIA_A16D, } }; diff --git a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c index d7471a6de9b4..4bbc1e68d1b8 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c +++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c @@ -74,10 +74,10 @@ static struct rc_map_table avermedia_cardbus[] = { static struct rc_map_list avermedia_cardbus_map = { .map = { - .scan = avermedia_cardbus, - .size = ARRAY_SIZE(avermedia_cardbus), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_AVERMEDIA_CARDBUS, + .scan = avermedia_cardbus, + .size = ARRAY_SIZE(avermedia_cardbus), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_AVERMEDIA_CARDBUS, } }; diff --git a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c index e2417d6331fe..f6b8547dbad3 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c +++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c @@ -55,10 +55,10 @@ static struct rc_map_table avermedia_dvbt[] = { static struct rc_map_list avermedia_dvbt_map = { .map = { - .scan = avermedia_dvbt, - .size = ARRAY_SIZE(avermedia_dvbt), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_AVERMEDIA_DVBT, + .scan = avermedia_dvbt, + .size = ARRAY_SIZE(avermedia_dvbt), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_AVERMEDIA_DVBT, } }; diff --git a/drivers/media/rc/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c index 843598a5f1b5..9882e2cde975 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m135a.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c @@ -124,10 +124,10 @@ static struct rc_map_table avermedia_m135a[] = { static struct rc_map_list avermedia_m135a_map = { .map = { - .scan = avermedia_m135a, - .size = ARRAY_SIZE(avermedia_m135a), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_AVERMEDIA_M135A, + .scan = avermedia_m135a, + .size = ARRAY_SIZE(avermedia_m135a), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_AVERMEDIA_M135A, } }; 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 b24e7481ac21..d86126e10375 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c @@ -72,10 +72,10 @@ static struct rc_map_table avermedia_m733a_rm_k6[] = { static struct rc_map_list avermedia_m733a_rm_k6_map = { .map = { - .scan = avermedia_m733a_rm_k6, - .size = ARRAY_SIZE(avermedia_m733a_rm_k6), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_AVERMEDIA_M733A_RM_K6, + .scan = avermedia_m733a_rm_k6, + .size = ARRAY_SIZE(avermedia_m733a_rm_k6), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_AVERMEDIA_M733A_RM_K6, } }; diff --git a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c index 2583400ca1b4..5d92d36d9174 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c +++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c @@ -56,10 +56,10 @@ static struct rc_map_table avermedia_rm_ks[] = { static struct rc_map_list avermedia_rm_ks_map = { .map = { - .scan = avermedia_rm_ks, - .size = ARRAY_SIZE(avermedia_rm_ks), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_AVERMEDIA_RM_KS, + .scan = avermedia_rm_ks, + .size = ARRAY_SIZE(avermedia_rm_ks), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_AVERMEDIA_RM_KS, } }; diff --git a/drivers/media/rc/keymaps/rc-avermedia.c b/drivers/media/rc/keymaps/rc-avermedia.c index 3f68fbecc188..6503f11c7df5 100644 --- a/drivers/media/rc/keymaps/rc-avermedia.c +++ b/drivers/media/rc/keymaps/rc-avermedia.c @@ -63,10 +63,10 @@ static struct rc_map_table avermedia[] = { static struct rc_map_list avermedia_map = { .map = { - .scan = avermedia, - .size = ARRAY_SIZE(avermedia), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_AVERMEDIA, + .scan = avermedia, + .size = ARRAY_SIZE(avermedia), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_AVERMEDIA, } }; diff --git a/drivers/media/rc/keymaps/rc-avertv-303.c b/drivers/media/rc/keymaps/rc-avertv-303.c index c35bc5b835c4..fbdd7ada57ce 100644 --- a/drivers/media/rc/keymaps/rc-avertv-303.c +++ b/drivers/media/rc/keymaps/rc-avertv-303.c @@ -62,10 +62,10 @@ static struct rc_map_table avertv_303[] = { static struct rc_map_list avertv_303_map = { .map = { - .scan = avertv_303, - .size = ARRAY_SIZE(avertv_303), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_AVERTV_303, + .scan = avertv_303, + .size = ARRAY_SIZE(avertv_303), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_AVERTV_303, } }; diff --git a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c index ea7f2d0f31eb..18d7dcb869b0 100644 --- a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c +++ b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c @@ -79,10 +79,10 @@ static struct rc_map_table azurewave_ad_tu700[] = { static struct rc_map_list azurewave_ad_tu700_map = { .map = { - .scan = azurewave_ad_tu700, - .size = ARRAY_SIZE(azurewave_ad_tu700), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_AZUREWAVE_AD_TU700, + .scan = azurewave_ad_tu700, + .size = ARRAY_SIZE(azurewave_ad_tu700), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_AZUREWAVE_AD_TU700, } }; diff --git a/drivers/media/rc/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c index 1fc344e9daa7..d256743be998 100644 --- a/drivers/media/rc/keymaps/rc-behold-columbus.c +++ b/drivers/media/rc/keymaps/rc-behold-columbus.c @@ -85,10 +85,10 @@ static struct rc_map_table behold_columbus[] = { static struct rc_map_list behold_columbus_map = { .map = { - .scan = behold_columbus, - .size = ARRAY_SIZE(behold_columbus), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_BEHOLD_COLUMBUS, + .scan = behold_columbus, + .size = ARRAY_SIZE(behold_columbus), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_BEHOLD_COLUMBUS, } }; diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c index 520a96f2ff86..93dc795adc67 100644 --- a/drivers/media/rc/keymaps/rc-behold.c +++ b/drivers/media/rc/keymaps/rc-behold.c @@ -118,10 +118,10 @@ static struct rc_map_table behold[] = { static struct rc_map_list behold_map = { .map = { - .scan = behold, - .size = ARRAY_SIZE(behold), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_BEHOLD, + .scan = behold, + .size = ARRAY_SIZE(behold), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_BEHOLD, } }; diff --git a/drivers/media/rc/keymaps/rc-budget-ci-old.c b/drivers/media/rc/keymaps/rc-budget-ci-old.c index b196a5f436a3..81ea1424d9e5 100644 --- a/drivers/media/rc/keymaps/rc-budget-ci-old.c +++ b/drivers/media/rc/keymaps/rc-budget-ci-old.c @@ -70,10 +70,10 @@ static struct rc_map_table budget_ci_old[] = { static struct rc_map_list budget_ci_old_map = { .map = { - .scan = budget_ci_old, - .size = ARRAY_SIZE(budget_ci_old), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_BUDGET_CI_OLD, + .scan = budget_ci_old, + .size = ARRAY_SIZE(budget_ci_old), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_BUDGET_CI_OLD, } }; diff --git a/drivers/media/rc/keymaps/rc-cec.c b/drivers/media/rc/keymaps/rc-cec.c index 354c8e724b8e..76d34abb7c85 100644 --- a/drivers/media/rc/keymaps/rc-cec.c +++ b/drivers/media/rc/keymaps/rc-cec.c @@ -160,7 +160,7 @@ static struct rc_map_list cec_map = { .map = { .scan = cec, .size = ARRAY_SIZE(cec), - .rc_type = RC_TYPE_CEC, + .rc_proto = RC_PROTO_CEC, .name = RC_MAP_CEC, } }; diff --git a/drivers/media/rc/keymaps/rc-cinergy-1400.c b/drivers/media/rc/keymaps/rc-cinergy-1400.c index a099c080bf8c..bcb96b3dda85 100644 --- a/drivers/media/rc/keymaps/rc-cinergy-1400.c +++ b/drivers/media/rc/keymaps/rc-cinergy-1400.c @@ -61,10 +61,10 @@ static struct rc_map_table cinergy_1400[] = { static struct rc_map_list cinergy_1400_map = { .map = { - .scan = cinergy_1400, - .size = ARRAY_SIZE(cinergy_1400), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_CINERGY_1400, + .scan = cinergy_1400, + .size = ARRAY_SIZE(cinergy_1400), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_CINERGY_1400, } }; diff --git a/drivers/media/rc/keymaps/rc-cinergy.c b/drivers/media/rc/keymaps/rc-cinergy.c index b0f4328bdd6f..fd56c402aae5 100644 --- a/drivers/media/rc/keymaps/rc-cinergy.c +++ b/drivers/media/rc/keymaps/rc-cinergy.c @@ -55,10 +55,10 @@ static struct rc_map_table cinergy[] = { static struct rc_map_list cinergy_map = { .map = { - .scan = cinergy, - .size = ARRAY_SIZE(cinergy), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_CINERGY, + .scan = cinergy, + .size = ARRAY_SIZE(cinergy), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_CINERGY, } }; diff --git a/drivers/media/rc/keymaps/rc-d680-dmb.c b/drivers/media/rc/keymaps/rc-d680-dmb.c index bb5745d29d8a..2c94b9d88b67 100644 --- a/drivers/media/rc/keymaps/rc-d680-dmb.c +++ b/drivers/media/rc/keymaps/rc-d680-dmb.c @@ -51,10 +51,10 @@ static struct rc_map_table rc_map_d680_dmb_table[] = { static struct rc_map_list d680_dmb_map = { .map = { - .scan = rc_map_d680_dmb_table, - .size = ARRAY_SIZE(rc_map_d680_dmb_table), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_D680_DMB, + .scan = rc_map_d680_dmb_table, + .size = ARRAY_SIZE(rc_map_d680_dmb_table), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_D680_DMB, } }; diff --git a/drivers/media/rc/keymaps/rc-delock-61959.c b/drivers/media/rc/keymaps/rc-delock-61959.c index 01bed864f09d..62de69d78d92 100644 --- a/drivers/media/rc/keymaps/rc-delock-61959.c +++ b/drivers/media/rc/keymaps/rc-delock-61959.c @@ -58,10 +58,10 @@ static struct rc_map_table delock_61959[] = { static struct rc_map_list delock_61959_map = { .map = { - .scan = delock_61959, - .size = ARRAY_SIZE(delock_61959), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_DELOCK_61959, + .scan = delock_61959, + .size = ARRAY_SIZE(delock_61959), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_DELOCK_61959, } }; diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c index a0fa543c9f9e..1b4df106b7b5 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-nec.c +++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c @@ -101,10 +101,10 @@ static struct rc_map_table dib0700_nec_table[] = { static struct rc_map_list dib0700_nec_map = { .map = { - .scan = dib0700_nec_table, - .size = ARRAY_SIZE(dib0700_nec_table), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_DIB0700_NEC_TABLE, + .scan = dib0700_nec_table, + .size = ARRAY_SIZE(dib0700_nec_table), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_DIB0700_NEC_TABLE, } }; diff --git a/drivers/media/rc/keymaps/rc-dib0700-rc5.c b/drivers/media/rc/keymaps/rc-dib0700-rc5.c index 907941145eb7..b0f8151bb824 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-rc5.c +++ b/drivers/media/rc/keymaps/rc-dib0700-rc5.c @@ -212,10 +212,10 @@ static struct rc_map_table dib0700_rc5_table[] = { static struct rc_map_list dib0700_rc5_map = { .map = { - .scan = dib0700_rc5_table, - .size = ARRAY_SIZE(dib0700_rc5_table), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_DIB0700_RC5_TABLE, + .scan = dib0700_rc5_table, + .size = ARRAY_SIZE(dib0700_rc5_table), + .rc_proto = RC_PROTO_RC5, + .name = RC_MAP_DIB0700_RC5_TABLE, } }; diff --git a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c index bed78acb9198..01ca8b39359f 100644 --- a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c +++ b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c @@ -75,10 +75,10 @@ static struct rc_map_table digitalnow_tinytwin[] = { static struct rc_map_list digitalnow_tinytwin_map = { .map = { - .scan = digitalnow_tinytwin, - .size = ARRAY_SIZE(digitalnow_tinytwin), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_DIGITALNOW_TINYTWIN, + .scan = digitalnow_tinytwin, + .size = ARRAY_SIZE(digitalnow_tinytwin), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_DIGITALNOW_TINYTWIN, } }; diff --git a/drivers/media/rc/keymaps/rc-digittrade.c b/drivers/media/rc/keymaps/rc-digittrade.c index a3b97a1fe223..a54b1d632ca6 100644 --- a/drivers/media/rc/keymaps/rc-digittrade.c +++ b/drivers/media/rc/keymaps/rc-digittrade.c @@ -59,10 +59,10 @@ static struct rc_map_table digittrade[] = { static struct rc_map_list digittrade_map = { .map = { - .scan = digittrade, - .size = ARRAY_SIZE(digittrade), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_DIGITTRADE, + .scan = digittrade, + .size = ARRAY_SIZE(digittrade), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_DIGITTRADE, } }; diff --git a/drivers/media/rc/keymaps/rc-dm1105-nec.c b/drivers/media/rc/keymaps/rc-dm1105-nec.c index 46e7ae414cc8..c353445d10ed 100644 --- a/drivers/media/rc/keymaps/rc-dm1105-nec.c +++ b/drivers/media/rc/keymaps/rc-dm1105-nec.c @@ -53,10 +53,10 @@ static struct rc_map_table dm1105_nec[] = { static struct rc_map_list dm1105_nec_map = { .map = { - .scan = dm1105_nec, - .size = ARRAY_SIZE(dm1105_nec), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_DM1105_NEC, + .scan = dm1105_nec, + .size = ARRAY_SIZE(dm1105_nec), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_DM1105_NEC, } }; 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 d2826b46fea2..5bafd5b70f5e 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c @@ -55,10 +55,10 @@ static struct rc_map_table dntv_live_dvb_t[] = { static struct rc_map_list dntv_live_dvb_t_map = { .map = { - .scan = dntv_live_dvb_t, - .size = ARRAY_SIZE(dntv_live_dvb_t), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_DNTV_LIVE_DVB_T, + .scan = dntv_live_dvb_t, + .size = ARRAY_SIZE(dntv_live_dvb_t), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_DNTV_LIVE_DVB_T, } }; 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 0d74769467b5..360167c8829b 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c @@ -74,10 +74,10 @@ static struct rc_map_table dntv_live_dvbt_pro[] = { static struct rc_map_list dntv_live_dvbt_pro_map = { .map = { - .scan = dntv_live_dvbt_pro, - .size = ARRAY_SIZE(dntv_live_dvbt_pro), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_DNTV_LIVE_DVBT_PRO, + .scan = dntv_live_dvbt_pro, + .size = ARRAY_SIZE(dntv_live_dvbt_pro), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_DNTV_LIVE_DVBT_PRO, } }; diff --git a/drivers/media/rc/keymaps/rc-dtt200u.c b/drivers/media/rc/keymaps/rc-dtt200u.c index 25650e9e4664..c932d8b6c509 100644 --- a/drivers/media/rc/keymaps/rc-dtt200u.c +++ b/drivers/media/rc/keymaps/rc-dtt200u.c @@ -35,10 +35,10 @@ static struct rc_map_table dtt200u_table[] = { static struct rc_map_list dtt200u_map = { .map = { - .scan = dtt200u_table, - .size = ARRAY_SIZE(dtt200u_table), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_DTT200U, + .scan = dtt200u_table, + .size = ARRAY_SIZE(dtt200u_table), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_DTT200U, } }; diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c index c5115a1165d1..d6c0b4c1e20e 100644 --- a/drivers/media/rc/keymaps/rc-dvbsky.c +++ b/drivers/media/rc/keymaps/rc-dvbsky.c @@ -54,10 +54,10 @@ static struct rc_map_table rc5_dvbsky[] = { static struct rc_map_list rc5_dvbsky_map = { .map = { - .scan = rc5_dvbsky, - .size = ARRAY_SIZE(rc5_dvbsky), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_DVBSKY, + .scan = rc5_dvbsky, + .size = ARRAY_SIZE(rc5_dvbsky), + .rc_proto = RC_PROTO_RC5, + .name = RC_MAP_DVBSKY, } }; diff --git a/drivers/media/rc/keymaps/rc-dvico-mce.c b/drivers/media/rc/keymaps/rc-dvico-mce.c index d1e861f4d095..e4cee190b923 100644 --- a/drivers/media/rc/keymaps/rc-dvico-mce.c +++ b/drivers/media/rc/keymaps/rc-dvico-mce.c @@ -61,10 +61,10 @@ static struct rc_map_table rc_map_dvico_mce_table[] = { static struct rc_map_list dvico_mce_map = { .map = { - .scan = rc_map_dvico_mce_table, - .size = ARRAY_SIZE(rc_map_dvico_mce_table), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_DVICO_MCE, + .scan = rc_map_dvico_mce_table, + .size = ARRAY_SIZE(rc_map_dvico_mce_table), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_DVICO_MCE, } }; diff --git a/drivers/media/rc/keymaps/rc-dvico-portable.c b/drivers/media/rc/keymaps/rc-dvico-portable.c index ac4cb515cbf1..cdd21f54aa61 100644 --- a/drivers/media/rc/keymaps/rc-dvico-portable.c +++ b/drivers/media/rc/keymaps/rc-dvico-portable.c @@ -52,10 +52,10 @@ static struct rc_map_table rc_map_dvico_portable_table[] = { static struct rc_map_list dvico_portable_map = { .map = { - .scan = rc_map_dvico_portable_table, - .size = ARRAY_SIZE(rc_map_dvico_portable_table), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_DVICO_PORTABLE, + .scan = rc_map_dvico_portable_table, + .size = ARRAY_SIZE(rc_map_dvico_portable_table), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_DVICO_PORTABLE, } }; diff --git a/drivers/media/rc/keymaps/rc-em-terratec.c b/drivers/media/rc/keymaps/rc-em-terratec.c index 7f1e06be175b..18e1a2679c20 100644 --- a/drivers/media/rc/keymaps/rc-em-terratec.c +++ b/drivers/media/rc/keymaps/rc-em-terratec.c @@ -46,10 +46,10 @@ static struct rc_map_table em_terratec[] = { static struct rc_map_list em_terratec_map = { .map = { - .scan = em_terratec, - .size = ARRAY_SIZE(em_terratec), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_EM_TERRATEC, + .scan = em_terratec, + .size = ARRAY_SIZE(em_terratec), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_EM_TERRATEC, } }; diff --git a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c index 4fc3904daf06..72ffd5cb0108 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c @@ -58,10 +58,10 @@ static struct rc_map_table encore_enltv_fm53[] = { static struct rc_map_list encore_enltv_fm53_map = { .map = { - .scan = encore_enltv_fm53, - .size = ARRAY_SIZE(encore_enltv_fm53), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_ENCORE_ENLTV_FM53, + .scan = encore_enltv_fm53, + .size = ARRAY_SIZE(encore_enltv_fm53), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_ENCORE_ENLTV_FM53, } }; diff --git a/drivers/media/rc/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c index f1914e23d203..e0381e7aa964 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv.c @@ -89,10 +89,10 @@ static struct rc_map_table encore_enltv[] = { static struct rc_map_list encore_enltv_map = { .map = { - .scan = encore_enltv, - .size = ARRAY_SIZE(encore_enltv), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_ENCORE_ENLTV, + .scan = encore_enltv, + .size = ARRAY_SIZE(encore_enltv), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_ENCORE_ENLTV, } }; diff --git a/drivers/media/rc/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c index 9c6c55240d18..e9b0bfba319c 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv2.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c @@ -67,10 +67,10 @@ static struct rc_map_table encore_enltv2[] = { static struct rc_map_list encore_enltv2_map = { .map = { - .scan = encore_enltv2, - .size = ARRAY_SIZE(encore_enltv2), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_ENCORE_ENLTV2, + .scan = encore_enltv2, + .size = ARRAY_SIZE(encore_enltv2), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_ENCORE_ENLTV2, } }; diff --git a/drivers/media/rc/keymaps/rc-evga-indtube.c b/drivers/media/rc/keymaps/rc-evga-indtube.c index 2370d2a3deb6..b77c5e908668 100644 --- a/drivers/media/rc/keymaps/rc-evga-indtube.c +++ b/drivers/media/rc/keymaps/rc-evga-indtube.c @@ -38,10 +38,10 @@ static struct rc_map_table evga_indtube[] = { static struct rc_map_list evga_indtube_map = { .map = { - .scan = evga_indtube, - .size = ARRAY_SIZE(evga_indtube), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_EVGA_INDTUBE, + .scan = evga_indtube, + .size = ARRAY_SIZE(evga_indtube), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_EVGA_INDTUBE, } }; diff --git a/drivers/media/rc/keymaps/rc-eztv.c b/drivers/media/rc/keymaps/rc-eztv.c index b5c96ed84376..5013b3b2aa93 100644 --- a/drivers/media/rc/keymaps/rc-eztv.c +++ b/drivers/media/rc/keymaps/rc-eztv.c @@ -73,10 +73,10 @@ static struct rc_map_table eztv[] = { static struct rc_map_list eztv_map = { .map = { - .scan = eztv, - .size = ARRAY_SIZE(eztv), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_EZTV, + .scan = eztv, + .size = ARRAY_SIZE(eztv), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_EZTV, } }; diff --git a/drivers/media/rc/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c index 25cb89fac03c..418b32521273 100644 --- a/drivers/media/rc/keymaps/rc-flydvb.c +++ b/drivers/media/rc/keymaps/rc-flydvb.c @@ -54,10 +54,10 @@ static struct rc_map_table flydvb[] = { static struct rc_map_list flydvb_map = { .map = { - .scan = flydvb, - .size = ARRAY_SIZE(flydvb), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_FLYDVB, + .scan = flydvb, + .size = ARRAY_SIZE(flydvb), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_FLYDVB, } }; diff --git a/drivers/media/rc/keymaps/rc-flyvideo.c b/drivers/media/rc/keymaps/rc-flyvideo.c index e71377dd0534..93fb87ecf061 100644 --- a/drivers/media/rc/keymaps/rc-flyvideo.c +++ b/drivers/media/rc/keymaps/rc-flyvideo.c @@ -47,10 +47,10 @@ static struct rc_map_table flyvideo[] = { static struct rc_map_list flyvideo_map = { .map = { - .scan = flyvideo, - .size = ARRAY_SIZE(flyvideo), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_FLYVIDEO, + .scan = flyvideo, + .size = ARRAY_SIZE(flyvideo), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_FLYVIDEO, } }; diff --git a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c index cf0608dc83d5..9ed3f749262b 100644 --- a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c +++ b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c @@ -75,10 +75,10 @@ static struct rc_map_table fusionhdtv_mce[] = { static struct rc_map_list fusionhdtv_mce_map = { .map = { - .scan = fusionhdtv_mce, - .size = ARRAY_SIZE(fusionhdtv_mce), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_FUSIONHDTV_MCE, + .scan = fusionhdtv_mce, + .size = ARRAY_SIZE(fusionhdtv_mce), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_FUSIONHDTV_MCE, } }; diff --git a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c index 03575bdb2eca..3443b721d092 100644 --- a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c +++ b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c @@ -58,10 +58,10 @@ static struct rc_map_table gadmei_rm008z[] = { static struct rc_map_list gadmei_rm008z_map = { .map = { - .scan = gadmei_rm008z, - .size = ARRAY_SIZE(gadmei_rm008z), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_GADMEI_RM008Z, + .scan = gadmei_rm008z, + .size = ARRAY_SIZE(gadmei_rm008z), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_GADMEI_RM008Z, } }; diff --git a/drivers/media/rc/keymaps/rc-geekbox.c b/drivers/media/rc/keymaps/rc-geekbox.c index affc4c481888..4aa1b54bb52e 100644 --- a/drivers/media/rc/keymaps/rc-geekbox.c +++ b/drivers/media/rc/keymaps/rc-geekbox.c @@ -31,10 +31,10 @@ static struct rc_map_table geekbox[] = { static struct rc_map_list geekbox_map = { .map = { - .scan = geekbox, - .size = ARRAY_SIZE(geekbox), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_GEEKBOX, + .scan = geekbox, + .size = ARRAY_SIZE(geekbox), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_GEEKBOX, } }; diff --git a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c index b2ab13b0dcb1..d140e8d45bcc 100644 --- a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c +++ b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c @@ -61,10 +61,10 @@ static struct rc_map_table genius_tvgo_a11mce[] = { static struct rc_map_list genius_tvgo_a11mce_map = { .map = { - .scan = genius_tvgo_a11mce, - .size = ARRAY_SIZE(genius_tvgo_a11mce), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_GENIUS_TVGO_A11MCE, + .scan = genius_tvgo_a11mce, + .size = ARRAY_SIZE(genius_tvgo_a11mce), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_GENIUS_TVGO_A11MCE, } }; diff --git a/drivers/media/rc/keymaps/rc-gotview7135.c b/drivers/media/rc/keymaps/rc-gotview7135.c index 229a36ac7f0a..51230fbb52ba 100644 --- a/drivers/media/rc/keymaps/rc-gotview7135.c +++ b/drivers/media/rc/keymaps/rc-gotview7135.c @@ -56,10 +56,10 @@ static struct rc_map_table gotview7135[] = { static struct rc_map_list gotview7135_map = { .map = { - .scan = gotview7135, - .size = ARRAY_SIZE(gotview7135), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_GOTVIEW7135, + .scan = gotview7135, + .size = ARRAY_SIZE(gotview7135), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_GOTVIEW7135, } }; diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c index 36d57f7c532b..890164b68d64 100644 --- a/drivers/media/rc/keymaps/rc-hauppauge.c +++ b/drivers/media/rc/keymaps/rc-hauppauge.c @@ -269,10 +269,10 @@ static struct rc_map_table rc5_hauppauge_new[] = { static struct rc_map_list rc5_hauppauge_new_map = { .map = { - .scan = rc5_hauppauge_new, - .size = ARRAY_SIZE(rc5_hauppauge_new), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_HAUPPAUGE, + .scan = rc5_hauppauge_new, + .size = ARRAY_SIZE(rc5_hauppauge_new), + .rc_proto = RC_PROTO_RC5, + .name = RC_MAP_HAUPPAUGE, } }; diff --git a/drivers/media/rc/keymaps/rc-imon-mce.c b/drivers/media/rc/keymaps/rc-imon-mce.c index f0da960560b0..6a69ce1451f1 100644 --- a/drivers/media/rc/keymaps/rc-imon-mce.c +++ b/drivers/media/rc/keymaps/rc-imon-mce.c @@ -118,11 +118,11 @@ static struct rc_map_table imon_mce[] = { static struct rc_map_list imon_mce_map = { .map = { - .scan = imon_mce, - .size = ARRAY_SIZE(imon_mce), + .scan = imon_mce, + .size = ARRAY_SIZE(imon_mce), /* its RC6, but w/a hardware decoder */ - .rc_type = RC_TYPE_RC6_MCE, - .name = RC_MAP_IMON_MCE, + .rc_proto = RC_PROTO_RC6_MCE, + .name = RC_MAP_IMON_MCE, } }; diff --git a/drivers/media/rc/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c index 999c6295c70e..a7296ffbf218 100644 --- a/drivers/media/rc/keymaps/rc-imon-pad.c +++ b/drivers/media/rc/keymaps/rc-imon-pad.c @@ -132,11 +132,11 @@ static struct rc_map_table imon_pad[] = { static struct rc_map_list imon_pad_map = { .map = { - .scan = imon_pad, - .size = ARRAY_SIZE(imon_pad), + .scan = imon_pad, + .size = ARRAY_SIZE(imon_pad), /* actual protocol details unknown, hardware decoder */ - .rc_type = RC_TYPE_OTHER, - .name = RC_MAP_IMON_PAD, + .rc_proto = RC_PROTO_OTHER, + .name = RC_MAP_IMON_PAD, } }; diff --git a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c index 9ee154cb0c6b..8cf87a15c4f2 100644 --- a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c +++ b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c @@ -65,10 +65,10 @@ static struct rc_map_table iodata_bctv7e[] = { static struct rc_map_list iodata_bctv7e_map = { .map = { - .scan = iodata_bctv7e, - .size = ARRAY_SIZE(iodata_bctv7e), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_IODATA_BCTV7E, + .scan = iodata_bctv7e, + .size = ARRAY_SIZE(iodata_bctv7e), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_IODATA_BCTV7E, } }; diff --git a/drivers/media/rc/keymaps/rc-it913x-v1.c b/drivers/media/rc/keymaps/rc-it913x-v1.c index 0ac775fd109d..908d14848ae8 100644 --- a/drivers/media/rc/keymaps/rc-it913x-v1.c +++ b/drivers/media/rc/keymaps/rc-it913x-v1.c @@ -71,10 +71,10 @@ static struct rc_map_table it913x_v1_rc[] = { static struct rc_map_list it913x_v1_map = { .map = { - .scan = it913x_v1_rc, - .size = ARRAY_SIZE(it913x_v1_rc), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_IT913X_V1, + .scan = it913x_v1_rc, + .size = ARRAY_SIZE(it913x_v1_rc), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_IT913X_V1, } }; diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c index bd42a30ec06f..05ab7fa4f90b 100644 --- a/drivers/media/rc/keymaps/rc-it913x-v2.c +++ b/drivers/media/rc/keymaps/rc-it913x-v2.c @@ -70,10 +70,10 @@ static struct rc_map_table it913x_v2_rc[] = { static struct rc_map_list it913x_v2_map = { .map = { - .scan = it913x_v2_rc, - .size = ARRAY_SIZE(it913x_v2_rc), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_IT913X_V2, + .scan = it913x_v2_rc, + .size = ARRAY_SIZE(it913x_v2_rc), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_IT913X_V2, } }; diff --git a/drivers/media/rc/keymaps/rc-kaiomy.c b/drivers/media/rc/keymaps/rc-kaiomy.c index 60803a732c08..e791f1e1b43b 100644 --- a/drivers/media/rc/keymaps/rc-kaiomy.c +++ b/drivers/media/rc/keymaps/rc-kaiomy.c @@ -64,10 +64,10 @@ static struct rc_map_table kaiomy[] = { static struct rc_map_list kaiomy_map = { .map = { - .scan = kaiomy, - .size = ARRAY_SIZE(kaiomy), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_KAIOMY, + .scan = kaiomy, + .size = ARRAY_SIZE(kaiomy), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_KAIOMY, } }; diff --git a/drivers/media/rc/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c index ba087eed1ed9..71dce0138f0e 100644 --- a/drivers/media/rc/keymaps/rc-kworld-315u.c +++ b/drivers/media/rc/keymaps/rc-kworld-315u.c @@ -60,10 +60,10 @@ static struct rc_map_table kworld_315u[] = { static struct rc_map_list kworld_315u_map = { .map = { - .scan = kworld_315u, - .size = ARRAY_SIZE(kworld_315u), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_KWORLD_315U, + .scan = kworld_315u, + .size = ARRAY_SIZE(kworld_315u), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_KWORLD_315U, } }; diff --git a/drivers/media/rc/keymaps/rc-kworld-pc150u.c b/drivers/media/rc/keymaps/rc-kworld-pc150u.c index b92e571f4def..3846059060aa 100644 --- a/drivers/media/rc/keymaps/rc-kworld-pc150u.c +++ b/drivers/media/rc/keymaps/rc-kworld-pc150u.c @@ -78,10 +78,10 @@ static struct rc_map_table kworld_pc150u[] = { static struct rc_map_list kworld_pc150u_map = { .map = { - .scan = kworld_pc150u, - .size = ARRAY_SIZE(kworld_pc150u), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_KWORLD_PC150U, + .scan = kworld_pc150u, + .size = ARRAY_SIZE(kworld_pc150u), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_KWORLD_PC150U, } }; 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 edc868564f99..e0322ed16c94 100644 --- a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c +++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c @@ -76,10 +76,10 @@ static struct rc_map_table kworld_plus_tv_analog[] = { static struct rc_map_list kworld_plus_tv_analog_map = { .map = { - .scan = kworld_plus_tv_analog, - .size = ARRAY_SIZE(kworld_plus_tv_analog), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_KWORLD_PLUS_TV_ANALOG, + .scan = kworld_plus_tv_analog, + .size = ARRAY_SIZE(kworld_plus_tv_analog), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_KWORLD_PLUS_TV_ANALOG, } }; diff --git a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c index 03d762d986ee..e534a5601b6d 100644 --- a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c +++ b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c @@ -76,10 +76,10 @@ static struct rc_map_table leadtek_y04g0051[] = { static struct rc_map_list leadtek_y04g0051_map = { .map = { - .scan = leadtek_y04g0051, - .size = ARRAY_SIZE(leadtek_y04g0051), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_LEADTEK_Y04G0051, + .scan = leadtek_y04g0051, + .size = ARRAY_SIZE(leadtek_y04g0051), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_LEADTEK_Y04G0051, } }; diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c index 2b0027c41332..9c93f90f5c2b 100644 --- a/drivers/media/rc/keymaps/rc-lme2510.c +++ b/drivers/media/rc/keymaps/rc-lme2510.c @@ -87,10 +87,10 @@ static struct rc_map_table lme2510_rc[] = { static struct rc_map_list lme2510_map = { .map = { - .scan = lme2510_rc, - .size = ARRAY_SIZE(lme2510_rc), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_LME2510, + .scan = lme2510_rc, + .size = ARRAY_SIZE(lme2510_rc), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_LME2510, } }; diff --git a/drivers/media/rc/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c index 92424ef2aaa6..da566902a4dd 100644 --- a/drivers/media/rc/keymaps/rc-manli.c +++ b/drivers/media/rc/keymaps/rc-manli.c @@ -111,10 +111,10 @@ static struct rc_map_table manli[] = { static struct rc_map_list manli_map = { .map = { - .scan = manli, - .size = ARRAY_SIZE(manli), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_MANLI, + .scan = manli, + .size = ARRAY_SIZE(manli), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_MANLI, } }; diff --git a/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c b/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c index 966f9b3c71da..c9973340e546 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c +++ b/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c @@ -98,10 +98,10 @@ static struct rc_map_table medion_x10_digitainer[] = { static struct rc_map_list medion_x10_digitainer_map = { .map = { - .scan = medion_x10_digitainer, - .size = ARRAY_SIZE(medion_x10_digitainer), - .rc_type = RC_TYPE_OTHER, - .name = RC_MAP_MEDION_X10_DIGITAINER, + .scan = medion_x10_digitainer, + .size = ARRAY_SIZE(medion_x10_digitainer), + .rc_proto = RC_PROTO_OTHER, + .name = RC_MAP_MEDION_X10_DIGITAINER, } }; diff --git a/drivers/media/rc/keymaps/rc-medion-x10-or2x.c b/drivers/media/rc/keymaps/rc-medion-x10-or2x.c index b077300ecb5c..103ad88d242c 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10-or2x.c +++ b/drivers/media/rc/keymaps/rc-medion-x10-or2x.c @@ -83,10 +83,10 @@ static struct rc_map_table medion_x10_or2x[] = { static struct rc_map_list medion_x10_or2x_map = { .map = { - .scan = medion_x10_or2x, - .size = ARRAY_SIZE(medion_x10_or2x), - .rc_type = RC_TYPE_OTHER, - .name = RC_MAP_MEDION_X10_OR2X, + .scan = medion_x10_or2x, + .size = ARRAY_SIZE(medion_x10_or2x), + .rc_proto = RC_PROTO_OTHER, + .name = RC_MAP_MEDION_X10_OR2X, } }; diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c index 479cdb897810..bbffa5dfe420 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10.c +++ b/drivers/media/rc/keymaps/rc-medion-x10.c @@ -93,10 +93,10 @@ static struct rc_map_table medion_x10[] = { static struct rc_map_list medion_x10_map = { .map = { - .scan = medion_x10, - .size = ARRAY_SIZE(medion_x10), - .rc_type = RC_TYPE_OTHER, - .name = RC_MAP_MEDION_X10, + .scan = medion_x10, + .size = ARRAY_SIZE(medion_x10), + .rc_proto = RC_PROTO_OTHER, + .name = RC_MAP_MEDION_X10, } }; diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c index 2fa71d0d72d7..94aa12d4b73c 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c @@ -44,10 +44,10 @@ static struct rc_map_table msi_digivox_ii[] = { static struct rc_map_list msi_digivox_ii_map = { .map = { - .scan = msi_digivox_ii, - .size = ARRAY_SIZE(msi_digivox_ii), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_MSI_DIGIVOX_II, + .scan = msi_digivox_ii, + .size = ARRAY_SIZE(msi_digivox_ii), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_MSI_DIGIVOX_II, } }; diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c index 303a0b73175b..8fec0c1dcb12 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c @@ -62,10 +62,10 @@ static struct rc_map_table msi_digivox_iii[] = { static struct rc_map_list msi_digivox_iii_map = { .map = { - .scan = msi_digivox_iii, - .size = ARRAY_SIZE(msi_digivox_iii), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_MSI_DIGIVOX_III, + .scan = msi_digivox_iii, + .size = ARRAY_SIZE(msi_digivox_iii), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_MSI_DIGIVOX_III, } }; diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c index fd7a55c56167..dfa0ed1d7667 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c @@ -100,10 +100,10 @@ static struct rc_map_table msi_tvanywhere_plus[] = { static struct rc_map_list msi_tvanywhere_plus_map = { .map = { - .scan = msi_tvanywhere_plus, - .size = ARRAY_SIZE(msi_tvanywhere_plus), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_MSI_TVANYWHERE_PLUS, + .scan = msi_tvanywhere_plus, + .size = ARRAY_SIZE(msi_tvanywhere_plus), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_MSI_TVANYWHERE_PLUS, } }; diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c index 4233a8d4d63e..2111816a3f59 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c @@ -46,10 +46,10 @@ static struct rc_map_table msi_tvanywhere[] = { static struct rc_map_list msi_tvanywhere_map = { .map = { - .scan = msi_tvanywhere, - .size = ARRAY_SIZE(msi_tvanywhere), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_MSI_TVANYWHERE, + .scan = msi_tvanywhere, + .size = ARRAY_SIZE(msi_tvanywhere), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_MSI_TVANYWHERE, } }; diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c index 4c50f33c7c41..109b6e1a8b1a 100644 --- a/drivers/media/rc/keymaps/rc-nebula.c +++ b/drivers/media/rc/keymaps/rc-nebula.c @@ -73,10 +73,10 @@ static struct rc_map_table nebula[] = { static struct rc_map_list nebula_map = { .map = { - .scan = nebula, - .size = ARRAY_SIZE(nebula), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_NEBULA, + .scan = nebula, + .size = ARRAY_SIZE(nebula), + .rc_proto = RC_PROTO_RC5, + .name = RC_MAP_NEBULA, } }; 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 292bbad35d21..bb2d3a2962c0 100644 --- a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c @@ -134,10 +134,10 @@ static struct rc_map_table nec_terratec_cinergy_xs[] = { static struct rc_map_list nec_terratec_cinergy_xs_map = { .map = { - .scan = nec_terratec_cinergy_xs, - .size = ARRAY_SIZE(nec_terratec_cinergy_xs), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_NEC_TERRATEC_CINERGY_XS, + .scan = nec_terratec_cinergy_xs, + .size = ARRAY_SIZE(nec_terratec_cinergy_xs), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_NEC_TERRATEC_CINERGY_XS, } }; diff --git a/drivers/media/rc/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c index ca1b82a2c54f..cd25df336749 100644 --- a/drivers/media/rc/keymaps/rc-norwood.c +++ b/drivers/media/rc/keymaps/rc-norwood.c @@ -62,10 +62,10 @@ static struct rc_map_table norwood[] = { static struct rc_map_list norwood_map = { .map = { - .scan = norwood, - .size = ARRAY_SIZE(norwood), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_NORWOOD, + .scan = norwood, + .size = ARRAY_SIZE(norwood), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_NORWOOD, } }; diff --git a/drivers/media/rc/keymaps/rc-npgtech.c b/drivers/media/rc/keymaps/rc-npgtech.c index 1fb946024512..140bbc20a764 100644 --- a/drivers/media/rc/keymaps/rc-npgtech.c +++ b/drivers/media/rc/keymaps/rc-npgtech.c @@ -57,10 +57,10 @@ static struct rc_map_table npgtech[] = { static struct rc_map_list npgtech_map = { .map = { - .scan = npgtech, - .size = ARRAY_SIZE(npgtech), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_NPGTECH, + .scan = npgtech, + .size = ARRAY_SIZE(npgtech), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_NPGTECH, } }; diff --git a/drivers/media/rc/keymaps/rc-pctv-sedna.c b/drivers/media/rc/keymaps/rc-pctv-sedna.c index 5ef01ab3fd50..52b4558b7bd0 100644 --- a/drivers/media/rc/keymaps/rc-pctv-sedna.c +++ b/drivers/media/rc/keymaps/rc-pctv-sedna.c @@ -57,10 +57,10 @@ static struct rc_map_table pctv_sedna[] = { static struct rc_map_list pctv_sedna_map = { .map = { - .scan = pctv_sedna, - .size = ARRAY_SIZE(pctv_sedna), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PCTV_SEDNA, + .scan = pctv_sedna, + .size = ARRAY_SIZE(pctv_sedna), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PCTV_SEDNA, } }; diff --git a/drivers/media/rc/keymaps/rc-pinnacle-color.c b/drivers/media/rc/keymaps/rc-pinnacle-color.c index a218b471a4ca..973c9c34e304 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-color.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-color.c @@ -71,10 +71,10 @@ static struct rc_map_table pinnacle_color[] = { static struct rc_map_list pinnacle_color_map = { .map = { - .scan = pinnacle_color, - .size = ARRAY_SIZE(pinnacle_color), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PINNACLE_COLOR, + .scan = pinnacle_color, + .size = ARRAY_SIZE(pinnacle_color), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PINNACLE_COLOR, } }; diff --git a/drivers/media/rc/keymaps/rc-pinnacle-grey.c b/drivers/media/rc/keymaps/rc-pinnacle-grey.c index 4a3f467a47a2..22e44b0d2a93 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-grey.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-grey.c @@ -66,10 +66,10 @@ static struct rc_map_table pinnacle_grey[] = { static struct rc_map_list pinnacle_grey_map = { .map = { - .scan = pinnacle_grey, - .size = ARRAY_SIZE(pinnacle_grey), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PINNACLE_GREY, + .scan = pinnacle_grey, + .size = ARRAY_SIZE(pinnacle_grey), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PINNACLE_GREY, } }; diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c index e89cc10b68bf..186dcf8e0491 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c @@ -47,10 +47,10 @@ static struct rc_map_table pinnacle_pctv_hd[] = { static struct rc_map_list pinnacle_pctv_hd_map = { .map = { - .scan = pinnacle_pctv_hd, - .size = ARRAY_SIZE(pinnacle_pctv_hd), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_PINNACLE_PCTV_HD, + .scan = pinnacle_pctv_hd, + .size = ARRAY_SIZE(pinnacle_pctv_hd), + .rc_proto = RC_PROTO_RC5, + .name = RC_MAP_PINNACLE_PCTV_HD, } }; diff --git a/drivers/media/rc/keymaps/rc-pixelview-002t.c b/drivers/media/rc/keymaps/rc-pixelview-002t.c index d967c3816fdc..b235ada2e28f 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-002t.c +++ b/drivers/media/rc/keymaps/rc-pixelview-002t.c @@ -54,10 +54,10 @@ static struct rc_map_table pixelview_002t[] = { static struct rc_map_list pixelview_map = { .map = { - .scan = pixelview_002t, - .size = ARRAY_SIZE(pixelview_002t), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_PIXELVIEW_002T, + .scan = pixelview_002t, + .size = ARRAY_SIZE(pixelview_002t), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_PIXELVIEW_002T, } }; diff --git a/drivers/media/rc/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c index 224d0efaa6e5..453d52d663fe 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-mk12.c +++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c @@ -60,10 +60,10 @@ static struct rc_map_table pixelview_mk12[] = { static struct rc_map_list pixelview_map = { .map = { - .scan = pixelview_mk12, - .size = ARRAY_SIZE(pixelview_mk12), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_PIXELVIEW_MK12, + .scan = pixelview_mk12, + .size = ARRAY_SIZE(pixelview_mk12), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_PIXELVIEW_MK12, } }; diff --git a/drivers/media/rc/keymaps/rc-pixelview-new.c b/drivers/media/rc/keymaps/rc-pixelview-new.c index 781d788d6b6d..ef97095ec8f1 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-new.c +++ b/drivers/media/rc/keymaps/rc-pixelview-new.c @@ -60,10 +60,10 @@ static struct rc_map_table pixelview_new[] = { static struct rc_map_list pixelview_new_map = { .map = { - .scan = pixelview_new, - .size = ARRAY_SIZE(pixelview_new), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PIXELVIEW_NEW, + .scan = pixelview_new, + .size = ARRAY_SIZE(pixelview_new), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PIXELVIEW_NEW, } }; diff --git a/drivers/media/rc/keymaps/rc-pixelview.c b/drivers/media/rc/keymaps/rc-pixelview.c index 39e6feaa35a3..cfd8f80d3617 100644 --- a/drivers/media/rc/keymaps/rc-pixelview.c +++ b/drivers/media/rc/keymaps/rc-pixelview.c @@ -59,10 +59,10 @@ static struct rc_map_table pixelview[] = { static struct rc_map_list pixelview_map = { .map = { - .scan = pixelview, - .size = ARRAY_SIZE(pixelview), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PIXELVIEW, + .scan = pixelview, + .size = ARRAY_SIZE(pixelview), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PIXELVIEW, } }; diff --git a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c index e96fa3ab9f4b..b63f82bcf29a 100644 --- a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c +++ b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c @@ -58,10 +58,10 @@ static struct rc_map_table powercolor_real_angel[] = { static struct rc_map_list powercolor_real_angel_map = { .map = { - .scan = powercolor_real_angel, - .size = ARRAY_SIZE(powercolor_real_angel), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_POWERCOLOR_REAL_ANGEL, + .scan = powercolor_real_angel, + .size = ARRAY_SIZE(powercolor_real_angel), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_POWERCOLOR_REAL_ANGEL, } }; diff --git a/drivers/media/rc/keymaps/rc-proteus-2309.c b/drivers/media/rc/keymaps/rc-proteus-2309.c index eef626ee02df..be34c517e4e1 100644 --- a/drivers/media/rc/keymaps/rc-proteus-2309.c +++ b/drivers/media/rc/keymaps/rc-proteus-2309.c @@ -46,10 +46,10 @@ static struct rc_map_table proteus_2309[] = { static struct rc_map_list proteus_2309_map = { .map = { - .scan = proteus_2309, - .size = ARRAY_SIZE(proteus_2309), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PROTEUS_2309, + .scan = proteus_2309, + .size = ARRAY_SIZE(proteus_2309), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PROTEUS_2309, } }; diff --git a/drivers/media/rc/keymaps/rc-purpletv.c b/drivers/media/rc/keymaps/rc-purpletv.c index cec6fe466829..84c40b97ee00 100644 --- a/drivers/media/rc/keymaps/rc-purpletv.c +++ b/drivers/media/rc/keymaps/rc-purpletv.c @@ -58,10 +58,10 @@ static struct rc_map_table purpletv[] = { static struct rc_map_list purpletv_map = { .map = { - .scan = purpletv, - .size = ARRAY_SIZE(purpletv), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PURPLETV, + .scan = purpletv, + .size = ARRAY_SIZE(purpletv), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PURPLETV, } }; diff --git a/drivers/media/rc/keymaps/rc-pv951.c b/drivers/media/rc/keymaps/rc-pv951.c index 5ac89ce8c053..be190ddebfc4 100644 --- a/drivers/media/rc/keymaps/rc-pv951.c +++ b/drivers/media/rc/keymaps/rc-pv951.c @@ -55,10 +55,10 @@ static struct rc_map_table pv951[] = { static struct rc_map_list pv951_map = { .map = { - .scan = pv951, - .size = ARRAY_SIZE(pv951), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_PV951, + .scan = pv951, + .size = ARRAY_SIZE(pv951), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_PV951, } }; diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c index 5be567506bcd..0d87b20a0c43 100644 --- a/drivers/media/rc/keymaps/rc-rc6-mce.c +++ b/drivers/media/rc/keymaps/rc-rc6-mce.c @@ -96,10 +96,10 @@ static struct rc_map_table rc6_mce[] = { static struct rc_map_list rc6_mce_map = { .map = { - .scan = rc6_mce, - .size = ARRAY_SIZE(rc6_mce), - .rc_type = RC_TYPE_RC6_MCE, - .name = RC_MAP_RC6_MCE, + .scan = rc6_mce, + .size = ARRAY_SIZE(rc6_mce), + .rc_proto = RC_PROTO_RC6_MCE, + .name = RC_MAP_RC6_MCE, } }; 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 9f778bd091db..957fa21747ea 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 @@ -55,10 +55,10 @@ static struct rc_map_table real_audio_220_32_keys[] = { static struct rc_map_list real_audio_220_32_keys_map = { .map = { - .scan = real_audio_220_32_keys, - .size = ARRAY_SIZE(real_audio_220_32_keys), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_REAL_AUDIO_220_32_KEYS, + .scan = real_audio_220_32_keys, + .size = ARRAY_SIZE(real_audio_220_32_keys), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_REAL_AUDIO_220_32_KEYS, } }; diff --git a/drivers/media/rc/keymaps/rc-reddo.c b/drivers/media/rc/keymaps/rc-reddo.c index b80b336e9284..3b37acc7b144 100644 --- a/drivers/media/rc/keymaps/rc-reddo.c +++ b/drivers/media/rc/keymaps/rc-reddo.c @@ -62,10 +62,10 @@ static struct rc_map_table reddo[] = { static struct rc_map_list reddo_map = { .map = { - .scan = reddo, - .size = ARRAY_SIZE(reddo), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_REDDO, + .scan = reddo, + .size = ARRAY_SIZE(reddo), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_REDDO, } }; diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c index c7f33ec719b4..30630a6f76ac 100644 --- a/drivers/media/rc/keymaps/rc-snapstream-firefly.c +++ b/drivers/media/rc/keymaps/rc-snapstream-firefly.c @@ -83,10 +83,10 @@ static struct rc_map_table snapstream_firefly[] = { static struct rc_map_list snapstream_firefly_map = { .map = { - .scan = snapstream_firefly, - .size = ARRAY_SIZE(snapstream_firefly), - .rc_type = RC_TYPE_OTHER, - .name = RC_MAP_SNAPSTREAM_FIREFLY, + .scan = snapstream_firefly, + .size = ARRAY_SIZE(snapstream_firefly), + .rc_proto = RC_PROTO_OTHER, + .name = RC_MAP_SNAPSTREAM_FIREFLY, } }; diff --git a/drivers/media/rc/keymaps/rc-streamzap.c b/drivers/media/rc/keymaps/rc-streamzap.c index 23c061174ed7..b53bca9e4576 100644 --- a/drivers/media/rc/keymaps/rc-streamzap.c +++ b/drivers/media/rc/keymaps/rc-streamzap.c @@ -57,10 +57,10 @@ static struct rc_map_table streamzap[] = { static struct rc_map_list streamzap_map = { .map = { - .scan = streamzap, - .size = ARRAY_SIZE(streamzap), - .rc_type = RC_TYPE_RC5_SZ, - .name = RC_MAP_STREAMZAP, + .scan = streamzap, + .size = ARRAY_SIZE(streamzap), + .rc_proto = RC_PROTO_RC5_SZ, + .name = RC_MAP_STREAMZAP, } }; diff --git a/drivers/media/rc/keymaps/rc-su3000.c b/drivers/media/rc/keymaps/rc-su3000.c index 8dbd3e9bc951..d9af7e3c55d9 100644 --- a/drivers/media/rc/keymaps/rc-su3000.c +++ b/drivers/media/rc/keymaps/rc-su3000.c @@ -51,10 +51,10 @@ static struct rc_map_table su3000[] = { static struct rc_map_list su3000_map = { .map = { - .scan = su3000, - .size = ARRAY_SIZE(su3000), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_SU3000, + .scan = su3000, + .size = ARRAY_SIZE(su3000), + .rc_proto = RC_PROTO_RC5, + .name = RC_MAP_SU3000, } }; diff --git a/drivers/media/rc/keymaps/rc-tbs-nec.c b/drivers/media/rc/keymaps/rc-tbs-nec.c index 24ce2a252502..05facc043272 100644 --- a/drivers/media/rc/keymaps/rc-tbs-nec.c +++ b/drivers/media/rc/keymaps/rc-tbs-nec.c @@ -52,10 +52,10 @@ static struct rc_map_table tbs_nec[] = { static struct rc_map_list tbs_nec_map = { .map = { - .scan = tbs_nec, - .size = ARRAY_SIZE(tbs_nec), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_TBS_NEC, + .scan = tbs_nec, + .size = ARRAY_SIZE(tbs_nec), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TBS_NEC, } }; diff --git a/drivers/media/rc/keymaps/rc-technisat-ts35.c b/drivers/media/rc/keymaps/rc-technisat-ts35.c index 3328cbefabad..dff7021734ba 100644 --- a/drivers/media/rc/keymaps/rc-technisat-ts35.c +++ b/drivers/media/rc/keymaps/rc-technisat-ts35.c @@ -53,10 +53,10 @@ static struct rc_map_table technisat_ts35[] = { static struct rc_map_list technisat_ts35_map = { .map = { - .scan = technisat_ts35, - .size = ARRAY_SIZE(technisat_ts35), - .rc_type = RC_TYPE_UNKNOWN, - .name = RC_MAP_TECHNISAT_TS35, + .scan = technisat_ts35, + .size = ARRAY_SIZE(technisat_ts35), + .rc_proto = RC_PROTO_UNKNOWN, + .name = RC_MAP_TECHNISAT_TS35, } }; diff --git a/drivers/media/rc/keymaps/rc-technisat-usb2.c b/drivers/media/rc/keymaps/rc-technisat-usb2.c index 02c9c243c060..58b3baf5ee96 100644 --- a/drivers/media/rc/keymaps/rc-technisat-usb2.c +++ b/drivers/media/rc/keymaps/rc-technisat-usb2.c @@ -66,10 +66,10 @@ static struct rc_map_table technisat_usb2[] = { static struct rc_map_list technisat_usb2_map = { .map = { - .scan = technisat_usb2, - .size = ARRAY_SIZE(technisat_usb2), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_TECHNISAT_USB2, + .scan = technisat_usb2, + .size = ARRAY_SIZE(technisat_usb2), + .rc_proto = RC_PROTO_RC5, + .name = RC_MAP_TECHNISAT_USB2, } }; 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 7958f458527a..7ae88ccf1def 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c @@ -65,10 +65,10 @@ static struct rc_map_table terratec_cinergy_c_pci[] = { static struct rc_map_list terratec_cinergy_c_pci_map = { .map = { - .scan = terratec_cinergy_c_pci, - .size = ARRAY_SIZE(terratec_cinergy_c_pci), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_TERRATEC_CINERGY_C_PCI, + .scan = terratec_cinergy_c_pci, + .size = ARRAY_SIZE(terratec_cinergy_c_pci), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TERRATEC_CINERGY_C_PCI, } }; 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 1e096bbda4a0..bf0171b05ac2 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c @@ -63,10 +63,10 @@ static struct rc_map_table terratec_cinergy_s2_hd[] = { static struct rc_map_list terratec_cinergy_s2_hd_map = { .map = { - .scan = terratec_cinergy_s2_hd, - .size = ARRAY_SIZE(terratec_cinergy_s2_hd), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_TERRATEC_CINERGY_S2_HD, + .scan = terratec_cinergy_s2_hd, + .size = ARRAY_SIZE(terratec_cinergy_s2_hd), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TERRATEC_CINERGY_S2_HD, } }; diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c index 97eb83ab5a35..3d0f6f7e5bea 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c @@ -69,10 +69,10 @@ static struct rc_map_table terratec_cinergy_xs[] = { static struct rc_map_list terratec_cinergy_xs_map = { .map = { - .scan = terratec_cinergy_xs, - .size = ARRAY_SIZE(terratec_cinergy_xs), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_TERRATEC_CINERGY_XS, + .scan = terratec_cinergy_xs, + .size = ARRAY_SIZE(terratec_cinergy_xs), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TERRATEC_CINERGY_XS, } }; diff --git a/drivers/media/rc/keymaps/rc-terratec-slim-2.c b/drivers/media/rc/keymaps/rc-terratec-slim-2.c index 4c149ef712dc..df57e0a45820 100644 --- a/drivers/media/rc/keymaps/rc-terratec-slim-2.c +++ b/drivers/media/rc/keymaps/rc-terratec-slim-2.c @@ -49,10 +49,10 @@ static struct rc_map_table terratec_slim_2[] = { static struct rc_map_list terratec_slim_2_map = { .map = { - .scan = terratec_slim_2, - .size = ARRAY_SIZE(terratec_slim_2), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_TERRATEC_SLIM_2, + .scan = terratec_slim_2, + .size = ARRAY_SIZE(terratec_slim_2), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_TERRATEC_SLIM_2, } }; diff --git a/drivers/media/rc/keymaps/rc-terratec-slim.c b/drivers/media/rc/keymaps/rc-terratec-slim.c index 3d8a19cdb5a2..628272c58d65 100644 --- a/drivers/media/rc/keymaps/rc-terratec-slim.c +++ b/drivers/media/rc/keymaps/rc-terratec-slim.c @@ -56,10 +56,10 @@ static struct rc_map_table terratec_slim[] = { static struct rc_map_list terratec_slim_map = { .map = { - .scan = terratec_slim, - .size = ARRAY_SIZE(terratec_slim), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_TERRATEC_SLIM, + .scan = terratec_slim, + .size = ARRAY_SIZE(terratec_slim), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_TERRATEC_SLIM, } }; diff --git a/drivers/media/rc/keymaps/rc-tevii-nec.c b/drivers/media/rc/keymaps/rc-tevii-nec.c index 38e0c0875596..31f8a0fd1f2c 100644 --- a/drivers/media/rc/keymaps/rc-tevii-nec.c +++ b/drivers/media/rc/keymaps/rc-tevii-nec.c @@ -65,10 +65,10 @@ static struct rc_map_table tevii_nec[] = { static struct rc_map_list tevii_nec_map = { .map = { - .scan = tevii_nec, - .size = ARRAY_SIZE(tevii_nec), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_TEVII_NEC, + .scan = tevii_nec, + .size = ARRAY_SIZE(tevii_nec), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TEVII_NEC, } }; diff --git a/drivers/media/rc/keymaps/rc-tivo.c b/drivers/media/rc/keymaps/rc-tivo.c index 5cc1b456e329..1962e33c8f4e 100644 --- a/drivers/media/rc/keymaps/rc-tivo.c +++ b/drivers/media/rc/keymaps/rc-tivo.c @@ -75,10 +75,10 @@ static struct rc_map_table tivo[] = { static struct rc_map_list tivo_map = { .map = { - .scan = tivo, - .size = ARRAY_SIZE(tivo), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_TIVO, + .scan = tivo, + .size = ARRAY_SIZE(tivo), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_TIVO, } }; 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 47270f72ebf0..eeeca142f7b1 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 @@ -62,10 +62,10 @@ static struct rc_map_table total_media_in_hand_02[] = { static struct rc_map_list total_media_in_hand_02_map = { .map = { - .scan = total_media_in_hand_02, - .size = ARRAY_SIZE(total_media_in_hand_02), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_TOTAL_MEDIA_IN_HAND_02, + .scan = total_media_in_hand_02, + .size = ARRAY_SIZE(total_media_in_hand_02), + .rc_proto = RC_PROTO_RC5, + .name = RC_MAP_TOTAL_MEDIA_IN_HAND_02, } }; 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 5b9f9ec13680..bc73bee309d8 100644 --- a/drivers/media/rc/keymaps/rc-total-media-in-hand.c +++ b/drivers/media/rc/keymaps/rc-total-media-in-hand.c @@ -62,10 +62,10 @@ static struct rc_map_table total_media_in_hand[] = { static struct rc_map_list total_media_in_hand_map = { .map = { - .scan = total_media_in_hand, - .size = ARRAY_SIZE(total_media_in_hand), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_TOTAL_MEDIA_IN_HAND, + .scan = total_media_in_hand, + .size = ARRAY_SIZE(total_media_in_hand), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_TOTAL_MEDIA_IN_HAND, } }; diff --git a/drivers/media/rc/keymaps/rc-trekstor.c b/drivers/media/rc/keymaps/rc-trekstor.c index f9a2e0fabb9f..63f966219342 100644 --- a/drivers/media/rc/keymaps/rc-trekstor.c +++ b/drivers/media/rc/keymaps/rc-trekstor.c @@ -57,10 +57,10 @@ static struct rc_map_table trekstor[] = { static struct rc_map_list trekstor_map = { .map = { - .scan = trekstor, - .size = ARRAY_SIZE(trekstor), - .rc_type = RC_TYPE_NEC, - .name = RC_MAP_TREKSTOR, + .scan = trekstor, + .size = ARRAY_SIZE(trekstor), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_TREKSTOR, } }; diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c index c766d3b2b6b0..374c230705d2 100644 --- a/drivers/media/rc/keymaps/rc-tt-1500.c +++ b/drivers/media/rc/keymaps/rc-tt-1500.c @@ -59,10 +59,10 @@ static struct rc_map_table tt_1500[] = { static struct rc_map_list tt_1500_map = { .map = { - .scan = tt_1500, - .size = ARRAY_SIZE(tt_1500), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_TT_1500, + .scan = tt_1500, + .size = ARRAY_SIZE(tt_1500), + .rc_proto = RC_PROTO_RC5, + .name = RC_MAP_TT_1500, } }; 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 202500cb3061..240d720d440c 100644 --- a/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c +++ b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c @@ -75,10 +75,10 @@ static struct rc_map_table twinhan_dtv_cab_ci[] = { static struct rc_map_list twinhan_dtv_cab_ci_map = { .map = { - .scan = twinhan_dtv_cab_ci, - .size = ARRAY_SIZE(twinhan_dtv_cab_ci), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_TWINHAN_DTV_CAB_CI, + .scan = twinhan_dtv_cab_ci, + .size = ARRAY_SIZE(twinhan_dtv_cab_ci), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TWINHAN_DTV_CAB_CI, } }; diff --git a/drivers/media/rc/keymaps/rc-twinhan1027.c b/drivers/media/rc/keymaps/rc-twinhan1027.c index 509299b90c90..2275b37c61d2 100644 --- a/drivers/media/rc/keymaps/rc-twinhan1027.c +++ b/drivers/media/rc/keymaps/rc-twinhan1027.c @@ -64,10 +64,10 @@ static struct rc_map_table twinhan_vp1027[] = { static struct rc_map_list twinhan_vp1027_map = { .map = { - .scan = twinhan_vp1027, - .size = ARRAY_SIZE(twinhan_vp1027), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_TWINHAN_VP1027_DVBS, + .scan = twinhan_vp1027, + .size = ARRAY_SIZE(twinhan_vp1027), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_TWINHAN_VP1027_DVBS, } }; diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-m1f.c index 23ee05e53949..fe02e047bd01 100644 --- a/drivers/media/rc/keymaps/rc-videomate-m1f.c +++ b/drivers/media/rc/keymaps/rc-videomate-m1f.c @@ -69,10 +69,10 @@ static struct rc_map_table videomate_k100[] = { static struct rc_map_list videomate_k100_map = { .map = { - .scan = videomate_k100, - .size = ARRAY_SIZE(videomate_k100), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_VIDEOMATE_K100, + .scan = videomate_k100, + .size = ARRAY_SIZE(videomate_k100), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_VIDEOMATE_K100, } }; diff --git a/drivers/media/rc/keymaps/rc-videomate-s350.c b/drivers/media/rc/keymaps/rc-videomate-s350.c index 8a354775a2d8..b4f103269872 100644 --- a/drivers/media/rc/keymaps/rc-videomate-s350.c +++ b/drivers/media/rc/keymaps/rc-videomate-s350.c @@ -62,10 +62,10 @@ static struct rc_map_table videomate_s350[] = { static struct rc_map_list videomate_s350_map = { .map = { - .scan = videomate_s350, - .size = ARRAY_SIZE(videomate_s350), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_VIDEOMATE_S350, + .scan = videomate_s350, + .size = ARRAY_SIZE(videomate_s350), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_VIDEOMATE_S350, } }; diff --git a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c index eb0cda7766c4..c431fdf44057 100644 --- a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c +++ b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c @@ -64,10 +64,10 @@ static struct rc_map_table videomate_tv_pvr[] = { static struct rc_map_list videomate_tv_pvr_map = { .map = { - .scan = videomate_tv_pvr, - .size = ARRAY_SIZE(videomate_tv_pvr), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_VIDEOMATE_TV_PVR, + .scan = videomate_tv_pvr, + .size = ARRAY_SIZE(videomate_tv_pvr), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_VIDEOMATE_TV_PVR, } }; diff --git a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c index c1dd598e828e..5a437e61bd5d 100644 --- a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c +++ b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c @@ -59,10 +59,10 @@ static struct rc_map_table winfast_usbii_deluxe[] = { static struct rc_map_list winfast_usbii_deluxe_map = { .map = { - .scan = winfast_usbii_deluxe, - .size = ARRAY_SIZE(winfast_usbii_deluxe), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_WINFAST_USBII_DELUXE, + .scan = winfast_usbii_deluxe, + .size = ARRAY_SIZE(winfast_usbii_deluxe), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_WINFAST_USBII_DELUXE, } }; diff --git a/drivers/media/rc/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c index 8a779da1e973..53685d1f9a47 100644 --- a/drivers/media/rc/keymaps/rc-winfast.c +++ b/drivers/media/rc/keymaps/rc-winfast.c @@ -79,10 +79,10 @@ static struct rc_map_table winfast[] = { static struct rc_map_list winfast_map = { .map = { - .scan = winfast, - .size = ARRAY_SIZE(winfast), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_WINFAST, + .scan = winfast, + .size = ARRAY_SIZE(winfast), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_WINFAST, } }; diff --git a/drivers/media/rc/keymaps/rc-zx-irdec.c b/drivers/media/rc/keymaps/rc-zx-irdec.c new file mode 100644 index 000000000000..5bf3ab002afc --- /dev/null +++ b/drivers/media/rc/keymaps/rc-zx-irdec.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2017 Sanechips Technology Co., Ltd. + * Copyright 2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <media/rc-map.h> + +static struct rc_map_table zx_irdec_table[] = { + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + { 0x31, KEY_0 }, + { 0x16, KEY_DELETE }, + { 0x0a, KEY_MODE }, /* Input method */ + { 0x0c, KEY_VOLUMEUP }, + { 0x18, KEY_VOLUMEDOWN }, + { 0x0b, KEY_CHANNELUP }, + { 0x15, KEY_CHANNELDOWN }, + { 0x0d, KEY_PAGEUP }, + { 0x13, KEY_PAGEDOWN }, + { 0x46, KEY_FASTFORWARD }, + { 0x43, KEY_REWIND }, + { 0x44, KEY_PLAYPAUSE }, + { 0x45, KEY_STOP }, + { 0x49, KEY_OK }, + { 0x47, KEY_UP }, + { 0x4b, KEY_DOWN }, + { 0x48, KEY_LEFT }, + { 0x4a, KEY_RIGHT }, + { 0x4d, KEY_MENU }, + { 0x56, KEY_APPSELECT }, /* Application */ + { 0x4c, KEY_BACK }, + { 0x1e, KEY_INFO }, + { 0x4e, KEY_F1 }, + { 0x4f, KEY_F2 }, + { 0x50, KEY_F3 }, + { 0x51, KEY_F4 }, + { 0x1c, KEY_AUDIO }, + { 0x12, KEY_MUTE }, + { 0x11, KEY_DOT }, /* Location */ + { 0x1d, KEY_SETUP }, + { 0x40, KEY_POWER }, +}; + +static struct rc_map_list zx_irdec_map = { + .map = { + .scan = zx_irdec_table, + .size = ARRAY_SIZE(zx_irdec_table), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_ZX_IRDEC, + } +}; + +static int __init init_rc_map_zx_irdec(void) +{ + return rc_map_register(&zx_irdec_map); +} + +static void __exit exit_rc_map_zx_irdec(void) +{ + rc_map_unregister(&zx_irdec_map); +} + +module_init(init_rc_map_zx_irdec) +module_exit(exit_rc_map_zx_irdec) + +MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index db1e7b70c998..9080e39ea391 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -59,6 +59,8 @@ static void lirc_release(struct device *ld) { struct irctl *ir = container_of(ld, struct irctl, dev); + put_device(ir->dev.parent); + if (ir->buf_internal) { lirc_buffer_free(ir->buf); kfree(ir->buf); @@ -218,6 +220,8 @@ int lirc_register_driver(struct lirc_driver *d) mutex_unlock(&lirc_dev_lock); + get_device(ir->dev.parent); + dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", ir->d.name, ir->d.minor); diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index eb130694bbb8..bf7aaff3aa37 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -538,12 +538,12 @@ static int mceusb_cmd_datasize(u8 cmd, u8 subcmd) return datasize; } -static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, - int buf_len, int offset, int len, bool out) +static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len, + int offset, int len, bool out) { #if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) char *inout; - u8 cmd, subcmd, data1, data2, data3, data4; + u8 cmd, subcmd, *data; struct device *dev = ir->dev; int start, skip = 0; u32 carrier, period; @@ -564,17 +564,14 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, start = offset + skip; cmd = buf[start] & 0xff; subcmd = buf[start + 1] & 0xff; - data1 = buf[start + 2] & 0xff; - data2 = buf[start + 3] & 0xff; - data3 = buf[start + 4] & 0xff; - data4 = buf[start + 5] & 0xff; + data = buf + start + 2; switch (cmd) { case MCE_CMD_NULL: if (subcmd == MCE_CMD_NULL) break; if ((subcmd == MCE_CMD_PORT_SYS) && - (data1 == MCE_CMD_RESUME)) + (data[0] == MCE_CMD_RESUME)) dev_dbg(dev, "Device resume requested"); else dev_dbg(dev, "Unknown command 0x%02x 0x%02x", @@ -585,7 +582,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, case MCE_RSP_EQEMVER: if (!out) dev_dbg(dev, "Emulator interface version %x", - data1); + data[0]); break; case MCE_CMD_G_REVISION: if (len == 2) @@ -603,13 +600,13 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, case MCE_RSP_EQWAKEVERSION: if (!out) dev_dbg(dev, "Wake version, proto: 0x%02x, payload: 0x%02x, address: 0x%02x, version: 0x%02x", - data1, data2, data3, data4); + data[0], data[1], data[2], data[3]); break; case MCE_RSP_GETPORTSTATUS: if (!out) /* We use data1 + 1 here, to match hw labels */ dev_dbg(dev, "TX port %d: blaster is%s connected", - data1 + 1, data4 ? " not" : ""); + data[0] + 1, data[3] ? " not" : ""); break; case MCE_CMD_FLASHLED: dev_dbg(dev, "Attempting to flash LED"); @@ -630,11 +627,11 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, break; case MCE_CMD_UNKNOWN: dev_dbg(dev, "Resp to 9f 05 of 0x%02x 0x%02x", - data1, data2); + data[0], data[1]); break; case MCE_RSP_EQIRCFS: - period = DIV_ROUND_CLOSEST( - (1U << data1 * 2) * (data2 + 1), 10); + period = DIV_ROUND_CLOSEST((1U << data[0] * 2) * + (data[1] + 1), 10); if (!period) break; carrier = (1000 * 1000) / period; @@ -646,11 +643,12 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, break; case MCE_RSP_EQIRTXPORTS: dev_dbg(dev, "%s transmit blaster mask of 0x%02x", - inout, data1); + inout, data[0]); break; case MCE_RSP_EQIRTIMEOUT: /* value is in units of 50us, so x*50/1000 ms */ - period = ((data1 << 8) | data2) * MCE_TIME_UNIT / 1000; + period = ((data[0] << 8) | data[1]) * + MCE_TIME_UNIT / 1000; dev_dbg(dev, "%s receive timeout of %d ms", inout, period); break; @@ -662,7 +660,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, break; case MCE_RSP_EQIRRXPORTEN: dev_dbg(dev, "%s %s-range receive sensor in use", - inout, data1 == 0x02 ? "short" : "long"); + inout, data[0] == 0x02 ? "short" : "long"); break; case MCE_CMD_GETIRRXPORTEN: /* aka MCE_RSP_EQIRRXCFCNT */ @@ -670,13 +668,13 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, dev_dbg(dev, "Get receive sensor"); else if (ir->learning_enabled) dev_dbg(dev, "RX pulse count: %d", - ((data1 << 8) | data2)); + ((data[0] << 8) | data[1])); break; case MCE_RSP_EQIRNUMPORTS: if (out) break; dev_dbg(dev, "Num TX ports: %x, num RX ports: %x", - data1, data2); + data[0], data[1]); break; case MCE_RSP_CMD_ILLEGAL: dev_dbg(dev, "Illegal PORT_IR command"); @@ -1264,12 +1262,12 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys)); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; usb_to_input_id(ir->usbdev, &rc->input_id); rc->dev.parent = dev; rc->priv = ir; - rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rc->timeout = MS_TO_NS(100); if (!ir->flags.no_tx) { rc->s_tx_mask = mceusb_set_tx_mask; diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 65566d569cb1..f2204eb77e2a 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -138,12 +138,12 @@ static int meson_ir_probe(struct platform_device *pdev) } ir->rc->priv = ir; - ir->rc->input_name = DRIVER_NAME; + 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_BIT_ALL_IR_DECODER; + ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; ir->rc->rx_resolution = US_TO_NS(MESON_TRATE); ir->rc->timeout = MS_TO_NS(200); ir->rc->driver_name = DRIVER_NAME; diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c index f1e164e441e8..e88eb64e8e69 100644 --- a/drivers/media/rc/mtk-cir.c +++ b/drivers/media/rc/mtk-cir.c @@ -25,35 +25,28 @@ /* Register to enable PWM and IR */ #define MTK_CONFIG_HIGH_REG 0x0c -/* Enable IR pulse width detection */ + +/* Bit to enable IR pulse width detection */ #define MTK_PWM_EN BIT(13) -/* Enable IR hardware function */ -#define MTK_IR_EN BIT(0) -/* Register to setting sample period */ -#define MTK_CONFIG_LOW_REG 0x10 -/* Field to set sample period */ -#define CHK_PERIOD DIV_ROUND_CLOSEST(MTK_IR_SAMPLE, \ - MTK_IR_CLK_PERIOD) -#define MTK_CHK_PERIOD (((CHK_PERIOD) << 8) & (GENMASK(20, 8))) -#define MTK_CHK_PERIOD_MASK (GENMASK(20, 8)) +/* + * Register to setting ok count whose unit based on hardware sampling period + * indicating IR receiving completion and then making IRQ fires + */ +#define MTK_OK_COUNT(x) (((x) & GENMASK(23, 16)) << 16) + +/* Bit to enable IR hardware function */ +#define MTK_IR_EN BIT(0) -/* Register to clear state of state machine */ -#define MTK_IRCLR_REG 0x20 /* Bit to restart IR receiving */ #define MTK_IRCLR BIT(0) -/* Register containing pulse width data */ -#define MTK_CHKDATA_REG(i) (0x88 + 4 * (i)) +/* Fields containing pulse width data */ #define MTK_WIDTH_MASK (GENMASK(7, 0)) -/* Register to enable IR interrupt */ -#define MTK_IRINT_EN_REG 0xcc /* Bit to enable interrupt */ #define MTK_IRINT_EN BIT(0) -/* Register to ack IR interrupt */ -#define MTK_IRINT_CLR_REG 0xd0 /* Bit to clear interrupt status */ #define MTK_IRINT_CLR BIT(0) @@ -63,24 +56,85 @@ #define MTK_IR_END(v, p) ((v) == MTK_MAX_SAMPLES && (p) == 0) /* Number of registers to record the pulse width */ #define MTK_CHKDATA_SZ 17 -/* Source clock frequency */ -#define MTK_IR_BASE_CLK 273000000 -/* Frequency after IR internal divider */ -#define MTK_IR_CLK_FREQ (MTK_IR_BASE_CLK / 4) -/* Period for MTK_IR_CLK in ns*/ -#define MTK_IR_CLK_PERIOD DIV_ROUND_CLOSEST(1000000000ul, \ - MTK_IR_CLK_FREQ) /* Sample period in ns */ -#define MTK_IR_SAMPLE (MTK_IR_CLK_PERIOD * 0xc00) +#define MTK_IR_SAMPLE 46000 + +enum mtk_fields { + /* Register to setting software sampling period */ + MTK_CHK_PERIOD, + /* Register to setting hardware sampling period */ + MTK_HW_PERIOD, +}; + +enum mtk_regs { + /* Register to clear state of state machine */ + MTK_IRCLR_REG, + /* Register containing pulse width data */ + MTK_CHKDATA_REG, + /* Register to enable IR interrupt */ + MTK_IRINT_EN_REG, + /* Register to ack IR interrupt */ + MTK_IRINT_CLR_REG +}; + +static const u32 mt7623_regs[] = { + [MTK_IRCLR_REG] = 0x20, + [MTK_CHKDATA_REG] = 0x88, + [MTK_IRINT_EN_REG] = 0xcc, + [MTK_IRINT_CLR_REG] = 0xd0, +}; + +static const u32 mt7622_regs[] = { + [MTK_IRCLR_REG] = 0x18, + [MTK_CHKDATA_REG] = 0x30, + [MTK_IRINT_EN_REG] = 0x1c, + [MTK_IRINT_CLR_REG] = 0x20, +}; + +struct mtk_field_type { + u32 reg; + u8 offset; + u32 mask; +}; + +/* + * struct mtk_ir_data - This is the structure holding all differences among + various hardwares + * @regs: The pointer to the array holding registers offset + * @fields: The pointer to the array holding fields location + * @div: The internal divisor for the based reference clock + * @ok_count: The count indicating the completion of IR data + * receiving when count is reached + * @hw_period: The value indicating the hardware sampling period + */ +struct mtk_ir_data { + const u32 *regs; + const struct mtk_field_type *fields; + u8 div; + u8 ok_count; + u32 hw_period; +}; + +static const struct mtk_field_type mt7623_fields[] = { + [MTK_CHK_PERIOD] = {0x10, 8, GENMASK(20, 8)}, + [MTK_HW_PERIOD] = {0x10, 0, GENMASK(7, 0)}, +}; + +static const struct mtk_field_type mt7622_fields[] = { + [MTK_CHK_PERIOD] = {0x24, 0, GENMASK(24, 0)}, + [MTK_HW_PERIOD] = {0x10, 0, GENMASK(24, 0)}, +}; /* * struct mtk_ir - This is the main datasructure for holding the state * of the driver * @dev: The device pointer * @rc: The rc instrance - * @irq: The IRQ that we are using * @base: The mapped register i/o base - * @clk: The clock that we are using + * @irq: The IRQ that we are using + * @clk: The clock that IR internal is using + * @bus: The clock that software decoder is using + * @data: Holding specific data for vaious platform */ struct mtk_ir { struct device *dev; @@ -88,8 +142,36 @@ struct mtk_ir { void __iomem *base; int irq; struct clk *clk; + struct clk *bus; + const struct mtk_ir_data *data; }; +static inline u32 mtk_chkdata_reg(struct mtk_ir *ir, u32 i) +{ + return ir->data->regs[MTK_CHKDATA_REG] + 4 * i; +} + +static inline u32 mtk_chk_period(struct mtk_ir *ir) +{ + u32 val; + + /* Period of raw software sampling in ns */ + val = DIV_ROUND_CLOSEST(1000000000ul, + clk_get_rate(ir->bus) / ir->data->div); + + /* + * Period for software decoder used in the + * unit of raw software sampling + */ + val = DIV_ROUND_CLOSEST(MTK_IR_SAMPLE, val); + + dev_dbg(ir->dev, "@pwm clk = \t%lu\n", + clk_get_rate(ir->bus) / ir->data->div); + dev_dbg(ir->dev, "@chkperiod = %08x\n", val); + + return val; +} + static void mtk_w32_mask(struct mtk_ir *ir, u32 val, u32 mask, unsigned int reg) { u32 tmp; @@ -113,16 +195,16 @@ static inline void mtk_irq_disable(struct mtk_ir *ir, u32 mask) { u32 val; - val = mtk_r32(ir, MTK_IRINT_EN_REG); - mtk_w32(ir, val & ~mask, MTK_IRINT_EN_REG); + val = mtk_r32(ir, ir->data->regs[MTK_IRINT_EN_REG]); + mtk_w32(ir, val & ~mask, ir->data->regs[MTK_IRINT_EN_REG]); } static inline void mtk_irq_enable(struct mtk_ir *ir, u32 mask) { u32 val; - val = mtk_r32(ir, MTK_IRINT_EN_REG); - mtk_w32(ir, val | mask, MTK_IRINT_EN_REG); + val = mtk_r32(ir, ir->data->regs[MTK_IRINT_EN_REG]); + mtk_w32(ir, val | mask, ir->data->regs[MTK_IRINT_EN_REG]); } static irqreturn_t mtk_ir_irq(int irqno, void *dev_id) @@ -140,7 +222,7 @@ static irqreturn_t mtk_ir_irq(int irqno, void *dev_id) * every decoder to reset themselves through long enough * trailing spaces and 2) the IRQ handler guarantees that * start of IR message is always contained in and starting - * from register MTK_CHKDATA_REG(0). + * from register mtk_chkdata_reg(ir, i). */ ir_raw_event_reset(ir->rc); @@ -149,7 +231,7 @@ static irqreturn_t mtk_ir_irq(int irqno, void *dev_id) /* Handle all pulse and space IR controller captures */ for (i = 0 ; i < MTK_CHKDATA_SZ ; i++) { - val = mtk_r32(ir, MTK_CHKDATA_REG(i)); + val = mtk_r32(ir, mtk_chkdata_reg(ir, i)); dev_dbg(ir->dev, "@reg%d=0x%08x\n", i, val); for (j = 0 ; j < 4 ; j++) { @@ -181,18 +263,44 @@ static irqreturn_t mtk_ir_irq(int irqno, void *dev_id) * Restart controller for the next receive that would * clear up all CHKDATA registers */ - mtk_w32_mask(ir, 0x1, MTK_IRCLR, MTK_IRCLR_REG); + mtk_w32_mask(ir, 0x1, MTK_IRCLR, ir->data->regs[MTK_IRCLR_REG]); /* Clear interrupt status */ - mtk_w32_mask(ir, 0x1, MTK_IRINT_CLR, MTK_IRINT_CLR_REG); + mtk_w32_mask(ir, 0x1, MTK_IRINT_CLR, + ir->data->regs[MTK_IRINT_CLR_REG]); return IRQ_HANDLED; } +static const struct mtk_ir_data mt7623_data = { + .regs = mt7623_regs, + .fields = mt7623_fields, + .ok_count = 0xf, + .hw_period = 0xff, + .div = 4, +}; + +static const struct mtk_ir_data mt7622_data = { + .regs = mt7622_regs, + .fields = mt7622_fields, + .ok_count = 0xf, + .hw_period = 0xffff, + .div = 32, +}; + +static const struct of_device_id mtk_ir_match[] = { + { .compatible = "mediatek,mt7623-cir", .data = &mt7623_data}, + { .compatible = "mediatek,mt7622-cir", .data = &mt7622_data}, + {}, +}; +MODULE_DEVICE_TABLE(of, mtk_ir_match); + static int mtk_ir_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *dn = dev->of_node; + const struct of_device_id *of_id = + of_match_device(mtk_ir_match, &pdev->dev); struct resource *res; struct mtk_ir *ir; u32 val; @@ -204,9 +312,7 @@ static int mtk_ir_probe(struct platform_device *pdev) return -ENOMEM; ir->dev = dev; - - if (!of_device_is_compatible(dn, "mediatek,mt7623-cir")) - return -ENODEV; + ir->data = of_id->data; ir->clk = devm_clk_get(dev, "clk"); if (IS_ERR(ir->clk)) { @@ -214,6 +320,15 @@ static int mtk_ir_probe(struct platform_device *pdev) return PTR_ERR(ir->clk); } + ir->bus = devm_clk_get(dev, "bus"); + if (IS_ERR(ir->bus)) { + /* + * For compatibility with older device trees try unnamed + * ir->bus uses the same clock as ir->clock. + */ + ir->bus = ir->clk; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ir->base = devm_ioremap_resource(dev, res); if (IS_ERR(ir->base)) { @@ -228,7 +343,7 @@ static int mtk_ir_probe(struct platform_device *pdev) } ir->rc->priv = ir; - ir->rc->input_name = MTK_IR_DEV; + ir->rc->device_name = MTK_IR_DEV; ir->rc->input_phys = MTK_IR_DEV "/input0"; ir->rc->input_id.bustype = BUS_HOST; ir->rc->input_id.vendor = 0x0001; @@ -238,7 +353,7 @@ static int mtk_ir_probe(struct platform_device *pdev) ir->rc->map_name = map_name ?: RC_MAP_EMPTY; ir->rc->dev.parent = dev; ir->rc->driver_name = MTK_IR_DEV; - ir->rc->allowed_protocols = RC_BIT_ALL; + ir->rc->allowed_protocols = RC_PROTO_BIT_ALL; ir->rc->rx_resolution = MTK_IR_SAMPLE; ir->rc->timeout = MTK_MAX_SAMPLES * (MTK_IR_SAMPLE + 1); @@ -256,40 +371,60 @@ static int mtk_ir_probe(struct platform_device *pdev) return -ENODEV; } - /* - * Enable interrupt after proper hardware - * setup and IRQ handler registration - */ if (clk_prepare_enable(ir->clk)) { dev_err(dev, "try to enable ir_clk failed\n"); + return -EINVAL; + } + + if (clk_prepare_enable(ir->bus)) { + dev_err(dev, "try to enable ir_clk failed\n"); ret = -EINVAL; goto exit_clkdisable_clk; } + /* + * Enable interrupt after proper hardware + * setup and IRQ handler registration + */ mtk_irq_disable(ir, MTK_IRINT_EN); ret = devm_request_irq(dev, ir->irq, mtk_ir_irq, 0, MTK_IR_DEV, ir); if (ret) { dev_err(dev, "failed request irq\n"); - goto exit_clkdisable_clk; + goto exit_clkdisable_bus; } + /* + * Setup software sample period as the reference of software decoder + */ + val = (mtk_chk_period(ir) << ir->data->fields[MTK_CHK_PERIOD].offset) & + ir->data->fields[MTK_CHK_PERIOD].mask; + mtk_w32_mask(ir, val, ir->data->fields[MTK_CHK_PERIOD].mask, + ir->data->fields[MTK_CHK_PERIOD].reg); + + /* + * Setup hardware sampling period used to setup the proper timeout for + * indicating end of IR receiving completion + */ + val = (ir->data->hw_period << ir->data->fields[MTK_HW_PERIOD].offset) & + ir->data->fields[MTK_HW_PERIOD].mask; + mtk_w32_mask(ir, val, ir->data->fields[MTK_HW_PERIOD].mask, + ir->data->fields[MTK_HW_PERIOD].reg); + /* Enable IR and PWM */ val = mtk_r32(ir, MTK_CONFIG_HIGH_REG); - val |= MTK_PWM_EN | MTK_IR_EN; + val |= MTK_OK_COUNT(ir->data->ok_count) | MTK_PWM_EN | MTK_IR_EN; mtk_w32(ir, val, MTK_CONFIG_HIGH_REG); - /* Setting sample period */ - mtk_w32_mask(ir, MTK_CHK_PERIOD, MTK_CHK_PERIOD_MASK, - MTK_CONFIG_LOW_REG); - mtk_irq_enable(ir, MTK_IRINT_EN); - dev_info(dev, "Initialized MT7623 IR driver, sample period = %luus\n", + dev_info(dev, "Initialized MT7623 IR driver, sample period = %dus\n", DIV_ROUND_CLOSEST(MTK_IR_SAMPLE, 1000)); return 0; +exit_clkdisable_bus: + clk_disable_unprepare(ir->bus); exit_clkdisable_clk: clk_disable_unprepare(ir->clk); @@ -308,17 +443,12 @@ static int mtk_ir_remove(struct platform_device *pdev) mtk_irq_disable(ir, MTK_IRINT_EN); synchronize_irq(ir->irq); + clk_disable_unprepare(ir->bus); clk_disable_unprepare(ir->clk); return 0; } -static const struct of_device_id mtk_ir_match[] = { - { .compatible = "mediatek,mt7623-cir" }, - {}, -}; -MODULE_DEVICE_TABLE(of, mtk_ir_match); - static struct platform_driver mtk_ir_driver = { .probe = mtk_ir_probe, .remove = mtk_ir_remove, diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index ec4b25bd2ec2..5e1d866a61a5 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -727,70 +727,6 @@ out_raw: return ret; } -/* - * nvt_tx_ir - * - * 1) clean TX fifo first (handled by AP) - * 2) copy data from user space - * 3) disable RX interrupts, enable TX interrupts: TTR & TFU - * 4) send 9 packets to TX FIFO to open TTR - * in interrupt_handler: - * 5) send all data out - * go back to write(): - * 6) disable TX interrupts, re-enable RX interupts - * - * The key problem of this function is user space data may larger than - * driver's data buf length. So nvt_tx_ir() will only copy TX_BUF_LEN data to - * buf, and keep current copied data buf num in cur_buf_num. But driver's buf - * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to - * set TXFCONT as 0xff, until buf_count less than 0xff. - */ -static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n) -{ - struct nvt_dev *nvt = dev->priv; - unsigned long flags; - unsigned int i; - u8 iren; - int ret; - - spin_lock_irqsave(&nvt->lock, flags); - - ret = min((unsigned)(TX_BUF_LEN / sizeof(unsigned)), n); - nvt->tx.buf_count = (ret * sizeof(unsigned)); - - memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count); - - nvt->tx.cur_buf_num = 0; - - /* save currently enabled interrupts */ - iren = nvt_cir_reg_read(nvt, CIR_IREN); - - /* now disable all interrupts, save TFU & TTR */ - nvt_cir_reg_write(nvt, CIR_IREN_TFU | CIR_IREN_TTR, CIR_IREN); - - nvt->tx.tx_state = ST_TX_REPLY; - - nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV_8 | - CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON); - - /* trigger TTR interrupt by writing out ones, (yes, it's ugly) */ - for (i = 0; i < 9; i++) - nvt_cir_reg_write(nvt, 0x01, CIR_STXFIFO); - - spin_unlock_irqrestore(&nvt->lock, flags); - - wait_event(nvt->tx.queue, nvt->tx.tx_state == ST_TX_REQUEST); - - spin_lock_irqsave(&nvt->lock, flags); - nvt->tx.tx_state = ST_TX_NONE; - spin_unlock_irqrestore(&nvt->lock, flags); - - /* restore enabled interrupts to prior state */ - nvt_cir_reg_write(nvt, iren, CIR_IREN); - - return ret; -} - /* dump contents of the last rx buffer we got from the hw rx fifo */ static void nvt_dump_rx_buf(struct nvt_dev *nvt) { @@ -895,11 +831,6 @@ static void nvt_cir_log_irqs(u8 status, u8 iren) CIR_IRSTS_TFU | CIR_IRSTS_GH) ? " ?" : ""); } -static bool nvt_cir_tx_inactive(struct nvt_dev *nvt) -{ - return nvt->tx.tx_state == ST_TX_NONE; -} - /* interrupt service routine for incoming and outgoing CIR data */ static irqreturn_t nvt_cir_isr(int irq, void *data) { @@ -952,40 +883,8 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) if (status & CIR_IRSTS_RFO) nvt_handle_rx_fifo_overrun(nvt); - - else if (status & (CIR_IRSTS_RTR | CIR_IRSTS_PE)) { - /* We only do rx if not tx'ing */ - if (nvt_cir_tx_inactive(nvt)) - nvt_get_rx_ir_data(nvt); - } - - if (status & CIR_IRSTS_TE) - nvt_clear_tx_fifo(nvt); - - if (status & CIR_IRSTS_TTR) { - unsigned int pos, count; - u8 tmp; - - pos = nvt->tx.cur_buf_num; - count = nvt->tx.buf_count; - - /* Write data into the hardware tx fifo while pos < count */ - if (pos < count) { - nvt_cir_reg_write(nvt, nvt->tx.buf[pos], CIR_STXFIFO); - nvt->tx.cur_buf_num++; - /* Disable TX FIFO Trigger Level Reach (TTR) interrupt */ - } else { - tmp = nvt_cir_reg_read(nvt, CIR_IREN); - nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN); - } - } - - if (status & CIR_IRSTS_TFU) { - if (nvt->tx.tx_state == ST_TX_REPLY) { - nvt->tx.tx_state = ST_TX_REQUEST; - wake_up(&nvt->tx.queue); - } - } + else if (status & (CIR_IRSTS_RTR | CIR_IRSTS_PE)) + nvt_get_rx_ir_data(nvt); spin_unlock(&nvt->lock); @@ -1062,7 +961,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) if (!nvt) return -ENOMEM; - /* input device for IR remote (and tx) */ + /* input device for IR remote */ nvt->rdev = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW); if (!nvt->rdev) return -ENOMEM; @@ -1105,8 +1004,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) pnp_set_drvdata(pdev, nvt); - init_waitqueue_head(&nvt->tx.queue); - ret = nvt_hw_detect(nvt); if (ret) return ret; @@ -1126,15 +1023,14 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) /* Set up the rc device */ rdev->priv = nvt; - rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; - rdev->allowed_wakeup_protocols = RC_BIT_ALL_IR_ENCODER; + rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + rdev->allowed_wakeup_protocols = RC_PROTO_BIT_ALL_IR_ENCODER; rdev->encode_wakeup = true; rdev->open = nvt_open; rdev->close = nvt_close; - rdev->tx_ir = nvt_tx_ir; rdev->s_tx_carrier = nvt_set_tx_carrier; rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_filter; - rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver"; + rdev->device_name = "Nuvoton w836x7hg Infrared Remote Transceiver"; rdev->input_phys = "nuvoton/cir0"; rdev->input_id.bustype = BUS_HOST; rdev->input_id.vendor = PCI_VENDOR_ID_WINBOND2; @@ -1148,8 +1044,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) #if 0 rdev->min_timeout = XYZ; rdev->max_timeout = XYZ; - /* tx bits */ - rdev->tx_resolution = XYZ; #endif ret = devm_rc_register_device(&pdev->dev, rdev); if (ret) @@ -1205,8 +1099,6 @@ static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) spin_lock_irqsave(&nvt->lock, flags); - nvt->tx.tx_state = ST_TX_NONE; - /* disable all CIR interrupts */ nvt_cir_reg_write(nvt, 0, CIR_IREN); diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index 88a29df38a57..0737c27f7ddc 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -46,14 +46,6 @@ static int debug; KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) -/* - * Original lirc driver said min value of 76, and recommended value of 256 - * for the buffer length, but then used 2048. Never mind that the size of the - * RX FIFO is 32 bytes... So I'm using 32 for RX and 256 for TX atm, but I'm - * not sure if maybe that TX value is off by a factor of 8 (bits vs. bytes), - * and I don't have TX-capable hardware to test/debug on... - */ -#define TX_BUF_LEN 256 #define RX_BUF_LEN 32 #define SIO_ID_MASK 0xfff0 @@ -81,14 +73,6 @@ struct nvt_dev { u8 buf[RX_BUF_LEN]; unsigned int pkts; - struct { - u8 buf[TX_BUF_LEN]; - unsigned int buf_count; - unsigned int cur_buf_num; - wait_queue_head_t queue; - u8 tx_state; - } tx; - /* EFER Config register index/data pair */ u32 cr_efir; u32 cr_efdr; @@ -103,18 +87,10 @@ struct nvt_dev { u8 chip_major; u8 chip_minor; - /* hardware features */ - bool hw_tx_capable; - /* carrier period = 1 / frequency */ u32 carrier; }; -/* send states */ -#define ST_TX_NONE 0x0 -#define ST_TX_REQUEST 0x2 -#define ST_TX_REPLY 0x4 - /* buffer packet constants */ #define BUF_PULSE_BIT 0x80 #define BUF_LEN_MASK 0x7f diff --git a/drivers/media/rc/pwm-ir-tx.c b/drivers/media/rc/pwm-ir-tx.c new file mode 100644 index 000000000000..27d0f5837a76 --- /dev/null +++ b/drivers/media/rc/pwm-ir-tx.c @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2017 Sean Young <sean@mess.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pwm.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <media/rc-core.h> + +#define DRIVER_NAME "pwm-ir-tx" +#define DEVICE_NAME "PWM IR Transmitter" + +struct pwm_ir { + struct pwm_device *pwm; + unsigned int carrier; + unsigned int duty_cycle; +}; + +static const struct of_device_id pwm_ir_of_match[] = { + { .compatible = "pwm-ir-tx", }, + { }, +}; +MODULE_DEVICE_TABLE(of, pwm_ir_of_match); + +static int pwm_ir_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle) +{ + struct pwm_ir *pwm_ir = dev->priv; + + pwm_ir->duty_cycle = duty_cycle; + + return 0; +} + +static int pwm_ir_set_carrier(struct rc_dev *dev, u32 carrier) +{ + struct pwm_ir *pwm_ir = dev->priv; + + if (!carrier) + return -EINVAL; + + pwm_ir->carrier = carrier; + + return 0; +} + +static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, + unsigned int count) +{ + struct pwm_ir *pwm_ir = dev->priv; + struct pwm_device *pwm = pwm_ir->pwm; + int i, duty, period; + ktime_t edge; + long delta; + + period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, pwm_ir->carrier); + duty = DIV_ROUND_CLOSEST(pwm_ir->duty_cycle * period, 100); + + pwm_config(pwm, duty, period); + + edge = ktime_get(); + + for (i = 0; i < count; i++) { + if (i % 2) // space + pwm_disable(pwm); + else + pwm_enable(pwm); + + edge = ktime_add_us(edge, txbuf[i]); + delta = ktime_us_delta(edge, ktime_get()); + if (delta > 0) + usleep_range(delta, delta + 10); + } + + pwm_disable(pwm); + + return count; +} + +static int pwm_ir_probe(struct platform_device *pdev) +{ + struct pwm_ir *pwm_ir; + struct rc_dev *rcdev; + int rc; + + pwm_ir = devm_kmalloc(&pdev->dev, sizeof(*pwm_ir), GFP_KERNEL); + if (!pwm_ir) + return -ENOMEM; + + pwm_ir->pwm = devm_pwm_get(&pdev->dev, NULL); + if (IS_ERR(pwm_ir->pwm)) + return PTR_ERR(pwm_ir->pwm); + + pwm_ir->carrier = 38000; + pwm_ir->duty_cycle = 50; + + rcdev = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW_TX); + if (!rcdev) + return -ENOMEM; + + rcdev->priv = pwm_ir; + rcdev->driver_name = DRIVER_NAME; + rcdev->device_name = DEVICE_NAME; + rcdev->tx_ir = pwm_ir_tx; + rcdev->s_tx_duty_cycle = pwm_ir_set_duty_cycle; + rcdev->s_tx_carrier = pwm_ir_set_carrier; + + rc = devm_rc_register_device(&pdev->dev, rcdev); + if (rc < 0) + dev_err(&pdev->dev, "failed to register rc device\n"); + + return rc; +} + +static struct platform_driver pwm_ir_driver = { + .probe = pwm_ir_probe, + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(pwm_ir_of_match), + }, +}; +module_platform_driver(pwm_ir_driver); + +MODULE_DESCRIPTION("PWM IR Transmitter"); +MODULE_AUTHOR("Sean Young <sean@mess.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index b3e7cac2c3ee..7da9c96cb058 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -27,7 +27,7 @@ struct ir_raw_handler { u64 protocols; /* which are handled by this handler */ int (*decode)(struct rc_dev *dev, struct ir_raw_event event); - int (*encode)(enum rc_type protocol, u32 scancode, + int (*encode)(enum rc_proto protocol, u32 scancode, struct ir_raw_event *events, unsigned int max); /* These two should only be used by the lirc decoder */ @@ -41,8 +41,9 @@ struct ir_raw_event_ctrl { /* fifo for the pulse/space durations */ DECLARE_KFIFO(kfifo, struct ir_raw_event, MAX_IR_EVENT_SIZE); ktime_t last_event; /* when last event occurred */ - enum raw_event_type last_type; /* last event type */ struct rc_dev *dev; /* pointer to the parent rc_dev */ + /* edge driver */ + struct timer_list edge_handle; /* raw decoder state follows */ struct ir_raw_event prev_ev; diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index b6d256f03847..503bc425a187 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -88,7 +88,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store); /** * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space * @dev: the struct rc_dev device descriptor - * @type: the type of the event that has occurred + * @pulse: true for pulse, false for space * * This routine (which may be called from an interrupt context) is used to * store the beginning of an ir pulse or space (or the start/end of ir @@ -96,43 +96,31 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store); * hardware which does not provide durations directly but only interrupts * (or similar events) on state change. */ -int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type) +int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse) { ktime_t now; - s64 delta; /* ns */ DEFINE_IR_RAW_EVENT(ev); int rc = 0; - int delay; if (!dev->raw) return -EINVAL; now = ktime_get(); - delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event)); - delay = MS_TO_NS(dev->input_dev->rep[REP_DELAY]); + ev.duration = ktime_to_ns(ktime_sub(now, dev->raw->last_event)); + ev.pulse = !pulse; - /* Check for a long duration since last event or if we're - * being called for the first time, note that delta can't - * possibly be negative. - */ - if (delta > delay || !dev->raw->last_type) - type |= IR_START_EVENT; - else - ev.duration = delta; - - if (type & IR_START_EVENT) - ir_raw_event_reset(dev); - else if (dev->raw->last_type & IR_SPACE) { - ev.pulse = false; - rc = ir_raw_event_store(dev, &ev); - } else if (dev->raw->last_type & IR_PULSE) { - ev.pulse = true; - rc = ir_raw_event_store(dev, &ev); - } else - return 0; + rc = ir_raw_event_store(dev, &ev); dev->raw->last_event = now; - dev->raw->last_type = type; + + /* timer could be set to timeout (125ms by default) */ + if (!timer_pending(&dev->raw->edge_handle) || + time_after(dev->raw->edge_handle.expires, + jiffies + msecs_to_jiffies(15))) { + mod_timer(&dev->raw->edge_handle, + jiffies + msecs_to_jiffies(15)); + } + return rc; } EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); @@ -225,7 +213,7 @@ ir_raw_get_allowed_protocols(void) return atomic64_read(&available_protocols); } -static int change_protocol(struct rc_dev *dev, u64 *rc_type) +static int change_protocol(struct rc_dev *dev, u64 *rc_proto) { /* the caller will update dev->enabled_protocols */ return 0; @@ -462,7 +450,7 @@ EXPORT_SYMBOL(ir_raw_gen_pl); * -EINVAL if the scancode is ambiguous or invalid, or if no * compatible encoder was found. */ -int ir_raw_encode_scancode(enum rc_type protocol, u32 scancode, +int ir_raw_encode_scancode(enum rc_proto protocol, u32 scancode, struct ir_raw_event *events, unsigned int max) { struct ir_raw_handler *handler; @@ -483,6 +471,27 @@ int ir_raw_encode_scancode(enum rc_type protocol, u32 scancode, } EXPORT_SYMBOL(ir_raw_encode_scancode); +static void edge_handle(unsigned long arg) +{ + struct rc_dev *dev = (struct rc_dev *)arg; + ktime_t interval = ktime_sub(ktime_get(), dev->raw->last_event); + + if (ktime_to_ns(interval) >= dev->timeout) { + DEFINE_IR_RAW_EVENT(ev); + + ev.timeout = true; + ev.duration = ktime_to_ns(interval); + + ir_raw_event_store(dev, &ev); + } else { + mod_timer(&dev->raw->edge_handle, + jiffies + nsecs_to_jiffies(dev->timeout - + ktime_to_ns(interval))); + } + + ir_raw_event_handle(dev); +} + /* * Used to (un)register raw event clients */ @@ -504,6 +513,8 @@ int ir_raw_event_prepare(struct rc_dev *dev) dev->raw->dev = dev; dev->change_protocol = change_protocol; + setup_timer(&dev->raw->edge_handle, edge_handle, + (unsigned long)dev); INIT_KFIFO(dev->raw->kfifo); return 0; @@ -555,6 +566,7 @@ void ir_raw_event_unregister(struct rc_dev *dev) return; kthread_stop(dev->raw->thread); + del_timer_sync(&dev->raw->edge_handle); mutex_lock(&ir_raw_handler_lock); list_del(&dev->raw->list); diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index 62195af24fbe..3822d9ebcb46 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -219,15 +219,15 @@ static int __init loop_init(void) return -ENOMEM; } - rc->input_name = "rc-core loopback device"; + rc->device_name = "rc-core loopback device"; rc->input_phys = "rc-core/virtual"; rc->input_id.bustype = BUS_VIRTUAL; rc->input_id.version = 1; rc->driver_name = DRIVER_NAME; rc->map_name = RC_MAP_EMPTY; rc->priv = &loopdev; - rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; - rc->allowed_wakeup_protocols = RC_BIT_ALL_IR_ENCODER; + rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + rc->allowed_wakeup_protocols = RC_PROTO_BIT_ALL_IR_ENCODER; rc->encode_wakeup = true; rc->timeout = 100 * 1000 * 1000; /* 100 ms */ rc->min_timeout = 1; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index a9eba0013525..981cccd6b988 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -30,8 +30,54 @@ #define IR_TAB_MAX_SIZE 8192 #define RC_DEV_MAX 256 -/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */ -#define IR_KEYPRESS_TIMEOUT 250 +static const struct { + const char *name; + unsigned int repeat_period; + unsigned int scancode_bits; +} protocols[] = { + [RC_PROTO_UNKNOWN] = { .name = "unknown", .repeat_period = 250 }, + [RC_PROTO_OTHER] = { .name = "other", .repeat_period = 250 }, + [RC_PROTO_RC5] = { .name = "rc-5", + .scancode_bits = 0x1f7f, .repeat_period = 164 }, + [RC_PROTO_RC5X_20] = { .name = "rc-5x-20", + .scancode_bits = 0x1f7f3f, .repeat_period = 164 }, + [RC_PROTO_RC5_SZ] = { .name = "rc-5-sz", + .scancode_bits = 0x2fff, .repeat_period = 164 }, + [RC_PROTO_JVC] = { .name = "jvc", + .scancode_bits = 0xffff, .repeat_period = 250 }, + [RC_PROTO_SONY12] = { .name = "sony-12", + .scancode_bits = 0x1f007f, .repeat_period = 100 }, + [RC_PROTO_SONY15] = { .name = "sony-15", + .scancode_bits = 0xff007f, .repeat_period = 100 }, + [RC_PROTO_SONY20] = { .name = "sony-20", + .scancode_bits = 0x1fff7f, .repeat_period = 100 }, + [RC_PROTO_NEC] = { .name = "nec", + .scancode_bits = 0xffff, .repeat_period = 160 }, + [RC_PROTO_NECX] = { .name = "nec-x", + .scancode_bits = 0xffffff, .repeat_period = 160 }, + [RC_PROTO_NEC32] = { .name = "nec-32", + .scancode_bits = 0xffffffff, .repeat_period = 160 }, + [RC_PROTO_SANYO] = { .name = "sanyo", + .scancode_bits = 0x1fffff, .repeat_period = 250 }, + [RC_PROTO_MCIR2_KBD] = { .name = "mcir2-kbd", + .scancode_bits = 0xffff, .repeat_period = 150 }, + [RC_PROTO_MCIR2_MSE] = { .name = "mcir2-mse", + .scancode_bits = 0x1fffff, .repeat_period = 150 }, + [RC_PROTO_RC6_0] = { .name = "rc-6-0", + .scancode_bits = 0xffff, .repeat_period = 164 }, + [RC_PROTO_RC6_6A_20] = { .name = "rc-6-6a-20", + .scancode_bits = 0xfffff, .repeat_period = 164 }, + [RC_PROTO_RC6_6A_24] = { .name = "rc-6-6a-24", + .scancode_bits = 0xffffff, .repeat_period = 164 }, + [RC_PROTO_RC6_6A_32] = { .name = "rc-6-6a-32", + .scancode_bits = 0xffffffff, .repeat_period = 164 }, + [RC_PROTO_RC6_MCE] = { .name = "rc-6-mce", + .scancode_bits = 0xffff7fff, .repeat_period = 164 }, + [RC_PROTO_SHARP] = { .name = "sharp", + .scancode_bits = 0x1fff, .repeat_period = 250 }, + [RC_PROTO_XMP] = { .name = "xmp", .repeat_period = 250 }, + [RC_PROTO_CEC] = { .name = "cec", .repeat_period = 550 }, +}; /* Used to keep track of known keymaps */ static LIST_HEAD(rc_map_list); @@ -110,10 +156,10 @@ static struct rc_map_table empty[] = { static struct rc_map_list empty_map = { .map = { - .scan = empty, - .size = ARRAY_SIZE(empty), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_EMPTY, + .scan = empty, + .size = ARRAY_SIZE(empty), + .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .name = RC_MAP_EMPTY, } }; @@ -121,7 +167,7 @@ static struct rc_map_list empty_map = { * ir_create_table() - initializes a scancode table * @rc_map: the rc_map to initialize * @name: name to assign to the table - * @rc_type: ir type to assign to the new table + * @rc_proto: ir type to assign to the new table * @size: initial size of the table * @return: zero on success or a negative error code * @@ -129,12 +175,12 @@ static struct rc_map_list empty_map = { * memory to hold at least the specified number of elements. */ static int ir_create_table(struct rc_map *rc_map, - const char *name, u64 rc_type, size_t size) + const char *name, u64 rc_proto, size_t size) { rc_map->name = kstrdup(name, GFP_KERNEL); if (!rc_map->name) return -ENOMEM; - rc_map->rc_type = rc_type; + rc_map->rc_proto = rc_proto; rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table)); rc_map->size = rc_map->alloc / sizeof(struct rc_map_table); rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL); @@ -389,7 +435,7 @@ static int ir_setkeytable(struct rc_dev *dev, int rc; rc = ir_create_table(rc_map, from->name, - from->rc_type, from->size); + from->rc_proto, from->size); if (rc) return rc; @@ -530,7 +576,7 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode) if (keycode != KEY_RESERVED) IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n", - dev->input_name, scancode, keycode); + dev->device_name, scancode, keycode); return keycode; } @@ -613,16 +659,17 @@ static void ir_timer_keyup(unsigned long cookie) void rc_repeat(struct rc_dev *dev) { unsigned long flags; + unsigned int timeout = protocols[dev->last_protocol].repeat_period; spin_lock_irqsave(&dev->keylock, flags); - input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode); - input_sync(dev->input_dev); - if (!dev->keypressed) goto out; - dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); + input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode); + input_sync(dev->input_dev); + + dev->keyup_jiffies = jiffies + msecs_to_jiffies(timeout); mod_timer(&dev->timer_keyup, dev->keyup_jiffies); out: @@ -641,7 +688,7 @@ EXPORT_SYMBOL_GPL(rc_repeat); * This function is used internally to register a keypress, it must be * called with keylock held. */ -static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol, +static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, u32 scancode, u32 keycode, u8 toggle) { bool new_event = (!dev->keypressed || @@ -663,7 +710,7 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol, dev->last_keycode = keycode; IR_dprintk(1, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", - dev->input_name, keycode, protocol, scancode); + dev->device_name, keycode, protocol, scancode); input_report_key(dev->input_dev, keycode, 1); led_trigger_event(led_feedback, LED_FULL); @@ -683,7 +730,8 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol, * This routine is used to signal that a key has been pressed on the * remote control. */ -void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle) +void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u32 scancode, + u8 toggle) { unsigned long flags; u32 keycode = rc_g_keycode_from_table(dev, scancode); @@ -692,7 +740,8 @@ void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 togg ir_do_keydown(dev, protocol, scancode, keycode, toggle); if (dev->keypressed) { - dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); + dev->keyup_jiffies = jiffies + + msecs_to_jiffies(protocols[protocol].repeat_period); mod_timer(&dev->timer_keyup, dev->keyup_jiffies); } spin_unlock_irqrestore(&dev->keylock, flags); @@ -711,7 +760,7 @@ EXPORT_SYMBOL_GPL(rc_keydown); * This routine is used to signal that a key has been pressed on the * remote control. The driver must manually call rc_keyup() at a later stage. */ -void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol, +void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol, u32 scancode, u8 toggle) { unsigned long flags; @@ -733,44 +782,28 @@ EXPORT_SYMBOL_GPL(rc_keydown_notimeout); static int rc_validate_filter(struct rc_dev *dev, struct rc_scancode_filter *filter) { - static u32 masks[] = { - [RC_TYPE_RC5] = 0x1f7f, - [RC_TYPE_RC5X_20] = 0x1f7f3f, - [RC_TYPE_RC5_SZ] = 0x2fff, - [RC_TYPE_SONY12] = 0x1f007f, - [RC_TYPE_SONY15] = 0xff007f, - [RC_TYPE_SONY20] = 0x1fff7f, - [RC_TYPE_JVC] = 0xffff, - [RC_TYPE_NEC] = 0xffff, - [RC_TYPE_NECX] = 0xffffff, - [RC_TYPE_NEC32] = 0xffffffff, - [RC_TYPE_SANYO] = 0x1fffff, - [RC_TYPE_MCIR2_KBD] = 0xffff, - [RC_TYPE_MCIR2_MSE] = 0x1fffff, - [RC_TYPE_RC6_0] = 0xffff, - [RC_TYPE_RC6_6A_20] = 0xfffff, - [RC_TYPE_RC6_6A_24] = 0xffffff, - [RC_TYPE_RC6_6A_32] = 0xffffffff, - [RC_TYPE_RC6_MCE] = 0xffff7fff, - [RC_TYPE_SHARP] = 0x1fff, - }; - u32 s = filter->data; - enum rc_type protocol = dev->wakeup_protocol; + u32 mask, s = filter->data; + enum rc_proto protocol = dev->wakeup_protocol; + + if (protocol >= ARRAY_SIZE(protocols)) + return -EINVAL; + + mask = protocols[protocol].scancode_bits; switch (protocol) { - case RC_TYPE_NECX: + case RC_PROTO_NECX: if ((((s >> 16) ^ ~(s >> 8)) & 0xff) == 0) return -EINVAL; break; - case RC_TYPE_NEC32: + case RC_PROTO_NEC32: if ((((s >> 24) ^ ~(s >> 16)) & 0xff) == 0) return -EINVAL; break; - case RC_TYPE_RC6_MCE: + case RC_PROTO_RC6_MCE: if ((s & 0xffff0000) != 0x800f0000) return -EINVAL; break; - case RC_TYPE_RC6_6A_32: + case RC_PROTO_RC6_6A_32: if ((s & 0xffff0000) == 0x800f0000) return -EINVAL; break; @@ -778,14 +811,13 @@ static int rc_validate_filter(struct rc_dev *dev, break; } - filter->data &= masks[protocol]; - filter->mask &= masks[protocol]; + filter->data &= mask; + filter->mask &= mask; /* * If we have to raw encode the IR for wakeup, we cannot have a mask */ - if (dev->encode_wakeup && - filter->mask != 0 && filter->mask != masks[protocol]) + if (dev->encode_wakeup && filter->mask != 0 && filter->mask != mask) return -EINVAL; return 0; @@ -859,30 +891,30 @@ static const struct { const char *name; const char *module_name; } proto_names[] = { - { RC_BIT_NONE, "none", NULL }, - { RC_BIT_OTHER, "other", NULL }, - { RC_BIT_UNKNOWN, "unknown", NULL }, - { RC_BIT_RC5 | - RC_BIT_RC5X_20, "rc-5", "ir-rc5-decoder" }, - { RC_BIT_NEC | - RC_BIT_NECX | - RC_BIT_NEC32, "nec", "ir-nec-decoder" }, - { RC_BIT_RC6_0 | - RC_BIT_RC6_6A_20 | - RC_BIT_RC6_6A_24 | - RC_BIT_RC6_6A_32 | - RC_BIT_RC6_MCE, "rc-6", "ir-rc6-decoder" }, - { RC_BIT_JVC, "jvc", "ir-jvc-decoder" }, - { RC_BIT_SONY12 | - RC_BIT_SONY15 | - RC_BIT_SONY20, "sony", "ir-sony-decoder" }, - { RC_BIT_RC5_SZ, "rc-5-sz", "ir-rc5-decoder" }, - { RC_BIT_SANYO, "sanyo", "ir-sanyo-decoder" }, - { RC_BIT_SHARP, "sharp", "ir-sharp-decoder" }, - { RC_BIT_MCIR2_KBD | - RC_BIT_MCIR2_MSE, "mce_kbd", "ir-mce_kbd-decoder" }, - { RC_BIT_XMP, "xmp", "ir-xmp-decoder" }, - { RC_BIT_CEC, "cec", NULL }, + { RC_PROTO_BIT_NONE, "none", NULL }, + { RC_PROTO_BIT_OTHER, "other", NULL }, + { RC_PROTO_BIT_UNKNOWN, "unknown", NULL }, + { RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC5X_20, "rc-5", "ir-rc5-decoder" }, + { RC_PROTO_BIT_NEC | + RC_PROTO_BIT_NECX | + RC_PROTO_BIT_NEC32, "nec", "ir-nec-decoder" }, + { RC_PROTO_BIT_RC6_0 | + RC_PROTO_BIT_RC6_6A_20 | + RC_PROTO_BIT_RC6_6A_24 | + RC_PROTO_BIT_RC6_6A_32 | + RC_PROTO_BIT_RC6_MCE, "rc-6", "ir-rc6-decoder" }, + { RC_PROTO_BIT_JVC, "jvc", "ir-jvc-decoder" }, + { RC_PROTO_BIT_SONY12 | + RC_PROTO_BIT_SONY15 | + RC_PROTO_BIT_SONY20, "sony", "ir-sony-decoder" }, + { RC_PROTO_BIT_RC5_SZ, "rc-5-sz", "ir-rc5-decoder" }, + { RC_PROTO_BIT_SANYO, "sanyo", "ir-sanyo-decoder" }, + { RC_PROTO_BIT_SHARP, "sharp", "ir-sharp-decoder" }, + { RC_PROTO_BIT_MCIR2_KBD | + RC_PROTO_BIT_MCIR2_MSE, "mce_kbd", "ir-mce_kbd-decoder" }, + { RC_PROTO_BIT_XMP, "xmp", "ir-xmp-decoder" }, + { RC_PROTO_BIT_CEC, "cec", NULL }, }; /** @@ -1052,8 +1084,9 @@ static void ir_raw_load_modules(u64 *protocols) int i, ret; for (i = 0; i < ARRAY_SIZE(proto_names); i++) { - if (proto_names[i].type == RC_BIT_NONE || - proto_names[i].type & (RC_BIT_OTHER | RC_BIT_UNKNOWN)) + if (proto_names[i].type == RC_PROTO_BIT_NONE || + proto_names[i].type & (RC_PROTO_BIT_OTHER | + RC_PROTO_BIT_UNKNOWN)) continue; available = ir_raw_get_allowed_protocols(); @@ -1271,7 +1304,7 @@ static ssize_t store_filter(struct device *device, * Refuse to set a filter unless a protocol is enabled * and the filter is valid for that protocol */ - if (dev->wakeup_protocol != RC_TYPE_UNKNOWN) + if (dev->wakeup_protocol != RC_PROTO_UNKNOWN) ret = rc_validate_filter(dev, &new_filter); else ret = -EINVAL; @@ -1298,40 +1331,6 @@ unlock: return (ret < 0) ? ret : len; } -/* - * This is the list of all variants of all protocols, which is used by - * the wakeup_protocols sysfs entry. In the protocols sysfs entry some - * some protocols are grouped together (e.g. nec = nec + necx + nec32). - * - * For wakeup we need to know the exact protocol variant so the hardware - * can be programmed exactly what to expect. - */ -static const char * const proto_variant_names[] = { - [RC_TYPE_UNKNOWN] = "unknown", - [RC_TYPE_OTHER] = "other", - [RC_TYPE_RC5] = "rc-5", - [RC_TYPE_RC5X_20] = "rc-5x-20", - [RC_TYPE_RC5_SZ] = "rc-5-sz", - [RC_TYPE_JVC] = "jvc", - [RC_TYPE_SONY12] = "sony-12", - [RC_TYPE_SONY15] = "sony-15", - [RC_TYPE_SONY20] = "sony-20", - [RC_TYPE_NEC] = "nec", - [RC_TYPE_NECX] = "nec-x", - [RC_TYPE_NEC32] = "nec-32", - [RC_TYPE_SANYO] = "sanyo", - [RC_TYPE_MCIR2_KBD] = "mcir2-kbd", - [RC_TYPE_MCIR2_MSE] = "mcir2-mse", - [RC_TYPE_RC6_0] = "rc-6-0", - [RC_TYPE_RC6_6A_20] = "rc-6-6a-20", - [RC_TYPE_RC6_6A_24] = "rc-6-6a-24", - [RC_TYPE_RC6_6A_32] = "rc-6-6a-32", - [RC_TYPE_RC6_MCE] = "rc-6-mce", - [RC_TYPE_SHARP] = "sharp", - [RC_TYPE_XMP] = "xmp", - [RC_TYPE_CEC] = "cec", -}; - /** * show_wakeup_protocols() - shows the wakeup IR protocol * @device: the device descriptor @@ -1352,7 +1351,7 @@ static ssize_t show_wakeup_protocols(struct device *device, { struct rc_dev *dev = to_rc_dev(device); u64 allowed; - enum rc_type enabled; + enum rc_proto enabled; char *tmp = buf; int i; @@ -1366,14 +1365,12 @@ static ssize_t show_wakeup_protocols(struct device *device, IR_dprintk(1, "%s: allowed - 0x%llx, enabled - %d\n", __func__, (long long)allowed, enabled); - for (i = 0; i < ARRAY_SIZE(proto_variant_names); i++) { + for (i = 0; i < ARRAY_SIZE(protocols); i++) { if (allowed & (1ULL << i)) { if (i == enabled) - tmp += sprintf(tmp, "[%s] ", - proto_variant_names[i]); + tmp += sprintf(tmp, "[%s] ", protocols[i].name); else - tmp += sprintf(tmp, "%s ", - proto_variant_names[i]); + tmp += sprintf(tmp, "%s ", protocols[i].name); } } @@ -1403,7 +1400,7 @@ static ssize_t store_wakeup_protocols(struct device *device, const char *buf, size_t len) { struct rc_dev *dev = to_rc_dev(device); - enum rc_type protocol; + enum rc_proto protocol; ssize_t rc; u64 allowed; int i; @@ -1413,17 +1410,17 @@ static ssize_t store_wakeup_protocols(struct device *device, allowed = dev->allowed_wakeup_protocols; if (sysfs_streq(buf, "none")) { - protocol = RC_TYPE_UNKNOWN; + protocol = RC_PROTO_UNKNOWN; } else { - for (i = 0; i < ARRAY_SIZE(proto_variant_names); i++) { + for (i = 0; i < ARRAY_SIZE(protocols); i++) { if ((allowed & (1ULL << i)) && - sysfs_streq(buf, proto_variant_names[i])) { + sysfs_streq(buf, protocols[i].name)) { protocol = i; break; } } - if (i == ARRAY_SIZE(proto_variant_names)) { + if (i == ARRAY_SIZE(protocols)) { rc = -EINVAL; goto out; } @@ -1443,7 +1440,7 @@ static ssize_t store_wakeup_protocols(struct device *device, dev->wakeup_protocol = protocol; IR_dprintk(1, "Wakeup protocol changed to %d\n", protocol); - if (protocol == RC_TYPE_RC6_MCE) + if (protocol == RC_PROTO_RC6_MCE) dev->scancode_wakeup_filter.data = 0x800f0000; else dev->scancode_wakeup_filter.data = 0; @@ -1507,7 +1504,7 @@ static struct attribute *rc_dev_protocol_attrs[] = { NULL, }; -static struct attribute_group rc_dev_protocol_attr_grp = { +static const struct attribute_group rc_dev_protocol_attr_grp = { .attrs = rc_dev_protocol_attrs, }; @@ -1517,7 +1514,7 @@ static struct attribute *rc_dev_filter_attrs[] = { NULL, }; -static struct attribute_group rc_dev_filter_attr_grp = { +static const struct attribute_group rc_dev_filter_attr_grp = { .attrs = rc_dev_filter_attrs, }; @@ -1528,7 +1525,7 @@ static struct attribute *rc_dev_wakeup_filter_attrs[] = { NULL, }; -static struct attribute_group rc_dev_wakeup_filter_attr_grp = { +static const struct attribute_group rc_dev_wakeup_filter_attr_grp = { .attrs = rc_dev_wakeup_filter_attrs, }; @@ -1624,7 +1621,7 @@ static int rc_prepare_rx_device(struct rc_dev *dev) { int rc; struct rc_map *rc_map; - u64 rc_type; + u64 rc_proto; if (!dev->map_name) return -EINVAL; @@ -1639,17 +1636,17 @@ static int rc_prepare_rx_device(struct rc_dev *dev) if (rc) return rc; - rc_type = BIT_ULL(rc_map->rc_type); + rc_proto = BIT_ULL(rc_map->rc_proto); if (dev->change_protocol) { - rc = dev->change_protocol(dev, &rc_type); + rc = dev->change_protocol(dev, &rc_proto); if (rc < 0) goto out_table; - dev->enabled_protocols = rc_type; + dev->enabled_protocols = rc_proto; } if (dev->driver_type == RC_DRIVER_IR_RAW) - ir_raw_load_modules(&rc_type); + ir_raw_load_modules(&rc_proto); set_bit(EV_KEY, dev->input_dev->evbit); set_bit(EV_REP, dev->input_dev->evbit); @@ -1663,7 +1660,7 @@ static int rc_prepare_rx_device(struct rc_dev *dev) dev->input_dev->dev.parent = &dev->dev; memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id)); dev->input_dev->phys = dev->input_phys; - dev->input_dev->name = dev->input_name; + dev->input_dev->name = dev->device_name; return 0; @@ -1759,7 +1756,7 @@ int rc_register_device(struct rc_dev *dev) path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); dev_info(&dev->dev, "%s as %s\n", - dev->input_name ?: "Unspecified device", path ?: "N/A"); + dev->device_name ?: "Unspecified device", path ?: "N/A"); kfree(path); if (dev->driver_type != RC_DRIVER_IR_RAW_TX) { diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 56d43be2756b..6784cb9fc4e7 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -951,12 +951,12 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) usb_make_path(rr3->udev, rr3->phys, sizeof(rr3->phys)); - rc->input_name = rr3->name; + rc->device_name = rr3->name; rc->input_phys = rr3->phys; usb_to_input_id(rr3->udev, &rc->input_id); rc->dev.parent = dev; rc->priv = rr3; - rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT); rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT); rc->timeout = US_TO_NS(redrat3_get_timeout(rr3)); diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c index 77d5d4cbed0a..8b66926bc16a 100644 --- a/drivers/media/rc/serial_ir.c +++ b/drivers/media/rc/serial_ir.c @@ -139,10 +139,8 @@ struct serial_ir { struct platform_device *pdev; struct timer_list timeout_timer; - unsigned int freq; + unsigned int carrier; unsigned int duty_cycle; - - unsigned int pulse_width, space_width; }; static struct serial_ir serial_ir; @@ -183,18 +181,6 @@ static void off(void) soutp(UART_MCR, hardware[type].off); } -static void init_timing_params(unsigned int new_duty_cycle, - unsigned int new_freq) -{ - serial_ir.duty_cycle = new_duty_cycle; - serial_ir.freq = new_freq; - - serial_ir.pulse_width = DIV_ROUND_CLOSEST( - new_duty_cycle * NSEC_PER_SEC, new_freq * 100l); - serial_ir.space_width = DIV_ROUND_CLOSEST( - (100l - new_duty_cycle) * NSEC_PER_SEC, new_freq * 100l); -} - static void send_pulse_irdeo(unsigned int length, ktime_t target) { long rawbits; @@ -241,13 +227,20 @@ static void send_pulse_homebrew_softcarrier(unsigned int length, ktime_t edge) * ndelay(s64) does not compile; so use s32 rather than s64. */ s32 delta; + unsigned int pulse, space; + + /* Ensure the dividend fits into 32 bit */ + pulse = DIV_ROUND_CLOSEST(serial_ir.duty_cycle * (NSEC_PER_SEC / 100), + serial_ir.carrier); + space = DIV_ROUND_CLOSEST((100 - serial_ir.duty_cycle) * + (NSEC_PER_SEC / 100), serial_ir.carrier); for (;;) { now = ktime_get(); if (ktime_compare(now, target) >= 0) break; on(); - edge = ktime_add_ns(edge, serial_ir.pulse_width); + edge = ktime_add_ns(edge, pulse); delta = ktime_to_ns(ktime_sub(edge, now)); if (delta > 0) ndelay(delta); @@ -255,7 +248,7 @@ static void send_pulse_homebrew_softcarrier(unsigned int length, ktime_t edge) off(); if (ktime_compare(now, target) >= 0) break; - edge = ktime_add_ns(edge, serial_ir.space_width); + edge = ktime_add_ns(edge, space); delta = ktime_to_ns(ktime_sub(edge, now)); if (delta > 0) ndelay(delta); @@ -513,19 +506,19 @@ static int serial_ir_probe(struct platform_device *dev) switch (type) { case IR_HOMEBREW: - rcdev->input_name = "Serial IR type home-brew"; + rcdev->device_name = "Serial IR type home-brew"; break; case IR_IRDEO: - rcdev->input_name = "Serial IR type IRdeo"; + rcdev->device_name = "Serial IR type IRdeo"; break; case IR_IRDEO_REMOTE: - rcdev->input_name = "Serial IR type IRdeo remote"; + rcdev->device_name = "Serial IR type IRdeo remote"; break; case IR_ANIMAX: - rcdev->input_name = "Serial IR type AnimaX"; + rcdev->device_name = "Serial IR type AnimaX"; break; case IR_IGOR: - rcdev->input_name = "Serial IR type IgorPlug"; + rcdev->device_name = "Serial IR type IgorPlug"; break; } @@ -537,7 +530,7 @@ static int serial_ir_probe(struct platform_device *dev) rcdev->open = serial_ir_open; rcdev->close = serial_ir_close; rcdev->dev.parent = &serial_ir.pdev->dev; - rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rcdev->driver_name = KBUILD_MODNAME; rcdev->map_name = RC_MAP_RC6_MCE; rcdev->min_timeout = 1; @@ -580,7 +573,8 @@ static int serial_ir_probe(struct platform_device *dev) return result; /* Initialize pulse/space widths */ - init_timing_params(50, 38000); + serial_ir.duty_cycle = 50; + serial_ir.carrier = 38000; /* If pin is high, then this must be an active low receiver. */ if (sense == -1) { @@ -684,7 +678,7 @@ static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, static int serial_ir_tx_duty_cycle(struct rc_dev *dev, u32 cycle) { - init_timing_params(cycle, serial_ir.freq); + serial_ir.duty_cycle = cycle; return 0; } @@ -693,7 +687,7 @@ static int serial_ir_tx_carrier(struct rc_dev *dev, u32 carrier) if (carrier > 500000 || carrier < 20000) return -EINVAL; - init_timing_params(serial_ir.duty_cycle, carrier); + serial_ir.carrier = carrier; return 0; } diff --git a/drivers/media/rc/sir_ir.c b/drivers/media/rc/sir_ir.c index 20234ba0b318..bc906fb128d5 100644 --- a/drivers/media/rc/sir_ir.c +++ b/drivers/media/rc/sir_ir.c @@ -155,7 +155,7 @@ static irqreturn_t sir_interrupt(int irq, void *dev_id) { unsigned char data; ktime_t curr_time; - static unsigned long delt; + unsigned long delt; unsigned long deltintr; unsigned long flags; int counter = 0; @@ -308,14 +308,14 @@ static int sir_ir_probe(struct platform_device *dev) if (!rcdev) return -ENOMEM; - rcdev->input_name = "SIR IrDA port"; + rcdev->device_name = "SIR IrDA port"; rcdev->input_phys = KBUILD_MODNAME "/input0"; rcdev->input_id.bustype = BUS_HOST; rcdev->input_id.vendor = 0x0001; rcdev->input_id.product = 0x0001; rcdev->input_id.version = 0x0100; rcdev->tx_ir = sir_tx_ir; - rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rcdev->driver_name = KBUILD_MODNAME; rcdev->map_name = RC_MAP_RC6_MCE; rcdev->timeout = IR_DEFAULT_TIMEOUT; diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index a08e1dd06124..a8e39c635f34 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -280,7 +280,7 @@ static int st_rc_probe(struct platform_device *pdev) else rc_dev->rx_base = rc_dev->base; - rc_dev->rstc = reset_control_get_optional(dev, NULL); + rc_dev->rstc = reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(rc_dev->rstc)) { ret = PTR_ERR(rc_dev->rstc); goto err; @@ -290,7 +290,7 @@ static int st_rc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rc_dev); st_rc_hardware_init(rc_dev); - rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; /* rx sampling rate is 10Mhz */ rdev->rx_resolution = 100; rdev->timeout = US_TO_NS(MAX_SYMB_TIME); @@ -299,7 +299,7 @@ static int st_rc_probe(struct platform_device *pdev) rdev->close = st_rc_close; rdev->driver_name = IR_ST_NAME; rdev->map_name = RC_MAP_EMPTY; - rdev->input_name = "ST Remote Control Receiver"; + rdev->device_name = "ST Remote Control Receiver"; ret = rc_register_device(rdev); if (ret < 0) diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index b09c45abb5f3..f03a174ddf9d 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -299,12 +299,12 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys)); strlcat(sz->phys, "/input0", sizeof(sz->phys)); - rdev->input_name = sz->name; + rdev->device_name = sz->name; rdev->input_phys = sz->phys; usb_to_input_id(sz->usbdev, &rdev->input_id); rdev->dev.parent = dev; rdev->priv = sz; - rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rdev->driver_name = DRIVER_NAME; rdev->map_name = RC_MAP_STREAMZAP; diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index 4b785dd775c1..97f367b446c4 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -173,7 +173,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) } /* Reset (optional) */ - ir->rst = devm_reset_control_get_optional(dev, NULL); + ir->rst = devm_reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(ir->rst)) return PTR_ERR(ir->rst); ret = reset_control_deassert(ir->rst); @@ -215,7 +215,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) } ir->rc->priv = ir; - ir->rc->input_name = SUNXI_IR_DEV; + ir->rc->device_name = SUNXI_IR_DEV; ir->rc->input_phys = "sunxi-ir/input0"; ir->rc->input_id.bustype = BUS_HOST; ir->rc->input_id.vendor = 0x0001; @@ -224,7 +224,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) ir->map_name = of_get_property(dn, "linux,rc-map-name", NULL); ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY; ir->rc->dev.parent = dev; - ir->rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; + ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; ir->rc->rx_resolution = SUNXI_IR_SAMPLE; ir->rc->timeout = MS_TO_NS(SUNXI_IR_TIMEOUT); ir->rc->driver_name = SUNXI_IR_DEV; diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c index 23be7702e2df..aafea3c5170b 100644 --- a/drivers/media/rc/ttusbir.c +++ b/drivers/media/rc/ttusbir.c @@ -309,11 +309,11 @@ static int ttusbir_probe(struct usb_interface *intf, usb_make_path(tt->udev, tt->phys, sizeof(tt->phys)); - rc->input_name = DRIVER_DESC; + rc->device_name = DRIVER_DESC; rc->input_phys = tt->phys; usb_to_input_id(tt->udev, &rc->input_id); rc->dev.parent = &intf->dev; - rc->allowed_protocols = RC_BIT_ALL_IR_DECODER; + rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rc->priv = tt; rc->driver_name = DRIVER_NAME; rc->map_name = RC_MAP_TT_1500; diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 5a4d4a611197..3ca7ab48293d 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -429,7 +429,7 @@ wbcir_irq_tx(struct wbcir_data *data) bytes[used] = byte; } - while (data->txbuf[data->txoff] == 0 && data->txoff != data->txlen) + while (data->txoff != data->txlen && data->txbuf[data->txoff] == 0) data->txoff++; if (used == 0) { @@ -697,7 +697,7 @@ wbcir_shutdown(struct pnp_dev *device) } switch (rc->wakeup_protocol) { - case RC_TYPE_RC5: + case RC_PROTO_RC5: /* Mask = 13 bits, ex toggle */ mask[0] = (mask_sc & 0x003f); mask[0] |= (mask_sc & 0x0300) >> 2; @@ -714,7 +714,7 @@ wbcir_shutdown(struct pnp_dev *device) proto = IR_PROTOCOL_RC5; break; - case RC_TYPE_NEC: + case RC_PROTO_NEC: mask[1] = bitrev8(mask_sc); mask[0] = mask[1]; mask[3] = bitrev8(mask_sc >> 8); @@ -728,7 +728,7 @@ wbcir_shutdown(struct pnp_dev *device) proto = IR_PROTOCOL_NEC; break; - case RC_TYPE_NECX: + case RC_PROTO_NECX: mask[1] = bitrev8(mask_sc); mask[0] = mask[1]; mask[2] = bitrev8(mask_sc >> 8); @@ -742,7 +742,7 @@ wbcir_shutdown(struct pnp_dev *device) proto = IR_PROTOCOL_NEC; break; - case RC_TYPE_NEC32: + case RC_PROTO_NEC32: mask[0] = bitrev8(mask_sc); mask[1] = bitrev8(mask_sc >> 8); mask[2] = bitrev8(mask_sc >> 16); @@ -756,7 +756,7 @@ wbcir_shutdown(struct pnp_dev *device) proto = IR_PROTOCOL_NEC; break; - case RC_TYPE_RC6_0: + case RC_PROTO_RC6_0: /* Command */ match[0] = wbcir_to_rc6cells(wake_sc >> 0); mask[0] = wbcir_to_rc6cells(mask_sc >> 0); @@ -779,9 +779,9 @@ wbcir_shutdown(struct pnp_dev *device) proto = IR_PROTOCOL_RC6; break; - case RC_TYPE_RC6_6A_24: - case RC_TYPE_RC6_6A_32: - case RC_TYPE_RC6_MCE: + case RC_PROTO_RC6_6A_24: + case RC_PROTO_RC6_6A_32: + case RC_PROTO_RC6_MCE: i = 0; /* Command */ @@ -800,13 +800,13 @@ wbcir_shutdown(struct pnp_dev *device) match[i] = wbcir_to_rc6cells(wake_sc >> 16); mask[i++] = wbcir_to_rc6cells(mask_sc >> 16); - if (rc->wakeup_protocol == RC_TYPE_RC6_6A_20) { + if (rc->wakeup_protocol == RC_PROTO_RC6_6A_20) { rc6_csl = 52; } else { match[i] = wbcir_to_rc6cells(wake_sc >> 20); mask[i++] = wbcir_to_rc6cells(mask_sc >> 20); - if (rc->wakeup_protocol == RC_TYPE_RC6_6A_24) { + if (rc->wakeup_protocol == RC_PROTO_RC6_6A_24) { rc6_csl = 60; } else { /* Customer range bit and bits 15 - 8 */ @@ -1068,7 +1068,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) } data->dev->driver_name = DRVNAME; - data->dev->input_name = WBCIR_NAME; + data->dev->device_name = WBCIR_NAME; data->dev->input_phys = "wbcir/cir0"; data->dev->input_id.bustype = BUS_HOST; data->dev->input_id.vendor = PCI_VENDOR_ID_WINBOND; @@ -1086,12 +1086,13 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) data->dev->timeout = IR_DEFAULT_TIMEOUT; data->dev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; data->dev->rx_resolution = US_TO_NS(2); - data->dev->allowed_protocols = RC_BIT_ALL_IR_DECODER; - data->dev->allowed_wakeup_protocols = RC_BIT_NEC | RC_BIT_NECX | - RC_BIT_NEC32 | RC_BIT_RC5 | RC_BIT_RC6_0 | - RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | - RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE; - data->dev->wakeup_protocol = RC_TYPE_RC6_MCE; + data->dev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + data->dev->allowed_wakeup_protocols = RC_PROTO_BIT_NEC | + RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32 | RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | + RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | + RC_PROTO_BIT_RC6_MCE; + data->dev->wakeup_protocol = RC_PROTO_RC6_MCE; data->dev->scancode_wakeup_filter.data = 0x800f040c; data->dev->scancode_wakeup_filter.mask = 0xffff7fff; data->dev->s_wakeup_filter = wbcir_set_wakeup_filter; diff --git a/drivers/media/rc/zx-irdec.c b/drivers/media/rc/zx-irdec.c new file mode 100644 index 000000000000..12d322ec8a29 --- /dev/null +++ b/drivers/media/rc/zx-irdec.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2017 Sanechips Technology Co., Ltd. + * Copyright 2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> + +#include <media/rc-core.h> + +#define DRIVER_NAME "zx-irdec" + +#define ZX_IR_ENABLE 0x04 +#define ZX_IREN BIT(0) +#define ZX_IR_CTRL 0x08 +#define ZX_DEGL_MASK GENMASK(21, 20) +#define ZX_DEGL_VALUE(x) (((x) << 20) & ZX_DEGL_MASK) +#define ZX_WDBEGIN_MASK GENMASK(18, 8) +#define ZX_WDBEGIN_VALUE(x) (((x) << 8) & ZX_WDBEGIN_MASK) +#define ZX_IR_INTEN 0x10 +#define ZX_IR_INTSTCLR 0x14 +#define ZX_IR_CODE 0x30 +#define ZX_IR_CNUM 0x34 +#define ZX_NECRPT BIT(16) + +struct zx_irdec { + void __iomem *base; + struct rc_dev *rcd; +}; + +static void zx_irdec_set_mask(struct zx_irdec *irdec, unsigned int reg, + u32 mask, u32 value) +{ + u32 data; + + data = readl(irdec->base + reg); + data &= ~mask; + data |= value & mask; + writel(data, irdec->base + reg); +} + +static irqreturn_t zx_irdec_irq(int irq, void *dev_id) +{ + struct zx_irdec *irdec = dev_id; + u8 address, not_address; + u8 command, not_command; + u32 rawcode, scancode; + enum rc_proto rc_proto; + + /* Clear interrupt */ + writel(1, irdec->base + ZX_IR_INTSTCLR); + + /* Check repeat frame */ + if (readl(irdec->base + ZX_IR_CNUM) & ZX_NECRPT) { + rc_repeat(irdec->rcd); + goto done; + } + + rawcode = readl(irdec->base + ZX_IR_CODE); + not_command = (rawcode >> 24) & 0xff; + command = (rawcode >> 16) & 0xff; + not_address = (rawcode >> 8) & 0xff; + address = rawcode & 0xff; + + scancode = ir_nec_bytes_to_scancode(address, not_address, + command, not_command, + &rc_proto); + rc_keydown(irdec->rcd, rc_proto, scancode, 0); + +done: + return IRQ_HANDLED; +} + +static int zx_irdec_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct zx_irdec *irdec; + struct resource *res; + struct rc_dev *rcd; + int irq; + int ret; + + irdec = devm_kzalloc(dev, sizeof(*irdec), GFP_KERNEL); + if (!irdec) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irdec->base = devm_ioremap_resource(dev, res); + if (IS_ERR(irdec->base)) + return PTR_ERR(irdec->base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + rcd = devm_rc_allocate_device(dev, RC_DRIVER_SCANCODE); + if (!rcd) { + dev_err(dev, "failed to allocate rc device\n"); + return -ENOMEM; + } + + irdec->rcd = rcd; + + rcd->priv = irdec; + rcd->input_phys = DRIVER_NAME "/input0"; + rcd->input_id.bustype = BUS_HOST; + rcd->map_name = RC_MAP_ZX_IRDEC; + rcd->allowed_protocols = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | + RC_PROTO_BIT_NEC32; + rcd->driver_name = DRIVER_NAME; + rcd->device_name = DRIVER_NAME; + + platform_set_drvdata(pdev, irdec); + + ret = devm_rc_register_device(dev, rcd); + if (ret) { + dev_err(dev, "failed to register rc device\n"); + return ret; + } + + ret = devm_request_irq(dev, irq, zx_irdec_irq, 0, NULL, irdec); + if (ret) { + dev_err(dev, "failed to request irq\n"); + return ret; + } + + /* + * Initialize deglitch level and watchdog counter beginner as + * recommended by vendor BSP code. + */ + zx_irdec_set_mask(irdec, ZX_IR_CTRL, ZX_DEGL_MASK, ZX_DEGL_VALUE(0)); + zx_irdec_set_mask(irdec, ZX_IR_CTRL, ZX_WDBEGIN_MASK, + ZX_WDBEGIN_VALUE(0x21c)); + + /* Enable interrupt */ + writel(1, irdec->base + ZX_IR_INTEN); + + /* Enable the decoder */ + zx_irdec_set_mask(irdec, ZX_IR_ENABLE, ZX_IREN, ZX_IREN); + + return 0; +} + +static int zx_irdec_remove(struct platform_device *pdev) +{ + struct zx_irdec *irdec = platform_get_drvdata(pdev); + + /* Disable the decoder */ + zx_irdec_set_mask(irdec, ZX_IR_ENABLE, ZX_IREN, 0); + + /* Disable interrupt */ + writel(0, irdec->base + ZX_IR_INTEN); + + return 0; +} + +static const struct of_device_id zx_irdec_match[] = { + { .compatible = "zte,zx296718-irdec" }, + { }, +}; +MODULE_DEVICE_TABLE(of, zx_irdec_match); + +static struct platform_driver zx_irdec_driver = { + .probe = zx_irdec_probe, + .remove = zx_irdec_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = zx_irdec_match, + }, +}; +module_platform_driver(zx_irdec_driver); + +MODULE_DESCRIPTION("ZTE ZX IR remote control driver"); +MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/tuners/fc0012.c b/drivers/media/tuners/fc0012.c index dcc323ffbde7..625ac6f51c39 100644 --- a/drivers/media/tuners/fc0012.c +++ b/drivers/media/tuners/fc0012.c @@ -351,7 +351,7 @@ static int fc0012_get_rf_strength(struct dvb_frontend *fe, u16 *strength) int ret; unsigned char tmp; int int_temp, lna_gain, int_lna, tot_agc_gain, power; - const int fc0012_lna_gain_table[] = { + static const int fc0012_lna_gain_table[] = { /* low gain */ -63, -58, -99, -73, -63, -65, -54, -60, diff --git a/drivers/media/tuners/fc0013.c b/drivers/media/tuners/fc0013.c index 91dfa770a5cc..e606118d1a9b 100644 --- a/drivers/media/tuners/fc0013.c +++ b/drivers/media/tuners/fc0013.c @@ -511,7 +511,7 @@ static int fc0013_get_rf_strength(struct dvb_frontend *fe, u16 *strength) int ret; unsigned char tmp; int int_temp, lna_gain, int_lna, tot_agc_gain, power; - const int fc0013_lna_gain_table[] = { + static const int fc0013_lna_gain_table[] = { /* low gain */ -63, -58, -99, -73, -63, -65, -54, -60, diff --git a/drivers/media/tuners/tda18271-maps.c b/drivers/media/tuners/tda18271-maps.c index 7d114677b4ca..9679804fd219 100644 --- a/drivers/media/tuners/tda18271-maps.c +++ b/drivers/media/tuners/tda18271-maps.c @@ -1182,7 +1182,7 @@ fail: /*---------------------------------------------------------------------*/ -static struct tda18271_std_map tda18271c1_std_map = { +static const struct tda18271_std_map tda18271c1_std_map = { .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ .atv_b = { .if_freq = 6750, .fm_rfn = 0, .agc_mode = 1, .std = 6, @@ -1215,7 +1215,7 @@ static struct tda18271_std_map tda18271c1_std_map = { .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ }; -static struct tda18271_std_map tda18271c2_std_map = { +static const struct tda18271_std_map tda18271c2_std_map = { .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ .atv_b = { .if_freq = 6000, .fm_rfn = 0, .agc_mode = 1, .std = 5, diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c index 3339b13dd3f5..cf44d3657f55 100644 --- a/drivers/media/tuners/tuner-simple.c +++ b/drivers/media/tuners/tuner-simple.c @@ -846,7 +846,7 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, /* This function returns the tuned frequency on success, 0 on error */ struct tuner_simple_priv *priv = fe->tuner_priv; struct tunertype *tun = priv->tun; - static struct tuner_params *t_params; + struct tuner_params *t_params; u8 config, cb; u32 div; int ret; diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 8251942bcd12..e70c9e2f3798 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -859,7 +859,7 @@ static const struct v4l2_file_operations airspy_fops = { .unlocked_ioctl = video_ioctl2, }; -static struct video_device airspy_template = { +static const struct video_device airspy_template = { .name = "AirSpy SDR", .release = video_device_release_empty, .fops = &airspy_fops, @@ -1087,7 +1087,7 @@ err_free_mem: } /* USB device ID list */ -static struct usb_device_id airspy_id_table[] = { +static const struct usb_device_id airspy_id_table[] = { { USB_DEVICE(0x1d50, 0x60a1) }, /* AirSpy */ { } }; diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c index 68c3a80ce349..ea57859aee77 100644 --- a/drivers/media/usb/as102/as102_usb_drv.c +++ b/drivers/media/usb/as102/as102_usb_drv.c @@ -33,7 +33,7 @@ static void as102_usb_stop_stream(struct as102_dev_t *dev); static int as102_open(struct inode *inode, struct file *file); static int as102_release(struct inode *inode, struct file *file); -static struct usb_device_id as102_usb_id_table[] = { +static const struct usb_device_id as102_usb_id_table[] = { { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) }, { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) }, { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) }, diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig index 78b797e0b434..70521e0b4c53 100644 --- a/drivers/media/usb/au0828/Kconfig +++ b/drivers/media/usb/au0828/Kconfig @@ -31,6 +31,7 @@ config VIDEO_AU0828_V4L2 config VIDEO_AU0828_RC bool "AU0828 Remote Controller support" depends on RC_CORE + depends on !(RC_CORE=m && VIDEO_AU0828=y) depends on VIDEO_AU0828 ---help--- Enables Remote Controller support on au0828 driver. diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 739df61cec4f..cd363a2100d4 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -628,6 +628,8 @@ static int au0828_usb_probe(struct usb_interface *interface, if (retval) { pr_err("%s() au0282_dev_register failed to register on V4L2\n", __func__); + mutex_unlock(&dev->lock); + kfree(dev); goto done; } diff --git a/drivers/media/usb/au0828/au0828-i2c.c b/drivers/media/usb/au0828/au0828-i2c.c index 42b352bb4f02..ef7d1b830ca3 100644 --- a/drivers/media/usb/au0828/au0828-i2c.c +++ b/drivers/media/usb/au0828/au0828-i2c.c @@ -329,14 +329,14 @@ static u32 au0828_functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } -static struct i2c_algorithm au0828_i2c_algo_template = { +static const struct i2c_algorithm au0828_i2c_algo_template = { .master_xfer = i2c_xfer, .functionality = au0828_functionality, }; /* ----------------------------------------------------------------------- */ -static struct i2c_adapter au0828_i2c_adap_template = { +static const struct i2c_adapter au0828_i2c_adap_template = { .name = KBUILD_MODNAME, .owner = THIS_MODULE, .algo = &au0828_i2c_algo_template, diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 9d82ec0a4b64..7996eb83a54e 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -335,7 +335,7 @@ int au0828_rc_register(struct au0828_dev *dev) usb_make_path(dev->usbdev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype = BUS_USB; rc->input_id.version = 1; @@ -343,8 +343,8 @@ int au0828_rc_register(struct au0828_dev *dev) rc->input_id.product = le16_to_cpu(dev->usbdev->descriptor.idProduct); rc->dev.parent = &dev->usbdev->dev; rc->driver_name = "au0828-input"; - rc->allowed_protocols = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 | - RC_BIT_RC5; + rc->allowed_protocols = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | + RC_PROTO_BIT_NEC32 | RC_PROTO_BIT_RC5; /* all done */ err = rc_register_device(rc); diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 2a255bd32bb3..9342402b92f7 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1740,7 +1740,7 @@ void au0828_v4l2_resume(struct au0828_dev *dev) } } -static struct v4l2_file_operations au0828_v4l_fops = { +static const struct v4l2_file_operations au0828_v4l_fops = { .owner = THIS_MODULE, .open = au0828_v4l2_open, .release = au0828_v4l2_close, diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c index 788c73803138..a8f3169e30b3 100644 --- a/drivers/media/usb/b2c2/flexcop-usb.c +++ b/drivers/media/usb/b2c2/flexcop-usb.c @@ -596,7 +596,7 @@ static void flexcop_usb_disconnect(struct usb_interface *intf) info("%s successfully deinitialized and disconnected.", DRIVER_NAME); } -static struct usb_device_id flexcop_usb_table [] = { +static const struct usb_device_id flexcop_usb_table[] = { { USB_DEVICE(0x0af7, 0x0101) }, { } }; diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index 1c7e16e5d88b..6089036049d9 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -60,7 +60,7 @@ static int submit_urbs(struct camera_data *cam); static int set_alternate(struct camera_data *cam, unsigned int alt); static int configure_transfer_mode(struct camera_data *cam, unsigned int alt); -static struct usb_device_id cpia2_id_table[] = { +static const struct usb_device_id cpia2_id_table[] = { {USB_DEVICE(0x0553, 0x0100)}, {USB_DEVICE(0x0553, 0x0140)}, {USB_DEVICE(0x0553, 0x0151)}, /* STV0676 */ diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c index 7122023e7004..3dedd83f0b19 100644 --- a/drivers/media/usb/cpia2/cpia2_v4l.c +++ b/drivers/media/usb/cpia2/cpia2_v4l.c @@ -1075,7 +1075,7 @@ static const struct v4l2_file_operations cpia2_fops = { .mmap = cpia2_mmap, }; -static struct video_device cpia2_template = { +static const struct video_device cpia2_template = { /* I could not find any place for the old .initialize initializer?? */ .name = "CPiA2 Camera", .fops = &cpia2_fops, diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 509d9711d590..d538fa407742 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1490,7 +1490,7 @@ static void bb_buf_release(struct videobuf_queue *q, free_buffer(q, buf); } -static struct videobuf_queue_ops cx231xx_qops = { +static const struct videobuf_queue_ops cx231xx_qops = { .buf_setup = bb_buf_setup, .buf_prepare = bb_buf_prepare, .buf_queue = bb_buf_queue, @@ -1843,7 +1843,7 @@ static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) return videobuf_mmap_mapper(&fh->vidq, vma); } -static struct v4l2_file_operations mpeg_fops = { +static const struct v4l2_file_operations mpeg_fops = { .owner = THIS_MODULE, .open = mpeg_open, .release = mpeg_release, diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index a050d125934c..06f10d7fc4b0 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c @@ -403,7 +403,7 @@ static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, return 0; } -static struct snd_pcm_hardware snd_cx231xx_hw_capture = { +static const struct snd_pcm_hardware snd_cx231xx_hw_capture = { .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 46646ecd2dbc..f372ad3917a8 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -1311,6 +1311,7 @@ int cx231xx_dev_init(struct cx231xx *dev) dev->i2c_bus[0].i2c_period = I2C_SPEED_100K; /* 100 KHz */ dev->i2c_bus[0].i2c_nostop = 0; dev->i2c_bus[0].i2c_reserve = 0; + dev->i2c_bus[0].i2c_rc = -ENODEV; /* External Master 2 Bus */ dev->i2c_bus[1].nr = 1; @@ -1318,6 +1319,7 @@ int cx231xx_dev_init(struct cx231xx *dev) dev->i2c_bus[1].i2c_period = I2C_SPEED_100K; /* 100 KHz */ dev->i2c_bus[1].i2c_nostop = 0; dev->i2c_bus[1].i2c_reserve = 0; + dev->i2c_bus[1].i2c_rc = -ENODEV; /* Internal Master 3 Bus */ dev->i2c_bus[2].nr = 2; @@ -1325,6 +1327,7 @@ int cx231xx_dev_init(struct cx231xx *dev) dev->i2c_bus[2].i2c_period = I2C_SPEED_100K; /* 100kHz */ dev->i2c_bus[2].i2c_nostop = 0; dev->i2c_bus[2].i2c_reserve = 0; + dev->i2c_bus[2].i2c_rc = -ENODEV; /* register I2C buses */ errCode = cx231xx_i2c_register(&dev->i2c_bus[0]); diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index ee3eeeb600f8..c18bb33e060e 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -585,6 +585,9 @@ static void unregister_dvb(struct cx231xx_dvb *dvb) dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); dvb_dmxdev_release(&dvb->dmxdev); dvb_dmx_release(&dvb->demux); + dvb_unregister_frontend(dvb->frontend); + dvb_frontend_detach(dvb->frontend); + dvb_unregister_adapter(&dvb->adapter); /* remove I2C tuner */ client = dvb->i2c_client_tuner; if (client) { @@ -597,9 +600,6 @@ static void unregister_dvb(struct cx231xx_dvb *dvb) module_put(client->dev.driver->owner); i2c_unregister_device(client); } - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); } static int dvb_init(struct cx231xx *dev) diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c index 8d95b1154e12..23648dab7be8 100644 --- a/drivers/media/usb/cx231xx/cx231xx-i2c.c +++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c @@ -459,7 +459,7 @@ static const struct i2c_algorithm cx231xx_algo = { .functionality = functionality, }; -static struct i2c_adapter cx231xx_adap_template = { +static const struct i2c_adapter cx231xx_adap_template = { .owner = THIS_MODULE, .name = "cx231xx", .algo = &cx231xx_algo, @@ -538,7 +538,7 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus) bus->i2c_adap.algo_data = bus; i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); - i2c_add_adapter(&bus->i2c_adap); + bus->i2c_rc = i2c_add_adapter(&bus->i2c_adap); if (0 != bus->i2c_rc) dev_warn(dev->dev, @@ -551,10 +551,10 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus) * cx231xx_i2c_unregister() * unregister i2c_bus */ -int cx231xx_i2c_unregister(struct cx231xx_i2c *bus) +void cx231xx_i2c_unregister(struct cx231xx_i2c *bus) { - i2c_del_adapter(&bus->i2c_adap); - return 0; + if (!bus->i2c_rc) + i2c_del_adapter(&bus->i2c_adap); } /* diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c index eecf074b0a48..02ebeb16055f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-input.c +++ b/drivers/media/usb/cx231xx/cx231xx-input.c @@ -24,7 +24,7 @@ #define MODULE_NAME "cx231xx-input" -static int get_key_isdbt(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_isdbt(struct IR_i2c *ir, enum rc_proto *protocol, u32 *pscancode, u8 *toggle) { int rc; @@ -50,7 +50,7 @@ static int get_key_isdbt(struct IR_i2c *ir, enum rc_type *protocol, dev_dbg(&ir->rc->dev, "cmd %02x, scan = %02x\n", cmd, scancode); - *protocol = RC_TYPE_OTHER; + *protocol = RC_PROTO_OTHER; *pscancode = scancode; *toggle = 0; return 1; @@ -91,7 +91,7 @@ int cx231xx_ir_init(struct cx231xx *dev) /* The i2c micro-controller only outputs the cmd part of NEC protocol */ dev->init_data.rc_dev->scancode_mask = 0xff; dev->init_data.rc_dev->driver_name = "cx231xx"; - dev->init_data.type = RC_BIT_NEC; + dev->init_data.type = RC_PROTO_BIT_NEC; info.addr = 0x30; /* Load and bind ir-kbd-i2c */ diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index f67f86876625..179b8481a870 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -859,7 +859,7 @@ static void buffer_release(struct videobuf_queue *vq, free_buffer(vq, buf); } -static struct videobuf_queue_ops cx231xx_video_qops = { +static const struct videobuf_queue_ops cx231xx_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 986c64ba5b56..72d5937a087e 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -476,7 +476,7 @@ struct cx231xx_i2c { /* i2c i/o */ struct i2c_adapter i2c_adap; - u32 i2c_rc; + int i2c_rc; /* different settings for each bus */ u8 i2c_period; @@ -762,7 +762,7 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev); /* Provided by cx231xx-i2c.c */ void cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port); int cx231xx_i2c_register(struct cx231xx_i2c *bus); -int cx231xx_i2c_unregister(struct cx231xx_i2c *bus); +void cx231xx_i2c_unregister(struct cx231xx_i2c *bus); int cx231xx_i2c_mux_create(struct cx231xx *dev); int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no); void cx231xx_i2c_mux_unregister(struct cx231xx *dev); diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 23bbbf367b51..8013659c41b1 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -1237,7 +1237,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) /* Only process key if canary killed */ if (buf[16] != 0xff && buf[0] != 0x01) { - enum rc_type proto; + enum rc_proto proto; dev_dbg(&d->udev->dev, "%s: key pressed %*ph\n", __func__, 4, buf + 12); @@ -1253,13 +1253,13 @@ static int af9015_rc_query(struct dvb_usb_device *d) /* NEC */ state->rc_keycode = RC_SCANCODE_NEC(buf[12], buf[14]); - proto = RC_TYPE_NEC; + proto = RC_PROTO_NEC; } else { /* NEC extended*/ state->rc_keycode = RC_SCANCODE_NECX(buf[12] << 8 | buf[13], buf[14]); - proto = RC_TYPE_NECX; + proto = RC_PROTO_NECX; } } else { /* 32 bit NEC */ @@ -1267,7 +1267,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) buf[13] << 16 | buf[14] << 8 | buf[15]); - proto = RC_TYPE_NEC32; + proto = RC_PROTO_NEC32; } rc_keydown(d->rc_dev, proto, state->rc_keycode, 0); } else { @@ -1336,7 +1336,8 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) if (!rc->map_name) rc->map_name = RC_MAP_EMPTY; - rc->allowed_protos = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32; + rc->allowed_protos = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | + RC_PROTO_BIT_NEC32; rc->query = af9015_rc_query; rc->interval = 500; diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 4df9486e19b9..666d319d3d1a 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1828,7 +1828,7 @@ static int af9035_rc_query(struct dvb_usb_device *d) { struct usb_interface *intf = d->intf; int ret; - enum rc_type proto; + enum rc_proto proto; u32 key; u8 buf[4]; struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, buf }; @@ -1843,17 +1843,17 @@ static int af9035_rc_query(struct dvb_usb_device *d) if ((buf[0] + buf[1]) == 0xff) { /* NEC standard 16bit */ key = RC_SCANCODE_NEC(buf[0], buf[2]); - proto = RC_TYPE_NEC; + proto = RC_PROTO_NEC; } else { /* NEC extended 24bit */ key = RC_SCANCODE_NECX(buf[0] << 8 | buf[1], buf[2]); - proto = RC_TYPE_NECX; + proto = RC_PROTO_NECX; } } else { /* NEC full code 32bit */ key = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]); - proto = RC_TYPE_NEC32; + proto = RC_PROTO_NEC32; } dev_dbg(&intf->dev, "%*ph\n", 4, buf); @@ -1881,11 +1881,11 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) switch (state->ir_type) { case 0: /* NEC */ default: - rc->allowed_protos = RC_BIT_NEC | RC_BIT_NECX | - RC_BIT_NEC32; + rc->allowed_protos = RC_PROTO_BIT_NEC | + RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32; break; case 1: /* RC6 */ - rc->allowed_protos = RC_BIT_RC6_MCE; + rc->allowed_protos = RC_PROTO_BIT_RC6_MCE; break; } @@ -2108,6 +2108,8 @@ static const struct usb_device_id af9035_id_table[] = { { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2, &af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2", RC_MAP_IT913X_V1) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T1, + &af9035_props, "TerraTec T1", RC_MAP_IT913X_V1) }, /* XXX: that same ID [0ccd:0099] is used by af9015 driver too */ { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099, &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index 6795c0c609b1..20ee7eea2a91 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -1142,7 +1142,7 @@ static int anysee_rc_query(struct dvb_usb_device *d) if (ircode[0]) { dev_dbg(&d->udev->dev, "%s: key pressed %02x\n", __func__, ircode[1]); - rc_keydown(d->rc_dev, RC_TYPE_NEC, + rc_keydown(d->rc_dev, RC_PROTO_NEC, RC_SCANCODE_NEC(0x08, ircode[1]), 0); } @@ -1151,7 +1151,7 @@ static int anysee_rc_query(struct dvb_usb_device *d) static int anysee_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { - rc->allowed_protos = RC_BIT_NEC; + rc->allowed_protos = RC_PROTO_BIT_NEC; rc->query = anysee_rc_query; rc->interval = 250; /* windows driver uses 500ms */ diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c index 50c07fe7dacb..1414d59e85ba 100644 --- a/drivers/media/usb/dvb-usb-v2/az6007.c +++ b/drivers/media/usb/dvb-usb-v2/az6007.c @@ -208,7 +208,7 @@ static int az6007_rc_query(struct dvb_usb_device *d) { struct az6007_device_state *st = d_to_priv(d); unsigned code; - enum rc_type proto; + enum rc_proto proto; az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10); @@ -218,18 +218,18 @@ static int az6007_rc_query(struct dvb_usb_device *d) if ((st->data[3] ^ st->data[4]) == 0xff) { if ((st->data[1] ^ st->data[2]) == 0xff) { code = RC_SCANCODE_NEC(st->data[1], st->data[3]); - proto = RC_TYPE_NEC; + proto = RC_PROTO_NEC; } else { code = RC_SCANCODE_NECX(st->data[1] << 8 | st->data[2], st->data[3]); - proto = RC_TYPE_NECX; + proto = RC_PROTO_NECX; } } else { code = RC_SCANCODE_NEC32(st->data[1] << 24 | st->data[2] << 16 | st->data[3] << 8 | st->data[4]); - proto = RC_TYPE_NEC32; + proto = RC_PROTO_NEC32; } rc_keydown(d->rc_dev, proto, code, st->data[5]); @@ -241,7 +241,8 @@ static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { pr_debug("Getting az6007 Remote Control properties\n"); - rc->allowed_protos = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32; + rc->allowed_protos = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | + RC_PROTO_BIT_NEC32; rc->query = az6007_rc_query; rc->interval = 400; @@ -933,7 +934,7 @@ static struct dvb_usb_device_properties az6007_cablestar_hdci_props = { } }; -static struct usb_device_id az6007_usb_table[] = { +static const struct usb_device_id az6007_usb_table[] = { {DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007, &az6007_props, "Azurewave 6007", RC_MAP_EMPTY)}, {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7, diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 35f27e2e4e28..0005bdb2207d 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -138,7 +138,7 @@ struct dvb_usb_driver_info { struct dvb_usb_rc { const char *map_name; u64 allowed_protos; - int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); + int (*change_protocol)(struct rc_dev *dev, u64 *rc_proto); int (*query) (struct dvb_usb_device *d); unsigned int interval; enum rc_driver_type driver_type; diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 955fb0d07507..096bb75a24e5 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -154,13 +154,12 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) } dev->dev.parent = &d->udev->dev; - dev->input_name = d->name; + dev->device_name = d->name; usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); dev->input_phys = d->rc_phys; usb_to_input_id(d->udev, &dev->input_id); - /* TODO: likely RC-core should took const char * */ - dev->driver_name = (char *) d->props->driver_name; + dev->driver_name = d->props->driver_name; dev->map_name = d->rc.map_name; dev->allowed_protocols = d->rc.allowed_protos; dev->change_protocol = d->rc.change_protocol; diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index 5730760e4e93..131b6c08e199 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -211,7 +211,7 @@ static int dvbsky_rc_query(struct dvb_usb_device *d) rc5_system = (code & 0x7C0) >> 6; toggle = (code & 0x800) ? 1 : 0; scancode = rc5_system << 8 | rc5_command; - rc_keydown(d->rc_dev, RC_TYPE_RC5, scancode, toggle); + rc_keydown(d->rc_dev, RC_PROTO_RC5, scancode, toggle); } return 0; } @@ -223,7 +223,7 @@ static int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) return 0; } - rc->allowed_protos = RC_BIT_RC5; + rc->allowed_protos = RC_PROTO_BIT_RC5; rc->query = dvbsky_rc_query; rc->interval = 300; return 0; diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index a91fdad8f8d4..5e320fa4a795 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -347,8 +347,8 @@ static void lme2510_int_response(struct urb *lme_urb) ibuf[5]); deb_info(1, "INT Key = 0x%08x", key); - rc_keydown(adap_to_d(adap)->rc_dev, RC_TYPE_NEC32, key, - 0); + rc_keydown(adap_to_d(adap)->rc_dev, RC_PROTO_NEC32, key, + 0); break; case 0xbb: switch (st->tuner_config) { @@ -1232,7 +1232,7 @@ static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, static int lme2510_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { - rc->allowed_protos = RC_BIT_NEC32; + rc->allowed_protos = RC_PROTO_BIT_NEC32; return 0; } diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index b0d5904a4ea6..67953360fda5 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -77,7 +77,9 @@ int mxl111sf_ctrl_msg(struct mxl111sf_state *state, dvb_usbv2_generic_rw(d, state->sndbuf, 1+wlen, state->rcvbuf, rlen); - memcpy(rbuf, state->rcvbuf, rlen); + if (rbuf) + memcpy(rbuf, state->rcvbuf, rlen); + mutex_unlock(&state->msg_lock); mxl_fail(ret); diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index e16ca07acf1d..95a7b9123f8e 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -1631,24 +1631,24 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d) goto err; if (buf[4] & 0x01) { - enum rc_type proto; + enum rc_proto proto; if (buf[2] == (u8) ~buf[3]) { if (buf[0] == (u8) ~buf[1]) { /* NEC standard (16 bit) */ rc_code = RC_SCANCODE_NEC(buf[0], buf[2]); - proto = RC_TYPE_NEC; + proto = RC_PROTO_NEC; } else { /* NEC extended (24 bit) */ rc_code = RC_SCANCODE_NECX(buf[0] << 8 | buf[1], buf[2]); - proto = RC_TYPE_NECX; + proto = RC_PROTO_NECX; } } else { /* NEC full (32 bit) */ rc_code = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]); - proto = RC_TYPE_NEC32; + proto = RC_PROTO_NEC32; } rc_keydown(d->rc_dev, proto, rc_code, 0); @@ -1673,7 +1673,8 @@ static int rtl2831u_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { rc->map_name = RC_MAP_EMPTY; - rc->allowed_protos = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32; + rc->allowed_protos = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | + RC_PROTO_BIT_NEC32; rc->query = rtl2831u_rc_query; rc->interval = 400; @@ -1778,7 +1779,7 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d, /* load empty to enable rc */ if (!rc->map_name) rc->map_name = RC_MAP_EMPTY; - rc->allowed_protos = RC_BIT_ALL_IR_DECODER; + rc->allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; rc->driver_type = RC_DRIVER_IR_RAW; rc->query = rtl2832u_rc_query; rc->interval = 200; diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 99a3f3625944..37dea0adc695 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -458,7 +458,7 @@ static int cxusb_rc_query(struct dvb_usb_device *d) cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4); if (ircode[2] || ircode[3]) - rc_keydown(d->rc_dev, RC_TYPE_NEC, + rc_keydown(d->rc_dev, RC_PROTO_NEC, RC_SCANCODE_NEC(~ircode[2] & 0xff, ircode[3]), 0); return 0; } @@ -473,7 +473,7 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d) return 0; if (ircode[1] || ircode[2]) - rc_keydown(d->rc_dev, RC_TYPE_NEC, + rc_keydown(d->rc_dev, RC_PROTO_NEC, RC_SCANCODE_NEC(~ircode[1] & 0xff, ircode[2]), 0); return 0; } @@ -486,7 +486,7 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d) return 0; if (ircode[0] || ircode[1]) - rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, + rc_keydown(d->rc_dev, RC_PROTO_UNKNOWN, RC_SCANCODE_RC5(ircode[0], ircode[1]), 0); return 0; } @@ -1646,7 +1646,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { .rc_codes = RC_MAP_DVICO_PORTABLE, .module_name = KBUILD_MODNAME, .rc_query = cxusb_rc_query, - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, }, .generic_bulk_ctrl_endpoint = 0x01, @@ -1703,7 +1703,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { .rc_codes = RC_MAP_DVICO_MCE, .module_name = KBUILD_MODNAME, .rc_query = cxusb_rc_query, - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, }, .generic_bulk_ctrl_endpoint = 0x01, @@ -1768,7 +1768,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { .rc_codes = RC_MAP_DVICO_PORTABLE, .module_name = KBUILD_MODNAME, .rc_query = cxusb_rc_query, - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, }, .generic_bulk_ctrl_endpoint = 0x01, @@ -1824,7 +1824,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { .rc_codes = RC_MAP_DVICO_PORTABLE, .module_name = KBUILD_MODNAME, .rc_query = cxusb_rc_query, - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, }, .generic_bulk_ctrl_endpoint = 0x01, @@ -1879,7 +1879,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { .rc_codes = RC_MAP_DVICO_MCE, .module_name = KBUILD_MODNAME, .rc_query = cxusb_bluebird2_rc_query, - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, }, .num_device_descs = 1, @@ -1933,7 +1933,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { .rc_codes = RC_MAP_DVICO_PORTABLE, .module_name = KBUILD_MODNAME, .rc_query = cxusb_bluebird2_rc_query, - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, }, .num_device_descs = 1, @@ -1989,7 +1989,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope .rc_codes = RC_MAP_DVICO_PORTABLE, .module_name = KBUILD_MODNAME, .rc_query = cxusb_rc_query, - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, }, .num_device_descs = 1, @@ -2088,7 +2088,7 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { .rc_codes = RC_MAP_DVICO_MCE, .module_name = KBUILD_MODNAME, .rc_query = cxusb_rc_query, - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, }, .num_device_descs = 1, @@ -2142,7 +2142,7 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { .rc_codes = RC_MAP_D680_DMB, .module_name = KBUILD_MODNAME, .rc_query = cxusb_d680_dmb_rc_query, - .allowed_protos = RC_BIT_UNKNOWN, + .allowed_protos = RC_PROTO_BIT_UNKNOWN, }, .num_device_descs = 1, @@ -2197,7 +2197,7 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = { .rc_codes = RC_MAP_D680_DMB, .module_name = KBUILD_MODNAME, .rc_query = cxusb_d680_dmb_rc_query, - .allowed_protos = RC_BIT_UNKNOWN, + .allowed_protos = RC_PROTO_BIT_UNKNOWN, }, .num_device_descs = 1, @@ -2251,7 +2251,7 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = { .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02, .module_name = KBUILD_MODNAME, .rc_query = cxusb_d680_dmb_rc_query, - .allowed_protos = RC_BIT_UNKNOWN, + .allowed_protos = RC_PROTO_BIT_UNKNOWN, }, .num_device_descs = 1, @@ -2305,7 +2305,7 @@ static struct dvb_usb_device_properties cxusb_mygica_t230c_properties = { .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02, .module_name = KBUILD_MODNAME, .rc_query = cxusb_d680_dmb_rc_query, - .allowed_protos = RC_BIT_UNKNOWN, + .allowed_protos = RC_PROTO_BIT_UNKNOWN, }, .num_device_descs = 1, diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h index 8fd8f5b489d2..f89ab3b5a6c4 100644 --- a/drivers/media/usb/dvb-usb/dib0700.h +++ b/drivers/media/usb/dvb-usb/dib0700.h @@ -64,7 +64,7 @@ extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); extern struct i2c_algorithm dib0700_i2c_algo; extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, int *cold); -extern int dib0700_change_protocol(struct rc_dev *dev, u64 *rc_type); +extern int dib0700_change_protocol(struct rc_dev *dev, u64 *rc_proto); extern int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz); extern int dib0700_device_count; diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c index bea1b4764a66..1ee7ec558293 100644 --- a/drivers/media/usb/dvb-usb/dib0700_core.c +++ b/drivers/media/usb/dvb-usb/dib0700_core.c @@ -638,7 +638,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return ret; } -int dib0700_change_protocol(struct rc_dev *rc, u64 *rc_type) +int dib0700_change_protocol(struct rc_dev *rc, u64 *rc_proto) { struct dvb_usb_device *d = rc->priv; struct dib0700_state *st = d->priv; @@ -654,19 +654,19 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 *rc_type) st->buf[2] = 0; /* Set the IR mode */ - if (*rc_type & RC_BIT_RC5) { + if (*rc_proto & RC_PROTO_BIT_RC5) { new_proto = 1; - *rc_type = RC_BIT_RC5; - } else if (*rc_type & RC_BIT_NEC) { + *rc_proto = RC_PROTO_BIT_RC5; + } else if (*rc_proto & RC_PROTO_BIT_NEC) { new_proto = 0; - *rc_type = RC_BIT_NEC; - } else if (*rc_type & RC_BIT_RC6_MCE) { + *rc_proto = RC_PROTO_BIT_NEC; + } else if (*rc_proto & RC_PROTO_BIT_RC6_MCE) { if (st->fw_version < 0x10200) { ret = -EINVAL; goto out; } new_proto = 2; - *rc_type = RC_BIT_RC6_MCE; + *rc_proto = RC_PROTO_BIT_RC6_MCE; } else { ret = -EINVAL; goto out; @@ -680,7 +680,7 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 *rc_type) goto out; } - d->props.rc.core.protocol = *rc_type; + d->props.rc.core.protocol = *rc_proto; out: mutex_unlock(&d->usb_mutex); @@ -712,7 +712,7 @@ static void dib0700_rc_urb_completion(struct urb *purb) { struct dvb_usb_device *d = purb->context; struct dib0700_rc_response *poll_reply; - enum rc_type protocol; + enum rc_proto protocol; u32 keycode; u8 toggle; @@ -745,7 +745,7 @@ static void dib0700_rc_urb_completion(struct urb *purb) purb->actual_length); switch (d->props.rc.core.protocol) { - case RC_BIT_NEC: + case RC_PROTO_BIT_NEC: toggle = 0; /* NEC protocol sends repeat code as 0 0 0 FF */ @@ -764,25 +764,25 @@ static void dib0700_rc_urb_completion(struct urb *purb) poll_reply->nec.not_system << 16 | poll_reply->nec.data << 8 | poll_reply->nec.not_data); - protocol = RC_TYPE_NEC32; + protocol = RC_PROTO_NEC32; } else if ((poll_reply->nec.system ^ poll_reply->nec.not_system) != 0xff) { deb_data("NEC extended protocol\n"); keycode = RC_SCANCODE_NECX(poll_reply->nec.system << 8 | poll_reply->nec.not_system, poll_reply->nec.data); - protocol = RC_TYPE_NECX; + protocol = RC_PROTO_NECX; } else { deb_data("NEC normal protocol\n"); keycode = RC_SCANCODE_NEC(poll_reply->nec.system, poll_reply->nec.data); - protocol = RC_TYPE_NEC; + protocol = RC_PROTO_NEC; } break; default: deb_data("RC5 protocol\n"); - protocol = RC_TYPE_RC5; + protocol = RC_PROTO_RC5; toggle = poll_reply->report_id; keycode = RC_SCANCODE_RC5(poll_reply->rc5.system, poll_reply->rc5.data); diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 6a57fc6d3472..6020170fe99a 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -514,7 +514,7 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) */ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d) { - enum rc_type protocol; + enum rc_proto protocol; u32 scancode; u8 toggle; int i; @@ -547,7 +547,7 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d) dib0700_rc_setup(d, NULL); /* reset ir sensor data to prevent false events */ switch (d->props.rc.core.protocol) { - case RC_BIT_NEC: + case RC_PROTO_BIT_NEC: /* NEC protocol sends repeat code as 0 0 0 FF */ if ((st->buf[3 - 2] == 0x00) && (st->buf[3 - 3] == 0x00) && (st->buf[3] == 0xff)) { @@ -555,14 +555,14 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d) return 0; } - protocol = RC_TYPE_NEC; + protocol = RC_PROTO_NEC; scancode = RC_SCANCODE_NEC(st->buf[3 - 2], st->buf[3 - 3]); toggle = 0; break; default: /* RC-5 protocol changes toggle bit on new keypress */ - protocol = RC_TYPE_RC5; + protocol = RC_PROTO_RC5; scancode = RC_SCANCODE_RC5(st->buf[3 - 2], st->buf[3 - 3]); toggle = st->buf[3 - 1]; break; @@ -3909,9 +3909,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -3949,9 +3949,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4014,9 +4014,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4059,9 +4059,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4140,9 +4140,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4185,9 +4185,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4242,9 +4242,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4308,9 +4308,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4357,9 +4357,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_NEC_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4430,9 +4430,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4466,9 +4466,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4542,9 +4542,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4586,9 +4586,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_NEC_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4635,9 +4635,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4672,9 +4672,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4709,9 +4709,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4746,9 +4746,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4783,9 +4783,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4820,9 +4820,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4871,9 +4871,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4906,9 +4906,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4943,9 +4943,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4981,9 +4981,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -5035,9 +5035,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, diff --git a/drivers/media/usb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c index fcbff7fb0c4e..512370786696 100644 --- a/drivers/media/usb/dvb-usb/dtt200u.c +++ b/drivers/media/usb/dvb-usb/dtt200u.c @@ -100,14 +100,14 @@ static int dtt200u_rc_query(struct dvb_usb_device *d) goto ret; if (st->data[0] == 1) { - enum rc_type proto = RC_TYPE_NEC; + enum rc_proto proto = RC_PROTO_NEC; scancode = st->data[1]; if ((u8) ~st->data[1] != st->data[2]) { /* Extended NEC */ scancode = scancode << 8; scancode |= st->data[2]; - proto = RC_TYPE_NECX; + proto = RC_PROTO_NECX; } scancode = scancode << 8; scancode |= st->data[3]; @@ -213,7 +213,7 @@ static struct dvb_usb_device_properties dtt200u_properties = { .rc_interval = 300, .rc_codes = RC_MAP_DTT200U, .rc_query = dtt200u_rc_query, - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, }, .generic_bulk_ctrl_endpoint = 0x01, @@ -265,7 +265,7 @@ static struct dvb_usb_device_properties wt220u_properties = { .rc_interval = 300, .rc_codes = RC_MAP_DTT200U, .rc_query = dtt200u_rc_query, - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, }, .generic_bulk_ctrl_endpoint = 0x01, @@ -317,7 +317,7 @@ static struct dvb_usb_device_properties wt220u_fc_properties = { .rc_interval = 300, .rc_codes = RC_MAP_DTT200U, .rc_query = dtt200u_rc_query, - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, }, .generic_bulk_ctrl_endpoint = 0x01, @@ -369,7 +369,7 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = { .rc_interval = 300, .rc_codes = RC_MAP_DTT200U, .rc_query = dtt200u_rc_query, - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, }, .generic_bulk_ctrl_endpoint = 0x01, diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c index f05f1fc80729..0b03f9bd9c26 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c @@ -279,7 +279,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) dev->change_protocol = d->props.rc.core.change_protocol; dev->allowed_protocols = d->props.rc.core.allowed_protos; usb_to_input_id(d->udev, &dev->input_id); - dev->input_name = "IR-receiver inside an USB DVB receiver"; + dev->device_name = "IR-receiver inside an USB DVB receiver"; dev->input_phys = d->rc_phys; dev->dev.parent = &d->udev->dev; dev->priv = d; diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h index 67f898b6f6d0..72468fdffa18 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb.h +++ b/drivers/media/usb/dvb-usb/dvb-usb.h @@ -202,7 +202,7 @@ struct dvb_rc { u64 protocol; u64 allowed_protos; enum rc_driver_type driver_type; - int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); + int (*change_protocol)(struct rc_dev *dev, u64 *rc_proto); char *module_name; int (*rc_query) (struct dvb_usb_device *d); int rc_interval; diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 57b187240110..b421329b21fa 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -1671,7 +1671,7 @@ static int dw2102_rc_query(struct dvb_usb_device *d) if (msg.buf[0] != 0xff) { deb_rc("%s: rc code: %x, %x\n", __func__, key[0], key[1]); - rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, key[0], 0); + rc_keydown(d->rc_dev, RC_PROTO_UNKNOWN, key[0], 0); } } @@ -1692,7 +1692,8 @@ static int prof_rc_query(struct dvb_usb_device *d) if (msg.buf[0] != 0xff) { deb_rc("%s: rc code: %x, %x\n", __func__, key[0], key[1]); - rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, key[0]^0xff, 0); + rc_keydown(d->rc_dev, RC_PROTO_UNKNOWN, key[0] ^ 0xff, + 0); } } @@ -1713,7 +1714,7 @@ static int su3000_rc_query(struct dvb_usb_device *d) if (msg.buf[0] != 0xff) { deb_rc("%s: rc code: %x, %x\n", __func__, key[0], key[1]); - rc_keydown(d->rc_dev, RC_TYPE_RC5, + rc_keydown(d->rc_dev, RC_PROTO_RC5, RC_SCANCODE_RC5(key[1], key[0]), 0); } } @@ -1912,7 +1913,7 @@ static struct dvb_usb_device_properties dw2102_properties = { .rc_interval = 150, .rc_codes = RC_MAP_DM1105_NEC, .module_name = "dw2102", - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, .rc_query = dw2102_rc_query, }, @@ -1967,7 +1968,7 @@ static struct dvb_usb_device_properties dw2104_properties = { .rc_interval = 150, .rc_codes = RC_MAP_DM1105_NEC, .module_name = "dw2102", - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, .rc_query = dw2102_rc_query, }, @@ -2018,7 +2019,7 @@ static struct dvb_usb_device_properties dw3101_properties = { .rc_interval = 150, .rc_codes = RC_MAP_DM1105_NEC, .module_name = "dw2102", - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, .rc_query = dw2102_rc_query, }, @@ -2067,7 +2068,7 @@ static struct dvb_usb_device_properties s6x0_properties = { .rc_interval = 150, .rc_codes = RC_MAP_TEVII_NEC, .module_name = "dw2102", - .allowed_protos = RC_BIT_NEC, + .allowed_protos = RC_PROTO_BIT_NEC, .rc_query = dw2102_rc_query, }, @@ -2103,46 +2104,46 @@ static struct dvb_usb_device_properties s6x0_properties = { }; static struct dvb_usb_device_properties *p1100; -static struct dvb_usb_device_description d1100 = { +static const struct dvb_usb_device_description d1100 = { "Prof 1100 USB ", {&dw2102_table[PROF_1100], NULL}, {NULL}, }; static struct dvb_usb_device_properties *s660; -static struct dvb_usb_device_description d660 = { +static const struct dvb_usb_device_description d660 = { "TeVii S660 USB", {&dw2102_table[TEVII_S660], NULL}, {NULL}, }; -static struct dvb_usb_device_description d480_1 = { +static const struct dvb_usb_device_description d480_1 = { "TeVii S480.1 USB", {&dw2102_table[TEVII_S480_1], NULL}, {NULL}, }; -static struct dvb_usb_device_description d480_2 = { +static const struct dvb_usb_device_description d480_2 = { "TeVii S480.2 USB", {&dw2102_table[TEVII_S480_2], NULL}, {NULL}, }; static struct dvb_usb_device_properties *p7500; -static struct dvb_usb_device_description d7500 = { +static const struct dvb_usb_device_description d7500 = { "Prof 7500 USB DVB-S2", {&dw2102_table[PROF_7500], NULL}, {NULL}, }; static struct dvb_usb_device_properties *s421; -static struct dvb_usb_device_description d421 = { +static const struct dvb_usb_device_description d421 = { "TeVii S421 PCI", {&dw2102_table[TEVII_S421], NULL}, {NULL}, }; -static struct dvb_usb_device_description d632 = { +static const struct dvb_usb_device_description d632 = { "TeVii S632 USB", {&dw2102_table[TEVII_S632], NULL}, {NULL}, @@ -2161,7 +2162,7 @@ static struct dvb_usb_device_properties su3000_properties = { .rc_interval = 150, .rc_codes = RC_MAP_SU3000, .module_name = "dw2102", - .allowed_protos = RC_BIT_RC5, + .allowed_protos = RC_PROTO_BIT_RC5, .rc_query = su3000_rc_query, }, @@ -2230,7 +2231,7 @@ static struct dvb_usb_device_properties t220_properties = { .rc_interval = 150, .rc_codes = RC_MAP_SU3000, .module_name = "dw2102", - .allowed_protos = RC_BIT_RC5, + .allowed_protos = RC_PROTO_BIT_RC5, .rc_query = su3000_rc_query, }, @@ -2279,7 +2280,7 @@ static struct dvb_usb_device_properties tt_s2_4600_properties = { .rc_interval = 250, .rc_codes = RC_MAP_TT_1500, .module_name = "dw2102", - .allowed_protos = RC_BIT_RC5, + .allowed_protos = RC_PROTO_BIT_RC5, .rc_query = su3000_rc_query, }, @@ -2334,10 +2335,12 @@ static struct dvb_usb_device_properties tt_s2_4600_properties = { static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { + int retval = -ENOMEM; p1100 = kmemdup(&s6x0_properties, sizeof(struct dvb_usb_device_properties), GFP_KERNEL); if (!p1100) - return -ENOMEM; + goto err0; + /* copy default structure */ /* fill only different fields */ p1100->firmware = P1100_FIRMWARE; @@ -2348,10 +2351,9 @@ static int dw2102_probe(struct usb_interface *intf, s660 = kmemdup(&s6x0_properties, sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!s660) { - kfree(p1100); - return -ENOMEM; - } + if (!s660) + goto err1; + s660->firmware = S660_FIRMWARE; s660->num_device_descs = 3; s660->devices[0] = d660; @@ -2361,11 +2363,9 @@ static int dw2102_probe(struct usb_interface *intf, p7500 = kmemdup(&s6x0_properties, sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!p7500) { - kfree(p1100); - kfree(s660); - return -ENOMEM; - } + if (!p7500) + goto err2; + p7500->firmware = P7500_FIRMWARE; p7500->devices[0] = d7500; p7500->rc.core.rc_query = prof_rc_query; @@ -2375,12 +2375,9 @@ static int dw2102_probe(struct usb_interface *intf, s421 = kmemdup(&su3000_properties, sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!s421) { - kfree(p1100); - kfree(s660); - kfree(p7500); - return -ENOMEM; - } + if (!s421) + goto err3; + s421->num_device_descs = 2; s421->devices[0] = d421; s421->devices[1] = d632; @@ -2410,7 +2407,16 @@ static int dw2102_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr)) return 0; - return -ENODEV; + retval = -ENODEV; + kfree(s421); +err3: + kfree(p7500); +err2: + kfree(s660); +err1: + kfree(p1100); +err0: + return retval; } static void dw2102_disconnect(struct usb_interface *intf) diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index 70672e1e5ec7..32081c2ce0da 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -241,7 +241,7 @@ static int m920x_rc_core_query(struct dvb_usb_device *d) else if (state == REMOTE_KEY_REPEAT) rc_repeat(d->rc_dev); else - rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, rc_state[1], 0); + rc_keydown(d->rc_dev, RC_PROTO_UNKNOWN, rc_state[1], 0); out: kfree(rc_state); @@ -1208,7 +1208,7 @@ static struct dvb_usb_device_properties vp7049_properties = { .rc_interval = 150, .rc_codes = RC_MAP_TWINHAN_VP1027_DVBS, .rc_query = m920x_rc_core_query, - .allowed_protos = RC_BIT_UNKNOWN, + .allowed_protos = RC_PROTO_BIT_UNKNOWN, }, .size_of_priv = sizeof(struct m920x_state), diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c index d54ebe7e0215..601ade7ca48d 100644 --- a/drivers/media/usb/dvb-usb/pctv452e.c +++ b/drivers/media/usb/dvb-usb/pctv452e.c @@ -600,7 +600,7 @@ static int pctv452e_rc_query(struct dvb_usb_device *d) info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[6], rx[7]); - rc_keydown(d->rc_dev, RC_TYPE_RC5, state->last_rc_key, 0); + rc_keydown(d->rc_dev, RC_PROTO_RC5, state->last_rc_key, 0); } else if (state->last_rc_key) { rc_keyup(d->rc_dev); state->last_rc_key = 0; @@ -958,7 +958,7 @@ static struct dvb_usb_device_properties pctv452e_properties = { .rc.core = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .allowed_protos = RC_BIT_RC5, + .allowed_protos = RC_PROTO_BIT_RC5, .rc_query = pctv452e_rc_query, .rc_interval = 100, }, @@ -1011,7 +1011,7 @@ static struct dvb_usb_device_properties tt_connect_s2_3600_properties = { .rc.core = { .rc_codes = RC_MAP_TT_1500, - .allowed_protos = RC_BIT_RC5, + .allowed_protos = RC_PROTO_BIT_RC5, .rc_query = pctv452e_rc_query, .rc_interval = 100, }, diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index 9f7dd1afcb15..18d0f8f5283f 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -749,7 +749,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = { .rc_codes = RC_MAP_TECHNISAT_USB2, .module_name = "technisat-usb2", .rc_query = technisat_usb2_rc_query, - .allowed_protos = RC_BIT_ALL_IR_DECODER, + .allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER, .driver_type = RC_DRIVER_IR_RAW, } }; diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c index 9e0d6a4166d2..e7020f245f53 100644 --- a/drivers/media/usb/dvb-usb/ttusb2.c +++ b/drivers/media/usb/dvb-usb/ttusb2.c @@ -459,7 +459,7 @@ static int tt3650_rc_query(struct dvb_usb_device *d) /* got a "press" event */ st->last_rc_key = RC_SCANCODE_RC5(rx[3], rx[2]); deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]); - rc_keydown(d->rc_dev, RC_TYPE_RC5, st->last_rc_key, rx[1]); + rc_keydown(d->rc_dev, RC_PROTO_RC5, st->last_rc_key, rx[1]); } else if (st->last_rc_key) { rc_keyup(d->rc_dev); st->last_rc_key = 0; @@ -766,7 +766,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { .rc_interval = 150, /* Less than IR_KEYPRESS_TIMEOUT */ .rc_codes = RC_MAP_TT_1500, .rc_query = tt3650_rc_query, - .allowed_protos = RC_BIT_RC5, + .allowed_protos = RC_PROTO_BIT_RC5, }, .num_adapters = 1, diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index ffad7f1af166..4628d73f46f2 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -216,7 +216,7 @@ static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, return 0; } -static struct snd_pcm_hardware snd_em28xx_hw_capture = { +static const struct snd_pcm_hardware snd_em28xx_hw_capture = { .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -564,7 +564,7 @@ static int em28xx_vol_get(struct snd_kcontrol *kcontrol, val, (int)kcontrol->private_value); value->value.integer.value[0] = 0x1f - (val & 0x1f); - value->value.integer.value[1] = 0x1f - ((val << 8) & 0x1f); + value->value.integer.value[1] = 0x1f - ((val >> 8) & 0x1f); return 0; } diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 60b195c157b8..66c5012a628a 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -876,7 +876,7 @@ static const struct i2c_algorithm em28xx_algo = { .functionality = functionality, }; -static struct i2c_adapter em28xx_adap_template = { +static const struct i2c_adapter em28xx_adap_template = { .owner = THIS_MODULE, .name = "em28xx", .algo = &em28xx_algo, diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index ca9673917ad5..046223de1e91 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -55,7 +55,7 @@ struct em28xx_ir_poll_result { unsigned int toggle_bit:1; unsigned int read_count:7; - enum rc_type protocol; + enum rc_proto protocol; u32 scancode; }; @@ -70,11 +70,12 @@ struct em28xx_IR { struct delayed_work work; unsigned int full_code:1; unsigned int last_readcount; - u64 rc_type; + u64 rc_proto; struct i2c_client *i2c_client; - int (*get_key_i2c)(struct i2c_client *ir, enum rc_type *protocol, u32 *scancode); + int (*get_key_i2c)(struct i2c_client *ir, enum rc_proto *protocol, + u32 *scancode); int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); }; @@ -83,7 +84,7 @@ struct em28xx_IR { **********************************************************/ static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, - enum rc_type *protocol, u32 *scancode) + enum rc_proto *protocol, u32 *scancode) { unsigned char b; @@ -101,13 +102,13 @@ static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, /* keep old data */ return 1; - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = b; return 1; } static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev, - enum rc_type *protocol, u32 *scancode) + enum rc_proto *protocol, u32 *scancode) { unsigned char buf[2]; int size; @@ -131,13 +132,14 @@ static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev, * So, the code translation is not complete. Yet, it is enough to * work with the provided RC5 IR. */ - *protocol = RC_TYPE_RC5; + *protocol = RC_PROTO_RC5; *scancode = (bitrev8(buf[1]) & 0x1f) << 8 | bitrev8(buf[0]) >> 2; return 1; } static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev, - enum rc_type *protocol, u32 *scancode) + enum rc_proto *protocol, + u32 *scancode) { unsigned char buf[3]; @@ -149,13 +151,14 @@ static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev, if (buf[0] != 0x00) return 0; - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = buf[2] & 0x3f; return 1; } static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev, - enum rc_type *protocol, u32 *scancode) + enum rc_proto *protocol, + u32 *scancode) { unsigned char subaddr, keydetect, key; @@ -175,7 +178,7 @@ static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev, if (key == 0x00) return 0; - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = key; return 1; } @@ -207,19 +210,19 @@ static int default_polling_getkey(struct em28xx_IR *ir, poll_result->read_count = (msg[0] & 0x7f); /* Remote Control Address/Data (Regs 0x46/0x47) */ - switch (ir->rc_type) { - case RC_BIT_RC5: - poll_result->protocol = RC_TYPE_RC5; + switch (ir->rc_proto) { + case RC_PROTO_BIT_RC5: + poll_result->protocol = RC_PROTO_RC5; poll_result->scancode = RC_SCANCODE_RC5(msg[1], msg[2]); break; - case RC_BIT_NEC: - poll_result->protocol = RC_TYPE_NEC; + case RC_PROTO_BIT_NEC: + poll_result->protocol = RC_PROTO_NEC; poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[2]); break; default: - poll_result->protocol = RC_TYPE_UNKNOWN; + poll_result->protocol = RC_PROTO_UNKNOWN; poll_result->scancode = msg[1] << 8 | msg[2]; break; } @@ -252,37 +255,37 @@ static int em2874_polling_getkey(struct em28xx_IR *ir, * Remote Control Address (Reg 0x52) * Remote Control Data (Reg 0x53-0x55) */ - switch (ir->rc_type) { - case RC_BIT_RC5: - poll_result->protocol = RC_TYPE_RC5; + switch (ir->rc_proto) { + case RC_PROTO_BIT_RC5: + poll_result->protocol = RC_PROTO_RC5; poll_result->scancode = RC_SCANCODE_RC5(msg[1], msg[2]); break; - case RC_BIT_NEC: + case RC_PROTO_BIT_NEC: poll_result->scancode = msg[1] << 8 | msg[2]; if ((msg[3] ^ msg[4]) != 0xff) { /* 32 bits NEC */ - poll_result->protocol = RC_TYPE_NEC32; + poll_result->protocol = RC_PROTO_NEC32; poll_result->scancode = RC_SCANCODE_NEC32((msg[1] << 24) | (msg[2] << 16) | (msg[3] << 8) | (msg[4])); } else if ((msg[1] ^ msg[2]) != 0xff) { /* 24 bits NEC */ - poll_result->protocol = RC_TYPE_NECX; + poll_result->protocol = RC_PROTO_NECX; poll_result->scancode = RC_SCANCODE_NECX(msg[1] << 8 | msg[2], msg[3]); } else { /* Normal NEC */ - poll_result->protocol = RC_TYPE_NEC; + poll_result->protocol = RC_PROTO_NEC; poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[3]); } break; - case RC_BIT_RC6_0: - poll_result->protocol = RC_TYPE_RC6_0; + case RC_PROTO_BIT_RC6_0: + poll_result->protocol = RC_PROTO_RC6_0; poll_result->scancode = RC_SCANCODE_RC6_0(msg[1], msg[2]); break; default: - poll_result->protocol = RC_TYPE_UNKNOWN; + poll_result->protocol = RC_PROTO_UNKNOWN; poll_result->scancode = (msg[1] << 24) | (msg[2] << 16) | (msg[3] << 8) | msg[4]; break; @@ -298,7 +301,7 @@ static int em2874_polling_getkey(struct em28xx_IR *ir, static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir) { static u32 scancode; - enum rc_type protocol; + enum rc_proto protocol; int rc; rc = ir->get_key_i2c(ir->i2c_client, &protocol, &scancode); @@ -338,7 +341,7 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir) poll_result.toggle_bit); else rc_keydown(ir->rc, - RC_TYPE_UNKNOWN, + RC_PROTO_UNKNOWN, poll_result.scancode & 0xff, poll_result.toggle_bit); @@ -383,70 +386,71 @@ static void em28xx_ir_stop(struct rc_dev *rc) cancel_delayed_work_sync(&ir->work); } -static int em2860_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type) +static int em2860_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_proto) { struct em28xx_IR *ir = rc_dev->priv; struct em28xx *dev = ir->dev; /* Adjust xclk based on IR table for RC5/NEC tables */ - if (*rc_type & RC_BIT_RC5) { + if (*rc_proto & RC_PROTO_BIT_RC5) { dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE; ir->full_code = 1; - *rc_type = RC_BIT_RC5; - } else if (*rc_type & RC_BIT_NEC) { + *rc_proto = RC_PROTO_BIT_RC5; + } else if (*rc_proto & RC_PROTO_BIT_NEC) { dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE; ir->full_code = 1; - *rc_type = RC_BIT_NEC; - } else if (*rc_type & RC_BIT_UNKNOWN) { - *rc_type = RC_BIT_UNKNOWN; + *rc_proto = RC_PROTO_BIT_NEC; + } else if (*rc_proto & RC_PROTO_BIT_UNKNOWN) { + *rc_proto = RC_PROTO_BIT_UNKNOWN; } else { - *rc_type = ir->rc_type; + *rc_proto = ir->rc_proto; return -EINVAL; } em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk, EM28XX_XCLK_IR_RC5_MODE); - ir->rc_type = *rc_type; + ir->rc_proto = *rc_proto; return 0; } -static int em2874_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type) +static int em2874_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_proto) { struct em28xx_IR *ir = rc_dev->priv; struct em28xx *dev = ir->dev; u8 ir_config = EM2874_IR_RC5; /* Adjust xclk and set type based on IR table for RC5/NEC/RC6 tables */ - if (*rc_type & RC_BIT_RC5) { + if (*rc_proto & RC_PROTO_BIT_RC5) { dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE; ir->full_code = 1; - *rc_type = RC_BIT_RC5; - } else if (*rc_type & RC_BIT_NEC) { + *rc_proto = RC_PROTO_BIT_RC5; + } else if (*rc_proto & RC_PROTO_BIT_NEC) { dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE; ir_config = EM2874_IR_NEC | EM2874_IR_NEC_NO_PARITY; ir->full_code = 1; - *rc_type = RC_BIT_NEC; - } else if (*rc_type & RC_BIT_RC6_0) { + *rc_proto = RC_PROTO_BIT_NEC; + } else if (*rc_proto & RC_PROTO_BIT_RC6_0) { dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE; ir_config = EM2874_IR_RC6_MODE_0; ir->full_code = 1; - *rc_type = RC_BIT_RC6_0; - } else if (*rc_type & RC_BIT_UNKNOWN) { - *rc_type = RC_BIT_UNKNOWN; + *rc_proto = RC_PROTO_BIT_RC6_0; + } else if (*rc_proto & RC_PROTO_BIT_UNKNOWN) { + *rc_proto = RC_PROTO_BIT_UNKNOWN; } else { - *rc_type = ir->rc_type; + *rc_proto = ir->rc_proto; return -EINVAL; } em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk, EM28XX_XCLK_IR_RC5_MODE); - ir->rc_type = *rc_type; + ir->rc_proto = *rc_proto; return 0; } -static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type) + +static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_proto) { struct em28xx_IR *ir = rc_dev->priv; struct em28xx *dev = ir->dev; @@ -455,12 +459,12 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type) switch (dev->chip_id) { case CHIP_ID_EM2860: case CHIP_ID_EM2883: - return em2860_ir_change_protocol(rc_dev, rc_type); + return em2860_ir_change_protocol(rc_dev, rc_proto); case CHIP_ID_EM2884: case CHIP_ID_EM2874: case CHIP_ID_EM28174: case CHIP_ID_EM28178: - return em2874_ir_change_protocol(rc_dev, rc_type); + return em2874_ir_change_protocol(rc_dev, rc_proto); default: dev_err(&ir->dev->intf->dev, "Unrecognized em28xx chip id 0x%02x: IR not supported\n", @@ -686,7 +690,7 @@ static int em28xx_ir_init(struct em28xx *dev) struct em28xx_IR *ir; struct rc_dev *rc; int err = -ENOMEM; - u64 rc_type; + u64 rc_proto; u16 i2c_rc_dev_addr = 0; if (dev->is_audio_only) { @@ -749,7 +753,7 @@ static int em28xx_ir_init(struct em28xx *dev) case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: rc->map_name = RC_MAP_HAUPPAUGE; ir->get_key_i2c = em28xx_get_key_em_haup; - rc->allowed_protocols = RC_BIT_RC5; + rc->allowed_protocols = RC_PROTO_BIT_RC5; break; case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE: rc->map_name = RC_MAP_WINFAST_USBII_DELUXE; @@ -771,7 +775,8 @@ static int em28xx_ir_init(struct em28xx *dev) switch (dev->chip_id) { case CHIP_ID_EM2860: case CHIP_ID_EM2883: - rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC; + rc->allowed_protocols = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_NEC; ir->get_key = default_polling_getkey; break; case CHIP_ID_EM2884: @@ -779,8 +784,9 @@ static int em28xx_ir_init(struct em28xx *dev) case CHIP_ID_EM28174: case CHIP_ID_EM28178: ir->get_key = em2874_polling_getkey; - rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC | - RC_BIT_NECX | RC_BIT_NEC32 | RC_BIT_RC6_0; + rc->allowed_protocols = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | + RC_PROTO_BIT_NEC32 | RC_PROTO_BIT_RC6_0; break; default: err = -ENODEV; @@ -791,8 +797,8 @@ static int em28xx_ir_init(struct em28xx *dev) rc->map_name = dev->board.ir_codes; /* By default, keep protocol field untouched */ - rc_type = RC_BIT_UNKNOWN; - err = em28xx_ir_change_protocol(rc, &rc_type); + rc_proto = RC_PROTO_BIT_UNKNOWN; + err = em28xx_ir_change_protocol(rc, &rc_proto); if (err) goto error; } @@ -807,7 +813,7 @@ static int em28xx_ir_init(struct em28xx *dev) usb_make_path(udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype = BUS_USB; rc->input_id.version = 1; diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index ed5ec9773969..98cd57eaf36a 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -857,7 +857,7 @@ static int go7007_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static struct v4l2_file_operations go7007_fops = { +static const struct v4l2_file_operations go7007_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vb2_fop_release, @@ -901,7 +901,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static struct video_device go7007_template = { +static const struct video_device go7007_template = { .name = "go7007", .fops = &go7007_fops, .release = video_device_release_empty, diff --git a/drivers/media/usb/go7007/snd-go7007.c b/drivers/media/usb/go7007/snd-go7007.c index 070871fb1fc4..c618764480c6 100644 --- a/drivers/media/usb/go7007/snd-go7007.c +++ b/drivers/media/usb/go7007/snd-go7007.c @@ -52,7 +52,7 @@ struct go7007_snd { int capturing; }; -static struct snd_pcm_hardware go7007_snd_capture_hw = { +static const struct snd_pcm_hardware go7007_snd_capture_hw = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 16bc1dde2c8c..0f141762abf1 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1964,7 +1964,7 @@ out: return ret; } -static struct v4l2_file_operations dev_fops = { +static const struct v4l2_file_operations dev_fops = { .owner = THIS_MODULE, .open = dev_open, .release = dev_close, diff --git a/drivers/media/usb/gspca/xirlink_cit.c b/drivers/media/usb/gspca/xirlink_cit.c index b600ea6460d3..68656e7986c7 100644 --- a/drivers/media/usb/gspca/xirlink_cit.c +++ b/drivers/media/usb/gspca/xirlink_cit.c @@ -1315,7 +1315,7 @@ static int cit_set_sharpness(struct gspca_dev *gspca_dev, s32 val) break; case CIT_MODEL1: { int i; - const unsigned short sa[] = { + static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a }; for (i = 0; i < cit_model1_ntries; i++) diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index d9a525260511..7eb53517a82f 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -1263,7 +1263,7 @@ static const struct v4l2_file_operations hackrf_fops = { .unlocked_ioctl = video_ioctl2, }; -static struct video_device hackrf_template = { +static const struct video_device hackrf_template = { .name = "HackRF One", .release = video_device_release_empty, .fops = &hackrf_fops, @@ -1545,7 +1545,7 @@ err: } /* USB device ID list */ -static struct usb_device_id hackrf_id_table[] = { +static const struct usb_device_id hackrf_id_table[] = { { USB_DEVICE(0x1d50, 0x6089) }, /* HackRF One */ { } }; diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 15f016ad5b89..dbe29c6c4d8b 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -53,7 +53,7 @@ MODULE_PARM_DESC(boost_audio, "boost the audio signal"); /* table of devices that work with this driver */ -static struct usb_device_id hdpvr_table[] = { +static const struct usb_device_id hdpvr_table[] = { { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID) }, { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID1) }, { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID2) }, diff --git a/drivers/media/usb/hdpvr/hdpvr-i2c.c b/drivers/media/usb/hdpvr/hdpvr-i2c.c index fcab55038d99..1db49ed5eaf1 100644 --- a/drivers/media/usb/hdpvr/hdpvr-i2c.c +++ b/drivers/media/usb/hdpvr/hdpvr-i2c.c @@ -55,7 +55,8 @@ struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev) /* Our default information for ir-kbd-i2c.c to use */ init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_BIT_RC5 | RC_BIT_RC6_MCE | RC_BIT_RC6_6A_32; + init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_RC6_6A_32; init_data->name = "HD-PVR"; init_data->polling_interval = 405; /* ms, duplicated from Windows */ hdpvr_ir_rx_i2c_board_info.platform_data = init_data; @@ -184,7 +185,7 @@ static const struct i2c_algorithm hdpvr_algo = { .functionality = hdpvr_functionality, }; -static struct i2c_adapter hdpvr_i2c_adapter_template = { +static const struct i2c_adapter hdpvr_i2c_adapter_template = { .name = "Hauppage HD PVR I2C", .owner = THIS_MODULE, .algo = &hdpvr_algo, diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index bb3d31e2a0b5..a097d3dbc141 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -1143,7 +1143,7 @@ static const struct v4l2_file_operations msi2500_fops = { .unlocked_ioctl = video_ioctl2, }; -static struct video_device msi2500_template = { +static const struct video_device msi2500_template = { .name = "Mirics MSi3101 SDR Dongle", .release = video_device_release_empty, .fops = &msi2500_fops, @@ -1308,7 +1308,7 @@ err: } /* USB device ID list */ -static struct usb_device_id msi2500_id_table[] = { +static const struct usb_device_id msi2500_id_table[] = { {USB_DEVICE(0x1df7, 0x2500)}, /* Mirics MSi3101 SDR Dongle */ {USB_DEVICE(0x2040, 0xd300)}, /* Hauppauge WinTV 133559 LF */ {} diff --git a/drivers/media/usb/pulse8-cec/pulse8-cec.c b/drivers/media/usb/pulse8-cec/pulse8-cec.c index f9ed9c950247..50146f263d90 100644 --- a/drivers/media/usb/pulse8-cec/pulse8-cec.c +++ b/drivers/media/usb/pulse8-cec/pulse8-cec.c @@ -642,8 +642,7 @@ static const struct cec_adap_ops pulse8_cec_adap_ops = { static int pulse8_connect(struct serio *serio, struct serio_driver *drv) { - u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | CEC_CAP_PHYS_ADDR | - CEC_CAP_PASSTHROUGH | CEC_CAP_RC | CEC_CAP_MONITOR_ALL; + u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | CEC_CAP_MONITOR_ALL; struct pulse8 *pulse8; int err = -ENOMEM; struct cec_log_addrs log_addrs = {}; @@ -656,7 +655,7 @@ static int pulse8_connect(struct serio *serio, struct serio_driver *drv) pulse8->serio = serio; pulse8->adap = cec_allocate_adapter(&pulse8_cec_adap_ops, pulse8, - "HDMI CEC", caps, 1); + dev_name(&serio->dev), caps, 1); err = PTR_ERR_OR_ZERO(pulse8->adap); if (err < 0) goto free_device; @@ -732,7 +731,7 @@ static void pulse8_ping_eeprom_work_handler(struct work_struct *work) mutex_unlock(&pulse8->config_lock); } -static struct serio_device_id pulse8_serio_ids[] = { +static const struct serio_device_id pulse8_serio_ids[] = { { .type = SERIO_RS232, .proto = SERIO_PULSE8_CEC, diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c index ca637074fa1f..43e43404095f 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c @@ -198,7 +198,7 @@ static int pvr2_encoder_cmd(void *ctxt, } - LOCK_TAKE(hdw->ctl_lock); do { + LOCK_TAKE(hdw->ctl_lock); while (1) { if (!hdw->state_encoder_ok) { ret = -EIO; @@ -293,9 +293,9 @@ rdData[0]); wrData[0] = 0x0; ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1); - if (ret) break; + break; - } while(0); LOCK_GIVE(hdw->ctl_lock); + }; LOCK_GIVE(hdw->ctl_lock); return ret; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c index 20a52b785fff..ff7b4d1d385d 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c @@ -514,12 +514,12 @@ static u32 pvr2_i2c_functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } -static struct i2c_algorithm pvr2_i2c_algo_template = { +static const struct i2c_algorithm pvr2_i2c_algo_template = { .master_xfer = pvr2_i2c_xfer, .functionality = pvr2_i2c_functionality, }; -static struct i2c_adapter pvr2_i2c_adap_template = { +static const struct i2c_adapter pvr2_i2c_adap_template = { .owner = THIS_MODULE, .class = 0, }; @@ -567,7 +567,7 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) case PVR2_IR_SCHEME_29XXX: /* Original 29xxx device */ init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; - init_data->type = RC_BIT_RC5; + init_data->type = RC_PROTO_BIT_RC5; init_data->name = hdw->hdw_desc->description; init_data->polling_interval = 100; /* ms From ir-kbd-i2c */ /* IR Receiver */ @@ -580,11 +580,11 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) break; case PVR2_IR_SCHEME_ZILOG: /* HVR-1950 style */ case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */ - init_data->ir_codes = RC_MAP_HAUPPAUGE; + init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_BIT_RC5 | RC_BIT_RC6_MCE | - RC_BIT_RC6_6A_32; - init_data->name = hdw->hdw_desc->description; + init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_RC6_6A_32; + init_data->name = hdw->hdw_desc->description; /* IR Receiver */ info.addr = 0x71; info.platform_data = init_data; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 8f13c60198ed..4320bda9352d 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -1226,7 +1226,7 @@ static const struct v4l2_file_operations vdev_fops = { }; -static struct video_device vdev_template = { +static const struct video_device vdev_template = { .fops = &vdev_fops, }; diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 22420c14ac98..eb6921d2743e 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -146,7 +146,7 @@ static const struct v4l2_file_operations pwc_fops = { .mmap = vb2_fop_mmap, .unlocked_ioctl = video_ioctl2, }; -static struct video_device pwc_template = { +static const struct video_device pwc_template = { .name = "Philips Webcam", /* Filled in later */ .release = video_device_release_empty, .fops = &pwc_fops, diff --git a/drivers/media/usb/rainshadow-cec/rainshadow-cec.c b/drivers/media/usb/rainshadow-cec/rainshadow-cec.c index 65692576690f..cecdcbcd400c 100644 --- a/drivers/media/usb/rainshadow-cec/rainshadow-cec.c +++ b/drivers/media/usb/rainshadow-cec/rainshadow-cec.c @@ -309,8 +309,7 @@ static const struct cec_adap_ops rain_cec_adap_ops = { static int rain_connect(struct serio *serio, struct serio_driver *drv) { - u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | CEC_CAP_PHYS_ADDR | - CEC_CAP_PASSTHROUGH | CEC_CAP_RC | CEC_CAP_MONITOR_ALL; + u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | CEC_CAP_MONITOR_ALL; struct rain *rain; int err = -ENOMEM; struct cec_log_addrs log_addrs = {}; @@ -323,7 +322,7 @@ static int rain_connect(struct serio *serio, struct serio_driver *drv) rain->serio = serio; rain->adap = cec_allocate_adapter(&rain_cec_adap_ops, rain, - "HDMI CEC", caps, 1); + dev_name(&serio->dev), caps, 1); err = PTR_ERR_OR_ZERO(rain->adap); if (err < 0) goto free_device; @@ -359,7 +358,7 @@ free_device: return err; } -static struct serio_device_id rain_serio_ids[] = { +static const struct serio_device_id rain_serio_ids[] = { { .type = SERIO_RS232, .proto = SERIO_RAINSHADOW_CEC, diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 6a88b1dbb3a0..b2f239c4ba42 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -381,7 +381,7 @@ MODULE_PARM_DESC(jpeg_enable, "Jpeg enable(1-on 0-off) default 1"); /* USB device table */ #define USB_SENSORAY_VID 0x1943 -static struct usb_device_id s2255_table[] = { +static const struct usb_device_id s2255_table[] = { {USB_DEVICE(USB_SENSORAY_VID, 0x2255)}, {USB_DEVICE(USB_SENSORAY_VID, 0x2257)}, /*same family as 2255*/ { } /* Terminating entry */ @@ -1590,7 +1590,7 @@ static void s2255_video_device_release(struct video_device *vdev) return; } -static struct video_device template = { +static const struct video_device template = { .name = "s2255v", .fops = &s2255_fops_v4l, .ioctl_ops = &s2255_ioctl_ops, diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index c86eb6164713..bea8bbbb84fb 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -47,7 +47,7 @@ MODULE_AUTHOR("Ezequiel Garcia"); MODULE_DESCRIPTION("STK1160 driver"); /* Devices supported by this driver */ -static struct usb_device_id stk1160_id_table[] = { +static const struct usb_device_id stk1160_id_table[] = { { USB_DEVICE(0x05e1, 0x0408) }, { } }; diff --git a/drivers/media/usb/stk1160/stk1160-i2c.c b/drivers/media/usb/stk1160/stk1160-i2c.c index 3f2517be02bb..2c70173e3c82 100644 --- a/drivers/media/usb/stk1160/stk1160-i2c.c +++ b/drivers/media/usb/stk1160/stk1160-i2c.c @@ -240,7 +240,7 @@ static const struct i2c_algorithm algo = { .functionality = functionality, }; -static struct i2c_adapter adap_template = { +static const struct i2c_adapter adap_template = { .owner = THIS_MODULE, .name = "stk1160", .algo = &algo, diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index a005d262392a..77b759a0bcd9 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -326,7 +326,7 @@ static int stk1160_stop_streaming(struct stk1160 *dev) return 0; } -static struct v4l2_file_operations stk1160_fops = { +static const struct v4l2_file_operations stk1160_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vb2_fop_release, @@ -751,7 +751,7 @@ static const struct vb2_ops stk1160_video_qops = { .wait_finish = vb2_ops_wait_finish, }; -static struct video_device v4l_template = { +static const struct video_device v4l_template = { .name = "stk1160", .tvnorms = V4L2_STD_525_60 | V4L2_STD_625_50, .fops = &stk1160_fops, diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 90d4a08cda31..c0bba773db25 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -55,7 +55,7 @@ MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay@gmail.com> and Nicolas VIVIEN"); MODULE_DESCRIPTION("Syntek DC1125 webcam driver"); /* Some cameras have audio interfaces, we aren't interested in those */ -static struct usb_device_id stkwebcam_table[] = { +static const struct usb_device_id stkwebcam_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) }, { } @@ -1202,7 +1202,7 @@ static const struct v4l2_ctrl_ops stk_ctrl_ops = { .s_ctrl = stk_s_ctrl, }; -static struct v4l2_file_operations v4l_stk_fops = { +static const struct v4l2_file_operations v4l_stk_fops = { .owner = THIS_MODULE, .open = v4l_stk_open, .release = v4l_stk_release, @@ -1244,7 +1244,7 @@ static void stk_v4l_dev_release(struct video_device *vd) kfree(dev); } -static struct video_device stk_v4l_data = { +static const struct video_device stk_v4l_data = { .name = "stkwebcam", .fops = &v4l_stk_fops, .ioctl_ops = &v4l_stk_ioctl_ops, diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c index 422322541af6..3717a6844ea8 100644 --- a/drivers/media/usb/tm6000/tm6000-alsa.c +++ b/drivers/media/usb/tm6000/tm6000-alsa.c @@ -143,7 +143,7 @@ static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size) */ #define DEFAULT_FIFO_SIZE 4096 -static struct snd_pcm_hardware snd_tm6000_digital_hw = { +static const struct snd_pcm_hardware snd_tm6000_digital_hw = { .info = SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c index b293dea6554f..2537643a1808 100644 --- a/drivers/media/usb/tm6000/tm6000-cards.c +++ b/drivers/media/usb/tm6000/tm6000-cards.c @@ -613,7 +613,7 @@ static struct tm6000_board tm6000_boards[] = { }; /* table of devices that work with this driver */ -static struct usb_device_id tm6000_id_table[] = { +static const struct usb_device_id tm6000_id_table[] = { { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC }, { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC }, { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV }, diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c index 1a033f57fcc1..91889ad9cdd7 100644 --- a/drivers/media/usb/tm6000/tm6000-input.c +++ b/drivers/media/usb/tm6000/tm6000-input.c @@ -66,7 +66,7 @@ struct tm6000_IR { struct urb *int_urb; /* IR device properties */ - u64 rc_type; + u64 rc_proto; }; void tm6000_ir_wait(struct tm6000_core *dev, u8 state) @@ -103,13 +103,13 @@ static int tm6000_ir_config(struct tm6000_IR *ir) * IR, in order to discard such decoding */ - switch (ir->rc_type) { - case RC_BIT_NEC: + switch (ir->rc_proto) { + case RC_PROTO_BIT_NEC: leader = 900; /* ms */ pulse = 700; /* ms - the actual value would be 562 */ break; default: - case RC_BIT_RC5: + case RC_PROTO_BIT_RC5: leader = 900; /* ms - from the NEC decoding */ pulse = 1780; /* ms - The actual value would be 1776 */ break; @@ -117,12 +117,12 @@ static int tm6000_ir_config(struct tm6000_IR *ir) pulse = ir_clock_mhz * pulse; leader = ir_clock_mhz * leader; - if (ir->rc_type == RC_BIT_NEC) + if (ir->rc_proto == RC_PROTO_BIT_NEC) leader = leader | 0x8000; dprintk(2, "%s: %s, %d MHz, leader = 0x%04x, pulse = 0x%06x \n", __func__, - (ir->rc_type == RC_BIT_NEC) ? "NEC" : "RC-5", + (ir->rc_proto == RC_PROTO_BIT_NEC) ? "NEC" : "RC-5", ir_clock_mhz, leader, pulse); /* Remote WAKEUP = enable, normal mode, from IR decoder output */ @@ -162,24 +162,24 @@ static void tm6000_ir_keydown(struct tm6000_IR *ir, { u8 device, command; u32 scancode; - enum rc_type protocol; + enum rc_proto protocol; if (len < 1) return; command = buf[0]; device = (len > 1 ? buf[1] : 0x0); - switch (ir->rc_type) { - case RC_BIT_RC5: - protocol = RC_TYPE_RC5; + switch (ir->rc_proto) { + case RC_PROTO_BIT_RC5: + protocol = RC_PROTO_RC5; scancode = RC_SCANCODE_RC5(device, command); break; - case RC_BIT_NEC: - protocol = RC_TYPE_NEC; + case RC_PROTO_BIT_NEC: + protocol = RC_PROTO_NEC; scancode = RC_SCANCODE_NEC(device, command); break; default: - protocol = RC_TYPE_OTHER; + protocol = RC_PROTO_OTHER; scancode = RC_SCANCODE_OTHER(device << 8 | command); break; } @@ -311,7 +311,7 @@ static void tm6000_ir_stop(struct rc_dev *rc) cancel_delayed_work_sync(&ir->work); } -static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) +static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto) { struct tm6000_IR *ir = rc->priv; @@ -320,7 +320,7 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) dprintk(2, "%s\n",__func__); - ir->rc_type = *rc_type; + ir->rc_proto = *rc_proto; tm6000_ir_config(ir); /* TODO */ @@ -409,7 +409,7 @@ int tm6000_ir_init(struct tm6000_core *dev) struct tm6000_IR *ir; struct rc_dev *rc; int err = -ENOMEM; - u64 rc_type; + u64 rc_proto; if (!enable_ir) return -ENODEV; @@ -433,7 +433,7 @@ int tm6000_ir_init(struct tm6000_core *dev) ir->rc = rc; /* input setup */ - rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC; + rc->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_NEC; /* Needed, in order to support NEC remotes with 24 or 32 bits */ rc->scancode_mask = 0xffff; rc->priv = ir; @@ -455,10 +455,10 @@ int tm6000_ir_init(struct tm6000_core *dev) usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); - rc_type = RC_BIT_UNKNOWN; - tm6000_ir_change_protocol(rc, &rc_type); + rc_proto = RC_PROTO_BIT_UNKNOWN; + tm6000_ir_change_protocol(rc, &rc_proto); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype = BUS_USB; rc->input_id.version = 1; diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 7e960d0a5b92..ec8c4d2534dc 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -801,7 +801,7 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb free_buffer(vq, buf); } -static struct videobuf_queue_ops tm6000_video_qops = { +static const struct videobuf_queue_ops tm6000_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, @@ -1532,7 +1532,7 @@ static int tm6000_mmap(struct file *file, struct vm_area_struct * vma) return res; } -static struct v4l2_file_operations tm6000_fops = { +static const struct v4l2_file_operations tm6000_fops = { .owner = THIS_MODULE, .open = tm6000_open, .release = tm6000_release, diff --git a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c index 361e40b56045..b842f367249f 100644 --- a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c @@ -1640,7 +1640,7 @@ static void frontend_init(struct ttusb* ttusb) -static struct i2c_algorithm ttusb_dec_algo = { +static const struct i2c_algorithm ttusb_dec_algo = { .master_xfer = master_xfer, .functionality = functionality, }; @@ -1795,7 +1795,7 @@ static void ttusb_disconnect(struct usb_interface *intf) dprintk("%s: TTUSB DVB disconnected\n", __func__); } -static struct usb_device_id ttusb_table[] = { +static const struct usb_device_id ttusb_table[] = { {USB_DEVICE(0xb48, 0x1003)}, {USB_DEVICE(0xb48, 0x1004)}, {USB_DEVICE(0xb48, 0x1005)}, diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 01c7e6d4481c..cdefb5dfbbdc 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -1791,7 +1791,7 @@ static void ttusb_dec_set_model(struct ttusb_dec *dec, } } -static struct usb_device_id ttusb_dec_table[] = { +static const struct usb_device_id ttusb_dec_table[] = { {USB_DEVICE(0x0b48, 0x1006)}, /* DEC3000-s */ /*{USB_DEVICE(0x0b48, 0x1007)}, Unconfirmed */ {USB_DEVICE(0x0b48, 0x1008)}, /* DEC2000-t */ diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c index 9db31db7d9ac..2c2ca77fa01f 100644 --- a/drivers/media/usb/usbtv/usbtv-audio.c +++ b/drivers/media/usb/usbtv/usbtv-audio.c @@ -43,7 +43,7 @@ #include "usbtv.h" -static struct snd_pcm_hardware snd_usbtv_digital_hw = { +static const struct snd_pcm_hardware snd_usbtv_digital_hw = { .info = SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index ceb953be0770..f06f09a0876e 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -142,7 +142,7 @@ static void usbtv_disconnect(struct usb_interface *intf) v4l2_device_put(&usbtv->v4l2_dev); } -static struct usb_device_id usbtv_id_table[] = { +static const struct usb_device_id usbtv_id_table[] = { { USB_DEVICE(0x1b71, 0x3002) }, {} }; diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 8135614f395a..95b5f4319ec2 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -629,7 +629,7 @@ static struct v4l2_ioctl_ops usbtv_ioctl_ops = { .vidioc_streamoff = vb2_ioctl_streamoff, }; -static struct v4l2_file_operations usbtv_fops = { +static const struct v4l2_file_operations usbtv_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, .mmap = vb2_fop_mmap, diff --git a/drivers/media/usb/usbvision/usbvision-i2c.c b/drivers/media/usb/usbvision/usbvision-i2c.c index fdf6b6e285da..837bd4d9db41 100644 --- a/drivers/media/usb/usbvision/usbvision-i2c.c +++ b/drivers/media/usb/usbvision/usbvision-i2c.c @@ -163,7 +163,7 @@ static u32 functionality(struct i2c_adapter *adap) /* -----exported algorithm data: ------------------------------------- */ -static struct i2c_algorithm usbvision_algo = { +static const struct i2c_algorithm usbvision_algo = { .master_xfer = usbvision_i2c_xfer, .smbus_xfer = NULL, .functionality = functionality, @@ -173,7 +173,7 @@ static struct i2c_algorithm usbvision_algo = { /* ----------------------------------------------------------------------- */ /* usbvision specific I2C functions */ /* ----------------------------------------------------------------------- */ -static struct i2c_adapter i2c_adap_template; +static const struct i2c_adapter i2c_adap_template; int usbvision_i2c_register(struct usb_usbvision *usbvision) { @@ -187,8 +187,9 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision) usbvision->i2c_adap = i2c_adap_template; - sprintf(usbvision->i2c_adap.name, "%s-%d-%s", i2c_adap_template.name, - usbvision->dev->bus->busnum, usbvision->dev->devpath); + snprintf(usbvision->i2c_adap.name, sizeof(usbvision->i2c_adap.name), + "usbvision-%d-%s", + usbvision->dev->bus->busnum, usbvision->dev->devpath); PDEBUG(DBG_I2C, "Adaptername: %s", usbvision->i2c_adap.name); usbvision->i2c_adap.dev.parent = &usbvision->dev->dev; @@ -440,7 +441,7 @@ static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char add return rdcount; } -static struct i2c_adapter i2c_adap_template = { +static const struct i2c_adapter i2c_adap_template = { .owner = THIS_MODULE, .name = "usbvision", }; diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 756322c4ac05..960272d3c924 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -904,7 +904,7 @@ static ssize_t usbvision_read(struct file *file, char __user *buf, PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __func__, (unsigned long)count, noblock); - if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) + if (!USBVISION_IS_OPERATIONAL(usbvision) || !buf) return -EFAULT; /* This entry point is compatible with the mmap routines @@ -1234,7 +1234,7 @@ static void usbvision_vdev_init(struct usb_usbvision *usbvision, { struct usb_device *usb_dev = usbvision->dev; - if (usb_dev == NULL) { + if (!usb_dev) { dev_err(&usbvision->dev->dev, "%s: usbvision->dev is not set\n", __func__); return; @@ -1319,8 +1319,8 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev, { struct usb_usbvision *usbvision; - usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL); - if (usbvision == NULL) + usbvision = kzalloc(sizeof(*usbvision), GFP_KERNEL); + if (!usbvision) return NULL; usbvision->dev = dev; @@ -1334,7 +1334,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev, /* prepare control urb for control messages during interrupts */ usbvision->ctrl_urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); - if (usbvision->ctrl_urb == NULL) + if (!usbvision->ctrl_urb) goto err_unreg; return usbvision; @@ -1380,7 +1380,7 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) { int model; - if (usbvision == NULL) + if (!usbvision) return; model = usbvision->dev_model; @@ -1474,7 +1474,7 @@ static int usbvision_probe(struct usb_interface *intf, } usbvision = usbvision_alloc(dev, intf); - if (usbvision == NULL) { + if (!usbvision) { dev_err(&intf->dev, "%s: couldn't allocate USBVision struct\n", __func__); ret = -ENOMEM; goto err_usb; @@ -1494,8 +1494,7 @@ static int usbvision_probe(struct usb_interface *intf, usbvision->num_alt = uif->num_altsetting; PDEBUG(DBG_PROBE, "Alternate settings: %i", usbvision->num_alt); usbvision->alt_max_pkt_size = kmalloc(32 * usbvision->num_alt, GFP_KERNEL); - if (usbvision->alt_max_pkt_size == NULL) { - dev_err(&intf->dev, "usbvision: out of memory!\n"); + if (!usbvision->alt_max_pkt_size) { ret = -ENOMEM; goto err_pkt; } @@ -1566,7 +1565,7 @@ static void usbvision_disconnect(struct usb_interface *intf) PDEBUG(DBG_PROBE, ""); - if (usbvision == NULL) { + if (!usbvision) { pr_err("%s: usb_get_intfdata() failed\n", __func__); return; } diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index c2ee6e39fd0c..20397aba6849 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -2002,6 +2002,13 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, goto done; } + /* Validate the user-provided bit-size and offset */ + if (mapping->size > 32 || + mapping->offset + mapping->size > ctrl->info.size * 8) { + ret = -EINVAL; + goto done; + } + list_for_each_entry(map, &ctrl->info.mappings, list) { if (mapping->id == map->id) { uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', " diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 70842c5af05b..6d22b22cb35b 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1802,8 +1802,9 @@ static int uvc_scan_device(struct uvc_device *dev) * already been canceled by the USB core. There is no need to kill the * interrupt URB manually. */ -static void uvc_delete(struct uvc_device *dev) +static void uvc_delete(struct kref *kref) { + struct uvc_device *dev = container_of(kref, struct uvc_device, ref); struct list_head *p, *n; uvc_status_cleanup(dev); @@ -1854,11 +1855,7 @@ static void uvc_release(struct video_device *vdev) struct uvc_streaming *stream = video_get_drvdata(vdev); struct uvc_device *dev = stream->dev; - /* Decrement the registered streams count and delete the device when it - * reaches zero. - */ - if (atomic_dec_and_test(&dev->nstreams)) - uvc_delete(dev); + kref_put(&dev->ref, uvc_delete); } /* @@ -1870,10 +1867,10 @@ static void uvc_unregister_video(struct uvc_device *dev) /* Unregistering all video devices might result in uvc_delete() being * called from inside the loop if there's no open file handle. To avoid - * that, increment the stream count before iterating over the streams - * and decrement it when done. + * that, increment the refcount before iterating over the streams and + * decrement it when done. */ - atomic_inc(&dev->nstreams); + kref_get(&dev->ref); list_for_each_entry(stream, &dev->streams, list) { if (!video_is_registered(&stream->vdev)) @@ -1884,11 +1881,7 @@ static void uvc_unregister_video(struct uvc_device *dev) uvc_debugfs_cleanup_stream(stream); } - /* Decrement the stream count and call uvc_delete explicitly if there - * are no stream left. - */ - if (atomic_dec_and_test(&dev->nstreams)) - uvc_delete(dev); + kref_put(&dev->ref, uvc_delete); } static int uvc_register_video(struct uvc_device *dev, @@ -1946,7 +1939,7 @@ static int uvc_register_video(struct uvc_device *dev, else stream->chain->caps |= V4L2_CAP_VIDEO_OUTPUT; - atomic_inc(&dev->nstreams); + kref_get(&dev->ref); return 0; } @@ -2031,7 +2024,7 @@ static int uvc_probe(struct usb_interface *intf, INIT_LIST_HEAD(&dev->entities); INIT_LIST_HEAD(&dev->chains); INIT_LIST_HEAD(&dev->streams); - atomic_set(&dev->nstreams, 0); + kref_init(&dev->ref); atomic_set(&dev->nmappings, 0); mutex_init(&dev->lock); @@ -2096,7 +2089,6 @@ static int uvc_probe(struct usb_interface *intf, sizeof(dev->mdev.serial)); strcpy(dev->mdev.bus_info, udev->devpath); dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); - dev->mdev.driver_version = LINUX_VERSION_CODE; media_device_init(&dev->mdev); dev->vdev.mdev = &dev->mdev; @@ -2284,7 +2276,7 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout"); * VENDOR_SPEC because they don't announce themselves as UVC devices, even * though they are compliant. */ -static struct usb_device_id uvc_ids[] = { +static const struct usb_device_id uvc_ids[] = { /* LogiLink Wireless Webcam */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c index ac386bb547e6..554063c07d7a 100644 --- a/drivers/media/usb/uvc/uvc_entity.c +++ b/drivers/media/usb/uvc/uvc_entity.c @@ -61,7 +61,7 @@ static int uvc_mc_create_links(struct uvc_video_chain *chain, return 0; } -static struct v4l2_subdev_ops uvc_subdev_ops = { +static const struct v4l2_subdev_ops uvc_subdev_ops = { }; void uvc_mc_cleanup_entity(struct uvc_entity *entity) diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index aa2199775cb8..c8d78b2f3de4 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -82,9 +82,14 @@ static int uvc_queue_setup(struct vb2_queue *vq, struct uvc_streaming *stream = uvc_queue_to_stream(queue); unsigned size = stream->ctrl.dwMaxVideoFrameSize; - /* Make sure the image size is large enough. */ + /* + * When called with plane sizes, validate them. The driver supports + * single planar formats only, and requires buffers to be large enough + * to store a complete frame. + */ if (*nplanes) - return sizes[0] < size ? -EINVAL : 0; + return *nplanes != 1 || sizes[0] < size ? -EINVAL : 0; + *nplanes = 1; sizes[0] = size; return 0; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 15e415e32c7f..34c7ee6cc9e5 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -166,7 +166,7 @@ /* Maximum status buffer size in bytes of interrupt URB. */ #define UVC_MAX_STATUS_SIZE 16 -#define UVC_CTRL_CONTROL_TIMEOUT 300 +#define UVC_CTRL_CONTROL_TIMEOUT 500 #define UVC_CTRL_STREAMING_TIMEOUT 5000 /* Maximum allowed number of control mappings per device */ @@ -575,7 +575,7 @@ struct uvc_device { /* Video Streaming interfaces */ struct list_head streams; - atomic_t nstreams; + struct kref ref; /* Status Interrupt Endpoint */ struct usb_host_endpoint *int_ep; diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index efdcd5bd6a4c..4ff8d0aed015 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -93,7 +93,7 @@ MODULE_PARM_DESC(mode, "0 = 320x240, 1 = 160x120, 2 = 640x480"); /* Devices supported by this driver * .driver_info contains the init method used by the camera */ -static struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] = { {USB_DEVICE(0x08ca, 0x0109), .driver_info = METHOD0 }, {USB_DEVICE(0x041e, 0x4024), .driver_info = METHOD0 }, {USB_DEVICE(0x0d64, 0x0108), .driver_info = METHOD0 }, @@ -439,7 +439,7 @@ static void buffer_release(struct videobuf_queue *vq, free_buffer(vq, buf); } -static struct videobuf_queue_ops zr364xx_video_qops = { +static const struct videobuf_queue_ops zr364xx_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, @@ -1335,7 +1335,7 @@ static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static struct video_device zr364xx_template = { +static const struct video_device zr364xx_template = { .name = DRIVER_DESC, .fops = &zr364xx_fops, .ioctl_ops = &zr364xx_ioctl_ops, diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 851f128eba22..d741a8e0fdac 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -44,12 +44,7 @@ static bool match_devname(struct v4l2_subdev *sd, static bool match_fwnode(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { - if (!is_of_node(sd->fwnode) || !is_of_node(asd->match.fwnode.fwnode)) - return sd->fwnode == asd->match.fwnode.fwnode; - - return !of_node_cmp(of_node_full_name(to_of_node(sd->fwnode)), - of_node_full_name( - to_of_node(asd->match.fwnode.fwnode))); + return sd->fwnode == asd->match.fwnode.fwnode; } static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c index 297e10e69898..90628d7a04de 100644 --- a/drivers/media/v4l2-core/v4l2-clk.c +++ b/drivers/media/v4l2-core/v4l2-clk.c @@ -61,8 +61,7 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id) /* if dev_name is not found, try use the OF name to find again */ if (PTR_ERR(clk) == -ENODEV && dev->of_node) { - v4l2_clk_name_of(clk_name, sizeof(clk_name), - of_node_full_name(dev->of_node)); + v4l2_clk_name_of(clk_name, sizeof(clk_name), dev->of_node); clk = v4l2_clk_find(clk_name); } diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 6f52970f8b54..821f2aa299ae 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -43,6 +43,7 @@ struct v4l2_window32 { compat_caddr_t clips; /* actually struct v4l2_clip32 * */ __u32 clipcount; compat_caddr_t bitmap; + __u8 global_alpha; }; static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up) @@ -51,7 +52,8 @@ static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user copy_from_user(&kp->w, &up->w, sizeof(up->w)) || get_user(kp->field, &up->field) || get_user(kp->chromakey, &up->chromakey) || - get_user(kp->clipcount, &up->clipcount)) + get_user(kp->clipcount, &up->clipcount) || + get_user(kp->global_alpha, &up->global_alpha)) return -EFAULT; if (kp->clipcount > 2048) return -EINVAL; @@ -84,7 +86,8 @@ static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) || put_user(kp->field, &up->field) || put_user(kp->chromakey, &up->chromakey) || - put_user(kp->clipcount, &up->clipcount)) + put_user(kp->clipcount, &up->clipcount) || + put_user(kp->global_alpha, &up->global_alpha)) return -EFAULT; return 0; } @@ -627,7 +630,8 @@ struct v4l2_input32 { __u32 tuner; /* Associated tuner */ compat_u64 std; __u32 status; - __u32 reserved[4]; + __u32 capabilities; + __u32 reserved[3]; }; /* The 64-bit v4l2_input struct has extra padding at the end of the struct. @@ -796,7 +800,8 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u copy_to_user(&up->u, &kp->u, sizeof(kp->u)) || put_user(kp->pending, &up->pending) || put_user(kp->sequence, &up->sequence) || - compat_put_timespec(&kp->timestamp, &up->timestamp) || + put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || + put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) || put_user(kp->id, &up->id) || copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32))) return -EFAULT; diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c index 7b8288108e8a..4ceef217de83 100644 --- a/drivers/media/v4l2-core/v4l2-flash-led-class.c +++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c @@ -18,7 +18,7 @@ #include <media/v4l2-flash-led-class.h> #define has_flash_op(v4l2_flash, op) \ - (v4l2_flash && v4l2_flash->ops->op) + (v4l2_flash && v4l2_flash->ops && v4l2_flash->ops->op) #define call_flash_op(v4l2_flash, op, arg) \ (has_flash_op(v4l2_flash, op) ? \ @@ -110,7 +110,7 @@ static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash, led_set_brightness_sync(&v4l2_flash->fled_cdev->led_cdev, brightness); } else { - led_set_brightness_sync(&v4l2_flash->iled_cdev->led_cdev, + led_set_brightness_sync(v4l2_flash->iled_cdev, brightness); } } @@ -133,7 +133,7 @@ static int v4l2_flash_update_led_brightness(struct v4l2_flash *v4l2_flash, return 0; led_cdev = &v4l2_flash->fled_cdev->led_cdev; } else { - led_cdev = &v4l2_flash->iled_cdev->led_cdev; + led_cdev = v4l2_flash->iled_cdev; } ret = led_update_brightness(led_cdev); @@ -197,7 +197,7 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c) { struct v4l2_flash *v4l2_flash = v4l2_ctrl_to_v4l2_flash(c); struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; - struct led_classdev *led_cdev = &fled_cdev->led_cdev; + struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL; struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; bool external_strobe; int ret = 0; @@ -299,11 +299,26 @@ static void __fill_ctrl_init_data(struct v4l2_flash *v4l2_flash, struct v4l2_flash_ctrl_data *ctrl_init_data) { struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; - const struct led_flash_ops *fled_cdev_ops = fled_cdev->ops; - struct led_classdev *led_cdev = &fled_cdev->led_cdev; + struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL; struct v4l2_ctrl_config *ctrl_cfg; u32 mask; + /* Init INDICATOR_INTENSITY ctrl data */ + if (v4l2_flash->iled_cdev) { + ctrl_init_data[INDICATOR_INTENSITY].cid = + V4L2_CID_FLASH_INDICATOR_INTENSITY; + ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config; + __lfs_to_v4l2_ctrl_config(&flash_cfg->intensity, + ctrl_cfg); + ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY; + ctrl_cfg->min = 0; + ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + } + + if (!led_cdev || WARN_ON(!(led_cdev->flags & LED_DEV_CAP_FLASH))) + return; + /* Init FLASH_FAULT ctrl data */ if (flash_cfg->flash_faults) { ctrl_init_data[FLASH_FAULT].cid = V4L2_CID_FLASH_FAULT; @@ -331,27 +346,11 @@ static void __fill_ctrl_init_data(struct v4l2_flash *v4l2_flash, /* Init TORCH_INTENSITY ctrl data */ ctrl_init_data[TORCH_INTENSITY].cid = V4L2_CID_FLASH_TORCH_INTENSITY; ctrl_cfg = &ctrl_init_data[TORCH_INTENSITY].config; - __lfs_to_v4l2_ctrl_config(&flash_cfg->torch_intensity, ctrl_cfg); + __lfs_to_v4l2_ctrl_config(&flash_cfg->intensity, ctrl_cfg); ctrl_cfg->id = V4L2_CID_FLASH_TORCH_INTENSITY; ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; - /* Init INDICATOR_INTENSITY ctrl data */ - if (v4l2_flash->iled_cdev) { - ctrl_init_data[INDICATOR_INTENSITY].cid = - V4L2_CID_FLASH_INDICATOR_INTENSITY; - ctrl_cfg = &ctrl_init_data[INDICATOR_INTENSITY].config; - __lfs_to_v4l2_ctrl_config(&flash_cfg->indicator_intensity, - ctrl_cfg); - ctrl_cfg->id = V4L2_CID_FLASH_INDICATOR_INTENSITY; - ctrl_cfg->min = 0; - ctrl_cfg->flags = V4L2_CTRL_FLAG_VOLATILE | - V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; - } - - if (!(led_cdev->flags & LED_DEV_CAP_FLASH)) - return; - /* Init FLASH_STROBE ctrl data */ ctrl_init_data[FLASH_STROBE].cid = V4L2_CID_FLASH_STROBE; ctrl_cfg = &ctrl_init_data[FLASH_STROBE].config; @@ -376,7 +375,7 @@ static void __fill_ctrl_init_data(struct v4l2_flash *v4l2_flash, } /* Init STROBE_STATUS ctrl data */ - if (fled_cdev_ops->strobe_get) { + if (has_flash_op(fled_cdev, strobe_get)) { ctrl_init_data[STROBE_STATUS].cid = V4L2_CID_FLASH_STROBE_STATUS; ctrl_cfg = &ctrl_init_data[STROBE_STATUS].config; @@ -386,7 +385,7 @@ static void __fill_ctrl_init_data(struct v4l2_flash *v4l2_flash, } /* Init FLASH_TIMEOUT ctrl data */ - if (fled_cdev_ops->timeout_set) { + if (has_flash_op(fled_cdev, timeout_set)) { ctrl_init_data[FLASH_TIMEOUT].cid = V4L2_CID_FLASH_TIMEOUT; ctrl_cfg = &ctrl_init_data[FLASH_TIMEOUT].config; __lfs_to_v4l2_ctrl_config(&fled_cdev->timeout, ctrl_cfg); @@ -394,7 +393,7 @@ static void __fill_ctrl_init_data(struct v4l2_flash *v4l2_flash, } /* Init FLASH_INTENSITY ctrl data */ - if (fled_cdev_ops->flash_brightness_set) { + if (has_flash_op(fled_cdev, flash_brightness_set)) { ctrl_init_data[FLASH_INTENSITY].cid = V4L2_CID_FLASH_INTENSITY; ctrl_cfg = &ctrl_init_data[FLASH_INTENSITY].config; __lfs_to_v4l2_ctrl_config(&fled_cdev->brightness, ctrl_cfg); @@ -486,7 +485,9 @@ static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash) struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; int ret = 0; - v4l2_flash_set_led_brightness(v4l2_flash, ctrls[TORCH_INTENSITY]); + if (ctrls[TORCH_INTENSITY]) + v4l2_flash_set_led_brightness(v4l2_flash, + ctrls[TORCH_INTENSITY]); if (ctrls[INDICATOR_INTENSITY]) v4l2_flash_set_led_brightness(v4l2_flash, @@ -528,24 +529,23 @@ static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd); struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; - struct led_classdev *led_cdev = &fled_cdev->led_cdev; - struct led_classdev_flash *iled_cdev = v4l2_flash->iled_cdev; - struct led_classdev *led_cdev_ind = NULL; + struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL; + struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev; int ret = 0; if (!v4l2_fh_is_singular(&fh->vfh)) return 0; - mutex_lock(&led_cdev->led_access); - - led_sysfs_disable(led_cdev); - led_trigger_remove(led_cdev); + if (led_cdev) { + mutex_lock(&led_cdev->led_access); - mutex_unlock(&led_cdev->led_access); + led_sysfs_disable(led_cdev); + led_trigger_remove(led_cdev); - if (iled_cdev) { - led_cdev_ind = &iled_cdev->led_cdev; + mutex_unlock(&led_cdev->led_access); + } + if (led_cdev_ind) { mutex_lock(&led_cdev_ind->led_access); led_sysfs_disable(led_cdev_ind); @@ -560,9 +560,11 @@ static int v4l2_flash_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return 0; out_sync_device: - mutex_lock(&led_cdev->led_access); - led_sysfs_enable(led_cdev); - mutex_unlock(&led_cdev->led_access); + if (led_cdev) { + mutex_lock(&led_cdev->led_access); + led_sysfs_enable(led_cdev); + mutex_unlock(&led_cdev->led_access); + } if (led_cdev_ind) { mutex_lock(&led_cdev_ind->led_access); @@ -577,25 +579,26 @@ static int v4l2_flash_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_flash *v4l2_flash = v4l2_subdev_to_v4l2_flash(sd); struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; - struct led_classdev *led_cdev = &fled_cdev->led_cdev; - struct led_classdev_flash *iled_cdev = v4l2_flash->iled_cdev; + struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL; + struct led_classdev *led_cdev_ind = v4l2_flash->iled_cdev; int ret = 0; if (!v4l2_fh_is_singular(&fh->vfh)) return 0; - mutex_lock(&led_cdev->led_access); + if (led_cdev) { + mutex_lock(&led_cdev->led_access); - if (v4l2_flash->ctrls[STROBE_SOURCE]) - ret = v4l2_ctrl_s_ctrl(v4l2_flash->ctrls[STROBE_SOURCE], + if (v4l2_flash->ctrls[STROBE_SOURCE]) + ret = v4l2_ctrl_s_ctrl( + v4l2_flash->ctrls[STROBE_SOURCE], V4L2_FLASH_STROBE_SOURCE_SOFTWARE); - led_sysfs_enable(led_cdev); - - mutex_unlock(&led_cdev->led_access); + led_sysfs_enable(led_cdev); - if (iled_cdev) { - struct led_classdev *led_cdev_ind = &iled_cdev->led_cdev; + mutex_unlock(&led_cdev->led_access); + } + if (led_cdev_ind) { mutex_lock(&led_cdev_ind->led_access); led_sysfs_enable(led_cdev_ind); mutex_unlock(&led_cdev_ind->led_access); @@ -611,25 +614,19 @@ static const struct v4l2_subdev_internal_ops v4l2_flash_subdev_internal_ops = { static const struct v4l2_subdev_ops v4l2_flash_subdev_ops; -struct v4l2_flash *v4l2_flash_init( +static struct v4l2_flash *__v4l2_flash_init( struct device *dev, struct fwnode_handle *fwn, - struct led_classdev_flash *fled_cdev, - struct led_classdev_flash *iled_cdev, - const struct v4l2_flash_ops *ops, - struct v4l2_flash_config *config) + struct led_classdev_flash *fled_cdev, struct led_classdev *iled_cdev, + const struct v4l2_flash_ops *ops, struct v4l2_flash_config *config) { struct v4l2_flash *v4l2_flash; - struct led_classdev *led_cdev; struct v4l2_subdev *sd; int ret; - if (!fled_cdev || !ops || !config) + if (!config) return ERR_PTR(-EINVAL); - led_cdev = &fled_cdev->led_cdev; - - v4l2_flash = devm_kzalloc(led_cdev->dev, sizeof(*v4l2_flash), - GFP_KERNEL); + v4l2_flash = devm_kzalloc(dev, sizeof(*v4l2_flash), GFP_KERNEL); if (!v4l2_flash) return ERR_PTR(-ENOMEM); @@ -638,7 +635,7 @@ struct v4l2_flash *v4l2_flash_init( v4l2_flash->iled_cdev = iled_cdev; v4l2_flash->ops = ops; sd->dev = dev; - sd->fwnode = fwn ? fwn : dev_fwnode(led_cdev->dev); + sd->fwnode = fwn ? fwn : dev_fwnode(dev); v4l2_subdev_init(sd, &v4l2_flash_subdev_ops); sd->internal_ops = &v4l2_flash_subdev_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; @@ -670,8 +667,26 @@ err_init_controls: return ERR_PTR(ret); } + +struct v4l2_flash *v4l2_flash_init( + struct device *dev, struct fwnode_handle *fwn, + struct led_classdev_flash *fled_cdev, + const struct v4l2_flash_ops *ops, + struct v4l2_flash_config *config) +{ + return __v4l2_flash_init(dev, fwn, fled_cdev, NULL, ops, config); +} EXPORT_SYMBOL_GPL(v4l2_flash_init); +struct v4l2_flash *v4l2_flash_indicator_init( + struct device *dev, struct fwnode_handle *fwn, + struct led_classdev *iled_cdev, + struct v4l2_flash_config *config) +{ + return __v4l2_flash_init(dev, fwn, NULL, iled_cdev, NULL, config); +} +EXPORT_SYMBOL_GPL(v4l2_flash_indicator_init); + void v4l2_flash_release(struct v4l2_flash *v4l2_flash) { struct v4l2_subdev *sd; diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 153c53ca3925..40b2fbfe8865 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -28,8 +28,16 @@ #include <media/v4l2-fwnode.h> -static int v4l2_fwnode_endpoint_parse_csi_bus(struct fwnode_handle *fwnode, - struct v4l2_fwnode_endpoint *vep) +enum v4l2_fwnode_bus_type { + V4L2_FWNODE_BUS_TYPE_GUESS = 0, + V4L2_FWNODE_BUS_TYPE_CSI2_CPHY, + V4L2_FWNODE_BUS_TYPE_CSI1, + V4L2_FWNODE_BUS_TYPE_CCP2, + NR_OF_V4L2_FWNODE_BUS_TYPE, +}; + +static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, + struct v4l2_fwnode_endpoint *vep) { struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2; bool have_clk_lane = false; @@ -40,10 +48,10 @@ static int v4l2_fwnode_endpoint_parse_csi_bus(struct fwnode_handle *fwnode, rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0); if (rval > 0) { - u32 array[ARRAY_SIZE(bus->data_lanes)]; + u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES]; bus->num_data_lanes = - min_t(int, ARRAY_SIZE(bus->data_lanes), rval); + min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval); fwnode_property_read_u32_array(fwnode, "data-lanes", array, bus->num_data_lanes); @@ -56,24 +64,25 @@ static int v4l2_fwnode_endpoint_parse_csi_bus(struct fwnode_handle *fwnode, bus->data_lanes[i] = array[i]; } - } - - rval = fwnode_property_read_u32_array(fwnode, "lane-polarities", NULL, - 0); - if (rval > 0) { - u32 array[ARRAY_SIZE(bus->lane_polarities)]; - if (rval < 1 + bus->num_data_lanes /* clock + data */) { - pr_warn("too few lane-polarities entries (need %u, got %u)\n", - 1 + bus->num_data_lanes, rval); - return -EINVAL; + rval = fwnode_property_read_u32_array(fwnode, + "lane-polarities", NULL, + 0); + if (rval > 0) { + if (rval != 1 + bus->num_data_lanes /* clock+data */) { + pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n", + 1 + bus->num_data_lanes, rval); + return -EINVAL; + } + + fwnode_property_read_u32_array(fwnode, + "lane-polarities", array, + 1 + bus->num_data_lanes); + + for (i = 0; i < 1 + bus->num_data_lanes; i++) + bus->lane_polarities[i] = array[i]; } - fwnode_property_read_u32_array(fwnode, "lane-polarities", array, - 1 + bus->num_data_lanes); - - for (i = 0; i < 1 + bus->num_data_lanes; i++) - bus->lane_polarities[i] = array[i]; } if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) { @@ -146,6 +155,32 @@ static void v4l2_fwnode_endpoint_parse_parallel_bus( } +static void +v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode, + struct v4l2_fwnode_endpoint *vep, + u32 bus_type) +{ + struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1; + u32 v; + + if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) + bus->clock_inv = v; + + if (!fwnode_property_read_u32(fwnode, "strobe", &v)) + bus->strobe = v; + + if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) + bus->data_lane = v; + + if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) + bus->clock_lane = v; + + if (bus_type == V4L2_FWNODE_BUS_TYPE_CCP2) + vep->bus_type = V4L2_MBUS_CCP2; + else + vep->bus_type = V4L2_MBUS_CSI1; +} + /** * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties * @fwnode: pointer to the endpoint's fwnode handle @@ -168,6 +203,7 @@ static void v4l2_fwnode_endpoint_parse_parallel_bus( int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep) { + u32 bus_type = 0; int rval; fwnode_graph_parse_endpoint(fwnode, &vep->base); @@ -176,17 +212,30 @@ int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode, memset(&vep->bus_type, 0, sizeof(*vep) - offsetof(typeof(*vep), bus_type)); - rval = v4l2_fwnode_endpoint_parse_csi_bus(fwnode, vep); - if (rval) - return rval; - /* - * Parse the parallel video bus properties only if none - * of the MIPI CSI-2 specific properties were found. - */ - if (vep->bus.mipi_csi2.flags == 0) - v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep); - - return 0; + fwnode_property_read_u32(fwnode, "bus-type", &bus_type); + + switch (bus_type) { + case V4L2_FWNODE_BUS_TYPE_GUESS: + rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep); + if (rval) + return rval; + /* + * Parse the parallel video bus properties only if none + * of the MIPI CSI-2 specific properties were found. + */ + if (vep->bus.mipi_csi2.flags == 0) + v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep); + + return 0; + case V4L2_FWNODE_BUS_TYPE_CCP2: + case V4L2_FWNODE_BUS_TYPE_CSI1: + v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, bus_type); + + return 0; + default: + pr_warn("unsupported bus type %u\n", bus_type); + return -EINVAL; + } } EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse); @@ -247,23 +296,23 @@ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse( rval = fwnode_property_read_u64_array(fwnode, "link-frequencies", NULL, 0); - if (rval < 0) - goto out_err; - - vep->link_frequencies = - kmalloc_array(rval, sizeof(*vep->link_frequencies), GFP_KERNEL); - if (!vep->link_frequencies) { - rval = -ENOMEM; - goto out_err; - } + if (rval > 0) { + vep->link_frequencies = + kmalloc_array(rval, sizeof(*vep->link_frequencies), + GFP_KERNEL); + if (!vep->link_frequencies) { + rval = -ENOMEM; + goto out_err; + } - vep->nr_of_link_frequencies = rval; + vep->nr_of_link_frequencies = rval; - rval = fwnode_property_read_u64_array(fwnode, "link-frequencies", - vep->link_frequencies, - vep->nr_of_link_frequencies); - if (rval < 0) - goto out_err; + rval = fwnode_property_read_u64_array( + fwnode, "link-frequencies", vep->link_frequencies, + vep->nr_of_link_frequencies); + if (rval < 0) + goto out_err; + } return vep; diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index cab63bb49c97..b60a6b0841d1 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1195,10 +1195,6 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_SGBRG10: descr = "10-bit Bayer GBGB/RGRG"; break; case V4L2_PIX_FMT_SGRBG10: descr = "10-bit Bayer GRGR/BGBG"; break; case V4L2_PIX_FMT_SRGGB10: descr = "10-bit Bayer RGRG/GBGB"; break; - case V4L2_PIX_FMT_SBGGR12: descr = "12-bit Bayer BGBG/GRGR"; break; - case V4L2_PIX_FMT_SGBRG12: descr = "12-bit Bayer GBGB/RGRG"; break; - case V4L2_PIX_FMT_SGRBG12: descr = "12-bit Bayer GRGR/BGBG"; break; - case V4L2_PIX_FMT_SRGGB12: descr = "12-bit Bayer RGRG/GBGB"; break; case V4L2_PIX_FMT_SBGGR10P: descr = "10-bit Bayer BGBG/GRGR Packed"; break; case V4L2_PIX_FMT_SGBRG10P: descr = "10-bit Bayer GBGB/RGRG Packed"; break; case V4L2_PIX_FMT_SGRBG10P: descr = "10-bit Bayer GRGR/BGBG Packed"; break; @@ -1211,6 +1207,14 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_SGBRG10DPCM8: descr = "8-bit Bayer GBGB/RGRG (DPCM)"; break; case V4L2_PIX_FMT_SGRBG10DPCM8: descr = "8-bit Bayer GRGR/BGBG (DPCM)"; break; case V4L2_PIX_FMT_SRGGB10DPCM8: descr = "8-bit Bayer RGRG/GBGB (DPCM)"; break; + case V4L2_PIX_FMT_SBGGR12: descr = "12-bit Bayer BGBG/GRGR"; break; + case V4L2_PIX_FMT_SGBRG12: descr = "12-bit Bayer GBGB/RGRG"; break; + case V4L2_PIX_FMT_SGRBG12: descr = "12-bit Bayer GRGR/BGBG"; break; + case V4L2_PIX_FMT_SRGGB12: descr = "12-bit Bayer RGRG/GBGB"; break; + case V4L2_PIX_FMT_SBGGR12P: descr = "12-bit Bayer BGBG/GRGR Packed"; break; + case V4L2_PIX_FMT_SGBRG12P: descr = "12-bit Bayer GBGB/RGRG Packed"; break; + case V4L2_PIX_FMT_SGRBG12P: descr = "12-bit Bayer GRGR/BGBG Packed"; break; + case V4L2_PIX_FMT_SRGGB12P: descr = "12-bit Bayer RGRG/GBGB Packed"; break; case V4L2_PIX_FMT_SBGGR16: descr = "16-bit Bayer BGBG/GRGR"; break; case V4L2_PIX_FMT_SGBRG16: descr = "16-bit Bayer GBGB/RGRG"; break; case V4L2_PIX_FMT_SGRBG16: descr = "16-bit Bayer GRGR/BGBG"; break; diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 14f83cecfa92..cb115ba6a1d2 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -194,8 +194,6 @@ static void __enqueue_in_driver(struct vb2_buffer *vb); static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) { struct vb2_queue *q = vb->vb2_queue; - enum dma_data_direction dma_dir = - q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; void *mem_priv; int plane; int ret = -ENOMEM; @@ -209,7 +207,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) mem_priv = call_ptr_memop(vb, alloc, q->alloc_devs[plane] ? : q->dev, - q->dma_attrs, size, dma_dir, q->gfp_flags); + q->dma_attrs, size, q->dma_dir, q->gfp_flags); if (IS_ERR_OR_NULL(mem_priv)) { if (mem_priv) ret = PTR_ERR(mem_priv); @@ -978,8 +976,6 @@ static int __prepare_userptr(struct vb2_buffer *vb, const void *pb) void *mem_priv; unsigned int plane; int ret = 0; - enum dma_data_direction dma_dir = - q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; bool reacquired = vb->planes[0].mem_priv == NULL; memset(planes, 0, sizeof(planes[0]) * vb->num_planes); @@ -1030,7 +1026,7 @@ static int __prepare_userptr(struct vb2_buffer *vb, const void *pb) mem_priv = call_ptr_memop(vb, get_userptr, q->alloc_devs[plane] ? : q->dev, planes[plane].m.userptr, - planes[plane].length, dma_dir); + planes[plane].length, q->dma_dir); if (IS_ERR(mem_priv)) { dprintk(1, "failed acquiring userspace memory for plane %d\n", plane); @@ -1096,8 +1092,6 @@ static int __prepare_dmabuf(struct vb2_buffer *vb, const void *pb) void *mem_priv; unsigned int plane; int ret = 0; - enum dma_data_direction dma_dir = - q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; bool reacquired = vb->planes[0].mem_priv == NULL; memset(planes, 0, sizeof(planes[0]) * vb->num_planes); @@ -1139,7 +1133,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb, const void *pb) continue; } - dprintk(1, "buffer for plane %d changed\n", plane); + dprintk(3, "buffer for plane %d changed\n", plane); if (!reacquired) { reacquired = true; @@ -1156,7 +1150,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb, const void *pb) /* Acquire each plane's memory */ mem_priv = call_ptr_memop(vb, attach_dmabuf, q->alloc_devs[plane] ? : q->dev, - dbuf, planes[plane].length, dma_dir); + dbuf, planes[plane].length, q->dma_dir); if (IS_ERR(mem_priv)) { dprintk(1, "failed to attach dmabuf\n"); ret = PTR_ERR(mem_priv); @@ -1298,7 +1292,7 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb) /* Fill buffer information for the userspace */ call_void_bufop(q, fill_user_buffer, vb, pb); - dprintk(1, "prepare of buffer %d succeeded\n", vb->index); + dprintk(2, "prepare of buffer %d succeeded\n", vb->index); return ret; } @@ -1428,7 +1422,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb) return ret; } - dprintk(1, "qbuf of buffer %d succeeded\n", vb->index); + dprintk(2, "qbuf of buffer %d succeeded\n", vb->index); return 0; } EXPORT_SYMBOL_GPL(vb2_core_qbuf); @@ -1476,7 +1470,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) } if (nonblocking) { - dprintk(1, "nonblocking and no buffers to dequeue, will not wait\n"); + dprintk(3, "nonblocking and no buffers to dequeue, will not wait\n"); return -EAGAIN; } @@ -1623,7 +1617,7 @@ int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb, /* go back to dequeued state */ __vb2_dqbuf(vb); - dprintk(1, "dqbuf of buffer %d, with state %d\n", + dprintk(2, "dqbuf of buffer %d, with state %d\n", vb->index, vb->state); return 0; @@ -2003,6 +1997,11 @@ int vb2_core_queue_init(struct vb2_queue *q) if (q->buf_struct_size == 0) q->buf_struct_size = sizeof(struct vb2_buffer); + if (q->bidirectional) + q->dma_dir = DMA_BIDIRECTIONAL; + else + q->dma_dir = q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + return 0; } EXPORT_SYMBOL_GPL(vb2_core_queue_init); diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 4f246d166111..9f389f36566d 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -352,7 +352,7 @@ static int vb2_dc_dmabuf_ops_mmap(struct dma_buf *dbuf, return vb2_dc_mmap(dbuf->priv, vma); } -static struct dma_buf_ops vb2_dc_dmabuf_ops = { +static const struct dma_buf_ops vb2_dc_dmabuf_ops = { .attach = vb2_dc_dmabuf_ops_attach, .detach = vb2_dc_dmabuf_ops_detach, .map_dma_buf = vb2_dc_dmabuf_ops_map, @@ -508,7 +508,8 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr, buf->dma_dir = dma_dir; offset = vaddr & ~PAGE_MASK; - vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE); + vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE || + dma_dir == DMA_BIDIRECTIONAL); if (IS_ERR(vec)) { ret = PTR_ERR(vec); goto fail_buf; diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 5defa1f22ca2..6808231a6bdc 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c @@ -239,7 +239,8 @@ static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr, buf->offset = vaddr & ~PAGE_MASK; buf->size = size; buf->dma_sgt = &buf->sg_table; - vec = vb2_create_framevec(vaddr, size, buf->dma_dir == DMA_FROM_DEVICE); + vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE || + dma_dir == DMA_BIDIRECTIONAL); if (IS_ERR(vec)) goto userptr_fail_pfnvec; buf->vec = vec; @@ -292,7 +293,8 @@ static void vb2_dma_sg_put_userptr(void *buf_priv) vm_unmap_ram(buf->vaddr, buf->num_pages); sg_free_table(buf->dma_sgt); while (--i >= 0) { - if (buf->dma_dir == DMA_FROM_DEVICE) + if (buf->dma_dir == DMA_FROM_DEVICE || + buf->dma_dir == DMA_BIDIRECTIONAL) set_page_dirty_lock(buf->pages[i]); } vb2_destroy_framevec(buf->vec); @@ -500,7 +502,7 @@ static int vb2_dma_sg_dmabuf_ops_mmap(struct dma_buf *dbuf, return vb2_dma_sg_mmap(dbuf->priv, vma); } -static struct dma_buf_ops vb2_dma_sg_dmabuf_ops = { +static const struct dma_buf_ops vb2_dma_sg_dmabuf_ops = { .attach = vb2_dma_sg_dmabuf_ops_attach, .detach = vb2_dma_sg_dmabuf_ops_detach, .map_dma_buf = vb2_dma_sg_dmabuf_ops_map, diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index b337d780844c..3a7c80cd1a17 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -87,7 +87,8 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, buf->dma_dir = dma_dir; offset = vaddr & ~PAGE_MASK; buf->size = size; - vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE); + vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE || + dma_dir == DMA_BIDIRECTIONAL); if (IS_ERR(vec)) { ret = PTR_ERR(vec); goto fail_pfnvec_create; @@ -137,7 +138,8 @@ static void vb2_vmalloc_put_userptr(void *buf_priv) pages = frame_vector_pages(buf->vec); if (vaddr) vm_unmap_ram((void *)vaddr, n_pages); - if (buf->dma_dir == DMA_FROM_DEVICE) + 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]); } else { @@ -338,7 +340,7 @@ static int vb2_vmalloc_dmabuf_ops_mmap(struct dma_buf *dbuf, return vb2_vmalloc_mmap(dbuf->priv, vma); } -static struct dma_buf_ops vb2_vmalloc_dmabuf_ops = { +static const struct dma_buf_ops vb2_vmalloc_dmabuf_ops = { .attach = vb2_vmalloc_dmabuf_ops_attach, .detach = vb2_vmalloc_dmabuf_ops_detach, .map_dma_buf = vb2_vmalloc_dmabuf_ops_map, |