media updates for v4.14-rc1

-----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJZsSBoAAoJEAhfPr2O5OEVDc4QAJZSuVYmyLgvtmPxhyqgCvkz
 I0DmWM4ZtK2VT/xJ/AA23z8IiLKi2+pDC0Xx6/aIiA665cyl3oPUdkKIaHW9Z6+A
 fV8gSFkmGkluQb9mP/KdHYI2oSeEv2ivCa1kfaApYcoBa904z8uU++z15Iu5p/+m
 fjpc2vnc9rax0Vuwmgv7p1CL4j4e/ja0siCSCGbu2ad50KqP4ytnBooNPQOQt89D
 L+Av5MeGml/CTUUnAFjWfSmQ72Ht8GhoBBKc6wGoq9x3GTckDDTqy8BAqGt4UQnu
 fR0mb71zuSVmTjxRe7tc/74m3ReaeSHzQeHJhjdQslvNmV3RVQgk/6CCsmqNEegr
 rbC3glQCM+gp5YywCjRL6DCPsoqvjexLtPQjMZIGYxgSYQUyXGOxilgmj9+73761
 6aOl0nqdgN+vlWzaSeDF9EQxRsc+cCq/Po8/xuPE/Pzs6zTQwU+6b+ADLf9jCyDP
 LTC49wOj24SoWiTlG1FTct2ogZ3h5wNPWlurBtmyiFJn+43RpsH5IW9wLilCjeiE
 6JeCWEIBglCCq/TVCzETKNSaixDL6/lMQ9uRdCpIO4VLyoS6S9pZASNPBmQ1h7h/
 oTjYDeWirIthNOccstbBoJQYSX62CqAIW3wq5ME6PAgM+ioiLXLYk0fV3yBKoBNW
 Z0SBeTcuPxWmfzuxMtik
 =fNM2
 -----END PGP SIGNATURE-----

Merge tag 'media/v4.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab:
 "Brazil's Independence Day pull request :-)

  This is one of the biggest media pull requests, with 625 patches
  affecting almost all parts of media (RC, DVB, V4L2, CEC, docs).

  This contains:

   - A lot of new drivers:
     * DVB frontends: mxl5xx, stv0910, stv6111;
     * camera flash: as3645a led driver;
     * HDMI receiver: adv748X;
     * camera sensor: Omnivision 6650 5M driver (ov6650);
     * HDMI CEC: ao-cec meson driver;
     * V4L2: Qualcom camss driver;
     * Remote controller: gpio-ir-tx, pwm-ir-tx and zx-irdec drivers.

   - The DDbridge DVB driver got a massive update, with makes it in sync
     with modern hardware from that vendor;

   - There's an important milestone on this series: the DVB
     documentation was written in 2003, but only started to be updated
     in 2007. It also used to contain several gaps from the time it was
     kept out of tree, mentioning error codes and device nodes that
     never existed upstream. On this series, it received a massive
     update: all non-deprecated digital TV APIs are now in sync with the
     current implementation;

   - Some DVB APIs that aren't used by any upstream driver got removed;

   - Other parts of the media documentation algo got updated, fixing
     some bugs on its PDF output and making it compatible with Sphinx
     version 1.6.

     As the number of hacks required to build PDF output reduced, I hope
     we'll have less troubles as newer versions of our documentation
     toolchain are released (famous last words);

   - As usual, lots of driver cleanups and improvements"

* tag 'media/v4.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (624 commits)
  media: leds: as3645a: add V4L2_FLASH_LED_CLASS dependency
  media: get rid of removed DMX_GET_CAPS and DMX_SET_SOURCE leftovers
  media: Revert "[media] v4l: async: make v4l2 coexist with devicetree nodes in a dt overlay"
  media: staging: atomisp: sh_css_calloc shall return a pointer to the allocated space
  media: Revert "[media] lirc_dev: remove superfluous get/put_device() calls"
  media: add qcom_camss.rst to v4l-drivers rst file
  media: dvb headers: make checkpatch happier
  media: dvb uapi: move frontend legacy API to another part of the book
  media: pixfmt-srggb12p.rst: better format the table for PDF output
  media: docs-rst: media: Don't use \small for V4L2_PIX_FMT_SRGGB10 documentation
  media: index.rst: don't write "Contents:" on PDF output
  media: pixfmt*.rst: replace a two dots by a comma
  media: vidioc-g-fmt.rst: adjust table format
  media: vivid.rst: add a blank line to correct ReST format
  media: v4l2 uapi book: get rid of driver programming's chapter
  media: format.rst: use the right markup for important notes
  media: docs-rst: cardlists: change their format to flat-tables
  media: em28xx-cardlist.rst: update to reflect last changes
  media: v4l2-event.rst: adjust table to fit on PDF output
  media: docs: don't show ToC for each part on PDF output
  ...
This commit is contained in:
Linus Torvalds 2017-09-07 12:53:14 -07:00
commit c0da4fa0d1
888 changed files with 44749 additions and 10692 deletions

View file

@ -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

View file

@ -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

View file

@ -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;
/*
* 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 (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;
}
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;
if (entry) {
entry->msg = *msg;
/* Add new msg at the end of the queue */
list_add_tail(&entry->list, &fh->msgs);
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 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);
kfree(entry);
}
mutex_unlock(&fh->lock);
/*
* if the queue now has more than CEC_MAX_MSG_RX_QUEUE_SZ
* messages, drop the oldest one and send a lost message event.
* We lost a message, either because kmalloc failed or the queue
* was full.
*/
if (fh->queued_msgs == CEC_MAX_MSG_RX_QUEUE_SZ) {
list_del(&entry->list);
goto lost_msgs;
}
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);
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",

View file

@ -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);

View file

@ -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;

802
drivers/media/cec/cec-pin.c Normal file
View file

@ -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);

View file

@ -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,
};

View file

@ -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,

View file

@ -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,

View file

@ -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) {

View file

@ -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);
}

View file

@ -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),

View file

@ -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 +

View file

@ -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;

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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),

View file

@ -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

View file

@ -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

View file

@ -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,
};

View file

@ -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 <[email protected]>, Abylay Ospan <[email protected]>");
MODULE_LICENSE("GPL");

View file

@ -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);

View file

@ -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,
};

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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__);

View file

@ -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 */

View file

@ -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,

View file

@ -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;

View file

@ -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) {

View file

@ -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;

View file

@ -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;
}

File diff suppressed because it is too large Load diff

View file

@ -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_ */

View file

@ -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 */
};

View file

@ -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__ */

View file

@ -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,
};

View file

@ -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 (state->cab_state->state >= FE_CAB_DEMODOK)
*status |= FE_HAS_VITERBI;
if (state->cab_state->state >= FE_CAB_DATAOK)
*status |= FE_HAS_SYNC;
if (stv0367_readbits(state, (state->cab_state->qamfec_status_reg ?
state->cab_state->qamfec_status_reg : F367CAB_QAMFEC_LOCK))) {
*status |= FE_HAS_LOCK;
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_NOCARRIER)
*status |= FE_HAS_CARRIER;
if (state->cab_state->state >= FE_CAB_DEMODOK)
*status |= FE_HAS_VITERBI;
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 |

File diff suppressed because it is too large Load diff

View file

@ -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_ */

File diff suppressed because it is too large Load diff

View file

@ -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, &reg, 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, &regval);
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, &reg);
if (reg & 0x20)
read_reg(state, 2, &reg);
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");

View file

@ -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_ */

View file

@ -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,
};

View file

@ -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

View file

@ -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

View file

@ -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 },
{ }

View file

@ -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 },

View file

@ -0,0 +1,7 @@
adv748x-objs := \
adv748x-afe.o \
adv748x-core.o \
adv748x-csi2.o \
adv748x-hdmi.o
obj-$(CONFIG_VIDEO_ADV748X) += adv748x.o

View file

@ -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);
}

View file

@ -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 <[email protected]>");
MODULE_DESCRIPTION("ADV748X video decoder");
MODULE_LICENSE("GPL v2");

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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_ */

View file

@ -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 },
{ }
};

View file

@ -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;

View file

@ -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 },
{ }
};

View file

@ -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,
};

View file

@ -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;
}
/*

View file

@ -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;

View file

@ -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) ?

View file

@ -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);

View file

@ -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,

View file

@ -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,

View file

@ -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_read_reg(ov13858, OV13858_REG_DIGITAL_GAIN,
OV13858_REG_VALUE_08BIT, &val);
ret = ov13858_write_reg(ov13858, OV13858_REG_B_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_G_MWB_GAIN,
OV13858_REG_VALUE_16BIT, d_gain);
if (ret)
return ret;
return ov13858_write_reg(ov13858, OV13858_REG_DIGITAL_GAIN,
OV13858_REG_VALUE_08BIT, val);
ret = ov13858_write_reg(ov13858, OV13858_REG_R_MWB_GAIN,
OV13858_REG_VALUE_16BIT, d_gain);
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,

View file

@ -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)

View file

@ -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) {

2601
drivers/media/i2c/ov5670.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -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,

View file

@ -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)

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 },

View file

@ -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;

View file

@ -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");

View file

@ -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 },

View file

@ -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

View file

@ -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

View file

@ -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,
};

View file

@ -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},
{}
};

View file

@ -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 },
{},
};

View file

@ -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,

View file

@ -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);
}

View file

@ -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;

View file

@ -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) },
{ },
};

View file

@ -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"),

View file

@ -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},

View file

@ -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,

View file

@ -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;

View file

@ -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;
}

View file

@ -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 |

View file

@ -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,}

View file

@ -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 */

View file

@ -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);

View file

@ -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 |

View file

@ -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,}

View file

@ -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,

Some files were not shown because too many files have changed in this diff Show more