Pull media updates from Mauro Carvalho Chehab: - new framework support for HDMI CEC and remote control support - new encoding codec driver for Mediatek SoC - new frontend driver: helene tuner - added support for NetUp almost universal devices, with supports DVB-C/S/S2/T/T2 and ISDB-T - the mn88472 frontend driver got promoted from staging - a new driver for RCar video input - some soc_camera legacy drivers got removed: timb, omap1, mx2, mx3 - lots of driver cleanups, improvements and fixups * tag 'media/v4.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (377 commits) [media] cec: always check all_device_types and features [media] cec: poll should check if there is room in the tx queue [media] vivid: support monitor all mode [media] cec: fix test for unconfigured adapter in main message loop [media] cec: limit the size of the transmit queue [media] cec: zero unused msg part after msg->len [media] cec: don't set fh to NULL in CEC_TRANSMIT [media] cec: clear all status fields before transmit and always fill in sequence [media] cec: CEC_RECEIVE overwrote the timeout field [media] cxd2841er: Reading SNR for DVB-C added [media] cxd2841er: Reading BER and UCB for DVB-C added [media] cxd2841er: fix switch-case for DVB-C [media] cxd2841er: fix signal strength scale for ISDB-T [media] cxd2841er: adjust the dB scale for DVB-C [media] cxd2841er: provide signal strength for DVB-C [media] cxd2841er: fix BER report via DVBv5 stats API [media] mb86a20s: apply mask to val after checking for read failure [media] airspy: fix error logic during device register [media] s5p-cec/TODO: add TODO item [media] cec/TODO: drop comment about sphinx documentation ...
Unified · Split
| @@ -300,6 +300,9 @@ X!Isound/sound_firmware.c · 299 unmodified lines | ||
| 300 | 300 | !Iinclude/media/media-devnode.h |
| 301 | 301 | !Iinclude/media/media-entity.h |
| 302 | 302 | </sect1> |
| 303 | + <sect1><title>Consumer Electronics Control devices</title> | |
| 304 | +!Iinclude/media/cec-edid.h | |
| 305 | + </sect1> | |
| 303 | 306 | |
| 304 | 307 | </chapter> |
| 305 | 308 | |
| @@ -64,6 +64,7 @@ IOCTLS = \ · 63 unmodified lines | ||
| 64 | 64 | $(shell perl -ne 'print "$$1 " if /\#define\s+([A-Z][^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/net.h) \ |
| 65 | 65 | $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/video.h) \ |
| 66 | 66 | $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/media.h) \ |
| 67 | + $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/cec.h) \ | |
| 67 | 68 | $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \ |
| 68 | 69 | |
| 69 | 70 | DEFINES = \ |
| @@ -100,6 +101,7 @@ STRUCTS = \ · 30 unmodified lines | ||
| 100 | 101 | $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/ && !/_old/)' $(srctree)/include/uapi/linux/dvb/net.h) \ |
| 101 | 102 | $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/video.h) \ |
| 102 | 103 | $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/media.h) \ |
| 104 | + $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/cec.h) \ | |
| 103 | 105 | $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \ |
| 104 | 106 | $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-mediabus.h) |
| 105 | 107 | |
| @@ -342,6 +342,16 @@ in the frequency range from 87,5 to 108,0 MHz</title> · 341 unmodified lines | ||
| 342 | 342 | <subtitle>Specification Version 1.4a</subtitle> |
| 343 | 343 | </biblioentry> |
| 344 | 344 | |
| 345 | + <biblioentry id="hdmi2"> | |
| 346 | + <abbrev>HDMI2</abbrev> | |
| 347 | + <authorgroup> | |
| 348 | + <corpauthor>HDMI Licensing LLC | |
| 349 | +(<ulink url="http://www.hdmi.org">http://www.hdmi.org</ulink>)</corpauthor> | |
| 350 | + </authorgroup> | |
| 351 | + <title>High-Definition Multimedia Interface</title> | |
| 352 | + <subtitle>Specification Version 2.0</subtitle> | |
| 353 | + </biblioentry> | |
| 354 | + | |
| 345 | 355 | <biblioentry id="dp"> |
| 346 | 356 | <abbrev>DP</abbrev> |
| 347 | 357 | <authorgroup> |
| @@ -0,0 +1,75 @@ | ||
| 1 | +<partinfo> | |
| 2 | + <authorgroup> | |
| 3 | + <author> | |
| 4 | + <firstname>Hans</firstname> | |
| 5 | + <surname>Verkuil</surname> | |
| 6 | + <affiliation><address><email>hans.verkuil@cisco.com</email></address></affiliation> | |
| 7 | + <contrib>Initial version.</contrib> | |
| 8 | + </author> | |
| 9 | + </authorgroup> | |
| 10 | + <copyright> | |
| 11 | + <year>2016</year> | |
| 12 | + <holder>Hans Verkuil</holder> | |
| 13 | + </copyright> | |
| 14 | + | |
| 15 | + <revhistory> | |
| 16 | + <!-- Put document revisions here, newest first. --> | |
| 17 | + <revision> | |
| 18 | + <revnumber>1.0.0</revnumber> | |
| 19 | + <date>2016-03-17</date> | |
| 20 | + <authorinitials>hv</authorinitials> | |
| 21 | + <revremark>Initial revision</revremark> | |
| 22 | + </revision> | |
| 23 | + </revhistory> | |
| 24 | +</partinfo> | |
| 25 | + | |
| 26 | +<title>CEC API</title> | |
| 27 | + | |
| 28 | +<chapter id="cec-api"> | |
| 29 | + <title>CEC: Consumer Electronics Control</title> | |
| 30 | + | |
| 31 | + <section id="cec-intro"> | |
| 32 | + <title>Introduction</title> | |
| 33 | + <para> | |
| 34 | + Note: this documents the proposed CEC API. This API is not yet finalized and | |
| 35 | + is currently only available as a staging kernel module. | |
| 36 | + </para> | |
| 37 | + <para>HDMI connectors provide a single pin for use by the Consumer Electronics | |
| 38 | + Control protocol. This protocol allows different devices connected by an HDMI cable | |
| 39 | + to communicate. The protocol for CEC version 1.4 is defined in supplements 1 (CEC) | |
| 40 | + and 2 (HEAC or HDMI Ethernet and Audio Return Channel) of the HDMI 1.4a | |
| 41 | + (<xref linkend="hdmi" />) specification and the extensions added to CEC version 2.0 | |
| 42 | + are defined in chapter 11 of the HDMI 2.0 (<xref linkend="hdmi2" />) specification. | |
| 43 | + </para> | |
| 44 | + | |
| 45 | + <para>The bitrate is very slow (effectively no more than 36 bytes per second) and | |
| 46 | + is based on the ancient AV.link protocol used in old SCART connectors. The protocol | |
| 47 | + closely resembles a crazy Rube Goldberg contraption and is an unholy mix of low and | |
| 48 | + high level messages. Some messages, especially those part of the HEAC protocol layered | |
| 49 | + on top of CEC, need to be handled by the kernel, others can be handled either by the | |
| 50 | + kernel or by userspace.</para> | |
| 51 | + | |
| 52 | + <para>In addition, CEC can be implemented in HDMI receivers, transmitters and in USB | |
| 53 | + devices that have an HDMI input and an HDMI output and that control just the CEC pin.</para> | |
| 54 | + | |
| 55 | + <para>Drivers that support CEC will create a CEC device node (/dev/cecX) | |
| 56 | + to give userspace access to the CEC adapter. The &CEC-ADAP-G-CAPS; ioctl will tell userspace | |
| 57 | + what it is allowed to do.</para> | |
| 58 | + </section> | |
| 59 | +</chapter> | |
| 60 | + | |
| 61 | +<appendix id="cec-user-func"> | |
| 62 | + <title>Function Reference</title> | |
| 63 | + <!-- Keep this alphabetically sorted. --> | |
| 64 | + &sub-cec-func-open; | |
| 65 | + &sub-cec-func-close; | |
| 66 | + &sub-cec-func-ioctl; | |
| 67 | + &sub-cec-func-poll; | |
| 68 | + <!-- All ioctls go here. --> | |
| 69 | + &sub-cec-ioc-adap-g-caps; | |
| 70 | + &sub-cec-ioc-adap-g-log-addrs; | |
| 71 | + &sub-cec-ioc-adap-g-phys-addr; | |
| 72 | + &sub-cec-ioc-dqevent; | |
| 73 | + &sub-cec-ioc-g-mode; | |
| 74 | + &sub-cec-ioc-receive; | |
| 75 | +</appendix> | |
| @@ -0,0 +1,64 @@ | ||
| 1 | +<refentry id="cec-func-close"> | |
| 2 | + <refmeta> | |
| 3 | + <refentrytitle>cec close()</refentrytitle> | |
| 4 | + &manvol; | |
| 5 | + </refmeta> | |
| 6 | + | |
| 7 | + <refnamediv> | |
| 8 | + <refname>cec-close</refname> | |
| 9 | + <refpurpose>Close a cec device</refpurpose> | |
| 10 | + </refnamediv> | |
| 11 | + | |
| 12 | + <refsynopsisdiv> | |
| 13 | + <funcsynopsis> | |
| 14 | + <funcsynopsisinfo>#include <unistd.h></funcsynopsisinfo> | |
| 15 | + <funcprototype> | |
| 16 | + <funcdef>int <function>close</function></funcdef> | |
| 17 | + <paramdef>int <parameter>fd</parameter></paramdef> | |
| 18 | + </funcprototype> | |
| 19 | + </funcsynopsis> | |
| 20 | + </refsynopsisdiv> | |
| 21 | + | |
| 22 | + <refsect1> | |
| 23 | + <title>Arguments</title> | |
| 24 | + | |
| 25 | + <variablelist> | |
| 26 | + <varlistentry> | |
| 27 | + <term><parameter>fd</parameter></term> | |
| 28 | + <listitem> | |
| 29 | + <para>&fd;</para> | |
| 30 | + </listitem> | |
| 31 | + </varlistentry> | |
| 32 | + </variablelist> | |
| 33 | + </refsect1> | |
| 34 | + | |
| 35 | + <refsect1> | |
| 36 | + <title>Description</title> | |
| 37 | + | |
| 38 | + <para> | |
| 39 | + Note: this documents the proposed CEC API. This API is not yet finalized and | |
| 40 | + is currently only available as a staging kernel module. | |
| 41 | + </para> | |
| 42 | + | |
| 43 | + <para>Closes the cec device. Resources associated with the file descriptor | |
| 44 | + are freed. The device configuration remain unchanged.</para> | |
| 45 | + </refsect1> | |
| 46 | + | |
| 47 | + <refsect1> | |
| 48 | + <title>Return Value</title> | |
| 49 | + | |
| 50 | + <para><function>close</function> returns 0 on success. On error, -1 is | |
| 51 | + returned, and <varname>errno</varname> is set appropriately. Possible error | |
| 52 | + codes are:</para> | |
| 53 | + | |
| 54 | + <variablelist> | |
| 55 | + <varlistentry> | |
| 56 | + <term><errorcode>EBADF</errorcode></term> | |
| 57 | + <listitem> | |
| 58 | + <para><parameter>fd</parameter> is not a valid open file descriptor. | |
| 59 | + </para> | |
| 60 | + </listitem> | |
| 61 | + </varlistentry> | |
| 62 | + </variablelist> | |
| 63 | + </refsect1> | |
| 64 | +</refentry> | |
| @@ -0,0 +1,78 @@ | ||
| 1 | +<refentry id="cec-func-ioctl"> | |
| 2 | + <refmeta> | |
| 3 | + <refentrytitle>cec ioctl()</refentrytitle> | |
| 4 | + &manvol; | |
| 5 | + </refmeta> | |
| 6 | + | |
| 7 | + <refnamediv> | |
| 8 | + <refname>cec-ioctl</refname> | |
| 9 | + <refpurpose>Control a cec device</refpurpose> | |
| 10 | + </refnamediv> | |
| 11 | + | |
| 12 | + <refsynopsisdiv> | |
| 13 | + <funcsynopsis> | |
| 14 | + <funcsynopsisinfo>#include <sys/ioctl.h></funcsynopsisinfo> | |
| 15 | + <funcprototype> | |
| 16 | + <funcdef>int <function>ioctl</function></funcdef> | |
| 17 | + <paramdef>int <parameter>fd</parameter></paramdef> | |
| 18 | + <paramdef>int <parameter>request</parameter></paramdef> | |
| 19 | + <paramdef>void *<parameter>argp</parameter></paramdef> | |
| 20 | + </funcprototype> | |
| 21 | + </funcsynopsis> | |
| 22 | + </refsynopsisdiv> | |
| 23 | + | |
| 24 | + <refsect1> | |
| 25 | + <title>Arguments</title> | |
| 26 | + | |
| 27 | + <variablelist> | |
| 28 | + <varlistentry> | |
| 29 | + <term><parameter>fd</parameter></term> | |
| 30 | + <listitem> | |
| 31 | + <para>&fd;</para> | |
| 32 | + </listitem> | |
| 33 | + </varlistentry> | |
| 34 | + <varlistentry> | |
| 35 | + <term><parameter>request</parameter></term> | |
| 36 | + <listitem> | |
| 37 | + <para>CEC ioctl request code as defined in the cec.h header file, | |
| 38 | + for example CEC_ADAP_G_CAPS.</para> | |
| 39 | + </listitem> | |
| 40 | + </varlistentry> | |
| 41 | + <varlistentry> | |
| 42 | + <term><parameter>argp</parameter></term> | |
| 43 | + <listitem> | |
| 44 | + <para>Pointer to a request-specific structure.</para> | |
| 45 | + </listitem> | |
| 46 | + </varlistentry> | |
| 47 | + </variablelist> | |
| 48 | + </refsect1> | |
| 49 | + | |
| 50 | + <refsect1> | |
| 51 | + <title>Description</title> | |
| 52 | + <para> | |
| 53 | + Note: this documents the proposed CEC API. This API is not yet finalized and | |
| 54 | + is currently only available as a staging kernel module. | |
| 55 | + </para> | |
| 56 | + | |
| 57 | + <para>The <function>ioctl()</function> function manipulates cec device | |
| 58 | + parameters. The argument <parameter>fd</parameter> must be an open file | |
| 59 | + descriptor.</para> | |
| 60 | + <para>The ioctl <parameter>request</parameter> code specifies the cec | |
| 61 | + function to be called. It has encoded in it whether the argument is an | |
| 62 | + input, output or read/write parameter, and the size of the argument | |
| 63 | + <parameter>argp</parameter> in bytes.</para> | |
| 64 | + <para>Macros and structures definitions specifying cec ioctl requests and | |
| 65 | + their parameters are located in the cec.h header file. All cec ioctl | |
| 66 | + requests, their respective function and parameters are specified in | |
| 67 | + <xref linkend="cec-user-func" />.</para> | |
| 68 | + </refsect1> | |
| 69 | + | |
| 70 | + <refsect1> | |
| 71 | + &return-value; | |
| 72 | + | |
| 73 | + <para>Request-specific error codes are listed in the | |
| 74 | + individual requests descriptions.</para> | |
| 75 | + <para>When an ioctl that takes an output or read/write parameter fails, | |
| 76 | + the parameter remains unmodified.</para> | |
| 77 | + </refsect1> | |
| 78 | +</refentry> | |
| @@ -0,0 +1,104 @@ | ||
| 1 | +<refentry id="cec-func-open"> | |
| 2 | + <refmeta> | |
| 3 | + <refentrytitle>cec open()</refentrytitle> | |
| 4 | + &manvol; | |
| 5 | + </refmeta> | |
| 6 | + | |
| 7 | + <refnamediv> | |
| 8 | + <refname>cec-open</refname> | |
| 9 | + <refpurpose>Open a cec device</refpurpose> | |
| 10 | + </refnamediv> | |
| 11 | + | |
| 12 | + <refsynopsisdiv> | |
| 13 | + <funcsynopsis> | |
| 14 | + <funcsynopsisinfo>#include <fcntl.h></funcsynopsisinfo> | |
| 15 | + <funcprototype> | |
| 16 | + <funcdef>int <function>open</function></funcdef> | |
| 17 | + <paramdef>const char *<parameter>device_name</parameter></paramdef> | |
| 18 | + <paramdef>int <parameter>flags</parameter></paramdef> | |
| 19 | + </funcprototype> | |
| 20 | + </funcsynopsis> | |
| 21 | + </refsynopsisdiv> | |
| 22 | + | |
| 23 | + <refsect1> | |
| 24 | + <title>Arguments</title> | |
| 25 | + | |
| 26 | + <variablelist> | |
| 27 | + <varlistentry> | |
| 28 | + <term><parameter>device_name</parameter></term> | |
| 29 | + <listitem> | |
| 30 | + <para>Device to be opened.</para> | |
| 31 | + </listitem> | |
| 32 | + </varlistentry> | |
| 33 | + <varlistentry> | |
| 34 | + <term><parameter>flags</parameter></term> | |
| 35 | + <listitem> | |
| 36 | + <para>Open flags. Access mode must be <constant>O_RDWR</constant>. | |
| 37 | + </para> | |
| 38 | + <para>When the <constant>O_NONBLOCK</constant> flag is | |
| 39 | +given, the &CEC-RECEIVE; ioctl will return &EAGAIN; when no message is | |
| 40 | +available, and the &CEC-TRANSMIT;, &CEC-ADAP-S-PHYS-ADDR; and | |
| 41 | +&CEC-ADAP-S-LOG-ADDRS; ioctls all act in non-blocking mode.</para> | |
| 42 | + <para>Other flags have no effect.</para> | |
| 43 | + </listitem> | |
| 44 | + </varlistentry> | |
| 45 | + </variablelist> | |
| 46 | + </refsect1> | |
| 47 | + <refsect1> | |
| 48 | + <title>Description</title> | |
| 49 | + <para> | |
| 50 | + Note: this documents the proposed CEC API. This API is not yet finalized and | |
| 51 | + is currently only available as a staging kernel module. | |
| 52 | + </para> | |
| 53 | + | |
| 54 | + <para>To open a cec device applications call <function>open()</function> | |
| 55 | + with the desired device name. The function has no side effects; the device | |
| 56 | + configuration remain unchanged.</para> | |
| 57 | + <para>When the device is opened in read-only mode, attempts to modify its | |
| 58 | + configuration will result in an error, and <varname>errno</varname> will be | |
| 59 | + set to <errorcode>EBADF</errorcode>.</para> | |
| 60 | + </refsect1> | |
| 61 | + <refsect1> | |
| 62 | + <title>Return Value</title> | |
| 63 | + | |
| 64 | + <para><function>open</function> returns the new file descriptor on success. | |
| 65 | + On error, -1 is returned, and <varname>errno</varname> is set appropriately. | |
| 66 | + Possible error codes include:</para> | |
| 67 | + | |
| 68 | + <variablelist> | |
| 69 | + <varlistentry> | |
| 70 | + <term><errorcode>EACCES</errorcode></term> | |
| 71 | + <listitem> | |
| 72 | + <para>The requested access to the file is not allowed.</para> | |
| 73 | + </listitem> | |
| 74 | + </varlistentry> | |
| 75 | + <varlistentry> | |
| 76 | + <term><errorcode>EMFILE</errorcode></term> | |
| 77 | + <listitem> | |
| 78 | + <para>The process already has the maximum number of files open. | |
| 79 | + </para> | |
| 80 | + </listitem> | |
| 81 | + </varlistentry> | |
| 82 | + <varlistentry> | |
| 83 | + <term><errorcode>ENFILE</errorcode></term> | |
| 84 | + <listitem> | |
| 85 | + <para>The system limit on the total number of open files has been | |
| 86 | + reached.</para> | |
| 87 | + </listitem> | |
| 88 | + </varlistentry> | |
| 89 | + <varlistentry> | |
| 90 | + <term><errorcode>ENOMEM</errorcode></term> | |
| 91 | + <listitem> | |
| 92 | + <para>Insufficient kernel memory was available.</para> | |
| 93 | + </listitem> | |
| 94 | + </varlistentry> | |
| 95 | + <varlistentry> | |
| 96 | + <term><errorcode>ENXIO</errorcode></term> | |
| 97 | + <listitem> | |
| 98 | + <para>No device corresponding to this device special file exists. | |
| 99 | + </para> | |
| 100 | + </listitem> | |
| 101 | + </varlistentry> | |
| 102 | + </variablelist> | |
| 103 | + </refsect1> | |
| 104 | +</refentry> | |
| @@ -0,0 +1,94 @@ | ||
| 1 | +<refentry id="cec-func-poll"> | |
| 2 | + <refmeta> | |
| 3 | + <refentrytitle>cec poll()</refentrytitle> | |
| 4 | + &manvol; | |
| 5 | + </refmeta> | |
| 6 | + | |
| 7 | + <refnamediv> | |
| 8 | + <refname>cec-poll</refname> | |
| 9 | + <refpurpose>Wait for some event on a file descriptor</refpurpose> | |
| 10 | + </refnamediv> | |
| 11 | + | |
| 12 | + <refsynopsisdiv> | |
| 13 | + <funcsynopsis> | |
| 14 | + <funcsynopsisinfo>#include <sys/poll.h></funcsynopsisinfo> | |
| 15 | + <funcprototype> | |
| 16 | + <funcdef>int <function>poll</function></funcdef> | |
| 17 | + <paramdef>struct pollfd *<parameter>ufds</parameter></paramdef> | |
| 18 | + <paramdef>unsigned int <parameter>nfds</parameter></paramdef> | |
| 19 | + <paramdef>int <parameter>timeout</parameter></paramdef> | |
| 20 | + </funcprototype> | |
| 21 | + </funcsynopsis> | |
| 22 | + </refsynopsisdiv> | |
| 23 | + | |
| 24 | + <refsect1> | |
| 25 | + <title>Description</title> | |
| 26 | + | |
| 27 | + <para> | |
| 28 | + Note: this documents the proposed CEC API. This API is not yet finalized and | |
| 29 | + is currently only available as a staging kernel module. | |
| 30 | + </para> | |
| 31 | + | |
| 32 | + <para>With the <function>poll()</function> function applications | |
| 33 | +can wait for CEC events.</para> | |
| 34 | + | |
| 35 | + <para>On success <function>poll()</function> returns the number of | |
| 36 | +file descriptors that have been selected (that is, file descriptors | |
| 37 | +for which the <structfield>revents</structfield> field of the | |
| 38 | +respective <structname>pollfd</structname> structure is non-zero). | |
| 39 | +CEC devices set the <constant>POLLIN</constant> and | |
| 40 | +<constant>POLLRDNORM</constant> flags in the | |
| 41 | +<structfield>revents</structfield> field if there are messages in the | |
| 42 | +receive queue. If the transmit queue has room for new messages, the | |
| 43 | +<constant>POLLOUT</constant> and <constant>POLLWRNORM</constant> | |
| 44 | +flags are set. If there are events in the event queue, then the | |
| 45 | +<constant>POLLPRI</constant> flag is set. | |
| 46 | +When the function timed out it returns a value of zero, on | |
| 47 | +failure it returns <returnvalue>-1</returnvalue> and the | |
| 48 | +<varname>errno</varname> variable is set appropriately. | |
| 49 | +</para> | |
| 50 | + | |
| 51 | + <para>For more details see the | |
| 52 | +<function>poll()</function> manual page.</para> | |
| 53 | + </refsect1> | |
| 54 | + | |
| 55 | + <refsect1> | |
| 56 | + <title>Return Value</title> | |
| 57 | + | |
| 58 | + <para>On success, <function>poll()</function> returns the number | |
| 59 | +structures which have non-zero <structfield>revents</structfield> | |
| 60 | +fields, or zero if the call timed out. On error | |
| 61 | +<returnvalue>-1</returnvalue> is returned, and the | |
| 62 | +<varname>errno</varname> variable is set appropriately:</para> | |
| 63 | + | |
| 64 | + <variablelist> | |
| 65 | + <varlistentry> | |
| 66 | + <term><errorcode>EBADF</errorcode></term> | |
| 67 | + <listitem> | |
| 68 | + <para>One or more of the <parameter>ufds</parameter> members | |
| 69 | +specify an invalid file descriptor.</para> | |
| 70 | + </listitem> | |
| 71 | + </varlistentry> | |
| 72 | + <varlistentry> | |
| 73 | + <term><errorcode>EFAULT</errorcode></term> | |
| 74 | + <listitem> | |
| 75 | + <para><parameter>ufds</parameter> references an inaccessible | |
| 76 | +memory area.</para> | |
| 77 | + </listitem> | |
| 78 | + </varlistentry> | |
| 79 | + <varlistentry> | |
| 80 | + <term><errorcode>EINTR</errorcode></term> | |
| 81 | + <listitem> | |
| 82 | + <para>The call was interrupted by a signal.</para> | |
| 83 | + </listitem> | |
| 84 | + </varlistentry> | |
| 85 | + <varlistentry> | |
| 86 | + <term><errorcode>EINVAL</errorcode></term> | |
| 87 | + <listitem> | |
| 88 | + <para>The <parameter>nfds</parameter> argument is greater | |
| 89 | +than <constant>OPEN_MAX</constant>.</para> | |
| 90 | + </listitem> | |
| 91 | + </varlistentry> | |
| 92 | + </variablelist> | |
| 93 | + </refsect1> | |
| 94 | +</refentry> | |
| @@ -0,0 +1,151 @@ | ||
| 1 | +<refentry id="cec-ioc-adap-g-caps"> | |
| 2 | + <refmeta> | |
| 3 | + <refentrytitle>ioctl CEC_ADAP_G_CAPS</refentrytitle> | |
| 4 | + &manvol; | |
| 5 | + </refmeta> | |
| 6 | + | |
| 7 | + <refnamediv> | |
| 8 | + <refname>CEC_ADAP_G_CAPS</refname> | |
| 9 | + <refpurpose>Query device capabilities</refpurpose> | |
| 10 | + </refnamediv> | |
| 11 | + | |
| 12 | + <refsynopsisdiv> | |
| 13 | + <funcsynopsis> | |
| 14 | + <funcprototype> | |
| 15 | + <funcdef>int <function>ioctl</function></funcdef> | |
| 16 | + <paramdef>int <parameter>fd</parameter></paramdef> | |
| 17 | + <paramdef>int <parameter>request</parameter></paramdef> | |
| 18 | + <paramdef>struct cec_caps *<parameter>argp</parameter></paramdef> | |
| 19 | + </funcprototype> | |
| 20 | + </funcsynopsis> | |
| 21 | + </refsynopsisdiv> | |
| 22 | + | |
| 23 | + <refsect1> | |
| 24 | + <title>Arguments</title> | |
| 25 | + | |
| 26 | + <variablelist> | |
| 27 | + <varlistentry> | |
| 28 | + <term><parameter>fd</parameter></term> | |
| 29 | + <listitem> | |
| 30 | + <para>File descriptor returned by | |
| 31 | + <link linkend='cec-func-open'><function>open()</function></link>.</para> | |
| 32 | + </listitem> | |
| 33 | + </varlistentry> | |
| 34 | + <varlistentry> | |
| 35 | + <term><parameter>request</parameter></term> | |
| 36 | + <listitem> | |
| 37 | + <para>CEC_ADAP_G_CAPS</para> | |
| 38 | + </listitem> | |
| 39 | + </varlistentry> | |
| 40 | + <varlistentry> | |
| 41 | + <term><parameter>argp</parameter></term> | |
| 42 | + <listitem> | |
| 43 | + <para></para> | |
| 44 | + </listitem> | |
| 45 | + </varlistentry> | |
| 46 | + </variablelist> | |
| 47 | + </refsect1> | |
| 48 | + | |
| 49 | + <refsect1> | |
| 50 | + <title>Description</title> | |
| 51 | + | |
| 52 | + <para> | |
| 53 | + Note: this documents the proposed CEC API. This API is not yet finalized and | |
| 54 | + is currently only available as a staging kernel module. | |
| 55 | + </para> | |
| 56 | + | |
| 57 | + <para>All cec devices must support the <constant>CEC_ADAP_G_CAPS</constant> | |
| 58 | + ioctl. To query device information, applications call the ioctl with a | |
| 59 | + pointer to a &cec-caps;. The driver fills the structure and returns | |
| 60 | + the information to the application. | |
| 61 | + The ioctl never fails.</para> | |
| 62 | + | |
| 63 | + <table pgwide="1" frame="none" id="cec-caps"> | |
| 64 | + <title>struct <structname>cec_caps</structname></title> | |
| 65 | + <tgroup cols="3"> | |
| 66 | + &cs-str; | |
| 67 | + <tbody valign="top"> | |
| 68 | + <row> | |
| 69 | + <entry>char</entry> | |
| 70 | + <entry><structfield>driver[32]</structfield></entry> | |
| 71 | + <entry>The name of the cec adapter driver.</entry> | |
| 72 | + </row> | |
| 73 | + <row> | |
| 74 | + <entry>char</entry> | |
| 75 | + <entry><structfield>name[32]</structfield></entry> | |
| 76 | + <entry>The name of this CEC adapter. The combination <structfield>driver</structfield> | |
| 77 | + and <structfield>name</structfield> must be unique.</entry> | |
| 78 | + </row> | |
| 79 | + <row> | |
| 80 | + <entry>__u32</entry> | |
| 81 | + <entry><structfield>capabilities</structfield></entry> | |
| 82 | + <entry>The capabilities of the CEC adapter, see <xref | |
| 83 | + linkend="cec-capabilities" />.</entry> | |
| 84 | + </row> | |
| 85 | + <row> | |
| 86 | + <entry>__u32</entry> | |
| 87 | + <entry><structfield>version</structfield></entry> | |
| 88 | + <entry>CEC Framework API version, formatted with the | |
| 89 | + <constant>KERNEL_VERSION()</constant> macro.</entry> | |
| 90 | + </row> | |
| 91 | + </tbody> | |
| 92 | + </tgroup> | |
| 93 | + </table> | |
| 94 | + | |
| 95 | + <table pgwide="1" frame="none" id="cec-capabilities"> | |
| 96 | + <title>CEC Capabilities Flags</title> | |
| 97 | + <tgroup cols="3"> | |
| 98 | + &cs-def; | |
| 99 | + <tbody valign="top"> | |
| 100 | + <row> | |
| 101 | + <entry><constant>CEC_CAP_PHYS_ADDR</constant></entry> | |
| 102 | + <entry>0x00000001</entry> | |
| 103 | + <entry>Userspace has to configure the physical address by | |
| 104 | + calling &CEC-ADAP-S-PHYS-ADDR;. If this capability isn't set, | |
| 105 | + then setting the physical address is handled by the kernel | |
| 106 | + whenever the EDID is set (for an HDMI receiver) or read (for | |
| 107 | + an HDMI transmitter).</entry> | |
| 108 | + </row> | |
| 109 | + <row> | |
| 110 | + <entry><constant>CEC_CAP_LOG_ADDRS</constant></entry> | |
| 111 | + <entry>0x00000002</entry> | |
| 112 | + <entry>Userspace has to configure the logical addresses by | |
| 113 | + calling &CEC-ADAP-S-LOG-ADDRS;. If this capability isn't set, | |
| 114 | + then the kernel will have configured this.</entry> | |
| 115 | + </row> | |
| 116 | + <row> | |
| 117 | + <entry><constant>CEC_CAP_TRANSMIT</constant></entry> | |
| 118 | + <entry>0x00000004</entry> | |
| 119 | + <entry>Userspace can transmit CEC messages by calling &CEC-TRANSMIT;. This | |
| 120 | + implies that userspace can be a follower as well, since being able to | |
| 121 | + transmit messages is a prerequisite of becoming a follower. If this | |
| 122 | + capability isn't set, then the kernel will handle all CEC transmits | |
| 123 | + and process all CEC messages it receives. | |
| 124 | + </entry> | |
| 125 | + </row> | |
| 126 | + <row> | |
| 127 | + <entry><constant>CEC_CAP_PASSTHROUGH</constant></entry> | |
| 128 | + <entry>0x00000008</entry> | |
| 129 | + <entry>Userspace can use the passthrough mode by | |
| 130 | + calling &CEC-S-MODE;.</entry> | |
| 131 | + </row> | |
| 132 | + <row> | |
| 133 | + <entry><constant>CEC_CAP_RC</constant></entry> | |
| 134 | + <entry>0x00000010</entry> | |
| 135 | + <entry>This adapter supports the remote control protocol.</entry> | |
| 136 | + </row> | |
| 137 | + <row> | |
| 138 | + <entry><constant>CEC_CAP_MONITOR_ALL</constant></entry> | |
| 139 | + <entry>0x00000020</entry> | |
| 140 | + <entry>The CEC hardware can monitor all messages, not just directed and | |
| 141 | + broadcast messages.</entry> | |
| 142 | + </row> | |
| 143 | + </tbody> | |
| 144 | + </tgroup> | |
| 145 | + </table> | |
| 146 | + </refsect1> | |
| 147 | + | |
| 148 | + <refsect1> | |
| 149 | + &return-value; | |
| 150 | + </refsect1> | |
| 151 | +</refentry> | |
| @@ -0,0 +1,329 @@ | ||
| 1 | +<refentry id="cec-ioc-adap-g-log-addrs"> | |
| 2 | + <refmeta> | |
| 3 | + <refentrytitle>ioctl CEC_ADAP_G_LOG_ADDRS, CEC_ADAP_S_LOG_ADDRS</refentrytitle> | |
| 4 | + &manvol; | |
| 5 | + </refmeta> | |
| 6 | + | |
| 7 | + <refnamediv> | |
| 8 | + <refname>CEC_ADAP_G_LOG_ADDRS</refname> | |
| 9 | + <refname>CEC_ADAP_S_LOG_ADDRS</refname> | |
| 10 | + <refpurpose>Get or set the logical addresses</refpurpose> | |
| 11 | + </refnamediv> | |
| 12 | + | |
| 13 | + <refsynopsisdiv> | |
| 14 | + <funcsynopsis> | |
| 15 | + <funcprototype> | |
| 16 | + <funcdef>int <function>ioctl</function></funcdef> | |
| 17 | + <paramdef>int <parameter>fd</parameter></paramdef> | |
| 18 | + <paramdef>int <parameter>request</parameter></paramdef> | |
| 19 | + <paramdef>struct cec_log_addrs *<parameter>argp</parameter></paramdef> | |
| 20 | + </funcprototype> | |
| 21 | + </funcsynopsis> | |
| 22 | + </refsynopsisdiv> | |
| 23 | + | |
| 24 | + <refsect1> | |
| 25 | + <title>Arguments</title> | |
| 26 | + | |
| 27 | + <variablelist> | |
| 28 | + <varlistentry> | |
| 29 | + <term><parameter>fd</parameter></term> | |
| 30 | + <listitem> | |
| 31 | + <para>File descriptor returned by | |
| 32 | + <link linkend='cec-func-open'><function>open()</function></link>.</para> | |
| 33 | + </listitem> | |
| 34 | + </varlistentry> | |
| 35 | + <varlistentry> | |
| 36 | + <term><parameter>request</parameter></term> | |
| 37 | + <listitem> | |
| 38 | + <para>CEC_ADAP_G_LOG_ADDRS, CEC_ADAP_S_LOG_ADDRS</para> | |
| 39 | + </listitem> | |
| 40 | + </varlistentry> | |
| 41 | + <varlistentry> | |
| 42 | + <term><parameter>argp</parameter></term> | |
| 43 | + <listitem> | |
| 44 | + <para></para> | |
| 45 | + </listitem> | |
| 46 | + </varlistentry> | |
| 47 | + </variablelist> | |
| 48 | + </refsect1> | |
| 49 | + | |
| 50 | + <refsect1> | |
| 51 | + <title>Description</title> | |
| 52 | + | |
| 53 | + <para> | |
| 54 | + Note: this documents the proposed CEC API. This API is not yet finalized and | |
| 55 | + is currently only available as a staging kernel module. | |
| 56 | + </para> | |
| 57 | + | |
| 58 | + <para>To query the current CEC logical addresses, applications call the | |
| 59 | +<constant>CEC_ADAP_G_LOG_ADDRS</constant> ioctl with a pointer to a | |
| 60 | +<structname>cec_log_addrs</structname> structure where the drivers stores the | |
| 61 | +logical addresses.</para> | |
| 62 | + | |
| 63 | + <para>To set new logical addresses, applications fill in struct <structname>cec_log_addrs</structname> | |
| 64 | +and call the <constant>CEC_ADAP_S_LOG_ADDRS</constant> ioctl with a pointer to this struct. | |
| 65 | +The <constant>CEC_ADAP_S_LOG_ADDRS</constant> ioctl is only available if | |
| 66 | +<constant>CEC_CAP_LOG_ADDRS</constant> is set (&ENOTTY; is returned otherwise). This ioctl will block until all | |
| 67 | +requested logical addresses have been claimed. <constant>CEC_ADAP_S_LOG_ADDRS</constant> | |
| 68 | +can only be called by a file handle in initiator mode (see &CEC-S-MODE;).</para> | |
| 69 | + | |
| 70 | + <table pgwide="1" frame="none" id="cec-log-addrs"> | |
| 71 | + <title>struct <structname>cec_log_addrs</structname></title> | |
| 72 | + <tgroup cols="3"> | |
| 73 | + &cs-str; | |
| 74 | + <tbody valign="top"> | |
| 75 | + <row> | |
| 76 | + <entry>__u8</entry> | |
| 77 | + <entry><structfield>log_addr</structfield>[CEC_MAX_LOG_ADDRS]</entry> | |
| 78 | + <entry>The actual logical addresses that were claimed. This is set by the | |
| 79 | + driver. If no logical address could be claimed, then it is set to | |
| 80 | + <constant>CEC_LOG_ADDR_INVALID</constant>. If this adapter is Unregistered, | |
| 81 | + then <structfield>log_addr[0]</structfield> is set to 0xf and all others to | |
| 82 | + <constant>CEC_LOG_ADDR_INVALID</constant>.</entry> | |
| 83 | + </row> | |
| 84 | + <row> | |
| 85 | + <entry>__u16</entry> | |
| 86 | + <entry><structfield>log_addr_mask</structfield></entry> | |
| 87 | + <entry>The bitmask of all logical addresses this adapter has claimed. | |
| 88 | + If this adapter is Unregistered then <structfield>log_addr_mask</structfield> | |
| 89 | + sets bit 15 and clears all other bits. If this adapter is not configured at all, then | |
| 90 | + <structfield>log_addr_mask</structfield> is set to 0. Set by the driver.</entry> | |
| 91 | + </row> | |
| 92 | + <row> | |
| 93 | + <entry>__u8</entry> | |
| 94 | + <entry><structfield>cec_version</structfield></entry> | |
| 95 | + <entry>The CEC version that this adapter shall use. See | |
| 96 | + <xref linkend="cec-versions" />. | |
| 97 | + Used to implement the <constant>CEC_MSG_CEC_VERSION</constant> and | |
| 98 | + <constant>CEC_MSG_REPORT_FEATURES</constant> messages. Note that | |
| 99 | + <constant>CEC_OP_CEC_VERSION_1_3A</constant> is not allowed | |
| 100 | + by the CEC framework. | |
| 101 | + </entry> | |
| 102 | + </row> | |
| 103 | + <row> | |
| 104 | + <entry>__u8</entry> | |
| 105 | + <entry><structfield>num_log_addrs</structfield></entry> | |
| 106 | + <entry>Number of logical addresses to set up. Must be ≤ | |
| 107 | + <structfield>available_log_addrs</structfield> as returned by | |
| 108 | + &CEC-ADAP-G-CAPS;. All arrays in this structure are only filled up to | |
| 109 | + index <structfield>available_log_addrs</structfield>-1. The remaining | |
| 110 | + array elements will be ignored. Note that the CEC 2.0 standard allows | |
| 111 | + for a maximum of 2 logical addresses, although some hardware has support | |
| 112 | + for more. <constant>CEC_MAX_LOG_ADDRS</constant> is 4. The driver will | |
| 113 | + return the actual number of logical addresses it could claim, which may | |
| 114 | + be less than what was requested. If this field is set to 0, then the | |
| 115 | + CEC adapter shall clear all claimed logical addresses and all other | |
| 116 | + fields will be ignored.</entry> | |
| 117 | + </row> | |
| 118 | + <row> | |
| 119 | + <entry>__u32</entry> | |
| 120 | + <entry><structfield>vendor_id</structfield></entry> | |
| 121 | + <entry>The vendor ID is a 24-bit number that identifies the specific | |
| 122 | + vendor or entity. Based on this ID vendor specific commands may be | |
| 123 | + defined. If you do not want a vendor ID then set it to | |
| 124 | + <constant>CEC_VENDOR_ID_NONE</constant>.</entry> | |
| 125 | + </row> | |
| 126 | + <row> | |
| 127 | + <entry>__u32</entry> | |
| 128 | + <entry><structfield>flags</structfield></entry> | |
| 129 | + <entry>Flags. No flags are defined yet, so set this to 0.</entry> | |
| 130 | + </row> | |
| 131 | + <row> | |
| 132 | + <entry>char</entry> | |
| 133 | + <entry><structfield>osd_name</structfield>[15]</entry> | |
| 134 | + <entry>The On-Screen Display name as is returned by the | |
| 135 | + <constant>CEC_MSG_SET_OSD_NAME</constant> message.</entry> | |
| 136 | + </row> | |
| 137 | + <row> | |
| 138 | + <entry>__u8</entry> | |
| 139 | + <entry><structfield>primary_device_type</structfield>[CEC_MAX_LOG_ADDRS]</entry> | |
| 140 | + <entry>Primary device type for each logical address. See | |
| 141 | + <xref linkend="cec-prim-dev-types" /> for possible types.</entry> | |
| 142 | + </row> | |
| 143 | + <row> | |
| 144 | + <entry>__u8</entry> | |
| 145 | + <entry><structfield>log_addr_type</structfield>[CEC_MAX_LOG_ADDRS]</entry> | |
| 146 | + <entry>Logical address types. See <xref linkend="cec-log-addr-types" /> for | |
| 147 | + possible types. The driver will update this with the actual logical address | |
| 148 | + type that it claimed (e.g. it may have to fallback to | |
| 149 | + <constant>CEC_LOG_ADDR_TYPE_UNREGISTERED</constant>).</entry> | |
| 150 | + </row> | |
| 151 | + <row> | |
| 152 | + <entry>__u8</entry> | |
| 153 | + <entry><structfield>all_device_types</structfield>[CEC_MAX_LOG_ADDRS]</entry> | |
| 154 | + <entry>CEC 2.0 specific: all device types. See <xref linkend="cec-all-dev-types-flags" />. | |
| 155 | + Used to implement the <constant>CEC_MSG_REPORT_FEATURES</constant> message. | |
| 156 | + This field is ignored if <structfield>cec_version</structfield> < | |
| 157 | + <constant>CEC_OP_CEC_VERSION_2_0</constant>.</entry> | |
| 158 | + </row> | |
| 159 | + <row> | |
| 160 | + <entry>__u8</entry> | |
| 161 | + <entry><structfield>features</structfield>[CEC_MAX_LOG_ADDRS][12]</entry> | |
| 162 | + <entry>Features for each logical address. Used to implement the | |
| 163 | + <constant>CEC_MSG_REPORT_FEATURES</constant> message. The 12 bytes include | |
| 164 | + both the RC Profile and the Device Features. | |
| 165 | + This field is ignored if <structfield>cec_version</structfield> < | |
| 166 | + <constant>CEC_OP_CEC_VERSION_2_0</constant>.</entry> | |
| 167 | + </row> | |
| 168 | + </tbody> | |
| 169 | + </tgroup> | |
| 170 | + </table> | |
| 171 | + | |
| 172 | + <table pgwide="1" frame="none" id="cec-versions"> | |
| 173 | + <title>CEC Versions</title> | |
| 174 | + <tgroup cols="3"> | |
| 175 | + &cs-def; | |
| 176 | + <tbody valign="top"> | |
| 177 | + <row> | |
| 178 | + <entry><constant>CEC_OP_CEC_VERSION_1_3A</constant></entry> | |
| 179 | + <entry>4</entry> | |
| 180 | + <entry>CEC version according to the HDMI 1.3a standard.</entry> | |
| 181 | + </row> | |
| 182 | + <row> | |
| 183 | + <entry><constant>CEC_OP_CEC_VERSION_1_4B</constant></entry> | |
| 184 | + <entry>5</entry> | |
| 185 | + <entry>CEC version according to the HDMI 1.4b standard.</entry> | |
| 186 | + </row> | |
| 187 | + <row> | |
| 188 | + <entry><constant>CEC_OP_CEC_VERSION_2_0</constant></entry> | |
| 189 | + <entry>6</entry> | |
| 190 | + <entry>CEC version according to the HDMI 2.0 standard.</entry> | |
| 191 | + </row> | |
| 192 | + </tbody> | |
| 193 | + </tgroup> | |
| 194 | + </table> | |
| 195 | + | |
| 196 | + <table pgwide="1" frame="none" id="cec-prim-dev-types"> | |
| 197 | + <title>CEC Primary Device Types</title> | |
| 198 | + <tgroup cols="3"> | |
| 199 | + &cs-def; | |
| 200 | + <tbody valign="top"> | |
| 201 | + <row> | |
| 202 | + <entry><constant>CEC_OP_PRIM_DEVTYPE_TV</constant></entry> | |
| 203 | + <entry>0</entry> | |
| 204 | + <entry>Use for a TV.</entry> | |
| 205 | + </row> | |
| 206 | + <row> | |
| 207 | + <entry><constant>CEC_OP_PRIM_DEVTYPE_RECORD</constant></entry> | |
| 208 | + <entry>1</entry> | |
| 209 | + <entry>Use for a recording device.</entry> | |
| 210 | + </row> | |
| 211 | + <row> | |
| 212 | + <entry><constant>CEC_OP_PRIM_DEVTYPE_TUNER</constant></entry> | |
| 213 | + <entry>3</entry> | |
| 214 | + <entry>Use for a device with a tuner.</entry> | |
| 215 | + </row> | |
| 216 | + <row> | |
| 217 | + <entry><constant>CEC_OP_PRIM_DEVTYPE_PLAYBACK</constant></entry> | |
| 218 | + <entry>4</entry> | |
| 219 | + <entry>Use for a playback device.</entry> | |
| 220 | + </row> | |
| 221 | + <row> | |
| 222 | + <entry><constant>CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM</constant></entry> | |
| 223 | + <entry>5</entry> | |
| 224 | + <entry>Use for an audio system (e.g. an audio/video receiver).</entry> | |
| 225 | + </row> | |
| 226 | + <row> | |
| 227 | + <entry><constant>CEC_OP_PRIM_DEVTYPE_SWITCH</constant></entry> | |
| 228 | + <entry>6</entry> | |
| 229 | + <entry>Use for a CEC switch.</entry> | |
| 230 | + </row> | |
| 231 | + <row> | |
| 232 | + <entry><constant>CEC_OP_PRIM_DEVTYPE_VIDEOPROC</constant></entry> | |
| 233 | + <entry>7</entry> | |
| 234 | + <entry>Use for a video processor device.</entry> | |
| 235 | + </row> | |
| 236 | + </tbody> | |
| 237 | + </tgroup> | |
| 238 | + </table> | |
| 239 | + | |
| 240 | + <table pgwide="1" frame="none" id="cec-log-addr-types"> | |
| 241 | + <title>CEC Logical Address Types</title> | |
| 242 | + <tgroup cols="3"> | |
| 243 | + &cs-def; | |
| 244 | + <tbody valign="top"> | |
| 245 | + <row> | |
| 246 | + <entry><constant>CEC_LOG_ADDR_TYPE_TV</constant></entry> | |
| 247 | + <entry>0</entry> | |
| 248 | + <entry>Use for a TV.</entry> | |
| 249 | + </row> | |
| 250 | + <row> | |
| 251 | + <entry><constant>CEC_LOG_ADDR_TYPE_RECORD</constant></entry> | |
| 252 | + <entry>1</entry> | |
| 253 | + <entry>Use for a recording device.</entry> | |
| 254 | + </row> | |
| 255 | + <row> | |
| 256 | + <entry><constant>CEC_LOG_ADDR_TYPE_TUNER</constant></entry> | |
| 257 | + <entry>2</entry> | |
| 258 | + <entry>Use for a tuner device.</entry> | |
| 259 | + </row> | |
| 260 | + <row> | |
| 261 | + <entry><constant>CEC_LOG_ADDR_TYPE_PLAYBACK</constant></entry> | |
| 262 | + <entry>3</entry> | |
| 263 | + <entry>Use for a playback device.</entry> | |
| 264 | + </row> | |
| 265 | + <row> | |
| 266 | + <entry><constant>CEC_LOG_ADDR_TYPE_AUDIOSYSTEM</constant></entry> | |
| 267 | + <entry>4</entry> | |
| 268 | + <entry>Use for an audio system device.</entry> | |
| 269 | + </row> | |
| 270 | + <row> | |
| 271 | + <entry><constant>CEC_LOG_ADDR_TYPE_SPECIFIC</constant></entry> | |
| 272 | + <entry>5</entry> | |
| 273 | + <entry>Use for a second TV or for a video processor device.</entry> | |
| 274 | + </row> | |
| 275 | + <row> | |
| 276 | + <entry><constant>CEC_LOG_ADDR_TYPE_UNREGISTERED</constant></entry> | |
| 277 | + <entry>6</entry> | |
| 278 | + <entry>Use this if you just want to remain unregistered. | |
| 279 | + Used for pure CEC switches or CDC-only devices (CDC: | |
| 280 | + Capability Discovery and Control).</entry> | |
| 281 | + </row> | |
| 282 | + </tbody> | |
| 283 | + </tgroup> | |
| 284 | + </table> | |
| 285 | + | |
| 286 | + <table pgwide="1" frame="none" id="cec-all-dev-types-flags"> | |
| 287 | + <title>CEC All Device Types Flags</title> | |
| 288 | + <tgroup cols="3"> | |
| 289 | + &cs-def; | |
| 290 | + <tbody valign="top"> | |
| 291 | + <row> | |
| 292 | + <entry><constant>CEC_OP_ALL_DEVTYPE_TV</constant></entry> | |
| 293 | + <entry>0x80</entry> | |
| 294 | + <entry>This supports the TV type.</entry> | |
| 295 | + </row> | |
| 296 | + <row> | |
| 297 | + <entry><constant>CEC_OP_ALL_DEVTYPE_RECORD</constant></entry> | |
| 298 | + <entry>0x40</entry> | |
| 299 | + <entry>This supports the Recording type.</entry> | |
| 300 | + </row> | |
| 301 | + <row> | |
| 302 | + <entry><constant>CEC_OP_ALL_DEVTYPE_TUNER</constant></entry> | |
| 303 | + <entry>0x20</entry> | |
| 304 | + <entry>This supports the Tuner type.</entry> | |
| 305 | + </row> | |
| 306 | + <row> | |
| 307 | + <entry><constant>CEC_OP_ALL_DEVTYPE_PLAYBACK</constant></entry> | |
| 308 | + <entry>0x10</entry> | |
| 309 | + <entry>This supports the Playback type.</entry> | |
| 310 | + </row> | |
| 311 | + <row> | |
| 312 | + <entry><constant>CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM</constant></entry> | |
| 313 | + <entry>0x08</entry> | |
| 314 | + <entry>This supports the Audio System type.</entry> | |
| 315 | + </row> | |
| 316 | + <row> | |
| 317 | + <entry><constant>CEC_OP_ALL_DEVTYPE_SWITCH</constant></entry> | |
| 318 | + <entry>0x04</entry> | |
| 319 | + <entry>This supports the CEC Switch or Video Processing type.</entry> | |
| 320 | + </row> | |
| 321 | + </tbody> | |
| 322 | + </tgroup> | |
| 323 | + </table> | |
| 324 | + </refsect1> | |
| 325 | + | |
| 326 | + <refsect1> | |
| 327 | + &return-value; | |
| 328 | + </refsect1> | |
| 329 | +</refentry> | |
| @@ -0,0 +1,86 @@ | ||
| 1 | +<refentry id="cec-ioc-adap-g-phys-addr"> | |
| 2 | + <refmeta> | |
| 3 | + <refentrytitle>ioctl CEC_ADAP_G_PHYS_ADDR, CEC_ADAP_S_PHYS_ADDR</refentrytitle> | |
| 4 | + &manvol; | |
| 5 | + </refmeta> | |
| 6 | + | |
| 7 | + <refnamediv> | |
| 8 | + <refname>CEC_ADAP_G_PHYS_ADDR</refname> | |
| 9 | + <refname>CEC_ADAP_S_PHYS_ADDR</refname> | |
| 10 | + <refpurpose>Get or set the physical address</refpurpose> | |
| 11 | + </refnamediv> | |
| 12 | + | |
| 13 | + <refsynopsisdiv> | |
| 14 | + <funcsynopsis> | |
| 15 | + <funcprototype> | |
| 16 | + <funcdef>int <function>ioctl</function></funcdef> | |
| 17 | + <paramdef>int <parameter>fd</parameter></paramdef> | |
| 18 | + <paramdef>int <parameter>request</parameter></paramdef> | |
| 19 | + <paramdef>__u16 *<parameter>argp</parameter></paramdef> | |
| 20 | + </funcprototype> | |
| 21 | + </funcsynopsis> | |
| 22 | + </refsynopsisdiv> | |
| 23 | + | |
| 24 | + <refsect1> | |
| 25 | + <title>Arguments</title> | |
| 26 | + | |
| 27 | + <variablelist> | |
| 28 | + <varlistentry> | |
| 29 | + <term><parameter>fd</parameter></term> | |
| 30 | + <listitem> | |
| 31 | + <para>File descriptor returned by | |
| 32 | + <link linkend='cec-func-open'><function>open()</function></link>.</para> | |
| 33 | + </listitem> | |
| 34 | + </varlistentry> | |
| 35 | + <varlistentry> | |
| 36 | + <term><parameter>request</parameter></term> | |
| 37 | + <listitem> | |
| 38 | + <para>CEC_ADAP_G_PHYS_ADDR, CEC_ADAP_S_PHYS_ADDR</para> | |
| 39 | + </listitem> | |
| 40 | + </varlistentry> | |
| 41 | + <varlistentry> | |
| 42 | + <term><parameter>argp</parameter></term> | |
| 43 | + <listitem> | |
| 44 | + <para></para> | |
| 45 | + </listitem> | |
| 46 | + </varlistentry> | |
| 47 | + </variablelist> | |
| 48 | + </refsect1> | |
| 49 | + | |
| 50 | + <refsect1> | |
| 51 | + <title>Description</title> | |
| 52 | + | |
| 53 | + <para> | |
| 54 | + Note: this documents the proposed CEC API. This API is not yet finalized and | |
| 55 | + is currently only available as a staging kernel module. | |
| 56 | + </para> | |
| 57 | + | |
| 58 | + <para>To query the current physical address applications call the | |
| 59 | +<constant>CEC_ADAP_G_PHYS_ADDR</constant> ioctl with a pointer to an __u16 | |
| 60 | +where the driver stores the physical address.</para> | |
| 61 | + | |
| 62 | + <para>To set a new physical address applications store the physical address in | |
| 63 | +an __u16 and call the <constant>CEC_ADAP_S_PHYS_ADDR</constant> ioctl with a | |
| 64 | +pointer to this integer. <constant>CEC_ADAP_S_PHYS_ADDR</constant> is only | |
| 65 | +available if <constant>CEC_CAP_PHYS_ADDR</constant> is set (&ENOTTY; will be returned | |
| 66 | +otherwise). <constant>CEC_ADAP_S_PHYS_ADDR</constant> | |
| 67 | +can only be called by a file handle in initiator mode (see &CEC-S-MODE;), if not | |
| 68 | +&EBUSY; will be returned.</para> | |
| 69 | + | |
| 70 | + <para>The physical address is a 16-bit number where each group of 4 bits | |
| 71 | +represent a digit of the physical address a.b.c.d where the most significant | |
| 72 | +4 bits represent 'a'. The CEC root device (usually the TV) has address 0.0.0.0. | |
| 73 | +Every device that is hooked up to an input of the TV has address a.0.0.0 (where | |
| 74 | +'a' is ≥ 1), devices hooked up to those in turn have addresses a.b.0.0, etc. | |
| 75 | +So a topology of up to 5 devices deep is supported. The physical address a | |
| 76 | +device shall use is stored in the EDID of the sink.</para> | |
| 77 | + | |
| 78 | +<para>For example, the EDID for each HDMI input of the TV will have a different | |
| 79 | +physical address of the form a.0.0.0 that the sources will read out and use as | |
| 80 | +their physical address.</para> | |
| 81 | + </refsect1> | |
| 82 | + | |
| 83 | + <refsect1> | |
| 84 | + &return-value; | |
| 85 | + </refsect1> | |
| 86 | +</refentry> | |
| @@ -0,0 +1,202 @@ | ||
| 1 | +<refentry id="cec-ioc-g-event"> | |
| 2 | + <refmeta> | |
| 3 | + <refentrytitle>ioctl CEC_DQEVENT</refentrytitle> | |
| 4 | + &manvol; | |
| 5 | + </refmeta> | |
| 6 | + | |
| 7 | + <refnamediv> | |
| 8 | + <refname>CEC_DQEVENT</refname> | |
| 9 | + <refpurpose>Dequeue a CEC event</refpurpose> | |
| 10 | + </refnamediv> | |
| 11 | + | |
| 12 | + <refsynopsisdiv> | |
| 13 | + <funcsynopsis> | |
| 14 | + <funcprototype> | |
| 15 | + <funcdef>int <function>ioctl</function></funcdef> | |
| 16 | + <paramdef>int <parameter>fd</parameter></paramdef> | |
| 17 | + <paramdef>int <parameter>request</parameter></paramdef> | |
| 18 | + <paramdef>struct cec_event *<parameter>argp</parameter></paramdef> | |
| 19 | + </funcprototype> | |
| 20 | + </funcsynopsis> | |
| 21 | + </refsynopsisdiv> | |
| 22 | + | |
| 23 | + <refsect1> | |
| 24 | + <title>Arguments</title> | |
| 25 | + | |
| 26 | + <variablelist> | |
| 27 | + <varlistentry> | |
| 28 | + <term><parameter>fd</parameter></term> | |
| 29 | + <listitem> | |
| 30 | + <para>File descriptor returned by | |
| 31 | + <link linkend='cec-func-open'><function>open()</function></link>.</para> | |
| 32 | + </listitem> | |
| 33 | + </varlistentry> | |
| 34 | + <varlistentry> | |
| 35 | + <term><parameter>request</parameter></term> | |
| 36 | + <listitem> | |
| 37 | + <para>CEC_DQEVENT</para> | |
| 38 | + </listitem> | |
| 39 | + </varlistentry> | |
| 40 | + <varlistentry> | |
| 41 | + <term><parameter>argp</parameter></term> | |
| 42 | + <listitem> | |
| 43 | + <para></para> | |
| 44 | + </listitem> | |
| 45 | + </varlistentry> | |
| 46 | + </variablelist> | |
| 47 | + </refsect1> | |
| 48 | + | |
| 49 | + <refsect1> | |
| 50 | + <title>Description</title> | |
| 51 | + | |
| 52 | + <para> | |
| 53 | + Note: this documents the proposed CEC API. This API is not yet finalized and | |
| 54 | + is currently only available as a staging kernel module. | |
| 55 | + </para> | |
| 56 | + | |
| 57 | + <para>CEC devices can send asynchronous events. These can be retrieved by calling | |
| 58 | + the <constant>CEC_DQEVENT</constant> ioctl. If the file descriptor is in non-blocking | |
| 59 | + mode and no event is pending, then it will return -1 and set errno to the &EAGAIN;.</para> | |
| 60 | + | |
| 61 | + <para>The internal event queues are per-filehandle and per-event type. If there is | |
| 62 | + no more room in a queue then the last event is overwritten with the new one. This | |
| 63 | + means that intermediate results can be thrown away but that the latest event is always | |
| 64 | + available. This also means that is it possible to read two successive events that have | |
| 65 | + the same value (e.g. two CEC_EVENT_STATE_CHANGE events with the same state). In that | |
| 66 | + case the intermediate state changes were lost but it is guaranteed that the state | |
| 67 | + did change in between the two events.</para> | |
| 68 | + | |
| 69 | + <table pgwide="1" frame="none" id="cec-event-state-change"> | |
| 70 | + <title>struct <structname>cec_event_state_change</structname></title> | |
| 71 | + <tgroup cols="3"> | |
| 72 | + &cs-str; | |
| 73 | + <tbody valign="top"> | |
| 74 | + <row> | |
| 75 | + <entry>__u16</entry> | |
| 76 | + <entry><structfield>phys_addr</structfield></entry> | |
| 77 | + <entry>The current physical address.</entry> | |
| 78 | + </row> | |
| 79 | + <row> | |
| 80 | + <entry>__u16</entry> | |
| 81 | + <entry><structfield>log_addr_mask</structfield></entry> | |
| 82 | + <entry>The current set of claimed logical addresses.</entry> | |
| 83 | + </row> | |
| 84 | + </tbody> | |
| 85 | + </tgroup> | |
| 86 | + </table> | |
| 87 | + | |
| 88 | + <table pgwide="1" frame="none" id="cec-event-lost-msgs"> | |
| 89 | + <title>struct <structname>cec_event_lost_msgs</structname></title> | |
| 90 | + <tgroup cols="3"> | |
| 91 | + &cs-str; | |
| 92 | + <tbody valign="top"> | |
| 93 | + <row> | |
| 94 | + <entry>__u32</entry> | |
| 95 | + <entry><structfield>lost_msgs</structfield></entry> | |
| 96 | + <entry>Set to the number of lost messages since the filehandle | |
| 97 | + was opened or since the last time this event was dequeued for | |
| 98 | + this filehandle. The messages lost are the oldest messages. So | |
| 99 | + when a new message arrives and there is no more room, then the | |
| 100 | + oldest message is discarded to make room for the new one. The | |
| 101 | + internal size of the message queue guarantees that all messages | |
| 102 | + received in the last two seconds will be stored. Since messages | |
| 103 | + should be replied to within a second according to the CEC | |
| 104 | + specification, this is more than enough. | |
| 105 | + </entry> | |
| 106 | + </row> | |
| 107 | + </tbody> | |
| 108 | + </tgroup> | |
| 109 | + </table> | |
| 110 | + | |
| 111 | + <table pgwide="1" frame="none" id="cec-event"> | |
| 112 | + <title>struct <structname>cec_event</structname></title> | |
| 113 | + <tgroup cols="4"> | |
| 114 | + &cs-str; | |
| 115 | + <tbody valign="top"> | |
| 116 | + <row> | |
| 117 | + <entry>__u64</entry> | |
| 118 | + <entry><structfield>ts</structfield></entry> | |
| 119 | + <entry>Timestamp of the event in ns.</entry> | |
| 120 | + <entry></entry> | |
| 121 | + </row> | |
| 122 | + <row> | |
| 123 | + <entry>__u32</entry> | |
| 124 | + <entry><structfield>event</structfield></entry> | |
| 125 | + <entry>The CEC event type, see <xref linkend="cec-events" />.</entry> | |
| 126 | + <entry></entry> | |
| 127 | + </row> | |
| 128 | + <row> | |
| 129 | + <entry>__u32</entry> | |
| 130 | + <entry><structfield>flags</structfield></entry> | |
| 131 | + <entry>Event flags, see <xref linkend="cec-event-flags" />.</entry> | |
| 132 | + <entry></entry> | |
| 133 | + </row> | |
| 134 | + <row> | |
| 135 | + <entry>union</entry> | |
| 136 | + <entry>(anonymous)</entry> | |
| 137 | + <entry></entry> | |
| 138 | + <entry></entry> | |
| 139 | + </row> | |
| 140 | + <row> | |
| 141 | + <entry></entry> | |
| 142 | + <entry>struct cec_event_state_change</entry> | |
| 143 | + <entry><structfield>state_change</structfield></entry> | |
| 144 | + <entry>The new adapter state as sent by the <constant>CEC_EVENT_STATE_CHANGE</constant> | |
| 145 | + event.</entry> | |
| 146 | + </row> | |
| 147 | + <row> | |
| 148 | + <entry></entry> | |
| 149 | + <entry>struct cec_event_lost_msgs</entry> | |
| 150 | + <entry><structfield>lost_msgs</structfield></entry> | |
| 151 | + <entry>The number of lost messages as sent by the <constant>CEC_EVENT_LOST_MSGS</constant> | |
| 152 | + event.</entry> | |
| 153 | + </row> | |
| 154 | + </tbody> | |
| 155 | + </tgroup> | |
| 156 | + </table> | |
| 157 | + | |
| 158 | + <table pgwide="1" frame="none" id="cec-events"> | |
| 159 | + <title>CEC Events Types</title> | |
| 160 | + <tgroup cols="3"> | |
| 161 | + &cs-def; | |
| 162 | + <tbody valign="top"> | |
| 163 | + <row> | |
| 164 | + <entry><constant>CEC_EVENT_STATE_CHANGE</constant></entry> | |
| 165 | + <entry>1</entry> | |
| 166 | + <entry>Generated when the CEC Adapter's state changes. When open() is | |
| 167 | + called an initial event will be generated for that filehandle with the | |
| 168 | + CEC Adapter's state at that time. | |
| 169 | + </entry> | |
| 170 | + </row> | |
| 171 | + <row> | |
| 172 | + <entry><constant>CEC_EVENT_LOST_MSGS</constant></entry> | |
| 173 | + <entry>2</entry> | |
| 174 | + <entry>Generated if one or more CEC messages were lost because the | |
| 175 | + application didn't dequeue CEC messages fast enough.</entry> | |
| 176 | + </row> | |
| 177 | + </tbody> | |
| 178 | + </tgroup> | |
| 179 | + </table> | |
| 180 | + | |
| 181 | + <table pgwide="1" frame="none" id="cec-event-flags"> | |
| 182 | + <title>CEC Event Flags</title> | |
| 183 | + <tgroup cols="3"> | |
| 184 | + &cs-def; | |
| 185 | + <tbody valign="top"> | |
| 186 | + <row> | |
| 187 | + <entry><constant>CEC_EVENT_FL_INITIAL_VALUE</constant></entry> | |
| 188 | + <entry>1</entry> | |
| 189 | + <entry>Set for the initial events that are generated when the device is | |
| 190 | + opened. See the table above for which events do this. This allows | |
| 191 | + applications to learn the initial state of the CEC adapter at open() | |
| 192 | + time.</entry> | |
| 193 | + </row> | |
| 194 | + </tbody> | |
| 195 | + </tgroup> | |
| 196 | + </table> | |
| 197 | + </refsect1> | |
| 198 | + | |
| 199 | + <refsect1> | |
| 200 | + &return-value; | |
| 201 | + </refsect1> | |
| 202 | +</refentry> | |
| @@ -0,0 +1,255 @@ | ||
| 1 | +<refentry id="cec-ioc-g-mode"> | |
| 2 | + <refmeta> | |
| 3 | + <refentrytitle>ioctl CEC_G_MODE, CEC_S_MODE</refentrytitle> | |
| 4 | + &manvol; | |
| 5 | + </refmeta> | |
| 6 | + | |
| 7 | + <refnamediv> | |
| 8 | + <refname>CEC_G_MODE</refname> | |
| 9 | + <refname>CEC_S_MODE</refname> | |
| 10 | + <refpurpose>Get or set exclusive use of the CEC adapter</refpurpose> | |
| 11 | + </refnamediv> | |
| 12 | + | |
| 13 | + <refsynopsisdiv> | |
| 14 | + <funcsynopsis> | |
| 15 | + <funcprototype> | |
| 16 | + <funcdef>int <function>ioctl</function></funcdef> | |
| 17 | + <paramdef>int <parameter>fd</parameter></paramdef> | |
| 18 | + <paramdef>int <parameter>request</parameter></paramdef> | |
| 19 | + <paramdef>__u32 *<parameter>argp</parameter></paramdef> | |
| 20 | + </funcprototype> | |
| 21 | + </funcsynopsis> | |
| 22 | + </refsynopsisdiv> | |
| 23 | + | |
| 24 | + <refsect1> | |
| 25 | + <title>Arguments</title> | |
| 26 | + | |
| 27 | + <variablelist> | |
| 28 | + <varlistentry> | |
| 29 | + <term><parameter>fd</parameter></term> | |
| 30 | + <listitem> | |
| 31 | + <para>File descriptor returned by | |
| 32 | + <link linkend='cec-func-open'><function>open()</function></link>.</para> | |
| 33 | + </listitem> | |
| 34 | + </varlistentry> | |
| 35 | + <varlistentry> | |
| 36 | + <term><parameter>request</parameter></term> | |
| 37 | + <listitem> | |
| 38 | + <para>CEC_G_MODE, CEC_S_MODE</para> | |
| 39 | + </listitem> | |
| 40 | + </varlistentry> | |
| 41 | + <varlistentry> | |
| 42 | + <term><parameter>argp</parameter></term> | |
| 43 | + <listitem> | |
| 44 | + <para></para> | |
| 45 | + </listitem> | |
| 46 | + </varlistentry> | |
| 47 | + </variablelist> | |
| 48 | + </refsect1> | |
| 49 | + | |
| 50 | + <refsect1> | |
| 51 | + <title>Description</title> | |
| 52 | + | |
| 53 | + <para> | |
| 54 | + Note: this documents the proposed CEC API. This API is not yet finalized and | |
| 55 | + is currently only available as a staging kernel module. | |
| 56 | + </para> | |
| 57 | + | |
| 58 | + <para>By default any filehandle can use &CEC-TRANSMIT; and &CEC-RECEIVE;, but | |
| 59 | +in order to prevent applications from stepping on each others toes it must be possible | |
| 60 | +to obtain exclusive access to the CEC adapter. This ioctl sets the filehandle | |
| 61 | +to initiator and/or follower mode which can be exclusive depending on the chosen | |
| 62 | +mode. The initiator is the filehandle that is used | |
| 63 | +to initiate messages, i.e. it commands other CEC devices. The follower is the filehandle | |
| 64 | +that receives messages sent to the CEC adapter and processes them. The same filehandle | |
| 65 | +can be both initiator and follower, or this role can be taken by two different | |
| 66 | +filehandles.</para> | |
| 67 | + | |
| 68 | + <para>When a CEC message is received, then the CEC framework will decide how | |
| 69 | +it will be processed. If the message is a reply to an earlier transmitted message, | |
| 70 | +then the reply is sent back to the filehandle that is waiting for it. In addition | |
| 71 | +the CEC framework will process it.</para> | |
| 72 | + | |
| 73 | + <para>If the message is not a reply, then the CEC framework will process it | |
| 74 | +first. If there is no follower, then the message is just discarded and a feature | |
| 75 | +abort is sent back to the initiator if the framework couldn't process it. If there | |
| 76 | +is a follower, then the message is passed on to the follower who will use | |
| 77 | +&CEC-RECEIVE; to dequeue the new message. The framework expects the follower to | |
| 78 | +make the right decisions.</para> | |
| 79 | + | |
| 80 | + <para>The CEC framework will process core messages unless requested otherwise | |
| 81 | +by the follower. The follower can enable the passthrough mode. In that case, the | |
| 82 | +CEC framework will pass on most core messages without processing them and | |
| 83 | +the follower will have to implement those messages. There are some messages | |
| 84 | +that the core will always process, regardless of the passthrough mode. See | |
| 85 | +<xref linkend="cec-core-processing" /> for details.</para> | |
| 86 | + | |
| 87 | + <para>If there is no initiator, then any CEC filehandle can use &CEC-TRANSMIT;. | |
| 88 | +If there is an exclusive initiator then only that initiator can call &CEC-TRANSMIT;. | |
| 89 | +The follower can of course always call &CEC-TRANSMIT;.</para> | |
| 90 | + | |
| 91 | + <para>Available initiator modes are:</para> | |
| 92 | + | |
| 93 | + <table pgwide="1" frame="none" id="cec-mode-initiator"> | |
| 94 | + <title>Initiator Modes</title> | |
| 95 | + <tgroup cols="3"> | |
| 96 | + &cs-def; | |
| 97 | + <tbody valign="top"> | |
| 98 | + <row> | |
| 99 | + <entry><constant>CEC_MODE_NO_INITIATOR</constant></entry> | |
| 100 | + <entry>0x0</entry> | |
| 101 | + <entry>This is not an initiator, i.e. it cannot transmit CEC messages | |
| 102 | + or make any other changes to the CEC adapter.</entry> | |
| 103 | + </row> | |
| 104 | + <row> | |
| 105 | + <entry><constant>CEC_MODE_INITIATOR</constant></entry> | |
| 106 | + <entry>0x1</entry> | |
| 107 | + <entry>This is an initiator (the default when the device is opened) and it | |
| 108 | + can transmit CEC messages and make changes to the CEC adapter, unless there | |
| 109 | + is an exclusive initiator.</entry> | |
| 110 | + </row> | |
| 111 | + <row> | |
| 112 | + <entry><constant>CEC_MODE_EXCL_INITIATOR</constant></entry> | |
| 113 | + <entry>0x2</entry> | |
| 114 | + <entry>This is an exclusive initiator and this file descriptor is the only one | |
| 115 | + that can transmit CEC messages and make changes to the CEC adapter. If someone | |
| 116 | + else is already the exclusive initiator then an attempt to become one will return | |
| 117 | + the &EBUSY; error.</entry> | |
| 118 | + </row> | |
| 119 | + </tbody> | |
| 120 | + </tgroup> | |
| 121 | + </table> | |
| 122 | + | |
| 123 | + <para>Available follower modes are:</para> | |
| 124 | + | |
| 125 | + <table pgwide="1" frame="none" id="cec-mode-follower"> | |
| 126 | + <title>Follower Modes</title> | |
| 127 | + <tgroup cols="3"> | |
| 128 | + &cs-def; | |
| 129 | + <tbody valign="top"> | |
| 130 | + <row> | |
| 131 | + <entry><constant>CEC_MODE_NO_FOLLOWER</constant></entry> | |
| 132 | + <entry>0x00</entry> | |
| 133 | + <entry>This is not a follower (the default when the device is opened).</entry> | |
| 134 | + </row> | |
| 135 | + <row> | |
| 136 | + <entry><constant>CEC_MODE_FOLLOWER</constant></entry> | |
| 137 | + <entry>0x10</entry> | |
| 138 | + <entry>This is a follower and it will receive CEC messages unless there is | |
| 139 | + an exclusive follower. You cannot become a follower if <constant>CEC_CAP_TRANSMIT</constant> | |
| 140 | + is not set or if <constant>CEC_MODE_NO_INITIATOR</constant> was specified, | |
| 141 | + &EINVAL; is returned in that case.</entry> | |
| 142 | + </row> | |
| 143 | + <row> | |
| 144 | + <entry><constant>CEC_MODE_EXCL_FOLLOWER</constant></entry> | |
| 145 | + <entry>0x20</entry> | |
| 146 | + <entry>This is an exclusive follower and only this file descriptor will receive | |
| 147 | + CEC messages for processing. If someone else is already the exclusive follower | |
| 148 | + then an attempt to become one will return the &EBUSY; error. You cannot become | |
| 149 | + a follower if <constant>CEC_CAP_TRANSMIT</constant> is not set or if | |
| 150 | + <constant>CEC_MODE_NO_INITIATOR</constant> was specified, &EINVAL; is returned | |
| 151 | + in that case.</entry> | |
| 152 | + </row> | |
| 153 | + <row> | |
| 154 | + <entry><constant>CEC_MODE_EXCL_FOLLOWER_PASSTHRU</constant></entry> | |
| 155 | + <entry>0x30</entry> | |
| 156 | + <entry>This is an exclusive follower and only this file descriptor will receive | |
| 157 | + CEC messages for processing. In addition it will put the CEC device into | |
| 158 | + passthrough mode, allowing the exclusive follower to handle most core messages | |
| 159 | + instead of relying on the CEC framework for that. If someone else is already the | |
| 160 | + exclusive follower then an attempt to become one will return the &EBUSY; error. | |
| 161 | + You cannot become a follower if <constant>CEC_CAP_TRANSMIT</constant> | |
| 162 | + is not set or if <constant>CEC_MODE_NO_INITIATOR</constant> was specified, | |
| 163 | + &EINVAL; is returned in that case.</entry> | |
| 164 | + </row> | |
| 165 | + <row> | |
| 166 | + <entry><constant>CEC_MODE_MONITOR</constant></entry> | |
| 167 | + <entry>0xe0</entry> | |
| 168 | + <entry>Put the file descriptor into monitor mode. Can only be used in combination | |
| 169 | + with <constant>CEC_MODE_NO_INITIATOR</constant>, otherwise &EINVAL; will be | |
| 170 | + returned. In monitor mode all messages this CEC device transmits and all messages | |
| 171 | + it receives (both broadcast messages and directed messages for one its logical | |
| 172 | + addresses) will be reported. This is very useful for debugging. This is only | |
| 173 | + allowed if the process has the <constant>CAP_NET_ADMIN</constant> | |
| 174 | + capability. If that is not set, then &EPERM; is returned.</entry> | |
| 175 | + </row> | |
| 176 | + <row> | |
| 177 | + <entry><constant>CEC_MODE_MONITOR_ALL</constant></entry> | |
| 178 | + <entry>0xf0</entry> | |
| 179 | + <entry>Put the file descriptor into 'monitor all' mode. Can only be used in combination | |
| 180 | + with <constant>CEC_MODE_NO_INITIATOR</constant>, otherwise &EINVAL; will be | |
| 181 | + returned. In 'monitor all' mode all messages this CEC device transmits and all messages | |
| 182 | + it receives, including directed messages for other CEC devices will be reported. This | |
| 183 | + is very useful for debugging, but not all devices support this. This mode requires that | |
| 184 | + the <constant>CEC_CAP_MONITOR_ALL</constant> capability is set, otherwise &EINVAL; is | |
| 185 | + returned. This is only allowed if the process has the <constant>CAP_NET_ADMIN</constant> | |
| 186 | + capability. If that is not set, then &EPERM; is returned.</entry> | |
| 187 | + </row> | |
| 188 | + </tbody> | |
| 189 | + </tgroup> | |
| 190 | + </table> | |
| 191 | + | |
| 192 | + <para>Core message processing details:</para> | |
| 193 | + | |
| 194 | + <table pgwide="1" frame="none" id="cec-core-processing"> | |
| 195 | + <title>Core Message Processing</title> | |
| 196 | + <tgroup cols="2"> | |
| 197 | + &cs-def; | |
| 198 | + <tbody valign="top"> | |
| 199 | + <row> | |
| 200 | + <entry><constant>CEC_MSG_GET_CEC_VERSION</constant></entry> | |
| 201 | + <entry>When in passthrough mode this message has to be handled by userspace, | |
| 202 | + otherwise the core will return the CEC version that was set with &CEC-ADAP-S-LOG-ADDRS;.</entry> | |
| 203 | + </row> | |
| 204 | + <row> | |
| 205 | + <entry><constant>CEC_MSG_GIVE_DEVICE_VENDOR_ID</constant></entry> | |
| 206 | + <entry>When in passthrough mode this message has to be handled by userspace, | |
| 207 | + otherwise the core will return the vendor ID that was set with &CEC-ADAP-S-LOG-ADDRS;.</entry> | |
| 208 | + </row> | |
| 209 | + <row> | |
| 210 | + <entry><constant>CEC_MSG_ABORT</constant></entry> | |
| 211 | + <entry>When in passthrough mode this message has to be handled by userspace, | |
| 212 | + otherwise the core will return a feature refused message as per the specification.</entry> | |
| 213 | + </row> | |
| 214 | + <row> | |
| 215 | + <entry><constant>CEC_MSG_GIVE_PHYSICAL_ADDR</constant></entry> | |
| 216 | + <entry>When in passthrough mode this message has to be handled by userspace, | |
| 217 | + otherwise the core will report the current physical address.</entry> | |
| 218 | + </row> | |
| 219 | + <row> | |
| 220 | + <entry><constant>CEC_MSG_GIVE_OSD_NAME</constant></entry> | |
| 221 | + <entry>When in passthrough mode this message has to be handled by userspace, | |
| 222 | + otherwise the core will report the current OSD name as was set with | |
| 223 | + &CEC-ADAP-S-LOG-ADDRS;.</entry> | |
| 224 | + </row> | |
| 225 | + <row> | |
| 226 | + <entry><constant>CEC_MSG_GIVE_FEATURES</constant></entry> | |
| 227 | + <entry>When in passthrough mode this message has to be handled by userspace, | |
| 228 | + otherwise the core will report the current features as was set with | |
| 229 | + &CEC-ADAP-S-LOG-ADDRS; or the message is ignore if the CEC version was | |
| 230 | + older than 2.0.</entry> | |
| 231 | + </row> | |
| 232 | + <row> | |
| 233 | + <entry><constant>CEC_MSG_USER_CONTROL_PRESSED</constant></entry> | |
| 234 | + <entry>If <constant>CEC_CAP_RC</constant> is set, then generate a remote control | |
| 235 | + key press. This message is always passed on to userspace.</entry> | |
| 236 | + </row> | |
| 237 | + <row> | |
| 238 | + <entry><constant>CEC_MSG_USER_CONTROL_RELEASED</constant></entry> | |
| 239 | + <entry>If <constant>CEC_CAP_RC</constant> is set, then generate a remote control | |
| 240 | + key release. This message is always passed on to userspace.</entry> | |
| 241 | + </row> | |
| 242 | + <row> | |
| 243 | + <entry><constant>CEC_MSG_REPORT_PHYSICAL_ADDR</constant></entry> | |
| 244 | + <entry>The CEC framework will make note of the reported physical address | |
| 245 | + and then just pass the message on to userspace.</entry> | |
| 246 | + </row> | |
| 247 | + </tbody> | |
| 248 | + </tgroup> | |
| 249 | + </table> | |
| 250 | + </refsect1> | |
| 251 | + | |
| 252 | + <refsect1> | |
| 253 | + &return-value; | |
| 254 | + </refsect1> | |
| 255 | +</refentry> | |
| @@ -0,0 +1,274 @@ | ||
| 1 | +<refentry id="cec-ioc-receive"> | |
| 2 | + <refmeta> | |
| 3 | + <refentrytitle>ioctl CEC_RECEIVE, CEC_TRANSMIT</refentrytitle> | |
| 4 | + &manvol; | |
| 5 | + </refmeta> | |
| 6 | + | |
| 7 | + <refnamediv> | |
| 8 | + <refname>CEC_RECEIVE</refname> | |
| 9 | + <refname>CEC_TRANSMIT</refname> | |
| 10 | + <refpurpose>Receive or transmit a CEC message</refpurpose> | |
| 11 | + </refnamediv> | |
| 12 | + | |
| 13 | + <refsynopsisdiv> | |
| 14 | + <funcsynopsis> | |
| 15 | + <funcprototype> | |
| 16 | + <funcdef>int <function>ioctl</function></funcdef> | |
| 17 | + <paramdef>int <parameter>fd</parameter></paramdef> | |
| 18 | + <paramdef>int <parameter>request</parameter></paramdef> | |
| 19 | + <paramdef>struct cec_msg *<parameter>argp</parameter></paramdef> | |
| 20 | + </funcprototype> | |
| 21 | + </funcsynopsis> | |
| 22 | + </refsynopsisdiv> | |
| 23 | + | |
| 24 | + <refsect1> | |
| 25 | + <title>Arguments</title> | |
| 26 | + | |
| 27 | + <variablelist> | |
| 28 | + <varlistentry> | |
| 29 | + <term><parameter>fd</parameter></term> | |
| 30 | + <listitem> | |
| 31 | + <para>File descriptor returned by | |
| 32 | + <link linkend='cec-func-open'><function>open()</function></link>.</para> | |
| 33 | + </listitem> | |
| 34 | + </varlistentry> | |
| 35 | + <varlistentry> | |
| 36 | + <term><parameter>request</parameter></term> | |
| 37 | + <listitem> | |
| 38 | + <para>CEC_RECEIVE, CEC_TRANSMIT</para> | |
| 39 | + </listitem> | |
| 40 | + </varlistentry> | |
| 41 | + <varlistentry> | |
| 42 | + <term><parameter>argp</parameter></term> | |
| 43 | + <listitem> | |
| 44 | + <para></para> | |
| 45 | + </listitem> | |
| 46 | + </varlistentry> | |
| 47 | + </variablelist> | |
| 48 | + </refsect1> | |
| 49 | + | |
| 50 | + <refsect1> | |
| 51 | + <title>Description</title> | |
| 52 | + | |
| 53 | + <para> | |
| 54 | + Note: this documents the proposed CEC API. This API is not yet finalized and | |
| 55 | + is currently only available as a staging kernel module. | |
| 56 | + </para> | |
| 57 | + | |
| 58 | + <para>To receive a CEC message the application has to fill in the | |
| 59 | + <structname>cec_msg</structname> structure and pass it to the | |
| 60 | + <constant>CEC_RECEIVE</constant> ioctl. <constant>CEC_RECEIVE</constant> is | |
| 61 | + only available if <constant>CEC_CAP_RECEIVE</constant> is set. If the | |
| 62 | + file descriptor is in non-blocking mode and there are no received | |
| 63 | + messages pending, then it will return -1 and set errno to the &EAGAIN;. | |
| 64 | + If the file descriptor is in blocking mode and <structfield>timeout</structfield> | |
| 65 | + is non-zero and no message arrived within <structfield>timeout</structfield> | |
| 66 | + milliseconds, then it will return -1 and set errno to the &ETIMEDOUT;.</para> | |
| 67 | + | |
| 68 | + <para>To send a CEC message the application has to fill in the | |
| 69 | + <structname>cec_msg</structname> structure and pass it to the | |
| 70 | + <constant>CEC_TRANSMIT</constant> ioctl. <constant>CEC_TRANSMIT</constant> is | |
| 71 | + only available if <constant>CEC_CAP_TRANSMIT</constant> is set. | |
| 72 | + If there is no more room in the transmit queue, then it will return | |
| 73 | + -1 and set errno to the &EBUSY;.</para> | |
| 74 | + | |
| 75 | + <table pgwide="1" frame="none" id="cec-msg"> | |
| 76 | + <title>struct <structname>cec_msg</structname></title> | |
| 77 | + <tgroup cols="3"> | |
| 78 | + &cs-str; | |
| 79 | + <tbody valign="top"> | |
| 80 | + <row> | |
| 81 | + <entry>__u64</entry> | |
| 82 | + <entry><structfield>ts</structfield></entry> | |
| 83 | + <entry>Timestamp of when the message was transmitted in ns in the case | |
| 84 | + of <constant>CEC_TRANSMIT</constant> with <structfield>reply</structfield> | |
| 85 | + set to 0, or the timestamp of the received message in all other cases.</entry> | |
| 86 | + </row> | |
| 87 | + <row> | |
| 88 | + <entry>__u32</entry> | |
| 89 | + <entry><structfield>len</structfield></entry> | |
| 90 | + <entry>The length of the message. For <constant>CEC_TRANSMIT</constant> this | |
| 91 | + is filled in by the application. The driver will fill this in for | |
| 92 | + <constant>CEC_RECEIVE</constant> and for <constant>CEC_TRANSMIT</constant> | |
| 93 | + it will be filled in with the length of the reply message if | |
| 94 | + <structfield>reply</structfield> was set.</entry> | |
| 95 | + </row> | |
| 96 | + <row> | |
| 97 | + <entry>__u32</entry> | |
| 98 | + <entry><structfield>timeout</structfield></entry> | |
| 99 | + <entry>The timeout in milliseconds. This is the time the device will wait for a message to | |
| 100 | + be received before timing out. If it is set to 0, then it will wait indefinitely when it | |
| 101 | + is called by <constant>CEC_RECEIVE</constant>. If it is 0 and it is called by | |
| 102 | + <constant>CEC_TRANSMIT</constant>, then it will be replaced by 1000 if the | |
| 103 | + <structfield>reply</structfield> is non-zero or ignored if <structfield>reply</structfield> | |
| 104 | + is 0.</entry> | |
| 105 | + </row> | |
| 106 | + <row> | |
| 107 | + <entry>__u32</entry> | |
| 108 | + <entry><structfield>sequence</structfield></entry> | |
| 109 | + <entry>The sequence number is automatically assigned by the CEC | |
| 110 | + framework for all transmitted messages. It can be later used by the | |
| 111 | + framework to generate an event if a reply for a message was | |
| 112 | + requested and the message was transmitted in a non-blocking mode. | |
| 113 | + </entry> | |
| 114 | + </row> | |
| 115 | + <row> | |
| 116 | + <entry>__u32</entry> | |
| 117 | + <entry><structfield>flags</structfield></entry> | |
| 118 | + <entry>Flags. No flags are defined yet, so set this to 0.</entry> | |
| 119 | + </row> | |
| 120 | + <row> | |
| 121 | + <entry>__u8</entry> | |
| 122 | + <entry><structfield>rx_status</structfield></entry> | |
| 123 | + <entry>The status bits of the received message. See <xref linkend="cec-rx-status" /> | |
| 124 | + for the possible status values. It is 0 if this message was transmitted, not | |
| 125 | + received, unless this is the reply to a transmitted message. In that case both | |
| 126 | + <structfield>rx_status</structfield> and <structfield>tx_status</structfield> | |
| 127 | + are set.</entry> | |
| 128 | + </row> | |
| 129 | + <row> | |
| 130 | + <entry>__u8</entry> | |
| 131 | + <entry><structfield>tx_status</structfield></entry> | |
| 132 | + <entry>The status bits of the transmitted message. See <xref linkend="cec-tx-status" /> | |
| 133 | + for the possible status values. It is 0 if this messages was received, not | |
| 134 | + transmitted.</entry> | |
| 135 | + </row> | |
| 136 | + <row> | |
| 137 | + <entry>__u8</entry> | |
| 138 | + <entry><structfield>msg</structfield>[16]</entry> | |
| 139 | + <entry>The message payload. For <constant>CEC_TRANSMIT</constant> this | |
| 140 | + is filled in by the application. The driver will fill this in for | |
| 141 | + <constant>CEC_RECEIVE</constant> and for <constant>CEC_TRANSMIT</constant> | |
| 142 | + it will be filled in with the payload of the reply message if | |
| 143 | + <structfield>reply</structfield> was set.</entry> | |
| 144 | + </row> | |
| 145 | + <row> | |
| 146 | + <entry>__u8</entry> | |
| 147 | + <entry><structfield>reply</structfield></entry> | |
| 148 | + <entry>Wait until this message is replied. If <structfield>reply</structfield> | |
| 149 | + is 0 and the <structfield>timeout</structfield> is 0, then don't wait for a reply but | |
| 150 | + return after transmitting the message. If there was an error as indicated by a non-zero | |
| 151 | + <structfield>tx_status</structfield> field, then <structfield>reply</structfield> and | |
| 152 | + <structfield>timeout</structfield> are both set to 0 by the driver. Ignored by | |
| 153 | + <constant>CEC_RECEIVE</constant>. The case where <structfield>reply</structfield> is 0 | |
| 154 | + (this is the opcode for the Feature Abort message) and <structfield>timeout</structfield> | |
| 155 | + is non-zero is specifically allowed to send a message and wait up to <structfield>timeout</structfield> | |
| 156 | + milliseconds for a Feature Abort reply. In this case <structfield>rx_status</structfield> | |
| 157 | + will either be set to <constant>CEC_RX_STATUS_TIMEOUT</constant> or | |
| 158 | + <constant>CEC_RX_STATUS_FEATURE_ABORT</constant>.</entry> | |
| 159 | + </row> | |
| 160 | + <row> | |
| 161 | + <entry>__u8</entry> | |
| 162 | + <entry><structfield>tx_arb_lost_cnt</structfield></entry> | |
| 163 | + <entry>A counter of the number of transmit attempts that resulted in the | |
| 164 | + Arbitration Lost error. This is only set if the hardware supports this, otherwise | |
| 165 | + it is always 0. This counter is only valid if the <constant>CEC_TX_STATUS_ARB_LOST</constant> | |
| 166 | + status bit is set.</entry> | |
| 167 | + </row> | |
| 168 | + <row> | |
| 169 | + <entry>__u8</entry> | |
| 170 | + <entry><structfield>tx_nack_cnt</structfield></entry> | |
| 171 | + <entry>A counter of the number of transmit attempts that resulted in the | |
| 172 | + Not Acknowledged error. This is only set if the hardware supports this, otherwise | |
| 173 | + it is always 0. This counter is only valid if the <constant>CEC_TX_STATUS_NACK</constant> | |
| 174 | + status bit is set.</entry> | |
| 175 | + </row> | |
| 176 | + <row> | |
| 177 | + <entry>__u8</entry> | |
| 178 | + <entry><structfield>tx_low_drive_cnt</structfield></entry> | |
| 179 | + <entry>A counter of the number of transmit attempts that resulted in the | |
| 180 | + Arbitration Lost error. This is only set if the hardware supports this, otherwise | |
| 181 | + it is always 0. This counter is only valid if the <constant>CEC_TX_STATUS_LOW_DRIVE</constant> | |
| 182 | + status bit is set.</entry> | |
| 183 | + </row> | |
| 184 | + <row> | |
| 185 | + <entry>__u8</entry> | |
| 186 | + <entry><structfield>tx_error_cnt</structfield></entry> | |
| 187 | + <entry>A counter of the number of transmit errors other than Arbitration Lost | |
| 188 | + or Not Acknowledged. This is only set if the hardware supports this, otherwise | |
| 189 | + it is always 0. This counter is only valid if the <constant>CEC_TX_STATUS_ERROR</constant> | |
| 190 | + status bit is set.</entry> | |
| 191 | + </row> | |
| 192 | + </tbody> | |
| 193 | + </tgroup> | |
| 194 | + </table> | |
| 195 | + | |
| 196 | + <table pgwide="1" frame="none" id="cec-tx-status"> | |
| 197 | + <title>CEC Transmit Status</title> | |
| 198 | + <tgroup cols="3"> | |
| 199 | + &cs-def; | |
| 200 | + <tbody valign="top"> | |
| 201 | + <row> | |
| 202 | + <entry><constant>CEC_TX_STATUS_OK</constant></entry> | |
| 203 | + <entry>0x01</entry> | |
| 204 | + <entry>The message was transmitted successfully. This is mutually exclusive with | |
| 205 | + <constant>CEC_TX_STATUS_MAX_RETRIES</constant>. Other bits can still be set if | |
| 206 | + earlier attempts met with failure before the transmit was eventually successful.</entry> | |
| 207 | + </row> | |
| 208 | + <row> | |
| 209 | + <entry><constant>CEC_TX_STATUS_ARB_LOST</constant></entry> | |
| 210 | + <entry>0x02</entry> | |
| 211 | + <entry>CEC line arbitration was lost.</entry> | |
| 212 | + </row> | |
| 213 | + <row> | |
| 214 | + <entry><constant>CEC_TX_STATUS_NACK</constant></entry> | |
| 215 | + <entry>0x04</entry> | |
| 216 | + <entry>Message was not acknowledged.</entry> | |
| 217 | + </row> | |
| 218 | + <row> | |
| 219 | + <entry><constant>CEC_TX_STATUS_LOW_DRIVE</constant></entry> | |
| 220 | + <entry>0x08</entry> | |
| 221 | + <entry>Low drive was detected on the CEC bus. This indicates that a follower | |
| 222 | + detected an error on the bus and requests a retransmission.</entry> | |
| 223 | + </row> | |
| 224 | + <row> | |
| 225 | + <entry><constant>CEC_TX_STATUS_ERROR</constant></entry> | |
| 226 | + <entry>0x10</entry> | |
| 227 | + <entry>Some error occurred. This is used for any errors that do not | |
| 228 | + fit the previous two, either because the hardware could not tell | |
| 229 | + which error occurred, or because the hardware tested for other conditions | |
| 230 | + besides those two.</entry> | |
| 231 | + </row> | |
| 232 | + <row> | |
| 233 | + <entry><constant>CEC_TX_STATUS_MAX_RETRIES</constant></entry> | |
| 234 | + <entry>0x20</entry> | |
| 235 | + <entry>The transmit failed after one or more retries. This status bit is mutually | |
| 236 | + exclusive with <constant>CEC_TX_STATUS_OK</constant>. Other bits can still be set | |
| 237 | + to explain which failures were seen.</entry> | |
| 238 | + </row> | |
| 239 | + </tbody> | |
| 240 | + </tgroup> | |
| 241 | + </table> | |
| 242 | + | |
| 243 | + <table pgwide="1" frame="none" id="cec-rx-status"> | |
| 244 | + <title>CEC Receive Status</title> | |
| 245 | + <tgroup cols="3"> | |
| 246 | + &cs-def; | |
| 247 | + <tbody valign="top"> | |
| 248 | + <row> | |
| 249 | + <entry><constant>CEC_RX_STATUS_OK</constant></entry> | |
| 250 | + <entry>0x01</entry> | |
| 251 | + <entry>The message was received successfully.</entry> | |
| 252 | + </row> | |
| 253 | + <row> | |
| 254 | + <entry><constant>CEC_RX_STATUS_TIMEOUT</constant></entry> | |
| 255 | + <entry>0x02</entry> | |
| 256 | + <entry>The reply to an earlier transmitted message timed out.</entry> | |
| 257 | + </row> | |
| 258 | + <row> | |
| 259 | + <entry><constant>CEC_RX_STATUS_FEATURE_ABORT</constant></entry> | |
| 260 | + <entry>0x04</entry> | |
| 261 | + <entry>The message was received successfully but the reply was | |
| 262 | + <constant>CEC_MSG_FEATURE_ABORT</constant>. This status is only | |
| 263 | + set if this message was the reply to an earlier transmitted | |
| 264 | + message.</entry> | |
| 265 | + </row> | |
| 266 | + </tbody> | |
| 267 | + </tgroup> | |
| 268 | + </table> | |
| 269 | + </refsect1> | |
| 270 | + | |
| 271 | + <refsect1> | |
| 272 | + &return-value; | |
| 273 | + </refsect1> | |
| 274 | +</refentry> | |
| @@ -88,7 +88,7 @@ function.<footnote> · 87 unmodified lines | ||
| 88 | 88 | <structfield>capabilities</structfield> field of &v4l2-capability; |
| 89 | 89 | returned by the &VIDIOC-QUERYCAP; ioctl is set. There are two |
| 90 | 90 | streaming methods, to determine if the memory mapping flavor is |
| 91 | −supported applications must call the &VIDIOC-REQBUFS; ioctl.</para> | |
| 91 | +supported applications must call the &VIDIOC-REQBUFS; ioctl with the memory type set to <constant>V4L2_MEMORY_MMAP</constant>.</para> | |
| 92 | 92 | |
| 93 | 93 | <para>Streaming is an I/O method where only pointers to buffers |
| 94 | 94 | are exchanged between application and driver, the data itself is not |
| @@ -369,7 +369,7 @@ rest should be evident.</para> · 274 unmodified lines | ||
| 369 | 369 | <structfield>capabilities</structfield> field of &v4l2-capability; |
| 370 | 370 | returned by the &VIDIOC-QUERYCAP; ioctl is set. If the particular user |
| 371 | 371 | pointer method (not only memory mapping) is supported must be |
| 372 | −determined by calling the &VIDIOC-REQBUFS; ioctl.</para> | |
| 372 | +determined by calling the &VIDIOC-REQBUFS; ioctl with the memory type set to <constant>V4L2_MEMORY_USERPTR</constant>.</para> | |
| 373 | 373 | |
| 374 | 374 | <para>This I/O method combines advantages of the read/write and |
| 375 | 375 | memory mapping methods. Buffers (planes) are allocated by the application |
| @@ -157,7 +157,7 @@ on working with the default settings initially.</para> · 156 unmodified lines | ||
| 157 | 157 | <varlistentry> |
| 158 | 158 | <term>LIRC_SET_{SEND,REC}_CARRIER</term> |
| 159 | 159 | <listitem> |
| 160 | − <para>Set send/receive carrier (in Hz).</para> | |
| 160 | + <para>Set send/receive carrier (in Hz). Return 0 on success.</para> | |
| 161 | 161 | </listitem> |
| 162 | 162 | </varlistentry> |
| 163 | 163 | <varlistentry> |
| @@ -121,6 +121,70 @@ · 120 unmodified lines | ||
| 121 | 121 | <entry><constant>MEDIA_ENT_F_AUDIO_MIXER</constant></entry> |
| 122 | 122 | <entry>Audio Mixer Function Entity.</entry> |
| 123 | 123 | </row> |
| 124 | + <row> | |
| 125 | + <entry><constant>MEDIA_ENT_F_PROC_VIDEO_COMPOSER</constant></entry> | |
| 126 | + <entry>Video composer (blender). An entity capable of video | |
| 127 | + composing must have at least two sink pads and one source | |
| 128 | + pad, and composes input video frames onto output video | |
| 129 | + frames. Composition can be performed using alpha blending, | |
| 130 | + color keying, raster operations (ROP), stitching or any other | |
| 131 | + means. | |
| 132 | + </entry> | |
| 133 | + </row> | |
| 134 | + <row> | |
| 135 | + <entry><constant>MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER</constant></entry> | |
| 136 | + <entry>Video pixel formatter. An entity capable of pixel formatting | |
| 137 | + must have at least one sink pad and one source pad. Read | |
| 138 | + pixel formatters read pixels from memory and perform a subset | |
| 139 | + of unpacking, cropping, color keying, alpha multiplication | |
| 140 | + and pixel encoding conversion. Write pixel formatters perform | |
| 141 | + a subset of dithering, pixel encoding conversion and packing | |
| 142 | + and write pixels to memory. | |
| 143 | + </entry> | |
| 144 | + </row> | |
| 145 | + <row> | |
| 146 | + <entry><constant>MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV</constant></entry> | |
| 147 | + <entry>Video pixel encoding converter. An entity capable of pixel | |
| 148 | + enconding conversion must have at least one sink pad and one | |
| 149 | + source pad, and convert the encoding of pixels received on | |
| 150 | + its sink pad(s) to a different encoding output on its source | |
| 151 | + pad(s). Pixel encoding conversion includes but isn't limited | |
| 152 | + to RGB to/from HSV, RGB to/from YUV and CFA (Bayer) to RGB | |
| 153 | + conversions. | |
| 154 | + </entry> | |
| 155 | + </row> | |
| 156 | + <row> | |
| 157 | + <entry><constant>MEDIA_ENT_F_PROC_VIDEO_LUT</constant></entry> | |
| 158 | + <entry>Video look-up table. An entity capable of video lookup table | |
| 159 | + processing must have one sink pad and one source pad. It uses | |
| 160 | + the values of the pixels received on its sink pad to look up | |
| 161 | + entries in internal tables and output them on its source pad. | |
| 162 | + The lookup processing can be performed on all components | |
| 163 | + separately or combine them for multi-dimensional table | |
| 164 | + lookups. | |
| 165 | + </entry> | |
| 166 | + </row> | |
| 167 | + <row> | |
| 168 | + <entry><constant>MEDIA_ENT_F_PROC_VIDEO_SCALER</constant></entry> | |
| 169 | + <entry>Video scaler. An entity capable of video scaling must have | |
| 170 | + at least one sink pad and one source pad, and scale the | |
| 171 | + video frame(s) received on its sink pad(s) to a different | |
| 172 | + resolution output on its source pad(s). The range of | |
| 173 | + supported scaling ratios is entity-specific and can differ | |
| 174 | + between the horizontal and vertical directions (in particular | |
| 175 | + scaling can be supported in one direction only). Binning and | |
| 176 | + skipping are considered as scaling. | |
| 177 | + </entry> | |
| 178 | + </row> | |
| 179 | + <row> | |
| 180 | + <entry><constant>MEDIA_ENT_F_PROC_VIDEO_STATISTICS</constant></entry> | |
| 181 | + <entry>Video statistics computation (histogram, 3A, ...). An entity | |
| 182 | + capable of statistics computation must have one sink pad and | |
| 183 | + one source pad. It computes statistics over the frames | |
| 184 | + received on its sink pad and outputs the statistics data on | |
| 185 | + its source pad. | |
| 186 | + </entry> | |
| 187 | + </row> | |
| 124 | 188 | </tbody> |
| 125 | 189 | </tgroup> |
| 126 | 190 | </table> |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | </refmeta> |
| 6 | 6 | <refnamediv> |
| 7 | 7 | <refname><constant>V4L2_PIX_FMT_Z16</constant></refname> |
| 8 | − <refpurpose>Interleaved grey-scale image, e.g. from a stereo-pair</refpurpose> | |
| 8 | + <refpurpose>16-bit depth data with distance values at each pixel</refpurpose> | |
| 9 | 9 | </refnamediv> |
| 10 | 10 | <refsect1> |
| 11 | 11 | <title>Description</title> |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | |
| 7 | 7 | <refnamediv> |
| 8 | 8 | <refname>VIDIOC_REQBUFS</refname> |
| 9 | − <refpurpose>Initiate Memory Mapping or User Pointer I/O</refpurpose> | |
| 9 | + <refpurpose>Initiate Memory Mapping, User Pointer or DMA Buffer I/O</refpurpose> | |
| 10 | 10 | </refnamediv> |
| 11 | 11 | |
| 12 | 12 | <refsynopsisdiv> |
| @@ -75,7 +75,7 @@ · 74 unmodified lines | ||
| 75 | 75 | </mediaobject> |
| 76 | 76 | </figure> |
| 77 | 77 | <para>The media infrastructure API was designed to control such |
| 78 | − devices. It is divided into four parts.</para> | |
| 78 | + devices. It is divided into five parts.</para> | |
| 79 | 79 | <para>The first part covers radio, video capture and output, |
| 80 | 80 | cameras, analog TV devices and codecs.</para> |
| 81 | 81 | <para>The second part covers the |
| @@ -87,6 +87,7 @@ · 5 unmodified lines | ||
| 87 | 87 | <xref linkend="fe-delivery-system-t" />.</para> |
| 88 | 88 | <para>The third part covers the Remote Controller API.</para> |
| 89 | 89 | <para>The fourth part covers the Media Controller API.</para> |
| 90 | + <para>The fifth part covers the CEC (Consumer Electronics Control) API.</para> | |
| 90 | 91 | <para>It should also be noted that a media device may also have audio |
| 91 | 92 | components, like mixers, PCM capture, PCM playback, etc, which |
| 92 | 93 | are controlled via ALSA API.</para> |
| @@ -107,6 +108,9 @@ · 14 unmodified lines | ||
| 107 | 108 | <part id="media_common"> |
| 108 | 109 | &sub-media-controller; |
| 109 | 110 | </part> |
| 111 | +<part id="cec"> | |
| 112 | +&sub-cec-api; | |
| 113 | +</part> | |
| 110 | 114 | |
| 111 | 115 | <chapter id="gen_errors"> |
| 112 | 116 | &sub-gen-errors; |
| @@ -0,0 +1,267 @@ | ||
| 1 | +CEC Kernel Support | |
| 2 | +================== | |
| 3 | + | |
| 4 | +The CEC framework provides a unified kernel interface for use with HDMI CEC | |
| 5 | +hardware. It is designed to handle a multiple types of hardware (receivers, | |
| 6 | +transmitters, USB dongles). The framework also gives the option to decide | |
| 7 | +what to do in the kernel driver and what should be handled by userspace | |
| 8 | +applications. In addition it integrates the remote control passthrough | |
| 9 | +feature into the kernel's remote control framework. | |
| 10 | + | |
| 11 | + | |
| 12 | +The CEC Protocol | |
| 13 | +---------------- | |
| 14 | + | |
| 15 | +The CEC protocol enables consumer electronic devices to communicate with each | |
| 16 | +other through the HDMI connection. The protocol uses logical addresses in the | |
| 17 | +communication. The logical address is strictly connected with the functionality | |
| 18 | +provided by the device. The TV acting as the communication hub is always | |
| 19 | +assigned address 0. The physical address is determined by the physical | |
| 20 | +connection between devices. | |
| 21 | + | |
| 22 | +The CEC framework described here is up to date with the CEC 2.0 specification. | |
| 23 | +It is documented in the HDMI 1.4 specification with the new 2.0 bits documented | |
| 24 | +in the HDMI 2.0 specification. But for most of the features the freely available | |
| 25 | +HDMI 1.3a specification is sufficient: | |
| 26 | + | |
| 27 | +http://www.microprocessor.org/HDMISpecification13a.pdf | |
| 28 | + | |
| 29 | + | |
| 30 | +The Kernel Interface | |
| 31 | +==================== | |
| 32 | + | |
| 33 | +CEC Adapter | |
| 34 | +----------- | |
| 35 | + | |
| 36 | +The struct cec_adapter represents the CEC adapter hardware. It is created by | |
| 37 | +calling cec_allocate_adapter() and deleted by calling cec_delete_adapter(): | |
| 38 | + | |
| 39 | +struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, | |
| 40 | + void *priv, const char *name, u32 caps, u8 available_las, | |
| 41 | + struct device *parent); | |
| 42 | +void cec_delete_adapter(struct cec_adapter *adap); | |
| 43 | + | |
| 44 | +To create an adapter you need to pass the following information: | |
| 45 | + | |
| 46 | +ops: adapter operations which are called by the CEC framework and that you | |
| 47 | +have to implement. | |
| 48 | + | |
| 49 | +priv: will be stored in adap->priv and can be used by the adapter ops. | |
| 50 | + | |
| 51 | +name: the name of the CEC adapter. Note: this name will be copied. | |
| 52 | + | |
| 53 | +caps: capabilities of the CEC adapter. These capabilities determine the | |
| 54 | + capabilities of the hardware and which parts are to be handled | |
| 55 | + by userspace and which parts are handled by kernelspace. The | |
| 56 | + capabilities are returned by CEC_ADAP_G_CAPS. | |
| 57 | + | |
| 58 | +available_las: the number of simultaneous logical addresses that this | |
| 59 | + adapter can handle. Must be 1 <= available_las <= CEC_MAX_LOG_ADDRS. | |
| 60 | + | |
| 61 | +parent: the parent device. | |
| 62 | + | |
| 63 | + | |
| 64 | +To register the /dev/cecX device node and the remote control device (if | |
| 65 | +CEC_CAP_RC is set) you call: | |
| 66 | + | |
| 67 | +int cec_register_adapter(struct cec_adapter *adap); | |
| 68 | + | |
| 69 | +To unregister the devices call: | |
| 70 | + | |
| 71 | +void cec_unregister_adapter(struct cec_adapter *adap); | |
| 72 | + | |
| 73 | +Note: if cec_register_adapter() fails, then call cec_delete_adapter() to | |
| 74 | +clean up. But if cec_register_adapter() succeeded, then only call | |
| 75 | +cec_unregister_adapter() to clean up, never cec_delete_adapter(). The | |
| 76 | +unregister function will delete the adapter automatically once the last user | |
| 77 | +of that /dev/cecX device has closed its file handle. | |
| 78 | + | |
| 79 | + | |
| 80 | +Implementing the Low-Level CEC Adapter | |
| 81 | +-------------------------------------- | |
| 82 | + | |
| 83 | +The following low-level adapter operations have to be implemented in | |
| 84 | +your driver: | |
| 85 | + | |
| 86 | +struct cec_adap_ops { | |
| 87 | + /* Low-level callbacks */ | |
| 88 | + int (*adap_enable)(struct cec_adapter *adap, bool enable); | |
| 89 | + int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable); | |
| 90 | + int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr); | |
| 91 | + int (*adap_transmit)(struct cec_adapter *adap, u8 attempts, | |
| 92 | + u32 signal_free_time, struct cec_msg *msg); | |
| 93 | + void (*adap_log_status)(struct cec_adapter *adap); | |
| 94 | + | |
| 95 | + /* High-level callbacks */ | |
| 96 | + ... | |
| 97 | +}; | |
| 98 | + | |
| 99 | +The three low-level ops deal with various aspects of controlling the CEC adapter | |
| 100 | +hardware: | |
| 101 | + | |
| 102 | + | |
| 103 | +To enable/disable the hardware: | |
| 104 | + | |
| 105 | + int (*adap_enable)(struct cec_adapter *adap, bool enable); | |
| 106 | + | |
| 107 | +This callback enables or disables the CEC hardware. Enabling the CEC hardware | |
| 108 | +means powering it up in a state where no logical addresses are claimed. This | |
| 109 | +op assumes that the physical address (adap->phys_addr) is valid when enable is | |
| 110 | +true and will not change while the CEC adapter remains enabled. The initial | |
| 111 | +state of the CEC adapter after calling cec_allocate_adapter() is disabled. | |
| 112 | + | |
| 113 | +Note that adap_enable must return 0 if enable is false. | |
| 114 | + | |
| 115 | + | |
| 116 | +To enable/disable the 'monitor all' mode: | |
| 117 | + | |
| 118 | + int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable); | |
| 119 | + | |
| 120 | +If enabled, then the adapter should be put in a mode to also monitor messages | |
| 121 | +that not for us. Not all hardware supports this and this function is only | |
| 122 | +called if the CEC_CAP_MONITOR_ALL capability is set. This callback is optional | |
| 123 | +(some hardware may always be in 'monitor all' mode). | |
| 124 | + | |
| 125 | +Note that adap_monitor_all_enable must return 0 if enable is false. | |
| 126 | + | |
| 127 | + | |
| 128 | +To program a new logical address: | |
| 129 | + | |
| 130 | + int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr); | |
| 131 | + | |
| 132 | +If logical_addr == CEC_LOG_ADDR_INVALID then all programmed logical addresses | |
| 133 | +are to be erased. Otherwise the given logical address should be programmed. | |
| 134 | +If the maximum number of available logical addresses is exceeded, then it | |
| 135 | +should return -ENXIO. Once a logical address is programmed the CEC hardware | |
| 136 | +can receive directed messages to that address. | |
| 137 | + | |
| 138 | +Note that adap_log_addr must return 0 if logical_addr is CEC_LOG_ADDR_INVALID. | |
| 139 | + | |
| 140 | + | |
| 141 | +To transmit a new message: | |
| 142 | + | |
| 143 | + int (*adap_transmit)(struct cec_adapter *adap, u8 attempts, | |
| 144 | + u32 signal_free_time, struct cec_msg *msg); | |
| 145 | + | |
| 146 | +This transmits a new message. The attempts argument is the suggested number of | |
| 147 | +attempts for the transmit. | |
| 148 | + | |
| 149 | +The signal_free_time is the number of data bit periods that the adapter should | |
| 150 | +wait when the line is free before attempting to send a message. This value | |
| 151 | +depends on whether this transmit is a retry, a message from a new initiator or | |
| 152 | +a new message for the same initiator. Most hardware will handle this | |
| 153 | +automatically, but in some cases this information is needed. | |
| 154 | + | |
| 155 | +The CEC_FREE_TIME_TO_USEC macro can be used to convert signal_free_time to | |
| 156 | +microseconds (one data bit period is 2.4 ms). | |
| 157 | + | |
| 158 | + | |
| 159 | +To log the current CEC hardware status: | |
| 160 | + | |
| 161 | + void (*adap_status)(struct cec_adapter *adap, struct seq_file *file); | |
| 162 | + | |
| 163 | +This optional callback can be used to show the status of the CEC hardware. | |
| 164 | +The status is available through debugfs: cat /sys/kernel/debug/cec/cecX/status | |
| 165 | + | |
| 166 | + | |
| 167 | +Your adapter driver will also have to react to events (typically interrupt | |
| 168 | +driven) by calling into the framework in the following situations: | |
| 169 | + | |
| 170 | +When a transmit finished (successfully or otherwise): | |
| 171 | + | |
| 172 | +void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt, | |
| 173 | + u8 nack_cnt, u8 low_drive_cnt, u8 error_cnt); | |
| 174 | + | |
| 175 | +The status can be one of: | |
| 176 | + | |
| 177 | +CEC_TX_STATUS_OK: the transmit was successful. | |
| 178 | +CEC_TX_STATUS_ARB_LOST: arbitration was lost: another CEC initiator | |
| 179 | +took control of the CEC line and you lost the arbitration. | |
| 180 | +CEC_TX_STATUS_NACK: the message was nacked (for a directed message) or | |
| 181 | +acked (for a broadcast message). A retransmission is needed. | |
| 182 | +CEC_TX_STATUS_LOW_DRIVE: low drive was detected on the CEC bus. This | |
| 183 | +indicates that a follower detected an error on the bus and requested a | |
| 184 | +retransmission. | |
| 185 | +CEC_TX_STATUS_ERROR: some unspecified error occurred: this can be one of | |
| 186 | +the previous two if the hardware cannot differentiate or something else | |
| 187 | +entirely. | |
| 188 | +CEC_TX_STATUS_MAX_RETRIES: could not transmit the message after | |
| 189 | +trying multiple times. Should only be set by the driver if it has hardware | |
| 190 | +support for retrying messages. If set, then the framework assumes that it | |
| 191 | +doesn't have to make another attempt to transmit the message since the | |
| 192 | +hardware did that already. | |
| 193 | + | |
| 194 | +The *_cnt arguments are the number of error conditions that were seen. | |
| 195 | +This may be 0 if no information is available. Drivers that do not support | |
| 196 | +hardware retry can just set the counter corresponding to the transmit error | |
| 197 | +to 1, if the hardware does support retry then either set these counters to | |
| 198 | +0 if the hardware provides no feedback of which errors occurred and how many | |
| 199 | +times, or fill in the correct values as reported by the hardware. | |
| 200 | + | |
| 201 | +When a CEC message was received: | |
| 202 | + | |
| 203 | +void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg); | |
| 204 | + | |
| 205 | +Speaks for itself. | |
| 206 | + | |
| 207 | +Implementing the High-Level CEC Adapter | |
| 208 | +--------------------------------------- | |
| 209 | + | |
| 210 | +The low-level operations drive the hardware, the high-level operations are | |
| 211 | +CEC protocol driven. The following high-level callbacks are available: | |
| 212 | + | |
| 213 | +struct cec_adap_ops { | |
| 214 | + /* Low-level callbacks */ | |
| 215 | + ... | |
| 216 | + | |
| 217 | + /* High-level CEC message callback */ | |
| 218 | + int (*received)(struct cec_adapter *adap, struct cec_msg *msg); | |
| 219 | +}; | |
| 220 | + | |
| 221 | +The received() callback allows the driver to optionally handle a newly | |
| 222 | +received CEC message | |
| 223 | + | |
| 224 | + int (*received)(struct cec_adapter *adap, struct cec_msg *msg); | |
| 225 | + | |
| 226 | +If the driver wants to process a CEC message, then it can implement this | |
| 227 | +callback. If it doesn't want to handle this message, then it should return | |
| 228 | +-ENOMSG, otherwise the CEC framework assumes it processed this message and | |
| 229 | +it will not no anything with it. | |
| 230 | + | |
| 231 | + | |
| 232 | +CEC framework functions | |
| 233 | +----------------------- | |
| 234 | + | |
| 235 | +CEC Adapter drivers can call the following CEC framework functions: | |
| 236 | + | |
| 237 | +int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg, | |
| 238 | + bool block); | |
| 239 | + | |
| 240 | +Transmit a CEC message. If block is true, then wait until the message has been | |
| 241 | +transmitted, otherwise just queue it and return. | |
| 242 | + | |
| 243 | +void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block); | |
| 244 | + | |
| 245 | +Change the physical address. This function will set adap->phys_addr and | |
| 246 | +send an event if it has changed. If cec_s_log_addrs() has been called and | |
| 247 | +the physical address has become valid, then the CEC framework will start | |
| 248 | +claiming the logical addresses. If block is true, then this function won't | |
| 249 | +return until this process has finished. | |
| 250 | + | |
| 251 | +When the physical address is set to a valid value the CEC adapter will | |
| 252 | +be enabled (see the adap_enable op). When it is set to CEC_PHYS_ADDR_INVALID, | |
| 253 | +then the CEC adapter will be disabled. If you change a valid physical address | |
| 254 | +to another valid physical address, then this function will first set the | |
| 255 | +address to CEC_PHYS_ADDR_INVALID before enabling the new physical address. | |
| 256 | + | |
| 257 | +int cec_s_log_addrs(struct cec_adapter *adap, | |
| 258 | + struct cec_log_addrs *log_addrs, bool block); | |
| 259 | + | |
| 260 | +Claim the CEC logical addresses. Should never be called if CEC_CAP_LOG_ADDRS | |
| 261 | +is set. If block is true, then wait until the logical addresses have been | |
| 262 | +claimed, otherwise just queue it and return. To unconfigure all logical | |
| 263 | +addresses call this function with log_addrs set to NULL or with | |
| 264 | +log_addrs->num_log_addrs set to 0. The block argument is ignored when | |
| 265 | +unconfiguring. This function will just return if the physical address is | |
| 266 | +invalid. Once the physical address becomes valid, then the framework will | |
| 267 | +attempt to claim these logical addresses. | |
| @@ -0,0 +1,59 @@ | ||
| 1 | +Mediatek Video Codec | |
| 2 | + | |
| 3 | +Mediatek Video Codec is the video codec hw present in Mediatek SoCs which | |
| 4 | +supports high resolution encoding functionalities. | |
| 5 | + | |
| 6 | +Required properties: | |
| 7 | +- compatible : "mediatek,mt8173-vcodec-enc" for encoder | |
| 8 | +- reg : Physical base address of the video codec registers and length of | |
| 9 | + memory mapped region. | |
| 10 | +- interrupts : interrupt number to the cpu. | |
| 11 | +- mediatek,larb : must contain the local arbiters in the current Socs. | |
| 12 | +- clocks : list of clock specifiers, corresponding to entries in | |
| 13 | + the clock-names property. | |
| 14 | +- clock-names: encoder must contain "venc_sel_src", "venc_sel", | |
| 15 | +- "venc_lt_sel_src", "venc_lt_sel". | |
| 16 | +- iommus : should point to the respective IOMMU block with master port as | |
| 17 | + argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt | |
| 18 | + for details. | |
| 19 | +- mediatek,vpu : the node of video processor unit | |
| 20 | + | |
| 21 | +Example: | |
| 22 | +vcodec_enc: vcodec@0x18002000 { | |
| 23 | + compatible = "mediatek,mt8173-vcodec-enc"; | |
| 24 | + reg = <0 0x18002000 0 0x1000>, /*VENC_SYS*/ | |
| 25 | + <0 0x19002000 0 0x1000>; /*VENC_LT_SYS*/ | |
| 26 | + interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_LOW>, | |
| 27 | + <GIC_SPI 202 IRQ_TYPE_LEVEL_LOW>; | |
| 28 | + mediatek,larb = <&larb3>, | |
| 29 | + <&larb5>; | |
| 30 | + iommus = <&iommu M4U_PORT_VENC_RCPU>, | |
| 31 | + <&iommu M4U_PORT_VENC_REC>, | |
| 32 | + <&iommu M4U_PORT_VENC_BSDMA>, | |
| 33 | + <&iommu M4U_PORT_VENC_SV_COMV>, | |
| 34 | + <&iommu M4U_PORT_VENC_RD_COMV>, | |
| 35 | + <&iommu M4U_PORT_VENC_CUR_LUMA>, | |
| 36 | + <&iommu M4U_PORT_VENC_CUR_CHROMA>, | |
| 37 | + <&iommu M4U_PORT_VENC_REF_LUMA>, | |
| 38 | + <&iommu M4U_PORT_VENC_REF_CHROMA>, | |
| 39 | + <&iommu M4U_PORT_VENC_NBM_RDMA>, | |
| 40 | + <&iommu M4U_PORT_VENC_NBM_WDMA>, | |
| 41 | + <&iommu M4U_PORT_VENC_RCPU_SET2>, | |
| 42 | + <&iommu M4U_PORT_VENC_REC_FRM_SET2>, | |
| 43 | + <&iommu M4U_PORT_VENC_BSDMA_SET2>, | |
| 44 | + <&iommu M4U_PORT_VENC_SV_COMA_SET2>, | |
| 45 | + <&iommu M4U_PORT_VENC_RD_COMA_SET2>, | |
| 46 | + <&iommu M4U_PORT_VENC_CUR_LUMA_SET2>, | |
| 47 | + <&iommu M4U_PORT_VENC_CUR_CHROMA_SET2>, | |
| 48 | + <&iommu M4U_PORT_VENC_REF_LUMA_SET2>, | |
| 49 | + <&iommu M4U_PORT_VENC_REC_CHROMA_SET2>; | |
| 50 | + mediatek,vpu = <&vpu>; | |
| 51 | + clocks = <&topckgen CLK_TOP_VENCPLL_D2>, | |
| 52 | + <&topckgen CLK_TOP_VENC_SEL>, | |
| 53 | + <&topckgen CLK_TOP_UNIVPLL1_D2>, | |
| 54 | + <&topckgen CLK_TOP_VENC_LT_SEL>; | |
| 55 | + clock-names = "venc_sel_src", | |
| 56 | + "venc_sel", | |
| 57 | + "venc_lt_sel_src", | |
| 58 | + "venc_lt_sel"; | |
| 59 | + }; | |
| @@ -0,0 +1,31 @@ | ||
| 1 | +* Mediatek Video Processor Unit | |
| 2 | + | |
| 3 | +Video Processor Unit is a HW video controller. It controls HW Codec including | |
| 4 | +H.264/VP8/VP9 Decode, H.264/VP8 Encode and Image Processor (scale/rotate/color convert). | |
| 5 | + | |
| 6 | +Required properties: | |
| 7 | + - compatible: "mediatek,mt8173-vpu" | |
| 8 | + - reg: Must contain an entry for each entry in reg-names. | |
| 9 | + - reg-names: Must include the following entries: | |
| 10 | + "tcm": tcm base | |
| 11 | + "cfg_reg": Main configuration registers base | |
| 12 | + - interrupts: interrupt number to the cpu. | |
| 13 | + - clocks : clock name from clock manager | |
| 14 | + - clock-names: must be main. It is the main clock of VPU | |
| 15 | + | |
| 16 | +Optional properties: | |
| 17 | + - memory-region: phandle to a node describing memory (see | |
| 18 | + Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt) | |
| 19 | + to be used for VPU extended memory; if not present, VPU may be located | |
| 20 | + anywhere in the memory | |
| 21 | + | |
| 22 | +Example: | |
| 23 | + vpu: vpu@10020000 { | |
| 24 | + compatible = "mediatek,mt8173-vpu"; | |
| 25 | + reg = <0 0x10020000 0 0x30000>, | |
| 26 | + <0 0x10050000 0 0x100>; | |
| 27 | + reg-names = "tcm", "cfg_reg"; | |
| 28 | + interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>; | |
| 29 | + clocks = <&topckgen TOP_SCP_SEL>; | |
| 30 | + clock-names = "main"; | |
| 31 | + }; | |
| @@ -0,0 +1,32 @@ | ||
| 1 | +Renesas R-Car Frame Compression Processor (FCP) | |
| 2 | +----------------------------------------------- | |
| 3 | + | |
| 4 | +The FCP is a companion module of video processing modules in the Renesas R-Car | |
| 5 | +Gen3 SoCs. It provides data compression and decompression, data caching, and | |
| 6 | +conversion of AXI transactions in order to reduce the memory bandwidth. | |
| 7 | + | |
| 8 | +There are three types of FCP: FCP for Codec (FCPC), FCP for VSP (FCPV) and FCP | |
| 9 | +for FDP (FCPF). Their configuration and behaviour depend on the module they | |
| 10 | +are paired with. These DT bindings currently support the FCPV only. | |
| 11 | + | |
| 12 | + - compatible: Must be one or more of the following | |
| 13 | + | |
| 14 | + - "renesas,r8a7795-fcpv" for R8A7795 (R-Car H3) compatible 'FCP for VSP' | |
| 15 | + - "renesas,fcpv" for generic compatible 'FCP for VSP' | |
| 16 | + | |
| 17 | + When compatible with the generic version, nodes must list the | |
| 18 | + SoC-specific version corresponding to the platform first, followed by the | |
| 19 | + family-specific and/or generic versions. | |
| 20 | + | |
| 21 | + - reg: the register base and size for the device registers | |
| 22 | + - clocks: Reference to the functional clock | |
| 23 | + | |
| 24 | + | |
| 25 | +Device node example | |
| 26 | +------------------- | |
| 27 | + | |
| 28 | + fcpvd1: fcp@fea2f000 { | |
| 29 | + compatible = "renesas,r8a7795-fcpv", "renesas,fcpv"; | |
| 30 | + reg = <0 0xfea2f000 0 0x200>; | |
| 31 | + clocks = <&cpg CPG_MOD 602>; | |
| 32 | + }; | |
| @@ -14,6 +14,11 @@ Required properties: · 13 unmodified lines | ||
| 14 | 14 | - interrupts: VSP interrupt specifier. |
| 15 | 15 | - clocks: A phandle + clock-specifier pair for the VSP functional clock. |
| 16 | 16 | |
| 17 | +Optional properties: | |
| 18 | + | |
| 19 | + - renesas,fcp: A phandle referencing the FCP that handles memory accesses | |
| 20 | + for the VSP. Not needed on Gen2, mandatory on Gen3. | |
| 21 | + | |
| 17 | 22 | |
| 18 | 23 | Example: R8A7790 (R-Car H2) VSP1-S node |
| 19 | 24 | |
| @@ -0,0 +1,31 @@ | ||
| 1 | +* Samsung HDMI CEC driver | |
| 2 | + | |
| 3 | +The HDMI CEC module is present is Samsung SoCs and its purpose is to | |
| 4 | +handle communication between HDMI connected devices over the CEC bus. | |
| 5 | + | |
| 6 | +Required properties: | |
| 7 | + - compatible : value should be following | |
| 8 | + "samsung,s5p-cec" | |
| 9 | + | |
| 10 | + - reg : Physical base address of the IP registers and length of memory | |
| 11 | + mapped region. | |
| 12 | + | |
| 13 | + - interrupts : HDMI CEC interrupt number to the CPU. | |
| 14 | + - clocks : from common clock binding: handle to HDMI CEC clock. | |
| 15 | + - clock-names : from common clock binding: must contain "hdmicec", | |
| 16 | + corresponding to entry in the clocks property. | |
| 17 | + - samsung,syscon-phandle - phandle to the PMU system controller | |
| 18 | + | |
| 19 | +Example: | |
| 20 | + | |
| 21 | +hdmicec: cec@100B0000 { | |
| 22 | + compatible = "samsung,s5p-cec"; | |
| 23 | + reg = <0x100B0000 0x200>; | |
| 24 | + interrupts = <0 114 0>; | |
| 25 | + clocks = <&clock CLK_HDMI_CEC>; | |
| 26 | + clock-names = "hdmicec"; | |
| 27 | + samsung,syscon-phandle = <&pmu_system_controller>; | |
| 28 | + pinctrl-names = "default"; | |
| 29 | + pinctrl-0 = <&hdmi_cec>; | |
| 30 | + status = "okay"; | |
| 31 | +}; | |
| @@ -21,15 +21,18 @@ Required properties: · 20 unmodified lines | ||
| 21 | 21 | - clock-names : from common clock binding: must contain "mfc", |
| 22 | 22 | corresponding to entry in the clocks property. |
| 23 | 23 | |
| 24 | − - samsung,mfc-r : Base address of the first memory bank used by MFC | |
| 25 | − for DMA contiguous memory allocation and its size. | |
| 26 | − | |
| 27 | − - samsung,mfc-l : Base address of the second memory bank used by MFC | |
| 28 | − for DMA contiguous memory allocation and its size. | |
| 29 | − | |
| 30 | 24 | Optional properties: |
| 31 | 25 | - power-domains : power-domain property defined with a phandle |
| 32 | 26 | to respective power domain. |
| 27 | + - memory-region : from reserved memory binding: phandles to two reserved | |
| 28 | + memory regions, first is for "left" mfc memory bus interfaces, | |
| 29 | + second if for the "right" mfc memory bus, used when no SYSMMU | |
| 30 | + support is available | |
| 31 | + | |
| 32 | +Obsolete properties: | |
| 33 | + - samsung,mfc-r, samsung,mfc-l : support removed, please use memory-region | |
| 34 | + property instead | |
| 35 | + | |
| 33 | 36 | |
| 34 | 37 | Example: |
| 35 | 38 | SoC specific DT entry: |
| @@ -43,9 +46,29 @@ mfc: codec@13400000 { · 7 unmodified lines | ||
| 43 | 46 | clock-names = "mfc"; |
| 44 | 47 | }; |
| 45 | 48 | |
| 49 | +Reserved memory specific DT entry for given board (see reserved memory binding | |
| 50 | +for more information): | |
| 51 | + | |
| 52 | +reserved-memory { | |
| 53 | + #address-cells = <1>; | |
| 54 | + #size-cells = <1>; | |
| 55 | + ranges; | |
| 56 | + | |
| 57 | + mfc_left: region@51000000 { | |
| 58 | + compatible = "shared-dma-pool"; | |
| 59 | + no-map; | |
| 60 | + reg = <0x51000000 0x800000>; | |
| 61 | + }; | |
| 62 | + | |
| 63 | + mfc_right: region@43000000 { | |
| 64 | + compatible = "shared-dma-pool"; | |
| 65 | + no-map; | |
| 66 | + reg = <0x43000000 0x800000>; | |
| 67 | + }; | |
| 68 | +}; | |
| 69 | + | |
| 46 | 70 | Board specific DT entry: |
| 47 | 71 | |
| 48 | 72 | codec@13400000 { |
| 49 | − samsung,mfc-r = <0x43000000 0x800000>; | |
| 50 | − samsung,mfc-l = <0x51000000 0x800000>; | |
| 73 | + memory-region = <&mfc_left>, <&mfc_right>; | |
| 51 | 74 | }; |
| @@ -54,3 +54,4 @@ · 53 unmodified lines | ||
| 54 | 54 | 53 -> Hauppauge WinTV Starburst [0070:c12a] |
| 55 | 55 | 54 -> ViewCast 260e [1576:0260] |
| 56 | 56 | 55 -> ViewCast 460e [1576:0460] |
| 57 | + 56 -> Hauppauge WinTV-quadHD (DVB) [0070:6a28,0070:6b28] | |
| @@ -96,21 +96,6 @@ Basic usage for V4L2 and sub-device drivers · 95 unmodified lines | ||
| 96 | 96 | |
| 97 | 97 | Where foo->sd is of type struct v4l2_subdev. |
| 98 | 98 | |
| 99 | − And set all core control ops in your struct v4l2_subdev_core_ops to these | |
| 100 | − helpers: | |
| 101 | − | |
| 102 | − .queryctrl = v4l2_subdev_queryctrl, | |
| 103 | − .querymenu = v4l2_subdev_querymenu, | |
| 104 | − .g_ctrl = v4l2_subdev_g_ctrl, | |
| 105 | − .s_ctrl = v4l2_subdev_s_ctrl, | |
| 106 | − .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | |
| 107 | − .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | |
| 108 | − .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | |
| 109 | − | |
| 110 | − Note: this is a temporary solution only. Once all V4L2 drivers that depend | |
| 111 | − on subdev drivers are converted to the control framework these helpers will | |
| 112 | − no longer be needed. | |
| 113 | − | |
| 114 | 99 | 1.4) Clean up the handler at the end: |
| 115 | 100 | |
| 116 | 101 | v4l2_ctrl_handler_free(&foo->ctrl_handler); |
| @@ -74,7 +74,8 @@ Section 11: Cropping, Composing, Scaling · 73 unmodified lines | ||
| 74 | 74 | Section 12: Formats |
| 75 | 75 | Section 13: Capture Overlay |
| 76 | 76 | Section 14: Output Overlay |
| 77 | −Section 15: Some Future Improvements | |
| 77 | +Section 15: CEC (Consumer Electronics Control) | |
| 78 | +Section 16: Some Future Improvements | |
| 78 | 79 | |
| 79 | 80 | |
| 80 | 81 | Section 1: Configuring the driver |
| @@ -364,7 +365,11 @@ For HDMI inputs it is possible to set the EDID. By default a simple EDID · 283 unmodified lines | ||
| 364 | 365 | is provided. You can only set the EDID for HDMI inputs. Internally, however, |
| 365 | 366 | the EDID is shared between all HDMI inputs. |
| 366 | 367 | |
| 367 | −No interpretation is done of the EDID data. | |
| 368 | +No interpretation is done of the EDID data with the exception of the | |
| 369 | +physical address. See the CEC section for more details. | |
| 370 | + | |
| 371 | +There is a maximum of 15 HDMI inputs (if there are more, then they will be | |
| 372 | +reduced to 15) since that's the limitation of the EDID physical address. | |
| 368 | 373 | |
| 369 | 374 | |
| 370 | 375 | Section 3: Video Output |
| @@ -409,6 +414,9 @@ standard, and for all others a 1:1 pixel aspect ratio is returned. · 38 unmodified lines | ||
| 409 | 414 | |
| 410 | 415 | An HDMI output has a valid EDID which can be obtained through VIDIOC_G_EDID. |
| 411 | 416 | |
| 417 | +There is a maximum of 15 HDMI outputs (if there are more, then they will be | |
| 418 | +reduced to 15) since that's the limitation of the EDID physical address. See | |
| 419 | +also the CEC section for more details. | |
| 412 | 420 | |
| 413 | 421 | Section 4: VBI Capture |
| 414 | 422 | ---------------------- |
| @@ -1108,7 +1116,26 @@ capabilities will slow down the video loop considerably as a lot of checks have · 693 unmodified lines | ||
| 1108 | 1116 | to be done per pixel. |
| 1109 | 1117 | |
| 1110 | 1118 | |
| 1111 | −Section 15: Some Future Improvements | |
| 1119 | +Section 15: CEC (Consumer Electronics Control) | |
| 1120 | +---------------------------------------------- | |
| 1121 | + | |
| 1122 | +If there are HDMI inputs then a CEC adapter will be created that has | |
| 1123 | +the same number of input ports. This is the equivalent of e.g. a TV that | |
| 1124 | +has that number of inputs. Each HDMI output will also create a | |
| 1125 | +CEC adapter that is hooked up to the corresponding input port, or (if there | |
| 1126 | +are more outputs than inputs) is not hooked up at all. In other words, | |
| 1127 | +this is the equivalent of hooking up each output device to an input port of | |
| 1128 | +the TV. Any remaining output devices remain unconnected. | |
| 1129 | + | |
| 1130 | +The EDID that each output reads reports a unique CEC physical address that is | |
| 1131 | +based on the physical address of the EDID of the input. So if the EDID of the | |
| 1132 | +receiver has physical address A.B.0.0, then each output will see an EDID | |
| 1133 | +containing physical address A.B.C.0 where C is 1 to the number of inputs. If | |
| 1134 | +there are more outputs than inputs then the remaining outputs have a CEC adapter | |
| 1135 | +that is disabled and reports an invalid physical address. | |
| 1136 | + | |
| 1137 | + | |
| 1138 | +Section 16: Some Future Improvements | |
| 1112 | 1139 | ------------------------------------ |
| 1113 | 1140 | |
| 1114 | 1141 | Just as a reminder and in no particular order: |
| @@ -1121,8 +1148,6 @@ Just as a reminder and in no particular order: · 6 unmodified lines | ||
| 1121 | 1148 | - Fix sequence/field numbering when looping of video with alternate fields |
| 1122 | 1149 | - Add support for V4L2_CID_BG_COLOR for video outputs |
| 1123 | 1150 | - Add ARGB888 overlay support: better testing of the alpha channel |
| 1124 | −- Add custom DV timings support | |
| 1125 | −- Add support for V4L2_DV_FL_REDUCED_FPS | |
| 1126 | 1151 | - Improve pixel aspect support in the tpg code by passing a real v4l2_fract |
| 1127 | 1152 | - Use per-queue locks and/or per-device locks to improve throughput |
| 1128 | 1153 | - Add support to loop from a specific output to a specific input across |
| @@ -1133,3 +1158,4 @@ Just as a reminder and in no particular order: · 4 unmodified lines | ||
| 1133 | 1158 | - Make a thread for the RDS generation, that would help in particular for the |
| 1134 | 1159 | "Controls" RDS Rx I/O Mode as the read-only RDS controls could be updated |
| 1135 | 1160 | in real-time. |
| 1161 | +- Changing the EDID should cause hotplug detect emulation to happen. | |
| @@ -1648,6 +1648,13 @@ L: linux-media@vger.kernel.org · 1647 unmodified lines | ||
| 1648 | 1648 | S: Maintained |
| 1649 | 1649 | F: drivers/media/platform/s5p-tv/ |
| 1650 | 1650 | |
| 1651 | +ARM/SAMSUNG S5P SERIES HDMI CEC SUBSYSTEM SUPPORT | |
| 1652 | +M: Kyungmin Park <kyungmin.park@samsung.com> | |
| 1653 | +L: linux-arm-kernel@lists.infradead.org | |
| 1654 | +L: linux-media@vger.kernel.org | |
| 1655 | +S: Maintained | |
| 1656 | +F: drivers/staging/media/platform/s5p-cec/ | |
| 1657 | + | |
| 1651 | 1658 | ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT |
| 1652 | 1659 | M: Andrzej Pietrasiewicz <andrzej.p@samsung.com> |
| 1653 | 1660 | M: Jacek Anaszewski <j.anaszewski@samsung.com> |
| @@ -2851,6 +2858,22 @@ F: drivers/net/ieee802154/cc2520.c · 1197 unmodified lines | ||
| 2851 | 2858 | F: include/linux/spi/cc2520.h |
| 2852 | 2859 | F: Documentation/devicetree/bindings/net/ieee802154/cc2520.txt |
| 2853 | 2860 | |
| 2861 | +CEC DRIVER | |
| 2862 | +M: Hans Verkuil <hans.verkuil@cisco.com> | |
| 2863 | +L: linux-media@vger.kernel.org | |
| 2864 | +T: git git://linuxtv.org/media_tree.git | |
| 2865 | +W: http://linuxtv.org | |
| 2866 | +S: Supported | |
| 2867 | +F: Documentation/cec.txt | |
| 2868 | +F: Documentation/DocBook/media/v4l/cec* | |
| 2869 | +F: drivers/staging/media/cec/ | |
| 2870 | +F: drivers/media/cec-edid.c | |
| 2871 | +F: drivers/media/rc/keymaps/rc-cec.c | |
| 2872 | +F: include/media/cec.h | |
| 2873 | +F: include/media/cec-edid.h | |
| 2874 | +F: include/linux/cec.h | |
| 2875 | +F: include/linux/cec-funcs.h | |
| 2876 | + | |
| 2854 | 2877 | CELL BROADBAND ENGINE ARCHITECTURE |
| 2855 | 2878 | M: Arnd Bergmann <arnd@arndb.de> |
| 2856 | 2879 | L: linuxppc-dev@lists.ozlabs.org |
| @@ -5177,10 +5200,10 @@ S: Maintained · 2320 unmodified lines | ||
| 5177 | 5200 | F: drivers/media/usb/gspca/m5602/ |
| 5178 | 5201 | |
| 5179 | 5202 | GSPCA PAC207 SONIXB SUBDRIVER |
| 5180 | −M: Hans de Goede <hdegoede@redhat.com> | |
| 5203 | +M: Hans Verkuil <hverkuil@xs4all.nl> | |
| 5181 | 5204 | L: linux-media@vger.kernel.org |
| 5182 | 5205 | T: git git://linuxtv.org/media_tree.git |
| 5183 | −S: Maintained | |
| 5206 | +S: Odd Fixes | |
| 5184 | 5207 | F: drivers/media/usb/gspca/pac207.c |
| 5185 | 5208 | |
| 5186 | 5209 | GSPCA SN9C20X SUBDRIVER |
| @@ -5198,10 +5221,10 @@ S: Maintained · 11 unmodified lines | ||
| 5198 | 5221 | F: drivers/media/usb/gspca/t613.c |
| 5199 | 5222 | |
| 5200 | 5223 | GSPCA USB WEBCAM DRIVER |
| 5201 | −M: Hans de Goede <hdegoede@redhat.com> | |
| 5224 | +M: Hans Verkuil <hverkuil@xs4all.nl> | |
| 5202 | 5225 | L: linux-media@vger.kernel.org |
| 5203 | 5226 | T: git git://linuxtv.org/media_tree.git |
| 5204 | −S: Maintained | |
| 5227 | +S: Odd Fixes | |
| 5205 | 5228 | F: drivers/media/usb/gspca/ |
| 5206 | 5229 | |
| 5207 | 5230 | GUID PARTITION TABLE (GPT) |
| @@ -7344,6 +7367,16 @@ L: linux-iio@vger.kernel.org · 2136 unmodified lines | ||
| 7344 | 7367 | S: Maintained |
| 7345 | 7368 | F: drivers/iio/potentiometer/mcp4531.c |
| 7346 | 7369 | |
| 7370 | +MEDIA DRIVERS FOR RENESAS - FCP | |
| 7371 | +M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | |
| 7372 | +L: linux-media@vger.kernel.org | |
| 7373 | +L: linux-renesas-soc@vger.kernel.org | |
| 7374 | +T: git git://linuxtv.org/media_tree.git | |
| 7375 | +S: Supported | |
| 7376 | +F: Documentation/devicetree/bindings/media/renesas,fcp.txt | |
| 7377 | +F: drivers/media/platform/rcar-fcp.c | |
| 7378 | +F: include/media/rcar-fcp.h | |
| 7379 | + | |
| 7347 | 7380 | MEDIA DRIVERS FOR RENESAS - VSP1 |
| 7348 | 7381 | M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| 7349 | 7382 | L: linux-media@vger.kernel.org |
| @@ -7353,8 +7386,18 @@ S: Supported · 3 unmodified lines | ||
| 7353 | 7386 | F: Documentation/devicetree/bindings/media/renesas,vsp1.txt |
| 7354 | 7387 | F: drivers/media/platform/vsp1/ |
| 7355 | 7388 | |
| 7389 | +MEDIA DRIVERS FOR HELENE | |
| 7390 | +M: Abylay Ospan <aospan@netup.ru> | |
| 7391 | +L: linux-media@vger.kernel.org | |
| 7392 | +W: https://linuxtv.org | |
| 7393 | +W: http://netup.tv/ | |
| 7394 | +T: git git://linuxtv.org/media_tree.git | |
| 7395 | +S: Supported | |
| 7396 | +F: drivers/media/dvb-frontends/helene* | |
| 7397 | + | |
| 7356 | 7398 | MEDIA DRIVERS FOR ASCOT2E |
| 7357 | 7399 | M: Sergey Kozlov <serjk@netup.ru> |
| 7400 | +M: Abylay Ospan <aospan@netup.ru> | |
| 7358 | 7401 | L: linux-media@vger.kernel.org |
| 7359 | 7402 | W: https://linuxtv.org |
| 7360 | 7403 | W: http://netup.tv/ |
| @@ -7364,6 +7407,7 @@ F: drivers/media/dvb-frontends/ascot2e* · 3 unmodified lines | ||
| 7364 | 7407 | |
| 7365 | 7408 | MEDIA DRIVERS FOR CXD2841ER |
| 7366 | 7409 | M: Sergey Kozlov <serjk@netup.ru> |
| 7410 | +M: Abylay Ospan <aospan@netup.ru> | |
| 7367 | 7411 | L: linux-media@vger.kernel.org |
| 7368 | 7412 | W: https://linuxtv.org |
| 7369 | 7413 | W: http://netup.tv/ |
| @@ -7373,6 +7417,7 @@ F: drivers/media/dvb-frontends/cxd2841er* · 3 unmodified lines | ||
| 7373 | 7417 | |
| 7374 | 7418 | MEDIA DRIVERS FOR HORUS3A |
| 7375 | 7419 | M: Sergey Kozlov <serjk@netup.ru> |
| 7420 | +M: Abylay Ospan <aospan@netup.ru> | |
| 7376 | 7421 | L: linux-media@vger.kernel.org |
| 7377 | 7422 | W: https://linuxtv.org |
| 7378 | 7423 | W: http://netup.tv/ |
| @@ -7382,6 +7427,7 @@ F: drivers/media/dvb-frontends/horus3a* · 3 unmodified lines | ||
| 7382 | 7427 | |
| 7383 | 7428 | MEDIA DRIVERS FOR LNBH25 |
| 7384 | 7429 | M: Sergey Kozlov <serjk@netup.ru> |
| 7430 | +M: Abylay Ospan <aospan@netup.ru> | |
| 7385 | 7431 | L: linux-media@vger.kernel.org |
| 7386 | 7432 | W: https://linuxtv.org |
| 7387 | 7433 | W: http://netup.tv/ |
| @@ -7391,6 +7437,7 @@ F: drivers/media/dvb-frontends/lnbh25* · 3 unmodified lines | ||
| 7391 | 7437 | |
| 7392 | 7438 | MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices |
| 7393 | 7439 | M: Sergey Kozlov <serjk@netup.ru> |
| 7440 | +M: Abylay Ospan <aospan@netup.ru> | |
| 7394 | 7441 | L: linux-media@vger.kernel.org |
| 7395 | 7442 | W: https://linuxtv.org |
| 7396 | 7443 | W: http://netup.tv/ |
| @@ -7640,10 +7687,8 @@ L: linux-media@vger.kernel.org · 243 unmodified lines | ||
| 7640 | 7687 | W: https://linuxtv.org |
| 7641 | 7688 | W: http://palosaari.fi/linux/ |
| 7642 | 7689 | Q: http://patchwork.linuxtv.org/project/linux-media/list/ |
| 7643 | −T: git git://linuxtv.org/anttip/media_tree.git | |
| 7644 | 7690 | S: Maintained |
| 7645 | −F: drivers/staging/media/mn88472/ | |
| 7646 | −F: drivers/media/dvb-frontends/mn88472.h | |
| 7691 | +F: drivers/media/dvb-frontends/mn88472* | |
| 7647 | 7692 | |
| 7648 | 7693 | MN88473 MEDIA DRIVER |
| 7649 | 7694 | M: Antti Palosaari <crope@iki.fi> |
| @@ -9255,6 +9300,13 @@ F: include/linux/tracehook.h · 1605 unmodified lines | ||
| 9255 | 9300 | F: include/uapi/linux/ptrace.h |
| 9256 | 9301 | F: kernel/ptrace.c |
| 9257 | 9302 | |
| 9303 | +PULSE8-CEC DRIVER | |
| 9304 | +M: Hans Verkuil <hverkuil@xs4all.nl> | |
| 9305 | +L: linux-media@vger.kernel.org | |
| 9306 | +T: git git://linuxtv.org/media_tree.git | |
| 9307 | +S: Maintained | |
| 9308 | +F: drivers/staging/media/pulse8-cec | |
| 9309 | + | |
| 9258 | 9310 | PVRUSB2 VIDEO4LINUX DRIVER |
| 9259 | 9311 | M: Mike Isely <isely@pobox.com> |
| 9260 | 9312 | L: pvrusb2@isely.net (subscribers-only) |
| @@ -9266,10 +9318,10 @@ F: Documentation/video4linux/README.pvrusb2 · 5 unmodified lines | ||
| 9266 | 9318 | F: drivers/media/usb/pvrusb2/ |
| 9267 | 9319 | |
| 9268 | 9320 | PWC WEBCAM DRIVER |
| 9269 | −M: Hans de Goede <hdegoede@redhat.com> | |
| 9321 | +M: Hans Verkuil <hverkuil@xs4all.nl> | |
| 9270 | 9322 | L: linux-media@vger.kernel.org |
| 9271 | 9323 | T: git git://linuxtv.org/media_tree.git |
| 9272 | −S: Maintained | |
| 9324 | +S: Odd Fixes | |
| 9273 | 9325 | F: drivers/media/usb/pwc/* |
| 9274 | 9326 | |
| 9275 | 9327 | PWM FAN DRIVER |
| @@ -9485,14 +9537,14 @@ F: drivers/video/fbdev/aty/radeon* · 209 unmodified lines | ||
| 9485 | 9537 | F: include/uapi/linux/radeonfb.h |
| 9486 | 9538 | |
| 9487 | 9539 | RADIOSHARK RADIO DRIVER |
| 9488 | −M: Hans de Goede <hdegoede@redhat.com> | |
| 9540 | +M: Hans Verkuil <hverkuil@xs4all.nl> | |
| 9489 | 9541 | L: linux-media@vger.kernel.org |
| 9490 | 9542 | T: git git://linuxtv.org/media_tree.git |
| 9491 | 9543 | S: Maintained |
| 9492 | 9544 | F: drivers/media/radio/radio-shark.c |
| 9493 | 9545 | |
| 9494 | 9546 | RADIOSHARK2 RADIO DRIVER |
| 9495 | −M: Hans de Goede <hdegoede@redhat.com> | |
| 9547 | +M: Hans Verkuil <hverkuil@xs4all.nl> | |
| 9496 | 9548 | L: linux-media@vger.kernel.org |
| 9497 | 9549 | T: git git://linuxtv.org/media_tree.git |
| 9498 | 9550 | S: Maintained |
| @@ -168,6 +168,18 @@ · 167 unmodified lines | ||
| 168 | 168 | }; |
| 169 | 169 | }; |
| 170 | 170 | |
| 171 | + reserved-memory { | |
| 172 | + #address-cells = <2>; | |
| 173 | + #size-cells = <2>; | |
| 174 | + ranges; | |
| 175 | + vpu_dma_reserved: vpu_dma_mem_region { | |
| 176 | + compatible = "shared-dma-pool"; | |
| 177 | + reg = <0 0xb7000000 0 0x500000>; | |
| 178 | + alignment = <0x1000>; | |
| 179 | + no-map; | |
| 180 | + }; | |
| 181 | + }; | |
| 182 | + | |
| 171 | 183 | timer { |
| 172 | 184 | compatible = "arm,armv8-timer"; |
| 173 | 185 | interrupt-parent = <&gic>; |
| @@ -312,6 +324,17 @@ · 138 unmodified lines | ||
| 312 | 324 | clock-names = "spi", "wrap"; |
| 313 | 325 | }; |
| 314 | 326 | |
| 327 | + vpu: vpu@10020000 { | |
| 328 | + compatible = "mediatek,mt8173-vpu"; | |
| 329 | + reg = <0 0x10020000 0 0x30000>, | |
| 330 | + <0 0x10050000 0 0x100>; | |
| 331 | + reg-names = "tcm", "cfg_reg"; | |
| 332 | + interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>; | |
| 333 | + clocks = <&topckgen CLK_TOP_SCP_SEL>; | |
| 334 | + clock-names = "main"; | |
| 335 | + memory-region = <&vpu_dma_reserved>; | |
| 336 | + }; | |
| 337 | + | |
| 315 | 338 | sysirq: intpol-controller@10200620 { |
| 316 | 339 | compatible = "mediatek,mt8173-sysirq", |
| 317 | 340 | "mediatek,mt6577-sysirq"; |
| @@ -754,6 +777,45 @@ · 436 unmodified lines | ||
| 754 | 777 | clock-names = "apb", "smi"; |
| 755 | 778 | }; |
| 756 | 779 | |
| 780 | + vcodec_enc: vcodec@18002000 { | |
| 781 | + compatible = "mediatek,mt8173-vcodec-enc"; | |
| 782 | + reg = <0 0x18002000 0 0x1000>, /* VENC_SYS */ | |
| 783 | + <0 0x19002000 0 0x1000>; /* VENC_LT_SYS */ | |
| 784 | + interrupts = <GIC_SPI 198 IRQ_TYPE_LEVEL_LOW>, | |
| 785 | + <GIC_SPI 202 IRQ_TYPE_LEVEL_LOW>; | |
| 786 | + mediatek,larb = <&larb3>, | |
| 787 | + <&larb5>; | |
| 788 | + iommus = <&iommu M4U_PORT_VENC_RCPU>, | |
| 789 | + <&iommu M4U_PORT_VENC_REC>, | |
| 790 | + <&iommu M4U_PORT_VENC_BSDMA>, | |
| 791 | + <&iommu M4U_PORT_VENC_SV_COMV>, | |
| 792 | + <&iommu M4U_PORT_VENC_RD_COMV>, | |
| 793 | + <&iommu M4U_PORT_VENC_CUR_LUMA>, | |
| 794 | + <&iommu M4U_PORT_VENC_CUR_CHROMA>, | |
| 795 | + <&iommu M4U_PORT_VENC_REF_LUMA>, | |
| 796 | + <&iommu M4U_PORT_VENC_REF_CHROMA>, | |
| 797 | + <&iommu M4U_PORT_VENC_NBM_RDMA>, | |
| 798 | + <&iommu M4U_PORT_VENC_NBM_WDMA>, | |
| 799 | + <&iommu M4U_PORT_VENC_RCPU_SET2>, | |
| 800 | + <&iommu M4U_PORT_VENC_REC_FRM_SET2>, | |
| 801 | + <&iommu M4U_PORT_VENC_BSDMA_SET2>, | |
| 802 | + <&iommu M4U_PORT_VENC_SV_COMA_SET2>, | |
| 803 | + <&iommu M4U_PORT_VENC_RD_COMA_SET2>, | |
| 804 | + <&iommu M4U_PORT_VENC_CUR_LUMA_SET2>, | |
| 805 | + <&iommu M4U_PORT_VENC_CUR_CHROMA_SET2>, | |
| 806 | + <&iommu M4U_PORT_VENC_REF_LUMA_SET2>, | |
| 807 | + <&iommu M4U_PORT_VENC_REC_CHROMA_SET2>; | |
| 808 | + mediatek,vpu = <&vpu>; | |
| 809 | + clocks = <&topckgen CLK_TOP_VENCPLL_D2>, | |
| 810 | + <&topckgen CLK_TOP_VENC_SEL>, | |
| 811 | + <&topckgen CLK_TOP_UNIVPLL1_D2>, | |
| 812 | + <&topckgen CLK_TOP_VENC_LT_SEL>; | |
| 813 | + clock-names = "venc_sel_src", | |
| 814 | + "venc_sel", | |
| 815 | + "venc_lt_sel_src", | |
| 816 | + "venc_lt_sel"; | |
| 817 | + }; | |
| 818 | + | |
| 757 | 819 | vencltsys: clock-controller@19000000 { |
| 758 | 820 | compatible = "mediatek,mt8173-vencltsys", "syscon"; |
| 759 | 821 | reg = <0 0x19000000 0 0x1000>; |
| @@ -1002,14 +1002,12 @@ static struct adv7842_output_format adv7842_opf[] = { · 1001 unmodified lines | ||
| 1002 | 1002 | { |
| 1003 | 1003 | .op_ch_sel = ADV7842_OP_CH_SEL_BRG, |
| 1004 | 1004 | .op_format_sel = ADV7842_OP_FORMAT_SEL_SDR_ITU656_8, |
| 1005 | − .op_656_range = 1, | |
| 1006 | 1005 | .blank_data = 1, |
| 1007 | 1006 | .insert_av_codes = 1, |
| 1008 | 1007 | }, |
| 1009 | 1008 | { |
| 1010 | 1009 | .op_ch_sel = ADV7842_OP_CH_SEL_RGB, |
| 1011 | 1010 | .op_format_sel = ADV7842_OP_FORMAT_SEL_SDR_ITU656_16, |
| 1012 | − .op_656_range = 1, | |
| 1013 | 1011 | .blank_data = 1, |
| 1014 | 1012 | }, |
| 1015 | 1013 | }; |
| @@ -148,40 +148,39 @@ static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane) · 147 unmodified lines | ||
| 148 | 148 | struct rcar_du_vsp_plane_state *state = |
| 149 | 149 | to_rcar_vsp_plane_state(plane->plane.state); |
| 150 | 150 | struct drm_framebuffer *fb = plane->plane.state->fb; |
| 151 | − struct v4l2_rect src; | |
| 152 | − struct v4l2_rect dst; | |
| 153 | − dma_addr_t paddr[2] = { 0, }; | |
| 154 | − u32 pixelformat = 0; | |
| 151 | + struct vsp1_du_atomic_config cfg = { | |
| 152 | + .pixelformat = 0, | |
| 153 | + .pitch = fb->pitches[0], | |
| 154 | + .alpha = state->alpha, | |
| 155 | + .zpos = state->zpos, | |
| 156 | + }; | |
| 155 | 157 | unsigned int i; |
| 156 | 158 | |
| 157 | − src.left = state->state.src_x >> 16; | |
| 158 | − src.top = state->state.src_y >> 16; | |
| 159 | − src.width = state->state.src_w >> 16; | |
| 160 | − src.height = state->state.src_h >> 16; | |
| 159 | + cfg.src.left = state->state.src_x >> 16; | |
| 160 | + cfg.src.top = state->state.src_y >> 16; | |
| 161 | + cfg.src.width = state->state.src_w >> 16; | |
| 162 | + cfg.src.height = state->state.src_h >> 16; | |
| 161 | 163 | |
| 162 | − dst.left = state->state.crtc_x; | |
| 163 | − dst.top = state->state.crtc_y; | |
| 164 | − dst.width = state->state.crtc_w; | |
| 165 | − dst.height = state->state.crtc_h; | |
| 164 | + cfg.dst.left = state->state.crtc_x; | |
| 165 | + cfg.dst.top = state->state.crtc_y; | |
| 166 | + cfg.dst.width = state->state.crtc_w; | |
| 167 | + cfg.dst.height = state->state.crtc_h; | |
| 166 | 168 | |
| 167 | 169 | for (i = 0; i < state->format->planes; ++i) { |
| 168 | 170 | struct drm_gem_cma_object *gem; |
| 169 | 171 | |
| 170 | 172 | gem = drm_fb_cma_get_gem_obj(fb, i); |
| 171 | − paddr[i] = gem->paddr + fb->offsets[i]; | |
| 173 | + cfg.mem[i] = gem->paddr + fb->offsets[i]; | |
| 172 | 174 | } |
| 173 | 175 | |
| 174 | 176 | for (i = 0; i < ARRAY_SIZE(formats_kms); ++i) { |
| 175 | 177 | if (formats_kms[i] == state->format->fourcc) { |
| 176 | − pixelformat = formats_v4l2[i]; | |
| 178 | + cfg.pixelformat = formats_v4l2[i]; | |
| 177 | 179 | break; |
| 178 | 180 | } |
| 179 | 181 | } |
| 180 | 182 | |
| 181 | − WARN_ON(!pixelformat); | |
| 182 | − | |
| 183 | − vsp1_du_atomic_update(plane->vsp->vsp, plane->index, pixelformat, | |
| 184 | − fb->pitches[0], paddr, &src, &dst); | |
| 183 | + vsp1_du_atomic_update(plane->vsp->vsp, plane->index, &cfg); | |
| 185 | 184 | } |
| 186 | 185 | |
| 187 | 186 | static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane, |
| @@ -220,8 +219,7 @@ static void rcar_du_vsp_plane_atomic_update(struct drm_plane *plane, · 32 unmodified lines | ||
| 220 | 219 | if (plane->state->crtc) |
| 221 | 220 | rcar_du_vsp_plane_setup(rplane); |
| 222 | 221 | else |
| 223 | − vsp1_du_atomic_update(rplane->vsp->vsp, rplane->index, 0, 0, 0, | |
| 224 | − NULL, NULL); | |
| 222 | + vsp1_du_atomic_update(rplane->vsp->vsp, rplane->index, NULL); | |
| 225 | 223 | } |
| 226 | 224 | |
| 227 | 225 | static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = { |
| @@ -269,6 +267,7 @@ static void rcar_du_vsp_plane_reset(struct drm_plane *plane) · 41 unmodified lines | ||
| 269 | 267 | return; |
| 270 | 268 | |
| 271 | 269 | state->alpha = 255; |
| 270 | + state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1; | |
| 272 | 271 | |
| 273 | 272 | plane->state = &state->state; |
| 274 | 273 | plane->state->plane = plane; |
| @@ -283,6 +282,8 @@ static int rcar_du_vsp_plane_atomic_set_property(struct drm_plane *plane, · 8 unmodified lines | ||
| 283 | 282 | |
| 284 | 283 | if (property == rcdu->props.alpha) |
| 285 | 284 | rstate->alpha = val; |
| 285 | + else if (property == rcdu->props.zpos) | |
| 286 | + rstate->zpos = val; | |
| 286 | 287 | else |
| 287 | 288 | return -EINVAL; |
| 288 | 289 | |
| @@ -299,6 +300,8 @@ static int rcar_du_vsp_plane_atomic_get_property(struct drm_plane *plane, · 10 unmodified lines | ||
| 299 | 300 | |
| 300 | 301 | if (property == rcdu->props.alpha) |
| 301 | 302 | *val = rstate->alpha; |
| 303 | + else if (property == rcdu->props.zpos) | |
| 304 | + *val = rstate->zpos; | |
| 302 | 305 | else |
| 303 | 306 | return -EINVAL; |
| 304 | 307 | |
| @@ -378,6 +381,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp) · 73 unmodified lines | ||
| 378 | 381 | |
| 379 | 382 | drm_object_attach_property(&plane->plane.base, |
| 380 | 383 | rcdu->props.alpha, 255); |
| 384 | + drm_object_attach_property(&plane->plane.base, | |
| 385 | + rcdu->props.zpos, 1); | |
| 381 | 386 | } |
| 382 | 387 | |
| 383 | 388 | return 0; |
| @@ -44,6 +44,7 @@ static inline struct rcar_du_vsp_plane *to_rcar_vsp_plane(struct drm_plane *p) · 43 unmodified lines | ||
| 44 | 44 | * @state: base DRM plane state |
| 45 | 45 | * @format: information about the pixel format used by the plane |
| 46 | 46 | * @alpha: value of the plane alpha property |
| 47 | + * @zpos: value of the plane zpos property | |
| 47 | 48 | */ |
| 48 | 49 | struct rcar_du_vsp_plane_state { |
| 49 | 50 | struct drm_plane_state state; |
| @@ -51,6 +52,7 @@ struct rcar_du_vsp_plane_state { · 1 unmodified line | ||
| 51 | 52 | const struct rcar_du_format_info *format; |
| 52 | 53 | |
| 53 | 54 | unsigned int alpha; |
| 55 | + unsigned int zpos; | |
| 54 | 56 | }; |
| 55 | 57 | |
| 56 | 58 | static inline struct rcar_du_vsp_plane_state * |
| @@ -126,7 +126,7 @@ struct sur40_image_header { · 125 unmodified lines | ||
| 126 | 126 | #define VIDEO_PACKET_SIZE 16384 |
| 127 | 127 | |
| 128 | 128 | /* polling interval (ms) */ |
| 129 | −#define POLL_INTERVAL 4 | |
| 129 | +#define POLL_INTERVAL 1 | |
| 130 | 130 | |
| 131 | 131 | /* maximum number of contacts FIXME: this is a guess? */ |
| 132 | 132 | #define MAX_CONTACTS 64 |
| @@ -151,7 +151,6 @@ struct sur40_state { · 18 unmodified lines | ||
| 151 | 151 | struct mutex lock; |
| 152 | 152 | |
| 153 | 153 | struct vb2_queue queue; |
| 154 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 155 | 154 | struct list_head buf_list; |
| 156 | 155 | spinlock_t qlock; |
| 157 | 156 | int sequence; |
| @@ -448,7 +447,7 @@ static void sur40_process_video(struct sur40_state *sur40) · 290 unmodified lines | ||
| 448 | 447 | |
| 449 | 448 | /* return error if streaming was stopped in the meantime */ |
| 450 | 449 | if (sur40->sequence == -1) |
| 451 | − goto err_poll; | |
| 450 | + return; | |
| 452 | 451 | |
| 453 | 452 | /* mark as finished */ |
| 454 | 453 | new_buf->vb.vb2_buf.timestamp = ktime_get_ns(); |
| @@ -580,19 +579,13 @@ static int sur40_probe(struct usb_interface *interface, · 125 unmodified lines | ||
| 580 | 579 | sur40->queue = sur40_queue; |
| 581 | 580 | sur40->queue.drv_priv = sur40; |
| 582 | 581 | sur40->queue.lock = &sur40->lock; |
| 582 | + sur40->queue.dev = sur40->dev; | |
| 583 | 583 | |
| 584 | 584 | /* initialize the queue */ |
| 585 | 585 | error = vb2_queue_init(&sur40->queue); |
| 586 | 586 | if (error) |
| 587 | 587 | goto err_unreg_v4l2; |
| 588 | 588 | |
| 589 | − sur40->alloc_ctx = vb2_dma_sg_init_ctx(sur40->dev); | |
| 590 | − if (IS_ERR(sur40->alloc_ctx)) { | |
| 591 | − dev_err(sur40->dev, "Can't allocate buffer context"); | |
| 592 | − error = PTR_ERR(sur40->alloc_ctx); | |
| 593 | − goto err_unreg_v4l2; | |
| 594 | − } | |
| 595 | − | |
| 596 | 589 | sur40->vdev = sur40_video_device; |
| 597 | 590 | sur40->vdev.v4l2_dev = &sur40->v4l2; |
| 598 | 591 | sur40->vdev.lock = &sur40->lock; |
| @@ -633,7 +626,6 @@ static void sur40_disconnect(struct usb_interface *interface) · 34 unmodified lines | ||
| 633 | 626 | |
| 634 | 627 | video_unregister_device(&sur40->vdev); |
| 635 | 628 | v4l2_device_unregister(&sur40->v4l2); |
| 636 | − vb2_dma_sg_cleanup_ctx(sur40->alloc_ctx); | |
| 637 | 629 | |
| 638 | 630 | input_unregister_polled_device(sur40->input); |
| 639 | 631 | input_free_polled_device(sur40->input); |
| @@ -653,13 +645,10 @@ static void sur40_disconnect(struct usb_interface *interface) · 13 unmodified lines | ||
| 653 | 645 | */ |
| 654 | 646 | static int sur40_queue_setup(struct vb2_queue *q, |
| 655 | 647 | unsigned int *nbuffers, unsigned int *nplanes, |
| 656 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 648 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 657 | 649 | { |
| 658 | − struct sur40_state *sur40 = vb2_get_drv_priv(q); | |
| 659 | − | |
| 660 | 650 | if (q->num_buffers + *nbuffers < 3) |
| 661 | 651 | *nbuffers = 3 - q->num_buffers; |
| 662 | − alloc_ctxs[0] = sur40->alloc_ctx; | |
| 663 | 652 | |
| 664 | 653 | if (*nplanes) |
| 665 | 654 | return sizes[0] < sur40_video_format.sizeimage ? -EINVAL : 0; |
| @@ -736,6 +725,7 @@ static int sur40_start_streaming(struct vb2_queue *vq, unsigned int count) · 70 unmodified lines | ||
| 736 | 725 | static void sur40_stop_streaming(struct vb2_queue *vq) |
| 737 | 726 | { |
| 738 | 727 | struct sur40_state *sur40 = vb2_get_drv_priv(vq); |
| 728 | + vb2_wait_for_all_buffers(vq); | |
| 739 | 729 | sur40->sequence = -1; |
| 740 | 730 | |
| 741 | 731 | /* Release all active buffers */ |
| @@ -793,7 +783,6 @@ static int sur40_vidioc_enum_fmt(struct file *file, void *priv, · 51 unmodified lines | ||
| 793 | 783 | { |
| 794 | 784 | if (f->index != 0) |
| 795 | 785 | return -EINVAL; |
| 796 | − strlcpy(f->description, "8-bit greyscale", sizeof(f->description)); | |
| 797 | 786 | f->pixelformat = V4L2_PIX_FMT_GREY; |
| 798 | 787 | f->flags = 0; |
| 799 | 788 | return 0; |
| @@ -80,6 +80,9 @@ config MEDIA_RC_SUPPORT · 79 unmodified lines | ||
| 80 | 80 | |
| 81 | 81 | Say Y when you have a TV or an IR device. |
| 82 | 82 | |
| 83 | +config MEDIA_CEC_EDID | |
| 84 | + bool | |
| 85 | + | |
| 83 | 86 | # |
| 84 | 87 | # Media controller |
| 85 | 88 | # Selectable only for webcam/grabbers, as other drivers don't use it |
| @@ -2,6 +2,10 @@ · 1 unmodified line | ||
| 2 | 2 | # Makefile for the kernel multimedia device drivers. |
| 3 | 3 | # |
| 4 | 4 | |
| 5 | +ifeq ($(CONFIG_MEDIA_CEC_EDID),y) | |
| 6 | + obj-$(CONFIG_MEDIA_SUPPORT) += cec-edid.o | |
| 7 | +endif | |
| 8 | + | |
| 5 | 9 | media-objs := media-device.o media-devnode.o media-entity.o |
| 6 | 10 | |
| 7 | 11 | # |
| @@ -0,0 +1,168 @@ | ||
| 1 | +/* | |
| 2 | + * cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions | |
| 3 | + * | |
| 4 | + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. | |
| 5 | + * | |
| 6 | + * This program is free software; you may redistribute it and/or modify | |
| 7 | + * it under the terms of the GNU General Public License as published by | |
| 8 | + * the Free Software Foundation; version 2 of the License. | |
| 9 | + * | |
| 10 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| 11 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
| 12 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| 13 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
| 14 | + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
| 15 | + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| 16 | + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 17 | + * SOFTWARE. | |
| 18 | + */ | |
| 19 | + | |
| 20 | +#include <linux/module.h> | |
| 21 | +#include <linux/kernel.h> | |
| 22 | +#include <linux/types.h> | |
| 23 | +#include <media/cec-edid.h> | |
| 24 | + | |
| 25 | +/* | |
| 26 | + * This EDID is expected to be a CEA-861 compliant, which means that there are | |
| 27 | + * at least two blocks and one or more of the extensions blocks are CEA-861 | |
| 28 | + * blocks. | |
| 29 | + * | |
| 30 | + * The returned location is guaranteed to be < size - 1. | |
| 31 | + */ | |
| 32 | +static unsigned int cec_get_edid_spa_location(const u8 *edid, unsigned int size) | |
| 33 | +{ | |
| 34 | + unsigned int blocks = size / 128; | |
| 35 | + unsigned int block; | |
| 36 | + u8 d; | |
| 37 | + | |
| 38 | + /* Sanity check: at least 2 blocks and a multiple of the block size */ | |
| 39 | + if (blocks < 2 || size % 128) | |
| 40 | + return 0; | |
| 41 | + | |
| 42 | + /* | |
| 43 | + * If there are fewer extension blocks than the size, then update | |
| 44 | + * 'blocks'. It is allowed to have more extension blocks than the size, | |
| 45 | + * since some hardware can only read e.g. 256 bytes of the EDID, even | |
| 46 | + * though more blocks are present. The first CEA-861 extension block | |
| 47 | + * should normally be in block 1 anyway. | |
| 48 | + */ | |
| 49 | + if (edid[0x7e] + 1 < blocks) | |
| 50 | + blocks = edid[0x7e] + 1; | |
| 51 | + | |
| 52 | + for (block = 1; block < blocks; block++) { | |
| 53 | + unsigned int offset = block * 128; | |
| 54 | + | |
| 55 | + /* Skip any non-CEA-861 extension blocks */ | |
| 56 | + if (edid[offset] != 0x02 || edid[offset + 1] != 0x03) | |
| 57 | + continue; | |
| 58 | + | |
| 59 | + /* search Vendor Specific Data Block (tag 3) */ | |
| 60 | + d = edid[offset + 2] & 0x7f; | |
| 61 | + /* Check if there are Data Blocks */ | |
| 62 | + if (d <= 4) | |
| 63 | + continue; | |
| 64 | + if (d > 4) { | |
| 65 | + unsigned int i = offset + 4; | |
| 66 | + unsigned int end = offset + d; | |
| 67 | + | |
| 68 | + /* Note: 'end' is always < 'size' */ | |
| 69 | + do { | |
| 70 | + u8 tag = edid[i] >> 5; | |
| 71 | + u8 len = edid[i] & 0x1f; | |
| 72 | + | |
| 73 | + if (tag == 3 && len >= 5 && i + len <= end) | |
| 74 | + return i + 4; | |
| 75 | + i += len + 1; | |
| 76 | + } while (i < end); | |
| 77 | + } | |
| 78 | + } | |
| 79 | + return 0; | |
| 80 | +} | |
| 81 | + | |
| 82 | +u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size, | |
| 83 | + unsigned int *offset) | |
| 84 | +{ | |
| 85 | + unsigned int loc = cec_get_edid_spa_location(edid, size); | |
| 86 | + | |
| 87 | + if (offset) | |
| 88 | + *offset = loc; | |
| 89 | + if (loc == 0) | |
| 90 | + return CEC_PHYS_ADDR_INVALID; | |
| 91 | + return (edid[loc] << 8) | edid[loc + 1]; | |
| 92 | +} | |
| 93 | +EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr); | |
| 94 | + | |
| 95 | +void cec_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr) | |
| 96 | +{ | |
| 97 | + unsigned int loc = cec_get_edid_spa_location(edid, size); | |
| 98 | + u8 sum = 0; | |
| 99 | + unsigned int i; | |
| 100 | + | |
| 101 | + if (loc == 0) | |
| 102 | + return; | |
| 103 | + edid[loc] = phys_addr >> 8; | |
| 104 | + edid[loc + 1] = phys_addr & 0xff; | |
| 105 | + loc &= ~0x7f; | |
| 106 | + | |
| 107 | + /* update the checksum */ | |
| 108 | + for (i = loc; i < loc + 127; i++) | |
| 109 | + sum += edid[i]; | |
| 110 | + edid[i] = 256 - sum; | |
| 111 | +} | |
| 112 | +EXPORT_SYMBOL_GPL(cec_set_edid_phys_addr); | |
| 113 | + | |
| 114 | +u16 cec_phys_addr_for_input(u16 phys_addr, u8 input) | |
| 115 | +{ | |
| 116 | + /* Check if input is sane */ | |
| 117 | + if (WARN_ON(input == 0 || input > 0xf)) | |
| 118 | + return CEC_PHYS_ADDR_INVALID; | |
| 119 | + | |
| 120 | + if (phys_addr == 0) | |
| 121 | + return input << 12; | |
| 122 | + | |
| 123 | + if ((phys_addr & 0x0fff) == 0) | |
| 124 | + return phys_addr | (input << 8); | |
| 125 | + | |
| 126 | + if ((phys_addr & 0x00ff) == 0) | |
| 127 | + return phys_addr | (input << 4); | |
| 128 | + | |
| 129 | + if ((phys_addr & 0x000f) == 0) | |
| 130 | + return phys_addr | input; | |
| 131 | + | |
| 132 | + /* | |
| 133 | + * All nibbles are used so no valid physical addresses can be assigned | |
| 134 | + * to the input. | |
| 135 | + */ | |
| 136 | + return CEC_PHYS_ADDR_INVALID; | |
| 137 | +} | |
| 138 | +EXPORT_SYMBOL_GPL(cec_phys_addr_for_input); | |
| 139 | + | |
| 140 | +int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port) | |
| 141 | +{ | |
| 142 | + int i; | |
| 143 | + | |
| 144 | + if (parent) | |
| 145 | + *parent = phys_addr; | |
| 146 | + if (port) | |
| 147 | + *port = 0; | |
| 148 | + if (phys_addr == CEC_PHYS_ADDR_INVALID) | |
| 149 | + return 0; | |
| 150 | + for (i = 0; i < 16; i += 4) | |
| 151 | + if (phys_addr & (0xf << i)) | |
| 152 | + break; | |
| 153 | + if (i == 16) | |
| 154 | + return 0; | |
| 155 | + if (parent) | |
| 156 | + *parent = phys_addr & (0xfff0 << i); | |
| 157 | + if (port) | |
| 158 | + *port = (phys_addr >> i) & 0xf; | |
| 159 | + for (i += 4; i < 16; i += 4) | |
| 160 | + if ((phys_addr & (0xf << i)) == 0) | |
| 161 | + return -EINVAL; | |
| 162 | + return 0; | |
| 163 | +} | |
| 164 | +EXPORT_SYMBOL_GPL(cec_phys_addr_validate); | |
| 165 | + | |
| 166 | +MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>"); | |
| 167 | +MODULE_DESCRIPTION("CEC EDID helper functions"); | |
| 168 | +MODULE_LICENSE("GPL"); | |
| @@ -777,7 +777,7 @@ static void precalculate_color(struct tpg_data *tpg, int k) · 776 unmodified lines | ||
| 777 | 777 | * Remember that r, g and b are still in the 0 - 0xff0 range. |
| 778 | 778 | */ |
| 779 | 779 | if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED && |
| 780 | − tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL) { | |
| 780 | + tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL && !tpg->is_yuv) { | |
| 781 | 781 | /* |
| 782 | 782 | * Convert from full range (which is what r, g and b are) |
| 783 | 783 | * to limited range (which is the 'real' RGB range), which |
| @@ -787,7 +787,7 @@ static void precalculate_color(struct tpg_data *tpg, int k) · 3 unmodified lines | ||
| 787 | 787 | g = (g * 219) / 255 + (16 << 4); |
| 788 | 788 | b = (b * 219) / 255 + (16 << 4); |
| 789 | 789 | } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED && |
| 790 | − tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED) { | |
| 790 | + tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED && !tpg->is_yuv) { | |
| 791 | 791 | /* |
| 792 | 792 | * Clamp r, g and b to the limited range and convert to full |
| 793 | 793 | * range since that's what we deliver. |
| @@ -143,7 +143,7 @@ struct dmx_ts_feed { · 142 unmodified lines | ||
| 143 | 143 | int type, |
| 144 | 144 | enum dmx_ts_pes pes_type, |
| 145 | 145 | size_t circular_buffer_size, |
| 146 | − struct timespec timeout); | |
| 146 | + ktime_t timeout); | |
| 147 | 147 | int (*start_filtering)(struct dmx_ts_feed *feed); |
| 148 | 148 | int (*stop_filtering)(struct dmx_ts_feed *feed); |
| 149 | 149 | }; |
| @@ -556,7 +556,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, · 555 unmodified lines | ||
| 556 | 556 | struct dmxdev_filter *filter, |
| 557 | 557 | struct dmxdev_feed *feed) |
| 558 | 558 | { |
| 559 | − struct timespec timeout = { 0 }; | |
| 559 | + ktime_t timeout = ktime_set(0, 0); | |
| 560 | 560 | struct dmx_pes_filter_params *para = &filter->params.pes; |
| 561 | 561 | dmx_output_t otype; |
| 562 | 562 | int ret; |
| @@ -123,6 +123,7 @@ struct dvb_ca_slot { · 122 unmodified lines | ||
| 123 | 123 | |
| 124 | 124 | /* Private CA-interface information */ |
| 125 | 125 | struct dvb_ca_private { |
| 126 | + struct kref refcount; | |
| 126 | 127 | |
| 127 | 128 | /* pointer back to the public data structure */ |
| 128 | 129 | struct dvb_ca_en50221 *pub; |
| @@ -161,6 +162,34 @@ struct dvb_ca_private { · 32 unmodified lines | ||
| 161 | 162 | struct mutex ioctl_mutex; |
| 162 | 163 | }; |
| 163 | 164 | |
| 165 | +static void dvb_ca_private_free(struct dvb_ca_private *ca) | |
| 166 | +{ | |
| 167 | + unsigned int i; | |
| 168 | + | |
| 169 | + dvb_unregister_device(ca->dvbdev); | |
| 170 | + for (i = 0; i < ca->slot_count; i++) | |
| 171 | + vfree(ca->slot_info[i].rx_buffer.data); | |
| 172 | + | |
| 173 | + kfree(ca->slot_info); | |
| 174 | + kfree(ca); | |
| 175 | +} | |
| 176 | + | |
| 177 | +static void dvb_ca_private_release(struct kref *ref) | |
| 178 | +{ | |
| 179 | + struct dvb_ca_private *ca = container_of(ref, struct dvb_ca_private, refcount); | |
| 180 | + dvb_ca_private_free(ca); | |
| 181 | +} | |
| 182 | + | |
| 183 | +static void dvb_ca_private_get(struct dvb_ca_private *ca) | |
| 184 | +{ | |
| 185 | + kref_get(&ca->refcount); | |
| 186 | +} | |
| 187 | + | |
| 188 | +static void dvb_ca_private_put(struct dvb_ca_private *ca) | |
| 189 | +{ | |
| 190 | + kref_put(&ca->refcount, dvb_ca_private_release); | |
| 191 | +} | |
| 192 | + | |
| 164 | 193 | static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); |
| 165 | 194 | static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); |
| 166 | 195 | static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); |
| @@ -1558,6 +1587,8 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) · 1391 unmodified lines | ||
| 1558 | 1587 | dvb_ca_en50221_thread_update_delay(ca); |
| 1559 | 1588 | dvb_ca_en50221_thread_wakeup(ca); |
| 1560 | 1589 | |
| 1590 | + dvb_ca_private_get(ca); | |
| 1591 | + | |
| 1561 | 1592 | return 0; |
| 1562 | 1593 | } |
| 1563 | 1594 | |
| @@ -1586,6 +1617,8 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) · 22 unmodified lines | ||
| 1586 | 1617 | |
| 1587 | 1618 | module_put(ca->pub->owner); |
| 1588 | 1619 | |
| 1620 | + dvb_ca_private_put(ca); | |
| 1621 | + | |
| 1589 | 1622 | return err; |
| 1590 | 1623 | } |
| 1591 | 1624 | |
| @@ -1681,6 +1714,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, · 89 unmodified lines | ||
| 1681 | 1714 | ret = -ENOMEM; |
| 1682 | 1715 | goto exit; |
| 1683 | 1716 | } |
| 1717 | + kref_init(&ca->refcount); | |
| 1684 | 1718 | ca->pub = pubca; |
| 1685 | 1719 | ca->flags = flags; |
| 1686 | 1720 | ca->slot_count = slot_count; |
| @@ -1759,10 +1793,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) · 72 unmodified lines | ||
| 1759 | 1793 | |
| 1760 | 1794 | for (i = 0; i < ca->slot_count; i++) { |
| 1761 | 1795 | dvb_ca_en50221_slot_shutdown(ca, i); |
| 1762 | − vfree(ca->slot_info[i].rx_buffer.data); | |
| 1763 | 1796 | } |
| 1764 | − kfree(ca->slot_info); | |
| 1765 | − dvb_unregister_device(ca->dvbdev); | |
| 1766 | − kfree(ca); | |
| 1797 | + dvb_ca_private_put(ca); | |
| 1767 | 1798 | pubca->private = NULL; |
| 1768 | 1799 | } |
| @@ -398,28 +398,23 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) · 397 unmodified lines | ||
| 398 | 398 | int dvr_done = 0; |
| 399 | 399 | |
| 400 | 400 | if (dvb_demux_speedcheck) { |
| 401 | − struct timespec cur_time, delta_time; | |
| 401 | + ktime_t cur_time; | |
| 402 | 402 | u64 speed_bytes, speed_timedelta; |
| 403 | 403 | |
| 404 | 404 | demux->speed_pkts_cnt++; |
| 405 | 405 | |
| 406 | 406 | /* show speed every SPEED_PKTS_INTERVAL packets */ |
| 407 | 407 | if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) { |
| 408 | − cur_time = current_kernel_time(); | |
| 408 | + cur_time = ktime_get(); | |
| 409 | 409 | |
| 410 | − if (demux->speed_last_time.tv_sec != 0 && | |
| 411 | − demux->speed_last_time.tv_nsec != 0) { | |
| 412 | − delta_time = timespec_sub(cur_time, | |
| 413 | − demux->speed_last_time); | |
| 410 | + if (ktime_to_ns(demux->speed_last_time) != 0) { | |
| 414 | 411 | speed_bytes = (u64)demux->speed_pkts_cnt |
| 415 | 412 | * 188 * 8; |
| 416 | 413 | /* convert to 1024 basis */ |
| 417 | 414 | speed_bytes = 1000 * div64_u64(speed_bytes, |
| 418 | 415 | 1024); |
| 419 | − speed_timedelta = | |
| 420 | − (u64)timespec_to_ns(&delta_time); | |
| 421 | − speed_timedelta = div64_u64(speed_timedelta, | |
| 422 | − 1000000); /* nsec -> usec */ | |
| 416 | + speed_timedelta = ktime_ms_delta(cur_time, | |
| 417 | + demux->speed_last_time); | |
| 423 | 418 | printk(KERN_INFO "TS speed %llu Kbits/sec \n", |
| 424 | 419 | div64_u64(speed_bytes, |
| 425 | 420 | speed_timedelta)); |
| @@ -666,7 +661,7 @@ out: · 240 unmodified lines | ||
| 666 | 661 | |
| 667 | 662 | static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, |
| 668 | 663 | enum dmx_ts_pes pes_type, |
| 669 | − size_t circular_buffer_size, struct timespec timeout) | |
| 664 | + size_t circular_buffer_size, ktime_t timeout) | |
| 670 | 665 | { |
| 671 | 666 | struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; |
| 672 | 667 | struct dvb_demux *demux = feed->demux; |
| @@ -83,7 +83,7 @@ struct dvb_demux_feed { · 82 unmodified lines | ||
| 83 | 83 | u8 *buffer; |
| 84 | 84 | int buffer_size; |
| 85 | 85 | |
| 86 | − struct timespec timeout; | |
| 86 | + ktime_t timeout; | |
| 87 | 87 | struct dvb_demux_filter *filter; |
| 88 | 88 | |
| 89 | 89 | int ts_type; |
| @@ -134,7 +134,7 @@ struct dvb_demux { · 44 unmodified lines | ||
| 134 | 134 | |
| 135 | 135 | uint8_t *cnt_storage; /* for TS continuity check */ |
| 136 | 136 | |
| 137 | − struct timespec speed_last_time; /* for TS speed check */ | |
| 137 | + ktime_t speed_last_time; /* for TS speed check */ | |
| 138 | 138 | uint32_t speed_pkts_cnt; /* for TS speed check */ |
| 139 | 139 | }; |
| 140 | 140 | |
| @@ -99,6 +99,7 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open( · 98 unmodified lines | ||
| 99 | 99 | static DEFINE_MUTEX(frontend_mutex); |
| 100 | 100 | |
| 101 | 101 | struct dvb_frontend_private { |
| 102 | + struct kref refcount; | |
| 102 | 103 | |
| 103 | 104 | /* thread/frontend values */ |
| 104 | 105 | struct dvb_device *dvbdev; |
| @@ -137,6 +138,23 @@ struct dvb_frontend_private { · 32 unmodified lines | ||
| 137 | 138 | #endif |
| 138 | 139 | }; |
| 139 | 140 | |
| 141 | +static void dvb_frontend_private_free(struct kref *ref) | |
| 142 | +{ | |
| 143 | + struct dvb_frontend_private *fepriv = | |
| 144 | + container_of(ref, struct dvb_frontend_private, refcount); | |
| 145 | + kfree(fepriv); | |
| 146 | +} | |
| 147 | + | |
| 148 | +static void dvb_frontend_private_put(struct dvb_frontend_private *fepriv) | |
| 149 | +{ | |
| 150 | + kref_put(&fepriv->refcount, dvb_frontend_private_free); | |
| 151 | +} | |
| 152 | + | |
| 153 | +static void dvb_frontend_private_get(struct dvb_frontend_private *fepriv) | |
| 154 | +{ | |
| 155 | + kref_get(&fepriv->refcount); | |
| 156 | +} | |
| 157 | + | |
| 140 | 158 | static void dvb_frontend_wakeup(struct dvb_frontend *fe); |
| 141 | 159 | static int dtv_get_frontend(struct dvb_frontend *fe, |
| 142 | 160 | struct dtv_frontend_properties *c, |
| @@ -2543,6 +2561,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) · 2400 unmodified lines | ||
| 2543 | 2561 | fepriv->events.eventr = fepriv->events.eventw = 0; |
| 2544 | 2562 | } |
| 2545 | 2563 | |
| 2564 | + dvb_frontend_private_get(fepriv); | |
| 2565 | + | |
| 2546 | 2566 | if (adapter->mfe_shared) |
| 2547 | 2567 | mutex_unlock (&adapter->mfe_lock); |
| 2548 | 2568 | return ret; |
| @@ -2591,6 +2611,8 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) · 42 unmodified lines | ||
| 2591 | 2611 | fe->ops.ts_bus_ctrl(fe, 0); |
| 2592 | 2612 | } |
| 2593 | 2613 | |
| 2614 | + dvb_frontend_private_put(fepriv); | |
| 2615 | + | |
| 2594 | 2616 | return ret; |
| 2595 | 2617 | } |
| 2596 | 2618 | |
| @@ -2679,6 +2701,8 @@ int dvb_register_frontend(struct dvb_adapter* dvb, · 82 unmodified lines | ||
| 2679 | 2701 | } |
| 2680 | 2702 | fepriv = fe->frontend_priv; |
| 2681 | 2703 | |
| 2704 | + kref_init(&fepriv->refcount); | |
| 2705 | + | |
| 2682 | 2706 | sema_init(&fepriv->sem, 1); |
| 2683 | 2707 | init_waitqueue_head (&fepriv->wait_queue); |
| 2684 | 2708 | init_waitqueue_head (&fepriv->events.wait_queue); |
| @@ -2713,18 +2737,11 @@ int dvb_unregister_frontend(struct dvb_frontend* fe) · 28 unmodified lines | ||
| 2713 | 2737 | |
| 2714 | 2738 | mutex_lock(&frontend_mutex); |
| 2715 | 2739 | dvb_frontend_stop (fe); |
| 2716 | − mutex_unlock(&frontend_mutex); | |
| 2717 | − | |
| 2718 | − if (fepriv->dvbdev->users < -1) | |
| 2719 | − wait_event(fepriv->dvbdev->wait_queue, | |
| 2720 | − fepriv->dvbdev->users==-1); | |
| 2721 | − | |
| 2722 | − mutex_lock(&frontend_mutex); | |
| 2723 | 2740 | dvb_unregister_device (fepriv->dvbdev); |
| 2724 | 2741 | |
| 2725 | 2742 | /* fe is invalid now */ |
| 2726 | − kfree(fepriv); | |
| 2727 | 2743 | mutex_unlock(&frontend_mutex); |
| 2744 | + dvb_frontend_private_put(fepriv); | |
| 2728 | 2745 | return 0; |
| 2729 | 2746 | } |
| 2730 | 2747 | EXPORT_SYMBOL(dvb_unregister_frontend); |
| @@ -997,7 +997,7 @@ static int dvb_net_feed_start(struct net_device *dev) · 996 unmodified lines | ||
| 997 | 997 | netdev_dbg(dev, "start filtering\n"); |
| 998 | 998 | priv->secfeed->start_filtering(priv->secfeed); |
| 999 | 999 | } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { |
| 1000 | − struct timespec timeout = { 0, 10000000 }; // 10 msec | |
| 1000 | + ktime_t timeout = ns_to_ktime(10 * NSEC_PER_MSEC); | |
| 1001 | 1001 | |
| 1002 | 1002 | /* we have payloads encapsulated in TS */ |
| 1003 | 1003 | netdev_dbg(dev, "alloc tsfeed\n"); |
| @@ -55,7 +55,13 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len) · 54 unmodified lines | ||
| 55 | 55 | |
| 56 | 56 | int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf) |
| 57 | 57 | { |
| 58 | − return (rbuf->pread==rbuf->pwrite); | |
| 58 | + /* smp_load_acquire() to load write pointer on reader side | |
| 59 | + * this pairs with smp_store_release() in dvb_ringbuffer_write(), | |
| 60 | + * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset() | |
| 61 | + * | |
| 62 | + * for memory barriers also see Documentation/circular-buffers.txt | |
| 63 | + */ | |
| 64 | + return (rbuf->pread == smp_load_acquire(&rbuf->pwrite)); | |
| 59 | 65 | } |
| 60 | 66 | |
| 61 | 67 | |
| @@ -64,7 +70,12 @@ ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf) · 2 unmodified lines | ||
| 64 | 70 | { |
| 65 | 71 | ssize_t free; |
| 66 | 72 | |
| 67 | − free = rbuf->pread - rbuf->pwrite; | |
| 73 | + /* ACCESS_ONCE() to load read pointer on writer side | |
| 74 | + * this pairs with smp_store_release() in dvb_ringbuffer_read(), | |
| 75 | + * dvb_ringbuffer_read_user(), dvb_ringbuffer_flush(), | |
| 76 | + * or dvb_ringbuffer_reset() | |
| 77 | + */ | |
| 78 | + free = ACCESS_ONCE(rbuf->pread) - rbuf->pwrite; | |
| 68 | 79 | if (free <= 0) |
| 69 | 80 | free += rbuf->size; |
| 70 | 81 | return free-1; |
| @@ -76,7 +87,11 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf) · 5 unmodified lines | ||
| 76 | 87 | { |
| 77 | 88 | ssize_t avail; |
| 78 | 89 | |
| 79 | − avail = rbuf->pwrite - rbuf->pread; | |
| 90 | + /* smp_load_acquire() to load write pointer on reader side | |
| 91 | + * this pairs with smp_store_release() in dvb_ringbuffer_write(), | |
| 92 | + * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset() | |
| 93 | + */ | |
| 94 | + avail = smp_load_acquire(&rbuf->pwrite) - rbuf->pread; | |
| 80 | 95 | if (avail < 0) |
| 81 | 96 | avail += rbuf->size; |
| 82 | 97 | return avail; |
| @@ -86,14 +101,25 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf) · 3 unmodified lines | ||
| 86 | 101 | |
| 87 | 102 | void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf) |
| 88 | 103 | { |
| 89 | − rbuf->pread = rbuf->pwrite; | |
| 104 | + /* dvb_ringbuffer_flush() counts as read operation | |
| 105 | + * smp_load_acquire() to load write pointer | |
| 106 | + * smp_store_release() to update read pointer, this ensures that the | |
| 107 | + * correct pointer is visible for subsequent dvb_ringbuffer_free() | |
| 108 | + * calls on other cpu cores | |
| 109 | + */ | |
| 110 | + smp_store_release(&rbuf->pread, smp_load_acquire(&rbuf->pwrite)); | |
| 90 | 111 | rbuf->error = 0; |
| 91 | 112 | } |
| 92 | 113 | EXPORT_SYMBOL(dvb_ringbuffer_flush); |
| 93 | 114 | |
| 94 | 115 | void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf) |
| 95 | 116 | { |
| 96 | − rbuf->pread = rbuf->pwrite = 0; | |
| 117 | + /* dvb_ringbuffer_reset() counts as read and write operation | |
| 118 | + * smp_store_release() to update read pointer | |
| 119 | + */ | |
| 120 | + smp_store_release(&rbuf->pread, 0); | |
| 121 | + /* smp_store_release() to update write pointer */ | |
| 122 | + smp_store_release(&rbuf->pwrite, 0); | |
| 97 | 123 | rbuf->error = 0; |
| 98 | 124 | } |
| 99 | 125 | |
| @@ -119,12 +145,17 @@ ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, si · 19 unmodified lines | ||
| 119 | 145 | return -EFAULT; |
| 120 | 146 | buf += split; |
| 121 | 147 | todo -= split; |
| 122 | − rbuf->pread = 0; | |
| 148 | + /* smp_store_release() for read pointer update to ensure | |
| 149 | + * that buf is not overwritten until read is complete, | |
| 150 | + * this pairs with ACCESS_ONCE() in dvb_ringbuffer_free() | |
| 151 | + */ | |
| 152 | + smp_store_release(&rbuf->pread, 0); | |
| 123 | 153 | } |
| 124 | 154 | if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) |
| 125 | 155 | return -EFAULT; |
| 126 | 156 | |
| 127 | − rbuf->pread = (rbuf->pread + todo) % rbuf->size; | |
| 157 | + /* smp_store_release() to update read pointer, see above */ | |
| 158 | + smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size); | |
| 128 | 159 | |
| 129 | 160 | return len; |
| 130 | 161 | } |
| @@ -139,11 +170,16 @@ void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len) · 8 unmodified lines | ||
| 139 | 170 | memcpy(buf, rbuf->data+rbuf->pread, split); |
| 140 | 171 | buf += split; |
| 141 | 172 | todo -= split; |
| 142 | − rbuf->pread = 0; | |
| 173 | + /* smp_store_release() for read pointer update to ensure | |
| 174 | + * that buf is not overwritten until read is complete, | |
| 175 | + * this pairs with ACCESS_ONCE() in dvb_ringbuffer_free() | |
| 176 | + */ | |
| 177 | + smp_store_release(&rbuf->pread, 0); | |
| 143 | 178 | } |
| 144 | 179 | memcpy(buf, rbuf->data+rbuf->pread, todo); |
| 145 | 180 | |
| 146 | − rbuf->pread = (rbuf->pread + todo) % rbuf->size; | |
| 181 | + /* smp_store_release() to update read pointer, see above */ | |
| 182 | + smp_store_release(&rbuf->pread, (rbuf->pread + todo) % rbuf->size); | |
| 147 | 183 | } |
| 148 | 184 | |
| 149 | 185 | |
| @@ -158,10 +194,16 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t · 8 unmodified lines | ||
| 158 | 194 | memcpy(rbuf->data+rbuf->pwrite, buf, split); |
| 159 | 195 | buf += split; |
| 160 | 196 | todo -= split; |
| 161 | − rbuf->pwrite = 0; | |
| 197 | + /* smp_store_release() for write pointer update to ensure that | |
| 198 | + * written data is visible on other cpu cores before the pointer | |
| 199 | + * update, this pairs with smp_load_acquire() in | |
| 200 | + * dvb_ringbuffer_empty() or dvb_ringbuffer_avail() | |
| 201 | + */ | |
| 202 | + smp_store_release(&rbuf->pwrite, 0); | |
| 162 | 203 | } |
| 163 | 204 | memcpy(rbuf->data+rbuf->pwrite, buf, todo); |
| 164 | − rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size; | |
| 205 | + /* smp_store_release() for write pointer update, see above */ | |
| 206 | + smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size); | |
| 165 | 207 | |
| 166 | 208 | return len; |
| 167 | 209 | } |
| @@ -181,12 +223,18 @@ ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, · 13 unmodified lines | ||
| 181 | 223 | return len - todo; |
| 182 | 224 | buf += split; |
| 183 | 225 | todo -= split; |
| 184 | − rbuf->pwrite = 0; | |
| 226 | + /* smp_store_release() for write pointer update to ensure that | |
| 227 | + * written data is visible on other cpu cores before the pointer | |
| 228 | + * update, this pairs with smp_load_acquire() in | |
| 229 | + * dvb_ringbuffer_empty() or dvb_ringbuffer_avail() | |
| 230 | + */ | |
| 231 | + smp_store_release(&rbuf->pwrite, 0); | |
| 185 | 232 | } |
| 186 | 233 | status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo); |
| 187 | 234 | if (status) |
| 188 | 235 | return len - todo; |
| 189 | − rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size; | |
| 236 | + /* smp_store_release() for write pointer update, see above */ | |
| 237 | + smp_store_release(&rbuf->pwrite, (rbuf->pwrite + todo) % rbuf->size); | |
| 190 | 238 | |
| 191 | 239 | return len; |
| 192 | 240 | } |
| @@ -73,6 +73,14 @@ config DVB_SI2165 · 72 unmodified lines | ||
| 73 | 73 | |
| 74 | 74 | Say Y when you want to support this frontend. |
| 75 | 75 | |
| 76 | +config DVB_MN88472 | |
| 77 | + tristate "Panasonic MN88472" | |
| 78 | + depends on DVB_CORE && I2C | |
| 79 | + select REGMAP_I2C | |
| 80 | + default m if !MEDIA_SUBDRV_AUTOSELECT | |
| 81 | + help | |
| 82 | + Say Y when you want to support this frontend. | |
| 83 | + | |
| 76 | 84 | config DVB_MN88473 |
| 77 | 85 | tristate "Panasonic MN88473" |
| 78 | 86 | depends on DVB_CORE && I2C |
| @@ -853,6 +861,13 @@ config DVB_ASCOT2E · 774 unmodified lines | ||
| 853 | 861 | help |
| 854 | 862 | Say Y when you want to support this frontend. |
| 855 | 863 | |
| 864 | +config DVB_HELENE | |
| 865 | + tristate "Sony HELENE Sat/Ter tuner (CXD2858ER)" | |
| 866 | + depends on DVB_CORE && I2C | |
| 867 | + default m if !MEDIA_SUBDRV_AUTOSELECT | |
| 868 | + help | |
| 869 | + Say Y when you want to support this frontend. | |
| 870 | + | |
| 856 | 871 | comment "Tools to develop new frontends" |
| 857 | 872 | |
| 858 | 873 | config DVB_DUMMY_FE |
| @@ -95,6 +95,7 @@ obj-$(CONFIG_DVB_STV0900) += stv0900.o · 94 unmodified lines | ||
| 95 | 95 | obj-$(CONFIG_DVB_STV090x) += stv090x.o |
| 96 | 96 | obj-$(CONFIG_DVB_STV6110x) += stv6110x.o |
| 97 | 97 | obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o |
| 98 | +obj-$(CONFIG_DVB_MN88472) += mn88472.o | |
| 98 | 99 | obj-$(CONFIG_DVB_MN88473) += mn88473.o |
| 99 | 100 | obj-$(CONFIG_DVB_ISL6423) += isl6423.o |
| 100 | 101 | obj-$(CONFIG_DVB_EC100) += ec100.o |
| @@ -123,3 +124,4 @@ obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o · 22 unmodified lines | ||
| 123 | 124 | obj-$(CONFIG_DVB_TC90522) += tc90522.o |
| 124 | 125 | obj-$(CONFIG_DVB_HORUS3A) += horus3a.o |
| 125 | 126 | obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o |
| 127 | +obj-$(CONFIG_DVB_HELENE) += helene.o | |
| @@ -41,7 +41,6 @@ struct af9033_dev { · 40 unmodified lines | ||
| 41 | 41 | u64 post_bit_count; |
| 42 | 42 | u64 error_block_count; |
| 43 | 43 | u64 total_block_count; |
| 44 | − struct delayed_work stat_work; | |
| 45 | 44 | }; |
| 46 | 45 | |
| 47 | 46 | /* write multiple registers */ |
| @@ -468,8 +467,6 @@ static int af9033_init(struct dvb_frontend *fe) · 420 unmodified lines | ||
| 468 | 467 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 469 | 468 | c->post_bit_error.len = 1; |
| 470 | 469 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 471 | − /* start statistics polling */ | |
| 472 | − schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); | |
| 473 | 470 | |
| 474 | 471 | return 0; |
| 475 | 472 | |
| @@ -485,9 +482,6 @@ static int af9033_sleep(struct dvb_frontend *fe) · 9 unmodified lines | ||
| 485 | 482 | int ret, i; |
| 486 | 483 | u8 tmp; |
| 487 | 484 | |
| 488 | − /* stop statistics polling */ | |
| 489 | − cancel_delayed_work_sync(&dev->stat_work); | |
| 490 | − | |
| 491 | 485 | ret = af9033_wr_reg(dev, 0x80004c, 1); |
| 492 | 486 | if (ret < 0) |
| 493 | 487 | goto err; |
| @@ -821,36 +815,39 @@ err: · 327 unmodified lines | ||
| 821 | 815 | static int af9033_read_status(struct dvb_frontend *fe, enum fe_status *status) |
| 822 | 816 | { |
| 823 | 817 | struct af9033_dev *dev = fe->demodulator_priv; |
| 824 | − int ret; | |
| 825 | − u8 tmp; | |
| 818 | + struct dtv_frontend_properties *c = &fe->dtv_property_cache; | |
| 819 | + int ret, i, tmp = 0; | |
| 820 | + u8 u8tmp, buf[7]; | |
| 821 | + | |
| 822 | + dev_dbg(&dev->client->dev, "\n"); | |
| 826 | 823 | |
| 827 | 824 | *status = 0; |
| 828 | 825 | |
| 829 | 826 | /* radio channel status, 0=no result, 1=has signal, 2=no signal */ |
| 830 | − ret = af9033_rd_reg(dev, 0x800047, &tmp); | |
| 827 | + ret = af9033_rd_reg(dev, 0x800047, &u8tmp); | |
| 831 | 828 | if (ret < 0) |
| 832 | 829 | goto err; |
| 833 | 830 | |
| 834 | 831 | /* has signal */ |
| 835 | − if (tmp == 0x01) | |
| 832 | + if (u8tmp == 0x01) | |
| 836 | 833 | *status |= FE_HAS_SIGNAL; |
| 837 | 834 | |
| 838 | − if (tmp != 0x02) { | |
| 835 | + if (u8tmp != 0x02) { | |
| 839 | 836 | /* TPS lock */ |
| 840 | − ret = af9033_rd_reg_mask(dev, 0x80f5a9, &tmp, 0x01); | |
| 837 | + ret = af9033_rd_reg_mask(dev, 0x80f5a9, &u8tmp, 0x01); | |
| 841 | 838 | if (ret < 0) |
| 842 | 839 | goto err; |
| 843 | 840 | |
| 844 | − if (tmp) | |
| 841 | + if (u8tmp) | |
| 845 | 842 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | |
| 846 | 843 | FE_HAS_VITERBI; |
| 847 | 844 | |
| 848 | 845 | /* full lock */ |
| 849 | − ret = af9033_rd_reg_mask(dev, 0x80f999, &tmp, 0x01); | |
| 846 | + ret = af9033_rd_reg_mask(dev, 0x80f999, &u8tmp, 0x01); | |
| 850 | 847 | if (ret < 0) |
| 851 | 848 | goto err; |
| 852 | 849 | |
| 853 | − if (tmp) | |
| 850 | + if (u8tmp) | |
| 854 | 851 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | |
| 855 | 852 | FE_HAS_VITERBI | FE_HAS_SYNC | |
| 856 | 853 | FE_HAS_LOCK; |
| @@ -858,6 +855,148 @@ static int af9033_read_status(struct dvb_frontend *fe, enum fe_status *status) · 1 unmodified line | ||
| 858 | 855 | |
| 859 | 856 | dev->fe_status = *status; |
| 860 | 857 | |
| 858 | + /* signal strength */ | |
| 859 | + if (dev->fe_status & FE_HAS_SIGNAL) { | |
| 860 | + if (dev->is_af9035) { | |
| 861 | + ret = af9033_rd_reg(dev, 0x80004a, &u8tmp); | |
| 862 | + if (ret) | |
| 863 | + goto err; | |
| 864 | + tmp = -u8tmp * 1000; | |
| 865 | + } else { | |
| 866 | + ret = af9033_rd_reg(dev, 0x8000f7, &u8tmp); | |
| 867 | + if (ret) | |
| 868 | + goto err; | |
| 869 | + tmp = (u8tmp - 100) * 1000; | |
| 870 | + } | |
| 871 | + | |
| 872 | + c->strength.len = 1; | |
| 873 | + c->strength.stat[0].scale = FE_SCALE_DECIBEL; | |
| 874 | + c->strength.stat[0].svalue = tmp; | |
| 875 | + } else { | |
| 876 | + c->strength.len = 1; | |
| 877 | + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 878 | + } | |
| 879 | + | |
| 880 | + /* CNR */ | |
| 881 | + if (dev->fe_status & FE_HAS_VITERBI) { | |
| 882 | + u32 snr_val, snr_lut_size; | |
| 883 | + const struct val_snr *snr_lut = NULL; | |
| 884 | + | |
| 885 | + /* read value */ | |
| 886 | + ret = af9033_rd_regs(dev, 0x80002c, buf, 3); | |
| 887 | + if (ret) | |
| 888 | + goto err; | |
| 889 | + | |
| 890 | + snr_val = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0); | |
| 891 | + | |
| 892 | + /* read superframe number */ | |
| 893 | + ret = af9033_rd_reg(dev, 0x80f78b, &u8tmp); | |
| 894 | + if (ret) | |
| 895 | + goto err; | |
| 896 | + | |
| 897 | + if (u8tmp) | |
| 898 | + snr_val /= u8tmp; | |
| 899 | + | |
| 900 | + /* read current transmission mode */ | |
| 901 | + ret = af9033_rd_reg(dev, 0x80f900, &u8tmp); | |
| 902 | + if (ret) | |
| 903 | + goto err; | |
| 904 | + | |
| 905 | + switch ((u8tmp >> 0) & 3) { | |
| 906 | + case 0: | |
| 907 | + snr_val *= 4; | |
| 908 | + break; | |
| 909 | + case 1: | |
| 910 | + snr_val *= 1; | |
| 911 | + break; | |
| 912 | + case 2: | |
| 913 | + snr_val *= 2; | |
| 914 | + break; | |
| 915 | + default: | |
| 916 | + snr_val *= 0; | |
| 917 | + break; | |
| 918 | + } | |
| 919 | + | |
| 920 | + /* read current modulation */ | |
| 921 | + ret = af9033_rd_reg(dev, 0x80f903, &u8tmp); | |
| 922 | + if (ret) | |
| 923 | + goto err; | |
| 924 | + | |
| 925 | + switch ((u8tmp >> 0) & 3) { | |
| 926 | + case 0: | |
| 927 | + snr_lut_size = ARRAY_SIZE(qpsk_snr_lut); | |
| 928 | + snr_lut = qpsk_snr_lut; | |
| 929 | + break; | |
| 930 | + case 1: | |
| 931 | + snr_lut_size = ARRAY_SIZE(qam16_snr_lut); | |
| 932 | + snr_lut = qam16_snr_lut; | |
| 933 | + break; | |
| 934 | + case 2: | |
| 935 | + snr_lut_size = ARRAY_SIZE(qam64_snr_lut); | |
| 936 | + snr_lut = qam64_snr_lut; | |
| 937 | + break; | |
| 938 | + default: | |
| 939 | + snr_lut_size = 0; | |
| 940 | + tmp = 0; | |
| 941 | + break; | |
| 942 | + } | |
| 943 | + | |
| 944 | + for (i = 0; i < snr_lut_size; i++) { | |
| 945 | + tmp = snr_lut[i].snr * 1000; | |
| 946 | + if (snr_val < snr_lut[i].val) | |
| 947 | + break; | |
| 948 | + } | |
| 949 | + | |
| 950 | + c->cnr.len = 1; | |
| 951 | + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; | |
| 952 | + c->cnr.stat[0].svalue = tmp; | |
| 953 | + } else { | |
| 954 | + c->cnr.len = 1; | |
| 955 | + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 956 | + } | |
| 957 | + | |
| 958 | + /* UCB/PER/BER */ | |
| 959 | + if (dev->fe_status & FE_HAS_LOCK) { | |
| 960 | + /* outer FEC, 204 byte packets */ | |
| 961 | + u16 abort_packet_count, rsd_packet_count; | |
| 962 | + /* inner FEC, bits */ | |
| 963 | + u32 rsd_bit_err_count; | |
| 964 | + | |
| 965 | + /* | |
| 966 | + * Packet count used for measurement is 10000 | |
| 967 | + * (rsd_packet_count). Maybe it should be increased? | |
| 968 | + */ | |
| 969 | + | |
| 970 | + ret = af9033_rd_regs(dev, 0x800032, buf, 7); | |
| 971 | + if (ret) | |
| 972 | + goto err; | |
| 973 | + | |
| 974 | + abort_packet_count = (buf[1] << 8) | (buf[0] << 0); | |
| 975 | + rsd_bit_err_count = (buf[4] << 16) | (buf[3] << 8) | buf[2]; | |
| 976 | + rsd_packet_count = (buf[6] << 8) | (buf[5] << 0); | |
| 977 | + | |
| 978 | + dev->error_block_count += abort_packet_count; | |
| 979 | + dev->total_block_count += rsd_packet_count; | |
| 980 | + dev->post_bit_error += rsd_bit_err_count; | |
| 981 | + dev->post_bit_count += rsd_packet_count * 204 * 8; | |
| 982 | + | |
| 983 | + c->block_count.len = 1; | |
| 984 | + c->block_count.stat[0].scale = FE_SCALE_COUNTER; | |
| 985 | + c->block_count.stat[0].uvalue = dev->total_block_count; | |
| 986 | + | |
| 987 | + c->block_error.len = 1; | |
| 988 | + c->block_error.stat[0].scale = FE_SCALE_COUNTER; | |
| 989 | + c->block_error.stat[0].uvalue = dev->error_block_count; | |
| 990 | + | |
| 991 | + c->post_bit_count.len = 1; | |
| 992 | + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; | |
| 993 | + c->post_bit_count.stat[0].uvalue = dev->post_bit_count; | |
| 994 | + | |
| 995 | + c->post_bit_error.len = 1; | |
| 996 | + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; | |
| 997 | + c->post_bit_error.stat[0].uvalue = dev->post_bit_error; | |
| 998 | + } | |
| 999 | + | |
| 861 | 1000 | return 0; |
| 862 | 1001 | |
| 863 | 1002 | err: |
| @@ -1059,159 +1198,6 @@ err: · 195 unmodified lines | ||
| 1059 | 1198 | return ret; |
| 1060 | 1199 | } |
| 1061 | 1200 | |
| 1062 | −static void af9033_stat_work(struct work_struct *work) | |
| 1063 | −{ | |
| 1064 | − struct af9033_dev *dev = container_of(work, struct af9033_dev, stat_work.work); | |
| 1065 | − struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; | |
| 1066 | − int ret, tmp, i, len; | |
| 1067 | − u8 u8tmp, buf[7]; | |
| 1068 | − | |
| 1069 | − dev_dbg(&dev->client->dev, "\n"); | |
| 1070 | − | |
| 1071 | − /* signal strength */ | |
| 1072 | − if (dev->fe_status & FE_HAS_SIGNAL) { | |
| 1073 | − if (dev->is_af9035) { | |
| 1074 | − ret = af9033_rd_reg(dev, 0x80004a, &u8tmp); | |
| 1075 | − tmp = -u8tmp * 1000; | |
| 1076 | − } else { | |
| 1077 | − ret = af9033_rd_reg(dev, 0x8000f7, &u8tmp); | |
| 1078 | − tmp = (u8tmp - 100) * 1000; | |
| 1079 | − } | |
| 1080 | − if (ret) | |
| 1081 | − goto err; | |
| 1082 | − | |
| 1083 | − c->strength.len = 1; | |
| 1084 | − c->strength.stat[0].scale = FE_SCALE_DECIBEL; | |
| 1085 | − c->strength.stat[0].svalue = tmp; | |
| 1086 | − } else { | |
| 1087 | − c->strength.len = 1; | |
| 1088 | − c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 1089 | − } | |
| 1090 | − | |
| 1091 | − /* CNR */ | |
| 1092 | − if (dev->fe_status & FE_HAS_VITERBI) { | |
| 1093 | − u32 snr_val; | |
| 1094 | − const struct val_snr *snr_lut; | |
| 1095 | − | |
| 1096 | − /* read value */ | |
| 1097 | − ret = af9033_rd_regs(dev, 0x80002c, buf, 3); | |
| 1098 | − if (ret) | |
| 1099 | − goto err; | |
| 1100 | − | |
| 1101 | − snr_val = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0); | |
| 1102 | − | |
| 1103 | − /* read superframe number */ | |
| 1104 | − ret = af9033_rd_reg(dev, 0x80f78b, &u8tmp); | |
| 1105 | − if (ret) | |
| 1106 | − goto err; | |
| 1107 | − | |
| 1108 | − if (u8tmp) | |
| 1109 | − snr_val /= u8tmp; | |
| 1110 | − | |
| 1111 | − /* read current transmission mode */ | |
| 1112 | − ret = af9033_rd_reg(dev, 0x80f900, &u8tmp); | |
| 1113 | − if (ret) | |
| 1114 | − goto err; | |
| 1115 | − | |
| 1116 | − switch ((u8tmp >> 0) & 3) { | |
| 1117 | − case 0: | |
| 1118 | − snr_val *= 4; | |
| 1119 | − break; | |
| 1120 | − case 1: | |
| 1121 | − snr_val *= 1; | |
| 1122 | − break; | |
| 1123 | − case 2: | |
| 1124 | − snr_val *= 2; | |
| 1125 | − break; | |
| 1126 | − default: | |
| 1127 | − goto err_schedule_delayed_work; | |
| 1128 | − } | |
| 1129 | − | |
| 1130 | − /* read current modulation */ | |
| 1131 | − ret = af9033_rd_reg(dev, 0x80f903, &u8tmp); | |
| 1132 | − if (ret) | |
| 1133 | − goto err; | |
| 1134 | − | |
| 1135 | − switch ((u8tmp >> 0) & 3) { | |
| 1136 | − case 0: | |
| 1137 | − len = ARRAY_SIZE(qpsk_snr_lut); | |
| 1138 | − snr_lut = qpsk_snr_lut; | |
| 1139 | − break; | |
| 1140 | − case 1: | |
| 1141 | − len = ARRAY_SIZE(qam16_snr_lut); | |
| 1142 | − snr_lut = qam16_snr_lut; | |
| 1143 | − break; | |
| 1144 | − case 2: | |
| 1145 | − len = ARRAY_SIZE(qam64_snr_lut); | |
| 1146 | − snr_lut = qam64_snr_lut; | |
| 1147 | − break; | |
| 1148 | − default: | |
| 1149 | − goto err_schedule_delayed_work; | |
| 1150 | − } | |
| 1151 | − | |
| 1152 | − for (i = 0; i < len; i++) { | |
| 1153 | − tmp = snr_lut[i].snr * 1000; | |
| 1154 | − if (snr_val < snr_lut[i].val) | |
| 1155 | − break; | |
| 1156 | − } | |
| 1157 | − | |
| 1158 | − c->cnr.len = 1; | |
| 1159 | − c->cnr.stat[0].scale = FE_SCALE_DECIBEL; | |
| 1160 | − c->cnr.stat[0].svalue = tmp; | |
| 1161 | − } else { | |
| 1162 | − c->cnr.len = 1; | |
| 1163 | − c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 1164 | − } | |
| 1165 | − | |
| 1166 | − /* UCB/PER/BER */ | |
| 1167 | − if (dev->fe_status & FE_HAS_LOCK) { | |
| 1168 | − /* outer FEC, 204 byte packets */ | |
| 1169 | − u16 abort_packet_count, rsd_packet_count; | |
| 1170 | − /* inner FEC, bits */ | |
| 1171 | − u32 rsd_bit_err_count; | |
| 1172 | − | |
| 1173 | − /* | |
| 1174 | − * Packet count used for measurement is 10000 | |
| 1175 | − * (rsd_packet_count). Maybe it should be increased? | |
| 1176 | − */ | |
| 1177 | − | |
| 1178 | − ret = af9033_rd_regs(dev, 0x800032, buf, 7); | |
| 1179 | − if (ret) | |
| 1180 | − goto err; | |
| 1181 | − | |
| 1182 | − abort_packet_count = (buf[1] << 8) | (buf[0] << 0); | |
| 1183 | − rsd_bit_err_count = (buf[4] << 16) | (buf[3] << 8) | buf[2]; | |
| 1184 | − rsd_packet_count = (buf[6] << 8) | (buf[5] << 0); | |
| 1185 | − | |
| 1186 | − dev->error_block_count += abort_packet_count; | |
| 1187 | − dev->total_block_count += rsd_packet_count; | |
| 1188 | − dev->post_bit_error += rsd_bit_err_count; | |
| 1189 | − dev->post_bit_count += rsd_packet_count * 204 * 8; | |
| 1190 | − | |
| 1191 | − c->block_count.len = 1; | |
| 1192 | − c->block_count.stat[0].scale = FE_SCALE_COUNTER; | |
| 1193 | − c->block_count.stat[0].uvalue = dev->total_block_count; | |
| 1194 | − | |
| 1195 | − c->block_error.len = 1; | |
| 1196 | − c->block_error.stat[0].scale = FE_SCALE_COUNTER; | |
| 1197 | − c->block_error.stat[0].uvalue = dev->error_block_count; | |
| 1198 | − | |
| 1199 | − c->post_bit_count.len = 1; | |
| 1200 | − c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; | |
| 1201 | − c->post_bit_count.stat[0].uvalue = dev->post_bit_count; | |
| 1202 | − | |
| 1203 | − c->post_bit_error.len = 1; | |
| 1204 | − c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; | |
| 1205 | − c->post_bit_error.stat[0].uvalue = dev->post_bit_error; | |
| 1206 | − } | |
| 1207 | − | |
| 1208 | −err_schedule_delayed_work: | |
| 1209 | − schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); | |
| 1210 | − return; | |
| 1211 | −err: | |
| 1212 | − dev_dbg(&dev->client->dev, "failed=%d\n", ret); | |
| 1213 | −} | |
| 1214 | − | |
| 1215 | 1201 | static struct dvb_frontend_ops af9033_ops = { |
| 1216 | 1202 | .delsys = { SYS_DVBT }, |
| 1217 | 1203 | .info = { |
| @@ -1272,7 +1258,6 @@ static int af9033_probe(struct i2c_client *client, · 54 unmodified lines | ||
| 1272 | 1258 | |
| 1273 | 1259 | /* setup the state */ |
| 1274 | 1260 | dev->client = client; |
| 1275 | − INIT_DELAYED_WORK(&dev->stat_work, af9033_stat_work); | |
| 1276 | 1261 | memcpy(&dev->cfg, cfg, sizeof(struct af9033_config)); |
| 1277 | 1262 | |
| 1278 | 1263 | if (dev->cfg.clock != 12000000) { |
| @@ -1372,9 +1357,6 @@ static int af9033_remove(struct i2c_client *client) · 93 unmodified lines | ||
| 1372 | 1357 | |
| 1373 | 1358 | dev_dbg(&dev->client->dev, "\n"); |
| 1374 | 1359 | |
| 1375 | − /* stop statistics polling */ | |
| 1376 | − cancel_delayed_work_sync(&dev->stat_work); | |
| 1377 | − | |
| 1378 | 1360 | dev->fe.ops.release = NULL; |
| 1379 | 1361 | dev->fe.demodulator_priv = NULL; |
| 1380 | 1362 | kfree(dev); |
| @@ -1391,6 +1373,7 @@ MODULE_DEVICE_TABLE(i2c, af9033_id_table); · 10 unmodified lines | ||
| 1391 | 1373 | static struct i2c_driver af9033_driver = { |
| 1392 | 1374 | .driver = { |
| 1393 | 1375 | .name = "af9033", |
| 1376 | + .suppress_bind_attrs = true, | |
| 1394 | 1377 | }, |
| 1395 | 1378 | .probe = af9033_probe, |
| 1396 | 1379 | .remove = af9033_remove, |
| @@ -132,7 +132,7 @@ static int ascot2e_write_regs(struct ascot2e_priv *priv, · 131 unmodified lines | ||
| 132 | 132 | } |
| 133 | 133 | }; |
| 134 | 134 | |
| 135 | − if (len + 1 >= sizeof(buf)) { | |
| 135 | + if (len + 1 > sizeof(buf)) { | |
| 136 | 136 | dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n", |
| 137 | 137 | reg, len + 1); |
| 138 | 138 | return -E2BIG; |
| @@ -1,7 +1,9 @@ | ||
| 1 | 1 | /* |
| 2 | 2 | * cxd2841er.c |
| 3 | 3 | * |
| 4 | − * Sony CXD2441ER digital demodulator driver | |
| 4 | + * Sony digital demodulator driver for | |
| 5 | + * CXD2841ER - DVB-S/S2/T/T2/C/C2 | |
| 6 | + * CXD2854ER - DVB-S/S2/T/T2/C/C2, ISDB-T/S | |
| 5 | 7 | * |
| 6 | 8 | * Copyright 2012 Sony Corporation |
| 7 | 9 | * Copyright (C) 2014 NetUP Inc. |
| @@ -34,6 +36,16 @@ · 26 unmodified lines | ||
| 34 | 36 | #include "cxd2841er_priv.h" |
| 35 | 37 | |
| 36 | 38 | #define MAX_WRITE_REGSIZE 16 |
| 39 | +#define LOG2_E_100X 144 | |
| 40 | + | |
| 41 | +/* DVB-C constellation */ | |
| 42 | +enum sony_dvbc_constellation_t { | |
| 43 | + SONY_DVBC_CONSTELLATION_16QAM, | |
| 44 | + SONY_DVBC_CONSTELLATION_32QAM, | |
| 45 | + SONY_DVBC_CONSTELLATION_64QAM, | |
| 46 | + SONY_DVBC_CONSTELLATION_128QAM, | |
| 47 | + SONY_DVBC_CONSTELLATION_256QAM | |
| 48 | +}; | |
| 37 | 49 | |
| 38 | 50 | enum cxd2841er_state { |
| 39 | 51 | STATE_SHUTDOWN = 0, |
| @@ -51,6 +63,8 @@ struct cxd2841er_priv { · 11 unmodified lines | ||
| 51 | 63 | const struct cxd2841er_config *config; |
| 52 | 64 | enum cxd2841er_state state; |
| 53 | 65 | u8 system; |
| 66 | + enum cxd2841er_xtal xtal; | |
| 67 | + enum fe_caps caps; | |
| 54 | 68 | }; |
| 55 | 69 | |
| 56 | 70 | static const struct cxd2841er_cnr_data s_cn_data[] = { |
| @@ -188,6 +202,9 @@ static const struct cxd2841er_cnr_data s2_cn_data[] = { · 131 unmodified lines | ||
| 188 | 202 | }; |
| 189 | 203 | |
| 190 | 204 | #define MAKE_IFFREQ_CONFIG(iffreq) ((u32)(((iffreq)/41.0)*16777216.0 + 0.5)) |
| 205 | +#define MAKE_IFFREQ_CONFIG_XTAL(xtal, iffreq) ((xtal == SONY_XTAL_24000) ? \ | |
| 206 | + (u32)(((iffreq)/48.0)*16777216.0 + 0.5) : \ | |
| 207 | + (u32)(((iffreq)/41.0)*16777216.0 + 0.5)) | |
| 191 | 208 | |
| 192 | 209 | static void cxd2841er_i2c_debug(struct cxd2841er_priv *priv, |
| 193 | 210 | u8 addr, u8 reg, u8 write, |
| @@ -217,7 +234,7 @@ static int cxd2841er_write_regs(struct cxd2841er_priv *priv, · 23 unmodified lines | ||
| 217 | 234 | }; |
| 218 | 235 | |
| 219 | 236 | if (len + 1 >= sizeof(buf)) { |
| 220 | − dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n", | |
| 237 | + dev_warn(&priv->i2c->dev, "wr reg=%04x: len=%d is too big!\n", | |
| 221 | 238 | reg, len + 1); |
| 222 | 239 | return -E2BIG; |
| 223 | 240 | } |
| @@ -282,6 +299,7 @@ static int cxd2841er_read_regs(struct cxd2841er_priv *priv, · 58 unmodified lines | ||
| 282 | 299 | KBUILD_MODNAME, ret, i2c_addr, reg); |
| 283 | 300 | return ret; |
| 284 | 301 | } |
| 302 | + cxd2841er_i2c_debug(priv, i2c_addr, reg, 0, val, len); | |
| 285 | 303 | return 0; |
| 286 | 304 | } |
| 287 | 305 | |
| @@ -427,6 +445,15 @@ static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv, · 139 unmodified lines | ||
| 427 | 445 | static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv, |
| 428 | 446 | u32 bandwidth); |
| 429 | 447 | |
| 448 | +static int cxd2841er_sleep_tc_to_active_i(struct cxd2841er_priv *priv, | |
| 449 | + u32 bandwidth); | |
| 450 | + | |
| 451 | +static int cxd2841er_active_i_to_sleep_tc(struct cxd2841er_priv *priv); | |
| 452 | + | |
| 453 | +static int cxd2841er_sleep_tc_to_shutdown(struct cxd2841er_priv *priv); | |
| 454 | + | |
| 455 | +static int cxd2841er_shutdown_to_sleep_tc(struct cxd2841er_priv *priv); | |
| 456 | + | |
| 430 | 457 | static int cxd2841er_retune_active(struct cxd2841er_priv *priv, |
| 431 | 458 | struct dtv_frontend_properties *p) |
| 432 | 459 | { |
| @@ -454,7 +481,13 @@ static int cxd2841er_retune_active(struct cxd2841er_priv *priv, · 21 unmodified lines | ||
| 454 | 481 | priv, p->bandwidth_hz); |
| 455 | 482 | case SYS_DVBC_ANNEX_A: |
| 456 | 483 | return cxd2841er_sleep_tc_to_active_c_band( |
| 457 | − priv, 8000000); | |
| 484 | + priv, p->bandwidth_hz); | |
| 485 | + case SYS_ISDBT: | |
| 486 | + cxd2841er_active_i_to_sleep_tc(priv); | |
| 487 | + cxd2841er_sleep_tc_to_shutdown(priv); | |
| 488 | + cxd2841er_shutdown_to_sleep_tc(priv); | |
| 489 | + return cxd2841er_sleep_tc_to_active_i( | |
| 490 | + priv, p->bandwidth_hz); | |
| 458 | 491 | } |
| 459 | 492 | } |
| 460 | 493 | dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n", |
| @@ -669,6 +702,45 @@ static int cxd2841er_active_c_to_sleep_tc(struct cxd2841er_priv *priv) · 208 unmodified lines | ||
| 669 | 702 | return 0; |
| 670 | 703 | } |
| 671 | 704 | |
| 705 | +static int cxd2841er_active_i_to_sleep_tc(struct cxd2841er_priv *priv) | |
| 706 | +{ | |
| 707 | + dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 708 | + if (priv->state != STATE_ACTIVE_TC) { | |
| 709 | + dev_err(&priv->i2c->dev, "%s(): invalid state %d\n", | |
| 710 | + __func__, priv->state); | |
| 711 | + return -EINVAL; | |
| 712 | + } | |
| 713 | + /* Set SLV-T Bank : 0x00 */ | |
| 714 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | |
| 715 | + /* disable TS output */ | |
| 716 | + cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01); | |
| 717 | + /* enable Hi-Z setting 1 */ | |
| 718 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x3f); | |
| 719 | + /* enable Hi-Z setting 2 */ | |
| 720 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0xff); | |
| 721 | + | |
| 722 | + /* TODO: Cancel demod parameter */ | |
| 723 | + | |
| 724 | + /* Set SLV-X Bank : 0x00 */ | |
| 725 | + cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); | |
| 726 | + /* disable ADC 1 */ | |
| 727 | + cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x01); | |
| 728 | + /* Set SLV-T Bank : 0x00 */ | |
| 729 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | |
| 730 | + /* Disable ADC 2 */ | |
| 731 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a); | |
| 732 | + /* Disable ADC 3 */ | |
| 733 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a); | |
| 734 | + /* Disable ADC clock */ | |
| 735 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); | |
| 736 | + /* Disable RF level monitor */ | |
| 737 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00); | |
| 738 | + /* Disable demod clock */ | |
| 739 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x00); | |
| 740 | + priv->state = STATE_SLEEP_TC; | |
| 741 | + return 0; | |
| 742 | +} | |
| 743 | + | |
| 672 | 744 | static int cxd2841er_shutdown_to_sleep_s(struct cxd2841er_priv *priv) |
| 673 | 745 | { |
| 674 | 746 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| @@ -686,8 +758,25 @@ static int cxd2841er_shutdown_to_sleep_s(struct cxd2841er_priv *priv) · 11 unmodified lines | ||
| 686 | 758 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); |
| 687 | 759 | /* Set demod SW reset */ |
| 688 | 760 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01); |
| 689 | − /* Set X'tal clock to 20.5Mhz */ | |
| 690 | − cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x00); | |
| 761 | + | |
| 762 | + switch (priv->xtal) { | |
| 763 | + case SONY_XTAL_20500: | |
| 764 | + cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x00); | |
| 765 | + break; | |
| 766 | + case SONY_XTAL_24000: | |
| 767 | + /* Select demod frequency */ | |
| 768 | + cxd2841er_write_reg(priv, I2C_SLVX, 0x12, 0x00); | |
| 769 | + cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x03); | |
| 770 | + break; | |
| 771 | + case SONY_XTAL_41000: | |
| 772 | + cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x01); | |
| 773 | + break; | |
| 774 | + default: | |
| 775 | + dev_dbg(&priv->i2c->dev, "%s(): invalid demod xtal %d\n", | |
| 776 | + __func__, priv->xtal); | |
| 777 | + return -EINVAL; | |
| 778 | + } | |
| 779 | + | |
| 691 | 780 | /* Set demod mode */ |
| 692 | 781 | cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x0a); |
| 693 | 782 | /* Clear demod SW reset */ |
| @@ -712,6 +801,8 @@ static int cxd2841er_shutdown_to_sleep_s(struct cxd2841er_priv *priv) · 18 unmodified lines | ||
| 712 | 801 | |
| 713 | 802 | static int cxd2841er_shutdown_to_sleep_tc(struct cxd2841er_priv *priv) |
| 714 | 803 | { |
| 804 | + u8 data = 0; | |
| 805 | + | |
| 715 | 806 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 716 | 807 | if (priv->state != STATE_SHUTDOWN) { |
| 717 | 808 | dev_dbg(&priv->i2c->dev, "%s(): invalid demod state %d\n", |
| @@ -727,9 +818,24 @@ static int cxd2841er_shutdown_to_sleep_tc(struct cxd2841er_priv *priv) · 9 unmodified lines | ||
| 727 | 818 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); |
| 728 | 819 | /* Set demod SW reset */ |
| 729 | 820 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01); |
| 730 | − /* Set X'tal clock to 20.5Mhz */ | |
| 821 | + /* Select ADC clock mode */ | |
| 731 | 822 | cxd2841er_write_reg(priv, I2C_SLVX, 0x13, 0x00); |
| 732 | − cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x00); | |
| 823 | + | |
| 824 | + switch (priv->xtal) { | |
| 825 | + case SONY_XTAL_20500: | |
| 826 | + data = 0x0; | |
| 827 | + break; | |
| 828 | + case SONY_XTAL_24000: | |
| 829 | + /* Select demod frequency */ | |
| 830 | + cxd2841er_write_reg(priv, I2C_SLVX, 0x12, 0x00); | |
| 831 | + data = 0x3; | |
| 832 | + break; | |
| 833 | + case SONY_XTAL_41000: | |
| 834 | + cxd2841er_write_reg(priv, I2C_SLVX, 0x12, 0x00); | |
| 835 | + data = 0x1; | |
| 836 | + break; | |
| 837 | + } | |
| 838 | + cxd2841er_write_reg(priv, I2C_SLVX, 0x14, data); | |
| 733 | 839 | /* Clear demod SW reset */ |
| 734 | 840 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x00); |
| 735 | 841 | usleep_range(1000, 2000); |
| @@ -809,11 +915,14 @@ static void cxd2841er_set_ts_clock_mode(struct cxd2841er_priv *priv, · 73 unmodified lines | ||
| 809 | 915 | |
| 810 | 916 | static u8 cxd2841er_chip_id(struct cxd2841er_priv *priv) |
| 811 | 917 | { |
| 812 | − u8 chip_id; | |
| 918 | + u8 chip_id = 0; | |
| 813 | 919 | |
| 814 | 920 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 815 | − cxd2841er_write_reg(priv, I2C_SLVT, 0, 0); | |
| 816 | − cxd2841er_read_reg(priv, I2C_SLVT, 0xfd, &chip_id); | |
| 921 | + if (cxd2841er_write_reg(priv, I2C_SLVT, 0, 0) == 0) | |
| 922 | + cxd2841er_read_reg(priv, I2C_SLVT, 0xfd, &chip_id); | |
| 923 | + else if (cxd2841er_write_reg(priv, I2C_SLVX, 0, 0) == 0) | |
| 924 | + cxd2841er_read_reg(priv, I2C_SLVX, 0xfd, &chip_id); | |
| 925 | + | |
| 817 | 926 | return chip_id; |
| 818 | 927 | } |
| 819 | 928 | |
| @@ -896,6 +1005,25 @@ static int cxd2841er_read_status_c(struct cxd2841er_priv *priv, u8 *tslock) · 76 unmodified lines | ||
| 896 | 1005 | return 0; |
| 897 | 1006 | } |
| 898 | 1007 | |
| 1008 | +static int cxd2841er_read_status_i(struct cxd2841er_priv *priv, | |
| 1009 | + u8 *sync, u8 *tslock, u8 *unlock) | |
| 1010 | +{ | |
| 1011 | + u8 data = 0; | |
| 1012 | + | |
| 1013 | + dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 1014 | + if (priv->state != STATE_ACTIVE_TC) | |
| 1015 | + return -EINVAL; | |
| 1016 | + /* Set SLV-T Bank : 0x60 */ | |
| 1017 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); | |
| 1018 | + cxd2841er_read_reg(priv, I2C_SLVT, 0x10, &data); | |
| 1019 | + dev_dbg(&priv->i2c->dev, | |
| 1020 | + "%s(): lock=0x%x\n", __func__, data); | |
| 1021 | + *sync = ((data & 0x02) ? 1 : 0); | |
| 1022 | + *tslock = ((data & 0x01) ? 1 : 0); | |
| 1023 | + *unlock = ((data & 0x10) ? 1 : 0); | |
| 1024 | + return 0; | |
| 1025 | +} | |
| 1026 | + | |
| 899 | 1027 | static int cxd2841er_read_status_tc(struct dvb_frontend *fe, |
| 900 | 1028 | enum fe_status *status) |
| 901 | 1029 | { |
| @@ -921,6 +1049,20 @@ static int cxd2841er_read_status_tc(struct dvb_frontend *fe, · 19 unmodified lines | ||
| 921 | 1049 | FE_HAS_SYNC; |
| 922 | 1050 | if (tslock) |
| 923 | 1051 | *status |= FE_HAS_LOCK; |
| 1052 | + } else if (priv->system == SYS_ISDBT) { | |
| 1053 | + ret = cxd2841er_read_status_i( | |
| 1054 | + priv, &sync, &tslock, &unlock); | |
| 1055 | + if (ret) | |
| 1056 | + goto done; | |
| 1057 | + if (unlock) | |
| 1058 | + goto done; | |
| 1059 | + if (sync) | |
| 1060 | + *status = FE_HAS_SIGNAL | | |
| 1061 | + FE_HAS_CARRIER | | |
| 1062 | + FE_HAS_VITERBI | | |
| 1063 | + FE_HAS_SYNC; | |
| 1064 | + if (tslock) | |
| 1065 | + *status |= FE_HAS_LOCK; | |
| 924 | 1066 | } else if (priv->system == SYS_DVBC_ANNEX_A) { |
| 925 | 1067 | ret = cxd2841er_read_status_c(priv, &tslock); |
| 926 | 1068 | if (ret) |
| @@ -997,6 +1139,76 @@ static int cxd2841er_get_carrier_offset_s_s2(struct cxd2841er_priv *priv, · 70 unmodified lines | ||
| 997 | 1139 | return 0; |
| 998 | 1140 | } |
| 999 | 1141 | |
| 1142 | +static int cxd2841er_get_carrier_offset_i(struct cxd2841er_priv *priv, | |
| 1143 | + u32 bandwidth, int *offset) | |
| 1144 | +{ | |
| 1145 | + u8 data[4]; | |
| 1146 | + | |
| 1147 | + dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 1148 | + if (priv->state != STATE_ACTIVE_TC) { | |
| 1149 | + dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n", | |
| 1150 | + __func__, priv->state); | |
| 1151 | + return -EINVAL; | |
| 1152 | + } | |
| 1153 | + if (priv->system != SYS_ISDBT) { | |
| 1154 | + dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n", | |
| 1155 | + __func__, priv->system); | |
| 1156 | + return -EINVAL; | |
| 1157 | + } | |
| 1158 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); | |
| 1159 | + cxd2841er_read_regs(priv, I2C_SLVT, 0x4c, data, sizeof(data)); | |
| 1160 | + *offset = -1 * sign_extend32( | |
| 1161 | + ((u32)(data[0] & 0x1F) << 24) | ((u32)data[1] << 16) | | |
| 1162 | + ((u32)data[2] << 8) | (u32)data[3], 29); | |
| 1163 | + | |
| 1164 | + switch (bandwidth) { | |
| 1165 | + case 6000000: | |
| 1166 | + *offset = -1 * ((*offset) * 8/264); | |
| 1167 | + break; | |
| 1168 | + case 7000000: | |
| 1169 | + *offset = -1 * ((*offset) * 8/231); | |
| 1170 | + break; | |
| 1171 | + case 8000000: | |
| 1172 | + *offset = -1 * ((*offset) * 8/198); | |
| 1173 | + break; | |
| 1174 | + default: | |
| 1175 | + dev_dbg(&priv->i2c->dev, "%s(): invalid bandwidth %d\n", | |
| 1176 | + __func__, bandwidth); | |
| 1177 | + return -EINVAL; | |
| 1178 | + } | |
| 1179 | + | |
| 1180 | + dev_dbg(&priv->i2c->dev, "%s(): bandwidth %d offset %d\n", | |
| 1181 | + __func__, bandwidth, *offset); | |
| 1182 | + | |
| 1183 | + return 0; | |
| 1184 | +} | |
| 1185 | + | |
| 1186 | +static int cxd2841er_get_carrier_offset_t(struct cxd2841er_priv *priv, | |
| 1187 | + u32 bandwidth, int *offset) | |
| 1188 | +{ | |
| 1189 | + u8 data[4]; | |
| 1190 | + | |
| 1191 | + dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 1192 | + if (priv->state != STATE_ACTIVE_TC) { | |
| 1193 | + dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n", | |
| 1194 | + __func__, priv->state); | |
| 1195 | + return -EINVAL; | |
| 1196 | + } | |
| 1197 | + if (priv->system != SYS_DVBT) { | |
| 1198 | + dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n", | |
| 1199 | + __func__, priv->system); | |
| 1200 | + return -EINVAL; | |
| 1201 | + } | |
| 1202 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | |
| 1203 | + cxd2841er_read_regs(priv, I2C_SLVT, 0x4c, data, sizeof(data)); | |
| 1204 | + *offset = -1 * sign_extend32( | |
| 1205 | + ((u32)(data[0] & 0x1F) << 24) | ((u32)data[1] << 16) | | |
| 1206 | + ((u32)data[2] << 8) | (u32)data[3], 29); | |
| 1207 | + *offset *= (bandwidth / 1000000); | |
| 1208 | + *offset /= 235; | |
| 1209 | + return 0; | |
| 1210 | +} | |
| 1211 | + | |
| 1000 | 1212 | static int cxd2841er_get_carrier_offset_t2(struct cxd2841er_priv *priv, |
| 1001 | 1213 | u32 bandwidth, int *offset) |
| 1002 | 1214 | { |
| @@ -1060,6 +1272,24 @@ static int cxd2841er_get_carrier_offset_c(struct cxd2841er_priv *priv, · 57 unmodified lines | ||
| 1060 | 1272 | return 0; |
| 1061 | 1273 | } |
| 1062 | 1274 | |
| 1275 | +static int cxd2841er_read_packet_errors_c( | |
| 1276 | + struct cxd2841er_priv *priv, u32 *penum) | |
| 1277 | +{ | |
| 1278 | + u8 data[3]; | |
| 1279 | + | |
| 1280 | + *penum = 0; | |
| 1281 | + if (priv->state != STATE_ACTIVE_TC) { | |
| 1282 | + dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n", | |
| 1283 | + __func__, priv->state); | |
| 1284 | + return -EINVAL; | |
| 1285 | + } | |
| 1286 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40); | |
| 1287 | + cxd2841er_read_regs(priv, I2C_SLVT, 0xea, data, sizeof(data)); | |
| 1288 | + if (data[2] & 0x01) | |
| 1289 | + *penum = ((u32)data[0] << 8) | (u32)data[1]; | |
| 1290 | + return 0; | |
| 1291 | +} | |
| 1292 | + | |
| 1063 | 1293 | static int cxd2841er_read_packet_errors_t( |
| 1064 | 1294 | struct cxd2841er_priv *priv, u32 *penum) |
| 1065 | 1295 | { |
| @@ -1096,11 +1326,85 @@ static int cxd2841er_read_packet_errors_t2( · 30 unmodified lines | ||
| 1096 | 1326 | return 0; |
| 1097 | 1327 | } |
| 1098 | 1328 | |
| 1099 | −static u32 cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv) | |
| 1329 | +static int cxd2841er_read_packet_errors_i( | |
| 1330 | + struct cxd2841er_priv *priv, u32 *penum) | |
| 1331 | +{ | |
| 1332 | + u8 data[2]; | |
| 1333 | + | |
| 1334 | + *penum = 0; | |
| 1335 | + if (priv->state != STATE_ACTIVE_TC) { | |
| 1336 | + dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n", | |
| 1337 | + __func__, priv->state); | |
| 1338 | + return -EINVAL; | |
| 1339 | + } | |
| 1340 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); | |
| 1341 | + cxd2841er_read_regs(priv, I2C_SLVT, 0xA1, data, 1); | |
| 1342 | + | |
| 1343 | + if (!(data[0] & 0x01)) | |
| 1344 | + return 0; | |
| 1345 | + | |
| 1346 | + /* Layer A */ | |
| 1347 | + cxd2841er_read_regs(priv, I2C_SLVT, 0xA2, data, sizeof(data)); | |
| 1348 | + *penum = ((u32)data[0] << 8) | (u32)data[1]; | |
| 1349 | + | |
| 1350 | + /* Layer B */ | |
| 1351 | + cxd2841er_read_regs(priv, I2C_SLVT, 0xA4, data, sizeof(data)); | |
| 1352 | + *penum += ((u32)data[0] << 8) | (u32)data[1]; | |
| 1353 | + | |
| 1354 | + /* Layer C */ | |
| 1355 | + cxd2841er_read_regs(priv, I2C_SLVT, 0xA6, data, sizeof(data)); | |
| 1356 | + *penum += ((u32)data[0] << 8) | (u32)data[1]; | |
| 1357 | + | |
| 1358 | + return 0; | |
| 1359 | +} | |
| 1360 | + | |
| 1361 | +static int cxd2841er_read_ber_c(struct cxd2841er_priv *priv, | |
| 1362 | + u32 *bit_error, u32 *bit_count) | |
| 1363 | +{ | |
| 1364 | + u8 data[3]; | |
| 1365 | + u32 bit_err, period_exp; | |
| 1366 | + | |
| 1367 | + dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 1368 | + if (priv->state != STATE_ACTIVE_TC) { | |
| 1369 | + dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n", | |
| 1370 | + __func__, priv->state); | |
| 1371 | + return -EINVAL; | |
| 1372 | + } | |
| 1373 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40); | |
| 1374 | + cxd2841er_read_regs(priv, I2C_SLVT, 0x62, data, sizeof(data)); | |
| 1375 | + if (!(data[0] & 0x80)) { | |
| 1376 | + dev_dbg(&priv->i2c->dev, | |
| 1377 | + "%s(): no valid BER data\n", __func__); | |
| 1378 | + return -EINVAL; | |
| 1379 | + } | |
| 1380 | + bit_err = ((u32)(data[0] & 0x3f) << 16) | | |
| 1381 | + ((u32)data[1] << 8) | | |
| 1382 | + (u32)data[2]; | |
| 1383 | + cxd2841er_read_reg(priv, I2C_SLVT, 0x60, data); | |
| 1384 | + period_exp = data[0] & 0x1f; | |
| 1385 | + | |
| 1386 | + if ((period_exp <= 11) && (bit_err > (1 << period_exp) * 204 * 8)) { | |
| 1387 | + dev_dbg(&priv->i2c->dev, | |
| 1388 | + "%s(): period_exp(%u) or bit_err(%u) not in range. no valid BER data\n", | |
| 1389 | + __func__, period_exp, bit_err); | |
| 1390 | + return -EINVAL; | |
| 1391 | + } | |
| 1392 | + | |
| 1393 | + dev_dbg(&priv->i2c->dev, | |
| 1394 | + "%s(): period_exp(%u) or bit_err(%u) count=%d\n", | |
| 1395 | + __func__, period_exp, bit_err, | |
| 1396 | + ((1 << period_exp) * 204 * 8)); | |
| 1397 | + | |
| 1398 | + *bit_error = bit_err; | |
| 1399 | + *bit_count = ((1 << period_exp) * 204 * 8); | |
| 1400 | + | |
| 1401 | + return 0; | |
| 1402 | +} | |
| 1403 | + | |
| 1404 | +static int cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv, | |
| 1405 | + u32 *bit_error, u32 *bit_count) | |
| 1100 | 1406 | { |
| 1101 | 1407 | u8 data[11]; |
| 1102 | − u32 bit_error, bit_count; | |
| 1103 | − u32 temp_q, temp_r; | |
| 1104 | 1408 | |
| 1105 | 1409 | /* Set SLV-T Bank : 0xA0 */ |
| 1106 | 1410 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0); |
| @@ -1116,40 +1420,30 @@ static u32 cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv) · 9 unmodified lines | ||
| 1116 | 1420 | */ |
| 1117 | 1421 | cxd2841er_read_regs(priv, I2C_SLVT, 0x35, data, 11); |
| 1118 | 1422 | if (data[0] & 0x01) { |
| 1119 | − bit_error = ((u32)(data[1] & 0x3F) << 16) | | |
| 1120 | − ((u32)(data[2] & 0xFF) << 8) | | |
| 1121 | − (u32)(data[3] & 0xFF); | |
| 1122 | − bit_count = ((u32)(data[8] & 0x3F) << 16) | | |
| 1123 | − ((u32)(data[9] & 0xFF) << 8) | | |
| 1124 | − (u32)(data[10] & 0xFF); | |
| 1125 | − /* | |
| 1126 | − * BER = bitError / bitCount | |
| 1127 | − * = (bitError * 10^7) / bitCount | |
| 1128 | − * = ((bitError * 625 * 125 * 128) / bitCount | |
| 1129 | − */ | |
| 1130 | − if ((bit_count == 0) || (bit_error > bit_count)) { | |
| 1423 | + *bit_error = ((u32)(data[1] & 0x3F) << 16) | | |
| 1424 | + ((u32)(data[2] & 0xFF) << 8) | | |
| 1425 | + (u32)(data[3] & 0xFF); | |
| 1426 | + *bit_count = ((u32)(data[8] & 0x3F) << 16) | | |
| 1427 | + ((u32)(data[9] & 0xFF) << 8) | | |
| 1428 | + (u32)(data[10] & 0xFF); | |
| 1429 | + if ((*bit_count == 0) || (*bit_error > *bit_count)) { | |
| 1131 | 1430 | dev_dbg(&priv->i2c->dev, |
| 1132 | 1431 | "%s(): invalid bit_error %d, bit_count %d\n", |
| 1133 | − __func__, bit_error, bit_count); | |
| 1134 | − return 0; | |
| 1432 | + __func__, *bit_error, *bit_count); | |
| 1433 | + return -EINVAL; | |
| 1135 | 1434 | } |
| 1136 | − temp_q = div_u64_rem(10000000ULL * bit_error, | |
| 1137 | − bit_count, &temp_r); | |
| 1138 | − if (bit_count != 1 && temp_r >= bit_count / 2) | |
| 1139 | − temp_q++; | |
| 1140 | − return temp_q; | |
| 1435 | + return 0; | |
| 1141 | 1436 | } |
| 1142 | 1437 | dev_dbg(&priv->i2c->dev, "%s(): no data available\n", __func__); |
| 1143 | − return 0; | |
| 1438 | + return -EINVAL; | |
| 1144 | 1439 | } |
| 1145 | 1440 | |
| 1146 | 1441 | |
| 1147 | −static u32 cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv) | |
| 1442 | +static int cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv, | |
| 1443 | + u32 *bit_error, u32 *bit_count) | |
| 1148 | 1444 | { |
| 1149 | 1445 | u8 data[5]; |
| 1150 | − u32 bit_error, period; | |
| 1151 | − u32 temp_q, temp_r; | |
| 1152 | − u32 result = 0; | |
| 1446 | + u32 period; | |
| 1153 | 1447 | |
| 1154 | 1448 | /* Set SLV-T Bank : 0xB2 */ |
| 1155 | 1449 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xb2); |
| @@ -1164,10 +1458,10 @@ static u32 cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv) · 8 unmodified lines | ||
| 1164 | 1458 | cxd2841er_read_regs(priv, I2C_SLVT, 0x30, data, 5); |
| 1165 | 1459 | if (data[0] & 0x01) { |
| 1166 | 1460 | /* Bit error count */ |
| 1167 | − bit_error = ((u32)(data[1] & 0x0F) << 24) | | |
| 1168 | − ((u32)(data[2] & 0xFF) << 16) | | |
| 1169 | − ((u32)(data[3] & 0xFF) << 8) | | |
| 1170 | − (u32)(data[4] & 0xFF); | |
| 1461 | + *bit_error = ((u32)(data[1] & 0x0F) << 24) | | |
| 1462 | + ((u32)(data[2] & 0xFF) << 16) | | |
| 1463 | + ((u32)(data[3] & 0xFF) << 8) | | |
| 1464 | + (u32)(data[4] & 0xFF); | |
| 1171 | 1465 | |
| 1172 | 1466 | /* Set SLV-T Bank : 0xA0 */ |
| 1173 | 1467 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0); |
| @@ -1177,40 +1471,30 @@ static u32 cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv) · 3 unmodified lines | ||
| 1177 | 1471 | if (period == 0) { |
| 1178 | 1472 | dev_dbg(&priv->i2c->dev, |
| 1179 | 1473 | "%s(): period is 0\n", __func__); |
| 1180 | − return 0; | |
| 1474 | + return -EINVAL; | |
| 1181 | 1475 | } |
| 1182 | − if (bit_error > (period * 64800)) { | |
| 1476 | + if (*bit_error > (period * 64800)) { | |
| 1183 | 1477 | dev_dbg(&priv->i2c->dev, |
| 1184 | 1478 | "%s(): invalid bit_err 0x%x period 0x%x\n", |
| 1185 | − __func__, bit_error, period); | |
| 1186 | − return 0; | |
| 1479 | + __func__, *bit_error, period); | |
| 1480 | + return -EINVAL; | |
| 1187 | 1481 | } |
| 1188 | − /* | |
| 1189 | − * BER = bitError / (period * 64800) | |
| 1190 | − * = (bitError * 10^7) / (period * 64800) | |
| 1191 | − * = (bitError * 10^5) / (period * 648) | |
| 1192 | − * = (bitError * 12500) / (period * 81) | |
| 1193 | − * = (bitError * 10) * 1250 / (period * 81) | |
| 1194 | − */ | |
| 1195 | − temp_q = div_u64_rem(12500ULL * bit_error, | |
| 1196 | − period * 81, &temp_r); | |
| 1197 | − if (temp_r >= period * 40) | |
| 1198 | − temp_q++; | |
| 1199 | − result = temp_q; | |
| 1482 | + *bit_count = period * 64800; | |
| 1483 | + | |
| 1484 | + return 0; | |
| 1200 | 1485 | } else { |
| 1201 | 1486 | dev_dbg(&priv->i2c->dev, |
| 1202 | 1487 | "%s(): no data available\n", __func__); |
| 1203 | 1488 | } |
| 1204 | − return result; | |
| 1489 | + return -EINVAL; | |
| 1205 | 1490 | } |
| 1206 | 1491 | |
| 1207 | −static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv, u32 *ber) | |
| 1492 | +static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv, | |
| 1493 | + u32 *bit_error, u32 *bit_count) | |
| 1208 | 1494 | { |
| 1209 | 1495 | u8 data[4]; |
| 1210 | − u32 div, q, r; | |
| 1211 | − u32 bit_err, period_exp, n_ldpc; | |
| 1496 | + u32 period_exp, n_ldpc; | |
| 1212 | 1497 | |
| 1213 | − *ber = 0; | |
| 1214 | 1498 | if (priv->state != STATE_ACTIVE_TC) { |
| 1215 | 1499 | dev_dbg(&priv->i2c->dev, |
| 1216 | 1500 | "%s(): invalid state %d\n", __func__, priv->state); |
| @@ -1221,40 +1505,44 @@ static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv, u32 *ber) · 4 unmodified lines | ||
| 1221 | 1505 | if (!(data[0] & 0x10)) { |
| 1222 | 1506 | dev_dbg(&priv->i2c->dev, |
| 1223 | 1507 | "%s(): no valid BER data\n", __func__); |
| 1224 | − return 0; | |
| 1508 | + return -EINVAL; | |
| 1225 | 1509 | } |
| 1226 | − bit_err = ((u32)(data[0] & 0x0f) << 24) | | |
| 1227 | − ((u32)data[1] << 16) | | |
| 1228 | − ((u32)data[2] << 8) | | |
| 1229 | − (u32)data[3]; | |
| 1510 | + *bit_error = ((u32)(data[0] & 0x0f) << 24) | | |
| 1511 | + ((u32)data[1] << 16) | | |
| 1512 | + ((u32)data[2] << 8) | | |
| 1513 | + (u32)data[3]; | |
| 1230 | 1514 | cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data); |
| 1231 | 1515 | period_exp = data[0] & 0x0f; |
| 1232 | 1516 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x22); |
| 1233 | 1517 | cxd2841er_read_reg(priv, I2C_SLVT, 0x5e, data); |
| 1234 | 1518 | n_ldpc = ((data[0] & 0x03) == 0 ? 16200 : 64800); |
| 1235 | − if (bit_err > ((1U << period_exp) * n_ldpc)) { | |
| 1519 | + if (*bit_error > ((1U << period_exp) * n_ldpc)) { | |
| 1236 | 1520 | dev_dbg(&priv->i2c->dev, |
| 1237 | 1521 | "%s(): invalid BER value\n", __func__); |
| 1238 | 1522 | return -EINVAL; |
| 1239 | 1523 | } |
| 1524 | + | |
| 1525 | + /* | |
| 1526 | + * FIXME: the right thing would be to return bit_error untouched, | |
| 1527 | + * but, as we don't know the scale returned by the counters, let's | |
| 1528 | + * at least preserver BER = bit_error/bit_count. | |
| 1529 | + */ | |
| 1240 | 1530 | if (period_exp >= 4) { |
| 1241 | − div = (1U << (period_exp - 4)) * (n_ldpc / 200); | |
| 1242 | − q = div_u64_rem(3125ULL * bit_err, div, &r); | |
| 1531 | + *bit_count = (1U << (period_exp - 4)) * (n_ldpc / 200); | |
| 1532 | + *bit_error *= 3125ULL; | |
| 1243 | 1533 | } else { |
| 1244 | − div = (1U << period_exp) * (n_ldpc / 200); | |
| 1245 | − q = div_u64_rem(50000ULL * bit_err, div, &r); | |
| 1534 | + *bit_count = (1U << period_exp) * (n_ldpc / 200); | |
| 1535 | + *bit_error *= 50000ULL; | |
| 1246 | 1536 | } |
| 1247 | − *ber = (r >= div / 2) ? q + 1 : q; | |
| 1248 | 1537 | return 0; |
| 1249 | 1538 | } |
| 1250 | 1539 | |
| 1251 | −static int cxd2841er_read_ber_t(struct cxd2841er_priv *priv, u32 *ber) | |
| 1540 | +static int cxd2841er_read_ber_t(struct cxd2841er_priv *priv, | |
| 1541 | + u32 *bit_error, u32 *bit_count) | |
| 1252 | 1542 | { |
| 1253 | 1543 | u8 data[2]; |
| 1254 | − u32 div, q, r; | |
| 1255 | − u32 bit_err, period; | |
| 1544 | + u32 period; | |
| 1256 | 1545 | |
| 1257 | − *ber = 0; | |
| 1258 | 1546 | if (priv->state != STATE_ACTIVE_TC) { |
| 1259 | 1547 | dev_dbg(&priv->i2c->dev, |
| 1260 | 1548 | "%s(): invalid state %d\n", __func__, priv->state); |
| @@ -1268,16 +1556,22 @@ static int cxd2841er_read_ber_t(struct cxd2841er_priv *priv, u32 *ber) · 7 unmodified lines | ||
| 1268 | 1556 | return 0; |
| 1269 | 1557 | } |
| 1270 | 1558 | cxd2841er_read_regs(priv, I2C_SLVT, 0x22, data, sizeof(data)); |
| 1271 | − bit_err = ((u32)data[0] << 8) | (u32)data[1]; | |
| 1559 | + *bit_error = ((u32)data[0] << 8) | (u32)data[1]; | |
| 1272 | 1560 | cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data); |
| 1273 | 1561 | period = ((data[0] & 0x07) == 0) ? 256 : (4096 << (data[0] & 0x07)); |
| 1274 | − div = period / 128; | |
| 1275 | − q = div_u64_rem(78125ULL * bit_err, div, &r); | |
| 1276 | − *ber = (r >= div / 2) ? q + 1 : q; | |
| 1562 | + | |
| 1563 | + /* | |
| 1564 | + * FIXME: the right thing would be to return bit_error untouched, | |
| 1565 | + * but, as we don't know the scale returned by the counters, let's | |
| 1566 | + * at least preserver BER = bit_error/bit_count. | |
| 1567 | + */ | |
| 1568 | + *bit_count = period / 128; | |
| 1569 | + *bit_error *= 78125ULL; | |
| 1277 | 1570 | return 0; |
| 1278 | 1571 | } |
| 1279 | 1572 | |
| 1280 | −static u32 cxd2841er_dvbs_read_snr(struct cxd2841er_priv *priv, u8 delsys) | |
| 1573 | +static u32 cxd2841er_dvbs_read_snr(struct cxd2841er_priv *priv, | |
| 1574 | + u8 delsys, u32 *snr) | |
| 1281 | 1575 | { |
| 1282 | 1576 | u8 data[3]; |
| 1283 | 1577 | u32 res = 0, value; |
| @@ -1335,9 +1629,71 @@ static u32 cxd2841er_dvbs_read_snr(struct cxd2841er_priv *priv, u8 delsys) · 51 unmodified lines | ||
| 1335 | 1629 | } else { |
| 1336 | 1630 | dev_dbg(&priv->i2c->dev, |
| 1337 | 1631 | "%s(): no data available\n", __func__); |
| 1632 | + return -EINVAL; | |
| 1338 | 1633 | } |
| 1339 | 1634 | done: |
| 1340 | − return res; | |
| 1635 | + *snr = res; | |
| 1636 | + return 0; | |
| 1637 | +} | |
| 1638 | + | |
| 1639 | +static uint32_t sony_log(uint32_t x) | |
| 1640 | +{ | |
| 1641 | + return (((10000>>8)*(intlog2(x)>>16) + LOG2_E_100X/2)/LOG2_E_100X); | |
| 1642 | +} | |
| 1643 | + | |
| 1644 | +static int cxd2841er_read_snr_c(struct cxd2841er_priv *priv, u32 *snr) | |
| 1645 | +{ | |
| 1646 | + u32 reg; | |
| 1647 | + u8 data[2]; | |
| 1648 | + enum sony_dvbc_constellation_t qam = SONY_DVBC_CONSTELLATION_16QAM; | |
| 1649 | + | |
| 1650 | + *snr = 0; | |
| 1651 | + if (priv->state != STATE_ACTIVE_TC) { | |
| 1652 | + dev_dbg(&priv->i2c->dev, | |
| 1653 | + "%s(): invalid state %d\n", | |
| 1654 | + __func__, priv->state); | |
| 1655 | + return -EINVAL; | |
| 1656 | + } | |
| 1657 | + | |
| 1658 | + /* | |
| 1659 | + * Freeze registers: ensure multiple separate register reads | |
| 1660 | + * are from the same snapshot | |
| 1661 | + */ | |
| 1662 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x01, 0x01); | |
| 1663 | + | |
| 1664 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x40); | |
| 1665 | + cxd2841er_read_regs(priv, I2C_SLVT, 0x19, data, 1); | |
| 1666 | + qam = (enum sony_dvbc_constellation_t) (data[0] & 0x07); | |
| 1667 | + cxd2841er_read_regs(priv, I2C_SLVT, 0x4C, data, 2); | |
| 1668 | + | |
| 1669 | + reg = ((u32)(data[0]&0x1f) << 8) | (u32)data[1]; | |
| 1670 | + if (reg == 0) { | |
| 1671 | + dev_dbg(&priv->i2c->dev, | |
| 1672 | + "%s(): reg value out of range\n", __func__); | |
| 1673 | + return 0; | |
| 1674 | + } | |
| 1675 | + | |
| 1676 | + switch (qam) { | |
| 1677 | + case SONY_DVBC_CONSTELLATION_16QAM: | |
| 1678 | + case SONY_DVBC_CONSTELLATION_64QAM: | |
| 1679 | + case SONY_DVBC_CONSTELLATION_256QAM: | |
| 1680 | + /* SNR(dB) = -9.50 * ln(IREG_SNR_ESTIMATE / (24320)) */ | |
| 1681 | + if (reg < 126) | |
| 1682 | + reg = 126; | |
| 1683 | + *snr = -95 * (int32_t)sony_log(reg) + 95941; | |
| 1684 | + break; | |
| 1685 | + case SONY_DVBC_CONSTELLATION_32QAM: | |
| 1686 | + case SONY_DVBC_CONSTELLATION_128QAM: | |
| 1687 | + /* SNR(dB) = -8.75 * ln(IREG_SNR_ESTIMATE / (20800)) */ | |
| 1688 | + if (reg < 69) | |
| 1689 | + reg = 69; | |
| 1690 | + *snr = -88 * (int32_t)sony_log(reg) + 86999; | |
| 1691 | + break; | |
| 1692 | + default: | |
| 1693 | + return -EINVAL; | |
| 1694 | + } | |
| 1695 | + | |
| 1696 | + return 0; | |
| 1341 | 1697 | } |
| 1342 | 1698 | |
| 1343 | 1699 | static int cxd2841er_read_snr_t(struct cxd2841er_priv *priv, u32 *snr) |
| @@ -1391,14 +1747,80 @@ static int cxd2841er_read_snr_t2(struct cxd2841er_priv *priv, u32 *snr) · 47 unmodified lines | ||
| 1391 | 1747 | return 0; |
| 1392 | 1748 | } |
| 1393 | 1749 | |
| 1394 | −static u16 cxd2841er_read_agc_gain_t_t2(struct cxd2841er_priv *priv, | |
| 1395 | − u8 delsys) | |
| 1750 | +static int cxd2841er_read_snr_i(struct cxd2841er_priv *priv, u32 *snr) | |
| 1751 | +{ | |
| 1752 | + u32 reg; | |
| 1753 | + u8 data[2]; | |
| 1754 | + | |
| 1755 | + *snr = 0; | |
| 1756 | + if (priv->state != STATE_ACTIVE_TC) { | |
| 1757 | + dev_dbg(&priv->i2c->dev, | |
| 1758 | + "%s(): invalid state %d\n", __func__, | |
| 1759 | + priv->state); | |
| 1760 | + return -EINVAL; | |
| 1761 | + } | |
| 1762 | + | |
| 1763 | + /* Freeze all registers */ | |
| 1764 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x01, 0x01); | |
| 1765 | + | |
| 1766 | + | |
| 1767 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); | |
| 1768 | + cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data)); | |
| 1769 | + reg = ((u32)data[0] << 8) | (u32)data[1]; | |
| 1770 | + if (reg == 0) { | |
| 1771 | + dev_dbg(&priv->i2c->dev, | |
| 1772 | + "%s(): reg value out of range\n", __func__); | |
| 1773 | + return 0; | |
| 1774 | + } | |
| 1775 | + if (reg > 4996) | |
| 1776 | + reg = 4996; | |
| 1777 | + *snr = 100 * intlog10(reg) - 9031; | |
| 1778 | + return 0; | |
| 1779 | +} | |
| 1780 | + | |
| 1781 | +static u16 cxd2841er_read_agc_gain_c(struct cxd2841er_priv *priv, | |
| 1782 | + u8 delsys) | |
| 1783 | +{ | |
| 1784 | + u8 data[2]; | |
| 1785 | + | |
| 1786 | + cxd2841er_write_reg( | |
| 1787 | + priv, I2C_SLVT, 0x00, 0x40); | |
| 1788 | + cxd2841er_read_regs(priv, I2C_SLVT, 0x49, data, 2); | |
| 1789 | + dev_dbg(&priv->i2c->dev, | |
| 1790 | + "%s(): AGC value=%u\n", | |
| 1791 | + __func__, (((u16)data[0] & 0x0F) << 8) | | |
| 1792 | + (u16)(data[1] & 0xFF)); | |
| 1793 | + return ((((u16)data[0] & 0x0F) << 8) | (u16)(data[1] & 0xFF)) << 4; | |
| 1794 | +} | |
| 1795 | + | |
| 1796 | +static u16 cxd2841er_read_agc_gain_t_t2(struct cxd2841er_priv *priv, | |
| 1797 | + u8 delsys) | |
| 1396 | 1798 | { |
| 1397 | 1799 | u8 data[2]; |
| 1398 | 1800 | |
| 1399 | 1801 | cxd2841er_write_reg( |
| 1400 | 1802 | priv, I2C_SLVT, 0x00, (delsys == SYS_DVBT ? 0x10 : 0x20)); |
| 1401 | 1803 | cxd2841er_read_regs(priv, I2C_SLVT, 0x26, data, 2); |
| 1804 | + dev_dbg(&priv->i2c->dev, | |
| 1805 | + "%s(): AGC value=%u\n", | |
| 1806 | + __func__, (((u16)data[0] & 0x0F) << 8) | | |
| 1807 | + (u16)(data[1] & 0xFF)); | |
| 1808 | + return ((((u16)data[0] & 0x0F) << 8) | (u16)(data[1] & 0xFF)) << 4; | |
| 1809 | +} | |
| 1810 | + | |
| 1811 | +static u16 cxd2841er_read_agc_gain_i(struct cxd2841er_priv *priv, | |
| 1812 | + u8 delsys) | |
| 1813 | +{ | |
| 1814 | + u8 data[2]; | |
| 1815 | + | |
| 1816 | + cxd2841er_write_reg( | |
| 1817 | + priv, I2C_SLVT, 0x00, 0x60); | |
| 1818 | + cxd2841er_read_regs(priv, I2C_SLVT, 0x26, data, 2); | |
| 1819 | + | |
| 1820 | + dev_dbg(&priv->i2c->dev, | |
| 1821 | + "%s(): AGC value=%u\n", | |
| 1822 | + __func__, (((u16)data[0] & 0x0F) << 8) | | |
| 1823 | + (u16)(data[1] & 0xFF)); | |
| 1402 | 1824 | return ((((u16)data[0] & 0x0F) << 8) | (u16)(data[1] & 0xFF)) << 4; |
| 1403 | 1825 | } |
| 1404 | 1826 | |
| @@ -1417,101 +1839,170 @@ static u16 cxd2841er_read_agc_gain_s(struct cxd2841er_priv *priv) · 12 unmodified lines | ||
| 1417 | 1839 | return ((((u16)data[0] & 0x1F) << 8) | (u16)(data[1] & 0xFF)) << 3; |
| 1418 | 1840 | } |
| 1419 | 1841 | |
| 1420 | −static int cxd2841er_read_ber(struct dvb_frontend *fe, u32 *ber) | |
| 1842 | +static void cxd2841er_read_ber(struct dvb_frontend *fe) | |
| 1421 | 1843 | { |
| 1422 | 1844 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 1423 | 1845 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 1846 | + u32 ret, bit_error = 0, bit_count = 0; | |
| 1424 | 1847 | |
| 1425 | 1848 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1426 | − *ber = 0; | |
| 1427 | 1849 | switch (p->delivery_system) { |
| 1850 | + case SYS_DVBC_ANNEX_A: | |
| 1851 | + case SYS_DVBC_ANNEX_B: | |
| 1852 | + case SYS_DVBC_ANNEX_C: | |
| 1853 | + ret = cxd2841er_read_ber_c(priv, &bit_error, &bit_count); | |
| 1854 | + break; | |
| 1428 | 1855 | case SYS_DVBS: |
| 1429 | − *ber = cxd2841er_mon_read_ber_s(priv); | |
| 1856 | + ret = cxd2841er_mon_read_ber_s(priv, &bit_error, &bit_count); | |
| 1430 | 1857 | break; |
| 1431 | 1858 | case SYS_DVBS2: |
| 1432 | − *ber = cxd2841er_mon_read_ber_s2(priv); | |
| 1859 | + ret = cxd2841er_mon_read_ber_s2(priv, &bit_error, &bit_count); | |
| 1433 | 1860 | break; |
| 1434 | 1861 | case SYS_DVBT: |
| 1435 | − return cxd2841er_read_ber_t(priv, ber); | |
| 1862 | + ret = cxd2841er_read_ber_t(priv, &bit_error, &bit_count); | |
| 1863 | + break; | |
| 1436 | 1864 | case SYS_DVBT2: |
| 1437 | − return cxd2841er_read_ber_t2(priv, ber); | |
| 1438 | − default: | |
| 1439 | − *ber = 0; | |
| 1865 | + ret = cxd2841er_read_ber_t2(priv, &bit_error, &bit_count); | |
| 1440 | 1866 | break; |
| 1867 | + default: | |
| 1868 | + p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 1869 | + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 1870 | + return; | |
| 1871 | + } | |
| 1872 | + | |
| 1873 | + if (!ret) { | |
| 1874 | + p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; | |
| 1875 | + p->post_bit_error.stat[0].uvalue += bit_error; | |
| 1876 | + p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; | |
| 1877 | + p->post_bit_count.stat[0].uvalue += bit_count; | |
| 1878 | + } else { | |
| 1879 | + p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 1880 | + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 1441 | 1881 | } |
| 1442 | − return 0; | |
| 1443 | 1882 | } |
| 1444 | 1883 | |
| 1445 | −static int cxd2841er_read_signal_strength(struct dvb_frontend *fe, | |
| 1446 | − u16 *strength) | |
| 1884 | +static void cxd2841er_read_signal_strength(struct dvb_frontend *fe) | |
| 1447 | 1885 | { |
| 1448 | 1886 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 1449 | 1887 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 1888 | + s32 strength; | |
| 1450 | 1889 | |
| 1451 | 1890 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1452 | 1891 | switch (p->delivery_system) { |
| 1453 | 1892 | case SYS_DVBT: |
| 1454 | 1893 | case SYS_DVBT2: |
| 1455 | − *strength = 65535 - cxd2841er_read_agc_gain_t_t2( | |
| 1456 | − priv, p->delivery_system); | |
| 1894 | + strength = cxd2841er_read_agc_gain_t_t2(priv, | |
| 1895 | + p->delivery_system); | |
| 1896 | + p->strength.stat[0].scale = FE_SCALE_DECIBEL; | |
| 1897 | + /* Formula was empirically determinated @ 410 MHz */ | |
| 1898 | + p->strength.stat[0].uvalue = strength * 366 / 100 - 89520; | |
| 1899 | + break; /* Code moved out of the function */ | |
| 1900 | + case SYS_DVBC_ANNEX_A: | |
| 1901 | + case SYS_DVBC_ANNEX_B: | |
| 1902 | + case SYS_DVBC_ANNEX_C: | |
| 1903 | + strength = cxd2841er_read_agc_gain_c(priv, | |
| 1904 | + p->delivery_system); | |
| 1905 | + p->strength.stat[0].scale = FE_SCALE_DECIBEL; | |
| 1906 | + /* | |
| 1907 | + * Formula was empirically determinated via linear regression, | |
| 1908 | + * using frequencies: 175 MHz, 410 MHz and 800 MHz, and a | |
| 1909 | + * stream modulated with QAM64 | |
| 1910 | + */ | |
| 1911 | + p->strength.stat[0].uvalue = strength * 4045 / 1000 - 85224; | |
| 1912 | + break; | |
| 1913 | + case SYS_ISDBT: | |
| 1914 | + strength = cxd2841er_read_agc_gain_i(priv, p->delivery_system); | |
| 1915 | + p->strength.stat[0].scale = FE_SCALE_DECIBEL; | |
| 1916 | + /* | |
| 1917 | + * Formula was empirically determinated via linear regression, | |
| 1918 | + * using frequencies: 175 MHz, 410 MHz and 800 MHz. | |
| 1919 | + */ | |
| 1920 | + p->strength.stat[0].uvalue = strength * 3775 / 1000 - 90185; | |
| 1457 | 1921 | break; |
| 1458 | 1922 | case SYS_DVBS: |
| 1459 | 1923 | case SYS_DVBS2: |
| 1460 | − *strength = 65535 - cxd2841er_read_agc_gain_s(priv); | |
| 1924 | + strength = 65535 - cxd2841er_read_agc_gain_s(priv); | |
| 1925 | + p->strength.stat[0].scale = FE_SCALE_RELATIVE; | |
| 1926 | + p->strength.stat[0].uvalue = strength; | |
| 1461 | 1927 | break; |
| 1462 | 1928 | default: |
| 1463 | − *strength = 0; | |
| 1929 | + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 1464 | 1930 | break; |
| 1465 | 1931 | } |
| 1466 | − return 0; | |
| 1467 | 1932 | } |
| 1468 | 1933 | |
| 1469 | −static int cxd2841er_read_snr(struct dvb_frontend *fe, u16 *snr) | |
| 1934 | +static void cxd2841er_read_snr(struct dvb_frontend *fe) | |
| 1470 | 1935 | { |
| 1471 | 1936 | u32 tmp = 0; |
| 1937 | + int ret = 0; | |
| 1472 | 1938 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 1473 | 1939 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 1474 | 1940 | |
| 1475 | 1941 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1476 | 1942 | switch (p->delivery_system) { |
| 1943 | + case SYS_DVBC_ANNEX_A: | |
| 1944 | + case SYS_DVBC_ANNEX_B: | |
| 1945 | + case SYS_DVBC_ANNEX_C: | |
| 1946 | + ret = cxd2841er_read_snr_c(priv, &tmp); | |
| 1947 | + break; | |
| 1477 | 1948 | case SYS_DVBT: |
| 1478 | − cxd2841er_read_snr_t(priv, &tmp); | |
| 1949 | + ret = cxd2841er_read_snr_t(priv, &tmp); | |
| 1479 | 1950 | break; |
| 1480 | 1951 | case SYS_DVBT2: |
| 1481 | − cxd2841er_read_snr_t2(priv, &tmp); | |
| 1952 | + ret = cxd2841er_read_snr_t2(priv, &tmp); | |
| 1953 | + break; | |
| 1954 | + case SYS_ISDBT: | |
| 1955 | + ret = cxd2841er_read_snr_i(priv, &tmp); | |
| 1482 | 1956 | break; |
| 1483 | 1957 | case SYS_DVBS: |
| 1484 | 1958 | case SYS_DVBS2: |
| 1485 | − tmp = cxd2841er_dvbs_read_snr(priv, p->delivery_system); | |
| 1959 | + ret = cxd2841er_dvbs_read_snr(priv, p->delivery_system, &tmp); | |
| 1486 | 1960 | break; |
| 1487 | 1961 | default: |
| 1488 | 1962 | dev_dbg(&priv->i2c->dev, "%s(): unknown delivery system %d\n", |
| 1489 | 1963 | __func__, p->delivery_system); |
| 1490 | − break; | |
| 1964 | + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 1965 | + return; | |
| 1966 | + } | |
| 1967 | + | |
| 1968 | + if (!ret) { | |
| 1969 | + p->cnr.stat[0].scale = FE_SCALE_DECIBEL; | |
| 1970 | + p->cnr.stat[0].svalue = tmp; | |
| 1971 | + } else { | |
| 1972 | + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 1491 | 1973 | } |
| 1492 | − *snr = tmp & 0xffff; | |
| 1493 | − return 0; | |
| 1494 | 1974 | } |
| 1495 | 1975 | |
| 1496 | −static int cxd2841er_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | |
| 1976 | +static void cxd2841er_read_ucblocks(struct dvb_frontend *fe) | |
| 1497 | 1977 | { |
| 1498 | 1978 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 1499 | 1979 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 1980 | + u32 ucblocks; | |
| 1500 | 1981 | |
| 1501 | 1982 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1502 | 1983 | switch (p->delivery_system) { |
| 1984 | + case SYS_DVBC_ANNEX_A: | |
| 1985 | + case SYS_DVBC_ANNEX_B: | |
| 1986 | + case SYS_DVBC_ANNEX_C: | |
| 1987 | + cxd2841er_read_packet_errors_c(priv, &ucblocks); | |
| 1988 | + break; | |
| 1503 | 1989 | case SYS_DVBT: |
| 1504 | − cxd2841er_read_packet_errors_t(priv, ucblocks); | |
| 1990 | + cxd2841er_read_packet_errors_t(priv, &ucblocks); | |
| 1505 | 1991 | break; |
| 1506 | 1992 | case SYS_DVBT2: |
| 1507 | − cxd2841er_read_packet_errors_t2(priv, ucblocks); | |
| 1993 | + cxd2841er_read_packet_errors_t2(priv, &ucblocks); | |
| 1508 | 1994 | break; |
| 1509 | − default: | |
| 1510 | − *ucblocks = 0; | |
| 1995 | + case SYS_ISDBT: | |
| 1996 | + cxd2841er_read_packet_errors_i(priv, &ucblocks); | |
| 1511 | 1997 | break; |
| 1998 | + default: | |
| 1999 | + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 2000 | + return; | |
| 1512 | 2001 | } |
| 1513 | 2002 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1514 | − return 0; | |
| 2003 | + | |
| 2004 | + p->block_error.stat[0].scale = FE_SCALE_COUNTER; | |
| 2005 | + p->block_error.stat[0].uvalue = ucblocks; | |
| 1515 | 2006 | } |
| 1516 | 2007 | |
| 1517 | 2008 | static int cxd2841er_dvbt2_set_profile( |
| @@ -1524,15 +2015,18 @@ static int cxd2841er_dvbt2_set_profile( · 6 unmodified lines | ||
| 1524 | 2015 | switch (profile) { |
| 1525 | 2016 | case DVBT2_PROFILE_BASE: |
| 1526 | 2017 | tune_mode = 0x01; |
| 1527 | − seq_not2d_time = 12; | |
| 2018 | + /* Set early unlock time */ | |
| 2019 | + seq_not2d_time = (priv->xtal == SONY_XTAL_24000)?0x0E:0x0C; | |
| 1528 | 2020 | break; |
| 1529 | 2021 | case DVBT2_PROFILE_LITE: |
| 1530 | 2022 | tune_mode = 0x05; |
| 1531 | − seq_not2d_time = 40; | |
| 2023 | + /* Set early unlock time */ | |
| 2024 | + seq_not2d_time = (priv->xtal == SONY_XTAL_24000)?0x2E:0x28; | |
| 1532 | 2025 | break; |
| 1533 | 2026 | case DVBT2_PROFILE_ANY: |
| 1534 | 2027 | tune_mode = 0x00; |
| 1535 | − seq_not2d_time = 40; | |
| 2028 | + /* Set early unlock time */ | |
| 2029 | + seq_not2d_time = (priv->xtal == SONY_XTAL_24000)?0x2E:0x28; | |
| 1536 | 2030 | break; |
| 1537 | 2031 | default: |
| 1538 | 2032 | return -EINVAL; |
| @@ -1574,254 +2068,617 @@ static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv, · 35 unmodified lines | ||
| 1574 | 2068 | u32 bandwidth) |
| 1575 | 2069 | { |
| 1576 | 2070 | u32 iffreq; |
| 1577 | − u8 b20_9f[5]; | |
| 1578 | − u8 b10_a6[14]; | |
| 1579 | − u8 b10_b6[3]; | |
| 1580 | − u8 b10_d7; | |
| 2071 | + u8 data[MAX_WRITE_REGSIZE]; | |
| 2072 | + | |
| 2073 | + const uint8_t nominalRate8bw[3][5] = { | |
| 2074 | + /* TRCG Nominal Rate [37:0] */ | |
| 2075 | + {0x11, 0xF0, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | |
| 2076 | + {0x15, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | |
| 2077 | + {0x11, 0xF0, 0x00, 0x00, 0x00} /* 41MHz XTal */ | |
| 2078 | + }; | |
| 2079 | + | |
| 2080 | + const uint8_t nominalRate7bw[3][5] = { | |
| 2081 | + /* TRCG Nominal Rate [37:0] */ | |
| 2082 | + {0x14, 0x80, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | |
| 2083 | + {0x18, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | |
| 2084 | + {0x14, 0x80, 0x00, 0x00, 0x00} /* 41MHz XTal */ | |
| 2085 | + }; | |
| 2086 | + | |
| 2087 | + const uint8_t nominalRate6bw[3][5] = { | |
| 2088 | + /* TRCG Nominal Rate [37:0] */ | |
| 2089 | + {0x17, 0xEA, 0xAA, 0xAA, 0xAA}, /* 20.5MHz XTal */ | |
| 2090 | + {0x1C, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | |
| 2091 | + {0x17, 0xEA, 0xAA, 0xAA, 0xAA} /* 41MHz XTal */ | |
| 2092 | + }; | |
| 2093 | + | |
| 2094 | + const uint8_t nominalRate5bw[3][5] = { | |
| 2095 | + /* TRCG Nominal Rate [37:0] */ | |
| 2096 | + {0x1C, 0xB3, 0x33, 0x33, 0x33}, /* 20.5MHz XTal */ | |
| 2097 | + {0x21, 0x99, 0x99, 0x99, 0x99}, /* 24MHz XTal */ | |
| 2098 | + {0x1C, 0xB3, 0x33, 0x33, 0x33} /* 41MHz XTal */ | |
| 2099 | + }; | |
| 2100 | + | |
| 2101 | + const uint8_t nominalRate17bw[3][5] = { | |
| 2102 | + /* TRCG Nominal Rate [37:0] */ | |
| 2103 | + {0x58, 0xE2, 0xAF, 0xE0, 0xBC}, /* 20.5MHz XTal */ | |
| 2104 | + {0x68, 0x0F, 0xA2, 0x32, 0xD0}, /* 24MHz XTal */ | |
| 2105 | + {0x58, 0xE2, 0xAF, 0xE0, 0xBC} /* 41MHz XTal */ | |
| 2106 | + }; | |
| 2107 | + | |
| 2108 | + const uint8_t itbCoef8bw[3][14] = { | |
| 2109 | + {0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, | |
| 2110 | + 0x23, 0xA9, 0x1F, 0xA8, 0x2C, 0xC8}, /* 20.5MHz XTal */ | |
| 2111 | + {0x2F, 0xBA, 0x28, 0x9B, 0x28, 0x9D, 0x28, 0xA1, | |
| 2112 | + 0x29, 0xA5, 0x2A, 0xAC, 0x29, 0xB5}, /* 24MHz XTal */ | |
| 2113 | + {0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, | |
| 2114 | + 0x23, 0xA9, 0x1F, 0xA8, 0x2C, 0xC8} /* 41MHz XTal */ | |
| 2115 | + }; | |
| 2116 | + | |
| 2117 | + const uint8_t itbCoef7bw[3][14] = { | |
| 2118 | + {0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, | |
| 2119 | + 0x29, 0xB0, 0x26, 0xA9, 0x21, 0xA5}, /* 20.5MHz XTal */ | |
| 2120 | + {0x30, 0xB1, 0x29, 0x9A, 0x28, 0x9C, 0x28, 0xA0, | |
| 2121 | + 0x29, 0xA2, 0x2B, 0xA6, 0x2B, 0xAD}, /* 24MHz XTal */ | |
| 2122 | + {0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, | |
| 2123 | + 0x29, 0xB0, 0x26, 0xA9, 0x21, 0xA5} /* 41MHz XTal */ | |
| 2124 | + }; | |
| 2125 | + | |
| 2126 | + const uint8_t itbCoef6bw[3][14] = { | |
| 2127 | + {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, | |
| 2128 | + 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ | |
| 2129 | + {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, | |
| 2130 | + 0x29, 0xA4, 0x29, 0xA2, 0x29, 0xA8}, /* 24MHz XTal */ | |
| 2131 | + {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, | |
| 2132 | + 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4} /* 41MHz XTal */ | |
| 2133 | + }; | |
| 2134 | + | |
| 2135 | + const uint8_t itbCoef5bw[3][14] = { | |
| 2136 | + {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, | |
| 2137 | + 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ | |
| 2138 | + {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, | |
| 2139 | + 0x29, 0xA4, 0x29, 0xA2, 0x29, 0xA8}, /* 24MHz XTal */ | |
| 2140 | + {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, | |
| 2141 | + 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4} /* 41MHz XTal */ | |
| 2142 | + }; | |
| 2143 | + | |
| 2144 | + const uint8_t itbCoef17bw[3][14] = { | |
| 2145 | + {0x25, 0xA0, 0x36, 0x8D, 0x2E, 0x94, 0x28, 0x9B, | |
| 2146 | + 0x32, 0x90, 0x2C, 0x9D, 0x29, 0x99}, /* 20.5MHz XTal */ | |
| 2147 | + {0x33, 0x8E, 0x2B, 0x97, 0x2D, 0x95, 0x37, 0x8B, | |
| 2148 | + 0x30, 0x97, 0x2D, 0x9A, 0x21, 0xA4}, /* 24MHz XTal */ | |
| 2149 | + {0x25, 0xA0, 0x36, 0x8D, 0x2E, 0x94, 0x28, 0x9B, | |
| 2150 | + 0x32, 0x90, 0x2C, 0x9D, 0x29, 0x99} /* 41MHz XTal */ | |
| 2151 | + }; | |
| 2152 | + | |
| 2153 | + /* Set SLV-T Bank : 0x20 */ | |
| 2154 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20); | |
| 1581 | 2155 | |
| 1582 | − dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 1583 | 2156 | switch (bandwidth) { |
| 1584 | 2157 | case 8000000: |
| 1585 | − /* bank 0x20, reg 0x9f */ | |
| 1586 | − b20_9f[0] = 0x11; | |
| 1587 | − b20_9f[1] = 0xf0; | |
| 1588 | − b20_9f[2] = 0x00; | |
| 1589 | − b20_9f[3] = 0x00; | |
| 1590 | − b20_9f[4] = 0x00; | |
| 1591 | − /* bank 0x10, reg 0xa6 */ | |
| 1592 | − b10_a6[0] = 0x26; | |
| 1593 | − b10_a6[1] = 0xaf; | |
| 1594 | − b10_a6[2] = 0x06; | |
| 1595 | − b10_a6[3] = 0xcd; | |
| 1596 | − b10_a6[4] = 0x13; | |
| 1597 | − b10_a6[5] = 0xbb; | |
| 1598 | − b10_a6[6] = 0x28; | |
| 1599 | − b10_a6[7] = 0xba; | |
| 1600 | − b10_a6[8] = 0x23; | |
| 1601 | − b10_a6[9] = 0xa9; | |
| 1602 | − b10_a6[10] = 0x1f; | |
| 1603 | − b10_a6[11] = 0xa8; | |
| 1604 | − b10_a6[12] = 0x2c; | |
| 1605 | − b10_a6[13] = 0xc8; | |
| 1606 | − iffreq = MAKE_IFFREQ_CONFIG(4.80); | |
| 1607 | − b10_d7 = 0x00; | |
| 2158 | + /* <Timing Recovery setting> */ | |
| 2159 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2160 | + 0x9F, nominalRate8bw[priv->xtal], 5); | |
| 2161 | + | |
| 2162 | + /* Set SLV-T Bank : 0x27 */ | |
| 2163 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); | |
| 2164 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, | |
| 2165 | + 0x7a, 0x00, 0x0f); | |
| 2166 | + | |
| 2167 | + /* Set SLV-T Bank : 0x10 */ | |
| 2168 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | |
| 2169 | + | |
| 2170 | + /* Group delay equaliser settings for | |
| 2171 | + * ASCOT2D, ASCOT2E and ASCOT3 tuners | |
| 2172 | + */ | |
| 2173 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2174 | + 0xA6, itbCoef8bw[priv->xtal], 14); | |
| 2175 | + /* <IF freq setting> */ | |
| 2176 | + iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.80); | |
| 2177 | + data[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 2178 | + data[1] = (u8)((iffreq >> 8) & 0xff); | |
| 2179 | + data[2] = (u8)(iffreq & 0xff); | |
| 2180 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | |
| 2181 | + /* System bandwidth setting */ | |
| 2182 | + cxd2841er_set_reg_bits( | |
| 2183 | + priv, I2C_SLVT, 0xD7, 0x00, 0x07); | |
| 1608 | 2184 | break; |
| 1609 | 2185 | case 7000000: |
| 1610 | − /* bank 0x20, reg 0x9f */ | |
| 1611 | − b20_9f[0] = 0x14; | |
| 1612 | − b20_9f[1] = 0x80; | |
| 1613 | − b20_9f[2] = 0x00; | |
| 1614 | − b20_9f[3] = 0x00; | |
| 1615 | − b20_9f[4] = 0x00; | |
| 1616 | − /* bank 0x10, reg 0xa6 */ | |
| 1617 | − b10_a6[0] = 0x2C; | |
| 1618 | − b10_a6[1] = 0xBD; | |
| 1619 | − b10_a6[2] = 0x02; | |
| 1620 | − b10_a6[3] = 0xCF; | |
| 1621 | − b10_a6[4] = 0x04; | |
| 1622 | − b10_a6[5] = 0xF8; | |
| 1623 | − b10_a6[6] = 0x23; | |
| 1624 | − b10_a6[7] = 0xA6; | |
| 1625 | − b10_a6[8] = 0x29; | |
| 1626 | − b10_a6[9] = 0xB0; | |
| 1627 | − b10_a6[10] = 0x26; | |
| 1628 | − b10_a6[11] = 0xA9; | |
| 1629 | − b10_a6[12] = 0x21; | |
| 1630 | − b10_a6[13] = 0xA5; | |
| 1631 | − iffreq = MAKE_IFFREQ_CONFIG(4.2); | |
| 1632 | − b10_d7 = 0x02; | |
| 2186 | + /* <Timing Recovery setting> */ | |
| 2187 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2188 | + 0x9F, nominalRate7bw[priv->xtal], 5); | |
| 2189 | + | |
| 2190 | + /* Set SLV-T Bank : 0x27 */ | |
| 2191 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); | |
| 2192 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, | |
| 2193 | + 0x7a, 0x00, 0x0f); | |
| 2194 | + | |
| 2195 | + /* Set SLV-T Bank : 0x10 */ | |
| 2196 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | |
| 2197 | + | |
| 2198 | + /* Group delay equaliser settings for | |
| 2199 | + * ASCOT2D, ASCOT2E and ASCOT3 tuners | |
| 2200 | + */ | |
| 2201 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2202 | + 0xA6, itbCoef7bw[priv->xtal], 14); | |
| 2203 | + /* <IF freq setting> */ | |
| 2204 | + iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.20); | |
| 2205 | + data[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 2206 | + data[1] = (u8)((iffreq >> 8) & 0xff); | |
| 2207 | + data[2] = (u8)(iffreq & 0xff); | |
| 2208 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | |
| 2209 | + /* System bandwidth setting */ | |
| 2210 | + cxd2841er_set_reg_bits( | |
| 2211 | + priv, I2C_SLVT, 0xD7, 0x02, 0x07); | |
| 1633 | 2212 | break; |
| 1634 | 2213 | case 6000000: |
| 1635 | − /* bank 0x20, reg 0x9f */ | |
| 1636 | − b20_9f[0] = 0x17; | |
| 1637 | − b20_9f[1] = 0xEA; | |
| 1638 | − b20_9f[2] = 0xAA; | |
| 1639 | − b20_9f[3] = 0xAA; | |
| 1640 | − b20_9f[4] = 0xAA; | |
| 1641 | − /* bank 0x10, reg 0xa6 */ | |
| 1642 | − b10_a6[0] = 0x27; | |
| 1643 | − b10_a6[1] = 0xA7; | |
| 1644 | − b10_a6[2] = 0x28; | |
| 1645 | − b10_a6[3] = 0xB3; | |
| 1646 | − b10_a6[4] = 0x02; | |
| 1647 | − b10_a6[5] = 0xF0; | |
| 1648 | − b10_a6[6] = 0x01; | |
| 1649 | − b10_a6[7] = 0xE8; | |
| 1650 | − b10_a6[8] = 0x00; | |
| 1651 | − b10_a6[9] = 0xCF; | |
| 1652 | − b10_a6[10] = 0x00; | |
| 1653 | − b10_a6[11] = 0xE6; | |
| 1654 | − b10_a6[12] = 0x23; | |
| 1655 | − b10_a6[13] = 0xA4; | |
| 1656 | − iffreq = MAKE_IFFREQ_CONFIG(3.6); | |
| 1657 | − b10_d7 = 0x04; | |
| 2214 | + /* <Timing Recovery setting> */ | |
| 2215 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2216 | + 0x9F, nominalRate6bw[priv->xtal], 5); | |
| 2217 | + | |
| 2218 | + /* Set SLV-T Bank : 0x27 */ | |
| 2219 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); | |
| 2220 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, | |
| 2221 | + 0x7a, 0x00, 0x0f); | |
| 2222 | + | |
| 2223 | + /* Set SLV-T Bank : 0x10 */ | |
| 2224 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | |
| 2225 | + | |
| 2226 | + /* Group delay equaliser settings for | |
| 2227 | + * ASCOT2D, ASCOT2E and ASCOT3 tuners | |
| 2228 | + */ | |
| 2229 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2230 | + 0xA6, itbCoef6bw[priv->xtal], 14); | |
| 2231 | + /* <IF freq setting> */ | |
| 2232 | + iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.60); | |
| 2233 | + data[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 2234 | + data[1] = (u8)((iffreq >> 8) & 0xff); | |
| 2235 | + data[2] = (u8)(iffreq & 0xff); | |
| 2236 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | |
| 2237 | + /* System bandwidth setting */ | |
| 2238 | + cxd2841er_set_reg_bits( | |
| 2239 | + priv, I2C_SLVT, 0xD7, 0x04, 0x07); | |
| 1658 | 2240 | break; |
| 1659 | 2241 | case 5000000: |
| 1660 | − /* bank 0x20, reg 0x9f */ | |
| 1661 | − b20_9f[0] = 0x1C; | |
| 1662 | − b20_9f[1] = 0xB3; | |
| 1663 | − b20_9f[2] = 0x33; | |
| 1664 | − b20_9f[3] = 0x33; | |
| 1665 | − b20_9f[4] = 0x33; | |
| 1666 | − /* bank 0x10, reg 0xa6 */ | |
| 1667 | − b10_a6[0] = 0x27; | |
| 1668 | − b10_a6[1] = 0xA7; | |
| 1669 | − b10_a6[2] = 0x28; | |
| 1670 | − b10_a6[3] = 0xB3; | |
| 1671 | − b10_a6[4] = 0x02; | |
| 1672 | − b10_a6[5] = 0xF0; | |
| 1673 | − b10_a6[6] = 0x01; | |
| 1674 | − b10_a6[7] = 0xE8; | |
| 1675 | − b10_a6[8] = 0x00; | |
| 1676 | − b10_a6[9] = 0xCF; | |
| 1677 | − b10_a6[10] = 0x00; | |
| 1678 | − b10_a6[11] = 0xE6; | |
| 1679 | − b10_a6[12] = 0x23; | |
| 1680 | − b10_a6[13] = 0xA4; | |
| 1681 | − iffreq = MAKE_IFFREQ_CONFIG(3.6); | |
| 1682 | − b10_d7 = 0x06; | |
| 2242 | + /* <Timing Recovery setting> */ | |
| 2243 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2244 | + 0x9F, nominalRate5bw[priv->xtal], 5); | |
| 2245 | + | |
| 2246 | + /* Set SLV-T Bank : 0x27 */ | |
| 2247 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); | |
| 2248 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, | |
| 2249 | + 0x7a, 0x00, 0x0f); | |
| 2250 | + | |
| 2251 | + /* Set SLV-T Bank : 0x10 */ | |
| 2252 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | |
| 2253 | + | |
| 2254 | + /* Group delay equaliser settings for | |
| 2255 | + * ASCOT2D, ASCOT2E and ASCOT3 tuners | |
| 2256 | + */ | |
| 2257 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2258 | + 0xA6, itbCoef5bw[priv->xtal], 14); | |
| 2259 | + /* <IF freq setting> */ | |
| 2260 | + iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.60); | |
| 2261 | + data[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 2262 | + data[1] = (u8)((iffreq >> 8) & 0xff); | |
| 2263 | + data[2] = (u8)(iffreq & 0xff); | |
| 2264 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | |
| 2265 | + /* System bandwidth setting */ | |
| 2266 | + cxd2841er_set_reg_bits( | |
| 2267 | + priv, I2C_SLVT, 0xD7, 0x06, 0x07); | |
| 1683 | 2268 | break; |
| 1684 | 2269 | case 1712000: |
| 1685 | − /* bank 0x20, reg 0x9f */ | |
| 1686 | − b20_9f[0] = 0x58; | |
| 1687 | − b20_9f[1] = 0xE2; | |
| 1688 | − b20_9f[2] = 0xAF; | |
| 1689 | − b20_9f[3] = 0xE0; | |
| 1690 | − b20_9f[4] = 0xBC; | |
| 1691 | − /* bank 0x10, reg 0xa6 */ | |
| 1692 | − b10_a6[0] = 0x25; | |
| 1693 | − b10_a6[1] = 0xA0; | |
| 1694 | − b10_a6[2] = 0x36; | |
| 1695 | − b10_a6[3] = 0x8D; | |
| 1696 | − b10_a6[4] = 0x2E; | |
| 1697 | − b10_a6[5] = 0x94; | |
| 1698 | − b10_a6[6] = 0x28; | |
| 1699 | − b10_a6[7] = 0x9B; | |
| 1700 | − b10_a6[8] = 0x32; | |
| 1701 | − b10_a6[9] = 0x90; | |
| 1702 | − b10_a6[10] = 0x2C; | |
| 1703 | − b10_a6[11] = 0x9D; | |
| 1704 | − b10_a6[12] = 0x29; | |
| 1705 | − b10_a6[13] = 0x99; | |
| 1706 | − iffreq = MAKE_IFFREQ_CONFIG(3.5); | |
| 1707 | − b10_d7 = 0x03; | |
| 2270 | + /* <Timing Recovery setting> */ | |
| 2271 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2272 | + 0x9F, nominalRate17bw[priv->xtal], 5); | |
| 2273 | + | |
| 2274 | + /* Set SLV-T Bank : 0x27 */ | |
| 2275 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); | |
| 2276 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, | |
| 2277 | + 0x7a, 0x03, 0x0f); | |
| 2278 | + | |
| 2279 | + /* Set SLV-T Bank : 0x10 */ | |
| 2280 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | |
| 2281 | + | |
| 2282 | + /* Group delay equaliser settings for | |
| 2283 | + * ASCOT2D, ASCOT2E and ASCOT3 tuners | |
| 2284 | + */ | |
| 2285 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2286 | + 0xA6, itbCoef17bw[priv->xtal], 14); | |
| 2287 | + /* <IF freq setting> */ | |
| 2288 | + iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.50); | |
| 2289 | + data[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 2290 | + data[1] = (u8)((iffreq >> 8) & 0xff); | |
| 2291 | + data[2] = (u8)(iffreq & 0xff); | |
| 2292 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | |
| 2293 | + /* System bandwidth setting */ | |
| 2294 | + cxd2841er_set_reg_bits( | |
| 2295 | + priv, I2C_SLVT, 0xD7, 0x03, 0x07); | |
| 1708 | 2296 | break; |
| 1709 | 2297 | default: |
| 1710 | 2298 | return -EINVAL; |
| 1711 | 2299 | } |
| 1712 | − /* Set SLV-T Bank : 0x20 */ | |
| 1713 | − cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x20); | |
| 1714 | − cxd2841er_write_regs(priv, I2C_SLVT, 0x9f, b20_9f, sizeof(b20_9f)); | |
| 1715 | − /* Set SLV-T Bank : 0x27 */ | |
| 1716 | − cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); | |
| 1717 | − cxd2841er_set_reg_bits( | |
| 1718 | − priv, I2C_SLVT, 0x7a, | |
| 1719 | − (bandwidth == 1712000 ? 0x03 : 0x00), 0x0f); | |
| 1720 | − /* Set SLV-T Bank : 0x10 */ | |
| 1721 | − cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | |
| 1722 | − /* Group delay equaliser sett. for ASCOT2E */ | |
| 1723 | − cxd2841er_write_regs(priv, I2C_SLVT, 0xa6, b10_a6, sizeof(b10_a6)); | |
| 1724 | − /* <IF freq setting> */ | |
| 1725 | − b10_b6[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 1726 | − b10_b6[1] = (u8)((iffreq >> 8) & 0xff); | |
| 1727 | − b10_b6[2] = (u8)(iffreq & 0xff); | |
| 1728 | − cxd2841er_write_regs(priv, I2C_SLVT, 0xb6, b10_b6, sizeof(b10_b6)); | |
| 1729 | − /* System bandwidth setting */ | |
| 1730 | − cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, b10_d7, 0x07); | |
| 1731 | 2300 | return 0; |
| 1732 | 2301 | } |
| 1733 | 2302 | |
| 1734 | 2303 | static int cxd2841er_sleep_tc_to_active_t_band( |
| 1735 | 2304 | struct cxd2841er_priv *priv, u32 bandwidth) |
| 1736 | 2305 | { |
| 1737 | − u8 b13_9c[2] = { 0x01, 0x14 }; | |
| 1738 | − u8 bw8mhz_b10_9f[] = { 0x11, 0xF0, 0x00, 0x00, 0x00 }; | |
| 1739 | − u8 bw8mhz_b10_a6[] = { 0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, | |
| 1740 | − 0x28, 0xBA, 0x23, 0xA9, 0x1F, 0xA8, 0x2C, 0xC8 }; | |
| 1741 | − u8 bw8mhz_b10_d9[] = { 0x01, 0xE0 }; | |
| 1742 | − u8 bw8mhz_b17_38[] = { 0x01, 0x02 }; | |
| 1743 | − u8 bw7mhz_b10_9f[] = { 0x14, 0x80, 0x00, 0x00, 0x00 }; | |
| 1744 | − u8 bw7mhz_b10_a6[] = { 0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, | |
| 1745 | − 0x23, 0xA6, 0x29, 0xB0, 0x26, 0xA9, 0x21, 0xA5 }; | |
| 1746 | − u8 bw7mhz_b10_d9[] = { 0x12, 0xF8 }; | |
| 1747 | − u8 bw7mhz_b17_38[] = { 0x00, 0x03 }; | |
| 1748 | − u8 bw6mhz_b10_9f[] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA }; | |
| 1749 | − u8 bw6mhz_b10_a6[] = { 0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, | |
| 1750 | − 0x01, 0xE8, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4 }; | |
| 1751 | − u8 bw6mhz_b10_d9[] = { 0x1F, 0xDC }; | |
| 1752 | − u8 bw6mhz_b17_38[] = { 0x00, 0x03 }; | |
| 1753 | − u8 bw5mhz_b10_9f[] = { 0x1C, 0xB3, 0x33, 0x33, 0x33 }; | |
| 1754 | − u8 bw5mhz_b10_a6[] = { 0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, | |
| 1755 | − 0x01, 0xE8, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4 }; | |
| 1756 | − u8 bw5mhz_b10_d9[] = { 0x26, 0x3C }; | |
| 1757 | − u8 bw5mhz_b17_38[] = { 0x00, 0x03 }; | |
| 1758 | − u8 b10_b6[3]; | |
| 1759 | − u8 d7val; | |
| 2306 | + u8 data[MAX_WRITE_REGSIZE]; | |
| 1760 | 2307 | u32 iffreq; |
| 1761 | − u8 *b10_9f; | |
| 1762 | − u8 *b10_a6; | |
| 1763 | − u8 *b10_d9; | |
| 1764 | − u8 *b17_38; | |
| 2308 | + u8 nominalRate8bw[3][5] = { | |
| 2309 | + /* TRCG Nominal Rate [37:0] */ | |
| 2310 | + {0x11, 0xF0, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | |
| 2311 | + {0x15, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | |
| 2312 | + {0x11, 0xF0, 0x00, 0x00, 0x00} /* 41MHz XTal */ | |
| 2313 | + }; | |
| 2314 | + u8 nominalRate7bw[3][5] = { | |
| 2315 | + /* TRCG Nominal Rate [37:0] */ | |
| 2316 | + {0x14, 0x80, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | |
| 2317 | + {0x18, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | |
| 2318 | + {0x14, 0x80, 0x00, 0x00, 0x00} /* 41MHz XTal */ | |
| 2319 | + }; | |
| 2320 | + u8 nominalRate6bw[3][5] = { | |
| 2321 | + /* TRCG Nominal Rate [37:0] */ | |
| 2322 | + {0x17, 0xEA, 0xAA, 0xAA, 0xAA}, /* 20.5MHz XTal */ | |
| 2323 | + {0x1C, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | |
| 2324 | + {0x17, 0xEA, 0xAA, 0xAA, 0xAA} /* 41MHz XTal */ | |
| 2325 | + }; | |
| 2326 | + u8 nominalRate5bw[3][5] = { | |
| 2327 | + /* TRCG Nominal Rate [37:0] */ | |
| 2328 | + {0x1C, 0xB3, 0x33, 0x33, 0x33}, /* 20.5MHz XTal */ | |
| 2329 | + {0x21, 0x99, 0x99, 0x99, 0x99}, /* 24MHz XTal */ | |
| 2330 | + {0x1C, 0xB3, 0x33, 0x33, 0x33} /* 41MHz XTal */ | |
| 2331 | + }; | |
| 1765 | 2332 | |
| 1766 | − dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 2333 | + u8 itbCoef8bw[3][14] = { | |
| 2334 | + {0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, 0x23, 0xA9, | |
| 2335 | + 0x1F, 0xA8, 0x2C, 0xC8}, /* 20.5MHz XTal */ | |
| 2336 | + {0x2F, 0xBA, 0x28, 0x9B, 0x28, 0x9D, 0x28, 0xA1, 0x29, 0xA5, | |
| 2337 | + 0x2A, 0xAC, 0x29, 0xB5}, /* 24MHz XTal */ | |
| 2338 | + {0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, 0x23, 0xA9, | |
| 2339 | + 0x1F, 0xA8, 0x2C, 0xC8} /* 41MHz XTal */ | |
| 2340 | + }; | |
| 2341 | + u8 itbCoef7bw[3][14] = { | |
| 2342 | + {0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, 0x29, 0xB0, | |
| 2343 | + 0x26, 0xA9, 0x21, 0xA5}, /* 20.5MHz XTal */ | |
| 2344 | + {0x30, 0xB1, 0x29, 0x9A, 0x28, 0x9C, 0x28, 0xA0, 0x29, 0xA2, | |
| 2345 | + 0x2B, 0xA6, 0x2B, 0xAD}, /* 24MHz XTal */ | |
| 2346 | + {0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, 0x29, 0xB0, | |
| 2347 | + 0x26, 0xA9, 0x21, 0xA5} /* 41MHz XTal */ | |
| 2348 | + }; | |
| 2349 | + u8 itbCoef6bw[3][14] = { | |
| 2350 | + {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, | |
| 2351 | + 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ | |
| 2352 | + {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, 0x29, 0xA4, | |
| 2353 | + 0x29, 0xA2, 0x29, 0xA8}, /* 24MHz XTal */ | |
| 2354 | + {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, | |
| 2355 | + 0x00, 0xE6, 0x23, 0xA4} /* 41MHz XTal */ | |
| 2356 | + }; | |
| 2357 | + u8 itbCoef5bw[3][14] = { | |
| 2358 | + {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, | |
| 2359 | + 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ | |
| 2360 | + {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, 0x29, 0xA4, | |
| 2361 | + 0x29, 0xA2, 0x29, 0xA8}, /* 24MHz XTal */ | |
| 2362 | + {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, | |
| 2363 | + 0x00, 0xE6, 0x23, 0xA4} /* 41MHz XTal */ | |
| 2364 | + }; | |
| 2365 | + | |
| 2366 | + /* Set SLV-T Bank : 0x13 */ | |
| 1767 | 2367 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x13); |
| 1768 | 2368 | /* Echo performance optimization setting */ |
| 1769 | − cxd2841er_write_regs(priv, I2C_SLVT, 0x9c, b13_9c, sizeof(b13_9c)); | |
| 2369 | + data[0] = 0x01; | |
| 2370 | + data[1] = 0x14; | |
| 2371 | + cxd2841er_write_regs(priv, I2C_SLVT, 0x9C, data, 2); | |
| 2372 | + | |
| 2373 | + /* Set SLV-T Bank : 0x10 */ | |
| 1770 | 2374 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
| 1771 | 2375 | |
| 1772 | 2376 | switch (bandwidth) { |
| 1773 | 2377 | case 8000000: |
| 1774 | − b10_9f = bw8mhz_b10_9f; | |
| 1775 | − b10_a6 = bw8mhz_b10_a6; | |
| 1776 | − b10_d9 = bw8mhz_b10_d9; | |
| 1777 | − b17_38 = bw8mhz_b17_38; | |
| 1778 | − d7val = 0; | |
| 1779 | − iffreq = MAKE_IFFREQ_CONFIG(4.80); | |
| 2378 | + /* <Timing Recovery setting> */ | |
| 2379 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2380 | + 0x9F, nominalRate8bw[priv->xtal], 5); | |
| 2381 | + /* Group delay equaliser settings for | |
| 2382 | + * ASCOT2D, ASCOT2E and ASCOT3 tuners | |
| 2383 | + */ | |
| 2384 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2385 | + 0xA6, itbCoef8bw[priv->xtal], 14); | |
| 2386 | + /* <IF freq setting> */ | |
| 2387 | + iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.80); | |
| 2388 | + data[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 2389 | + data[1] = (u8)((iffreq >> 8) & 0xff); | |
| 2390 | + data[2] = (u8)(iffreq & 0xff); | |
| 2391 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | |
| 2392 | + /* System bandwidth setting */ | |
| 2393 | + cxd2841er_set_reg_bits( | |
| 2394 | + priv, I2C_SLVT, 0xD7, 0x00, 0x07); | |
| 2395 | + | |
| 2396 | + /* Demod core latency setting */ | |
| 2397 | + if (priv->xtal == SONY_XTAL_24000) { | |
| 2398 | + data[0] = 0x15; | |
| 2399 | + data[1] = 0x28; | |
| 2400 | + } else { | |
| 2401 | + data[0] = 0x01; | |
| 2402 | + data[1] = 0xE0; | |
| 2403 | + } | |
| 2404 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | |
| 2405 | + | |
| 2406 | + /* Notch filter setting */ | |
| 2407 | + data[0] = 0x01; | |
| 2408 | + data[1] = 0x02; | |
| 2409 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17); | |
| 2410 | + cxd2841er_write_regs(priv, I2C_SLVT, 0x38, data, 2); | |
| 1780 | 2411 | break; |
| 1781 | 2412 | case 7000000: |
| 1782 | − b10_9f = bw7mhz_b10_9f; | |
| 1783 | − b10_a6 = bw7mhz_b10_a6; | |
| 1784 | − b10_d9 = bw7mhz_b10_d9; | |
| 1785 | − b17_38 = bw7mhz_b17_38; | |
| 1786 | − d7val = 2; | |
| 1787 | − iffreq = MAKE_IFFREQ_CONFIG(4.20); | |
| 2413 | + /* <Timing Recovery setting> */ | |
| 2414 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2415 | + 0x9F, nominalRate7bw[priv->xtal], 5); | |
| 2416 | + /* Group delay equaliser settings for | |
| 2417 | + * ASCOT2D, ASCOT2E and ASCOT3 tuners | |
| 2418 | + */ | |
| 2419 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2420 | + 0xA6, itbCoef7bw[priv->xtal], 14); | |
| 2421 | + /* <IF freq setting> */ | |
| 2422 | + iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.20); | |
| 2423 | + data[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 2424 | + data[1] = (u8)((iffreq >> 8) & 0xff); | |
| 2425 | + data[2] = (u8)(iffreq & 0xff); | |
| 2426 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | |
| 2427 | + /* System bandwidth setting */ | |
| 2428 | + cxd2841er_set_reg_bits( | |
| 2429 | + priv, I2C_SLVT, 0xD7, 0x02, 0x07); | |
| 2430 | + | |
| 2431 | + /* Demod core latency setting */ | |
| 2432 | + if (priv->xtal == SONY_XTAL_24000) { | |
| 2433 | + data[0] = 0x1F; | |
| 2434 | + data[1] = 0xF8; | |
| 2435 | + } else { | |
| 2436 | + data[0] = 0x12; | |
| 2437 | + data[1] = 0xF8; | |
| 2438 | + } | |
| 2439 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | |
| 2440 | + | |
| 2441 | + /* Notch filter setting */ | |
| 2442 | + data[0] = 0x00; | |
| 2443 | + data[1] = 0x03; | |
| 2444 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17); | |
| 2445 | + cxd2841er_write_regs(priv, I2C_SLVT, 0x38, data, 2); | |
| 1788 | 2446 | break; |
| 1789 | 2447 | case 6000000: |
| 1790 | − b10_9f = bw6mhz_b10_9f; | |
| 1791 | − b10_a6 = bw6mhz_b10_a6; | |
| 1792 | − b10_d9 = bw6mhz_b10_d9; | |
| 1793 | − b17_38 = bw6mhz_b17_38; | |
| 1794 | − d7val = 4; | |
| 1795 | − iffreq = MAKE_IFFREQ_CONFIG(3.60); | |
| 2448 | + /* <Timing Recovery setting> */ | |
| 2449 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2450 | + 0x9F, nominalRate6bw[priv->xtal], 5); | |
| 2451 | + /* Group delay equaliser settings for | |
| 2452 | + * ASCOT2D, ASCOT2E and ASCOT3 tuners | |
| 2453 | + */ | |
| 2454 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2455 | + 0xA6, itbCoef6bw[priv->xtal], 14); | |
| 2456 | + /* <IF freq setting> */ | |
| 2457 | + iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.60); | |
| 2458 | + data[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 2459 | + data[1] = (u8)((iffreq >> 8) & 0xff); | |
| 2460 | + data[2] = (u8)(iffreq & 0xff); | |
| 2461 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | |
| 2462 | + /* System bandwidth setting */ | |
| 2463 | + cxd2841er_set_reg_bits( | |
| 2464 | + priv, I2C_SLVT, 0xD7, 0x04, 0x07); | |
| 2465 | + | |
| 2466 | + /* Demod core latency setting */ | |
| 2467 | + if (priv->xtal == SONY_XTAL_24000) { | |
| 2468 | + data[0] = 0x25; | |
| 2469 | + data[1] = 0x4C; | |
| 2470 | + } else { | |
| 2471 | + data[0] = 0x1F; | |
| 2472 | + data[1] = 0xDC; | |
| 2473 | + } | |
| 2474 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | |
| 2475 | + | |
| 2476 | + /* Notch filter setting */ | |
| 2477 | + data[0] = 0x00; | |
| 2478 | + data[1] = 0x03; | |
| 2479 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17); | |
| 2480 | + cxd2841er_write_regs(priv, I2C_SLVT, 0x38, data, 2); | |
| 1796 | 2481 | break; |
| 1797 | 2482 | case 5000000: |
| 1798 | − b10_9f = bw5mhz_b10_9f; | |
| 1799 | − b10_a6 = bw5mhz_b10_a6; | |
| 1800 | − b10_d9 = bw5mhz_b10_d9; | |
| 1801 | − b17_38 = bw5mhz_b17_38; | |
| 1802 | − d7val = 6; | |
| 1803 | − iffreq = MAKE_IFFREQ_CONFIG(3.60); | |
| 2483 | + /* <Timing Recovery setting> */ | |
| 2484 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2485 | + 0x9F, nominalRate5bw[priv->xtal], 5); | |
| 2486 | + /* Group delay equaliser settings for | |
| 2487 | + * ASCOT2D, ASCOT2E and ASCOT3 tuners | |
| 2488 | + */ | |
| 2489 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2490 | + 0xA6, itbCoef5bw[priv->xtal], 14); | |
| 2491 | + /* <IF freq setting> */ | |
| 2492 | + iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.60); | |
| 2493 | + data[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 2494 | + data[1] = (u8)((iffreq >> 8) & 0xff); | |
| 2495 | + data[2] = (u8)(iffreq & 0xff); | |
| 2496 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | |
| 2497 | + /* System bandwidth setting */ | |
| 2498 | + cxd2841er_set_reg_bits( | |
| 2499 | + priv, I2C_SLVT, 0xD7, 0x06, 0x07); | |
| 2500 | + | |
| 2501 | + /* Demod core latency setting */ | |
| 2502 | + if (priv->xtal == SONY_XTAL_24000) { | |
| 2503 | + data[0] = 0x2C; | |
| 2504 | + data[1] = 0xC2; | |
| 2505 | + } else { | |
| 2506 | + data[0] = 0x26; | |
| 2507 | + data[1] = 0x3C; | |
| 2508 | + } | |
| 2509 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | |
| 2510 | + | |
| 2511 | + /* Notch filter setting */ | |
| 2512 | + data[0] = 0x00; | |
| 2513 | + data[1] = 0x03; | |
| 2514 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17); | |
| 2515 | + cxd2841er_write_regs(priv, I2C_SLVT, 0x38, data, 2); | |
| 2516 | + break; | |
| 2517 | + } | |
| 2518 | + | |
| 2519 | + return 0; | |
| 2520 | +} | |
| 2521 | + | |
| 2522 | +static int cxd2841er_sleep_tc_to_active_i_band( | |
| 2523 | + struct cxd2841er_priv *priv, u32 bandwidth) | |
| 2524 | +{ | |
| 2525 | + u32 iffreq; | |
| 2526 | + u8 data[3]; | |
| 2527 | + | |
| 2528 | + /* TRCG Nominal Rate */ | |
| 2529 | + u8 nominalRate8bw[3][5] = { | |
| 2530 | + {0x00, 0x00, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | |
| 2531 | + {0x11, 0xB8, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | |
| 2532 | + {0x00, 0x00, 0x00, 0x00, 0x00} /* 41MHz XTal */ | |
| 2533 | + }; | |
| 2534 | + | |
| 2535 | + u8 nominalRate7bw[3][5] = { | |
| 2536 | + {0x00, 0x00, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | |
| 2537 | + {0x14, 0x40, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | |
| 2538 | + {0x00, 0x00, 0x00, 0x00, 0x00} /* 41MHz XTal */ | |
| 2539 | + }; | |
| 2540 | + | |
| 2541 | + u8 nominalRate6bw[3][5] = { | |
| 2542 | + {0x14, 0x2E, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | |
| 2543 | + {0x17, 0xA0, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | |
| 2544 | + {0x14, 0x2E, 0x00, 0x00, 0x00} /* 41MHz XTal */ | |
| 2545 | + }; | |
| 2546 | + | |
| 2547 | + u8 itbCoef8bw[3][14] = { | |
| 2548 | + {0x00}, /* 20.5MHz XTal */ | |
| 2549 | + {0x2F, 0xBA, 0x28, 0x9B, 0x28, 0x9D, 0x28, 0xA1, 0x29, | |
| 2550 | + 0xA5, 0x2A, 0xAC, 0x29, 0xB5}, /* 24MHz Xtal */ | |
| 2551 | + {0x0}, /* 41MHz XTal */ | |
| 2552 | + }; | |
| 2553 | + | |
| 2554 | + u8 itbCoef7bw[3][14] = { | |
| 2555 | + {0x00}, /* 20.5MHz XTal */ | |
| 2556 | + {0x30, 0xB1, 0x29, 0x9A, 0x28, 0x9C, 0x28, 0xA0, 0x29, | |
| 2557 | + 0xA2, 0x2B, 0xA6, 0x2B, 0xAD}, /* 24MHz Xtal */ | |
| 2558 | + {0x00}, /* 41MHz XTal */ | |
| 2559 | + }; | |
| 2560 | + | |
| 2561 | + u8 itbCoef6bw[3][14] = { | |
| 2562 | + {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, | |
| 2563 | + 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ | |
| 2564 | + {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, 0x29, | |
| 2565 | + 0xA4, 0x29, 0xA2, 0x29, 0xA8}, /* 24MHz Xtal */ | |
| 2566 | + {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, | |
| 2567 | + 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 41MHz XTal */ | |
| 2568 | + }; | |
| 2569 | + | |
| 2570 | + dev_dbg(&priv->i2c->dev, "%s() bandwidth=%u\n", __func__, bandwidth); | |
| 2571 | + /* Set SLV-T Bank : 0x10 */ | |
| 2572 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | |
| 2573 | + | |
| 2574 | + /* 20.5/41MHz Xtal support is not available | |
| 2575 | + * on ISDB-T 7MHzBW and 8MHzBW | |
| 2576 | + */ | |
| 2577 | + if (priv->xtal != SONY_XTAL_24000 && bandwidth > 6000000) { | |
| 2578 | + dev_err(&priv->i2c->dev, | |
| 2579 | + "%s(): bandwidth %d supported only for 24MHz xtal\n", | |
| 2580 | + __func__, bandwidth); | |
| 2581 | + return -EINVAL; | |
| 2582 | + } | |
| 2583 | + | |
| 2584 | + switch (bandwidth) { | |
| 2585 | + case 8000000: | |
| 2586 | + /* TRCG Nominal Rate */ | |
| 2587 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2588 | + 0x9F, nominalRate8bw[priv->xtal], 5); | |
| 2589 | + /* Group delay equaliser settings for ASCOT tuners optimized */ | |
| 2590 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2591 | + 0xA6, itbCoef8bw[priv->xtal], 14); | |
| 2592 | + | |
| 2593 | + /* IF freq setting */ | |
| 2594 | + iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.75); | |
| 2595 | + data[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 2596 | + data[1] = (u8)((iffreq >> 8) & 0xff); | |
| 2597 | + data[2] = (u8)(iffreq & 0xff); | |
| 2598 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | |
| 2599 | + | |
| 2600 | + /* System bandwidth setting */ | |
| 2601 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, 0x0, 0x7); | |
| 2602 | + | |
| 2603 | + /* Demod core latency setting */ | |
| 2604 | + data[0] = 0x13; | |
| 2605 | + data[1] = 0xFC; | |
| 2606 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | |
| 2607 | + | |
| 2608 | + /* Acquisition optimization setting */ | |
| 2609 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x12); | |
| 2610 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x71, 0x03, 0x07); | |
| 2611 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x15); | |
| 2612 | + cxd2841er_write_reg(priv, I2C_SLVT, 0xBE, 0x03); | |
| 2613 | + break; | |
| 2614 | + case 7000000: | |
| 2615 | + /* TRCG Nominal Rate */ | |
| 2616 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2617 | + 0x9F, nominalRate7bw[priv->xtal], 5); | |
| 2618 | + /* Group delay equaliser settings for ASCOT tuners optimized */ | |
| 2619 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2620 | + 0xA6, itbCoef7bw[priv->xtal], 14); | |
| 2621 | + | |
| 2622 | + /* IF freq setting */ | |
| 2623 | + iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.15); | |
| 2624 | + data[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 2625 | + data[1] = (u8)((iffreq >> 8) & 0xff); | |
| 2626 | + data[2] = (u8)(iffreq & 0xff); | |
| 2627 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | |
| 2628 | + | |
| 2629 | + /* System bandwidth setting */ | |
| 2630 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, 0x02, 0x7); | |
| 2631 | + | |
| 2632 | + /* Demod core latency setting */ | |
| 2633 | + data[0] = 0x1A; | |
| 2634 | + data[1] = 0xFA; | |
| 2635 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | |
| 2636 | + | |
| 2637 | + /* Acquisition optimization setting */ | |
| 2638 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x12); | |
| 2639 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x71, 0x03, 0x07); | |
| 2640 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x15); | |
| 2641 | + cxd2841er_write_reg(priv, I2C_SLVT, 0xBE, 0x02); | |
| 2642 | + break; | |
| 2643 | + case 6000000: | |
| 2644 | + /* TRCG Nominal Rate */ | |
| 2645 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2646 | + 0x9F, nominalRate6bw[priv->xtal], 5); | |
| 2647 | + /* Group delay equaliser settings for ASCOT tuners optimized */ | |
| 2648 | + cxd2841er_write_regs(priv, I2C_SLVT, | |
| 2649 | + 0xA6, itbCoef6bw[priv->xtal], 14); | |
| 2650 | + | |
| 2651 | + /* IF freq setting */ | |
| 2652 | + iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.55); | |
| 2653 | + data[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 2654 | + data[1] = (u8)((iffreq >> 8) & 0xff); | |
| 2655 | + data[2] = (u8)(iffreq & 0xff); | |
| 2656 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | |
| 2657 | + | |
| 2658 | + /* System bandwidth setting */ | |
| 2659 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, 0x04, 0x7); | |
| 2660 | + | |
| 2661 | + /* Demod core latency setting */ | |
| 2662 | + if (priv->xtal == SONY_XTAL_24000) { | |
| 2663 | + data[0] = 0x1F; | |
| 2664 | + data[1] = 0x79; | |
| 2665 | + } else { | |
| 2666 | + data[0] = 0x1A; | |
| 2667 | + data[1] = 0xE2; | |
| 2668 | + } | |
| 2669 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | |
| 2670 | + | |
| 2671 | + /* Acquisition optimization setting */ | |
| 2672 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x12); | |
| 2673 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x71, 0x07, 0x07); | |
| 2674 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x15); | |
| 2675 | + cxd2841er_write_reg(priv, I2C_SLVT, 0xBE, 0x02); | |
| 1804 | 2676 | break; |
| 1805 | 2677 | default: |
| 1806 | 2678 | dev_dbg(&priv->i2c->dev, "%s(): invalid bandwidth %d\n", |
| 1807 | − __func__, bandwidth); | |
| 2679 | + __func__, bandwidth); | |
| 1808 | 2680 | return -EINVAL; |
| 1809 | 2681 | } |
| 1810 | − /* <IF freq setting> */ | |
| 1811 | − b10_b6[0] = (u8) ((iffreq >> 16) & 0xff); | |
| 1812 | − b10_b6[1] = (u8)((iffreq >> 8) & 0xff); | |
| 1813 | − b10_b6[2] = (u8)(iffreq & 0xff); | |
| 1814 | − cxd2841er_write_regs( | |
| 1815 | − priv, I2C_SLVT, 0x9f, b10_9f, sizeof(bw8mhz_b10_9f)); | |
| 1816 | − cxd2841er_write_regs( | |
| 1817 | − priv, I2C_SLVT, 0xa6, b10_a6, sizeof(bw8mhz_b10_a6)); | |
| 1818 | − cxd2841er_write_regs(priv, I2C_SLVT, 0xb6, b10_b6, sizeof(b10_b6)); | |
| 1819 | − cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, d7val, 0x7); | |
| 1820 | − cxd2841er_write_regs( | |
| 1821 | − priv, I2C_SLVT, 0xd9, b10_d9, sizeof(bw8mhz_b10_d9)); | |
| 1822 | − cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17); | |
| 1823 | − cxd2841er_write_regs( | |
| 1824 | − priv, I2C_SLVT, 0x38, b17_38, sizeof(bw8mhz_b17_38)); | |
| 1825 | 2682 | return 0; |
| 1826 | 2683 | } |
| 1827 | 2684 | |
| @@ -1837,7 +2694,7 @@ static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv, · 9 unmodified lines | ||
| 1837 | 2694 | u8 b10_b6[3]; |
| 1838 | 2695 | u32 iffreq; |
| 1839 | 2696 | |
| 1840 | − dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 2697 | + dev_dbg(&priv->i2c->dev, "%s() bw=%d\n", __func__, bandwidth); | |
| 1841 | 2698 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
| 1842 | 2699 | switch (bandwidth) { |
| 1843 | 2700 | case 8000000: |
| @@ -1854,7 +2711,7 @@ static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv, · 10 unmodified lines | ||
| 1854 | 2711 | iffreq = MAKE_IFFREQ_CONFIG(3.7); |
| 1855 | 2712 | break; |
| 1856 | 2713 | default: |
| 1857 | − dev_dbg(&priv->i2c->dev, "%s(): unsupported bandwidth %d\n", | |
| 2714 | + dev_err(&priv->i2c->dev, "%s(): unsupported bandwidth %d\n", | |
| 1858 | 2715 | __func__, bandwidth); |
| 1859 | 2716 | return -EINVAL; |
| 1860 | 2717 | } |
| @@ -1902,6 +2759,7 @@ static int cxd2841er_sleep_tc_to_active_t(struct cxd2841er_priv *priv, · 41 unmodified lines | ||
| 1902 | 2759 | u32 bandwidth) |
| 1903 | 2760 | { |
| 1904 | 2761 | u8 data[2] = { 0x09, 0x54 }; |
| 2762 | + u8 data24m[3] = {0xDC, 0x6C, 0x00}; | |
| 1905 | 2763 | |
| 1906 | 2764 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1907 | 2765 | cxd2841er_set_ts_clock_mode(priv, SYS_DVBT); |
| @@ -1919,7 +2777,11 @@ static int cxd2841er_sleep_tc_to_active_t(struct cxd2841er_priv *priv, · 11 unmodified lines | ||
| 1919 | 2777 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); |
| 1920 | 2778 | /* Enable ADC 1 */ |
| 1921 | 2779 | cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a); |
| 1922 | − /* xtal freq 20.5MHz */ | |
| 2780 | + /* Enable ADC 2 & 3 */ | |
| 2781 | + if (priv->xtal == SONY_XTAL_41000) { | |
| 2782 | + data[0] = 0x0A; | |
| 2783 | + data[1] = 0xD4; | |
| 2784 | + } | |
| 1923 | 2785 | cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2); |
| 1924 | 2786 | /* Enable ADC 4 */ |
| 1925 | 2787 | cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00); |
| @@ -1947,6 +2809,15 @@ static int cxd2841er_sleep_tc_to_active_t(struct cxd2841er_priv *priv, · 21 unmodified lines | ||
| 1947 | 2809 | /* TSIF setting */ |
| 1948 | 2810 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01); |
| 1949 | 2811 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01); |
| 2812 | + | |
| 2813 | + if (priv->xtal == SONY_XTAL_24000) { | |
| 2814 | + /* Set SLV-T Bank : 0x10 */ | |
| 2815 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | |
| 2816 | + cxd2841er_write_reg(priv, I2C_SLVT, 0xBF, 0x60); | |
| 2817 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x18); | |
| 2818 | + cxd2841er_write_regs(priv, I2C_SLVT, 0x24, data24m, 3); | |
| 2819 | + } | |
| 2820 | + | |
| 1950 | 2821 | cxd2841er_sleep_tc_to_active_t_band(priv, bandwidth); |
| 1951 | 2822 | /* Set SLV-T Bank : 0x00 */ |
| 1952 | 2823 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); |
| @@ -1961,7 +2832,7 @@ static int cxd2841er_sleep_tc_to_active_t(struct cxd2841er_priv *priv, · 8 unmodified lines | ||
| 1961 | 2832 | static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, |
| 1962 | 2833 | u32 bandwidth) |
| 1963 | 2834 | { |
| 1964 | − u8 data[2] = { 0x09, 0x54 }; | |
| 2835 | + u8 data[MAX_WRITE_REGSIZE]; | |
| 1965 | 2836 | |
| 1966 | 2837 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1967 | 2838 | cxd2841er_set_ts_clock_mode(priv, SYS_DVBT2); |
| @@ -1974,12 +2845,21 @@ static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, · 6 unmodified lines | ||
| 1974 | 2845 | /* Enable demod clock */ |
| 1975 | 2846 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01); |
| 1976 | 2847 | /* Disable RF level monitor */ |
| 2848 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x59, 0x00); | |
| 1977 | 2849 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00); |
| 1978 | 2850 | /* Enable ADC clock */ |
| 1979 | 2851 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); |
| 1980 | 2852 | /* Enable ADC 1 */ |
| 1981 | 2853 | cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a); |
| 1982 | − /* xtal freq 20.5MHz */ | |
| 2854 | + | |
| 2855 | + if (priv->xtal == SONY_XTAL_41000) { | |
| 2856 | + data[0] = 0x0A; | |
| 2857 | + data[1] = 0xD4; | |
| 2858 | + } else { | |
| 2859 | + data[0] = 0x09; | |
| 2860 | + data[1] = 0x54; | |
| 2861 | + } | |
| 2862 | + | |
| 1983 | 2863 | cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2); |
| 1984 | 2864 | /* Enable ADC 4 */ |
| 1985 | 2865 | cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00); |
| @@ -2002,6 +2882,10 @@ static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, · 16 unmodified lines | ||
| 2002 | 2882 | /* Set SLV-T Bank : 0x2b */ |
| 2003 | 2883 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b); |
| 2004 | 2884 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x76, 0x20, 0x70); |
| 2885 | + /* Set SLV-T Bank : 0x23 */ | |
| 2886 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x23); | |
| 2887 | + /* L1 Control setting */ | |
| 2888 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xE6, 0x00, 0x03); | |
| 2005 | 2889 | /* Set SLV-T Bank : 0x00 */ |
| 2006 | 2890 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); |
| 2007 | 2891 | /* TSIF setting */ |
| @@ -2020,6 +2904,72 @@ static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, · 12 unmodified lines | ||
| 2020 | 2904 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b); |
| 2021 | 2905 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x11, 0x20, 0x3f); |
| 2022 | 2906 | |
| 2907 | + /* 24MHz Xtal setting */ | |
| 2908 | + if (priv->xtal == SONY_XTAL_24000) { | |
| 2909 | + /* Set SLV-T Bank : 0x11 */ | |
| 2910 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x11); | |
| 2911 | + data[0] = 0xEB; | |
| 2912 | + data[1] = 0x03; | |
| 2913 | + data[2] = 0x3B; | |
| 2914 | + cxd2841er_write_regs(priv, I2C_SLVT, 0x33, data, 3); | |
| 2915 | + | |
| 2916 | + /* Set SLV-T Bank : 0x20 */ | |
| 2917 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20); | |
| 2918 | + data[0] = 0x5E; | |
| 2919 | + data[1] = 0x5E; | |
| 2920 | + data[2] = 0x47; | |
| 2921 | + cxd2841er_write_regs(priv, I2C_SLVT, 0x95, data, 3); | |
| 2922 | + | |
| 2923 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x99, 0x18); | |
| 2924 | + | |
| 2925 | + data[0] = 0x3F; | |
| 2926 | + data[1] = 0xFF; | |
| 2927 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | |
| 2928 | + | |
| 2929 | + /* Set SLV-T Bank : 0x24 */ | |
| 2930 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x24); | |
| 2931 | + data[0] = 0x0B; | |
| 2932 | + data[1] = 0x72; | |
| 2933 | + cxd2841er_write_regs(priv, I2C_SLVT, 0x34, data, 2); | |
| 2934 | + | |
| 2935 | + data[0] = 0x93; | |
| 2936 | + data[1] = 0xF3; | |
| 2937 | + data[2] = 0x00; | |
| 2938 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xD2, data, 3); | |
| 2939 | + | |
| 2940 | + data[0] = 0x05; | |
| 2941 | + data[1] = 0xB8; | |
| 2942 | + data[2] = 0xD8; | |
| 2943 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xDD, data, 3); | |
| 2944 | + | |
| 2945 | + cxd2841er_write_reg(priv, I2C_SLVT, 0xE0, 0x00); | |
| 2946 | + | |
| 2947 | + /* Set SLV-T Bank : 0x25 */ | |
| 2948 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x25); | |
| 2949 | + cxd2841er_write_reg(priv, I2C_SLVT, 0xED, 0x60); | |
| 2950 | + | |
| 2951 | + /* Set SLV-T Bank : 0x27 */ | |
| 2952 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); | |
| 2953 | + cxd2841er_write_reg(priv, I2C_SLVT, 0xFA, 0x34); | |
| 2954 | + | |
| 2955 | + /* Set SLV-T Bank : 0x2B */ | |
| 2956 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2B); | |
| 2957 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x4B, 0x2F); | |
| 2958 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x9E, 0x0E); | |
| 2959 | + | |
| 2960 | + /* Set SLV-T Bank : 0x2D */ | |
| 2961 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2D); | |
| 2962 | + data[0] = 0x89; | |
| 2963 | + data[1] = 0x89; | |
| 2964 | + cxd2841er_write_regs(priv, I2C_SLVT, 0x24, data, 2); | |
| 2965 | + | |
| 2966 | + /* Set SLV-T Bank : 0x5E */ | |
| 2967 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x5E); | |
| 2968 | + data[0] = 0x24; | |
| 2969 | + data[1] = 0x95; | |
| 2970 | + cxd2841er_write_regs(priv, I2C_SLVT, 0x8C, data, 2); | |
| 2971 | + } | |
| 2972 | + | |
| 2023 | 2973 | cxd2841er_sleep_tc_to_active_t2_band(priv, bandwidth); |
| 2024 | 2974 | |
| 2025 | 2975 | /* Set SLV-T Bank : 0x00 */ |
| @@ -2032,6 +2982,84 @@ static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, · 6 unmodified lines | ||
| 2032 | 2982 | return 0; |
| 2033 | 2983 | } |
| 2034 | 2984 | |
| 2985 | +/* ISDB-Tb part */ | |
| 2986 | +static int cxd2841er_sleep_tc_to_active_i(struct cxd2841er_priv *priv, | |
| 2987 | + u32 bandwidth) | |
| 2988 | +{ | |
| 2989 | + u8 data[2] = { 0x09, 0x54 }; | |
| 2990 | + u8 data24m[2] = {0x60, 0x00}; | |
| 2991 | + u8 data24m2[3] = {0xB7, 0x1B, 0x00}; | |
| 2992 | + | |
| 2993 | + dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 2994 | + cxd2841er_set_ts_clock_mode(priv, SYS_DVBT); | |
| 2995 | + /* Set SLV-X Bank : 0x00 */ | |
| 2996 | + cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); | |
| 2997 | + /* Set demod mode */ | |
| 2998 | + cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x06); | |
| 2999 | + /* Set SLV-T Bank : 0x00 */ | |
| 3000 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | |
| 3001 | + /* Enable demod clock */ | |
| 3002 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01); | |
| 3003 | + /* Enable RF level monitor */ | |
| 3004 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x01); | |
| 3005 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x59, 0x01); | |
| 3006 | + /* Enable ADC clock */ | |
| 3007 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); | |
| 3008 | + /* Enable ADC 1 */ | |
| 3009 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a); | |
| 3010 | + /* xtal freq 20.5MHz or 24M */ | |
| 3011 | + cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2); | |
| 3012 | + /* Enable ADC 4 */ | |
| 3013 | + cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00); | |
| 3014 | + /* ASCOT setting ON */ | |
| 3015 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xa5, 0x01, 0x01); | |
| 3016 | + /* FEC Auto Recovery setting */ | |
| 3017 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x30, 0x01, 0x01); | |
| 3018 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x31, 0x00, 0x01); | |
| 3019 | + /* ISDB-T initial setting */ | |
| 3020 | + /* Set SLV-T Bank : 0x00 */ | |
| 3021 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | |
| 3022 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x00, 0x01); | |
| 3023 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x00, 0x01); | |
| 3024 | + /* Set SLV-T Bank : 0x10 */ | |
| 3025 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | |
| 3026 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x69, 0x04, 0x07); | |
| 3027 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x6B, 0x03, 0x07); | |
| 3028 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x9D, 0x50, 0xFF); | |
| 3029 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xD3, 0x06, 0x1F); | |
| 3030 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xED, 0x00, 0x01); | |
| 3031 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xE2, 0xCE, 0x80); | |
| 3032 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xF2, 0x13, 0x10); | |
| 3033 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xDE, 0x2E, 0x3F); | |
| 3034 | + /* Set SLV-T Bank : 0x15 */ | |
| 3035 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x15); | |
| 3036 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xDE, 0x02, 0x03); | |
| 3037 | + /* Set SLV-T Bank : 0x1E */ | |
| 3038 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x1E); | |
| 3039 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x73, 0x68, 0xFF); | |
| 3040 | + /* Set SLV-T Bank : 0x63 */ | |
| 3041 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x63); | |
| 3042 | + cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x81, 0x00, 0x01); | |
| 3043 | + | |
| 3044 | + /* for xtal 24MHz */ | |
| 3045 | + /* Set SLV-T Bank : 0x10 */ | |
| 3046 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | |
| 3047 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xBF, data24m, 2); | |
| 3048 | + /* Set SLV-T Bank : 0x60 */ | |
| 3049 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); | |
| 3050 | + cxd2841er_write_regs(priv, I2C_SLVT, 0xA8, data24m2, 3); | |
| 3051 | + | |
| 3052 | + cxd2841er_sleep_tc_to_active_i_band(priv, bandwidth); | |
| 3053 | + /* Set SLV-T Bank : 0x00 */ | |
| 3054 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | |
| 3055 | + /* Disable HiZ Setting 1 */ | |
| 3056 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x28); | |
| 3057 | + /* Disable HiZ Setting 2 */ | |
| 3058 | + cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0x00); | |
| 3059 | + priv->state = STATE_ACTIVE_TC; | |
| 3060 | + return 0; | |
| 3061 | +} | |
| 3062 | + | |
| 2035 | 3063 | static int cxd2841er_sleep_tc_to_active_c(struct cxd2841er_priv *priv, |
| 2036 | 3064 | u32 bandwidth) |
| 2037 | 3065 | { |
| @@ -2079,7 +3107,7 @@ static int cxd2841er_sleep_tc_to_active_c(struct cxd2841er_priv *priv, · 41 unmodified lines | ||
| 2079 | 3107 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01); |
| 2080 | 3108 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01); |
| 2081 | 3109 | |
| 2082 | − cxd2841er_sleep_tc_to_active_c_band(priv, 8000000); | |
| 3110 | + cxd2841er_sleep_tc_to_active_c_band(priv, bandwidth); | |
| 2083 | 3111 | /* Set SLV-T Bank : 0x00 */ |
| 2084 | 3112 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); |
| 2085 | 3113 | /* Disable HiZ Setting 1 */ |
| @@ -2094,8 +3122,6 @@ static int cxd2841er_get_frontend(struct dvb_frontend *fe, · 8 unmodified lines | ||
| 2094 | 3122 | struct dtv_frontend_properties *p) |
| 2095 | 3123 | { |
| 2096 | 3124 | enum fe_status status = 0; |
| 2097 | − u16 strength = 0, snr = 0; | |
| 2098 | − u32 errors = 0, ber = 0; | |
| 2099 | 3125 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 2100 | 3126 | |
| 2101 | 3127 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| @@ -2104,32 +3130,18 @@ static int cxd2841er_get_frontend(struct dvb_frontend *fe, · 2 unmodified lines | ||
| 2104 | 3130 | else if (priv->state == STATE_ACTIVE_TC) |
| 2105 | 3131 | cxd2841er_read_status_tc(fe, &status); |
| 2106 | 3132 | |
| 3133 | + cxd2841er_read_signal_strength(fe); | |
| 3134 | + | |
| 2107 | 3135 | if (status & FE_HAS_LOCK) { |
| 2108 | − cxd2841er_read_signal_strength(fe, &strength); | |
| 2109 | − p->strength.len = 1; | |
| 2110 | − p->strength.stat[0].scale = FE_SCALE_RELATIVE; | |
| 2111 | − p->strength.stat[0].uvalue = strength; | |
| 2112 | − cxd2841er_read_snr(fe, &snr); | |
| 2113 | − p->cnr.len = 1; | |
| 2114 | − p->cnr.stat[0].scale = FE_SCALE_DECIBEL; | |
| 2115 | − p->cnr.stat[0].svalue = snr; | |
| 2116 | − cxd2841er_read_ucblocks(fe, &errors); | |
| 2117 | − p->block_error.len = 1; | |
| 2118 | − p->block_error.stat[0].scale = FE_SCALE_COUNTER; | |
| 2119 | − p->block_error.stat[0].uvalue = errors; | |
| 2120 | − cxd2841er_read_ber(fe, &ber); | |
| 2121 | − p->post_bit_error.len = 1; | |
| 2122 | − p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; | |
| 2123 | − p->post_bit_error.stat[0].uvalue = ber; | |
| 3136 | + cxd2841er_read_snr(fe); | |
| 3137 | + cxd2841er_read_ucblocks(fe); | |
| 3138 | + | |
| 3139 | + cxd2841er_read_ber(fe); | |
| 2124 | 3140 | } else { |
| 2125 | − p->strength.len = 1; | |
| 2126 | − p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 2127 | − p->cnr.len = 1; | |
| 2128 | 3141 | p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 2129 | − p->block_error.len = 1; | |
| 2130 | 3142 | p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 2131 | − p->post_bit_error.len = 1; | |
| 2132 | 3143 | p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 3144 | + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 2133 | 3145 | } |
| 2134 | 3146 | return 0; |
| 2135 | 3147 | } |
| @@ -2142,10 +3154,10 @@ static int cxd2841er_set_frontend_s(struct dvb_frontend *fe) · 6 unmodified lines | ||
| 2142 | 3154 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 2143 | 3155 | u32 symbol_rate = p->symbol_rate/1000; |
| 2144 | 3156 | |
| 2145 | − dev_dbg(&priv->i2c->dev, "%s(): %s frequency=%d symbol_rate=%d\n", | |
| 3157 | + dev_dbg(&priv->i2c->dev, "%s(): %s frequency=%d symbol_rate=%d xtal=%d\n", | |
| 2146 | 3158 | __func__, |
| 2147 | 3159 | (p->delivery_system == SYS_DVBS ? "DVB-S" : "DVB-S2"), |
| 2148 | − p->frequency, symbol_rate); | |
| 3160 | + p->frequency, symbol_rate, priv->xtal); | |
| 2149 | 3161 | switch (priv->state) { |
| 2150 | 3162 | case STATE_SLEEP_S: |
| 2151 | 3163 | ret = cxd2841er_sleep_s_to_active_s( |
| @@ -2189,6 +3201,13 @@ static int cxd2841er_set_frontend_s(struct dvb_frontend *fe) · 37 unmodified lines | ||
| 2189 | 3201 | __func__, carr_offset); |
| 2190 | 3202 | } |
| 2191 | 3203 | done: |
| 3204 | + /* Reset stats */ | |
| 3205 | + p->strength.stat[0].scale = FE_SCALE_RELATIVE; | |
| 3206 | + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 3207 | + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 3208 | + p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 3209 | + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 3210 | + | |
| 2192 | 3211 | return ret; |
| 2193 | 3212 | } |
| 2194 | 3213 | |
| @@ -2199,7 +3218,8 @@ static int cxd2841er_set_frontend_tc(struct dvb_frontend *fe) · 4 unmodified lines | ||
| 2199 | 3218 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 2200 | 3219 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 2201 | 3220 | |
| 2202 | − dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 3221 | + dev_dbg(&priv->i2c->dev, "%s() delivery_system=%d bandwidth_hz=%d\n", | |
| 3222 | + __func__, p->delivery_system, p->bandwidth_hz); | |
| 2203 | 3223 | if (p->delivery_system == SYS_DVBT) { |
| 2204 | 3224 | priv->system = SYS_DVBT; |
| 2205 | 3225 | switch (priv->state) { |
| @@ -2233,9 +3253,33 @@ static int cxd2841er_set_frontend_tc(struct dvb_frontend *fe) · 27 unmodified lines | ||
| 2233 | 3253 | __func__, priv->state); |
| 2234 | 3254 | ret = -EINVAL; |
| 2235 | 3255 | } |
| 3256 | + } else if (p->delivery_system == SYS_ISDBT) { | |
| 3257 | + priv->system = SYS_ISDBT; | |
| 3258 | + switch (priv->state) { | |
| 3259 | + case STATE_SLEEP_TC: | |
| 3260 | + ret = cxd2841er_sleep_tc_to_active_i( | |
| 3261 | + priv, p->bandwidth_hz); | |
| 3262 | + break; | |
| 3263 | + case STATE_ACTIVE_TC: | |
| 3264 | + ret = cxd2841er_retune_active(priv, p); | |
| 3265 | + break; | |
| 3266 | + default: | |
| 3267 | + dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n", | |
| 3268 | + __func__, priv->state); | |
| 3269 | + ret = -EINVAL; | |
| 3270 | + } | |
| 2236 | 3271 | } else if (p->delivery_system == SYS_DVBC_ANNEX_A || |
| 2237 | 3272 | p->delivery_system == SYS_DVBC_ANNEX_C) { |
| 2238 | 3273 | priv->system = SYS_DVBC_ANNEX_A; |
| 3274 | + /* correct bandwidth */ | |
| 3275 | + if (p->bandwidth_hz != 6000000 && | |
| 3276 | + p->bandwidth_hz != 7000000 && | |
| 3277 | + p->bandwidth_hz != 8000000) { | |
| 3278 | + p->bandwidth_hz = 8000000; | |
| 3279 | + dev_dbg(&priv->i2c->dev, "%s(): forcing bandwidth to %d\n", | |
| 3280 | + __func__, p->bandwidth_hz); | |
| 3281 | + } | |
| 3282 | + | |
| 2239 | 3283 | switch (priv->state) { |
| 2240 | 3284 | case STATE_SLEEP_TC: |
| 2241 | 3285 | ret = cxd2841er_sleep_tc_to_active_c( |
| @@ -2321,7 +3365,8 @@ static int cxd2841er_tune_tc(struct dvb_frontend *fe, · 79 unmodified lines | ||
| 2321 | 3365 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 2322 | 3366 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 2323 | 3367 | |
| 2324 | − dev_dbg(&priv->i2c->dev, "%s(): re_tune %d\n", __func__, re_tune); | |
| 3368 | + dev_dbg(&priv->i2c->dev, "%s(): re_tune %d bandwidth=%d\n", __func__, | |
| 3369 | + re_tune, p->bandwidth_hz); | |
| 2325 | 3370 | if (re_tune) { |
| 2326 | 3371 | ret = cxd2841er_set_frontend_tc(fe); |
| 2327 | 3372 | if (ret) |
| @@ -2329,7 +3374,16 @@ static int cxd2841er_tune_tc(struct dvb_frontend *fe, · 1 unmodified line | ||
| 2329 | 3374 | cxd2841er_read_status_tc(fe, status); |
| 2330 | 3375 | if (*status & FE_HAS_LOCK) { |
| 2331 | 3376 | switch (priv->system) { |
| 3377 | + case SYS_ISDBT: | |
| 3378 | + ret = cxd2841er_get_carrier_offset_i( | |
| 3379 | + priv, p->bandwidth_hz, | |
| 3380 | + &carrier_offset); | |
| 3381 | + break; | |
| 2332 | 3382 | case SYS_DVBT: |
| 3383 | + ret = cxd2841er_get_carrier_offset_t( | |
| 3384 | + priv, p->bandwidth_hz, | |
| 3385 | + &carrier_offset); | |
| 3386 | + break; | |
| 2333 | 3387 | case SYS_DVBT2: |
| 2334 | 3388 | ret = cxd2841er_get_carrier_offset_t2( |
| 2335 | 3389 | priv, p->bandwidth_hz, |
| @@ -2382,6 +3436,9 @@ static int cxd2841er_sleep_tc(struct dvb_frontend *fe) · 46 unmodified lines | ||
| 2382 | 3436 | case SYS_DVBT2: |
| 2383 | 3437 | cxd2841er_active_t2_to_sleep_tc(priv); |
| 2384 | 3438 | break; |
| 3439 | + case SYS_ISDBT: | |
| 3440 | + cxd2841er_active_i_to_sleep_tc(priv); | |
| 3441 | + break; | |
| 2385 | 3442 | case SYS_DVBC_ANNEX_A: |
| 2386 | 3443 | cxd2841er_active_c_to_sleep_tc(priv); |
| 2387 | 3444 | break; |
| @@ -2512,23 +3569,57 @@ static enum dvbfe_algo cxd2841er_get_algo(struct dvb_frontend *fe) · 124 unmodified lines | ||
| 2512 | 3569 | return DVBFE_ALGO_HW; |
| 2513 | 3570 | } |
| 2514 | 3571 | |
| 3572 | +static void cxd2841er_init_stats(struct dvb_frontend *fe) | |
| 3573 | +{ | |
| 3574 | + struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
| 3575 | + | |
| 3576 | + p->strength.len = 1; | |
| 3577 | + p->strength.stat[0].scale = FE_SCALE_RELATIVE; | |
| 3578 | + p->cnr.len = 1; | |
| 3579 | + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 3580 | + p->block_error.len = 1; | |
| 3581 | + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 3582 | + p->post_bit_error.len = 1; | |
| 3583 | + p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 3584 | + p->post_bit_count.len = 1; | |
| 3585 | + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 3586 | +} | |
| 3587 | + | |
| 3588 | + | |
| 2515 | 3589 | static int cxd2841er_init_s(struct dvb_frontend *fe) |
| 2516 | 3590 | { |
| 2517 | 3591 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 2518 | 3592 | |
| 3593 | + /* sanity. force demod to SHUTDOWN state */ | |
| 3594 | + if (priv->state == STATE_SLEEP_S) { | |
| 3595 | + dev_dbg(&priv->i2c->dev, "%s() forcing sleep->shutdown\n", | |
| 3596 | + __func__); | |
| 3597 | + cxd2841er_sleep_s_to_shutdown(priv); | |
| 3598 | + } else if (priv->state == STATE_ACTIVE_S) { | |
| 3599 | + dev_dbg(&priv->i2c->dev, "%s() forcing active->sleep->shutdown\n", | |
| 3600 | + __func__); | |
| 3601 | + cxd2841er_active_s_to_sleep_s(priv); | |
| 3602 | + cxd2841er_sleep_s_to_shutdown(priv); | |
| 3603 | + } | |
| 3604 | + | |
| 2519 | 3605 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 2520 | 3606 | cxd2841er_shutdown_to_sleep_s(priv); |
| 2521 | 3607 | /* SONY_DEMOD_CONFIG_SAT_IFAGCNEG set to 1 */ |
| 2522 | 3608 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0); |
| 2523 | 3609 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xb9, 0x01, 0x01); |
| 3610 | + | |
| 3611 | + cxd2841er_init_stats(fe); | |
| 3612 | + | |
| 2524 | 3613 | return 0; |
| 2525 | 3614 | } |
| 2526 | 3615 | |
| 2527 | 3616 | static int cxd2841er_init_tc(struct dvb_frontend *fe) |
| 2528 | 3617 | { |
| 2529 | 3618 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 3619 | + struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
| 2530 | 3620 | |
| 2531 | − dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 3621 | + dev_dbg(&priv->i2c->dev, "%s() bandwidth_hz=%d\n", | |
| 3622 | + __func__, p->bandwidth_hz); | |
| 2532 | 3623 | cxd2841er_shutdown_to_sleep_tc(priv); |
| 2533 | 3624 | /* SONY_DEMOD_CONFIG_IFAGCNEG = 1 */ |
| 2534 | 3625 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
| @@ -2538,12 +3629,14 @@ static int cxd2841er_init_tc(struct dvb_frontend *fe) · 3 unmodified lines | ||
| 2538 | 3629 | /* SONY_DEMOD_CONFIG_PARALLEL_SEL = 1 */ |
| 2539 | 3630 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); |
| 2540 | 3631 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xc4, 0x00, 0x80); |
| 3632 | + | |
| 3633 | + cxd2841er_init_stats(fe); | |
| 3634 | + | |
| 2541 | 3635 | return 0; |
| 2542 | 3636 | } |
| 2543 | 3637 | |
| 2544 | 3638 | static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops; |
| 2545 | −static struct dvb_frontend_ops cxd2841er_dvbt_t2_ops; | |
| 2546 | −static struct dvb_frontend_ops cxd2841er_dvbc_ops; | |
| 3639 | +static struct dvb_frontend_ops cxd2841er_t_c_ops; | |
| 2547 | 3640 | |
| 2548 | 3641 | static struct dvb_frontend *cxd2841er_attach(struct cxd2841er_config *cfg, |
| 2549 | 3642 | struct i2c_adapter *i2c, |
| @@ -2551,6 +3644,7 @@ static struct dvb_frontend *cxd2841er_attach(struct cxd2841er_config *cfg, · 1 unmodified line | ||
| 2551 | 3644 | { |
| 2552 | 3645 | u8 chip_id = 0; |
| 2553 | 3646 | const char *type; |
| 3647 | + const char *name; | |
| 2554 | 3648 | struct cxd2841er_priv *priv = NULL; |
| 2555 | 3649 | |
| 2556 | 3650 | /* allocate memory for the internal state */ |
| @@ -2561,46 +3655,49 @@ static struct dvb_frontend *cxd2841er_attach(struct cxd2841er_config *cfg, · 4 unmodified lines | ||
| 2561 | 3655 | priv->config = cfg; |
| 2562 | 3656 | priv->i2c_addr_slvx = (cfg->i2c_addr + 4) >> 1; |
| 2563 | 3657 | priv->i2c_addr_slvt = (cfg->i2c_addr) >> 1; |
| 2564 | − /* create dvb_frontend */ | |
| 2565 | − switch (system) { | |
| 2566 | − case SYS_DVBS: | |
| 2567 | − memcpy(&priv->frontend.ops, | |
| 2568 | − &cxd2841er_dvbs_s2_ops, | |
| 2569 | − sizeof(struct dvb_frontend_ops)); | |
| 2570 | − type = "S/S2"; | |
| 2571 | − break; | |
| 2572 | − case SYS_DVBT: | |
| 2573 | − memcpy(&priv->frontend.ops, | |
| 2574 | − &cxd2841er_dvbt_t2_ops, | |
| 2575 | − sizeof(struct dvb_frontend_ops)); | |
| 2576 | − type = "T/T2"; | |
| 2577 | − break; | |
| 2578 | − case SYS_DVBC_ANNEX_A: | |
| 2579 | − memcpy(&priv->frontend.ops, | |
| 2580 | − &cxd2841er_dvbc_ops, | |
| 2581 | − sizeof(struct dvb_frontend_ops)); | |
| 2582 | − type = "C/C2"; | |
| 2583 | − break; | |
| 2584 | − default: | |
| 2585 | − kfree(priv); | |
| 2586 | − return NULL; | |
| 2587 | − } | |
| 3658 | + priv->xtal = cfg->xtal; | |
| 2588 | 3659 | priv->frontend.demodulator_priv = priv; |
| 2589 | − dev_info(&priv->i2c->dev, | |
| 2590 | − "%s(): attaching CXD2841ER DVB-%s frontend\n", | |
| 2591 | − __func__, type); | |
| 2592 | 3660 | dev_info(&priv->i2c->dev, |
| 2593 | 3661 | "%s(): I2C adapter %p SLVX addr %x SLVT addr %x\n", |
| 2594 | 3662 | __func__, priv->i2c, |
| 2595 | 3663 | priv->i2c_addr_slvx, priv->i2c_addr_slvt); |
| 2596 | 3664 | chip_id = cxd2841er_chip_id(priv); |
| 2597 | − if (chip_id != CXD2841ER_CHIP_ID) { | |
| 3665 | + switch (chip_id) { | |
| 3666 | + case CXD2841ER_CHIP_ID: | |
| 3667 | + snprintf(cxd2841er_t_c_ops.info.name, 128, | |
| 3668 | + "Sony CXD2841ER DVB-T/T2/C demodulator"); | |
| 3669 | + name = "CXD2841ER"; | |
| 3670 | + break; | |
| 3671 | + case CXD2854ER_CHIP_ID: | |
| 3672 | + snprintf(cxd2841er_t_c_ops.info.name, 128, | |
| 3673 | + "Sony CXD2854ER DVB-T/T2/C and ISDB-T demodulator"); | |
| 3674 | + cxd2841er_t_c_ops.delsys[3] = SYS_ISDBT; | |
| 3675 | + name = "CXD2854ER"; | |
| 3676 | + break; | |
| 3677 | + default: | |
| 2598 | 3678 | dev_err(&priv->i2c->dev, "%s(): invalid chip ID 0x%02x\n", |
| 2599 | − __func__, chip_id); | |
| 3679 | + __func__, chip_id); | |
| 2600 | 3680 | priv->frontend.demodulator_priv = NULL; |
| 2601 | 3681 | kfree(priv); |
| 2602 | 3682 | return NULL; |
| 2603 | 3683 | } |
| 3684 | + | |
| 3685 | + /* create dvb_frontend */ | |
| 3686 | + if (system == SYS_DVBS) { | |
| 3687 | + memcpy(&priv->frontend.ops, | |
| 3688 | + &cxd2841er_dvbs_s2_ops, | |
| 3689 | + sizeof(struct dvb_frontend_ops)); | |
| 3690 | + type = "S/S2"; | |
| 3691 | + } else { | |
| 3692 | + memcpy(&priv->frontend.ops, | |
| 3693 | + &cxd2841er_t_c_ops, | |
| 3694 | + sizeof(struct dvb_frontend_ops)); | |
| 3695 | + type = "T/T2/C/ISDB-T"; | |
| 3696 | + } | |
| 3697 | + | |
| 3698 | + dev_info(&priv->i2c->dev, | |
| 3699 | + "%s(): attaching %s DVB-%s frontend\n", | |
| 3700 | + __func__, name, type); | |
| 2604 | 3701 | dev_info(&priv->i2c->dev, "%s(): chip ID 0x%02x OK.\n", |
| 2605 | 3702 | __func__, chip_id); |
| 2606 | 3703 | return &priv->frontend; |
| @@ -2613,19 +3710,12 @@ struct dvb_frontend *cxd2841er_attach_s(struct cxd2841er_config *cfg, · 6 unmodified lines | ||
| 2613 | 3710 | } |
| 2614 | 3711 | EXPORT_SYMBOL(cxd2841er_attach_s); |
| 2615 | 3712 | |
| 2616 | −struct dvb_frontend *cxd2841er_attach_t(struct cxd2841er_config *cfg, | |
| 2617 | − struct i2c_adapter *i2c) | |
| 2618 | −{ | |
| 2619 | − return cxd2841er_attach(cfg, i2c, SYS_DVBT); | |
| 2620 | −} | |
| 2621 | −EXPORT_SYMBOL(cxd2841er_attach_t); | |
| 2622 | − | |
| 2623 | −struct dvb_frontend *cxd2841er_attach_c(struct cxd2841er_config *cfg, | |
| 3713 | +struct dvb_frontend *cxd2841er_attach_t_c(struct cxd2841er_config *cfg, | |
| 2624 | 3714 | struct i2c_adapter *i2c) |
| 2625 | 3715 | { |
| 2626 | − return cxd2841er_attach(cfg, i2c, SYS_DVBC_ANNEX_A); | |
| 3716 | + return cxd2841er_attach(cfg, i2c, 0); | |
| 2627 | 3717 | } |
| 2628 | −EXPORT_SYMBOL(cxd2841er_attach_c); | |
| 3718 | +EXPORT_SYMBOL(cxd2841er_attach_t_c); | |
| 2629 | 3719 | |
| 2630 | 3720 | static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = { |
| 2631 | 3721 | .delsys = { SYS_DVBS, SYS_DVBS2 }, |
| @@ -2655,10 +3745,10 @@ static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = { · 23 unmodified lines | ||
| 2655 | 3745 | .tune = cxd2841er_tune_s |
| 2656 | 3746 | }; |
| 2657 | 3747 | |
| 2658 | −static struct dvb_frontend_ops cxd2841er_dvbt_t2_ops = { | |
| 2659 | − .delsys = { SYS_DVBT, SYS_DVBT2 }, | |
| 3748 | +static struct dvb_frontend_ops cxd2841er_t_c_ops = { | |
| 3749 | + .delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A }, | |
| 2660 | 3750 | .info = { |
| 2661 | − .name = "Sony CXD2841ER DVB-T/T2 demodulator", | |
| 3751 | + .name = "", /* will set in attach function */ | |
| 2662 | 3752 | .caps = FE_CAN_FEC_1_2 | |
| 2663 | 3753 | FE_CAN_FEC_2_3 | |
| 2664 | 3754 | FE_CAN_FEC_3_4 | |
| @@ -2691,37 +3781,6 @@ static struct dvb_frontend_ops cxd2841er_dvbt_t2_ops = { · 26 unmodified lines | ||
| 2691 | 3781 | .get_frontend_algo = cxd2841er_get_algo |
| 2692 | 3782 | }; |
| 2693 | 3783 | |
| 2694 | −static struct dvb_frontend_ops cxd2841er_dvbc_ops = { | |
| 2695 | − .delsys = { SYS_DVBC_ANNEX_A }, | |
| 2696 | − .info = { | |
| 2697 | − .name = "Sony CXD2841ER DVB-C demodulator", | |
| 2698 | − .caps = FE_CAN_FEC_1_2 | | |
| 2699 | − FE_CAN_FEC_2_3 | | |
| 2700 | − FE_CAN_FEC_3_4 | | |
| 2701 | − FE_CAN_FEC_5_6 | | |
| 2702 | − FE_CAN_FEC_7_8 | | |
| 2703 | − FE_CAN_FEC_AUTO | | |
| 2704 | − FE_CAN_QAM_16 | | |
| 2705 | − FE_CAN_QAM_32 | | |
| 2706 | − FE_CAN_QAM_64 | | |
| 2707 | − FE_CAN_QAM_128 | | |
| 2708 | − FE_CAN_QAM_256 | | |
| 2709 | − FE_CAN_QAM_AUTO | | |
| 2710 | − FE_CAN_INVERSION_AUTO, | |
| 2711 | − .frequency_min = 42000000, | |
| 2712 | − .frequency_max = 1002000000 | |
| 2713 | − }, | |
| 2714 | − .init = cxd2841er_init_tc, | |
| 2715 | − .sleep = cxd2841er_sleep_tc, | |
| 2716 | − .release = cxd2841er_release, | |
| 2717 | − .set_frontend = cxd2841er_set_frontend_tc, | |
| 2718 | − .get_frontend = cxd2841er_get_frontend, | |
| 2719 | − .read_status = cxd2841er_read_status_tc, | |
| 2720 | − .tune = cxd2841er_tune_tc, | |
| 2721 | − .i2c_gate_ctrl = cxd2841er_i2c_gate_ctrl, | |
| 2722 | − .get_frontend_algo = cxd2841er_get_algo, | |
| 2723 | −}; | |
| 2724 | − | |
| 2725 | −MODULE_DESCRIPTION("Sony CXD2841ER DVB-C/C2/T/T2/S/S2 demodulator driver"); | |
| 2726 | −MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>"); | |
| 3784 | +MODULE_DESCRIPTION("Sony CXD2841ER/CXD2854ER DVB-C/C2/T/T2/S/S2 demodulator driver"); | |
| 3785 | +MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>, Abylay Ospan <aospan@netup.ru>"); | |
| 2727 | 3786 | MODULE_LICENSE("GPL"); |
| @@ -25,41 +25,39 @@ · 24 unmodified lines | ||
| 25 | 25 | #include <linux/kconfig.h> |
| 26 | 26 | #include <linux/dvb/frontend.h> |
| 27 | 27 | |
| 28 | +enum cxd2841er_xtal { | |
| 29 | + SONY_XTAL_20500, /* 20.5 MHz */ | |
| 30 | + SONY_XTAL_24000, /* 24 MHz */ | |
| 31 | + SONY_XTAL_41000 /* 41 MHz */ | |
| 32 | +}; | |
| 33 | + | |
| 28 | 34 | struct cxd2841er_config { |
| 29 | 35 | u8 i2c_addr; |
| 36 | + enum cxd2841er_xtal xtal; | |
| 30 | 37 | }; |
| 31 | 38 | |
| 32 | 39 | #if IS_REACHABLE(CONFIG_DVB_CXD2841ER) |
| 33 | 40 | extern struct dvb_frontend *cxd2841er_attach_s(struct cxd2841er_config *cfg, |
| 34 | 41 | struct i2c_adapter *i2c); |
| 35 | 42 | |
| 36 | −extern struct dvb_frontend *cxd2841er_attach_t(struct cxd2841er_config *cfg, | |
| 37 | − struct i2c_adapter *i2c); | |
| 38 | − | |
| 39 | −extern struct dvb_frontend *cxd2841er_attach_c(struct cxd2841er_config *cfg, | |
| 43 | +extern struct dvb_frontend *cxd2841er_attach_t_c(struct cxd2841er_config *cfg, | |
| 40 | 44 | struct i2c_adapter *i2c); |
| 41 | 45 | #else |
| 42 | 46 | static inline struct dvb_frontend *cxd2841er_attach_s( |
| 43 | 47 | struct cxd2841er_config *cfg, |
| 44 | 48 | struct i2c_adapter *i2c) |
| 45 | 49 | { |
| 46 | − printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | |
| 50 | + pr_warn("%s: driver disabled by Kconfig\n", __func__); | |
| 47 | 51 | return NULL; |
| 48 | 52 | } |
| 49 | 53 | |
| 50 | −static inline struct dvb_frontend *cxd2841er_attach_t( | |
| 54 | +static inline struct dvb_frontend *cxd2841er_attach_t_c( | |
| 51 | 55 | struct cxd2841er_config *cfg, struct i2c_adapter *i2c) |
| 52 | 56 | { |
| 53 | − printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | |
| 57 | + pr_warn("%s: driver disabled by Kconfig\n", __func__); | |
| 54 | 58 | return NULL; |
| 55 | 59 | } |
| 56 | 60 | |
| 57 | −static inline struct dvb_frontend *cxd2841er_attach_c( | |
| 58 | − struct cxd2841er_config *cfg, struct i2c_adapter *i2c) | |
| 59 | −{ | |
| 60 | − printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | |
| 61 | − return NULL; | |
| 62 | −} | |
| 63 | 61 | #endif |
| 64 | 62 | |
| 65 | 63 | #endif |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | #define I2C_SLVT 1 |
| 27 | 27 | |
| 28 | 28 | #define CXD2841ER_CHIP_ID 0xa7 |
| 29 | +#define CXD2854ER_CHIP_ID 0xc1 | |
| 29 | 30 | |
| 30 | 31 | #define CXD2841ER_DVBS_POLLING_INVL 10 |
| 31 | 32 | |
| @@ -797,6 +797,8 @@ static const u16 bb_ramp_pwm_normal[] = { · 796 unmodified lines | ||
| 797 | 797 | (0 << 9) | 400, /* BB_RAMP6 */ |
| 798 | 798 | }; |
| 799 | 799 | |
| 800 | +#if 0 | |
| 801 | +/* Currently unused */ | |
| 800 | 802 | static const u16 bb_ramp_pwm_boost[] = { |
| 801 | 803 | 550, /* max BB gain in 10th of dB */ |
| 802 | 804 | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */ |
| @@ -806,6 +808,7 @@ static const u16 bb_ramp_pwm_boost[] = { · 3 unmodified lines | ||
| 806 | 808 | (2 << 9) | 208, /* BB_RAMP5 = 29dB */ |
| 807 | 809 | (0 << 9) | 440, /* BB_RAMP6 */ |
| 808 | 810 | }; |
| 811 | +#endif | |
| 809 | 812 | |
| 810 | 813 | static const u16 rf_ramp_pwm_cband[] = { |
| 811 | 814 | 314, /* max RF gain in 10th of dB */ |
| @@ -849,6 +852,8 @@ static const u16 rf_ramp_pwm_uhf[] = { · 37 unmodified lines | ||
| 849 | 852 | (0 << 10) | 580, /* GAIN_4_2, LNA 4 */ |
| 850 | 853 | }; |
| 851 | 854 | |
| 855 | +#if 0 | |
| 856 | +/* Currently unused */ | |
| 852 | 857 | static const u16 rf_ramp_pwm_sband[] = { |
| 853 | 858 | 253, /* max RF gain in 10th of dB */ |
| 854 | 859 | 38, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ |
| @@ -862,6 +867,7 @@ static const u16 rf_ramp_pwm_sband[] = { · 7 unmodified lines | ||
| 862 | 867 | (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */ |
| 863 | 868 | (0 << 10) | 0, /* GAIN_4_2, LNA 4 */ |
| 864 | 869 | }; |
| 870 | +#endif | |
| 865 | 871 | |
| 866 | 872 | struct slope { |
| 867 | 873 | s16 range; |
| @@ -1240,12 +1240,15 @@ static u32 frac_times1e6(u32 N, u32 D) · 1239 unmodified lines | ||
| 1240 | 1240 | * and rounded. For calc used formula: 16*10^(prescaleGain[dB]/20). |
| 1241 | 1241 | * |
| 1242 | 1242 | */ |
| 1243 | +#if 0 | |
| 1244 | +/* Currently, unused as we lack support for analog TV */ | |
| 1243 | 1245 | static const u16 nicam_presc_table_val[43] = { |
| 1244 | 1246 | 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, |
| 1245 | 1247 | 5, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16, |
| 1246 | 1248 | 18, 20, 23, 25, 28, 32, 36, 40, 45, |
| 1247 | 1249 | 51, 57, 64, 71, 80, 90, 101, 113, 127 |
| 1248 | 1250 | }; |
| 1251 | +#endif | |
| 1249 | 1252 | |
| 1250 | 1253 | /*============================================================================*/ |
| 1251 | 1254 | /*== END HELPER FUNCTIONS ==*/ |
| @@ -959,6 +959,15 @@ static int ds3000_set_frontend(struct dvb_frontend *fe) · 958 unmodified lines | ||
| 959 | 959 | /* enable ac coupling */ |
| 960 | 960 | ds3000_writereg(state, 0x25, 0x8a); |
| 961 | 961 | |
| 962 | + if ((c->symbol_rate < ds3000_ops.info.symbol_rate_min) || | |
| 963 | + (c->symbol_rate > ds3000_ops.info.symbol_rate_max)) { | |
| 964 | + dprintk("%s() symbol_rate %u out of range (%u ... %u)\n", | |
| 965 | + __func__, c->symbol_rate, | |
| 966 | + ds3000_ops.info.symbol_rate_min, | |
| 967 | + ds3000_ops.info.symbol_rate_max); | |
| 968 | + return -EINVAL; | |
| 969 | + } | |
| 970 | + | |
| 962 | 971 | /* enhance symbol rate performance */ |
| 963 | 972 | if ((c->symbol_rate / 1000) <= 5000) { |
| 964 | 973 | value = 29777 / (c->symbol_rate / 1000) + 1; |
| @@ -0,0 +1,1042 @@ | ||
| 1 | +/* | |
| 2 | + * helene.c | |
| 3 | + * | |
| 4 | + * Sony HELENE DVB-S/S2 DVB-T/T2 DVB-C/C2 ISDB-T/S tuner driver (CXD2858ER) | |
| 5 | + * | |
| 6 | + * Copyright 2012 Sony Corporation | |
| 7 | + * Copyright (C) 2014 NetUP Inc. | |
| 8 | + * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru> | |
| 9 | + * | |
| 10 | + * This program is free software; you can redistribute it and/or modify | |
| 11 | + * it under the terms of the GNU General Public License as published by | |
| 12 | + * the Free Software Foundation; either version 2 of the License, or | |
| 13 | + * (at your option) any later version. | |
| 14 | + * | |
| 15 | + * This program is distributed in the hope that it will be useful, | |
| 16 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 18 | + * GNU General Public License for more details. | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#include <linux/slab.h> | |
| 22 | +#include <linux/module.h> | |
| 23 | +#include <linux/dvb/frontend.h> | |
| 24 | +#include <linux/types.h> | |
| 25 | +#include "helene.h" | |
| 26 | +#include "dvb_frontend.h" | |
| 27 | + | |
| 28 | +#define MAX_WRITE_REGSIZE 20 | |
| 29 | + | |
| 30 | +enum helene_state { | |
| 31 | + STATE_UNKNOWN, | |
| 32 | + STATE_SLEEP, | |
| 33 | + STATE_ACTIVE | |
| 34 | +}; | |
| 35 | + | |
| 36 | +struct helene_priv { | |
| 37 | + u32 frequency; | |
| 38 | + u8 i2c_address; | |
| 39 | + struct i2c_adapter *i2c; | |
| 40 | + enum helene_state state; | |
| 41 | + void *set_tuner_data; | |
| 42 | + int (*set_tuner)(void *, int); | |
| 43 | + enum helene_xtal xtal; | |
| 44 | +}; | |
| 45 | + | |
| 46 | +#define TERR_INTERNAL_LOOPFILTER_AVAILABLE(tv_system) \ | |
| 47 | + (((tv_system) != SONY_HELENE_DTV_DVBC_6) && \ | |
| 48 | + ((tv_system) != SONY_HELENE_DTV_DVBC_8)\ | |
| 49 | + && ((tv_system) != SONY_HELENE_DTV_DVBC2_6) && \ | |
| 50 | + ((tv_system) != SONY_HELENE_DTV_DVBC2_8)) | |
| 51 | + | |
| 52 | +#define HELENE_AUTO 0xff | |
| 53 | +#define HELENE_OFFSET(ofs) ((u8)(ofs) & 0x1F) | |
| 54 | +#define HELENE_BW_6 0x00 | |
| 55 | +#define HELENE_BW_7 0x01 | |
| 56 | +#define HELENE_BW_8 0x02 | |
| 57 | +#define HELENE_BW_1_7 0x03 | |
| 58 | + | |
| 59 | +enum helene_tv_system_t { | |
| 60 | + SONY_HELENE_TV_SYSTEM_UNKNOWN, | |
| 61 | + /* Terrestrial Analog */ | |
| 62 | + SONY_HELENE_ATV_MN_EIAJ, | |
| 63 | + /**< System-M (Japan) (IF: Fp=5.75MHz in default) */ | |
| 64 | + SONY_HELENE_ATV_MN_SAP, | |
| 65 | + /**< System-M (US) (IF: Fp=5.75MHz in default) */ | |
| 66 | + SONY_HELENE_ATV_MN_A2, | |
| 67 | + /**< System-M (Korea) (IF: Fp=5.9MHz in default) */ | |
| 68 | + SONY_HELENE_ATV_BG, | |
| 69 | + /**< System-B/G (IF: Fp=7.3MHz in default) */ | |
| 70 | + SONY_HELENE_ATV_I, | |
| 71 | + /**< System-I (IF: Fp=7.85MHz in default) */ | |
| 72 | + SONY_HELENE_ATV_DK, | |
| 73 | + /**< System-D/K (IF: Fp=7.85MHz in default) */ | |
| 74 | + SONY_HELENE_ATV_L, | |
| 75 | + /**< System-L (IF: Fp=7.85MHz in default) */ | |
| 76 | + SONY_HELENE_ATV_L_DASH, | |
| 77 | + /**< System-L DASH (IF: Fp=2.2MHz in default) */ | |
| 78 | + /* Terrestrial/Cable Digital */ | |
| 79 | + SONY_HELENE_DTV_8VSB, | |
| 80 | + /**< ATSC 8VSB (IF: Fc=3.7MHz in default) */ | |
| 81 | + SONY_HELENE_DTV_QAM, | |
| 82 | + /**< US QAM (IF: Fc=3.7MHz in default) */ | |
| 83 | + SONY_HELENE_DTV_ISDBT_6, | |
| 84 | + /**< ISDB-T 6MHzBW (IF: Fc=3.55MHz in default) */ | |
| 85 | + SONY_HELENE_DTV_ISDBT_7, | |
| 86 | + /**< ISDB-T 7MHzBW (IF: Fc=4.15MHz in default) */ | |
| 87 | + SONY_HELENE_DTV_ISDBT_8, | |
| 88 | + /**< ISDB-T 8MHzBW (IF: Fc=4.75MHz in default) */ | |
| 89 | + SONY_HELENE_DTV_DVBT_5, | |
| 90 | + /**< DVB-T 5MHzBW (IF: Fc=3.6MHz in default) */ | |
| 91 | + SONY_HELENE_DTV_DVBT_6, | |
| 92 | + /**< DVB-T 6MHzBW (IF: Fc=3.6MHz in default) */ | |
| 93 | + SONY_HELENE_DTV_DVBT_7, | |
| 94 | + /**< DVB-T 7MHzBW (IF: Fc=4.2MHz in default) */ | |
| 95 | + SONY_HELENE_DTV_DVBT_8, | |
| 96 | + /**< DVB-T 8MHzBW (IF: Fc=4.8MHz in default) */ | |
| 97 | + SONY_HELENE_DTV_DVBT2_1_7, | |
| 98 | + /**< DVB-T2 1.7MHzBW (IF: Fc=3.5MHz in default) */ | |
| 99 | + SONY_HELENE_DTV_DVBT2_5, | |
| 100 | + /**< DVB-T2 5MHzBW (IF: Fc=3.6MHz in default) */ | |
| 101 | + SONY_HELENE_DTV_DVBT2_6, | |
| 102 | + /**< DVB-T2 6MHzBW (IF: Fc=3.6MHz in default) */ | |
| 103 | + SONY_HELENE_DTV_DVBT2_7, | |
| 104 | + /**< DVB-T2 7MHzBW (IF: Fc=4.2MHz in default) */ | |
| 105 | + SONY_HELENE_DTV_DVBT2_8, | |
| 106 | + /**< DVB-T2 8MHzBW (IF: Fc=4.8MHz in default) */ | |
| 107 | + SONY_HELENE_DTV_DVBC_6, | |
| 108 | + /**< DVB-C 6MHzBW (IF: Fc=3.7MHz in default) */ | |
| 109 | + SONY_HELENE_DTV_DVBC_8, | |
| 110 | + /**< DVB-C 8MHzBW (IF: Fc=4.9MHz in default) */ | |
| 111 | + SONY_HELENE_DTV_DVBC2_6, | |
| 112 | + /**< DVB-C2 6MHzBW (IF: Fc=3.7MHz in default) */ | |
| 113 | + SONY_HELENE_DTV_DVBC2_8, | |
| 114 | + /**< DVB-C2 8MHzBW (IF: Fc=4.9MHz in default) */ | |
| 115 | + SONY_HELENE_DTV_DTMB, | |
| 116 | + /**< DTMB (IF: Fc=5.1MHz in default) */ | |
| 117 | + /* Satellite */ | |
| 118 | + SONY_HELENE_STV_ISDBS, | |
| 119 | + /**< ISDB-S */ | |
| 120 | + SONY_HELENE_STV_DVBS, | |
| 121 | + /**< DVB-S */ | |
| 122 | + SONY_HELENE_STV_DVBS2, | |
| 123 | + /**< DVB-S2 */ | |
| 124 | + | |
| 125 | + SONY_HELENE_ATV_MIN = SONY_HELENE_ATV_MN_EIAJ, | |
| 126 | + /**< Minimum analog terrestrial system */ | |
| 127 | + SONY_HELENE_ATV_MAX = SONY_HELENE_ATV_L_DASH, | |
| 128 | + /**< Maximum analog terrestrial system */ | |
| 129 | + SONY_HELENE_DTV_MIN = SONY_HELENE_DTV_8VSB, | |
| 130 | + /**< Minimum digital terrestrial system */ | |
| 131 | + SONY_HELENE_DTV_MAX = SONY_HELENE_DTV_DTMB, | |
| 132 | + /**< Maximum digital terrestrial system */ | |
| 133 | + SONY_HELENE_TERR_TV_SYSTEM_NUM, | |
| 134 | + /**< Number of supported terrestrial broadcasting system */ | |
| 135 | + SONY_HELENE_STV_MIN = SONY_HELENE_STV_ISDBS, | |
| 136 | + /**< Minimum satellite system */ | |
| 137 | + SONY_HELENE_STV_MAX = SONY_HELENE_STV_DVBS2 | |
| 138 | + /**< Maximum satellite system */ | |
| 139 | +}; | |
| 140 | + | |
| 141 | +struct helene_terr_adjust_param_t { | |
| 142 | + /* < Addr:0x69 Bit[6:4] : RFVGA gain. | |
| 143 | + * 0xFF means Auto. (RF_GAIN_SEL = 1) | |
| 144 | + */ | |
| 145 | + uint8_t RF_GAIN; | |
| 146 | + /* < Addr:0x69 Bit[3:0] : IF_BPF gain. | |
| 147 | + */ | |
| 148 | + uint8_t IF_BPF_GC; | |
| 149 | + /* < Addr:0x6B Bit[3:0] : RF overload | |
| 150 | + * RF input detect level. (FRF <= 172MHz) | |
| 151 | + */ | |
| 152 | + uint8_t RFOVLD_DET_LV1_VL; | |
| 153 | + /* < Addr:0x6B Bit[3:0] : RF overload | |
| 154 | + * RF input detect level. (172MHz < FRF <= 464MHz) | |
| 155 | + */ | |
| 156 | + uint8_t RFOVLD_DET_LV1_VH; | |
| 157 | + /* < Addr:0x6B Bit[3:0] : RF overload | |
| 158 | + * RF input detect level. (FRF > 464MHz) | |
| 159 | + */ | |
| 160 | + uint8_t RFOVLD_DET_LV1_U; | |
| 161 | + /* < Addr:0x6C Bit[2:0] : | |
| 162 | + * Internal RFAGC detect level. (FRF <= 172MHz) | |
| 163 | + */ | |
| 164 | + uint8_t IFOVLD_DET_LV_VL; | |
| 165 | + /* < Addr:0x6C Bit[2:0] : | |
| 166 | + * Internal RFAGC detect level. (172MHz < FRF <= 464MHz) | |
| 167 | + */ | |
| 168 | + uint8_t IFOVLD_DET_LV_VH; | |
| 169 | + /* < Addr:0x6C Bit[2:0] : | |
| 170 | + * Internal RFAGC detect level. (FRF > 464MHz) | |
| 171 | + */ | |
| 172 | + uint8_t IFOVLD_DET_LV_U; | |
| 173 | + /* < Addr:0x6D Bit[5:4] : | |
| 174 | + * IF filter center offset. | |
| 175 | + */ | |
| 176 | + uint8_t IF_BPF_F0; | |
| 177 | + /* < Addr:0x6D Bit[1:0] : | |
| 178 | + * 6MHzBW(0x00) or 7MHzBW(0x01) | |
| 179 | + * or 8MHzBW(0x02) or 1.7MHzBW(0x03) | |
| 180 | + */ | |
| 181 | + uint8_t BW; | |
| 182 | + /* < Addr:0x6E Bit[4:0] : | |
| 183 | + * 5bit signed. IF offset (kHz) = FIF_OFFSET x 50 | |
| 184 | + */ | |
| 185 | + uint8_t FIF_OFFSET; | |
| 186 | + /* < Addr:0x6F Bit[4:0] : | |
| 187 | + * 5bit signed. BW offset (kHz) = | |
| 188 | + * BW_OFFSET x 50 (BW_OFFSET x 10 in 1.7MHzBW) | |
| 189 | + */ | |
| 190 | + uint8_t BW_OFFSET; | |
| 191 | + /* < Addr:0x9C Bit[0] : | |
| 192 | + * Local polarity. (0: Upper Local, 1: Lower Local) | |
| 193 | + */ | |
| 194 | + uint8_t IS_LOWERLOCAL; | |
| 195 | +}; | |
| 196 | + | |
| 197 | +static const struct helene_terr_adjust_param_t | |
| 198 | +terr_params[SONY_HELENE_TERR_TV_SYSTEM_NUM] = { | |
| 199 | + /*< SONY_HELENE_TV_SYSTEM_UNKNOWN */ | |
| 200 | + {HELENE_AUTO, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 201 | + HELENE_BW_6, HELENE_OFFSET(0), HELENE_OFFSET(0), 0x00}, | |
| 202 | + /* Analog */ | |
| 203 | + /**< SONY_HELENE_ATV_MN_EIAJ (System-M (Japan)) */ | |
| 204 | + {HELENE_AUTO, 0x05, 0x03, 0x06, 0x03, 0x01, 0x01, 0x01, 0x00, | |
| 205 | + HELENE_BW_6, HELENE_OFFSET(0), HELENE_OFFSET(1), 0x00}, | |
| 206 | + /**< SONY_HELENE_ATV_MN_SAP (System-M (US)) */ | |
| 207 | + {HELENE_AUTO, 0x05, 0x03, 0x06, 0x03, 0x01, 0x01, 0x01, 0x00, | |
| 208 | + HELENE_BW_6, HELENE_OFFSET(0), HELENE_OFFSET(1), 0x00}, | |
| 209 | + {HELENE_AUTO, 0x05, 0x03, 0x06, 0x03, 0x01, 0x01, 0x01, 0x00, | |
| 210 | + HELENE_BW_6, HELENE_OFFSET(3), HELENE_OFFSET(1), 0x00}, | |
| 211 | + /**< SONY_HELENE_ATV_MN_A2 (System-M (Korea)) */ | |
| 212 | + {HELENE_AUTO, 0x05, 0x03, 0x06, 0x03, 0x01, 0x01, 0x01, 0x00, | |
| 213 | + HELENE_BW_7, HELENE_OFFSET(11), HELENE_OFFSET(5), 0x00}, | |
| 214 | + /**< SONY_HELENE_ATV_BG (System-B/G) */ | |
| 215 | + {HELENE_AUTO, 0x05, 0x03, 0x06, 0x03, 0x01, 0x01, 0x01, 0x00, | |
| 216 | + HELENE_BW_8, HELENE_OFFSET(2), HELENE_OFFSET(-3), 0x00}, | |
| 217 | + /**< SONY_HELENE_ATV_I (System-I) */ | |
| 218 | + {HELENE_AUTO, 0x05, 0x03, 0x06, 0x03, 0x01, 0x01, 0x01, 0x00, | |
| 219 | + HELENE_BW_8, HELENE_OFFSET(2), HELENE_OFFSET(-3), 0x00}, | |
| 220 | + /**< SONY_HELENE_ATV_DK (System-D/K) */ | |
| 221 | + {HELENE_AUTO, 0x03, 0x04, 0x0A, 0x04, 0x04, 0x04, 0x04, 0x00, | |
| 222 | + HELENE_BW_8, HELENE_OFFSET(2), HELENE_OFFSET(-3), 0x00}, | |
| 223 | + /**< SONY_HELENE_ATV_L (System-L) */ | |
| 224 | + {HELENE_AUTO, 0x03, 0x04, 0x0A, 0x04, 0x04, 0x04, 0x04, 0x00, | |
| 225 | + HELENE_BW_8, HELENE_OFFSET(-1), HELENE_OFFSET(4), 0x00}, | |
| 226 | + /**< SONY_HELENE_ATV_L_DASH (System-L DASH) */ | |
| 227 | + /* Digital */ | |
| 228 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x03, 0x03, 0x03, 0x00, | |
| 229 | + HELENE_BW_6, HELENE_OFFSET(-6), HELENE_OFFSET(-3), 0x00}, | |
| 230 | + /**< SONY_HELENE_DTV_8VSB (ATSC 8VSB) */ | |
| 231 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 232 | + HELENE_BW_6, HELENE_OFFSET(-6), HELENE_OFFSET(-3), 0x00}, | |
| 233 | + /**< SONY_HELENE_DTV_QAM (US QAM) */ | |
| 234 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 235 | + HELENE_BW_6, HELENE_OFFSET(-9), HELENE_OFFSET(-5), 0x00}, | |
| 236 | + /**< SONY_HELENE_DTV_ISDBT_6 (ISDB-T 6MHzBW) */ | |
| 237 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 238 | + HELENE_BW_7, HELENE_OFFSET(-7), HELENE_OFFSET(-6), 0x00}, | |
| 239 | + /**< SONY_HELENE_DTV_ISDBT_7 (ISDB-T 7MHzBW) */ | |
| 240 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 241 | + HELENE_BW_8, HELENE_OFFSET(-5), HELENE_OFFSET(-7), 0x00}, | |
| 242 | + /**< SONY_HELENE_DTV_ISDBT_8 (ISDB-T 8MHzBW) */ | |
| 243 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 244 | + HELENE_BW_6, HELENE_OFFSET(-8), HELENE_OFFSET(-3), 0x00}, | |
| 245 | + /**< SONY_HELENE_DTV_DVBT_5 (DVB-T 5MHzBW) */ | |
| 246 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 247 | + HELENE_BW_6, HELENE_OFFSET(-8), HELENE_OFFSET(-3), 0x00}, | |
| 248 | + /**< SONY_HELENE_DTV_DVBT_6 (DVB-T 6MHzBW) */ | |
| 249 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 250 | + HELENE_BW_7, HELENE_OFFSET(-6), HELENE_OFFSET(-5), 0x00}, | |
| 251 | + /**< SONY_HELENE_DTV_DVBT_7 (DVB-T 7MHzBW) */ | |
| 252 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 253 | + HELENE_BW_8, HELENE_OFFSET(-4), HELENE_OFFSET(-6), 0x00}, | |
| 254 | + /**< SONY_HELENE_DTV_DVBT_8 (DVB-T 8MHzBW) */ | |
| 255 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 256 | + HELENE_BW_1_7, HELENE_OFFSET(-10), HELENE_OFFSET(-10), 0x00}, | |
| 257 | + /**< SONY_HELENE_DTV_DVBT2_1_7 (DVB-T2 1.7MHzBW) */ | |
| 258 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 259 | + HELENE_BW_6, HELENE_OFFSET(-8), HELENE_OFFSET(-3), 0x00}, | |
| 260 | + /**< SONY_HELENE_DTV_DVBT2_5 (DVB-T2 5MHzBW) */ | |
| 261 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 262 | + HELENE_BW_6, HELENE_OFFSET(-8), HELENE_OFFSET(-3), 0x00}, | |
| 263 | + /**< SONY_HELENE_DTV_DVBT2_6 (DVB-T2 6MHzBW) */ | |
| 264 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 265 | + HELENE_BW_7, HELENE_OFFSET(-6), HELENE_OFFSET(-5), 0x00}, | |
| 266 | + /**< SONY_HELENE_DTV_DVBT2_7 (DVB-T2 7MHzBW) */ | |
| 267 | + {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 268 | + HELENE_BW_8, HELENE_OFFSET(-4), HELENE_OFFSET(-6), 0x00}, | |
| 269 | + /**< SONY_HELENE_DTV_DVBT2_8 (DVB-T2 8MHzBW) */ | |
| 270 | + {HELENE_AUTO, 0x05, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, | |
| 271 | + HELENE_BW_6, HELENE_OFFSET(-6), HELENE_OFFSET(-4), 0x00}, | |
| 272 | + /**< SONY_HELENE_DTV_DVBC_6 (DVB-C 6MHzBW) */ | |
| 273 | + {HELENE_AUTO, 0x05, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, | |
| 274 | + HELENE_BW_8, HELENE_OFFSET(-2), HELENE_OFFSET(-3), 0x00}, | |
| 275 | + /**< SONY_HELENE_DTV_DVBC_8 (DVB-C 8MHzBW) */ | |
| 276 | + {HELENE_AUTO, 0x03, 0x09, 0x09, 0x09, 0x02, 0x02, 0x02, 0x00, | |
| 277 | + HELENE_BW_6, HELENE_OFFSET(-6), HELENE_OFFSET(-2), 0x00}, | |
| 278 | + /**< SONY_HELENE_DTV_DVBC2_6 (DVB-C2 6MHzBW) */ | |
| 279 | + {HELENE_AUTO, 0x03, 0x09, 0x09, 0x09, 0x02, 0x02, 0x02, 0x00, | |
| 280 | + HELENE_BW_8, HELENE_OFFSET(-2), HELENE_OFFSET(0), 0x00}, | |
| 281 | + /**< SONY_HELENE_DTV_DVBC2_8 (DVB-C2 8MHzBW) */ | |
| 282 | + {HELENE_AUTO, 0x04, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | |
| 283 | + HELENE_BW_8, HELENE_OFFSET(2), HELENE_OFFSET(1), 0x00} | |
| 284 | + /**< SONY_HELENE_DTV_DTMB (DTMB) */ | |
| 285 | +}; | |
| 286 | + | |
| 287 | +static void helene_i2c_debug(struct helene_priv *priv, | |
| 288 | + u8 reg, u8 write, const u8 *data, u32 len) | |
| 289 | +{ | |
| 290 | + dev_dbg(&priv->i2c->dev, "helene: I2C %s reg 0x%02x size %d\n", | |
| 291 | + (write == 0 ? "read" : "write"), reg, len); | |
| 292 | + print_hex_dump_bytes("helene: I2C data: ", | |
| 293 | + DUMP_PREFIX_OFFSET, data, len); | |
| 294 | +} | |
| 295 | + | |
| 296 | +static int helene_write_regs(struct helene_priv *priv, | |
| 297 | + u8 reg, const u8 *data, u32 len) | |
| 298 | +{ | |
| 299 | + int ret; | |
| 300 | + u8 buf[MAX_WRITE_REGSIZE + 1]; | |
| 301 | + struct i2c_msg msg[1] = { | |
| 302 | + { | |
| 303 | + .addr = priv->i2c_address, | |
| 304 | + .flags = 0, | |
| 305 | + .len = len + 1, | |
| 306 | + .buf = buf, | |
| 307 | + } | |
| 308 | + }; | |
| 309 | + | |
| 310 | + if (len + 1 > sizeof(buf)) { | |
| 311 | + dev_warn(&priv->i2c->dev, | |
| 312 | + "wr reg=%04x: len=%d vs %Zu is too big!\n", | |
| 313 | + reg, len + 1, sizeof(buf)); | |
| 314 | + return -E2BIG; | |
| 315 | + } | |
| 316 | + | |
| 317 | + helene_i2c_debug(priv, reg, 1, data, len); | |
| 318 | + buf[0] = reg; | |
| 319 | + memcpy(&buf[1], data, len); | |
| 320 | + ret = i2c_transfer(priv->i2c, msg, 1); | |
| 321 | + if (ret >= 0 && ret != 1) | |
| 322 | + ret = -EREMOTEIO; | |
| 323 | + if (ret < 0) { | |
| 324 | + dev_warn(&priv->i2c->dev, | |
| 325 | + "%s: i2c wr failed=%d reg=%02x len=%d\n", | |
| 326 | + KBUILD_MODNAME, ret, reg, len); | |
| 327 | + return ret; | |
| 328 | + } | |
| 329 | + return 0; | |
| 330 | +} | |
| 331 | + | |
| 332 | +static int helene_write_reg(struct helene_priv *priv, u8 reg, u8 val) | |
| 333 | +{ | |
| 334 | + return helene_write_regs(priv, reg, &val, 1); | |
| 335 | +} | |
| 336 | + | |
| 337 | +static int helene_read_regs(struct helene_priv *priv, | |
| 338 | + u8 reg, u8 *val, u32 len) | |
| 339 | +{ | |
| 340 | + int ret; | |
| 341 | + struct i2c_msg msg[2] = { | |
| 342 | + { | |
| 343 | + .addr = priv->i2c_address, | |
| 344 | + .flags = 0, | |
| 345 | + .len = 1, | |
| 346 | + .buf = ®, | |
| 347 | + }, { | |
| 348 | + .addr = priv->i2c_address, | |
| 349 | + .flags = I2C_M_RD, | |
| 350 | + .len = len, | |
| 351 | + .buf = val, | |
| 352 | + } | |
| 353 | + }; | |
| 354 | + | |
| 355 | + ret = i2c_transfer(priv->i2c, &msg[0], 1); | |
| 356 | + if (ret >= 0 && ret != 1) | |
| 357 | + ret = -EREMOTEIO; | |
| 358 | + if (ret < 0) { | |
| 359 | + dev_warn(&priv->i2c->dev, | |
| 360 | + "%s: I2C rw failed=%d addr=%02x reg=%02x\n", | |
| 361 | + KBUILD_MODNAME, ret, priv->i2c_address, reg); | |
| 362 | + return ret; | |
| 363 | + } | |
| 364 | + ret = i2c_transfer(priv->i2c, &msg[1], 1); | |
| 365 | + if (ret >= 0 && ret != 1) | |
| 366 | + ret = -EREMOTEIO; | |
| 367 | + if (ret < 0) { | |
| 368 | + dev_warn(&priv->i2c->dev, | |
| 369 | + "%s: i2c rd failed=%d addr=%02x reg=%02x\n", | |
| 370 | + KBUILD_MODNAME, ret, priv->i2c_address, reg); | |
| 371 | + return ret; | |
| 372 | + } | |
| 373 | + helene_i2c_debug(priv, reg, 0, val, len); | |
| 374 | + return 0; | |
| 375 | +} | |
| 376 | + | |
| 377 | +static int helene_read_reg(struct helene_priv *priv, u8 reg, u8 *val) | |
| 378 | +{ | |
| 379 | + return helene_read_regs(priv, reg, val, 1); | |
| 380 | +} | |
| 381 | + | |
| 382 | +static int helene_set_reg_bits(struct helene_priv *priv, | |
| 383 | + u8 reg, u8 data, u8 mask) | |
| 384 | +{ | |
| 385 | + int res; | |
| 386 | + u8 rdata; | |
| 387 | + | |
| 388 | + if (mask != 0xff) { | |
| 389 | + res = helene_read_reg(priv, reg, &rdata); | |
| 390 | + if (res != 0) | |
| 391 | + return res; | |
| 392 | + data = ((data & mask) | (rdata & (mask ^ 0xFF))); | |
| 393 | + } | |
| 394 | + return helene_write_reg(priv, reg, data); | |
| 395 | +} | |
| 396 | + | |
| 397 | +static int helene_enter_power_save(struct helene_priv *priv) | |
| 398 | +{ | |
| 399 | + dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 400 | + if (priv->state == STATE_SLEEP) | |
| 401 | + return 0; | |
| 402 | + | |
| 403 | + /* Standby setting for CPU */ | |
| 404 | + helene_write_reg(priv, 0x88, 0x0); | |
| 405 | + | |
| 406 | + /* Standby setting for internal logic block */ | |
| 407 | + helene_write_reg(priv, 0x87, 0xC0); | |
| 408 | + | |
| 409 | + priv->state = STATE_SLEEP; | |
| 410 | + return 0; | |
| 411 | +} | |
| 412 | + | |
| 413 | +static int helene_leave_power_save(struct helene_priv *priv) | |
| 414 | +{ | |
| 415 | + dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 416 | + if (priv->state == STATE_ACTIVE) | |
| 417 | + return 0; | |
| 418 | + | |
| 419 | + /* Standby setting for internal logic block */ | |
| 420 | + helene_write_reg(priv, 0x87, 0xC4); | |
| 421 | + | |
| 422 | + /* Standby setting for CPU */ | |
| 423 | + helene_write_reg(priv, 0x88, 0x40); | |
| 424 | + | |
| 425 | + priv->state = STATE_ACTIVE; | |
| 426 | + return 0; | |
| 427 | +} | |
| 428 | + | |
| 429 | +static int helene_init(struct dvb_frontend *fe) | |
| 430 | +{ | |
| 431 | + struct helene_priv *priv = fe->tuner_priv; | |
| 432 | + | |
| 433 | + dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 434 | + return helene_leave_power_save(priv); | |
| 435 | +} | |
| 436 | + | |
| 437 | +static int helene_release(struct dvb_frontend *fe) | |
| 438 | +{ | |
| 439 | + struct helene_priv *priv = fe->tuner_priv; | |
| 440 | + | |
| 441 | + dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 442 | + kfree(fe->tuner_priv); | |
| 443 | + fe->tuner_priv = NULL; | |
| 444 | + return 0; | |
| 445 | +} | |
| 446 | + | |
| 447 | +static int helene_sleep(struct dvb_frontend *fe) | |
| 448 | +{ | |
| 449 | + struct helene_priv *priv = fe->tuner_priv; | |
| 450 | + | |
| 451 | + dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | |
| 452 | + helene_enter_power_save(priv); | |
| 453 | + return 0; | |
| 454 | +} | |
| 455 | + | |
| 456 | +static enum helene_tv_system_t helene_get_tv_system(struct dvb_frontend *fe) | |
| 457 | +{ | |
| 458 | + enum helene_tv_system_t system = SONY_HELENE_TV_SYSTEM_UNKNOWN; | |
| 459 | + struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
| 460 | + struct helene_priv *priv = fe->tuner_priv; | |
| 461 | + | |
| 462 | + if (p->delivery_system == SYS_DVBT) { | |
| 463 | + if (p->bandwidth_hz <= 5000000) | |
| 464 | + system = SONY_HELENE_DTV_DVBT_5; | |
| 465 | + else if (p->bandwidth_hz <= 6000000) | |
| 466 | + system = SONY_HELENE_DTV_DVBT_6; | |
| 467 | + else if (p->bandwidth_hz <= 7000000) | |
| 468 | + system = SONY_HELENE_DTV_DVBT_7; | |
| 469 | + else if (p->bandwidth_hz <= 8000000) | |
| 470 | + system = SONY_HELENE_DTV_DVBT_8; | |
| 471 | + else { | |
| 472 | + system = SONY_HELENE_DTV_DVBT_8; | |
| 473 | + p->bandwidth_hz = 8000000; | |
| 474 | + } | |
| 475 | + } else if (p->delivery_system == SYS_DVBT2) { | |
| 476 | + if (p->bandwidth_hz <= 5000000) | |
| 477 | + system = SONY_HELENE_DTV_DVBT2_5; | |
| 478 | + else if (p->bandwidth_hz <= 6000000) | |
| 479 | + system = SONY_HELENE_DTV_DVBT2_6; | |
| 480 | + else if (p->bandwidth_hz <= 7000000) | |
| 481 | + system = SONY_HELENE_DTV_DVBT2_7; | |
| 482 | + else if (p->bandwidth_hz <= 8000000) | |
| 483 | + system = SONY_HELENE_DTV_DVBT2_8; | |
| 484 | + else { | |
| 485 | + system = SONY_HELENE_DTV_DVBT2_8; | |
| 486 | + p->bandwidth_hz = 8000000; | |
| 487 | + } | |
| 488 | + } else if (p->delivery_system == SYS_DVBS) { | |
| 489 | + system = SONY_HELENE_STV_DVBS; | |
| 490 | + } else if (p->delivery_system == SYS_DVBS2) { | |
| 491 | + system = SONY_HELENE_STV_DVBS2; | |
| 492 | + } else if (p->delivery_system == SYS_ISDBS) { | |
| 493 | + system = SONY_HELENE_STV_ISDBS; | |
| 494 | + } else if (p->delivery_system == SYS_ISDBT) { | |
| 495 | + if (p->bandwidth_hz <= 6000000) | |
| 496 | + system = SONY_HELENE_DTV_ISDBT_6; | |
| 497 | + else if (p->bandwidth_hz <= 7000000) | |
| 498 | + system = SONY_HELENE_DTV_ISDBT_7; | |
| 499 | + else if (p->bandwidth_hz <= 8000000) | |
| 500 | + system = SONY_HELENE_DTV_ISDBT_8; | |
| 501 | + else { | |
| 502 | + system = SONY_HELENE_DTV_ISDBT_8; | |
| 503 | + p->bandwidth_hz = 8000000; | |
| 504 | + } | |
| 505 | + } else if (p->delivery_system == SYS_DVBC_ANNEX_A) { | |
| 506 | + if (p->bandwidth_hz <= 6000000) | |
| 507 | + system = SONY_HELENE_DTV_DVBC_6; | |
| 508 | + else if (p->bandwidth_hz <= 8000000) | |
| 509 | + system = SONY_HELENE_DTV_DVBC_8; | |
| 510 | + } | |
| 511 | + dev_dbg(&priv->i2c->dev, | |
| 512 | + "%s(): HELENE DTV system %d (delsys %d, bandwidth %d)\n", | |
| 513 | + __func__, (int)system, p->delivery_system, | |
| 514 | + p->bandwidth_hz); | |
| 515 | + return system; | |
| 516 | +} | |
| 517 | + | |
| 518 | +static int helene_set_params_s(struct dvb_frontend *fe) | |
| 519 | +{ | |
| 520 | + u8 data[MAX_WRITE_REGSIZE]; | |
| 521 | + u32 frequency; | |
| 522 | + enum helene_tv_system_t tv_system; | |
| 523 | + struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
| 524 | + struct helene_priv *priv = fe->tuner_priv; | |
| 525 | + int frequencykHz = p->frequency; | |
| 526 | + uint32_t frequency4kHz = 0; | |
| 527 | + u32 symbol_rate = p->symbol_rate/1000; | |
| 528 | + | |
| 529 | + dev_dbg(&priv->i2c->dev, "%s(): tune frequency %dkHz sr=%uKsps\n", | |
| 530 | + __func__, frequencykHz, symbol_rate); | |
| 531 | + tv_system = helene_get_tv_system(fe); | |
| 532 | + | |
| 533 | + if (tv_system == SONY_HELENE_TV_SYSTEM_UNKNOWN) { | |
| 534 | + dev_err(&priv->i2c->dev, "%s(): unknown DTV system\n", | |
| 535 | + __func__); | |
| 536 | + return -EINVAL; | |
| 537 | + } | |
| 538 | + /* RF switch turn to satellite */ | |
| 539 | + if (priv->set_tuner) | |
| 540 | + priv->set_tuner(priv->set_tuner_data, 0); | |
| 541 | + frequency = roundup(p->frequency / 1000, 1); | |
| 542 | + | |
| 543 | + /* Disable IF signal output */ | |
| 544 | + helene_write_reg(priv, 0x15, 0x02); | |
| 545 | + | |
| 546 | + /* RFIN matching in power save (Sat) reset */ | |
| 547 | + helene_write_reg(priv, 0x43, 0x06); | |
| 548 | + | |
| 549 | + /* Analog block setting (0x6A, 0x6B) */ | |
| 550 | + data[0] = 0x00; | |
| 551 | + data[1] = 0x00; | |
| 552 | + helene_write_regs(priv, 0x6A, data, 2); | |
| 553 | + helene_write_reg(priv, 0x75, 0x99); | |
| 554 | + helene_write_reg(priv, 0x9D, 0x00); | |
| 555 | + | |
| 556 | + /* Tuning setting for CPU (0x61) */ | |
| 557 | + helene_write_reg(priv, 0x61, 0x07); | |
| 558 | + | |
| 559 | + /* Satellite mode select (0x01) */ | |
| 560 | + helene_write_reg(priv, 0x01, 0x01); | |
| 561 | + | |
| 562 | + /* Clock enable for internal logic block, CPU wake-up (0x04, 0x05) */ | |
| 563 | + data[0] = 0xC4; | |
| 564 | + data[1] = 0x40; | |
| 565 | + | |
| 566 | + switch (priv->xtal) { | |
| 567 | + case SONY_HELENE_XTAL_16000: | |
| 568 | + data[2] = 0x02; | |
| 569 | + break; | |
| 570 | + case SONY_HELENE_XTAL_20500: | |
| 571 | + data[2] = 0x02; | |
| 572 | + break; | |
| 573 | + case SONY_HELENE_XTAL_24000: | |
| 574 | + data[2] = 0x03; | |
| 575 | + break; | |
| 576 | + case SONY_HELENE_XTAL_41000: | |
| 577 | + data[2] = 0x05; | |
| 578 | + break; | |
| 579 | + default: | |
| 580 | + dev_err(&priv->i2c->dev, "%s(): unknown xtal %d\n", | |
| 581 | + __func__, priv->xtal); | |
| 582 | + return -EINVAL; | |
| 583 | + } | |
| 584 | + | |
| 585 | + /* Setting for analog block (0x07). LOOPFILTER INTERNAL */ | |
| 586 | + data[3] = 0x80; | |
| 587 | + | |
| 588 | + /* Tuning setting for analog block | |
| 589 | + * (0x08, 0x09, 0x0A, 0x0B). LOOPFILTER INTERNAL | |
| 590 | + */ | |
| 591 | + if (priv->xtal == SONY_HELENE_XTAL_20500) | |
| 592 | + data[4] = 0x58; | |
| 593 | + else | |
| 594 | + data[4] = 0x70; | |
| 595 | + | |
| 596 | + data[5] = 0x1E; | |
| 597 | + data[6] = 0x02; | |
| 598 | + data[7] = 0x24; | |
| 599 | + | |
| 600 | + /* Enable for analog block (0x0C, 0x0D, 0x0E). SAT LNA ON */ | |
| 601 | + data[8] = 0x0F; | |
| 602 | + data[8] |= 0xE0; /* POWERSAVE_TERR_RF_ACTIVE */ | |
| 603 | + data[9] = 0x02; | |
| 604 | + data[10] = 0x1E; | |
| 605 | + | |
| 606 | + /* Setting for LPF cutoff frequency (0x0F) */ | |
| 607 | + switch (tv_system) { | |
| 608 | + case SONY_HELENE_STV_ISDBS: | |
| 609 | + data[11] = 0x22; /* 22MHz */ | |
| 610 | + break; | |
| 611 | + case SONY_HELENE_STV_DVBS: | |
| 612 | + if (symbol_rate <= 4000) | |
| 613 | + data[11] = 0x05; | |
| 614 | + else if (symbol_rate <= 10000) | |
| 615 | + data[11] = (uint8_t)((symbol_rate * 47 | |
| 616 | + + (40000-1)) / 40000); | |
| 617 | + else | |
| 618 | + data[11] = (uint8_t)((symbol_rate * 27 | |
| 619 | + + (40000-1)) / 40000 + 5); | |
| 620 | + | |
| 621 | + if (data[11] > 36) | |
| 622 | + data[11] = 36; /* 5 <= lpf_cutoff <= 36 is valid */ | |
| 623 | + break; | |
| 624 | + case SONY_HELENE_STV_DVBS2: | |
| 625 | + if (symbol_rate <= 4000) | |
| 626 | + data[11] = 0x05; | |
| 627 | + else if (symbol_rate <= 10000) | |
| 628 | + data[11] = (uint8_t)((symbol_rate * 11 | |
| 629 | + + (10000-1)) / 10000); | |
| 630 | + else | |
| 631 | + data[11] = (uint8_t)((symbol_rate * 3 | |
| 632 | + + (5000-1)) / 5000 + 5); | |
| 633 | + | |
| 634 | + if (data[11] > 36) | |
| 635 | + data[11] = 36; /* 5 <= lpf_cutoff <= 36 is valid */ | |
| 636 | + break; | |
| 637 | + default: | |
| 638 | + dev_err(&priv->i2c->dev, "%s(): unknown standard %d\n", | |
| 639 | + __func__, tv_system); | |
| 640 | + return -EINVAL; | |
| 641 | + } | |
| 642 | + | |
| 643 | + /* RF tuning frequency setting (0x10, 0x11, 0x12) */ | |
| 644 | + frequency4kHz = (frequencykHz + 2) / 4; | |
| 645 | + data[12] = (uint8_t)(frequency4kHz & 0xFF); /* FRF_L */ | |
| 646 | + data[13] = (uint8_t)((frequency4kHz >> 8) & 0xFF); /* FRF_M */ | |
| 647 | + /* FRF_H (bit[3:0]) */ | |
| 648 | + data[14] = (uint8_t)((frequency4kHz >> 16) & 0x0F); | |
| 649 | + | |
| 650 | + /* Tuning command (0x13) */ | |
| 651 | + data[15] = 0xFF; | |
| 652 | + | |
| 653 | + /* Setting for IQOUT_LIMIT (0x14) 0.75Vpp */ | |
| 654 | + data[16] = 0x00; | |
| 655 | + | |
| 656 | + /* Enable IQ output (0x15) */ | |
| 657 | + data[17] = 0x01; | |
| 658 | + | |
| 659 | + helene_write_regs(priv, 0x04, data, 18); | |
| 660 | + | |
| 661 | + dev_dbg(&priv->i2c->dev, "%s(): tune done\n", | |
| 662 | + __func__); | |
| 663 | + | |
| 664 | + priv->frequency = frequency; | |
| 665 | + return 0; | |
| 666 | +} | |
| 667 | + | |
| 668 | +static int helene_set_params(struct dvb_frontend *fe) | |
| 669 | +{ | |
| 670 | + u8 data[MAX_WRITE_REGSIZE]; | |
| 671 | + u32 frequency; | |
| 672 | + enum helene_tv_system_t tv_system; | |
| 673 | + struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
| 674 | + struct helene_priv *priv = fe->tuner_priv; | |
| 675 | + int frequencykHz = p->frequency / 1000; | |
| 676 | + | |
| 677 | + dev_dbg(&priv->i2c->dev, "%s(): tune frequency %dkHz\n", | |
| 678 | + __func__, frequencykHz); | |
| 679 | + tv_system = helene_get_tv_system(fe); | |
| 680 | + | |
| 681 | + if (tv_system == SONY_HELENE_TV_SYSTEM_UNKNOWN) { | |
| 682 | + dev_dbg(&priv->i2c->dev, "%s(): unknown DTV system\n", | |
| 683 | + __func__); | |
| 684 | + return -EINVAL; | |
| 685 | + } | |
| 686 | + if (priv->set_tuner) | |
| 687 | + priv->set_tuner(priv->set_tuner_data, 1); | |
| 688 | + frequency = roundup(p->frequency / 1000, 25); | |
| 689 | + | |
| 690 | + /* mode select */ | |
| 691 | + helene_write_reg(priv, 0x01, 0x00); | |
| 692 | + | |
| 693 | + /* Disable IF signal output */ | |
| 694 | + helene_write_reg(priv, 0x74, 0x02); | |
| 695 | + | |
| 696 | + if (priv->state == STATE_SLEEP) | |
| 697 | + helene_leave_power_save(priv); | |
| 698 | + | |
| 699 | + /* Initial setting for internal analog block (0x91, 0x92) */ | |
| 700 | + if ((tv_system == SONY_HELENE_DTV_DVBC_6) || | |
| 701 | + (tv_system == SONY_HELENE_DTV_DVBC_8)) { | |
| 702 | + data[0] = 0x16; | |
| 703 | + data[1] = 0x26; | |
| 704 | + } else { | |
| 705 | + data[0] = 0x10; | |
| 706 | + data[1] = 0x20; | |
| 707 | + } | |
| 708 | + helene_write_regs(priv, 0x91, data, 2); | |
| 709 | + | |
| 710 | + /* Setting for analog block */ | |
| 711 | + if (TERR_INTERNAL_LOOPFILTER_AVAILABLE(tv_system)) | |
| 712 | + data[0] = 0x90; | |
| 713 | + else | |
| 714 | + data[0] = 0x00; | |
| 715 | + | |
| 716 | + /* Setting for local polarity (0x9D) */ | |
| 717 | + data[1] = (uint8_t)(terr_params[tv_system].IS_LOWERLOCAL & 0x01); | |
| 718 | + helene_write_regs(priv, 0x9C, data, 2); | |
| 719 | + | |
| 720 | + /* Enable for analog block */ | |
| 721 | + data[0] = 0xEE; | |
| 722 | + data[1] = 0x02; | |
| 723 | + data[2] = 0x1E; | |
| 724 | + data[3] = 0x67; /* Tuning setting for CPU */ | |
| 725 | + | |
| 726 | + /* Setting for PLL reference divider for xtal=24MHz */ | |
| 727 | + if ((tv_system == SONY_HELENE_DTV_DVBC_6) || | |
| 728 | + (tv_system == SONY_HELENE_DTV_DVBC_8)) | |
| 729 | + data[4] = 0x18; | |
| 730 | + else | |
| 731 | + data[4] = 0x03; | |
| 732 | + | |
| 733 | + /* Tuning setting for analog block */ | |
| 734 | + if (TERR_INTERNAL_LOOPFILTER_AVAILABLE(tv_system)) { | |
| 735 | + data[5] = 0x38; | |
| 736 | + data[6] = 0x1E; | |
| 737 | + data[7] = 0x02; | |
| 738 | + data[8] = 0x24; | |
| 739 | + } else if ((tv_system == SONY_HELENE_DTV_DVBC_6) || | |
| 740 | + (tv_system == SONY_HELENE_DTV_DVBC_8)) { | |
| 741 | + data[5] = 0x1C; | |
| 742 | + data[6] = 0x78; | |
| 743 | + data[7] = 0x08; | |
| 744 | + data[8] = 0x1C; | |
| 745 | + } else { | |
| 746 | + data[5] = 0xB4; | |
| 747 | + data[6] = 0x78; | |
| 748 | + data[7] = 0x08; | |
| 749 | + data[8] = 0x30; | |
| 750 | + } | |
| 751 | + helene_write_regs(priv, 0x5E, data, 9); | |
| 752 | + | |
| 753 | + /* LT_AMP_EN should be 0 */ | |
| 754 | + helene_set_reg_bits(priv, 0x67, 0x0, 0x02); | |
| 755 | + | |
| 756 | + /* Setting for IFOUT_LIMIT */ | |
| 757 | + data[0] = 0x00; /* 1.5Vpp */ | |
| 758 | + | |
| 759 | + /* RF_GAIN setting */ | |
| 760 | + if (terr_params[tv_system].RF_GAIN == HELENE_AUTO) | |
| 761 | + data[1] = 0x80; /* RF_GAIN_SEL = 1 */ | |
| 762 | + else | |
| 763 | + data[1] = (uint8_t)((terr_params[tv_system].RF_GAIN | |
| 764 | + << 4) & 0x70); | |
| 765 | + | |
| 766 | + /* IF_BPF_GC setting */ | |
| 767 | + data[1] |= (uint8_t)(terr_params[tv_system].IF_BPF_GC & 0x0F); | |
| 768 | + | |
| 769 | + /* Setting for internal RFAGC (0x6A, 0x6B, 0x6C) */ | |
| 770 | + data[2] = 0x00; | |
| 771 | + if (frequencykHz <= 172000) { | |
| 772 | + data[3] = (uint8_t)(terr_params[tv_system].RFOVLD_DET_LV1_VL | |
| 773 | + & 0x0F); | |
| 774 | + data[4] = (uint8_t)(terr_params[tv_system].IFOVLD_DET_LV_VL | |
| 775 | + & 0x07); | |
| 776 | + } else if (frequencykHz <= 464000) { | |
| 777 | + data[3] = (uint8_t)(terr_params[tv_system].RFOVLD_DET_LV1_VH | |
| 778 | + & 0x0F); | |
| 779 | + data[4] = (uint8_t)(terr_params[tv_system].IFOVLD_DET_LV_VH | |
| 780 | + & 0x07); | |
| 781 | + } else { | |
| 782 | + data[3] = (uint8_t)(terr_params[tv_system].RFOVLD_DET_LV1_U | |
| 783 | + & 0x0F); | |
| 784 | + data[4] = (uint8_t)(terr_params[tv_system].IFOVLD_DET_LV_U | |
| 785 | + & 0x07); | |
| 786 | + } | |
| 787 | + data[4] |= 0x20; | |
| 788 | + | |
| 789 | + /* Setting for IF frequency and bandwidth */ | |
| 790 | + | |
| 791 | + /* IF filter center frequency offset (IF_BPF_F0) (0x6D) */ | |
| 792 | + data[5] = (uint8_t)((terr_params[tv_system].IF_BPF_F0 << 4) & 0x30); | |
| 793 | + | |
| 794 | + /* IF filter band width (BW) (0x6D) */ | |
| 795 | + data[5] |= (uint8_t)(terr_params[tv_system].BW & 0x03); | |
| 796 | + | |
| 797 | + /* IF frequency offset value (FIF_OFFSET) (0x6E) */ | |
| 798 | + data[6] = (uint8_t)(terr_params[tv_system].FIF_OFFSET & 0x1F); | |
| 799 | + | |
| 800 | + /* IF band width offset value (BW_OFFSET) (0x6F) */ | |
| 801 | + data[7] = (uint8_t)(terr_params[tv_system].BW_OFFSET & 0x1F); | |
| 802 | + | |
| 803 | + /* RF tuning frequency setting (0x70, 0x71, 0x72) */ | |
| 804 | + data[8] = (uint8_t)(frequencykHz & 0xFF); /* FRF_L */ | |
| 805 | + data[9] = (uint8_t)((frequencykHz >> 8) & 0xFF); /* FRF_M */ | |
| 806 | + data[10] = (uint8_t)((frequencykHz >> 16) | |
| 807 | + & 0x0F); /* FRF_H (bit[3:0]) */ | |
| 808 | + | |
| 809 | + /* Tuning command */ | |
| 810 | + data[11] = 0xFF; | |
| 811 | + | |
| 812 | + /* Enable IF output, AGC and IFOUT pin selection (0x74) */ | |
| 813 | + data[12] = 0x01; | |
| 814 | + | |
| 815 | + if ((tv_system == SONY_HELENE_DTV_DVBC_6) || | |
| 816 | + (tv_system == SONY_HELENE_DTV_DVBC_8)) { | |
| 817 | + data[13] = 0xD9; | |
| 818 | + data[14] = 0x0F; | |
| 819 | + data[15] = 0x24; | |
| 820 | + data[16] = 0x87; | |
| 821 | + } else { | |
| 822 | + data[13] = 0x99; | |
| 823 | + data[14] = 0x00; | |
| 824 | + data[15] = 0x24; | |
| 825 | + data[16] = 0x87; | |
| 826 | + } | |
| 827 | + | |
| 828 | + helene_write_regs(priv, 0x68, data, 17); | |
| 829 | + | |
| 830 | + dev_dbg(&priv->i2c->dev, "%s(): tune done\n", | |
| 831 | + __func__); | |
| 832 | + | |
| 833 | + priv->frequency = frequency; | |
| 834 | + return 0; | |
| 835 | +} | |
| 836 | + | |
| 837 | +static int helene_get_frequency(struct dvb_frontend *fe, u32 *frequency) | |
| 838 | +{ | |
| 839 | + struct helene_priv *priv = fe->tuner_priv; | |
| 840 | + | |
| 841 | + *frequency = priv->frequency * 1000; | |
| 842 | + return 0; | |
| 843 | +} | |
| 844 | + | |
| 845 | +static struct dvb_tuner_ops helene_tuner_ops = { | |
| 846 | + .info = { | |
| 847 | + .name = "Sony HELENE Ter tuner", | |
| 848 | + .frequency_min = 1000000, | |
| 849 | + .frequency_max = 1200000000, | |
| 850 | + .frequency_step = 25000, | |
| 851 | + }, | |
| 852 | + .init = helene_init, | |
| 853 | + .release = helene_release, | |
| 854 | + .sleep = helene_sleep, | |
| 855 | + .set_params = helene_set_params, | |
| 856 | + .get_frequency = helene_get_frequency, | |
| 857 | +}; | |
| 858 | + | |
| 859 | +static struct dvb_tuner_ops helene_tuner_ops_s = { | |
| 860 | + .info = { | |
| 861 | + .name = "Sony HELENE Sat tuner", | |
| 862 | + .frequency_min = 500000, | |
| 863 | + .frequency_max = 2500000, | |
| 864 | + .frequency_step = 1000, | |
| 865 | + }, | |
| 866 | + .init = helene_init, | |
| 867 | + .release = helene_release, | |
| 868 | + .sleep = helene_sleep, | |
| 869 | + .set_params = helene_set_params_s, | |
| 870 | + .get_frequency = helene_get_frequency, | |
| 871 | +}; | |
| 872 | + | |
| 873 | +/* power-on tuner | |
| 874 | + * call once after reset | |
| 875 | + */ | |
| 876 | +static int helene_x_pon(struct helene_priv *priv) | |
| 877 | +{ | |
| 878 | + /* RFIN matching in power save (terrestrial) = ACTIVE */ | |
| 879 | + /* RFIN matching in power save (satellite) = ACTIVE */ | |
| 880 | + u8 dataT[] = { 0x06, 0x00, 0x02, 0x00 }; | |
| 881 | + /* SAT_RF_ACTIVE = true, lnaOff = false, terrRfActive = true */ | |
| 882 | + u8 dataS[] = { 0x05, 0x06 }; | |
| 883 | + u8 cdata[] = {0x7A, 0x01}; | |
| 884 | + u8 data[20]; | |
| 885 | + u8 rdata[2]; | |
| 886 | + | |
| 887 | + /* mode select */ | |
| 888 | + helene_write_reg(priv, 0x01, 0x00); | |
| 889 | + | |
| 890 | + helene_write_reg(priv, 0x67, dataT[3]); | |
| 891 | + helene_write_reg(priv, 0x43, dataS[1]); | |
| 892 | + helene_write_regs(priv, 0x5E, dataT, 3); | |
| 893 | + helene_write_reg(priv, 0x0C, dataS[0]); | |
| 894 | + | |
| 895 | + /* Initial setting for internal logic block */ | |
| 896 | + helene_write_regs(priv, 0x99, cdata, sizeof(cdata)); | |
| 897 | + | |
| 898 | + /* 0x81 - 0x94 */ | |
| 899 | + data[0] = 0x18; /* xtal 24 MHz */ | |
| 900 | + data[1] = (uint8_t)(0x80 | (0x04 & 0x1F)); /* 4 x 25 = 100uA */ | |
| 901 | + data[2] = (uint8_t)(0x80 | (0x26 & 0x7F)); /* 38 x 0.25 = 9.5pF */ | |
| 902 | + data[3] = 0x80; /* REFOUT signal output 500mVpp */ | |
| 903 | + data[4] = 0x00; /* GPIO settings */ | |
| 904 | + data[5] = 0x00; /* GPIO settings */ | |
| 905 | + data[6] = 0xC4; /* Clock enable for internal logic block */ | |
| 906 | + data[7] = 0x40; /* Start CPU boot-up */ | |
| 907 | + data[8] = 0x10; /* For burst-write */ | |
| 908 | + | |
| 909 | + /* Setting for internal RFAGC */ | |
| 910 | + data[9] = 0x00; | |
| 911 | + data[10] = 0x45; | |
| 912 | + data[11] = 0x75; | |
| 913 | + | |
| 914 | + data[12] = 0x07; /* Setting for analog block */ | |
| 915 | + | |
| 916 | + /* Initial setting for internal analog block */ | |
| 917 | + data[13] = 0x1C; | |
| 918 | + data[14] = 0x3F; | |
| 919 | + data[15] = 0x02; | |
| 920 | + data[16] = 0x10; | |
| 921 | + data[17] = 0x20; | |
| 922 | + data[18] = 0x0A; | |
| 923 | + data[19] = 0x00; | |
| 924 | + | |
| 925 | + helene_write_regs(priv, 0x81, data, sizeof(data)); | |
| 926 | + | |
| 927 | + /* Setting for internal RFAGC */ | |
| 928 | + helene_write_reg(priv, 0x9B, 0x00); | |
| 929 | + | |
| 930 | + msleep(20); | |
| 931 | + | |
| 932 | + /* Check CPU_STT/CPU_ERR */ | |
| 933 | + helene_read_regs(priv, 0x1A, rdata, sizeof(rdata)); | |
| 934 | + | |
| 935 | + if (rdata[0] != 0x00) { | |
| 936 | + dev_err(&priv->i2c->dev, | |
| 937 | + "HELENE tuner CPU error 0x%x\n", rdata[0]); | |
| 938 | + return -EIO; | |
| 939 | + } | |
| 940 | + | |
| 941 | + /* VCO current setting */ | |
| 942 | + cdata[0] = 0x90; | |
| 943 | + cdata[1] = 0x06; | |
| 944 | + helene_write_regs(priv, 0x17, cdata, sizeof(cdata)); | |
| 945 | + msleep(20); | |
| 946 | + helene_read_reg(priv, 0x19, data); | |
| 947 | + helene_write_reg(priv, 0x95, (uint8_t)((data[0] >> 4) & 0x0F)); | |
| 948 | + | |
| 949 | + /* Disable IF signal output */ | |
| 950 | + helene_write_reg(priv, 0x74, 0x02); | |
| 951 | + | |
| 952 | + /* Standby setting for CPU */ | |
| 953 | + helene_write_reg(priv, 0x88, 0x00); | |
| 954 | + | |
| 955 | + /* Standby setting for internal logic block */ | |
| 956 | + helene_write_reg(priv, 0x87, 0xC0); | |
| 957 | + | |
| 958 | + /* Load capacitance control setting for crystal oscillator */ | |
| 959 | + helene_write_reg(priv, 0x80, 0x01); | |
| 960 | + | |
| 961 | + /* Satellite initial setting */ | |
| 962 | + cdata[0] = 0x07; | |
| 963 | + cdata[1] = 0x00; | |
| 964 | + helene_write_regs(priv, 0x41, cdata, sizeof(cdata)); | |
| 965 | + | |
| 966 | + dev_info(&priv->i2c->dev, | |
| 967 | + "HELENE tuner x_pon done\n"); | |
| 968 | + | |
| 969 | + return 0; | |
| 970 | +} | |
| 971 | + | |
| 972 | +struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe, | |
| 973 | + const struct helene_config *config, | |
| 974 | + struct i2c_adapter *i2c) | |
| 975 | +{ | |
| 976 | + struct helene_priv *priv = NULL; | |
| 977 | + | |
| 978 | + priv = kzalloc(sizeof(struct helene_priv), GFP_KERNEL); | |
| 979 | + if (priv == NULL) | |
| 980 | + return NULL; | |
| 981 | + priv->i2c_address = (config->i2c_address >> 1); | |
| 982 | + priv->i2c = i2c; | |
| 983 | + priv->set_tuner_data = config->set_tuner_priv; | |
| 984 | + priv->set_tuner = config->set_tuner_callback; | |
| 985 | + priv->xtal = config->xtal; | |
| 986 | + | |
| 987 | + if (fe->ops.i2c_gate_ctrl) | |
| 988 | + fe->ops.i2c_gate_ctrl(fe, 1); | |
| 989 | + | |
| 990 | + if (helene_x_pon(priv) != 0) | |
| 991 | + return NULL; | |
| 992 | + | |
| 993 | + if (fe->ops.i2c_gate_ctrl) | |
| 994 | + fe->ops.i2c_gate_ctrl(fe, 0); | |
| 995 | + | |
| 996 | + memcpy(&fe->ops.tuner_ops, &helene_tuner_ops_s, | |
| 997 | + sizeof(struct dvb_tuner_ops)); | |
| 998 | + fe->tuner_priv = priv; | |
| 999 | + dev_info(&priv->i2c->dev, | |
| 1000 | + "Sony HELENE Sat attached on addr=%x at I2C adapter %p\n", | |
| 1001 | + priv->i2c_address, priv->i2c); | |
| 1002 | + return fe; | |
| 1003 | +} | |
| 1004 | +EXPORT_SYMBOL(helene_attach_s); | |
| 1005 | + | |
| 1006 | +struct dvb_frontend *helene_attach(struct dvb_frontend *fe, | |
| 1007 | + const struct helene_config *config, | |
| 1008 | + struct i2c_adapter *i2c) | |
| 1009 | +{ | |
| 1010 | + struct helene_priv *priv = NULL; | |
| 1011 | + | |
| 1012 | + priv = kzalloc(sizeof(struct helene_priv), GFP_KERNEL); | |
| 1013 | + if (priv == NULL) | |
| 1014 | + return NULL; | |
| 1015 | + priv->i2c_address = (config->i2c_address >> 1); | |
| 1016 | + priv->i2c = i2c; | |
| 1017 | + priv->set_tuner_data = config->set_tuner_priv; | |
| 1018 | + priv->set_tuner = config->set_tuner_callback; | |
| 1019 | + priv->xtal = config->xtal; | |
| 1020 | + | |
| 1021 | + if (fe->ops.i2c_gate_ctrl) | |
| 1022 | + fe->ops.i2c_gate_ctrl(fe, 1); | |
| 1023 | + | |
| 1024 | + if (helene_x_pon(priv) != 0) | |
| 1025 | + return NULL; | |
| 1026 | + | |
| 1027 | + if (fe->ops.i2c_gate_ctrl) | |
| 1028 | + fe->ops.i2c_gate_ctrl(fe, 0); | |
| 1029 | + | |
| 1030 | + memcpy(&fe->ops.tuner_ops, &helene_tuner_ops, | |
| 1031 | + sizeof(struct dvb_tuner_ops)); | |
| 1032 | + fe->tuner_priv = priv; | |
| 1033 | + dev_info(&priv->i2c->dev, | |
| 1034 | + "Sony HELENE Ter attached on addr=%x at I2C adapter %p\n", | |
| 1035 | + priv->i2c_address, priv->i2c); | |
| 1036 | + return fe; | |
| 1037 | +} | |
| 1038 | +EXPORT_SYMBOL(helene_attach); | |
| 1039 | + | |
| 1040 | +MODULE_DESCRIPTION("Sony HELENE Sat/Ter tuner driver"); | |
| 1041 | +MODULE_AUTHOR("Abylay Ospan <aospan@netup.ru>"); | |
| 1042 | +MODULE_LICENSE("GPL"); | |
| @@ -0,0 +1,79 @@ | ||
| 1 | +/* | |
| 2 | + * helene.h | |
| 3 | + * | |
| 4 | + * Sony HELENE DVB-S/S2/T/T2/C/C2/ISDB-T/S tuner driver (CXD2858ER) | |
| 5 | + * | |
| 6 | + * Copyright 2012 Sony Corporation | |
| 7 | + * Copyright (C) 2014 NetUP Inc. | |
| 8 | + * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru> | |
| 9 | + * | |
| 10 | + * This program is free software; you can redistribute it and/or modify | |
| 11 | + * it under the terms of the GNU General Public License as published by | |
| 12 | + * the Free Software Foundation; either version 2 of the License, or | |
| 13 | + * (at your option) any later version. | |
| 14 | + * | |
| 15 | + * This program is distributed in the hope that it will be useful, | |
| 16 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 18 | + * GNU General Public License for more details. | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#ifndef __DVB_HELENE_H__ | |
| 22 | +#define __DVB_HELENE_H__ | |
| 23 | + | |
| 24 | +#include <linux/kconfig.h> | |
| 25 | +#include <linux/dvb/frontend.h> | |
| 26 | +#include <linux/i2c.h> | |
| 27 | + | |
| 28 | +enum helene_xtal { | |
| 29 | + SONY_HELENE_XTAL_16000, /* 16 MHz */ | |
| 30 | + SONY_HELENE_XTAL_20500, /* 20.5 MHz */ | |
| 31 | + SONY_HELENE_XTAL_24000, /* 24 MHz */ | |
| 32 | + SONY_HELENE_XTAL_41000 /* 41 MHz */ | |
| 33 | +}; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * struct helene_config - the configuration of 'Helene' tuner driver | |
| 37 | + * @i2c_address: I2C address of the tuner | |
| 38 | + * @xtal_freq_mhz: Oscillator frequency, MHz | |
| 39 | + * @set_tuner_priv: Callback function private context | |
| 40 | + * @set_tuner_callback: Callback function that notifies the parent driver | |
| 41 | + * which tuner is active now | |
| 42 | + */ | |
| 43 | +struct helene_config { | |
| 44 | + u8 i2c_address; | |
| 45 | + u8 xtal_freq_mhz; | |
| 46 | + void *set_tuner_priv; | |
| 47 | + int (*set_tuner_callback)(void *, int); | |
| 48 | + enum helene_xtal xtal; | |
| 49 | +}; | |
| 50 | + | |
| 51 | +#if IS_REACHABLE(CONFIG_DVB_HELENE) | |
| 52 | +extern struct dvb_frontend *helene_attach(struct dvb_frontend *fe, | |
| 53 | + const struct helene_config *config, | |
| 54 | + struct i2c_adapter *i2c); | |
| 55 | +#else | |
| 56 | +static inline struct dvb_frontend *helene_attach(struct dvb_frontend *fe, | |
| 57 | + const struct helene_config *config, | |
| 58 | + struct i2c_adapter *i2c) | |
| 59 | +{ | |
| 60 | + pr_warn("%s: driver disabled by Kconfig\n", __func__); | |
| 61 | + return NULL; | |
| 62 | +} | |
| 63 | +#endif | |
| 64 | + | |
| 65 | +#if IS_REACHABLE(CONFIG_DVB_HELENE) | |
| 66 | +extern struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe, | |
| 67 | + const struct helene_config *config, | |
| 68 | + struct i2c_adapter *i2c); | |
| 69 | +#else | |
| 70 | +static inline struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe, | |
| 71 | + const struct helene_config *config, | |
| 72 | + struct i2c_adapter *i2c) | |
| 73 | +{ | |
| 74 | + pr_warn("%s: driver disabled by Kconfig\n", __func__); | |
| 75 | + return NULL; | |
| 76 | +} | |
| 77 | +#endif | |
| 78 | + | |
| 79 | +#endif | |
| @@ -66,7 +66,7 @@ static int horus3a_write_regs(struct horus3a_priv *priv, · 65 unmodified lines | ||
| 66 | 66 | } |
| 67 | 67 | }; |
| 68 | 68 | |
| 69 | − if (len + 1 >= sizeof(buf)) { | |
| 69 | + if (len + 1 > sizeof(buf)) { | |
| 70 | 70 | dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n", |
| 71 | 71 | reg, len + 1); |
| 72 | 72 | return -E2BIG; |
| @@ -272,24 +272,6 @@ static int horus3a_set_params(struct dvb_frontend *fe) · 199 unmodified lines | ||
| 272 | 272 | if (fc_lpf > 36) |
| 273 | 273 | fc_lpf = 36; |
| 274 | 274 | } else if (p->delivery_system == SYS_DVBS2) { |
| 275 | − int rolloff; | |
| 276 | − | |
| 277 | − switch (p->rolloff) { | |
| 278 | − case ROLLOFF_35: | |
| 279 | − rolloff = 35; | |
| 280 | − break; | |
| 281 | − case ROLLOFF_25: | |
| 282 | − rolloff = 25; | |
| 283 | − break; | |
| 284 | − case ROLLOFF_20: | |
| 285 | − rolloff = 20; | |
| 286 | − break; | |
| 287 | − case ROLLOFF_AUTO: | |
| 288 | − default: | |
| 289 | − dev_err(&priv->i2c->dev, | |
| 290 | − "horus3a: auto roll-off is not supported\n"); | |
| 291 | − return -EINVAL; | |
| 292 | − } | |
| 293 | 275 | /* |
| 294 | 276 | * SR <= 4.5: |
| 295 | 277 | * fc_lpf = 5 |
| @@ -302,11 +284,9 @@ static int horus3a_set_params(struct dvb_frontend *fe) · 6 unmodified lines | ||
| 302 | 284 | if (symbol_rate <= 4500) |
| 303 | 285 | fc_lpf = 5; |
| 304 | 286 | else if (symbol_rate <= 10000) |
| 305 | − fc_lpf = (u8)DIV_ROUND_UP( | |
| 306 | − symbol_rate * (200 + rolloff), 200000); | |
| 287 | + fc_lpf = (u8)((symbol_rate * 11 + (10000-1)) / 10000); | |
| 307 | 288 | else |
| 308 | − fc_lpf = (u8)DIV_ROUND_UP( | |
| 309 | − symbol_rate * (100 + rolloff), 200000) + 5; | |
| 289 | + fc_lpf = (u8)((symbol_rate * 3 + (5000-1)) / 5000 + 5); | |
| 310 | 290 | /* 5 <= fc_lpf <= 36 is valid */ |
| 311 | 291 | if (fc_lpf > 36) |
| 312 | 292 | fc_lpf = 36; |
| @@ -306,8 +306,8 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 305 unmodified lines | ||
| 306 | 306 | const struct m88ds3103_reg_val *init; |
| 307 | 307 | u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */ |
| 308 | 308 | u8 buf[3]; |
| 309 | − u16 u16tmp, divide_ratio = 0; | |
| 310 | − u32 tuner_frequency, target_mclk; | |
| 309 | + u16 u16tmp; | |
| 310 | + u32 tuner_frequency_khz, target_mclk; | |
| 311 | 311 | s32 s32tmp; |
| 312 | 312 | |
| 313 | 313 | dev_dbg(&client->dev, |
| @@ -344,7 +344,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 30 unmodified lines | ||
| 344 | 344 | } |
| 345 | 345 | |
| 346 | 346 | if (fe->ops.tuner_ops.get_frequency) { |
| 347 | − ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_frequency); | |
| 347 | + ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_frequency_khz); | |
| 348 | 348 | if (ret) |
| 349 | 349 | goto err; |
| 350 | 350 | } else { |
| @@ -353,20 +353,20 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 2 unmodified lines | ||
| 353 | 353 | * actual frequency used. Carrier offset calculation is not |
| 354 | 354 | * valid. |
| 355 | 355 | */ |
| 356 | − tuner_frequency = c->frequency; | |
| 356 | + tuner_frequency_khz = c->frequency; | |
| 357 | 357 | } |
| 358 | 358 | |
| 359 | 359 | /* select M88RS6000 demod main mclk and ts mclk from tuner die. */ |
| 360 | 360 | if (dev->chip_id == M88RS6000_CHIP_ID) { |
| 361 | 361 | if (c->symbol_rate > 45010000) |
| 362 | − dev->mclk_khz = 110250; | |
| 362 | + dev->mclk = 110250000; | |
| 363 | 363 | else |
| 364 | − dev->mclk_khz = 96000; | |
| 364 | + dev->mclk = 96000000; | |
| 365 | 365 | |
| 366 | 366 | if (c->delivery_system == SYS_DVBS) |
| 367 | − target_mclk = 96000; | |
| 367 | + target_mclk = 96000000; | |
| 368 | 368 | else |
| 369 | − target_mclk = 144000; | |
| 369 | + target_mclk = 144000000; | |
| 370 | 370 | |
| 371 | 371 | /* Enable demod clock path */ |
| 372 | 372 | ret = regmap_write(dev->regmap, 0x06, 0x00); |
| @@ -375,7 +375,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 2 unmodified lines | ||
| 375 | 375 | usleep_range(10000, 20000); |
| 376 | 376 | } else { |
| 377 | 377 | /* set M88DS3103 mclk and ts mclk. */ |
| 378 | − dev->mclk_khz = 96000; | |
| 378 | + dev->mclk = 96000000; | |
| 379 | 379 | |
| 380 | 380 | switch (dev->cfg->ts_mode) { |
| 381 | 381 | case M88DS3103_TS_SERIAL: |
| @@ -385,14 +385,14 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 3 unmodified lines | ||
| 385 | 385 | case M88DS3103_TS_PARALLEL: |
| 386 | 386 | case M88DS3103_TS_CI: |
| 387 | 387 | if (c->delivery_system == SYS_DVBS) |
| 388 | − target_mclk = 96000; | |
| 388 | + target_mclk = 96000000; | |
| 389 | 389 | else { |
| 390 | 390 | if (c->symbol_rate < 18000000) |
| 391 | − target_mclk = 96000; | |
| 391 | + target_mclk = 96000000; | |
| 392 | 392 | else if (c->symbol_rate < 28000000) |
| 393 | − target_mclk = 144000; | |
| 393 | + target_mclk = 144000000; | |
| 394 | 394 | else |
| 395 | − target_mclk = 192000; | |
| 395 | + target_mclk = 192000000; | |
| 396 | 396 | } |
| 397 | 397 | break; |
| 398 | 398 | default: |
| @@ -402,15 +402,15 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 3 unmodified lines | ||
| 402 | 402 | } |
| 403 | 403 | |
| 404 | 404 | switch (target_mclk) { |
| 405 | − case 96000: | |
| 405 | + case 96000000: | |
| 406 | 406 | u8tmp1 = 0x02; /* 0b10 */ |
| 407 | 407 | u8tmp2 = 0x01; /* 0b01 */ |
| 408 | 408 | break; |
| 409 | − case 144000: | |
| 409 | + case 144000000: | |
| 410 | 410 | u8tmp1 = 0x00; /* 0b00 */ |
| 411 | 411 | u8tmp2 = 0x01; /* 0b01 */ |
| 412 | 412 | break; |
| 413 | − case 192000: | |
| 413 | + case 192000000: | |
| 414 | 414 | u8tmp1 = 0x03; /* 0b11 */ |
| 415 | 415 | u8tmp2 = 0x00; /* 0b00 */ |
| 416 | 416 | break; |
| @@ -464,8 +464,8 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 47 unmodified lines | ||
| 464 | 464 | } |
| 465 | 465 | |
| 466 | 466 | if (dev->chip_id == M88RS6000_CHIP_ID) { |
| 467 | − if ((c->delivery_system == SYS_DVBS2) | |
| 468 | − && ((c->symbol_rate / 1000) <= 5000)) { | |
| 467 | + if (c->delivery_system == SYS_DVBS2 && | |
| 468 | + c->symbol_rate <= 5000000) { | |
| 469 | 469 | ret = regmap_write(dev->regmap, 0xc0, 0x04); |
| 470 | 470 | if (ret) |
| 471 | 471 | goto err; |
| @@ -522,37 +522,25 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 50 unmodified lines | ||
| 522 | 522 | ret = m88ds3103_update_bits(dev, 0x29, 0x20, u8tmp1); |
| 523 | 523 | if (ret) |
| 524 | 524 | goto err; |
| 525 | − u8tmp1 = 0; | |
| 526 | − u8tmp2 = 0; | |
| 525 | + u16tmp = 0; | |
| 526 | + u8tmp1 = 0x3f; | |
| 527 | + u8tmp2 = 0x3f; | |
| 527 | 528 | break; |
| 528 | 529 | default: |
| 529 | − if (dev->cfg->ts_clk) { | |
| 530 | − divide_ratio = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk); | |
| 531 | − u8tmp1 = divide_ratio / 2; | |
| 532 | − u8tmp2 = DIV_ROUND_UP(divide_ratio, 2); | |
| 533 | − } | |
| 530 | + u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk); | |
| 531 | + u8tmp1 = u16tmp / 2 - 1; | |
| 532 | + u8tmp2 = DIV_ROUND_UP(u16tmp, 2) - 1; | |
| 534 | 533 | } |
| 535 | 534 | |
| 536 | − dev_dbg(&client->dev, | |
| 537 | − "target_mclk=%d ts_clk=%d divide_ratio=%d\n", | |
| 538 | − target_mclk, dev->cfg->ts_clk, divide_ratio); | |
| 535 | + dev_dbg(&client->dev, "target_mclk=%u ts_clk=%u ts_clk_divide_ratio=%u\n", | |
| 536 | + target_mclk, dev->cfg->ts_clk, u16tmp); | |
| 539 | 537 | |
| 540 | − u8tmp1--; | |
| 541 | − u8tmp2--; | |
| 542 | 538 | /* u8tmp1[5:2] => fe[3:0], u8tmp1[1:0] => ea[7:6] */ |
| 543 | − u8tmp1 &= 0x3f; | |
| 544 | 539 | /* u8tmp2[5:0] => ea[5:0] */ |
| 545 | − u8tmp2 &= 0x3f; | |
| 546 | − | |
| 547 | − ret = regmap_bulk_read(dev->regmap, 0xfe, &u8tmp, 1); | |
| 540 | + u8tmp = (u8tmp1 >> 2) & 0x0f; | |
| 541 | + ret = regmap_update_bits(dev->regmap, 0xfe, 0x0f, u8tmp); | |
| 548 | 542 | if (ret) |
| 549 | 543 | goto err; |
| 550 | − | |
| 551 | − u8tmp = ((u8tmp & 0xf0) << 0) | u8tmp1 >> 2; | |
| 552 | − ret = regmap_write(dev->regmap, 0xfe, u8tmp); | |
| 553 | − if (ret) | |
| 554 | − goto err; | |
| 555 | − | |
| 556 | 544 | u8tmp = ((u8tmp1 & 0x03) << 6) | u8tmp2 >> 0; |
| 557 | 545 | ret = regmap_write(dev->regmap, 0xea, u8tmp); |
| 558 | 546 | if (ret) |
| @@ -581,7 +569,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 22 unmodified lines | ||
| 581 | 569 | if (ret) |
| 582 | 570 | goto err; |
| 583 | 571 | |
| 584 | − u16tmp = DIV_ROUND_CLOSEST((c->symbol_rate / 1000) << 15, dev->mclk_khz / 2); | |
| 572 | + u16tmp = DIV_ROUND_CLOSEST_ULL((u64)c->symbol_rate * 0x10000, dev->mclk); | |
| 585 | 573 | buf[0] = (u16tmp >> 0) & 0xff; |
| 586 | 574 | buf[1] = (u16tmp >> 8) & 0xff; |
| 587 | 575 | ret = regmap_bulk_write(dev->regmap, 0x61, buf, 2); |
| @@ -601,13 +589,11 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 13 unmodified lines | ||
| 601 | 589 | goto err; |
| 602 | 590 | |
| 603 | 591 | dev_dbg(&client->dev, "carrier offset=%d\n", |
| 604 | − (tuner_frequency - c->frequency)); | |
| 605 | − | |
| 606 | − s32tmp = 0x10000 * (tuner_frequency - c->frequency); | |
| 607 | − s32tmp = DIV_ROUND_CLOSEST(s32tmp, dev->mclk_khz); | |
| 608 | − if (s32tmp < 0) | |
| 609 | − s32tmp += 0x10000; | |
| 592 | + (tuner_frequency_khz - c->frequency)); | |
| 610 | 593 | |
| 594 | + /* Use 32-bit calc as there is no s64 version of DIV_ROUND_CLOSEST() */ | |
| 595 | + s32tmp = 0x10000 * (tuner_frequency_khz - c->frequency); | |
| 596 | + s32tmp = DIV_ROUND_CLOSEST(s32tmp, dev->mclk / 1000); | |
| 611 | 597 | buf[0] = (s32tmp >> 0) & 0xff; |
| 612 | 598 | buf[1] = (s32tmp >> 8) & 0xff; |
| 613 | 599 | ret = regmap_bulk_write(dev->regmap, 0x5e, buf, 2); |
| @@ -635,10 +621,10 @@ static int m88ds3103_init(struct dvb_frontend *fe) · 21 unmodified lines | ||
| 635 | 621 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
| 636 | 622 | struct i2c_client *client = dev->client; |
| 637 | 623 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| 638 | − int ret, len, remaining; | |
| 624 | + int ret, len, rem; | |
| 639 | 625 | unsigned int utmp; |
| 640 | − const struct firmware *fw = NULL; | |
| 641 | − u8 *fw_file; | |
| 626 | + const struct firmware *firmware; | |
| 627 | + const char *name; | |
| 642 | 628 | |
| 643 | 629 | dev_dbg(&client->dev, "\n"); |
| 644 | 630 | |
| @@ -664,7 +650,7 @@ static int m88ds3103_init(struct dvb_frontend *fe) · 19 unmodified lines | ||
| 664 | 650 | dev_dbg(&client->dev, "firmware=%02x\n", utmp); |
| 665 | 651 | |
| 666 | 652 | if (utmp) |
| 667 | − goto skip_fw_download; | |
| 653 | + goto warm; | |
| 668 | 654 | |
| 669 | 655 | /* global reset, global diseqc reset, golbal fec reset */ |
| 670 | 656 | ret = regmap_write(dev->regmap, 0x07, 0xe0); |
| @@ -679,52 +665,47 @@ static int m88ds3103_init(struct dvb_frontend *fe) · 8 unmodified lines | ||
| 679 | 665 | m88ds3103_ops.info.name); |
| 680 | 666 | |
| 681 | 667 | if (dev->chip_id == M88RS6000_CHIP_ID) |
| 682 | − fw_file = M88RS6000_FIRMWARE; | |
| 668 | + name = M88RS6000_FIRMWARE; | |
| 683 | 669 | else |
| 684 | − fw_file = M88DS3103_FIRMWARE; | |
| 670 | + name = M88DS3103_FIRMWARE; | |
| 685 | 671 | /* request the firmware, this will block and timeout */ |
| 686 | − ret = request_firmware(&fw, fw_file, &client->dev); | |
| 672 | + ret = request_firmware(&firmware, name, &client->dev); | |
| 687 | 673 | if (ret) { |
| 688 | − dev_err(&client->dev, "firmware file '%s' not found\n", fw_file); | |
| 674 | + dev_err(&client->dev, "firmware file '%s' not found\n", name); | |
| 689 | 675 | goto err; |
| 690 | 676 | } |
| 691 | 677 | |
| 692 | − dev_info(&client->dev, "downloading firmware from file '%s'\n", | |
| 693 | − fw_file); | |
| 678 | + dev_info(&client->dev, "downloading firmware from file '%s'\n", name); | |
| 694 | 679 | |
| 695 | 680 | ret = regmap_write(dev->regmap, 0xb2, 0x01); |
| 696 | 681 | if (ret) |
| 697 | − goto error_fw_release; | |
| 698 | − | |
| 699 | − for (remaining = fw->size; remaining > 0; | |
| 700 | − remaining -= (dev->cfg->i2c_wr_max - 1)) { | |
| 701 | − len = remaining; | |
| 702 | − if (len > (dev->cfg->i2c_wr_max - 1)) | |
| 703 | − len = (dev->cfg->i2c_wr_max - 1); | |
| 682 | + goto err_release_firmware; | |
| 704 | 683 | |
| 684 | + for (rem = firmware->size; rem > 0; rem -= (dev->cfg->i2c_wr_max - 1)) { | |
| 685 | + len = min(dev->cfg->i2c_wr_max - 1, rem); | |
| 705 | 686 | ret = regmap_bulk_write(dev->regmap, 0xb0, |
| 706 | − &fw->data[fw->size - remaining], len); | |
| 687 | + &firmware->data[firmware->size - rem], | |
| 688 | + len); | |
| 707 | 689 | if (ret) { |
| 708 | − dev_err(&client->dev, "firmware download failed=%d\n", | |
| 690 | + dev_err(&client->dev, "firmware download failed %d\n", | |
| 709 | 691 | ret); |
| 710 | − goto error_fw_release; | |
| 692 | + goto err_release_firmware; | |
| 711 | 693 | } |
| 712 | 694 | } |
| 713 | 695 | |
| 714 | 696 | ret = regmap_write(dev->regmap, 0xb2, 0x00); |
| 715 | 697 | if (ret) |
| 716 | − goto error_fw_release; | |
| 698 | + goto err_release_firmware; | |
| 717 | 699 | |
| 718 | − release_firmware(fw); | |
| 719 | − fw = NULL; | |
| 700 | + release_firmware(firmware); | |
| 720 | 701 | |
| 721 | 702 | ret = regmap_read(dev->regmap, 0xb9, &utmp); |
| 722 | 703 | if (ret) |
| 723 | 704 | goto err; |
| 724 | 705 | |
| 725 | 706 | if (!utmp) { |
| 707 | + ret = -EINVAL; | |
| 726 | 708 | dev_info(&client->dev, "firmware did not run\n"); |
| 727 | − ret = -EFAULT; | |
| 728 | 709 | goto err; |
| 729 | 710 | } |
| 730 | 711 | |
| @@ -733,7 +714,7 @@ static int m88ds3103_init(struct dvb_frontend *fe) · 2 unmodified lines | ||
| 733 | 714 | dev_info(&client->dev, "firmware version: %X.%X\n", |
| 734 | 715 | (utmp >> 4) & 0xf, (utmp >> 0 & 0xf)); |
| 735 | 716 | |
| 736 | −skip_fw_download: | |
| 717 | +warm: | |
| 737 | 718 | /* warm state */ |
| 738 | 719 | dev->warm = true; |
| 739 | 720 | |
| @@ -746,8 +727,8 @@ skip_fw_download: · 6 unmodified lines | ||
| 746 | 727 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 747 | 728 | |
| 748 | 729 | return 0; |
| 749 | −error_fw_release: | |
| 750 | − release_firmware(fw); | |
| 730 | +err_release_firmware: | |
| 731 | + release_firmware(firmware); | |
| 751 | 732 | err: |
| 752 | 733 | dev_dbg(&client->dev, "failed=%d\n", ret); |
| 753 | 734 | return ret; |
| @@ -952,8 +933,7 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe, · 198 unmodified lines | ||
| 952 | 933 | if (ret) |
| 953 | 934 | goto err; |
| 954 | 935 | |
| 955 | − c->symbol_rate = 1ull * ((buf[1] << 8) | (buf[0] << 0)) * | |
| 956 | − dev->mclk_khz * 1000 / 0x10000; | |
| 936 | + c->symbol_rate = DIV_ROUND_CLOSEST_ULL((u64)(buf[1] << 8 | buf[0] << 0) * dev->mclk, 0x10000); | |
| 957 | 937 | |
| 958 | 938 | return 0; |
| 959 | 939 | err: |
| @@ -1119,8 +1099,9 @@ static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe, · 159 unmodified lines | ||
| 1119 | 1099 | #define SEND_MASTER_CMD_TIMEOUT 120 |
| 1120 | 1100 | timeout = jiffies + msecs_to_jiffies(SEND_MASTER_CMD_TIMEOUT); |
| 1121 | 1101 | |
| 1122 | − /* DiSEqC message typical period is 54 ms */ | |
| 1123 | − usleep_range(50000, 54000); | |
| 1102 | + /* DiSEqC message period is 13.5 ms per byte */ | |
| 1103 | + utmp = diseqc_cmd->msg_len * 13500; | |
| 1104 | + usleep_range(utmp - 4000, utmp); | |
| 1124 | 1105 | |
| 1125 | 1106 | for (utmp = 1; !time_after(jiffies, timeout) && utmp;) { |
| 1126 | 1107 | ret = regmap_read(dev->regmap, 0xa1, &utmp); |
| @@ -1395,7 +1376,7 @@ static int m88ds3103_probe(struct i2c_client *client, · 268 unmodified lines | ||
| 1395 | 1376 | dev->config.clock = pdata->clk; |
| 1396 | 1377 | dev->config.i2c_wr_max = pdata->i2c_wr_max; |
| 1397 | 1378 | dev->config.ts_mode = pdata->ts_mode; |
| 1398 | − dev->config.ts_clk = pdata->ts_clk; | |
| 1379 | + dev->config.ts_clk = pdata->ts_clk * 1000; | |
| 1399 | 1380 | dev->config.ts_clk_pol = pdata->ts_clk_pol; |
| 1400 | 1381 | dev->config.spec_inv = pdata->spec_inv; |
| 1401 | 1382 | dev->config.agc_inv = pdata->agc_inv; |
| @@ -1446,6 +1427,11 @@ static int m88ds3103_probe(struct i2c_client *client, · 44 unmodified lines | ||
| 1446 | 1427 | goto err_kfree; |
| 1447 | 1428 | } |
| 1448 | 1429 | |
| 1430 | + if (!pdata->ts_clk) { | |
| 1431 | + ret = -EINVAL; | |
| 1432 | + goto err_kfree; | |
| 1433 | + } | |
| 1434 | + | |
| 1449 | 1435 | /* 0x29 register is defined differently for m88rs6000. */ |
| 1450 | 1436 | /* set internal tuner address to 0x21 */ |
| 1451 | 1437 | if (dev->chip_id == M88RS6000_CHIP_ID) |
| @@ -27,7 +27,6 @@ · 26 unmodified lines | ||
| 27 | 27 | |
| 28 | 28 | #define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw" |
| 29 | 29 | #define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw" |
| 30 | −#define M88DS3103_MCLK_KHZ 96000 | |
| 31 | 30 | #define M88RS6000_CHIP_ID 0x74 |
| 32 | 31 | #define M88DS3103_CHIP_ID 0x70 |
| 33 | 32 | |
| @@ -46,7 +45,7 @@ struct m88ds3103_dev { · 12 unmodified lines | ||
| 46 | 45 | /* auto detect chip id to do different config */ |
| 47 | 46 | u8 chip_id; |
| 48 | 47 | /* main mclk is calculated for M88RS6000 dynamically */ |
| 49 | − s32 mclk_khz; | |
| 48 | + s32 mclk; | |
| 50 | 49 | u64 post_bit_error; |
| 51 | 50 | u64 post_bit_count; |
| 52 | 51 | }; |
| @@ -609,7 +609,7 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe) · 608 unmodified lines | ||
| 609 | 609 | { |
| 610 | 610 | struct m88rs2000_state *state = fe->demodulator_priv; |
| 611 | 611 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| 612 | − enum fe_status status; | |
| 612 | + enum fe_status status = 0; | |
| 613 | 613 | int i, ret = 0; |
| 614 | 614 | u32 tuner_freq; |
| 615 | 615 | s16 offset = 0; |
| @@ -301,10 +301,11 @@ static int mb86a20s_read_status(struct dvb_frontend *fe, enum fe_status *status) · 300 unmodified lines | ||
| 301 | 301 | |
| 302 | 302 | *status = 0; |
| 303 | 303 | |
| 304 | − val = mb86a20s_readreg(state, 0x0a) & 0xf; | |
| 304 | + val = mb86a20s_readreg(state, 0x0a); | |
| 305 | 305 | if (val < 0) |
| 306 | 306 | return val; |
| 307 | 307 | |
| 308 | + val &= 0xf; | |
| 308 | 309 | if (val >= 2) |
| 309 | 310 | *status |= FE_HAS_SIGNAL; |
| 310 | 311 | |
| @@ -17,28 +17,90 @@ · 16 unmodified lines | ||
| 17 | 17 | #include "mn88472_priv.h" |
| 18 | 18 | |
| 19 | 19 | static int mn88472_get_tune_settings(struct dvb_frontend *fe, |
| 20 | − struct dvb_frontend_tune_settings *s) | |
| 20 | + struct dvb_frontend_tune_settings *s) | |
| 21 | 21 | { |
| 22 | − s->min_delay_ms = 800; | |
| 22 | + s->min_delay_ms = 1000; | |
| 23 | 23 | return 0; |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | +static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) | |
| 27 | +{ | |
| 28 | + struct i2c_client *client = fe->demodulator_priv; | |
| 29 | + struct mn88472_dev *dev = i2c_get_clientdata(client); | |
| 30 | + struct dtv_frontend_properties *c = &fe->dtv_property_cache; | |
| 31 | + int ret; | |
| 32 | + unsigned int utmp; | |
| 33 | + | |
| 34 | + if (!dev->active) { | |
| 35 | + ret = -EAGAIN; | |
| 36 | + goto err; | |
| 37 | + } | |
| 38 | + | |
| 39 | + switch (c->delivery_system) { | |
| 40 | + case SYS_DVBT: | |
| 41 | + ret = regmap_read(dev->regmap[0], 0x7f, &utmp); | |
| 42 | + if (ret) | |
| 43 | + goto err; | |
| 44 | + if ((utmp & 0x0f) >= 0x09) | |
| 45 | + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | |
| 46 | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | |
| 47 | + else | |
| 48 | + *status = 0; | |
| 49 | + break; | |
| 50 | + case SYS_DVBT2: | |
| 51 | + ret = regmap_read(dev->regmap[2], 0x92, &utmp); | |
| 52 | + if (ret) | |
| 53 | + goto err; | |
| 54 | + if ((utmp & 0x0f) >= 0x0d) | |
| 55 | + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | |
| 56 | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | |
| 57 | + else if ((utmp & 0x0f) >= 0x0a) | |
| 58 | + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | |
| 59 | + FE_HAS_VITERBI; | |
| 60 | + else if ((utmp & 0x0f) >= 0x07) | |
| 61 | + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; | |
| 62 | + else | |
| 63 | + *status = 0; | |
| 64 | + break; | |
| 65 | + case SYS_DVBC_ANNEX_A: | |
| 66 | + ret = regmap_read(dev->regmap[1], 0x84, &utmp); | |
| 67 | + if (ret) | |
| 68 | + goto err; | |
| 69 | + if ((utmp & 0x0f) >= 0x08) | |
| 70 | + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | |
| 71 | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | |
| 72 | + else | |
| 73 | + *status = 0; | |
| 74 | + break; | |
| 75 | + default: | |
| 76 | + ret = -EINVAL; | |
| 77 | + goto err; | |
| 78 | + } | |
| 79 | + | |
| 80 | + return 0; | |
| 81 | +err: | |
| 82 | + dev_dbg(&client->dev, "failed=%d\n", ret); | |
| 83 | + return ret; | |
| 84 | +} | |
| 85 | + | |
| 26 | 86 | static int mn88472_set_frontend(struct dvb_frontend *fe) |
| 27 | 87 | { |
| 28 | 88 | struct i2c_client *client = fe->demodulator_priv; |
| 29 | 89 | struct mn88472_dev *dev = i2c_get_clientdata(client); |
| 30 | 90 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| 31 | 91 | int ret, i; |
| 32 | − u32 if_frequency = 0; | |
| 33 | − u64 tmp; | |
| 34 | − u8 delivery_system_val, if_val[3], bw_val[7], bw_val2; | |
| 92 | + unsigned int utmp; | |
| 93 | + u32 if_frequency; | |
| 94 | + u8 buf[3], delivery_system_val, bandwidth_val, *bandwidth_vals_ptr; | |
| 95 | + u8 reg_bank0_b4_val, reg_bank0_cd_val, reg_bank0_d4_val; | |
| 96 | + u8 reg_bank0_d6_val; | |
| 35 | 97 | |
| 36 | 98 | dev_dbg(&client->dev, |
| 37 | − "delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d\n", | |
| 38 | − c->delivery_system, c->modulation, | |
| 39 | − c->frequency, c->symbol_rate, c->inversion); | |
| 99 | + "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%d stream_id=%d\n", | |
| 100 | + c->delivery_system, c->modulation, c->frequency, | |
| 101 | + c->bandwidth_hz, c->symbol_rate, c->inversion, c->stream_id); | |
| 40 | 102 | |
| 41 | − if (!dev->warm) { | |
| 103 | + if (!dev->active) { | |
| 42 | 104 | ret = -EAGAIN; |
| 43 | 105 | goto err; |
| 44 | 106 | } |
| @@ -46,39 +108,64 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) · 1 unmodified line | ||
| 46 | 108 | switch (c->delivery_system) { |
| 47 | 109 | case SYS_DVBT: |
| 48 | 110 | delivery_system_val = 0x02; |
| 111 | + reg_bank0_b4_val = 0x00; | |
| 112 | + reg_bank0_cd_val = 0x1f; | |
| 113 | + reg_bank0_d4_val = 0x0a; | |
| 114 | + reg_bank0_d6_val = 0x48; | |
| 49 | 115 | break; |
| 50 | 116 | case SYS_DVBT2: |
| 51 | 117 | delivery_system_val = 0x03; |
| 118 | + reg_bank0_b4_val = 0xf6; | |
| 119 | + reg_bank0_cd_val = 0x01; | |
| 120 | + reg_bank0_d4_val = 0x09; | |
| 121 | + reg_bank0_d6_val = 0x46; | |
| 52 | 122 | break; |
| 53 | 123 | case SYS_DVBC_ANNEX_A: |
| 54 | 124 | delivery_system_val = 0x04; |
| 125 | + reg_bank0_b4_val = 0x00; | |
| 126 | + reg_bank0_cd_val = 0x17; | |
| 127 | + reg_bank0_d4_val = 0x09; | |
| 128 | + reg_bank0_d6_val = 0x48; | |
| 55 | 129 | break; |
| 56 | 130 | default: |
| 57 | 131 | ret = -EINVAL; |
| 58 | 132 | goto err; |
| 59 | 133 | } |
| 60 | 134 | |
| 61 | − if (c->bandwidth_hz <= 5000000) { | |
| 62 | − memcpy(bw_val, "\xe5\x99\x9a\x1b\xa9\x1b\xa9", 7); | |
| 63 | − bw_val2 = 0x03; | |
| 64 | − } else if (c->bandwidth_hz <= 6000000) { | |
| 65 | − /* IF 3570000 Hz, BW 6000000 Hz */ | |
| 66 | − memcpy(bw_val, "\xbf\x55\x55\x15\x6b\x15\x6b", 7); | |
| 67 | − bw_val2 = 0x02; | |
| 68 | − } else if (c->bandwidth_hz <= 7000000) { | |
| 69 | − /* IF 4570000 Hz, BW 7000000 Hz */ | |
| 70 | − memcpy(bw_val, "\xa4\x00\x00\x0f\x2c\x0f\x2c", 7); | |
| 71 | − bw_val2 = 0x01; | |
| 72 | − } else if (c->bandwidth_hz <= 8000000) { | |
| 73 | − /* IF 4570000 Hz, BW 8000000 Hz */ | |
| 74 | − memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7); | |
| 75 | − bw_val2 = 0x00; | |
| 76 | − } else { | |
| 77 | − ret = -EINVAL; | |
| 78 | − goto err; | |
| 135 | + switch (c->delivery_system) { | |
| 136 | + case SYS_DVBT: | |
| 137 | + case SYS_DVBT2: | |
| 138 | + switch (c->bandwidth_hz) { | |
| 139 | + case 5000000: | |
| 140 | + bandwidth_vals_ptr = "\xe5\x99\x9a\x1b\xa9\x1b\xa9"; | |
| 141 | + bandwidth_val = 0x03; | |
| 142 | + break; | |
| 143 | + case 6000000: | |
| 144 | + bandwidth_vals_ptr = "\xbf\x55\x55\x15\x6b\x15\x6b"; | |
| 145 | + bandwidth_val = 0x02; | |
| 146 | + break; | |
| 147 | + case 7000000: | |
| 148 | + bandwidth_vals_ptr = "\xa4\x00\x00\x0f\x2c\x0f\x2c"; | |
| 149 | + bandwidth_val = 0x01; | |
| 150 | + break; | |
| 151 | + case 8000000: | |
| 152 | + bandwidth_vals_ptr = "\x8f\x80\x00\x08\xee\x08\xee"; | |
| 153 | + bandwidth_val = 0x00; | |
| 154 | + break; | |
| 155 | + default: | |
| 156 | + ret = -EINVAL; | |
| 157 | + goto err; | |
| 158 | + } | |
| 159 | + break; | |
| 160 | + case SYS_DVBC_ANNEX_A: | |
| 161 | + bandwidth_vals_ptr = NULL; | |
| 162 | + bandwidth_val = 0x00; | |
| 163 | + break; | |
| 164 | + default: | |
| 165 | + break; | |
| 79 | 166 | } |
| 80 | 167 | |
| 81 | − /* program tuner */ | |
| 168 | + /* Program tuner */ | |
| 82 | 169 | if (fe->ops.tuner_ops.set_params) { |
| 83 | 170 | ret = fe->ops.tuner_ops.set_params(fe); |
| 84 | 171 | if (ret) |
| @@ -91,20 +178,10 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) · 6 unmodified lines | ||
| 91 | 178 | goto err; |
| 92 | 179 | |
| 93 | 180 | dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency); |
| 94 | − } | |
| 95 | − | |
| 96 | − /* Calculate IF registers ( (1<<24)*IF / Xtal ) */ | |
| 97 | − tmp = div_u64(if_frequency * (u64)(1<<24) + (dev->xtal / 2), | |
| 98 | − dev->xtal); | |
| 99 | − if_val[0] = (tmp >> 16) & 0xff; | |
| 100 | − if_val[1] = (tmp >> 8) & 0xff; | |
| 101 | − if_val[2] = (tmp >> 0) & 0xff; | |
| 102 | − | |
| 103 | − ret = regmap_write(dev->regmap[2], 0xfb, 0x13); | |
| 104 | − ret = regmap_write(dev->regmap[2], 0xef, 0x13); | |
| 105 | − ret = regmap_write(dev->regmap[2], 0xf9, 0x13); | |
| 106 | − if (ret) | |
| 181 | + } else { | |
| 182 | + ret = -EINVAL; | |
| 107 | 183 | goto err; |
| 184 | + } | |
| 108 | 185 | |
| 109 | 186 | ret = regmap_write(dev->regmap[2], 0x00, 0x66); |
| 110 | 187 | if (ret) |
| @@ -118,157 +195,81 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) · 7 unmodified lines | ||
| 118 | 195 | ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val); |
| 119 | 196 | if (ret) |
| 120 | 197 | goto err; |
| 121 | − ret = regmap_write(dev->regmap[2], 0x04, bw_val2); | |
| 198 | + ret = regmap_write(dev->regmap[2], 0x04, bandwidth_val); | |
| 122 | 199 | if (ret) |
| 123 | 200 | goto err; |
| 124 | 201 | |
| 125 | − for (i = 0; i < sizeof(if_val); i++) { | |
| 126 | − ret = regmap_write(dev->regmap[2], 0x10 + i, if_val[i]); | |
| 202 | + /* IF */ | |
| 203 | + utmp = DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x1000000, dev->clk); | |
| 204 | + buf[0] = (utmp >> 16) & 0xff; | |
| 205 | + buf[1] = (utmp >> 8) & 0xff; | |
| 206 | + buf[2] = (utmp >> 0) & 0xff; | |
| 207 | + for (i = 0; i < 3; i++) { | |
| 208 | + ret = regmap_write(dev->regmap[2], 0x10 + i, buf[i]); | |
| 127 | 209 | if (ret) |
| 128 | 210 | goto err; |
| 129 | 211 | } |
| 130 | 212 | |
| 131 | − for (i = 0; i < sizeof(bw_val); i++) { | |
| 132 | − ret = regmap_write(dev->regmap[2], 0x13 + i, bw_val[i]); | |
| 133 | − if (ret) | |
| 134 | − goto err; | |
| 213 | + /* Bandwidth */ | |
| 214 | + if (bandwidth_vals_ptr) { | |
| 215 | + for (i = 0; i < 7; i++) { | |
| 216 | + ret = regmap_write(dev->regmap[2], 0x13 + i, | |
| 217 | + bandwidth_vals_ptr[i]); | |
| 218 | + if (ret) | |
| 219 | + goto err; | |
| 220 | + } | |
| 135 | 221 | } |
| 136 | 222 | |
| 223 | + ret = regmap_write(dev->regmap[0], 0xb4, reg_bank0_b4_val); | |
| 224 | + if (ret) | |
| 225 | + goto err; | |
| 226 | + ret = regmap_write(dev->regmap[0], 0xcd, reg_bank0_cd_val); | |
| 227 | + if (ret) | |
| 228 | + goto err; | |
| 229 | + ret = regmap_write(dev->regmap[0], 0xd4, reg_bank0_d4_val); | |
| 230 | + if (ret) | |
| 231 | + goto err; | |
| 232 | + ret = regmap_write(dev->regmap[0], 0xd6, reg_bank0_d6_val); | |
| 233 | + if (ret) | |
| 234 | + goto err; | |
| 235 | + | |
| 137 | 236 | switch (c->delivery_system) { |
| 138 | 237 | case SYS_DVBT: |
| 139 | 238 | ret = regmap_write(dev->regmap[0], 0x07, 0x26); |
| 140 | − ret = regmap_write(dev->regmap[0], 0xb0, 0x0a); | |
| 141 | − ret = regmap_write(dev->regmap[0], 0xb4, 0x00); | |
| 142 | − ret = regmap_write(dev->regmap[0], 0xcd, 0x1f); | |
| 143 | − ret = regmap_write(dev->regmap[0], 0xd4, 0x0a); | |
| 144 | − ret = regmap_write(dev->regmap[0], 0xd6, 0x48); | |
| 239 | + if (ret) | |
| 240 | + goto err; | |
| 145 | 241 | ret = regmap_write(dev->regmap[0], 0x00, 0xba); |
| 242 | + if (ret) | |
| 243 | + goto err; | |
| 146 | 244 | ret = regmap_write(dev->regmap[0], 0x01, 0x13); |
| 147 | 245 | if (ret) |
| 148 | 246 | goto err; |
| 149 | 247 | break; |
| 150 | 248 | case SYS_DVBT2: |
| 151 | 249 | ret = regmap_write(dev->regmap[2], 0x2b, 0x13); |
| 250 | + if (ret) | |
| 251 | + goto err; | |
| 152 | 252 | ret = regmap_write(dev->regmap[2], 0x4f, 0x05); |
| 253 | + if (ret) | |
| 254 | + goto err; | |
| 153 | 255 | ret = regmap_write(dev->regmap[1], 0xf6, 0x05); |
| 154 | − ret = regmap_write(dev->regmap[0], 0xb0, 0x0a); | |
| 155 | − ret = regmap_write(dev->regmap[0], 0xb4, 0xf6); | |
| 156 | − ret = regmap_write(dev->regmap[0], 0xcd, 0x01); | |
| 157 | − ret = regmap_write(dev->regmap[0], 0xd4, 0x09); | |
| 158 | − ret = regmap_write(dev->regmap[0], 0xd6, 0x46); | |
| 159 | − ret = regmap_write(dev->regmap[2], 0x30, 0x80); | |
| 160 | − ret = regmap_write(dev->regmap[2], 0x32, 0x00); | |
| 161 | 256 | if (ret) |
| 162 | 257 | goto err; |
| 163 | − break; | |
| 164 | − case SYS_DVBC_ANNEX_A: | |
| 165 | − ret = regmap_write(dev->regmap[0], 0xb0, 0x0b); | |
| 166 | − ret = regmap_write(dev->regmap[0], 0xb4, 0x00); | |
| 167 | − ret = regmap_write(dev->regmap[0], 0xcd, 0x17); | |
| 168 | − ret = regmap_write(dev->regmap[0], 0xd4, 0x09); | |
| 169 | − ret = regmap_write(dev->regmap[0], 0xd6, 0x48); | |
| 170 | − ret = regmap_write(dev->regmap[1], 0x00, 0xb0); | |
| 258 | + ret = regmap_write(dev->regmap[2], 0x32, c->stream_id); | |
| 171 | 259 | if (ret) |
| 172 | 260 | goto err; |
| 173 | 261 | break; |
| 174 | − default: | |
| 175 | − ret = -EINVAL; | |
| 176 | − goto err; | |
| 177 | − } | |
| 178 | − | |
| 179 | − ret = regmap_write(dev->regmap[0], 0x46, 0x00); | |
| 180 | − ret = regmap_write(dev->regmap[0], 0xae, 0x00); | |
| 181 | − | |
| 182 | − switch (dev->ts_mode) { | |
| 183 | − case SERIAL_TS_MODE: | |
| 184 | − ret = regmap_write(dev->regmap[2], 0x08, 0x1d); | |
| 185 | − break; | |
| 186 | − case PARALLEL_TS_MODE: | |
| 187 | − ret = regmap_write(dev->regmap[2], 0x08, 0x00); | |
| 262 | + case SYS_DVBC_ANNEX_A: | |
| 188 | 263 | break; |
| 189 | 264 | default: |
| 190 | − dev_dbg(&client->dev, "ts_mode error: %d\n", dev->ts_mode); | |
| 191 | − ret = -EINVAL; | |
| 192 | − goto err; | |
| 193 | − } | |
| 194 | − | |
| 195 | − switch (dev->ts_clock) { | |
| 196 | − case VARIABLE_TS_CLOCK: | |
| 197 | − ret = regmap_write(dev->regmap[0], 0xd9, 0xe3); | |
| 198 | 265 | break; |
| 199 | − case FIXED_TS_CLOCK: | |
| 200 | − ret = regmap_write(dev->regmap[0], 0xd9, 0xe1); | |
| 201 | − break; | |
| 202 | − default: | |
| 203 | − dev_dbg(&client->dev, "ts_clock error: %d\n", dev->ts_clock); | |
| 204 | − ret = -EINVAL; | |
| 205 | − goto err; | |
| 206 | 266 | } |
| 207 | 267 | |
| 208 | − /* Reset demod */ | |
| 268 | + /* Reset FSM */ | |
| 209 | 269 | ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); |
| 210 | 270 | if (ret) |
| 211 | 271 | goto err; |
| 212 | 272 | |
| 213 | − dev->delivery_system = c->delivery_system; | |
| 214 | − | |
| 215 | − return 0; | |
| 216 | −err: | |
| 217 | − dev_dbg(&client->dev, "failed=%d\n", ret); | |
| 218 | − return ret; | |
| 219 | −} | |
| 220 | − | |
| 221 | −static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) | |
| 222 | −{ | |
| 223 | − struct i2c_client *client = fe->demodulator_priv; | |
| 224 | − struct mn88472_dev *dev = i2c_get_clientdata(client); | |
| 225 | − struct dtv_frontend_properties *c = &fe->dtv_property_cache; | |
| 226 | − int ret; | |
| 227 | − unsigned int utmp; | |
| 228 | − int lock = 0; | |
| 229 | − | |
| 230 | − *status = 0; | |
| 231 | − | |
| 232 | − if (!dev->warm) { | |
| 233 | − ret = -EAGAIN; | |
| 234 | − goto err; | |
| 235 | − } | |
| 236 | − | |
| 237 | − switch (c->delivery_system) { | |
| 238 | − case SYS_DVBT: | |
| 239 | − ret = regmap_read(dev->regmap[0], 0x7F, &utmp); | |
| 240 | − if (ret) | |
| 241 | − goto err; | |
| 242 | − if ((utmp & 0xF) >= 0x09) | |
| 243 | − lock = 1; | |
| 244 | − break; | |
| 245 | − case SYS_DVBT2: | |
| 246 | − ret = regmap_read(dev->regmap[2], 0x92, &utmp); | |
| 247 | − if (ret) | |
| 248 | − goto err; | |
| 249 | − if ((utmp & 0xF) >= 0x07) | |
| 250 | − *status |= FE_HAS_SIGNAL; | |
| 251 | − if ((utmp & 0xF) >= 0x0a) | |
| 252 | − *status |= FE_HAS_CARRIER; | |
| 253 | − if ((utmp & 0xF) >= 0x0d) | |
| 254 | − *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | |
| 255 | − break; | |
| 256 | − case SYS_DVBC_ANNEX_A: | |
| 257 | − ret = regmap_read(dev->regmap[1], 0x84, &utmp); | |
| 258 | − if (ret) | |
| 259 | − goto err; | |
| 260 | − if ((utmp & 0xF) >= 0x08) | |
| 261 | − lock = 1; | |
| 262 | − break; | |
| 263 | − default: | |
| 264 | − ret = -EINVAL; | |
| 265 | − goto err; | |
| 266 | − } | |
| 267 | − | |
| 268 | − if (lock) | |
| 269 | − *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | | |
| 270 | − FE_HAS_SYNC | FE_HAS_LOCK; | |
| 271 | − | |
| 272 | 273 | return 0; |
| 273 | 274 | err: |
| 274 | 275 | dev_dbg(&client->dev, "failed=%d\n", ret); |
| @@ -279,93 +280,107 @@ static int mn88472_init(struct dvb_frontend *fe) · 4 unmodified lines | ||
| 279 | 280 | { |
| 280 | 281 | struct i2c_client *client = fe->demodulator_priv; |
| 281 | 282 | struct mn88472_dev *dev = i2c_get_clientdata(client); |
| 282 | − int ret, len, remaining; | |
| 283 | − const struct firmware *fw = NULL; | |
| 284 | − u8 *fw_file = MN88472_FIRMWARE; | |
| 285 | − unsigned int tmp; | |
| 283 | + int ret, len, rem; | |
| 284 | + unsigned int utmp; | |
| 285 | + const struct firmware *firmware; | |
| 286 | + const char *name = MN88472_FIRMWARE; | |
| 286 | 287 | |
| 287 | 288 | dev_dbg(&client->dev, "\n"); |
| 288 | 289 | |
| 289 | − /* set cold state by default */ | |
| 290 | − dev->warm = false; | |
| 291 | − | |
| 292 | − /* power on */ | |
| 290 | + /* Power up */ | |
| 293 | 291 | ret = regmap_write(dev->regmap[2], 0x05, 0x00); |
| 294 | 292 | if (ret) |
| 295 | 293 | goto err; |
| 296 | − | |
| 297 | − ret = regmap_bulk_write(dev->regmap[2], 0x0b, "\x00\x00", 2); | |
| 294 | + ret = regmap_write(dev->regmap[2], 0x0b, 0x00); | |
| 298 | 295 | if (ret) |
| 299 | 296 | goto err; |
| 300 | − | |
| 301 | − /* check if firmware is already running */ | |
| 302 | − ret = regmap_read(dev->regmap[0], 0xf5, &tmp); | |
| 297 | + ret = regmap_write(dev->regmap[2], 0x0c, 0x00); | |
| 303 | 298 | if (ret) |
| 304 | 299 | goto err; |
| 305 | 300 | |
| 306 | − if (!(tmp & 0x1)) { | |
| 307 | − dev_info(&client->dev, "firmware already running\n"); | |
| 308 | − dev->warm = true; | |
| 309 | − return 0; | |
| 310 | − } | |
| 301 | + /* Check if firmware is already running */ | |
| 302 | + ret = regmap_read(dev->regmap[0], 0xf5, &utmp); | |
| 303 | + if (ret) | |
| 304 | + goto err; | |
| 305 | + if (!(utmp & 0x01)) | |
| 306 | + goto warm; | |
| 311 | 307 | |
| 312 | − /* request the firmware, this will block and timeout */ | |
| 313 | − ret = request_firmware(&fw, fw_file, &client->dev); | |
| 308 | + ret = request_firmware(&firmware, name, &client->dev); | |
| 314 | 309 | if (ret) { |
| 315 | − dev_err(&client->dev, "firmare file '%s' not found\n", | |
| 316 | − fw_file); | |
| 310 | + dev_err(&client->dev, "firmware file '%s' not found\n", name); | |
| 317 | 311 | goto err; |
| 318 | 312 | } |
| 319 | 313 | |
| 320 | − dev_info(&client->dev, "downloading firmware from file '%s'\n", | |
| 321 | − fw_file); | |
| 314 | + dev_info(&client->dev, "downloading firmware from file '%s'\n", name); | |
| 322 | 315 | |
| 323 | 316 | ret = regmap_write(dev->regmap[0], 0xf5, 0x03); |
| 324 | 317 | if (ret) |
| 325 | − goto firmware_release; | |
| 326 | − | |
| 327 | − for (remaining = fw->size; remaining > 0; | |
| 328 | − remaining -= (dev->i2c_wr_max - 1)) { | |
| 329 | − len = remaining; | |
| 330 | − if (len > (dev->i2c_wr_max - 1)) | |
| 331 | − len = dev->i2c_wr_max - 1; | |
| 318 | + goto err_release_firmware; | |
| 332 | 319 | |
| 320 | + for (rem = firmware->size; rem > 0; rem -= (dev->i2c_write_max - 1)) { | |
| 321 | + len = min(dev->i2c_write_max - 1, rem); | |
| 333 | 322 | ret = regmap_bulk_write(dev->regmap[0], 0xf6, |
| 334 | − &fw->data[fw->size - remaining], len); | |
| 323 | + &firmware->data[firmware->size - rem], | |
| 324 | + len); | |
| 335 | 325 | if (ret) { |
| 336 | − dev_err(&client->dev, | |
| 337 | − "firmware download failed=%d\n", ret); | |
| 338 | − goto firmware_release; | |
| 326 | + dev_err(&client->dev, "firmware download failed %d\n", | |
| 327 | + ret); | |
| 328 | + goto err_release_firmware; | |
| 339 | 329 | } |
| 340 | 330 | } |
| 341 | 331 | |
| 342 | − /* parity check of firmware */ | |
| 343 | − ret = regmap_read(dev->regmap[0], 0xf8, &tmp); | |
| 344 | − if (ret) { | |
| 345 | − dev_err(&client->dev, | |
| 346 | − "parity reg read failed=%d\n", ret); | |
| 347 | − goto firmware_release; | |
| 348 | − } | |
| 349 | − if (tmp & 0x10) { | |
| 350 | − dev_err(&client->dev, | |
| 351 | − "firmware parity check failed=0x%x\n", tmp); | |
| 352 | − goto firmware_release; | |
| 332 | + /* Parity check of firmware */ | |
| 333 | + ret = regmap_read(dev->regmap[0], 0xf8, &utmp); | |
| 334 | + if (ret) | |
| 335 | + goto err_release_firmware; | |
| 336 | + if (utmp & 0x10) { | |
| 337 | + ret = -EINVAL; | |
| 338 | + dev_err(&client->dev, "firmware did not run\n"); | |
| 339 | + goto err_release_firmware; | |
| 353 | 340 | } |
| 354 | − dev_err(&client->dev, "firmware parity check succeeded=0x%x\n", tmp); | |
| 355 | 341 | |
| 356 | 342 | ret = regmap_write(dev->regmap[0], 0xf5, 0x00); |
| 357 | 343 | if (ret) |
| 358 | − goto firmware_release; | |
| 344 | + goto err_release_firmware; | |
| 345 | + | |
| 346 | + release_firmware(firmware); | |
| 347 | +warm: | |
| 348 | + /* TS config */ | |
| 349 | + switch (dev->ts_mode) { | |
| 350 | + case SERIAL_TS_MODE: | |
| 351 | + utmp = 0x1d; | |
| 352 | + break; | |
| 353 | + case PARALLEL_TS_MODE: | |
| 354 | + utmp = 0x00; | |
| 355 | + break; | |
| 356 | + default: | |
| 357 | + ret = -EINVAL; | |
| 358 | + goto err; | |
| 359 | + } | |
| 360 | + ret = regmap_write(dev->regmap[2], 0x08, utmp); | |
| 361 | + if (ret) | |
| 362 | + goto err; | |
| 359 | 363 | |
| 360 | − release_firmware(fw); | |
| 361 | − fw = NULL; | |
| 364 | + switch (dev->ts_clk) { | |
| 365 | + case VARIABLE_TS_CLOCK: | |
| 366 | + utmp = 0xe3; | |
| 367 | + break; | |
| 368 | + case FIXED_TS_CLOCK: | |
| 369 | + utmp = 0xe1; | |
| 370 | + break; | |
| 371 | + default: | |
| 372 | + ret = -EINVAL; | |
| 373 | + goto err; | |
| 374 | + } | |
| 375 | + ret = regmap_write(dev->regmap[0], 0xd9, utmp); | |
| 376 | + if (ret) | |
| 377 | + goto err; | |
| 362 | 378 | |
| 363 | − /* warm state */ | |
| 364 | − dev->warm = true; | |
| 379 | + dev->active = true; | |
| 365 | 380 | |
| 366 | 381 | return 0; |
| 367 | −firmware_release: | |
| 368 | − release_firmware(fw); | |
| 382 | +err_release_firmware: | |
| 383 | + release_firmware(firmware); | |
| 369 | 384 | err: |
| 370 | 385 | dev_dbg(&client->dev, "failed=%d\n", ret); |
| 371 | 386 | return ret; |
| @@ -379,18 +394,17 @@ static int mn88472_sleep(struct dvb_frontend *fe) · 7 unmodified lines | ||
| 379 | 394 | |
| 380 | 395 | dev_dbg(&client->dev, "\n"); |
| 381 | 396 | |
| 382 | − /* power off */ | |
| 397 | + /* Power down */ | |
| 398 | + ret = regmap_write(dev->regmap[2], 0x0c, 0x30); | |
| 399 | + if (ret) | |
| 400 | + goto err; | |
| 383 | 401 | ret = regmap_write(dev->regmap[2], 0x0b, 0x30); |
| 384 | − | |
| 385 | 402 | if (ret) |
| 386 | 403 | goto err; |
| 387 | − | |
| 388 | 404 | ret = regmap_write(dev->regmap[2], 0x05, 0x3e); |
| 389 | 405 | if (ret) |
| 390 | 406 | goto err; |
| 391 | 407 | |
| 392 | − dev->delivery_system = SYS_UNDEFINED; | |
| 393 | − | |
| 394 | 408 | return 0; |
| 395 | 409 | err: |
| 396 | 410 | dev_dbg(&client->dev, "failed=%d\n", ret); |
| @@ -434,10 +448,19 @@ static struct dvb_frontend_ops mn88472_ops = { · 37 unmodified lines | ||
| 434 | 448 | .read_status = mn88472_read_status, |
| 435 | 449 | }; |
| 436 | 450 | |
| 451 | +static struct dvb_frontend *mn88472_get_dvb_frontend(struct i2c_client *client) | |
| 452 | +{ | |
| 453 | + struct mn88472_dev *dev = i2c_get_clientdata(client); | |
| 454 | + | |
| 455 | + dev_dbg(&client->dev, "\n"); | |
| 456 | + | |
| 457 | + return &dev->fe; | |
| 458 | +} | |
| 459 | + | |
| 437 | 460 | static int mn88472_probe(struct i2c_client *client, |
| 438 | − const struct i2c_device_id *id) | |
| 461 | + const struct i2c_device_id *id) | |
| 439 | 462 | { |
| 440 | − struct mn88472_config *config = client->dev.platform_data; | |
| 463 | + struct mn88472_config *pdata = client->dev.platform_data; | |
| 441 | 464 | struct mn88472_dev *dev; |
| 442 | 465 | int ret; |
| 443 | 466 | unsigned int utmp; |
| @@ -448,23 +471,16 @@ static int mn88472_probe(struct i2c_client *client, · 4 unmodified lines | ||
| 448 | 471 | |
| 449 | 472 | dev_dbg(&client->dev, "\n"); |
| 450 | 473 | |
| 451 | − /* Caller really need to provide pointer for frontend we create. */ | |
| 452 | − if (config->fe == NULL) { | |
| 453 | − dev_err(&client->dev, "frontend pointer not defined\n"); | |
| 454 | − ret = -EINVAL; | |
| 455 | − goto err; | |
| 456 | − } | |
| 457 | − | |
| 458 | 474 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
| 459 | 475 | if (!dev) { |
| 460 | 476 | ret = -ENOMEM; |
| 461 | 477 | goto err; |
| 462 | 478 | } |
| 463 | 479 | |
| 464 | − dev->i2c_wr_max = config->i2c_wr_max; | |
| 465 | − dev->xtal = config->xtal; | |
| 466 | − dev->ts_mode = config->ts_mode; | |
| 467 | − dev->ts_clock = config->ts_clock; | |
| 480 | + dev->i2c_write_max = pdata->i2c_wr_max ? pdata->i2c_wr_max : ~0; | |
| 481 | + dev->clk = pdata->xtal; | |
| 482 | + dev->ts_mode = pdata->ts_mode; | |
| 483 | + dev->ts_clk = pdata->ts_clock; | |
| 468 | 484 | dev->client[0] = client; |
| 469 | 485 | dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); |
| 470 | 486 | if (IS_ERR(dev->regmap[0])) { |
| @@ -472,15 +488,25 @@ static int mn88472_probe(struct i2c_client *client, · 1 unmodified line | ||
| 472 | 488 | goto err_kfree; |
| 473 | 489 | } |
| 474 | 490 | |
| 475 | − /* check demod answers to I2C */ | |
| 476 | − ret = regmap_read(dev->regmap[0], 0x00, &utmp); | |
| 491 | + /* Check demod answers with correct chip id */ | |
| 492 | + ret = regmap_read(dev->regmap[0], 0xff, &utmp); | |
| 477 | 493 | if (ret) |
| 478 | 494 | goto err_regmap_0_regmap_exit; |
| 479 | 495 | |
| 496 | + dev_dbg(&client->dev, "chip id=%02x\n", utmp); | |
| 497 | + | |
| 498 | + if (utmp != 0x02) { | |
| 499 | + ret = -ENODEV; | |
| 500 | + goto err_regmap_0_regmap_exit; | |
| 501 | + } | |
| 502 | + | |
| 480 | 503 | /* |
| 481 | − * Chip has three I2C addresses for different register pages. Used | |
| 504 | + * Chip has three I2C addresses for different register banks. Used | |
| 482 | 505 | * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients, |
| 483 | − * 0x1a and 0x1c, in order to get own I2C client for each register page. | |
| 506 | + * 0x1a and 0x1c, in order to get own I2C client for each register bank. | |
| 507 | + * | |
| 508 | + * Also, register bank 2 do not support sequential I/O. Only single | |
| 509 | + * register write or read is allowed to that bank. | |
| 484 | 510 | */ |
| 485 | 511 | dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); |
| 486 | 512 | if (!dev->client[1]) { |
| @@ -510,15 +536,25 @@ static int mn88472_probe(struct i2c_client *client, · 23 unmodified lines | ||
| 510 | 536 | } |
| 511 | 537 | i2c_set_clientdata(dev->client[2], dev); |
| 512 | 538 | |
| 513 | − /* create dvb_frontend */ | |
| 539 | + /* Sleep because chip is active by default */ | |
| 540 | + ret = regmap_write(dev->regmap[2], 0x05, 0x3e); | |
| 541 | + if (ret) | |
| 542 | + goto err_regmap_2_regmap_exit; | |
| 543 | + | |
| 544 | + /* Create dvb frontend */ | |
| 514 | 545 | memcpy(&dev->fe.ops, &mn88472_ops, sizeof(struct dvb_frontend_ops)); |
| 515 | 546 | dev->fe.demodulator_priv = client; |
| 516 | − *config->fe = &dev->fe; | |
| 547 | + *pdata->fe = &dev->fe; | |
| 517 | 548 | i2c_set_clientdata(client, dev); |
| 518 | 549 | |
| 519 | − dev_info(&client->dev, "Panasonic MN88472 successfully attached\n"); | |
| 520 | − return 0; | |
| 550 | + /* Setup callbacks */ | |
| 551 | + pdata->get_dvb_frontend = mn88472_get_dvb_frontend; | |
| 521 | 552 | |
| 553 | + dev_info(&client->dev, "Panasonic MN88472 successfully identified\n"); | |
| 554 | + | |
| 555 | + return 0; | |
| 556 | +err_regmap_2_regmap_exit: | |
| 557 | + regmap_exit(dev->regmap[2]); | |
| 522 | 558 | err_client_2_i2c_unregister_device: |
| 523 | 559 | i2c_unregister_device(dev->client[2]); |
| 524 | 560 | err_regmap_1_regmap_exit: |
| @@ -561,11 +597,12 @@ MODULE_DEVICE_TABLE(i2c, mn88472_id_table); · 36 unmodified lines | ||
| 561 | 597 | |
| 562 | 598 | static struct i2c_driver mn88472_driver = { |
| 563 | 599 | .driver = { |
| 564 | − .name = "mn88472", | |
| 600 | + .name = "mn88472", | |
| 601 | + .suppress_bind_attrs = true, | |
| 565 | 602 | }, |
| 566 | − .probe = mn88472_probe, | |
| 567 | − .remove = mn88472_remove, | |
| 568 | − .id_table = mn88472_id_table, | |
| 603 | + .probe = mn88472_probe, | |
| 604 | + .remove = mn88472_remove, | |
| 605 | + .id_table = mn88472_id_table, | |
| 569 | 606 | }; |
| 570 | 607 | |
| 571 | 608 | module_i2c_driver(mn88472_driver); |
| @@ -19,23 +19,33 @@ · 18 unmodified lines | ||
| 19 | 19 | |
| 20 | 20 | #include <linux/dvb/frontend.h> |
| 21 | 21 | |
| 22 | −enum ts_clock { | |
| 23 | − VARIABLE_TS_CLOCK, | |
| 24 | − FIXED_TS_CLOCK, | |
| 25 | −}; | |
| 22 | +/** | |
| 23 | + * struct mn88472_config - Platform data for the mn88472 driver | |
| 24 | + * @xtal: Clock frequency. | |
| 25 | + * @ts_mode: TS mode. | |
| 26 | + * @ts_clock: TS clock config. | |
| 27 | + * @i2c_wr_max: Max number of bytes driver writes to I2C at once. | |
| 28 | + * @get_dvb_frontend: Get DVB frontend. | |
| 29 | + */ | |
| 26 | 30 | |
| 27 | −enum ts_mode { | |
| 28 | − SERIAL_TS_MODE, | |
| 29 | − PARALLEL_TS_MODE, | |
| 30 | −}; | |
| 31 | +/* Define old names for backward compatibility */ | |
| 32 | +#define VARIABLE_TS_CLOCK MN88472_TS_CLK_VARIABLE | |
| 33 | +#define FIXED_TS_CLOCK MN88472_TS_CLK_FIXED | |
| 34 | +#define SERIAL_TS_MODE MN88472_TS_MODE_SERIAL | |
| 35 | +#define PARALLEL_TS_MODE MN88472_TS_MODE_PARALLEL | |
| 31 | 36 | |
| 32 | 37 | struct mn88472_config { |
| 33 | − /* | |
| 34 | − * Max num of bytes given I2C adapter could write at once. | |
| 35 | − * Default: none | |
| 36 | − */ | |
| 37 | − u16 i2c_wr_max; | |
| 38 | + unsigned int xtal; | |
| 39 | + | |
| 40 | +#define MN88472_TS_MODE_SERIAL 0 | |
| 41 | +#define MN88472_TS_MODE_PARALLEL 1 | |
| 42 | + int ts_mode; | |
| 38 | 43 | |
| 44 | +#define MN88472_TS_CLK_FIXED 0 | |
| 45 | +#define MN88472_TS_CLK_VARIABLE 1 | |
| 46 | + int ts_clock; | |
| 47 | + | |
| 48 | + u16 i2c_wr_max; | |
| 39 | 49 | |
| 40 | 50 | /* Everything after that is returned by the driver. */ |
| 41 | 51 | |
| @@ -43,14 +53,7 @@ struct mn88472_config { · 1 unmodified line | ||
| 43 | 53 | * DVB frontend. |
| 44 | 54 | */ |
| 45 | 55 | struct dvb_frontend **fe; |
| 46 | − | |
| 47 | − /* | |
| 48 | − * Xtal frequency. | |
| 49 | − * Hz | |
| 50 | − */ | |
| 51 | − u32 xtal; | |
| 52 | − int ts_mode; | |
| 53 | − int ts_clock; | |
| 56 | + struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); | |
| 54 | 57 | }; |
| 55 | 58 | |
| 56 | 59 | #endif |
| @@ -28,12 +28,11 @@ struct mn88472_dev { · 27 unmodified lines | ||
| 28 | 28 | struct i2c_client *client[3]; |
| 29 | 29 | struct regmap *regmap[3]; |
| 30 | 30 | struct dvb_frontend fe; |
| 31 | − u16 i2c_wr_max; | |
| 32 | − enum fe_delivery_system delivery_system; | |
| 33 | − bool warm; /* FW running */ | |
| 34 | − u32 xtal; | |
| 35 | − int ts_mode; | |
| 36 | − int ts_clock; | |
| 31 | + u16 i2c_write_max; | |
| 32 | + unsigned int clk; | |
| 33 | + unsigned int active:1; | |
| 34 | + unsigned int ts_mode:1; | |
| 35 | + unsigned int ts_clk:1; | |
| 37 | 36 | }; |
| 38 | 37 | |
| 39 | 38 | #endif |
| @@ -330,7 +330,7 @@ static int mn88473_init(struct dvb_frontend *fe) · 329 unmodified lines | ||
| 330 | 330 | /* Request the firmware, this will block and timeout */ |
| 331 | 331 | ret = request_firmware(&fw, name, &client->dev); |
| 332 | 332 | if (ret) { |
| 333 | − dev_err(&client->dev, "firmare file '%s' not found\n", name); | |
| 333 | + dev_err(&client->dev, "firmware file '%s' not found\n", name); | |
| 334 | 334 | goto err; |
| 335 | 335 | } |
| 336 | 336 | |
| @@ -536,7 +536,7 @@ static int mn88473_probe(struct i2c_client *client, · 199 unmodified lines | ||
| 536 | 536 | /* Sleep because chip is active by default */ |
| 537 | 537 | ret = regmap_write(dev->regmap[2], 0x05, 0x3e); |
| 538 | 538 | if (ret) |
| 539 | − goto err_client_2_i2c_unregister_device; | |
| 539 | + goto err_regmap_2_regmap_exit; | |
| 540 | 540 | |
| 541 | 541 | /* Create dvb frontend */ |
| 542 | 542 | memcpy(&dev->frontend.ops, &mn88473_ops, sizeof(dev->frontend.ops)); |
| @@ -547,7 +547,8 @@ static int mn88473_probe(struct i2c_client *client, · 4 unmodified lines | ||
| 547 | 547 | dev_info(&client->dev, "Panasonic MN88473 successfully identified\n"); |
| 548 | 548 | |
| 549 | 549 | return 0; |
| 550 | − | |
| 550 | +err_regmap_2_regmap_exit: | |
| 551 | + regmap_exit(dev->regmap[2]); | |
| 551 | 552 | err_client_2_i2c_unregister_device: |
| 552 | 553 | i2c_unregister_device(dev->client[2]); |
| 553 | 554 | err_regmap_1_regmap_exit: |
| @@ -135,8 +135,6 @@ static int rtl2830_init(struct dvb_frontend *fe) · 134 unmodified lines | ||
| 135 | 135 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 136 | 136 | c->post_bit_count.len = 1; |
| 137 | 137 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 138 | − /* start statistics polling */ | |
| 139 | − schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); | |
| 140 | 138 | |
| 141 | 139 | dev->sleeping = false; |
| 142 | 140 | |
| @@ -152,8 +150,6 @@ static int rtl2830_sleep(struct dvb_frontend *fe) · 9 unmodified lines | ||
| 152 | 150 | struct rtl2830_dev *dev = i2c_get_clientdata(client); |
| 153 | 151 | |
| 154 | 152 | dev->sleeping = true; |
| 155 | − /* stop statistics polling */ | |
| 156 | − cancel_delayed_work_sync(&dev->stat_work); | |
| 157 | 153 | dev->fe_status = 0; |
| 158 | 154 | |
| 159 | 155 | return 0; |
| @@ -396,8 +392,10 @@ static int rtl2830_read_status(struct dvb_frontend *fe, enum fe_status *status) · 236 unmodified lines | ||
| 396 | 392 | { |
| 397 | 393 | struct i2c_client *client = fe->demodulator_priv; |
| 398 | 394 | struct rtl2830_dev *dev = i2c_get_clientdata(client); |
| 399 | − int ret; | |
| 400 | − u8 u8tmp; | |
| 395 | + struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; | |
| 396 | + int ret, stmp; | |
| 397 | + unsigned int utmp; | |
| 398 | + u8 u8tmp, buf[2]; | |
| 401 | 399 | |
| 402 | 400 | *status = 0; |
| 403 | 401 | |
| @@ -419,6 +417,89 @@ static int rtl2830_read_status(struct dvb_frontend *fe, enum fe_status *status) · 15 unmodified lines | ||
| 419 | 417 | |
| 420 | 418 | dev->fe_status = *status; |
| 421 | 419 | |
| 420 | + /* Signal strength */ | |
| 421 | + if (dev->fe_status & FE_HAS_SIGNAL) { | |
| 422 | + /* Read IF AGC */ | |
| 423 | + ret = rtl2830_bulk_read(client, 0x359, buf, 2); | |
| 424 | + if (ret) | |
| 425 | + goto err; | |
| 426 | + | |
| 427 | + stmp = buf[0] << 8 | buf[1] << 0; | |
| 428 | + stmp = sign_extend32(stmp, 13); | |
| 429 | + utmp = clamp_val(-4 * stmp + 32767, 0x0000, 0xffff); | |
| 430 | + | |
| 431 | + dev_dbg(&client->dev, "IF AGC=%d\n", stmp); | |
| 432 | + | |
| 433 | + c->strength.stat[0].scale = FE_SCALE_RELATIVE; | |
| 434 | + c->strength.stat[0].uvalue = utmp; | |
| 435 | + } else { | |
| 436 | + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 437 | + } | |
| 438 | + | |
| 439 | + /* CNR */ | |
| 440 | + if (dev->fe_status & FE_HAS_VITERBI) { | |
| 441 | + unsigned int hierarchy, constellation; | |
| 442 | + #define CONSTELLATION_NUM 3 | |
| 443 | + #define HIERARCHY_NUM 4 | |
| 444 | + static const u32 constant[CONSTELLATION_NUM][HIERARCHY_NUM] = { | |
| 445 | + {70705899, 70705899, 70705899, 70705899}, | |
| 446 | + {82433173, 82433173, 87483115, 94445660}, | |
| 447 | + {92888734, 92888734, 95487525, 99770748}, | |
| 448 | + }; | |
| 449 | + | |
| 450 | + ret = rtl2830_bulk_read(client, 0x33c, &u8tmp, 1); | |
| 451 | + if (ret) | |
| 452 | + goto err; | |
| 453 | + | |
| 454 | + constellation = (u8tmp >> 2) & 0x03; /* [3:2] */ | |
| 455 | + if (constellation > CONSTELLATION_NUM - 1) | |
| 456 | + goto err; | |
| 457 | + | |
| 458 | + hierarchy = (u8tmp >> 4) & 0x07; /* [6:4] */ | |
| 459 | + if (hierarchy > HIERARCHY_NUM - 1) | |
| 460 | + goto err; | |
| 461 | + | |
| 462 | + ret = rtl2830_bulk_read(client, 0x40c, buf, 2); | |
| 463 | + if (ret) | |
| 464 | + goto err; | |
| 465 | + | |
| 466 | + utmp = buf[0] << 8 | buf[1] << 0; | |
| 467 | + if (utmp) | |
| 468 | + stmp = (constant[constellation][hierarchy] - | |
| 469 | + intlog10(utmp)) / ((1 << 24) / 10000); | |
| 470 | + else | |
| 471 | + stmp = 0; | |
| 472 | + | |
| 473 | + dev_dbg(&client->dev, "CNR raw=%u\n", utmp); | |
| 474 | + | |
| 475 | + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; | |
| 476 | + c->cnr.stat[0].svalue = stmp; | |
| 477 | + } else { | |
| 478 | + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 479 | + } | |
| 480 | + | |
| 481 | + /* BER */ | |
| 482 | + if (dev->fe_status & FE_HAS_LOCK) { | |
| 483 | + ret = rtl2830_bulk_read(client, 0x34e, buf, 2); | |
| 484 | + if (ret) | |
| 485 | + goto err; | |
| 486 | + | |
| 487 | + utmp = buf[0] << 8 | buf[1] << 0; | |
| 488 | + dev->post_bit_error += utmp; | |
| 489 | + dev->post_bit_count += 1000000; | |
| 490 | + | |
| 491 | + dev_dbg(&client->dev, "BER errors=%u total=1000000\n", utmp); | |
| 492 | + | |
| 493 | + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; | |
| 494 | + c->post_bit_error.stat[0].uvalue = dev->post_bit_error; | |
| 495 | + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; | |
| 496 | + c->post_bit_count.stat[0].uvalue = dev->post_bit_count; | |
| 497 | + } else { | |
| 498 | + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 499 | + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 500 | + } | |
| 501 | + | |
| 502 | + | |
| 422 | 503 | return ret; |
| 423 | 504 | err: |
| 424 | 505 | dev_dbg(&client->dev, "failed=%d\n", ret); |
| @@ -503,109 +584,6 @@ static struct dvb_frontend_ops rtl2830_ops = { · 78 unmodified lines | ||
| 503 | 584 | .read_signal_strength = rtl2830_read_signal_strength, |
| 504 | 585 | }; |
| 505 | 586 | |
| 506 | −static void rtl2830_stat_work(struct work_struct *work) | |
| 507 | −{ | |
| 508 | − struct rtl2830_dev *dev = container_of(work, struct rtl2830_dev, stat_work.work); | |
| 509 | − struct i2c_client *client = dev->client; | |
| 510 | − struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; | |
| 511 | − int ret, tmp; | |
| 512 | − u8 u8tmp, buf[2]; | |
| 513 | − u16 u16tmp; | |
| 514 | − | |
| 515 | − dev_dbg(&client->dev, "\n"); | |
| 516 | − | |
| 517 | − /* signal strength */ | |
| 518 | − if (dev->fe_status & FE_HAS_SIGNAL) { | |
| 519 | − struct {signed int x:14; } s; | |
| 520 | − | |
| 521 | − /* read IF AGC */ | |
| 522 | − ret = rtl2830_bulk_read(client, 0x359, buf, 2); | |
| 523 | − if (ret) | |
| 524 | − goto err; | |
| 525 | − | |
| 526 | − u16tmp = buf[0] << 8 | buf[1] << 0; | |
| 527 | − u16tmp &= 0x3fff; /* [13:0] */ | |
| 528 | − tmp = s.x = u16tmp; /* 14-bit bin to 2 complement */ | |
| 529 | − u16tmp = clamp_val(-4 * tmp + 32767, 0x0000, 0xffff); | |
| 530 | − | |
| 531 | − dev_dbg(&client->dev, "IF AGC=%d\n", tmp); | |
| 532 | − | |
| 533 | − c->strength.stat[0].scale = FE_SCALE_RELATIVE; | |
| 534 | − c->strength.stat[0].uvalue = u16tmp; | |
| 535 | − } else { | |
| 536 | − c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 537 | − } | |
| 538 | − | |
| 539 | − /* CNR */ | |
| 540 | − if (dev->fe_status & FE_HAS_VITERBI) { | |
| 541 | − unsigned hierarchy, constellation; | |
| 542 | − #define CONSTELLATION_NUM 3 | |
| 543 | − #define HIERARCHY_NUM 4 | |
| 544 | − static const u32 constant[CONSTELLATION_NUM][HIERARCHY_NUM] = { | |
| 545 | − {70705899, 70705899, 70705899, 70705899}, | |
| 546 | − {82433173, 82433173, 87483115, 94445660}, | |
| 547 | − {92888734, 92888734, 95487525, 99770748}, | |
| 548 | − }; | |
| 549 | − | |
| 550 | − ret = rtl2830_bulk_read(client, 0x33c, &u8tmp, 1); | |
| 551 | − if (ret) | |
| 552 | − goto err; | |
| 553 | − | |
| 554 | − constellation = (u8tmp >> 2) & 0x03; /* [3:2] */ | |
| 555 | − if (constellation > CONSTELLATION_NUM - 1) | |
| 556 | − goto err_schedule_delayed_work; | |
| 557 | − | |
| 558 | − hierarchy = (u8tmp >> 4) & 0x07; /* [6:4] */ | |
| 559 | − if (hierarchy > HIERARCHY_NUM - 1) | |
| 560 | − goto err_schedule_delayed_work; | |
| 561 | − | |
| 562 | − ret = rtl2830_bulk_read(client, 0x40c, buf, 2); | |
| 563 | − if (ret) | |
| 564 | − goto err; | |
| 565 | − | |
| 566 | − u16tmp = buf[0] << 8 | buf[1] << 0; | |
| 567 | − if (u16tmp) | |
| 568 | − tmp = (constant[constellation][hierarchy] - | |
| 569 | − intlog10(u16tmp)) / ((1 << 24) / 10000); | |
| 570 | − else | |
| 571 | − tmp = 0; | |
| 572 | − | |
| 573 | − dev_dbg(&client->dev, "CNR raw=%u\n", u16tmp); | |
| 574 | − | |
| 575 | − c->cnr.stat[0].scale = FE_SCALE_DECIBEL; | |
| 576 | − c->cnr.stat[0].svalue = tmp; | |
| 577 | − } else { | |
| 578 | − c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 579 | − } | |
| 580 | − | |
| 581 | − /* BER */ | |
| 582 | − if (dev->fe_status & FE_HAS_LOCK) { | |
| 583 | − ret = rtl2830_bulk_read(client, 0x34e, buf, 2); | |
| 584 | − if (ret) | |
| 585 | − goto err; | |
| 586 | − | |
| 587 | − u16tmp = buf[0] << 8 | buf[1] << 0; | |
| 588 | − dev->post_bit_error += u16tmp; | |
| 589 | − dev->post_bit_count += 1000000; | |
| 590 | − | |
| 591 | − dev_dbg(&client->dev, "BER errors=%u total=1000000\n", u16tmp); | |
| 592 | − | |
| 593 | − c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; | |
| 594 | − c->post_bit_error.stat[0].uvalue = dev->post_bit_error; | |
| 595 | − c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; | |
| 596 | − c->post_bit_count.stat[0].uvalue = dev->post_bit_count; | |
| 597 | − } else { | |
| 598 | − c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 599 | − c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | |
| 600 | − } | |
| 601 | − | |
| 602 | −err_schedule_delayed_work: | |
| 603 | − schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); | |
| 604 | − return; | |
| 605 | −err: | |
| 606 | − dev_dbg(&client->dev, "failed=%d\n", ret); | |
| 607 | −} | |
| 608 | − | |
| 609 | 587 | static int rtl2830_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) |
| 610 | 588 | { |
| 611 | 589 | struct i2c_client *client = fe->demodulator_priv; |
| @@ -851,7 +829,6 @@ static int rtl2830_probe(struct i2c_client *client, · 239 unmodified lines | ||
| 851 | 829 | dev->client = client; |
| 852 | 830 | dev->pdata = client->dev.platform_data; |
| 853 | 831 | dev->sleeping = true; |
| 854 | − INIT_DELAYED_WORK(&dev->stat_work, rtl2830_stat_work); | |
| 855 | 832 | dev->regmap = regmap_init(&client->dev, ®map_bus, client, |
| 856 | 833 | ®map_config); |
| 857 | 834 | if (IS_ERR(dev->regmap)) { |
| @@ -904,9 +881,6 @@ static int rtl2830_remove(struct i2c_client *client) · 46 unmodified lines | ||
| 904 | 881 | |
| 905 | 882 | dev_dbg(&client->dev, "\n"); |
| 906 | 883 | |
| 907 | − /* stop statistics polling */ | |
| 908 | − cancel_delayed_work_sync(&dev->stat_work); | |
| 909 | − | |
| 910 | 884 | i2c_mux_del_adapters(dev->muxc); |
| 911 | 885 | regmap_exit(dev->regmap); |
| 912 | 886 | kfree(dev); |
| @@ -922,7 +896,8 @@ MODULE_DEVICE_TABLE(i2c, rtl2830_id_table); · 9 unmodified lines | ||
| 922 | 896 | |
| 923 | 897 | static struct i2c_driver rtl2830_driver = { |
| 924 | 898 | .driver = { |
| 925 | − .name = "rtl2830", | |
| 899 | + .name = "rtl2830", | |
| 900 | + .suppress_bind_attrs = true, | |
| 926 | 901 | }, |
| 927 | 902 | .probe = rtl2830_probe, |
| 928 | 903 | .remove = rtl2830_remove, |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | #include <linux/i2c-mux.h> |
| 25 | 25 | #include <linux/math64.h> |
| 26 | 26 | #include <linux/regmap.h> |
| 27 | +#include <linux/bitops.h> | |
| 27 | 28 | |
| 28 | 29 | struct rtl2830_dev { |
| 29 | 30 | struct rtl2830_platform_data *pdata; |
| @@ -33,7 +34,6 @@ struct rtl2830_dev { · 3 unmodified lines | ||
| 33 | 34 | struct dvb_frontend fe; |
| 34 | 35 | bool sleeping; |
| 35 | 36 | unsigned long filters; |
| 36 | − struct delayed_work stat_work; | |
| 37 | 37 | enum fe_status fe_status; |
| 38 | 38 | u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */ |
| 39 | 39 | u64 post_bit_error; |
| @@ -947,6 +947,8 @@ static int rtl2832_slave_ts_ctrl(struct i2c_client *client, bool enable) · 946 unmodified lines | ||
| 947 | 947 | goto err; |
| 948 | 948 | } |
| 949 | 949 | |
| 950 | + dev->slave_ts = enable; | |
| 951 | + | |
| 950 | 952 | return 0; |
| 951 | 953 | err: |
| 952 | 954 | dev_dbg(&client->dev, "failed=%d\n", ret); |
| @@ -960,7 +962,7 @@ static int rtl2832_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) · 7 unmodified lines | ||
| 960 | 962 | int ret; |
| 961 | 963 | u8 u8tmp; |
| 962 | 964 | |
| 963 | − dev_dbg(&client->dev, "onoff=%d\n", onoff); | |
| 965 | + dev_dbg(&client->dev, "onoff=%d, slave_ts=%d\n", onoff, dev->slave_ts); | |
| 964 | 966 | |
| 965 | 967 | /* enable / disable PID filter */ |
| 966 | 968 | if (onoff) |
| @@ -968,7 +970,10 @@ static int rtl2832_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) · 1 unmodified line | ||
| 968 | 970 | else |
| 969 | 971 | u8tmp = 0x00; |
| 970 | 972 | |
| 971 | − ret = regmap_update_bits(dev->regmap, 0x061, 0xc0, u8tmp); | |
| 973 | + if (dev->slave_ts) | |
| 974 | + ret = regmap_update_bits(dev->regmap, 0x021, 0xc0, u8tmp); | |
| 975 | + else | |
| 976 | + ret = regmap_update_bits(dev->regmap, 0x061, 0xc0, u8tmp); | |
| 972 | 977 | if (ret) |
| 973 | 978 | goto err; |
| 974 | 979 | |
| @@ -986,8 +991,8 @@ static int rtl2832_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, · 11 unmodified lines | ||
| 986 | 991 | int ret; |
| 987 | 992 | u8 buf[4]; |
| 988 | 993 | |
| 989 | − dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d\n", | |
| 990 | − index, pid, onoff); | |
| 994 | + dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d slave_ts=%d\n", | |
| 995 | + index, pid, onoff, dev->slave_ts); | |
| 991 | 996 | |
| 992 | 997 | /* skip invalid PIDs (0x2000) */ |
| 993 | 998 | if (pid > 0x1fff || index > 32) |
| @@ -1003,14 +1008,22 @@ static int rtl2832_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, · 9 unmodified lines | ||
| 1003 | 1008 | buf[1] = (dev->filters >> 8) & 0xff; |
| 1004 | 1009 | buf[2] = (dev->filters >> 16) & 0xff; |
| 1005 | 1010 | buf[3] = (dev->filters >> 24) & 0xff; |
| 1006 | − ret = regmap_bulk_write(dev->regmap, 0x062, buf, 4); | |
| 1011 | + | |
| 1012 | + if (dev->slave_ts) | |
| 1013 | + ret = regmap_bulk_write(dev->regmap, 0x022, buf, 4); | |
| 1014 | + else | |
| 1015 | + ret = regmap_bulk_write(dev->regmap, 0x062, buf, 4); | |
| 1007 | 1016 | if (ret) |
| 1008 | 1017 | goto err; |
| 1009 | 1018 | |
| 1010 | 1019 | /* add PID */ |
| 1011 | 1020 | buf[0] = (pid >> 8) & 0xff; |
| 1012 | 1021 | buf[1] = (pid >> 0) & 0xff; |
| 1013 | − ret = regmap_bulk_write(dev->regmap, 0x066 + 2 * index, buf, 2); | |
| 1022 | + | |
| 1023 | + if (dev->slave_ts) | |
| 1024 | + ret = regmap_bulk_write(dev->regmap, 0x026 + 2 * index, buf, 2); | |
| 1025 | + else | |
| 1026 | + ret = regmap_bulk_write(dev->regmap, 0x066 + 2 * index, buf, 2); | |
| 1014 | 1027 | if (ret) |
| 1015 | 1028 | goto err; |
| 1016 | 1029 | |
| @@ -1135,6 +1148,7 @@ MODULE_DEVICE_TABLE(i2c, rtl2832_id_table); · 118 unmodified lines | ||
| 1135 | 1148 | static struct i2c_driver rtl2832_driver = { |
| 1136 | 1149 | .driver = { |
| 1137 | 1150 | .name = "rtl2832", |
| 1151 | + .suppress_bind_attrs = true, | |
| 1138 | 1152 | }, |
| 1139 | 1153 | .probe = rtl2832_probe, |
| 1140 | 1154 | .remove = rtl2832_remove, |
| @@ -44,6 +44,7 @@ struct rtl2832_dev { · 43 unmodified lines | ||
| 44 | 44 | bool sleeping; |
| 45 | 45 | struct delayed_work i2c_gate_work; |
| 46 | 46 | unsigned long filters; /* PID filter */ |
| 47 | + bool slave_ts; | |
| 47 | 48 | }; |
| 48 | 49 | |
| 49 | 50 | struct rtl2832_reg_entry { |
| @@ -452,7 +452,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh, · 451 unmodified lines | ||
| 452 | 452 | /* Videobuf2 operations */ |
| 453 | 453 | static int rtl2832_sdr_queue_setup(struct vb2_queue *vq, |
| 454 | 454 | unsigned int *nbuffers, |
| 455 | − unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) | |
| 455 | + unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) | |
| 456 | 456 | { |
| 457 | 457 | struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq); |
| 458 | 458 | struct platform_device *pdev = dev->pdev; |
| @@ -357,9 +357,7 @@ static int si2168_init(struct dvb_frontend *fe) · 356 unmodified lines | ||
| 357 | 357 | struct si2168_dev *dev = i2c_get_clientdata(client); |
| 358 | 358 | int ret, len, remaining; |
| 359 | 359 | const struct firmware *fw; |
| 360 | − const char *fw_name; | |
| 361 | 360 | struct si2168_cmd cmd; |
| 362 | − unsigned int chip_id; | |
| 363 | 361 | |
| 364 | 362 | dev_dbg(&client->dev, "\n"); |
| 365 | 363 | |
| @@ -371,7 +369,7 @@ static int si2168_init(struct dvb_frontend *fe) · 5 unmodified lines | ||
| 371 | 369 | if (ret) |
| 372 | 370 | goto err; |
| 373 | 371 | |
| 374 | − if (dev->fw_loaded) { | |
| 372 | + if (dev->warm) { | |
| 375 | 373 | /* resume */ |
| 376 | 374 | memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8); |
| 377 | 375 | cmd.wlen = 8; |
| @@ -398,49 +396,14 @@ static int si2168_init(struct dvb_frontend *fe) · 20 unmodified lines | ||
| 398 | 396 | if (ret) |
| 399 | 397 | goto err; |
| 400 | 398 | |
| 401 | − /* query chip revision */ | |
| 402 | − memcpy(cmd.args, "\x02", 1); | |
| 403 | − cmd.wlen = 1; | |
| 404 | − cmd.rlen = 13; | |
| 405 | − ret = si2168_cmd_execute(client, &cmd); | |
| 406 | − if (ret) | |
| 407 | − goto err; | |
| 408 | − | |
| 409 | − chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 | | |
| 410 | − cmd.args[4] << 0; | |
| 411 | − | |
| 412 | − #define SI2168_A20 ('A' << 24 | 68 << 16 | '2' << 8 | '0' << 0) | |
| 413 | − #define SI2168_A30 ('A' << 24 | 68 << 16 | '3' << 8 | '0' << 0) | |
| 414 | − #define SI2168_B40 ('B' << 24 | 68 << 16 | '4' << 8 | '0' << 0) | |
| 415 | − | |
| 416 | − switch (chip_id) { | |
| 417 | − case SI2168_A20: | |
| 418 | − fw_name = SI2168_A20_FIRMWARE; | |
| 419 | − break; | |
| 420 | − case SI2168_A30: | |
| 421 | − fw_name = SI2168_A30_FIRMWARE; | |
| 422 | − break; | |
| 423 | − case SI2168_B40: | |
| 424 | − fw_name = SI2168_B40_FIRMWARE; | |
| 425 | − break; | |
| 426 | − default: | |
| 427 | − dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n", | |
| 428 | − cmd.args[2], cmd.args[1], | |
| 429 | − cmd.args[3], cmd.args[4]); | |
| 430 | − ret = -EINVAL; | |
| 431 | − goto err; | |
| 432 | − } | |
| 433 | − | |
| 434 | − dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n", | |
| 435 | − cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); | |
| 436 | − | |
| 437 | 399 | /* request the firmware, this will block and timeout */ |
| 438 | − ret = request_firmware(&fw, fw_name, &client->dev); | |
| 400 | + ret = request_firmware(&fw, dev->firmware_name, &client->dev); | |
| 439 | 401 | if (ret) { |
| 440 | 402 | /* fallback mechanism to handle old name for Si2168 B40 fw */ |
| 441 | − if (chip_id == SI2168_B40) { | |
| 442 | − fw_name = SI2168_B40_FIRMWARE_FALLBACK; | |
| 443 | − ret = request_firmware(&fw, fw_name, &client->dev); | |
| 403 | + if (dev->chip_id == SI2168_CHIP_ID_B40) { | |
| 404 | + dev->firmware_name = SI2168_B40_FIRMWARE_FALLBACK; | |
| 405 | + ret = request_firmware(&fw, dev->firmware_name, | |
| 406 | + &client->dev); | |
| 444 | 407 | } |
| 445 | 408 | |
| 446 | 409 | if (ret == 0) { |
| @@ -450,13 +413,13 @@ static int si2168_init(struct dvb_frontend *fe) · 3 unmodified lines | ||
| 450 | 413 | } else { |
| 451 | 414 | dev_err(&client->dev, |
| 452 | 415 | "firmware file '%s' not found\n", |
| 453 | − fw_name); | |
| 416 | + dev->firmware_name); | |
| 454 | 417 | goto err_release_firmware; |
| 455 | 418 | } |
| 456 | 419 | } |
| 457 | 420 | |
| 458 | 421 | dev_info(&client->dev, "downloading firmware from file '%s'\n", |
| 459 | − fw_name); | |
| 422 | + dev->firmware_name); | |
| 460 | 423 | |
| 461 | 424 | if ((fw->size % 17 == 0) && (fw->data[0] > 5)) { |
| 462 | 425 | /* firmware is in the new format */ |
| @@ -511,8 +474,11 @@ static int si2168_init(struct dvb_frontend *fe) · 48 unmodified lines | ||
| 511 | 474 | if (ret) |
| 512 | 475 | goto err; |
| 513 | 476 | |
| 514 | − dev_info(&client->dev, "firmware version: %c.%c.%d\n", | |
| 515 | − cmd.args[6], cmd.args[7], cmd.args[8]); | |
| 477 | + dev->version = (cmd.args[9] + '@') << 24 | (cmd.args[6] - '0') << 16 | | |
| 478 | + (cmd.args[7] - '0') << 8 | (cmd.args[8]) << 0; | |
| 479 | + dev_info(&client->dev, "firmware version: %c %d.%d.%d\n", | |
| 480 | + dev->version >> 24 & 0xff, dev->version >> 16 & 0xff, | |
| 481 | + dev->version >> 8 & 0xff, dev->version >> 0 & 0xff); | |
| 516 | 482 | |
| 517 | 483 | /* set ts mode */ |
| 518 | 484 | memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); |
| @@ -525,7 +491,7 @@ static int si2168_init(struct dvb_frontend *fe) · 6 unmodified lines | ||
| 525 | 491 | if (ret) |
| 526 | 492 | goto err; |
| 527 | 493 | |
| 528 | − dev->fw_loaded = true; | |
| 494 | + dev->warm = true; | |
| 529 | 495 | warm: |
| 530 | 496 | dev->active = true; |
| 531 | 497 | |
| @@ -549,6 +515,10 @@ static int si2168_sleep(struct dvb_frontend *fe) · 17 unmodified lines | ||
| 549 | 515 | |
| 550 | 516 | dev->active = false; |
| 551 | 517 | |
| 518 | + /* Firmware B 4.0-11 or later loses warm state during sleep */ | |
| 519 | + if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) | |
| 520 | + dev->warm = false; | |
| 521 | + | |
| 552 | 522 | memcpy(cmd.args, "\x13", 1); |
| 553 | 523 | cmd.wlen = 1; |
| 554 | 524 | cmd.rlen = 0; |
| @@ -653,6 +623,7 @@ static int si2168_probe(struct i2c_client *client, · 98 unmodified lines | ||
| 653 | 623 | struct si2168_config *config = client->dev.platform_data; |
| 654 | 624 | struct si2168_dev *dev; |
| 655 | 625 | int ret; |
| 626 | + struct si2168_cmd cmd; | |
| 656 | 627 | |
| 657 | 628 | dev_dbg(&client->dev, "\n"); |
| 658 | 629 | |
| @@ -663,8 +634,56 @@ static int si2168_probe(struct i2c_client *client, · 4 unmodified lines | ||
| 663 | 634 | goto err; |
| 664 | 635 | } |
| 665 | 636 | |
| 637 | + i2c_set_clientdata(client, dev); | |
| 666 | 638 | mutex_init(&dev->i2c_mutex); |
| 667 | 639 | |
| 640 | + /* Initialize */ | |
| 641 | + memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13); | |
| 642 | + cmd.wlen = 13; | |
| 643 | + cmd.rlen = 0; | |
| 644 | + ret = si2168_cmd_execute(client, &cmd); | |
| 645 | + if (ret) | |
| 646 | + goto err_kfree; | |
| 647 | + | |
| 648 | + /* Power up */ | |
| 649 | + memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8); | |
| 650 | + cmd.wlen = 8; | |
| 651 | + cmd.rlen = 1; | |
| 652 | + ret = si2168_cmd_execute(client, &cmd); | |
| 653 | + if (ret) | |
| 654 | + goto err_kfree; | |
| 655 | + | |
| 656 | + /* Query chip revision */ | |
| 657 | + memcpy(cmd.args, "\x02", 1); | |
| 658 | + cmd.wlen = 1; | |
| 659 | + cmd.rlen = 13; | |
| 660 | + ret = si2168_cmd_execute(client, &cmd); | |
| 661 | + if (ret) | |
| 662 | + goto err_kfree; | |
| 663 | + | |
| 664 | + dev->chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | | |
| 665 | + cmd.args[3] << 8 | cmd.args[4] << 0; | |
| 666 | + | |
| 667 | + switch (dev->chip_id) { | |
| 668 | + case SI2168_CHIP_ID_A20: | |
| 669 | + dev->firmware_name = SI2168_A20_FIRMWARE; | |
| 670 | + break; | |
| 671 | + case SI2168_CHIP_ID_A30: | |
| 672 | + dev->firmware_name = SI2168_A30_FIRMWARE; | |
| 673 | + break; | |
| 674 | + case SI2168_CHIP_ID_B40: | |
| 675 | + dev->firmware_name = SI2168_B40_FIRMWARE; | |
| 676 | + break; | |
| 677 | + default: | |
| 678 | + dev_dbg(&client->dev, "unknown chip version Si21%d-%c%c%c\n", | |
| 679 | + cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); | |
| 680 | + ret = -ENODEV; | |
| 681 | + goto err_kfree; | |
| 682 | + } | |
| 683 | + | |
| 684 | + dev->version = (cmd.args[1]) << 24 | (cmd.args[3] - '0') << 16 | | |
| 685 | + (cmd.args[4] - '0') << 8 | (cmd.args[5]) << 0; | |
| 686 | + | |
| 668 | 687 | /* create mux i2c adapter for tuner */ |
| 669 | 688 | dev->muxc = i2c_mux_alloc(client->adapter, &client->dev, |
| 670 | 689 | 1, 0, I2C_MUX_LOCKED, |
| @@ -686,11 +705,14 @@ static int si2168_probe(struct i2c_client *client, · 15 unmodified lines | ||
| 686 | 705 | dev->ts_mode = config->ts_mode; |
| 687 | 706 | dev->ts_clock_inv = config->ts_clock_inv; |
| 688 | 707 | dev->ts_clock_gapped = config->ts_clock_gapped; |
| 689 | − dev->fw_loaded = false; | |
| 690 | 708 | |
| 691 | − i2c_set_clientdata(client, dev); | |
| 709 | + dev_info(&client->dev, "Silicon Labs Si2168-%c%d%d successfully identified\n", | |
| 710 | + dev->version >> 24 & 0xff, dev->version >> 16 & 0xff, | |
| 711 | + dev->version >> 8 & 0xff); | |
| 712 | + dev_info(&client->dev, "firmware version: %c %d.%d.%d\n", | |
| 713 | + dev->version >> 24 & 0xff, dev->version >> 16 & 0xff, | |
| 714 | + dev->version >> 8 & 0xff, dev->version >> 0 & 0xff); | |
| 692 | 715 | |
| 693 | − dev_info(&client->dev, "Silicon Labs Si2168 successfully attached\n"); | |
| 694 | 716 | return 0; |
| 695 | 717 | err_kfree: |
| 696 | 718 | kfree(dev); |
| @@ -723,7 +745,8 @@ MODULE_DEVICE_TABLE(i2c, si2168_id_table); · 26 unmodified lines | ||
| 723 | 745 | |
| 724 | 746 | static struct i2c_driver si2168_driver = { |
| 725 | 747 | .driver = { |
| 726 | − .name = "si2168", | |
| 748 | + .name = "si2168", | |
| 749 | + .suppress_bind_attrs = true, | |
| 727 | 750 | }, |
| 728 | 751 | .probe = si2168_probe, |
| 729 | 752 | .remove = si2168_remove, |
| @@ -34,8 +34,14 @@ struct si2168_dev { · 33 unmodified lines | ||
| 34 | 34 | struct dvb_frontend fe; |
| 35 | 35 | enum fe_delivery_system delivery_system; |
| 36 | 36 | enum fe_status fe_status; |
| 37 | + #define SI2168_CHIP_ID_A20 ('A' << 24 | 68 << 16 | '2' << 8 | '0' << 0) | |
| 38 | + #define SI2168_CHIP_ID_A30 ('A' << 24 | 68 << 16 | '3' << 8 | '0' << 0) | |
| 39 | + #define SI2168_CHIP_ID_B40 ('B' << 24 | 68 << 16 | '4' << 8 | '0' << 0) | |
| 40 | + unsigned int chip_id; | |
| 41 | + unsigned int version; | |
| 42 | + const char *firmware_name; | |
| 37 | 43 | bool active; |
| 38 | − bool fw_loaded; | |
| 44 | + bool warm; | |
| 39 | 45 | u8 ts_mode; |
| 40 | 46 | bool ts_clock_inv; |
| 41 | 47 | bool ts_clock_gapped; |
| @@ -209,6 +209,7 @@ config VIDEO_ADV7604 · 208 unmodified lines | ||
| 209 | 209 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
| 210 | 210 | depends on GPIOLIB || COMPILE_TEST |
| 211 | 211 | select HDMI |
| 212 | + select MEDIA_CEC_EDID | |
| 212 | 213 | ---help--- |
| 213 | 214 | Support for the Analog Devices ADV7604 video decoder. |
| 214 | 215 | |
| @@ -218,10 +219,18 @@ config VIDEO_ADV7604 · 3 unmodified lines | ||
| 218 | 219 | To compile this driver as a module, choose M here: the |
| 219 | 220 | module will be called adv7604. |
| 220 | 221 | |
| 222 | +config VIDEO_ADV7604_CEC | |
| 223 | + bool "Enable Analog Devices ADV7604 CEC support" | |
| 224 | + depends on VIDEO_ADV7604 && MEDIA_CEC | |
| 225 | + ---help--- | |
| 226 | + When selected the adv7604 will support the optional | |
| 227 | + HDMI CEC feature. | |
| 228 | + | |
| 221 | 229 | config VIDEO_ADV7842 |
| 222 | 230 | tristate "Analog Devices ADV7842 decoder" |
| 223 | 231 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
| 224 | 232 | select HDMI |
| 233 | + select MEDIA_CEC_EDID | |
| 225 | 234 | ---help--- |
| 226 | 235 | Support for the Analog Devices ADV7842 video decoder. |
| 227 | 236 | |
| @@ -231,6 +240,13 @@ config VIDEO_ADV7842 · 3 unmodified lines | ||
| 231 | 240 | To compile this driver as a module, choose M here: the |
| 232 | 241 | module will be called adv7842. |
| 233 | 242 | |
| 243 | +config VIDEO_ADV7842_CEC | |
| 244 | + bool "Enable Analog Devices ADV7842 CEC support" | |
| 245 | + depends on VIDEO_ADV7842 && MEDIA_CEC | |
| 246 | + ---help--- | |
| 247 | + When selected the adv7842 will support the optional | |
| 248 | + HDMI CEC feature. | |
| 249 | + | |
| 234 | 250 | config VIDEO_BT819 |
| 235 | 251 | tristate "BT819A VideoStream decoder" |
| 236 | 252 | depends on VIDEO_V4L2 && I2C |
| @@ -447,6 +463,7 @@ config VIDEO_ADV7511 · 210 unmodified lines | ||
| 447 | 463 | tristate "Analog Devices ADV7511 encoder" |
| 448 | 464 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
| 449 | 465 | select HDMI |
| 466 | + select MEDIA_CEC_EDID | |
| 450 | 467 | ---help--- |
| 451 | 468 | Support for the Analog Devices ADV7511 video encoder. |
| 452 | 469 | |
| @@ -455,6 +472,13 @@ config VIDEO_ADV7511 · 2 unmodified lines | ||
| 455 | 472 | To compile this driver as a module, choose M here: the |
| 456 | 473 | module will be called adv7511. |
| 457 | 474 | |
| 475 | +config VIDEO_ADV7511_CEC | |
| 476 | + bool "Enable Analog Devices ADV7511 CEC support" | |
| 477 | + depends on VIDEO_ADV7511 && MEDIA_CEC | |
| 478 | + ---help--- | |
| 479 | + When selected the adv7511 will support the optional | |
| 480 | + HDMI CEC feature. | |
| 481 | + | |
| 458 | 482 | config VIDEO_AD9389B |
| 459 | 483 | tristate "Analog Devices AD9389B encoder" |
| 460 | 484 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
| @@ -33,6 +33,7 @@ · 32 unmodified lines | ||
| 33 | 33 | #include <media/v4l2-ctrls.h> |
| 34 | 34 | #include <media/v4l2-dv-timings.h> |
| 35 | 35 | #include <media/i2c/adv7511.h> |
| 36 | +#include <media/cec.h> | |
| 36 | 37 | |
| 37 | 38 | static int debug; |
| 38 | 39 | module_param(debug, int, 0644); |
| @@ -59,6 +60,8 @@ MODULE_LICENSE("GPL v2"); · 20 unmodified lines | ||
| 59 | 60 | #define ADV7511_MIN_PIXELCLOCK 20000000 |
| 60 | 61 | #define ADV7511_MAX_PIXELCLOCK 225000000 |
| 61 | 62 | |
| 63 | +#define ADV7511_MAX_ADDRS (3) | |
| 64 | + | |
| 62 | 65 | /* |
| 63 | 66 | ********************************************************************** |
| 64 | 67 | * |
| @@ -90,12 +93,20 @@ struct adv7511_state { · 25 unmodified lines | ||
| 90 | 93 | struct v4l2_ctrl_handler hdl; |
| 91 | 94 | int chip_revision; |
| 92 | 95 | u8 i2c_edid_addr; |
| 93 | − u8 i2c_cec_addr; | |
| 94 | 96 | u8 i2c_pktmem_addr; |
| 97 | + u8 i2c_cec_addr; | |
| 98 | + | |
| 99 | + struct i2c_client *i2c_cec; | |
| 100 | + struct cec_adapter *cec_adap; | |
| 101 | + u8 cec_addr[ADV7511_MAX_ADDRS]; | |
| 102 | + u8 cec_valid_addrs; | |
| 103 | + bool cec_enabled_adap; | |
| 104 | + | |
| 95 | 105 | /* Is the adv7511 powered on? */ |
| 96 | 106 | bool power_on; |
| 97 | 107 | /* Did we receive hotplug and rx-sense signals? */ |
| 98 | 108 | bool have_monitor; |
| 109 | + bool enabled_irq; | |
| 99 | 110 | /* timings from s_dv_timings */ |
| 100 | 111 | struct v4l2_dv_timings dv_timings; |
| 101 | 112 | u32 fmt_code; |
| @@ -227,7 +238,7 @@ static int adv_smbus_read_i2c_block_data(struct i2c_client *client, · 125 unmodified lines | ||
| 227 | 238 | return ret; |
| 228 | 239 | } |
| 229 | 240 | |
| 230 | −static inline void adv7511_edid_rd(struct v4l2_subdev *sd, u16 len, u8 *buf) | |
| 241 | +static void adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t *buf) | |
| 231 | 242 | { |
| 232 | 243 | struct adv7511_state *state = get_adv7511_state(sd); |
| 233 | 244 | int i; |
| @@ -242,6 +253,34 @@ static inline void adv7511_edid_rd(struct v4l2_subdev *sd, u16 len, u8 *buf) · 8 unmodified lines | ||
| 242 | 253 | v4l2_err(sd, "%s: i2c read error\n", __func__); |
| 243 | 254 | } |
| 244 | 255 | |
| 256 | +static inline int adv7511_cec_read(struct v4l2_subdev *sd, u8 reg) | |
| 257 | +{ | |
| 258 | + struct adv7511_state *state = get_adv7511_state(sd); | |
| 259 | + | |
| 260 | + return i2c_smbus_read_byte_data(state->i2c_cec, reg); | |
| 261 | +} | |
| 262 | + | |
| 263 | +static int adv7511_cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) | |
| 264 | +{ | |
| 265 | + struct adv7511_state *state = get_adv7511_state(sd); | |
| 266 | + int ret; | |
| 267 | + int i; | |
| 268 | + | |
| 269 | + for (i = 0; i < 3; i++) { | |
| 270 | + ret = i2c_smbus_write_byte_data(state->i2c_cec, reg, val); | |
| 271 | + if (ret == 0) | |
| 272 | + return 0; | |
| 273 | + } | |
| 274 | + v4l2_err(sd, "%s: I2C Write Problem\n", __func__); | |
| 275 | + return ret; | |
| 276 | +} | |
| 277 | + | |
| 278 | +static inline int adv7511_cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, | |
| 279 | + u8 val) | |
| 280 | +{ | |
| 281 | + return adv7511_cec_write(sd, reg, (adv7511_cec_read(sd, reg) & mask) | val); | |
| 282 | +} | |
| 283 | + | |
| 245 | 284 | static int adv7511_pktmem_rd(struct v4l2_subdev *sd, u8 reg) |
| 246 | 285 | { |
| 247 | 286 | struct adv7511_state *state = get_adv7511_state(sd); |
| @@ -343,28 +382,20 @@ static void adv7511_csc_rgb_full2limit(struct v4l2_subdev *sd, bool enable) · 95 unmodified lines | ||
| 343 | 382 | } |
| 344 | 383 | } |
| 345 | 384 | |
| 346 | −static void adv7511_set_IT_content_AVI_InfoFrame(struct v4l2_subdev *sd) | |
| 385 | +static void adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2_ctrl *ctrl) | |
| 347 | 386 | { |
| 348 | 387 | struct adv7511_state *state = get_adv7511_state(sd); |
| 349 | − if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { | |
| 350 | − /* CE format, not IT */ | |
| 351 | − adv7511_wr_and_or(sd, 0x57, 0x7f, 0x00); | |
| 352 | − } else { | |
| 353 | − /* IT format */ | |
| 354 | − adv7511_wr_and_or(sd, 0x57, 0x7f, 0x80); | |
| 388 | + | |
| 389 | + /* Only makes sense for RGB formats */ | |
| 390 | + if (state->fmt_code != MEDIA_BUS_FMT_RGB888_1X24) { | |
| 391 | + /* so just keep quantization */ | |
| 392 | + adv7511_csc_rgb_full2limit(sd, false); | |
| 393 | + return; | |
| 355 | 394 | } |
| 356 | −} | |
| 357 | 395 | |
| 358 | −static int adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2_ctrl *ctrl) | |
| 359 | −{ | |
| 360 | 396 | switch (ctrl->val) { |
| 361 | − default: | |
| 362 | − return -EINVAL; | |
| 363 | − break; | |
| 364 | − case V4L2_DV_RGB_RANGE_AUTO: { | |
| 397 | + case V4L2_DV_RGB_RANGE_AUTO: | |
| 365 | 398 | /* automatic */ |
| 366 | − struct adv7511_state *state = get_adv7511_state(sd); | |
| 367 | − | |
| 368 | 399 | if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { |
| 369 | 400 | /* CE format, RGB limited range (16-235) */ |
| 370 | 401 | adv7511_csc_rgb_full2limit(sd, true); |
| @@ -372,7 +403,6 @@ static int adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2 · 1 unmodified line | ||
| 372 | 403 | /* not CE format, RGB full range (0-255) */ |
| 373 | 404 | adv7511_csc_rgb_full2limit(sd, false); |
| 374 | 405 | } |
| 375 | − } | |
| 376 | 406 | break; |
| 377 | 407 | case V4L2_DV_RGB_RANGE_LIMITED: |
| 378 | 408 | /* RGB limited range (16-235) */ |
| @@ -383,7 +413,6 @@ static int adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2 · 4 unmodified lines | ||
| 383 | 413 | adv7511_csc_rgb_full2limit(sd, false); |
| 384 | 414 | break; |
| 385 | 415 | } |
| 386 | − return 0; | |
| 387 | 416 | } |
| 388 | 417 | |
| 389 | 418 | /* ------------------------------ CTRL OPS ------------------------------ */ |
| @@ -400,8 +429,10 @@ static int adv7511_s_ctrl(struct v4l2_ctrl *ctrl) · 10 unmodified lines | ||
| 400 | 429 | adv7511_wr_and_or(sd, 0xaf, 0xfd, ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00); |
| 401 | 430 | return 0; |
| 402 | 431 | } |
| 403 | − if (state->rgb_quantization_range_ctrl == ctrl) | |
| 404 | − return adv7511_set_rgb_quantization_mode(sd, ctrl); | |
| 432 | + if (state->rgb_quantization_range_ctrl == ctrl) { | |
| 433 | + adv7511_set_rgb_quantization_mode(sd, ctrl); | |
| 434 | + return 0; | |
| 435 | + } | |
| 405 | 436 | if (state->content_type_ctrl == ctrl) { |
| 406 | 437 | u8 itc, cn; |
| 407 | 438 | |
| @@ -425,16 +456,28 @@ static const struct v4l2_ctrl_ops adv7511_ctrl_ops = { · 17 unmodified lines | ||
| 425 | 456 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 426 | 457 | static void adv7511_inv_register(struct v4l2_subdev *sd) |
| 427 | 458 | { |
| 459 | + struct adv7511_state *state = get_adv7511_state(sd); | |
| 460 | + | |
| 428 | 461 | v4l2_info(sd, "0x000-0x0ff: Main Map\n"); |
| 462 | + if (state->i2c_cec) | |
| 463 | + v4l2_info(sd, "0x100-0x1ff: CEC Map\n"); | |
| 429 | 464 | } |
| 430 | 465 | |
| 431 | 466 | static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) |
| 432 | 467 | { |
| 468 | + struct adv7511_state *state = get_adv7511_state(sd); | |
| 469 | + | |
| 433 | 470 | reg->size = 1; |
| 434 | 471 | switch (reg->reg >> 8) { |
| 435 | 472 | case 0: |
| 436 | 473 | reg->val = adv7511_rd(sd, reg->reg & 0xff); |
| 437 | 474 | break; |
| 475 | + case 1: | |
| 476 | + if (state->i2c_cec) { | |
| 477 | + reg->val = adv7511_cec_read(sd, reg->reg & 0xff); | |
| 478 | + break; | |
| 479 | + } | |
| 480 | + /* fall through */ | |
| 438 | 481 | default: |
| 439 | 482 | v4l2_info(sd, "Register %03llx not supported\n", reg->reg); |
| 440 | 483 | adv7511_inv_register(sd); |
| @@ -445,10 +488,18 @@ static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * · 4 unmodified lines | ||
| 445 | 488 | |
| 446 | 489 | static int adv7511_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) |
| 447 | 490 | { |
| 491 | + struct adv7511_state *state = get_adv7511_state(sd); | |
| 492 | + | |
| 448 | 493 | switch (reg->reg >> 8) { |
| 449 | 494 | case 0: |
| 450 | 495 | adv7511_wr(sd, reg->reg & 0xff, reg->val & 0xff); |
| 451 | 496 | break; |
| 497 | + case 1: | |
| 498 | + if (state->i2c_cec) { | |
| 499 | + adv7511_cec_write(sd, reg->reg & 0xff, reg->val & 0xff); | |
| 500 | + break; | |
| 501 | + } | |
| 502 | + /* fall through */ | |
| 452 | 503 | default: |
| 453 | 504 | v4l2_info(sd, "Register %03llx not supported\n", reg->reg); |
| 454 | 505 | adv7511_inv_register(sd); |
| @@ -536,6 +587,7 @@ static int adv7511_log_status(struct v4l2_subdev *sd) · 81 unmodified lines | ||
| 536 | 587 | { |
| 537 | 588 | struct adv7511_state *state = get_adv7511_state(sd); |
| 538 | 589 | struct adv7511_state_edid *edid = &state->edid; |
| 590 | + int i; | |
| 539 | 591 | |
| 540 | 592 | static const char * const states[] = { |
| 541 | 593 | "in reset", |
| @@ -605,7 +657,23 @@ static int adv7511_log_status(struct v4l2_subdev *sd) · 63 unmodified lines | ||
| 605 | 657 | else |
| 606 | 658 | v4l2_info(sd, "no timings set\n"); |
| 607 | 659 | v4l2_info(sd, "i2c edid addr: 0x%x\n", state->i2c_edid_addr); |
| 660 | + | |
| 661 | + if (state->i2c_cec == NULL) | |
| 662 | + return 0; | |
| 663 | + | |
| 608 | 664 | v4l2_info(sd, "i2c cec addr: 0x%x\n", state->i2c_cec_addr); |
| 665 | + | |
| 666 | + v4l2_info(sd, "CEC: %s\n", state->cec_enabled_adap ? | |
| 667 | + "enabled" : "disabled"); | |
| 668 | + if (state->cec_enabled_adap) { | |
| 669 | + for (i = 0; i < ADV7511_MAX_ADDRS; i++) { | |
| 670 | + bool is_valid = state->cec_valid_addrs & (1 << i); | |
| 671 | + | |
| 672 | + if (is_valid) | |
| 673 | + v4l2_info(sd, "CEC Logical Address: 0x%x\n", | |
| 674 | + state->cec_addr[i]); | |
| 675 | + } | |
| 676 | + } | |
| 609 | 677 | v4l2_info(sd, "i2c pktmem addr: 0x%x\n", state->i2c_pktmem_addr); |
| 610 | 678 | return 0; |
| 611 | 679 | } |
| @@ -663,15 +731,197 @@ static int adv7511_s_power(struct v4l2_subdev *sd, int on) · 51 unmodified lines | ||
| 663 | 731 | return true; |
| 664 | 732 | } |
| 665 | 733 | |
| 734 | +#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) | |
| 735 | +static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable) | |
| 736 | +{ | |
| 737 | + struct adv7511_state *state = adap->priv; | |
| 738 | + struct v4l2_subdev *sd = &state->sd; | |
| 739 | + | |
| 740 | + if (state->i2c_cec == NULL) | |
| 741 | + return -EIO; | |
| 742 | + | |
| 743 | + if (!state->cec_enabled_adap && enable) { | |
| 744 | + /* power up cec section */ | |
| 745 | + adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x01); | |
| 746 | + /* legacy mode and clear all rx buffers */ | |
| 747 | + adv7511_cec_write(sd, 0x4a, 0x07); | |
| 748 | + adv7511_cec_write(sd, 0x4a, 0); | |
| 749 | + adv7511_cec_write_and_or(sd, 0x11, 0xfe, 0); /* initially disable tx */ | |
| 750 | + /* enabled irqs: */ | |
| 751 | + /* tx: ready */ | |
| 752 | + /* tx: arbitration lost */ | |
| 753 | + /* tx: retry timeout */ | |
| 754 | + /* rx: ready 1 */ | |
| 755 | + if (state->enabled_irq) | |
| 756 | + adv7511_wr_and_or(sd, 0x95, 0xc0, 0x39); | |
| 757 | + } else if (state->cec_enabled_adap && !enable) { | |
| 758 | + if (state->enabled_irq) | |
| 759 | + adv7511_wr_and_or(sd, 0x95, 0xc0, 0x00); | |
| 760 | + /* disable address mask 1-3 */ | |
| 761 | + adv7511_cec_write_and_or(sd, 0x4b, 0x8f, 0x00); | |
| 762 | + /* power down cec section */ | |
| 763 | + adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x00); | |
| 764 | + state->cec_valid_addrs = 0; | |
| 765 | + } | |
| 766 | + state->cec_enabled_adap = enable; | |
| 767 | + return 0; | |
| 768 | +} | |
| 769 | + | |
| 770 | +static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) | |
| 771 | +{ | |
| 772 | + struct adv7511_state *state = adap->priv; | |
| 773 | + struct v4l2_subdev *sd = &state->sd; | |
| 774 | + unsigned int i, free_idx = ADV7511_MAX_ADDRS; | |
| 775 | + | |
| 776 | + if (!state->cec_enabled_adap) | |
| 777 | + return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO; | |
| 778 | + | |
| 779 | + if (addr == CEC_LOG_ADDR_INVALID) { | |
| 780 | + adv7511_cec_write_and_or(sd, 0x4b, 0x8f, 0); | |
| 781 | + state->cec_valid_addrs = 0; | |
| 782 | + return 0; | |
| 783 | + } | |
| 784 | + | |
| 785 | + for (i = 0; i < ADV7511_MAX_ADDRS; i++) { | |
| 786 | + bool is_valid = state->cec_valid_addrs & (1 << i); | |
| 787 | + | |
| 788 | + if (free_idx == ADV7511_MAX_ADDRS && !is_valid) | |
| 789 | + free_idx = i; | |
| 790 | + if (is_valid && state->cec_addr[i] == addr) | |
| 791 | + return 0; | |
| 792 | + } | |
| 793 | + if (i == ADV7511_MAX_ADDRS) { | |
| 794 | + i = free_idx; | |
| 795 | + if (i == ADV7511_MAX_ADDRS) | |
| 796 | + return -ENXIO; | |
| 797 | + } | |
| 798 | + state->cec_addr[i] = addr; | |
| 799 | + state->cec_valid_addrs |= 1 << i; | |
| 800 | + | |
| 801 | + switch (i) { | |
| 802 | + case 0: | |
| 803 | + /* enable address mask 0 */ | |
| 804 | + adv7511_cec_write_and_or(sd, 0x4b, 0xef, 0x10); | |
| 805 | + /* set address for mask 0 */ | |
| 806 | + adv7511_cec_write_and_or(sd, 0x4c, 0xf0, addr); | |
| 807 | + break; | |
| 808 | + case 1: | |
| 809 | + /* enable address mask 1 */ | |
| 810 | + adv7511_cec_write_and_or(sd, 0x4b, 0xdf, 0x20); | |
| 811 | + /* set address for mask 1 */ | |
| 812 | + adv7511_cec_write_and_or(sd, 0x4c, 0x0f, addr << 4); | |
| 813 | + break; | |
| 814 | + case 2: | |
| 815 | + /* enable address mask 2 */ | |
| 816 | + adv7511_cec_write_and_or(sd, 0x4b, 0xbf, 0x40); | |
| 817 | + /* set address for mask 1 */ | |
| 818 | + adv7511_cec_write_and_or(sd, 0x4d, 0xf0, addr); | |
| 819 | + break; | |
| 820 | + } | |
| 821 | + return 0; | |
| 822 | +} | |
| 823 | + | |
| 824 | +static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | |
| 825 | + u32 signal_free_time, struct cec_msg *msg) | |
| 826 | +{ | |
| 827 | + struct adv7511_state *state = adap->priv; | |
| 828 | + struct v4l2_subdev *sd = &state->sd; | |
| 829 | + u8 len = msg->len; | |
| 830 | + unsigned int i; | |
| 831 | + | |
| 832 | + v4l2_dbg(1, debug, sd, "%s: len %d\n", __func__, len); | |
| 833 | + | |
| 834 | + if (len > 16) { | |
| 835 | + v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len); | |
| 836 | + return -EINVAL; | |
| 837 | + } | |
| 838 | + | |
| 839 | + /* | |
| 840 | + * The number of retries is the number of attempts - 1, but retry | |
| 841 | + * at least once. It's not clear if a value of 0 is allowed, so | |
| 842 | + * let's do at least one retry. | |
| 843 | + */ | |
| 844 | + adv7511_cec_write_and_or(sd, 0x12, ~0x70, max(1, attempts - 1) << 4); | |
| 845 | + | |
| 846 | + /* blocking, clear cec tx irq status */ | |
| 847 | + adv7511_wr_and_or(sd, 0x97, 0xc7, 0x38); | |
| 848 | + | |
| 849 | + /* write data */ | |
| 850 | + for (i = 0; i < len; i++) | |
| 851 | + adv7511_cec_write(sd, i, msg->msg[i]); | |
| 852 | + | |
| 853 | + /* set length (data + header) */ | |
| 854 | + adv7511_cec_write(sd, 0x10, len); | |
| 855 | + /* start transmit, enable tx */ | |
| 856 | + adv7511_cec_write(sd, 0x11, 0x01); | |
| 857 | + return 0; | |
| 858 | +} | |
| 859 | + | |
| 860 | +static void adv_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status) | |
| 861 | +{ | |
| 862 | + struct adv7511_state *state = get_adv7511_state(sd); | |
| 863 | + | |
| 864 | + if ((adv7511_cec_read(sd, 0x11) & 0x01) == 0) { | |
| 865 | + v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__); | |
| 866 | + return; | |
| 867 | + } | |
| 868 | + | |
| 869 | + if (tx_raw_status & 0x10) { | |
| 870 | + v4l2_dbg(1, debug, sd, | |
| 871 | + "%s: tx raw: arbitration lost\n", __func__); | |
| 872 | + cec_transmit_done(state->cec_adap, CEC_TX_STATUS_ARB_LOST, | |
| 873 | + 1, 0, 0, 0); | |
| 874 | + return; | |
| 875 | + } | |
| 876 | + if (tx_raw_status & 0x08) { | |
| 877 | + u8 status; | |
| 878 | + u8 nack_cnt; | |
| 879 | + u8 low_drive_cnt; | |
| 880 | + | |
| 881 | + v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__); | |
| 882 | + /* | |
| 883 | + * We set this status bit since this hardware performs | |
| 884 | + * retransmissions. | |
| 885 | + */ | |
| 886 | + status = CEC_TX_STATUS_MAX_RETRIES; | |
| 887 | + nack_cnt = adv7511_cec_read(sd, 0x14) & 0xf; | |
| 888 | + if (nack_cnt) | |
| 889 | + status |= CEC_TX_STATUS_NACK; | |
| 890 | + low_drive_cnt = adv7511_cec_read(sd, 0x14) >> 4; | |
| 891 | + if (low_drive_cnt) | |
| 892 | + status |= CEC_TX_STATUS_LOW_DRIVE; | |
| 893 | + cec_transmit_done(state->cec_adap, status, | |
| 894 | + 0, nack_cnt, low_drive_cnt, 0); | |
| 895 | + return; | |
| 896 | + } | |
| 897 | + if (tx_raw_status & 0x20) { | |
| 898 | + v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__); | |
| 899 | + cec_transmit_done(state->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); | |
| 900 | + return; | |
| 901 | + } | |
| 902 | +} | |
| 903 | + | |
| 904 | +static const struct cec_adap_ops adv7511_cec_adap_ops = { | |
| 905 | + .adap_enable = adv7511_cec_adap_enable, | |
| 906 | + .adap_log_addr = adv7511_cec_adap_log_addr, | |
| 907 | + .adap_transmit = adv7511_cec_adap_transmit, | |
| 908 | +}; | |
| 909 | +#endif | |
| 910 | + | |
| 666 | 911 | /* Enable interrupts */ |
| 667 | 912 | static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) |
| 668 | 913 | { |
| 914 | + struct adv7511_state *state = get_adv7511_state(sd); | |
| 669 | 915 | u8 irqs = MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT; |
| 670 | 916 | u8 irqs_rd; |
| 671 | 917 | int retries = 100; |
| 672 | 918 | |
| 673 | 919 | v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? "enable" : "disable"); |
| 674 | 920 | |
| 921 | + if (state->enabled_irq == enable) | |
| 922 | + return; | |
| 923 | + state->enabled_irq = enable; | |
| 924 | + | |
| 675 | 925 | /* The datasheet says that the EDID ready interrupt should be |
| 676 | 926 | disabled if there is no hotplug. */ |
| 677 | 927 | if (!enable) |
| @@ -679,6 +929,9 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) · 1 unmodified line | ||
| 679 | 929 | else if (adv7511_have_hotplug(sd)) |
| 680 | 930 | irqs |= MASK_ADV7511_EDID_RDY_INT; |
| 681 | 931 | |
| 932 | + adv7511_wr_and_or(sd, 0x95, 0xc0, | |
| 933 | + (state->cec_enabled_adap && enable) ? 0x39 : 0x00); | |
| 934 | + | |
| 682 | 935 | /* |
| 683 | 936 | * This i2c write can fail (approx. 1 in 1000 writes). But it |
| 684 | 937 | * is essential that this register is correct, so retry it |
| @@ -701,20 +954,53 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) · 16 unmodified lines | ||
| 701 | 954 | static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled) |
| 702 | 955 | { |
| 703 | 956 | u8 irq_status; |
| 957 | + u8 cec_irq; | |
| 704 | 958 | |
| 705 | 959 | /* disable interrupts to prevent a race condition */ |
| 706 | 960 | adv7511_set_isr(sd, false); |
| 707 | 961 | irq_status = adv7511_rd(sd, 0x96); |
| 962 | + cec_irq = adv7511_rd(sd, 0x97); | |
| 708 | 963 | /* clear detected interrupts */ |
| 709 | 964 | adv7511_wr(sd, 0x96, irq_status); |
| 965 | + adv7511_wr(sd, 0x97, cec_irq); | |
| 710 | 966 | |
| 711 | − v4l2_dbg(1, debug, sd, "%s: irq 0x%x\n", __func__, irq_status); | |
| 967 | + v4l2_dbg(1, debug, sd, "%s: irq 0x%x, cec-irq 0x%x\n", __func__, | |
| 968 | + irq_status, cec_irq); | |
| 712 | 969 | |
| 713 | 970 | if (irq_status & (MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT)) |
| 714 | 971 | adv7511_check_monitor_present_status(sd); |
| 715 | 972 | if (irq_status & MASK_ADV7511_EDID_RDY_INT) |
| 716 | 973 | adv7511_check_edid_status(sd); |
| 717 | 974 | |
| 975 | +#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) | |
| 976 | + if (cec_irq & 0x38) | |
| 977 | + adv_cec_tx_raw_status(sd, cec_irq); | |
| 978 | + | |
| 979 | + if (cec_irq & 1) { | |
| 980 | + struct adv7511_state *state = get_adv7511_state(sd); | |
| 981 | + struct cec_msg msg; | |
| 982 | + | |
| 983 | + msg.len = adv7511_cec_read(sd, 0x25) & 0x1f; | |
| 984 | + | |
| 985 | + v4l2_dbg(1, debug, sd, "%s: cec msg len %d\n", __func__, | |
| 986 | + msg.len); | |
| 987 | + | |
| 988 | + if (msg.len > 16) | |
| 989 | + msg.len = 16; | |
| 990 | + | |
| 991 | + if (msg.len) { | |
| 992 | + u8 i; | |
| 993 | + | |
| 994 | + for (i = 0; i < msg.len; i++) | |
| 995 | + msg.msg[i] = adv7511_cec_read(sd, i + 0x15); | |
| 996 | + | |
| 997 | + adv7511_cec_write(sd, 0x4a, 1); /* toggle to re-enable rx 1 */ | |
| 998 | + adv7511_cec_write(sd, 0x4a, 0); | |
| 999 | + cec_received_msg(state->cec_adap, &msg); | |
| 1000 | + } | |
| 1001 | + } | |
| 1002 | +#endif | |
| 1003 | + | |
| 718 | 1004 | /* enable interrupts */ |
| 719 | 1005 | adv7511_set_isr(sd, true); |
| 720 | 1006 | |
| @@ -771,12 +1057,14 @@ static int adv7511_s_dv_timings(struct v4l2_subdev *sd, · 50 unmodified lines | ||
| 771 | 1057 | /* save timings */ |
| 772 | 1058 | state->dv_timings = *timings; |
| 773 | 1059 | |
| 1060 | + /* set h/vsync polarities */ | |
| 1061 | + adv7511_wr_and_or(sd, 0x17, 0x9f, | |
| 1062 | + ((timings->bt.polarities & V4L2_DV_VSYNC_POS_POL) ? 0 : 0x40) | | |
| 1063 | + ((timings->bt.polarities & V4L2_DV_HSYNC_POS_POL) ? 0 : 0x20)); | |
| 1064 | + | |
| 774 | 1065 | /* update quantization range based on new dv_timings */ |
| 775 | 1066 | adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl); |
| 776 | 1067 | |
| 777 | − /* update AVI infoframe */ | |
| 778 | − adv7511_set_IT_content_AVI_InfoFrame(sd); | |
| 779 | − | |
| 780 | 1068 | return 0; |
| 781 | 1069 | } |
| 782 | 1070 | |
| @@ -956,8 +1244,6 @@ static int adv7511_enum_mbus_code(struct v4l2_subdev *sd, · 173 unmodified lines | ||
| 956 | 1244 | static void adv7511_fill_format(struct adv7511_state *state, |
| 957 | 1245 | struct v4l2_mbus_framefmt *format) |
| 958 | 1246 | { |
| 959 | − memset(format, 0, sizeof(*format)); | |
| 960 | − | |
| 961 | 1247 | format->width = state->dv_timings.bt.width; |
| 962 | 1248 | format->height = state->dv_timings.bt.height; |
| 963 | 1249 | format->field = V4L2_FIELD_NONE; |
| @@ -972,6 +1258,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd, · 8 unmodified lines | ||
| 972 | 1258 | if (format->pad != 0) |
| 973 | 1259 | return -EINVAL; |
| 974 | 1260 | |
| 1261 | + memset(&format->format, 0, sizeof(format->format)); | |
| 975 | 1262 | adv7511_fill_format(state, &format->format); |
| 976 | 1263 | |
| 977 | 1264 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) { |
| @@ -1132,6 +1419,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd, · 154 unmodified lines | ||
| 1132 | 1419 | adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2) | (itc << 7)); |
| 1133 | 1420 | adv7511_wr_and_or(sd, 0x59, 0x0f, (yq << 6) | (cn << 4)); |
| 1134 | 1421 | adv7511_wr_and_or(sd, 0x4a, 0xff, 1); |
| 1422 | + adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl); | |
| 1135 | 1423 | |
| 1136 | 1424 | return 0; |
| 1137 | 1425 | } |
| @@ -1183,6 +1471,8 @@ static void adv7511_notify_no_edid(struct v4l2_subdev *sd) · 45 unmodified lines | ||
| 1183 | 1471 | /* We failed to read the EDID, so send an event for this. */ |
| 1184 | 1472 | ed.present = false; |
| 1185 | 1473 | ed.segment = adv7511_rd(sd, 0xc4); |
| 1474 | + ed.phys_addr = CEC_PHYS_ADDR_INVALID; | |
| 1475 | + cec_s_phys_addr(state->cec_adap, ed.phys_addr, false); | |
| 1186 | 1476 | v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed); |
| 1187 | 1477 | v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x0); |
| 1188 | 1478 | } |
| @@ -1406,13 +1696,16 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd) · 217 unmodified lines | ||
| 1406 | 1696 | |
| 1407 | 1697 | v4l2_dbg(1, debug, sd, "%s: edid complete with %d segment(s)\n", __func__, state->edid.segments); |
| 1408 | 1698 | state->edid.complete = true; |
| 1409 | − | |
| 1699 | + ed.phys_addr = cec_get_edid_phys_addr(state->edid.data, | |
| 1700 | + state->edid.segments * 256, | |
| 1701 | + NULL); | |
| 1410 | 1702 | /* report when we have all segments |
| 1411 | 1703 | but report only for segment 0 |
| 1412 | 1704 | */ |
| 1413 | 1705 | ed.present = true; |
| 1414 | 1706 | ed.segment = 0; |
| 1415 | 1707 | state->edid_detect_counter++; |
| 1708 | + cec_s_phys_addr(state->cec_adap, ed.phys_addr, false); | |
| 1416 | 1709 | v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed); |
| 1417 | 1710 | return ed.present; |
| 1418 | 1711 | } |
| @@ -1420,17 +1713,43 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd) · 1 unmodified line | ||
| 1420 | 1713 | return false; |
| 1421 | 1714 | } |
| 1422 | 1715 | |
| 1716 | +static int adv7511_registered(struct v4l2_subdev *sd) | |
| 1717 | +{ | |
| 1718 | + struct adv7511_state *state = get_adv7511_state(sd); | |
| 1719 | + int err; | |
| 1720 | + | |
| 1721 | + err = cec_register_adapter(state->cec_adap); | |
| 1722 | + if (err) | |
| 1723 | + cec_delete_adapter(state->cec_adap); | |
| 1724 | + return err; | |
| 1725 | +} | |
| 1726 | + | |
| 1727 | +static void adv7511_unregistered(struct v4l2_subdev *sd) | |
| 1728 | +{ | |
| 1729 | + struct adv7511_state *state = get_adv7511_state(sd); | |
| 1730 | + | |
| 1731 | + cec_unregister_adapter(state->cec_adap); | |
| 1732 | +} | |
| 1733 | + | |
| 1734 | +static const struct v4l2_subdev_internal_ops adv7511_int_ops = { | |
| 1735 | + .registered = adv7511_registered, | |
| 1736 | + .unregistered = adv7511_unregistered, | |
| 1737 | +}; | |
| 1738 | + | |
| 1423 | 1739 | /* ----------------------------------------------------------------------- */ |
| 1424 | 1740 | /* Setup ADV7511 */ |
| 1425 | 1741 | static void adv7511_init_setup(struct v4l2_subdev *sd) |
| 1426 | 1742 | { |
| 1427 | 1743 | struct adv7511_state *state = get_adv7511_state(sd); |
| 1428 | 1744 | struct adv7511_state_edid *edid = &state->edid; |
| 1745 | + u32 cec_clk = state->pdata.cec_clk; | |
| 1746 | + u8 ratio; | |
| 1429 | 1747 | |
| 1430 | 1748 | v4l2_dbg(1, debug, sd, "%s\n", __func__); |
| 1431 | 1749 | |
| 1432 | 1750 | /* clear all interrupts */ |
| 1433 | 1751 | adv7511_wr(sd, 0x96, 0xff); |
| 1752 | + adv7511_wr(sd, 0x97, 0xff); | |
| 1434 | 1753 | /* |
| 1435 | 1754 | * Stop HPD from resetting a lot of registers. |
| 1436 | 1755 | * It might leave the chip in a partly un-initialized state, |
| @@ -1442,6 +1761,25 @@ static void adv7511_init_setup(struct v4l2_subdev *sd) · 5 unmodified lines | ||
| 1442 | 1761 | adv7511_set_isr(sd, false); |
| 1443 | 1762 | adv7511_s_stream(sd, false); |
| 1444 | 1763 | adv7511_s_audio_stream(sd, false); |
| 1764 | + | |
| 1765 | + if (state->i2c_cec == NULL) | |
| 1766 | + return; | |
| 1767 | + | |
| 1768 | + v4l2_dbg(1, debug, sd, "%s: cec_clk %d\n", __func__, cec_clk); | |
| 1769 | + | |
| 1770 | + /* cec soft reset */ | |
| 1771 | + adv7511_cec_write(sd, 0x50, 0x01); | |
| 1772 | + adv7511_cec_write(sd, 0x50, 0x00); | |
| 1773 | + | |
| 1774 | + /* legacy mode */ | |
| 1775 | + adv7511_cec_write(sd, 0x4a, 0x00); | |
| 1776 | + | |
| 1777 | + if (cec_clk % 750000 != 0) | |
| 1778 | + v4l2_err(sd, "%s: cec_clk %d, not multiple of 750 Khz\n", | |
| 1779 | + __func__, cec_clk); | |
| 1780 | + | |
| 1781 | + ratio = (cec_clk / 750000) - 1; | |
| 1782 | + adv7511_cec_write(sd, 0x4e, ratio << 2); | |
| 1445 | 1783 | } |
| 1446 | 1784 | |
| 1447 | 1785 | static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *id) |
| @@ -1476,6 +1814,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * · 28 unmodified lines | ||
| 1476 | 1814 | client->addr << 1); |
| 1477 | 1815 | |
| 1478 | 1816 | v4l2_i2c_subdev_init(sd, client, &adv7511_ops); |
| 1817 | + sd->internal_ops = &adv7511_int_ops; | |
| 1479 | 1818 | |
| 1480 | 1819 | hdl = &state->hdl; |
| 1481 | 1820 | v4l2_ctrl_handler_init(hdl, 10); |
| @@ -1516,26 +1855,47 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * · 34 unmodified lines | ||
| 1516 | 1855 | chip_id[0] = adv7511_rd(sd, 0xf5); |
| 1517 | 1856 | chip_id[1] = adv7511_rd(sd, 0xf6); |
| 1518 | 1857 | if (chip_id[0] != 0x75 || chip_id[1] != 0x11) { |
| 1519 | − v4l2_err(sd, "chip_id != 0x7511, read 0x%02x%02x\n", chip_id[0], chip_id[1]); | |
| 1858 | + v4l2_err(sd, "chip_id != 0x7511, read 0x%02x%02x\n", chip_id[0], | |
| 1859 | + chip_id[1]); | |
| 1520 | 1860 | err = -EIO; |
| 1521 | 1861 | goto err_entity; |
| 1522 | 1862 | } |
| 1523 | 1863 | |
| 1524 | − state->i2c_edid = i2c_new_dummy(client->adapter, state->i2c_edid_addr >> 1); | |
| 1864 | + state->i2c_edid = i2c_new_dummy(client->adapter, | |
| 1865 | + state->i2c_edid_addr >> 1); | |
| 1525 | 1866 | if (state->i2c_edid == NULL) { |
| 1526 | 1867 | v4l2_err(sd, "failed to register edid i2c client\n"); |
| 1527 | 1868 | err = -ENOMEM; |
| 1528 | 1869 | goto err_entity; |
| 1529 | 1870 | } |
| 1530 | 1871 | |
| 1872 | + adv7511_wr(sd, 0xe1, state->i2c_cec_addr); | |
| 1873 | + if (state->pdata.cec_clk < 3000000 || | |
| 1874 | + state->pdata.cec_clk > 100000000) { | |
| 1875 | + v4l2_err(sd, "%s: cec_clk %u outside range, disabling cec\n", | |
| 1876 | + __func__, state->pdata.cec_clk); | |
| 1877 | + state->pdata.cec_clk = 0; | |
| 1878 | + } | |
| 1879 | + | |
| 1880 | + if (state->pdata.cec_clk) { | |
| 1881 | + state->i2c_cec = i2c_new_dummy(client->adapter, | |
| 1882 | + state->i2c_cec_addr >> 1); | |
| 1883 | + if (state->i2c_cec == NULL) { | |
| 1884 | + v4l2_err(sd, "failed to register cec i2c client\n"); | |
| 1885 | + goto err_unreg_edid; | |
| 1886 | + } | |
| 1887 | + adv7511_wr(sd, 0xe2, 0x00); /* power up cec section */ | |
| 1888 | + } else { | |
| 1889 | + adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */ | |
| 1890 | + } | |
| 1891 | + | |
| 1531 | 1892 | state->i2c_pktmem = i2c_new_dummy(client->adapter, state->i2c_pktmem_addr >> 1); |
| 1532 | 1893 | if (state->i2c_pktmem == NULL) { |
| 1533 | 1894 | v4l2_err(sd, "failed to register pktmem i2c client\n"); |
| 1534 | 1895 | err = -ENOMEM; |
| 1535 | − goto err_unreg_edid; | |
| 1896 | + goto err_unreg_cec; | |
| 1536 | 1897 | } |
| 1537 | 1898 | |
| 1538 | − adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */ | |
| 1539 | 1899 | state->work_queue = create_singlethread_workqueue(sd->name); |
| 1540 | 1900 | if (state->work_queue == NULL) { |
| 1541 | 1901 | v4l2_err(sd, "could not create workqueue\n"); |
| @@ -1546,6 +1906,19 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * · 4 unmodified lines | ||
| 1546 | 1906 | INIT_DELAYED_WORK(&state->edid_handler, adv7511_edid_handler); |
| 1547 | 1907 | |
| 1548 | 1908 | adv7511_init_setup(sd); |
| 1909 | + | |
| 1910 | +#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) | |
| 1911 | + state->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops, | |
| 1912 | + state, dev_name(&client->dev), CEC_CAP_TRANSMIT | | |
| 1913 | + CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | CEC_CAP_RC, | |
| 1914 | + ADV7511_MAX_ADDRS, &client->dev); | |
| 1915 | + err = PTR_ERR_OR_ZERO(state->cec_adap); | |
| 1916 | + if (err) { | |
| 1917 | + destroy_workqueue(state->work_queue); | |
| 1918 | + goto err_unreg_pktmem; | |
| 1919 | + } | |
| 1920 | +#endif | |
| 1921 | + | |
| 1549 | 1922 | adv7511_set_isr(sd, true); |
| 1550 | 1923 | adv7511_check_monitor_present_status(sd); |
| 1551 | 1924 | |
| @@ -1555,6 +1928,9 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * · 3 unmodified lines | ||
| 1555 | 1928 | |
| 1556 | 1929 | err_unreg_pktmem: |
| 1557 | 1930 | i2c_unregister_device(state->i2c_pktmem); |
| 1931 | +err_unreg_cec: | |
| 1932 | + if (state->i2c_cec) | |
| 1933 | + i2c_unregister_device(state->i2c_cec); | |
| 1558 | 1934 | err_unreg_edid: |
| 1559 | 1935 | i2c_unregister_device(state->i2c_edid); |
| 1560 | 1936 | err_entity: |
| @@ -1576,9 +1952,12 @@ static int adv7511_remove(struct i2c_client *client) · 15 unmodified lines | ||
| 1576 | 1952 | v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name, |
| 1577 | 1953 | client->addr << 1, client->adapter->name); |
| 1578 | 1954 | |
| 1955 | + adv7511_set_isr(sd, false); | |
| 1579 | 1956 | adv7511_init_setup(sd); |
| 1580 | 1957 | cancel_delayed_work(&state->edid_handler); |
| 1581 | 1958 | i2c_unregister_device(state->i2c_edid); |
| 1959 | + if (state->i2c_cec) | |
| 1960 | + i2c_unregister_device(state->i2c_cec); | |
| 1582 | 1961 | i2c_unregister_device(state->i2c_pktmem); |
| 1583 | 1962 | destroy_workqueue(state->work_queue); |
| 1584 | 1963 | v4l2_device_unregister_subdev(sd); |
| @@ -40,6 +40,7 @@ · 39 unmodified lines | ||
| 40 | 40 | #include <linux/regmap.h> |
| 41 | 41 | |
| 42 | 42 | #include <media/i2c/adv7604.h> |
| 43 | +#include <media/cec.h> | |
| 43 | 44 | #include <media/v4l2-ctrls.h> |
| 44 | 45 | #include <media/v4l2-device.h> |
| 45 | 46 | #include <media/v4l2-event.h> |
| @@ -80,6 +81,8 @@ MODULE_LICENSE("GPL"); · 34 unmodified lines | ||
| 80 | 81 | |
| 81 | 82 | #define ADV76XX_OP_SWAP_CB_CR (1 << 0) |
| 82 | 83 | |
| 84 | +#define ADV76XX_MAX_ADDRS (3) | |
| 85 | + | |
| 83 | 86 | enum adv76xx_type { |
| 84 | 87 | ADV7604, |
| 85 | 88 | ADV7611, |
| @@ -164,6 +167,7 @@ struct adv76xx_state { · 78 unmodified lines | ||
| 164 | 167 | struct adv76xx_platform_data pdata; |
| 165 | 168 | |
| 166 | 169 | struct gpio_desc *hpd_gpio[4]; |
| 170 | + struct gpio_desc *reset_gpio; | |
| 167 | 171 | |
| 168 | 172 | struct v4l2_subdev sd; |
| 169 | 173 | struct media_pad pads[ADV76XX_PAD_MAX]; |
| @@ -184,10 +188,15 @@ struct adv76xx_state { · 14 unmodified lines | ||
| 184 | 188 | u16 spa_port_a[2]; |
| 185 | 189 | struct v4l2_fract aspect_ratio; |
| 186 | 190 | u32 rgb_quantization_range; |
| 187 | − struct workqueue_struct *work_queues; | |
| 188 | 191 | struct delayed_work delayed_work_enable_hotplug; |
| 189 | 192 | bool restart_stdi_once; |
| 190 | 193 | |
| 194 | + /* CEC */ | |
| 195 | + struct cec_adapter *cec_adap; | |
| 196 | + u8 cec_addr[ADV76XX_MAX_ADDRS]; | |
| 197 | + u8 cec_valid_addrs; | |
| 198 | + bool cec_enabled_adap; | |
| 199 | + | |
| 191 | 200 | /* i2c clients */ |
| 192 | 201 | struct i2c_client *i2c_clients[ADV76XX_PAGE_MAX]; |
| 193 | 202 | |
| @@ -381,7 +390,8 @@ static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val) · 187 unmodified lines | ||
| 381 | 390 | return regmap_write(state->regmap[ADV76XX_PAGE_IO], reg, val); |
| 382 | 391 | } |
| 383 | 392 | |
| 384 | −static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) | |
| 393 | +static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, | |
| 394 | + u8 val) | |
| 385 | 395 | { |
| 386 | 396 | return io_write(sd, reg, (io_read(sd, reg) & ~mask) | val); |
| 387 | 397 | } |
| @@ -414,6 +424,12 @@ static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) · 26 unmodified lines | ||
| 414 | 424 | return regmap_write(state->regmap[ADV76XX_PAGE_CEC], reg, val); |
| 415 | 425 | } |
| 416 | 426 | |
| 427 | +static inline int cec_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, | |
| 428 | + u8 val) | |
| 429 | +{ | |
| 430 | + return cec_write(sd, reg, (cec_read(sd, reg) & ~mask) | val); | |
| 431 | +} | |
| 432 | + | |
| 417 | 433 | static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) |
| 418 | 434 | { |
| 419 | 435 | struct adv76xx_state *state = to_state(sd); |
| @@ -892,9 +908,9 @@ static int adv76xx_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) · 472 unmodified lines | ||
| 892 | 908 | { |
| 893 | 909 | struct adv76xx_state *state = to_state(sd); |
| 894 | 910 | const struct adv76xx_chip_info *info = state->info; |
| 911 | + u16 cable_det = info->read_cable_det(sd); | |
| 895 | 912 | |
| 896 | − return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, | |
| 897 | − info->read_cable_det(sd)); | |
| 913 | + return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, cable_det); | |
| 898 | 914 | } |
| 899 | 915 | |
| 900 | 916 | static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, |
| @@ -1086,6 +1102,10 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) · 185 unmodified lines | ||
| 1086 | 1102 | struct adv76xx_state *state = to_state(sd); |
| 1087 | 1103 | bool rgb_output = io_read(sd, 0x02) & 0x02; |
| 1088 | 1104 | bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; |
| 1105 | + u8 y = HDMI_COLORSPACE_RGB; | |
| 1106 | + | |
| 1107 | + if (hdmi_signal && (io_read(sd, 0x60) & 1)) | |
| 1108 | + y = infoframe_read(sd, 0x01) >> 5; | |
| 1089 | 1109 | |
| 1090 | 1110 | v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n", |
| 1091 | 1111 | __func__, state->rgb_quantization_range, |
| @@ -1093,6 +1113,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) · 1 unmodified line | ||
| 1093 | 1113 | |
| 1094 | 1114 | adv76xx_set_gain(sd, true, 0x0, 0x0, 0x0); |
| 1095 | 1115 | adv76xx_set_offset(sd, true, 0x0, 0x0, 0x0); |
| 1116 | + io_write_clr_set(sd, 0x02, 0x04, rgb_output ? 0 : 4); | |
| 1096 | 1117 | |
| 1097 | 1118 | switch (state->rgb_quantization_range) { |
| 1098 | 1119 | case V4L2_DV_RGB_RANGE_AUTO: |
| @@ -1142,6 +1163,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) · 43 unmodified lines | ||
| 1142 | 1163 | break; |
| 1143 | 1164 | } |
| 1144 | 1165 | |
| 1166 | + if (y != HDMI_COLORSPACE_RGB) | |
| 1167 | + break; | |
| 1168 | + | |
| 1145 | 1169 | /* RGB limited range (16-235) */ |
| 1146 | 1170 | io_write_clr_set(sd, 0x02, 0xf0, 0x00); |
| 1147 | 1171 | |
| @@ -1153,6 +1177,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) · 5 unmodified lines | ||
| 1153 | 1177 | break; |
| 1154 | 1178 | } |
| 1155 | 1179 | |
| 1180 | + if (y != HDMI_COLORSPACE_RGB) | |
| 1181 | + break; | |
| 1182 | + | |
| 1156 | 1183 | /* RGB full range (0-255) */ |
| 1157 | 1184 | io_write_clr_set(sd, 0x02, 0xf0, 0x10); |
| 1158 | 1185 | |
| @@ -1849,6 +1876,7 @@ static void adv76xx_setup_format(struct adv76xx_state *state) · 690 unmodified lines | ||
| 1849 | 1876 | io_write_clr_set(sd, 0x04, 0xe0, adv76xx_op_ch_sel(state)); |
| 1850 | 1877 | io_write_clr_set(sd, 0x05, 0x01, |
| 1851 | 1878 | state->format->swap_cb_cr ? ADV76XX_OP_SWAP_CB_CR : 0); |
| 1879 | + set_rgb_quantization_range(sd); | |
| 1852 | 1880 | } |
| 1853 | 1881 | |
| 1854 | 1882 | static int adv76xx_get_format(struct v4l2_subdev *sd, |
| @@ -1924,6 +1952,210 @@ static int adv76xx_set_format(struct v4l2_subdev *sd, · 69 unmodified lines | ||
| 1924 | 1952 | return 0; |
| 1925 | 1953 | } |
| 1926 | 1954 | |
| 1955 | +#if IS_ENABLED(CONFIG_VIDEO_ADV7604_CEC) | |
| 1956 | +static void adv76xx_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status) | |
| 1957 | +{ | |
| 1958 | + struct adv76xx_state *state = to_state(sd); | |
| 1959 | + | |
| 1960 | + if ((cec_read(sd, 0x11) & 0x01) == 0) { | |
| 1961 | + v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__); | |
| 1962 | + return; | |
| 1963 | + } | |
| 1964 | + | |
| 1965 | + if (tx_raw_status & 0x02) { | |
| 1966 | + v4l2_dbg(1, debug, sd, "%s: tx raw: arbitration lost\n", | |
| 1967 | + __func__); | |
| 1968 | + cec_transmit_done(state->cec_adap, CEC_TX_STATUS_ARB_LOST, | |
| 1969 | + 1, 0, 0, 0); | |
| 1970 | + } | |
| 1971 | + if (tx_raw_status & 0x04) { | |
| 1972 | + u8 status; | |
| 1973 | + u8 nack_cnt; | |
| 1974 | + u8 low_drive_cnt; | |
| 1975 | + | |
| 1976 | + v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__); | |
| 1977 | + /* | |
| 1978 | + * We set this status bit since this hardware performs | |
| 1979 | + * retransmissions. | |
| 1980 | + */ | |
| 1981 | + status = CEC_TX_STATUS_MAX_RETRIES; | |
| 1982 | + nack_cnt = cec_read(sd, 0x14) & 0xf; | |
| 1983 | + if (nack_cnt) | |
| 1984 | + status |= CEC_TX_STATUS_NACK; | |
| 1985 | + low_drive_cnt = cec_read(sd, 0x14) >> 4; | |
| 1986 | + if (low_drive_cnt) | |
| 1987 | + status |= CEC_TX_STATUS_LOW_DRIVE; | |
| 1988 | + cec_transmit_done(state->cec_adap, status, | |
| 1989 | + 0, nack_cnt, low_drive_cnt, 0); | |
| 1990 | + return; | |
| 1991 | + } | |
| 1992 | + if (tx_raw_status & 0x01) { | |
| 1993 | + v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__); | |
| 1994 | + cec_transmit_done(state->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); | |
| 1995 | + return; | |
| 1996 | + } | |
| 1997 | +} | |
| 1998 | + | |
| 1999 | +static void adv76xx_cec_isr(struct v4l2_subdev *sd, bool *handled) | |
| 2000 | +{ | |
| 2001 | + struct adv76xx_state *state = to_state(sd); | |
| 2002 | + u8 cec_irq; | |
| 2003 | + | |
| 2004 | + /* cec controller */ | |
| 2005 | + cec_irq = io_read(sd, 0x4d) & 0x0f; | |
| 2006 | + if (!cec_irq) | |
| 2007 | + return; | |
| 2008 | + | |
| 2009 | + v4l2_dbg(1, debug, sd, "%s: cec: irq 0x%x\n", __func__, cec_irq); | |
| 2010 | + adv76xx_cec_tx_raw_status(sd, cec_irq); | |
| 2011 | + if (cec_irq & 0x08) { | |
| 2012 | + struct cec_msg msg; | |
| 2013 | + | |
| 2014 | + msg.len = cec_read(sd, 0x25) & 0x1f; | |
| 2015 | + if (msg.len > 16) | |
| 2016 | + msg.len = 16; | |
| 2017 | + | |
| 2018 | + if (msg.len) { | |
| 2019 | + u8 i; | |
| 2020 | + | |
| 2021 | + for (i = 0; i < msg.len; i++) | |
| 2022 | + msg.msg[i] = cec_read(sd, i + 0x15); | |
| 2023 | + cec_write(sd, 0x26, 0x01); /* re-enable rx */ | |
| 2024 | + cec_received_msg(state->cec_adap, &msg); | |
| 2025 | + } | |
| 2026 | + } | |
| 2027 | + | |
| 2028 | + /* note: the bit order is swapped between 0x4d and 0x4e */ | |
| 2029 | + cec_irq = ((cec_irq & 0x08) >> 3) | ((cec_irq & 0x04) >> 1) | | |
| 2030 | + ((cec_irq & 0x02) << 1) | ((cec_irq & 0x01) << 3); | |
| 2031 | + io_write(sd, 0x4e, cec_irq); | |
| 2032 | + | |
| 2033 | + if (handled) | |
| 2034 | + *handled = true; | |
| 2035 | +} | |
| 2036 | + | |
| 2037 | +static int adv76xx_cec_adap_enable(struct cec_adapter *adap, bool enable) | |
| 2038 | +{ | |
| 2039 | + struct adv76xx_state *state = adap->priv; | |
| 2040 | + struct v4l2_subdev *sd = &state->sd; | |
| 2041 | + | |
| 2042 | + if (!state->cec_enabled_adap && enable) { | |
| 2043 | + cec_write_clr_set(sd, 0x2a, 0x01, 0x01); /* power up cec */ | |
| 2044 | + cec_write(sd, 0x2c, 0x01); /* cec soft reset */ | |
| 2045 | + cec_write_clr_set(sd, 0x11, 0x01, 0); /* initially disable tx */ | |
| 2046 | + /* enabled irqs: */ | |
| 2047 | + /* tx: ready */ | |
| 2048 | + /* tx: arbitration lost */ | |
| 2049 | + /* tx: retry timeout */ | |
| 2050 | + /* rx: ready */ | |
| 2051 | + io_write_clr_set(sd, 0x50, 0x0f, 0x0f); | |
| 2052 | + cec_write(sd, 0x26, 0x01); /* enable rx */ | |
| 2053 | + } else if (state->cec_enabled_adap && !enable) { | |
| 2054 | + /* disable cec interrupts */ | |
| 2055 | + io_write_clr_set(sd, 0x50, 0x0f, 0x00); | |
| 2056 | + /* disable address mask 1-3 */ | |
| 2057 | + cec_write_clr_set(sd, 0x27, 0x70, 0x00); | |
| 2058 | + /* power down cec section */ | |
| 2059 | + cec_write_clr_set(sd, 0x2a, 0x01, 0x00); | |
| 2060 | + state->cec_valid_addrs = 0; | |
| 2061 | + } | |
| 2062 | + state->cec_enabled_adap = enable; | |
| 2063 | + adv76xx_s_detect_tx_5v_ctrl(sd); | |
| 2064 | + return 0; | |
| 2065 | +} | |
| 2066 | + | |
| 2067 | +static int adv76xx_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) | |
| 2068 | +{ | |
| 2069 | + struct adv76xx_state *state = adap->priv; | |
| 2070 | + struct v4l2_subdev *sd = &state->sd; | |
| 2071 | + unsigned int i, free_idx = ADV76XX_MAX_ADDRS; | |
| 2072 | + | |
| 2073 | + if (!state->cec_enabled_adap) | |
| 2074 | + return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO; | |
| 2075 | + | |
| 2076 | + if (addr == CEC_LOG_ADDR_INVALID) { | |
| 2077 | + cec_write_clr_set(sd, 0x27, 0x70, 0); | |
| 2078 | + state->cec_valid_addrs = 0; | |
| 2079 | + return 0; | |
| 2080 | + } | |
| 2081 | + | |
| 2082 | + for (i = 0; i < ADV76XX_MAX_ADDRS; i++) { | |
| 2083 | + bool is_valid = state->cec_valid_addrs & (1 << i); | |
| 2084 | + | |
| 2085 | + if (free_idx == ADV76XX_MAX_ADDRS && !is_valid) | |
| 2086 | + free_idx = i; | |
| 2087 | + if (is_valid && state->cec_addr[i] == addr) | |
| 2088 | + return 0; | |
| 2089 | + } | |
| 2090 | + if (i == ADV76XX_MAX_ADDRS) { | |
| 2091 | + i = free_idx; | |
| 2092 | + if (i == ADV76XX_MAX_ADDRS) | |
| 2093 | + return -ENXIO; | |
| 2094 | + } | |
| 2095 | + state->cec_addr[i] = addr; | |
| 2096 | + state->cec_valid_addrs |= 1 << i; | |
| 2097 | + | |
| 2098 | + switch (i) { | |
| 2099 | + case 0: | |
| 2100 | + /* enable address mask 0 */ | |
| 2101 | + cec_write_clr_set(sd, 0x27, 0x10, 0x10); | |
| 2102 | + /* set address for mask 0 */ | |
| 2103 | + cec_write_clr_set(sd, 0x28, 0x0f, addr); | |
| 2104 | + break; | |
| 2105 | + case 1: | |
| 2106 | + /* enable address mask 1 */ | |
| 2107 | + cec_write_clr_set(sd, 0x27, 0x20, 0x20); | |
| 2108 | + /* set address for mask 1 */ | |
| 2109 | + cec_write_clr_set(sd, 0x28, 0xf0, addr << 4); | |
| 2110 | + break; | |
| 2111 | + case 2: | |
| 2112 | + /* enable address mask 2 */ | |
| 2113 | + cec_write_clr_set(sd, 0x27, 0x40, 0x40); | |
| 2114 | + /* set address for mask 1 */ | |
| 2115 | + cec_write_clr_set(sd, 0x29, 0x0f, addr); | |
| 2116 | + break; | |
| 2117 | + } | |
| 2118 | + return 0; | |
| 2119 | +} | |
| 2120 | + | |
| 2121 | +static int adv76xx_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | |
| 2122 | + u32 signal_free_time, struct cec_msg *msg) | |
| 2123 | +{ | |
| 2124 | + struct adv76xx_state *state = adap->priv; | |
| 2125 | + struct v4l2_subdev *sd = &state->sd; | |
| 2126 | + u8 len = msg->len; | |
| 2127 | + unsigned int i; | |
| 2128 | + | |
| 2129 | + /* | |
| 2130 | + * The number of retries is the number of attempts - 1, but retry | |
| 2131 | + * at least once. It's not clear if a value of 0 is allowed, so | |
| 2132 | + * let's do at least one retry. | |
| 2133 | + */ | |
| 2134 | + cec_write_clr_set(sd, 0x12, 0x70, max(1, attempts - 1) << 4); | |
| 2135 | + | |
| 2136 | + if (len > 16) { | |
| 2137 | + v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len); | |
| 2138 | + return -EINVAL; | |
| 2139 | + } | |
| 2140 | + | |
| 2141 | + /* write data */ | |
| 2142 | + for (i = 0; i < len; i++) | |
| 2143 | + cec_write(sd, i, msg->msg[i]); | |
| 2144 | + | |
| 2145 | + /* set length (data + header) */ | |
| 2146 | + cec_write(sd, 0x10, len); | |
| 2147 | + /* start transmit, enable tx */ | |
| 2148 | + cec_write(sd, 0x11, 0x01); | |
| 2149 | + return 0; | |
| 2150 | +} | |
| 2151 | + | |
| 2152 | +static const struct cec_adap_ops adv76xx_cec_adap_ops = { | |
| 2153 | + .adap_enable = adv76xx_cec_adap_enable, | |
| 2154 | + .adap_log_addr = adv76xx_cec_adap_log_addr, | |
| 2155 | + .adap_transmit = adv76xx_cec_adap_transmit, | |
| 2156 | +}; | |
| 2157 | +#endif | |
| 2158 | + | |
| 1927 | 2159 | static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) |
| 1928 | 2160 | { |
| 1929 | 2161 | struct adv76xx_state *state = to_state(sd); |
| @@ -1969,6 +2201,11 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) · 39 unmodified lines | ||
| 1969 | 2201 | *handled = true; |
| 1970 | 2202 | } |
| 1971 | 2203 | |
| 2204 | +#if IS_ENABLED(CONFIG_VIDEO_ADV7604_CEC) | |
| 2205 | + /* cec */ | |
| 2206 | + adv76xx_cec_isr(sd, handled); | |
| 2207 | +#endif | |
| 2208 | + | |
| 1972 | 2209 | /* tx 5v detect */ |
| 1973 | 2210 | tx_5v = irq_reg_0x70 & info->cable_det_mask; |
| 1974 | 2211 | if (tx_5v) { |
| @@ -2018,39 +2255,12 @@ static int adv76xx_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) · 43 unmodified lines | ||
| 2018 | 2255 | return 0; |
| 2019 | 2256 | } |
| 2020 | 2257 | |
| 2021 | −static int get_edid_spa_location(const u8 *edid) | |
| 2022 | −{ | |
| 2023 | − u8 d; | |
| 2024 | − | |
| 2025 | − if ((edid[0x7e] != 1) || | |
| 2026 | − (edid[0x80] != 0x02) || | |
| 2027 | − (edid[0x81] != 0x03)) { | |
| 2028 | − return -1; | |
| 2029 | − } | |
| 2030 | − | |
| 2031 | − /* search Vendor Specific Data Block (tag 3) */ | |
| 2032 | − d = edid[0x82] & 0x7f; | |
| 2033 | − if (d > 4) { | |
| 2034 | − int i = 0x84; | |
| 2035 | − int end = 0x80 + d; | |
| 2036 | − | |
| 2037 | − do { | |
| 2038 | − u8 tag = edid[i] >> 5; | |
| 2039 | − u8 len = edid[i] & 0x1f; | |
| 2040 | − | |
| 2041 | − if ((tag == 3) && (len >= 5)) | |
| 2042 | − return i + 4; | |
| 2043 | − i += len + 1; | |
| 2044 | − } while (i < end); | |
| 2045 | − } | |
| 2046 | − return -1; | |
| 2047 | −} | |
| 2048 | − | |
| 2049 | 2258 | static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) |
| 2050 | 2259 | { |
| 2051 | 2260 | struct adv76xx_state *state = to_state(sd); |
| 2052 | 2261 | const struct adv76xx_chip_info *info = state->info; |
| 2053 | − int spa_loc; | |
| 2262 | + unsigned int spa_loc; | |
| 2263 | + u16 pa; | |
| 2054 | 2264 | int err; |
| 2055 | 2265 | int i; |
| 2056 | 2266 | |
| @@ -2081,6 +2291,10 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) · 24 unmodified lines | ||
| 2081 | 2291 | edid->blocks = 2; |
| 2082 | 2292 | return -E2BIG; |
| 2083 | 2293 | } |
| 2294 | + pa = cec_get_edid_phys_addr(edid->edid, edid->blocks * 128, &spa_loc); | |
| 2295 | + err = cec_phys_addr_validate(pa, &pa, NULL); | |
| 2296 | + if (err) | |
| 2297 | + return err; | |
| 2084 | 2298 | |
| 2085 | 2299 | v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n", |
| 2086 | 2300 | __func__, edid->pad, state->edid.present); |
| @@ -2090,9 +2304,12 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) · 3 unmodified lines | ||
| 2090 | 2304 | adv76xx_set_hpd(state, 0); |
| 2091 | 2305 | rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00); |
| 2092 | 2306 | |
| 2093 | − spa_loc = get_edid_spa_location(edid->edid); | |
| 2094 | − if (spa_loc < 0) | |
| 2095 | − spa_loc = 0xc0; /* Default value [REF_02, p. 116] */ | |
| 2307 | + /* | |
| 2308 | + * Return an error if no location of the source physical address | |
| 2309 | + * was found. | |
| 2310 | + */ | |
| 2311 | + if (spa_loc == 0) | |
| 2312 | + return -EINVAL; | |
| 2096 | 2313 | |
| 2097 | 2314 | switch (edid->pad) { |
| 2098 | 2315 | case ADV76XX_PAD_HDMI_PORT_A: |
| @@ -2152,10 +2369,10 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) · 53 unmodified lines | ||
| 2152 | 2369 | v4l2_err(sd, "error enabling edid (0x%x)\n", state->edid.present); |
| 2153 | 2370 | return -EIO; |
| 2154 | 2371 | } |
| 2372 | + cec_s_phys_addr(state->cec_adap, pa, false); | |
| 2155 | 2373 | |
| 2156 | 2374 | /* enable hotplug after 100 ms */ |
| 2157 | − queue_delayed_work(state->work_queues, | |
| 2158 | − &state->delayed_work_enable_hotplug, HZ / 10); | |
| 2375 | + schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10); | |
| 2159 | 2376 | return 0; |
| 2160 | 2377 | } |
| 2161 | 2378 | |
| @@ -2276,8 +2493,19 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) · 114 unmodified lines | ||
| 2276 | 2493 | ((edid_enabled & 0x02) ? "Yes" : "No"), |
| 2277 | 2494 | ((edid_enabled & 0x04) ? "Yes" : "No"), |
| 2278 | 2495 | ((edid_enabled & 0x08) ? "Yes" : "No")); |
| 2279 | − v4l2_info(sd, "CEC: %s\n", !!(cec_read(sd, 0x2a) & 0x01) ? | |
| 2496 | + v4l2_info(sd, "CEC: %s\n", state->cec_enabled_adap ? | |
| 2280 | 2497 | "enabled" : "disabled"); |
| 2498 | + if (state->cec_enabled_adap) { | |
| 2499 | + int i; | |
| 2500 | + | |
| 2501 | + for (i = 0; i < ADV76XX_MAX_ADDRS; i++) { | |
| 2502 | + bool is_valid = state->cec_valid_addrs & (1 << i); | |
| 2503 | + | |
| 2504 | + if (is_valid) | |
| 2505 | + v4l2_info(sd, "CEC Logical Address: 0x%x\n", | |
| 2506 | + state->cec_addr[i]); | |
| 2507 | + } | |
| 2508 | + } | |
| 2281 | 2509 | |
| 2282 | 2510 | v4l2_info(sd, "-----Signal status-----\n"); |
| 2283 | 2511 | cable_det = info->read_cable_det(sd); |
| @@ -2323,11 +2551,10 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) · 39 unmodified lines | ||
| 2323 | 2551 | rgb_quantization_range_txt[state->rgb_quantization_range]); |
| 2324 | 2552 | v4l2_info(sd, "Input color space: %s\n", |
| 2325 | 2553 | input_color_space_txt[reg_io_0x02 >> 4]); |
| 2326 | − v4l2_info(sd, "Output color space: %s %s, saturator %s, alt-gamma %s\n", | |
| 2554 | + v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n", | |
| 2327 | 2555 | (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", |
| 2328 | − (reg_io_0x02 & 0x04) ? "(16-235)" : "(0-255)", | |
| 2329 | 2556 | (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? |
| 2330 | − "enabled" : "disabled", | |
| 2557 | + "(16-235)" : "(0-255)", | |
| 2331 | 2558 | (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); |
| 2332 | 2559 | v4l2_info(sd, "Color space conversion: %s\n", |
| 2333 | 2560 | csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]); |
| @@ -2387,6 +2614,24 @@ static int adv76xx_subscribe_event(struct v4l2_subdev *sd, · 53 unmodified lines | ||
| 2387 | 2614 | } |
| 2388 | 2615 | } |
| 2389 | 2616 | |
| 2617 | +static int adv76xx_registered(struct v4l2_subdev *sd) | |
| 2618 | +{ | |
| 2619 | + struct adv76xx_state *state = to_state(sd); | |
| 2620 | + int err; | |
| 2621 | + | |
| 2622 | + err = cec_register_adapter(state->cec_adap); | |
| 2623 | + if (err) | |
| 2624 | + cec_delete_adapter(state->cec_adap); | |
| 2625 | + return err; | |
| 2626 | +} | |
| 2627 | + | |
| 2628 | +static void adv76xx_unregistered(struct v4l2_subdev *sd) | |
| 2629 | +{ | |
| 2630 | + struct adv76xx_state *state = to_state(sd); | |
| 2631 | + | |
| 2632 | + cec_unregister_adapter(state->cec_adap); | |
| 2633 | +} | |
| 2634 | + | |
| 2390 | 2635 | /* ----------------------------------------------------------------------- */ |
| 2391 | 2636 | |
| 2392 | 2637 | static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = { |
| @@ -2430,6 +2675,11 @@ static const struct v4l2_subdev_ops adv76xx_ops = { · 37 unmodified lines | ||
| 2430 | 2675 | .pad = &adv76xx_pad_ops, |
| 2431 | 2676 | }; |
| 2432 | 2677 | |
| 2678 | +static const struct v4l2_subdev_internal_ops adv76xx_int_ops = { | |
| 2679 | + .registered = adv76xx_registered, | |
| 2680 | + .unregistered = adv76xx_unregistered, | |
| 2681 | +}; | |
| 2682 | + | |
| 2433 | 2683 | /* -------------------------- custom ctrls ---------------------------------- */ |
| 2434 | 2684 | |
| 2435 | 2685 | static const struct v4l2_ctrl_config adv7604_ctrl_analog_sampling_phase = { |
| @@ -2492,10 +2742,7 @@ static int adv76xx_core_init(struct v4l2_subdev *sd) · 56 unmodified lines | ||
| 2492 | 2742 | cp_write(sd, 0xcf, 0x01); /* Power down macrovision */ |
| 2493 | 2743 | |
| 2494 | 2744 | /* video format */ |
| 2495 | − io_write_clr_set(sd, 0x02, 0x0f, | |
| 2496 | − pdata->alt_gamma << 3 | | |
| 2497 | − pdata->op_656_range << 2 | | |
| 2498 | − pdata->alt_data_sat << 0); | |
| 2745 | + io_write_clr_set(sd, 0x02, 0x0f, pdata->alt_gamma << 3); | |
| 2499 | 2746 | io_write_clr_set(sd, 0x05, 0x0e, pdata->blank_data << 3 | |
| 2500 | 2747 | pdata->insert_av_codes << 2 | |
| 2501 | 2748 | pdata->replicate_av_codes << 1); |
| @@ -2845,10 +3092,8 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) · 343 unmodified lines | ||
| 2845 | 3092 | if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) |
| 2846 | 3093 | state->pdata.inv_llc_pol = 1; |
| 2847 | 3094 | |
| 2848 | − if (bus_cfg.bus_type == V4L2_MBUS_BT656) { | |
| 3095 | + if (bus_cfg.bus_type == V4L2_MBUS_BT656) | |
| 2849 | 3096 | state->pdata.insert_av_codes = 1; |
| 2850 | − state->pdata.op_656_range = 1; | |
| 2851 | − } | |
| 2852 | 3097 | |
| 2853 | 3098 | /* Disable the interrupt for now as no DT-based board uses it. */ |
| 2854 | 3099 | state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED; |
| @@ -2871,7 +3116,6 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) · 16 unmodified lines | ||
| 2871 | 3116 | state->pdata.disable_pwrdnb = 0; |
| 2872 | 3117 | state->pdata.disable_cable_det_rst = 0; |
| 2873 | 3118 | state->pdata.blank_data = 1; |
| 2874 | − state->pdata.alt_data_sat = 1; | |
| 2875 | 3119 | state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0; |
| 2876 | 3120 | state->pdata.bus_order = ADV7604_BUS_ORDER_RGB; |
| 2877 | 3121 | |
| @@ -3020,6 +3264,19 @@ static int configure_regmaps(struct adv76xx_state *state) · 142 unmodified lines | ||
| 3020 | 3264 | return 0; |
| 3021 | 3265 | } |
| 3022 | 3266 | |
| 3267 | +static void adv76xx_reset(struct adv76xx_state *state) | |
| 3268 | +{ | |
| 3269 | + if (state->reset_gpio) { | |
| 3270 | + /* ADV76XX can be reset by a low reset pulse of minimum 5 ms. */ | |
| 3271 | + gpiod_set_value_cansleep(state->reset_gpio, 0); | |
| 3272 | + usleep_range(5000, 10000); | |
| 3273 | + gpiod_set_value_cansleep(state->reset_gpio, 1); | |
| 3274 | + /* It is recommended to wait 5 ms after the low pulse before */ | |
| 3275 | + /* an I2C write is performed to the ADV76XX. */ | |
| 3276 | + usleep_range(5000, 10000); | |
| 3277 | + } | |
| 3278 | +} | |
| 3279 | + | |
| 3023 | 3280 | static int adv76xx_probe(struct i2c_client *client, |
| 3024 | 3281 | const struct i2c_device_id *id) |
| 3025 | 3282 | { |
| @@ -3083,6 +3340,12 @@ static int adv76xx_probe(struct i2c_client *client, · 57 unmodified lines | ||
| 3083 | 3340 | if (state->hpd_gpio[i]) |
| 3084 | 3341 | v4l_info(client, "Handling HPD %u GPIO\n", i); |
| 3085 | 3342 | } |
| 3343 | + state->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", | |
| 3344 | + GPIOD_OUT_HIGH); | |
| 3345 | + if (IS_ERR(state->reset_gpio)) | |
| 3346 | + return PTR_ERR(state->reset_gpio); | |
| 3347 | + | |
| 3348 | + adv76xx_reset(state); | |
| 3086 | 3349 | |
| 3087 | 3350 | state->timings = cea640x480; |
| 3088 | 3351 | state->format = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); |
| @@ -3093,6 +3356,7 @@ static int adv76xx_probe(struct i2c_client *client, · 4 unmodified lines | ||
| 3093 | 3356 | id->name, i2c_adapter_id(client->adapter), |
| 3094 | 3357 | client->addr); |
| 3095 | 3358 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; |
| 3359 | + sd->internal_ops = &adv76xx_int_ops; | |
| 3096 | 3360 | |
| 3097 | 3361 | /* Configure IO Regmap region */ |
| 3098 | 3362 | err = configure_regmap(state, ADV76XX_PAGE_IO); |
| @@ -3206,14 +3470,6 @@ static int adv76xx_probe(struct i2c_client *client, · 107 unmodified lines | ||
| 3206 | 3470 | } |
| 3207 | 3471 | } |
| 3208 | 3472 | |
| 3209 | − /* work queues */ | |
| 3210 | − state->work_queues = create_singlethread_workqueue(client->name); | |
| 3211 | − if (!state->work_queues) { | |
| 3212 | − v4l2_err(sd, "Could not create work queue\n"); | |
| 3213 | − err = -ENOMEM; | |
| 3214 | − goto err_i2c; | |
| 3215 | − } | |
| 3216 | − | |
| 3217 | 3473 | INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, |
| 3218 | 3474 | adv76xx_delayed_work_enable_hotplug); |
| 3219 | 3475 | |
| @@ -3236,6 +3492,18 @@ static int adv76xx_probe(struct i2c_client *client, · 16 unmodified lines | ||
| 3236 | 3492 | err = adv76xx_core_init(sd); |
| 3237 | 3493 | if (err) |
| 3238 | 3494 | goto err_entity; |
| 3495 | + | |
| 3496 | +#if IS_ENABLED(CONFIG_VIDEO_ADV7604_CEC) | |
| 3497 | + state->cec_adap = cec_allocate_adapter(&adv76xx_cec_adap_ops, | |
| 3498 | + state, dev_name(&client->dev), | |
| 3499 | + CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | | |
| 3500 | + CEC_CAP_PASSTHROUGH | CEC_CAP_RC, ADV76XX_MAX_ADDRS, | |
| 3501 | + &client->dev); | |
| 3502 | + err = PTR_ERR_OR_ZERO(state->cec_adap); | |
| 3503 | + if (err) | |
| 3504 | + goto err_entity; | |
| 3505 | +#endif | |
| 3506 | + | |
| 3239 | 3507 | v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, |
| 3240 | 3508 | client->addr << 1, client->adapter->name); |
| 3241 | 3509 | |
| @@ -3249,7 +3517,6 @@ err_entity: · 7 unmodified lines | ||
| 3249 | 3517 | media_entity_cleanup(&sd->entity); |
| 3250 | 3518 | err_work_queues: |
| 3251 | 3519 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
| 3252 | − destroy_workqueue(state->work_queues); | |
| 3253 | 3520 | err_i2c: |
| 3254 | 3521 | adv76xx_unregister_clients(state); |
| 3255 | 3522 | err_hdl: |
| @@ -3264,8 +3531,14 @@ static int adv76xx_remove(struct i2c_client *client) · 8 unmodified lines | ||
| 3264 | 3531 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
| 3265 | 3532 | struct adv76xx_state *state = to_state(sd); |
| 3266 | 3533 | |
| 3534 | + /* disable interrupts */ | |
| 3535 | + io_write(sd, 0x40, 0); | |
| 3536 | + io_write(sd, 0x41, 0); | |
| 3537 | + io_write(sd, 0x46, 0); | |
| 3538 | + io_write(sd, 0x6e, 0); | |
| 3539 | + io_write(sd, 0x73, 0); | |
| 3540 | + | |
| 3267 | 3541 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
| 3268 | − destroy_workqueue(state->work_queues); | |
| 3269 | 3542 | v4l2_async_unregister_subdev(sd); |
| 3270 | 3543 | media_entity_cleanup(&sd->entity); |
| 3271 | 3544 | adv76xx_unregister_clients(to_state(sd)); |
| @@ -39,6 +39,7 @@ · 38 unmodified lines | ||
| 39 | 39 | #include <linux/workqueue.h> |
| 40 | 40 | #include <linux/v4l2-dv-timings.h> |
| 41 | 41 | #include <linux/hdmi.h> |
| 42 | +#include <media/cec.h> | |
| 42 | 43 | #include <media/v4l2-device.h> |
| 43 | 44 | #include <media/v4l2-event.h> |
| 44 | 45 | #include <media/v4l2-ctrls.h> |
| @@ -79,6 +80,8 @@ MODULE_LICENSE("GPL"); · 34 unmodified lines | ||
| 79 | 80 | |
| 80 | 81 | #define ADV7842_OP_SWAP_CB_CR (1 << 0) |
| 81 | 82 | |
| 83 | +#define ADV7842_MAX_ADDRS (3) | |
| 84 | + | |
| 82 | 85 | /* |
| 83 | 86 | ********************************************************************** |
| 84 | 87 | * |
| @@ -118,7 +121,6 @@ struct adv7842_state { · 33 unmodified lines | ||
| 118 | 121 | struct v4l2_fract aspect_ratio; |
| 119 | 122 | u32 rgb_quantization_range; |
| 120 | 123 | bool is_cea_format; |
| 121 | − struct workqueue_struct *work_queues; | |
| 122 | 124 | struct delayed_work delayed_work_enable_hotplug; |
| 123 | 125 | bool restart_stdi_once; |
| 124 | 126 | bool hdmi_port_a; |
| @@ -142,6 +144,11 @@ struct adv7842_state { · 17 unmodified lines | ||
| 142 | 144 | struct v4l2_ctrl *free_run_color_ctrl_manual; |
| 143 | 145 | struct v4l2_ctrl *free_run_color_ctrl; |
| 144 | 146 | struct v4l2_ctrl *rgb_quantization_range_ctrl; |
| 147 | + | |
| 148 | + struct cec_adapter *cec_adap; | |
| 149 | + u8 cec_addr[ADV7842_MAX_ADDRS]; | |
| 150 | + u8 cec_valid_addrs; | |
| 151 | + bool cec_enabled_adap; | |
| 145 | 152 | }; |
| 146 | 153 | |
| 147 | 154 | /* Unsupported timings. This device cannot support 720p30. */ |
| @@ -418,9 +425,9 @@ static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) · 270 unmodified lines | ||
| 418 | 425 | return adv_smbus_write_byte_data(state->i2c_cec, reg, val); |
| 419 | 426 | } |
| 420 | 427 | |
| 421 | −static inline int cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) | |
| 428 | +static inline int cec_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) | |
| 422 | 429 | { |
| 423 | − return cec_write(sd, reg, (cec_read(sd, reg) & mask) | val); | |
| 430 | + return cec_write(sd, reg, (cec_read(sd, reg) & ~mask) | val); | |
| 424 | 431 | } |
| 425 | 432 | |
| 426 | 433 | static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) |
| @@ -696,6 +703,18 @@ adv7842_get_dv_timings_cap(struct v4l2_subdev *sd) · 269 unmodified lines | ||
| 696 | 703 | |
| 697 | 704 | /* ----------------------------------------------------------------------- */ |
| 698 | 705 | |
| 706 | +static u16 adv7842_read_cable_det(struct v4l2_subdev *sd) | |
| 707 | +{ | |
| 708 | + u8 reg = io_read(sd, 0x6f); | |
| 709 | + u16 val = 0; | |
| 710 | + | |
| 711 | + if (reg & 0x02) | |
| 712 | + val |= 1; /* port A */ | |
| 713 | + if (reg & 0x01) | |
| 714 | + val |= 2; /* port B */ | |
| 715 | + return val; | |
| 716 | +} | |
| 717 | + | |
| 699 | 718 | static void adv7842_delayed_work_enable_hotplug(struct work_struct *work) |
| 700 | 719 | { |
| 701 | 720 | struct delayed_work *dwork = to_delayed_work(work); |
| @@ -756,56 +775,23 @@ static int edid_write_vga_segment(struct v4l2_subdev *sd) · 54 unmodified lines | ||
| 756 | 775 | } |
| 757 | 776 | |
| 758 | 777 | /* enable hotplug after 200 ms */ |
| 759 | − queue_delayed_work(state->work_queues, | |
| 760 | − &state->delayed_work_enable_hotplug, HZ / 5); | |
| 778 | + schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 5); | |
| 761 | 779 | |
| 762 | 780 | return 0; |
| 763 | 781 | } |
| 764 | 782 | |
| 765 | −static int edid_spa_location(const u8 *edid) | |
| 766 | −{ | |
| 767 | − u8 d; | |
| 768 | − | |
| 769 | − /* | |
| 770 | − * TODO, improve and update for other CEA extensions | |
| 771 | − * currently only for 1 segment (256 bytes), | |
| 772 | − * i.e. 1 extension block and CEA revision 3. | |
| 773 | − */ | |
| 774 | − if ((edid[0x7e] != 1) || | |
| 775 | − (edid[0x80] != 0x02) || | |
| 776 | − (edid[0x81] != 0x03)) { | |
| 777 | − return -EINVAL; | |
| 778 | − } | |
| 779 | − /* | |
| 780 | − * search Vendor Specific Data Block (tag 3) | |
| 781 | − */ | |
| 782 | − d = edid[0x82] & 0x7f; | |
| 783 | − if (d > 4) { | |
| 784 | − int i = 0x84; | |
| 785 | − int end = 0x80 + d; | |
| 786 | − do { | |
| 787 | − u8 tag = edid[i]>>5; | |
| 788 | − u8 len = edid[i] & 0x1f; | |
| 789 | − | |
| 790 | − if ((tag == 3) && (len >= 5)) | |
| 791 | − return i + 4; | |
| 792 | − i += len + 1; | |
| 793 | − } while (i < end); | |
| 794 | − } | |
| 795 | − return -EINVAL; | |
| 796 | −} | |
| 797 | − | |
| 798 | 783 | static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) |
| 799 | 784 | { |
| 800 | 785 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 801 | 786 | struct adv7842_state *state = to_state(sd); |
| 802 | − const u8 *val = state->hdmi_edid.edid; | |
| 803 | − int spa_loc = edid_spa_location(val); | |
| 787 | + const u8 *edid = state->hdmi_edid.edid; | |
| 788 | + int spa_loc; | |
| 789 | + u16 pa; | |
| 804 | 790 | int err = 0; |
| 805 | 791 | int i; |
| 806 | 792 | |
| 807 | − v4l2_dbg(2, debug, sd, "%s: write EDID on port %c (spa at 0x%x)\n", | |
| 808 | − __func__, (port == ADV7842_EDID_PORT_A) ? 'A' : 'B', spa_loc); | |
| 793 | + v4l2_dbg(2, debug, sd, "%s: write EDID on port %c\n", | |
| 794 | + __func__, (port == ADV7842_EDID_PORT_A) ? 'A' : 'B'); | |
| 809 | 795 | |
| 810 | 796 | /* HPA disable on port A and B */ |
| 811 | 797 | io_write_and_or(sd, 0x20, 0xcf, 0x00); |
| @@ -816,24 +802,33 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) · 4 unmodified lines | ||
| 816 | 802 | if (!state->hdmi_edid.present) |
| 817 | 803 | return 0; |
| 818 | 804 | |
| 805 | + pa = cec_get_edid_phys_addr(edid, 256, &spa_loc); | |
| 806 | + err = cec_phys_addr_validate(pa, &pa, NULL); | |
| 807 | + if (err) | |
| 808 | + return err; | |
| 809 | + | |
| 810 | + /* | |
| 811 | + * Return an error if no location of the source physical address | |
| 812 | + * was found. | |
| 813 | + */ | |
| 814 | + if (spa_loc == 0) | |
| 815 | + return -EINVAL; | |
| 816 | + | |
| 819 | 817 | /* edid segment pointer '0' for HDMI ports */ |
| 820 | 818 | rep_write_and_or(sd, 0x77, 0xef, 0x00); |
| 821 | 819 | |
| 822 | 820 | for (i = 0; !err && i < 256; i += I2C_SMBUS_BLOCK_MAX) |
| 823 | 821 | err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, |
| 824 | − I2C_SMBUS_BLOCK_MAX, val + i); | |
| 822 | + I2C_SMBUS_BLOCK_MAX, edid + i); | |
| 825 | 823 | if (err) |
| 826 | 824 | return err; |
| 827 | 825 | |
| 828 | − if (spa_loc < 0) | |
| 829 | − spa_loc = 0xc0; /* Default value [REF_02, p. 199] */ | |
| 830 | − | |
| 831 | 826 | if (port == ADV7842_EDID_PORT_A) { |
| 832 | − rep_write(sd, 0x72, val[spa_loc]); | |
| 833 | − rep_write(sd, 0x73, val[spa_loc + 1]); | |
| 827 | + rep_write(sd, 0x72, edid[spa_loc]); | |
| 828 | + rep_write(sd, 0x73, edid[spa_loc + 1]); | |
| 834 | 829 | } else { |
| 835 | − rep_write(sd, 0x74, val[spa_loc]); | |
| 836 | − rep_write(sd, 0x75, val[spa_loc + 1]); | |
| 830 | + rep_write(sd, 0x74, edid[spa_loc]); | |
| 831 | + rep_write(sd, 0x75, edid[spa_loc + 1]); | |
| 837 | 832 | } |
| 838 | 833 | rep_write(sd, 0x76, spa_loc & 0xff); |
| 839 | 834 | rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40); |
| @@ -853,10 +848,10 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) · 13 unmodified lines | ||
| 853 | 848 | (port == ADV7842_EDID_PORT_A) ? 'A' : 'B'); |
| 854 | 849 | return -EIO; |
| 855 | 850 | } |
| 851 | + cec_s_phys_addr(state->cec_adap, pa, false); | |
| 856 | 852 | |
| 857 | 853 | /* enable hotplug after 200 ms */ |
| 858 | − queue_delayed_work(state->work_queues, | |
| 859 | − &state->delayed_work_enable_hotplug, HZ / 5); | |
| 854 | + schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 5); | |
| 860 | 855 | |
| 861 | 856 | return 0; |
| 862 | 857 | } |
| @@ -983,20 +978,11 @@ static int adv7842_s_register(struct v4l2_subdev *sd, · 120 unmodified lines | ||
| 983 | 978 | static int adv7842_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) |
| 984 | 979 | { |
| 985 | 980 | struct adv7842_state *state = to_state(sd); |
| 986 | − int prev = v4l2_ctrl_g_ctrl(state->detect_tx_5v_ctrl); | |
| 987 | − u8 reg_io_6f = io_read(sd, 0x6f); | |
| 988 | − int val = 0; | |
| 981 | + u16 cable_det = adv7842_read_cable_det(sd); | |
| 989 | 982 | |
| 990 | − if (reg_io_6f & 0x02) | |
| 991 | − val |= 1; /* port A */ | |
| 992 | − if (reg_io_6f & 0x01) | |
| 993 | − val |= 2; /* port B */ | |
| 994 | − | |
| 995 | − v4l2_dbg(1, debug, sd, "%s: 0x%x -> 0x%x\n", __func__, prev, val); | |
| 983 | + v4l2_dbg(1, debug, sd, "%s: 0x%x\n", __func__, cable_det); | |
| 996 | 984 | |
| 997 | − if (val != prev) | |
| 998 | − return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, val); | |
| 999 | − return 0; | |
| 985 | + return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, cable_det); | |
| 1000 | 986 | } |
| 1001 | 987 | |
| 1002 | 988 | static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, |
| @@ -1198,6 +1184,10 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) · 195 unmodified lines | ||
| 1198 | 1184 | struct adv7842_state *state = to_state(sd); |
| 1199 | 1185 | bool rgb_output = io_read(sd, 0x02) & 0x02; |
| 1200 | 1186 | bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; |
| 1187 | + u8 y = HDMI_COLORSPACE_RGB; | |
| 1188 | + | |
| 1189 | + if (hdmi_signal && (io_read(sd, 0x60) & 1)) | |
| 1190 | + y = infoframe_read(sd, 0x01) >> 5; | |
| 1201 | 1191 | |
| 1202 | 1192 | v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n", |
| 1203 | 1193 | __func__, state->rgb_quantization_range, |
| @@ -1205,6 +1195,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) · 1 unmodified line | ||
| 1205 | 1195 | |
| 1206 | 1196 | adv7842_set_gain(sd, true, 0x0, 0x0, 0x0); |
| 1207 | 1197 | adv7842_set_offset(sd, true, 0x0, 0x0, 0x0); |
| 1198 | + io_write_clr_set(sd, 0x02, 0x04, rgb_output ? 0 : 4); | |
| 1208 | 1199 | |
| 1209 | 1200 | switch (state->rgb_quantization_range) { |
| 1210 | 1201 | case V4L2_DV_RGB_RANGE_AUTO: |
| @@ -1254,6 +1245,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) · 43 unmodified lines | ||
| 1254 | 1245 | break; |
| 1255 | 1246 | } |
| 1256 | 1247 | |
| 1248 | + if (y != HDMI_COLORSPACE_RGB) | |
| 1249 | + break; | |
| 1250 | + | |
| 1257 | 1251 | /* RGB limited range (16-235) */ |
| 1258 | 1252 | io_write_and_or(sd, 0x02, 0x0f, 0x00); |
| 1259 | 1253 | |
| @@ -1265,6 +1259,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) · 5 unmodified lines | ||
| 1265 | 1259 | break; |
| 1266 | 1260 | } |
| 1267 | 1261 | |
| 1262 | + if (y != HDMI_COLORSPACE_RGB) | |
| 1263 | + break; | |
| 1264 | + | |
| 1268 | 1265 | /* RGB full range (0-255) */ |
| 1269 | 1266 | io_write_and_or(sd, 0x02, 0x0f, 0x10); |
| 1270 | 1267 | |
| @@ -2072,6 +2069,7 @@ static void adv7842_setup_format(struct adv7842_state *state) · 801 unmodified lines | ||
| 2072 | 2069 | io_write_clr_set(sd, 0x04, 0xe0, adv7842_op_ch_sel(state)); |
| 2073 | 2070 | io_write_clr_set(sd, 0x05, 0x01, |
| 2074 | 2071 | state->format->swap_cb_cr ? ADV7842_OP_SWAP_CB_CR : 0); |
| 2072 | + set_rgb_quantization_range(sd); | |
| 2075 | 2073 | } |
| 2076 | 2074 | |
| 2077 | 2075 | static int adv7842_get_format(struct v4l2_subdev *sd, |
| @@ -2170,6 +2168,207 @@ static void adv7842_irq_enable(struct v4l2_subdev *sd, bool enable) · 92 unmodified lines | ||
| 2170 | 2168 | } |
| 2171 | 2169 | } |
| 2172 | 2170 | |
| 2171 | +#if IS_ENABLED(CONFIG_VIDEO_ADV7842_CEC) | |
| 2172 | +static void adv7842_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status) | |
| 2173 | +{ | |
| 2174 | + struct adv7842_state *state = to_state(sd); | |
| 2175 | + | |
| 2176 | + if ((cec_read(sd, 0x11) & 0x01) == 0) { | |
| 2177 | + v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__); | |
| 2178 | + return; | |
| 2179 | + } | |
| 2180 | + | |
| 2181 | + if (tx_raw_status & 0x02) { | |
| 2182 | + v4l2_dbg(1, debug, sd, "%s: tx raw: arbitration lost\n", | |
| 2183 | + __func__); | |
| 2184 | + cec_transmit_done(state->cec_adap, CEC_TX_STATUS_ARB_LOST, | |
| 2185 | + 1, 0, 0, 0); | |
| 2186 | + return; | |
| 2187 | + } | |
| 2188 | + if (tx_raw_status & 0x04) { | |
| 2189 | + u8 status; | |
| 2190 | + u8 nack_cnt; | |
| 2191 | + u8 low_drive_cnt; | |
| 2192 | + | |
| 2193 | + v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__); | |
| 2194 | + /* | |
| 2195 | + * We set this status bit since this hardware performs | |
| 2196 | + * retransmissions. | |
| 2197 | + */ | |
| 2198 | + status = CEC_TX_STATUS_MAX_RETRIES; | |
| 2199 | + nack_cnt = cec_read(sd, 0x14) & 0xf; | |
| 2200 | + if (nack_cnt) | |
| 2201 | + status |= CEC_TX_STATUS_NACK; | |
| 2202 | + low_drive_cnt = cec_read(sd, 0x14) >> 4; | |
| 2203 | + if (low_drive_cnt) | |
| 2204 | + status |= CEC_TX_STATUS_LOW_DRIVE; | |
| 2205 | + cec_transmit_done(state->cec_adap, status, | |
| 2206 | + 0, nack_cnt, low_drive_cnt, 0); | |
| 2207 | + return; | |
| 2208 | + } | |
| 2209 | + if (tx_raw_status & 0x01) { | |
| 2210 | + v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__); | |
| 2211 | + cec_transmit_done(state->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); | |
| 2212 | + return; | |
| 2213 | + } | |
| 2214 | +} | |
| 2215 | + | |
| 2216 | +static void adv7842_cec_isr(struct v4l2_subdev *sd, bool *handled) | |
| 2217 | +{ | |
| 2218 | + u8 cec_irq; | |
| 2219 | + | |
| 2220 | + /* cec controller */ | |
| 2221 | + cec_irq = io_read(sd, 0x93) & 0x0f; | |
| 2222 | + if (!cec_irq) | |
| 2223 | + return; | |
| 2224 | + | |
| 2225 | + v4l2_dbg(1, debug, sd, "%s: cec: irq 0x%x\n", __func__, cec_irq); | |
| 2226 | + adv7842_cec_tx_raw_status(sd, cec_irq); | |
| 2227 | + if (cec_irq & 0x08) { | |
| 2228 | + struct adv7842_state *state = to_state(sd); | |
| 2229 | + struct cec_msg msg; | |
| 2230 | + | |
| 2231 | + msg.len = cec_read(sd, 0x25) & 0x1f; | |
| 2232 | + if (msg.len > 16) | |
| 2233 | + msg.len = 16; | |
| 2234 | + | |
| 2235 | + if (msg.len) { | |
| 2236 | + u8 i; | |
| 2237 | + | |
| 2238 | + for (i = 0; i < msg.len; i++) | |
| 2239 | + msg.msg[i] = cec_read(sd, i + 0x15); | |
| 2240 | + cec_write(sd, 0x26, 0x01); /* re-enable rx */ | |
| 2241 | + cec_received_msg(state->cec_adap, &msg); | |
| 2242 | + } | |
| 2243 | + } | |
| 2244 | + | |
| 2245 | + io_write(sd, 0x94, cec_irq); | |
| 2246 | + | |
| 2247 | + if (handled) | |
| 2248 | + *handled = true; | |
| 2249 | +} | |
| 2250 | + | |
| 2251 | +static int adv7842_cec_adap_enable(struct cec_adapter *adap, bool enable) | |
| 2252 | +{ | |
| 2253 | + struct adv7842_state *state = adap->priv; | |
| 2254 | + struct v4l2_subdev *sd = &state->sd; | |
| 2255 | + | |
| 2256 | + if (!state->cec_enabled_adap && enable) { | |
| 2257 | + cec_write_clr_set(sd, 0x2a, 0x01, 0x01); /* power up cec */ | |
| 2258 | + cec_write(sd, 0x2c, 0x01); /* cec soft reset */ | |
| 2259 | + cec_write_clr_set(sd, 0x11, 0x01, 0); /* initially disable tx */ | |
| 2260 | + /* enabled irqs: */ | |
| 2261 | + /* tx: ready */ | |
| 2262 | + /* tx: arbitration lost */ | |
| 2263 | + /* tx: retry timeout */ | |
| 2264 | + /* rx: ready */ | |
| 2265 | + io_write_clr_set(sd, 0x96, 0x0f, 0x0f); | |
| 2266 | + cec_write(sd, 0x26, 0x01); /* enable rx */ | |
| 2267 | + } else if (state->cec_enabled_adap && !enable) { | |
| 2268 | + /* disable cec interrupts */ | |
| 2269 | + io_write_clr_set(sd, 0x96, 0x0f, 0x00); | |
| 2270 | + /* disable address mask 1-3 */ | |
| 2271 | + cec_write_clr_set(sd, 0x27, 0x70, 0x00); | |
| 2272 | + /* power down cec section */ | |
| 2273 | + cec_write_clr_set(sd, 0x2a, 0x01, 0x00); | |
| 2274 | + state->cec_valid_addrs = 0; | |
| 2275 | + } | |
| 2276 | + state->cec_enabled_adap = enable; | |
| 2277 | + return 0; | |
| 2278 | +} | |
| 2279 | + | |
| 2280 | +static int adv7842_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) | |
| 2281 | +{ | |
| 2282 | + struct adv7842_state *state = adap->priv; | |
| 2283 | + struct v4l2_subdev *sd = &state->sd; | |
| 2284 | + unsigned int i, free_idx = ADV7842_MAX_ADDRS; | |
| 2285 | + | |
| 2286 | + if (!state->cec_enabled_adap) | |
| 2287 | + return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO; | |
| 2288 | + | |
| 2289 | + if (addr == CEC_LOG_ADDR_INVALID) { | |
| 2290 | + cec_write_clr_set(sd, 0x27, 0x70, 0); | |
| 2291 | + state->cec_valid_addrs = 0; | |
| 2292 | + return 0; | |
| 2293 | + } | |
| 2294 | + | |
| 2295 | + for (i = 0; i < ADV7842_MAX_ADDRS; i++) { | |
| 2296 | + bool is_valid = state->cec_valid_addrs & (1 << i); | |
| 2297 | + | |
| 2298 | + if (free_idx == ADV7842_MAX_ADDRS && !is_valid) | |
| 2299 | + free_idx = i; | |
| 2300 | + if (is_valid && state->cec_addr[i] == addr) | |
| 2301 | + return 0; | |
| 2302 | + } | |
| 2303 | + if (i == ADV7842_MAX_ADDRS) { | |
| 2304 | + i = free_idx; | |
| 2305 | + if (i == ADV7842_MAX_ADDRS) | |
| 2306 | + return -ENXIO; | |
| 2307 | + } | |
| 2308 | + state->cec_addr[i] = addr; | |
| 2309 | + state->cec_valid_addrs |= 1 << i; | |
| 2310 | + | |
| 2311 | + switch (i) { | |
| 2312 | + case 0: | |
| 2313 | + /* enable address mask 0 */ | |
| 2314 | + cec_write_clr_set(sd, 0x27, 0x10, 0x10); | |
| 2315 | + /* set address for mask 0 */ | |
| 2316 | + cec_write_clr_set(sd, 0x28, 0x0f, addr); | |
| 2317 | + break; | |
| 2318 | + case 1: | |
| 2319 | + /* enable address mask 1 */ | |
| 2320 | + cec_write_clr_set(sd, 0x27, 0x20, 0x20); | |
| 2321 | + /* set address for mask 1 */ | |
| 2322 | + cec_write_clr_set(sd, 0x28, 0xf0, addr << 4); | |
| 2323 | + break; | |
| 2324 | + case 2: | |
| 2325 | + /* enable address mask 2 */ | |
| 2326 | + cec_write_clr_set(sd, 0x27, 0x40, 0x40); | |
| 2327 | + /* set address for mask 1 */ | |
| 2328 | + cec_write_clr_set(sd, 0x29, 0x0f, addr); | |
| 2329 | + break; | |
| 2330 | + } | |
| 2331 | + return 0; | |
| 2332 | +} | |
| 2333 | + | |
| 2334 | +static int adv7842_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | |
| 2335 | + u32 signal_free_time, struct cec_msg *msg) | |
| 2336 | +{ | |
| 2337 | + struct adv7842_state *state = adap->priv; | |
| 2338 | + struct v4l2_subdev *sd = &state->sd; | |
| 2339 | + u8 len = msg->len; | |
| 2340 | + unsigned int i; | |
| 2341 | + | |
| 2342 | + /* | |
| 2343 | + * The number of retries is the number of attempts - 1, but retry | |
| 2344 | + * at least once. It's not clear if a value of 0 is allowed, so | |
| 2345 | + * let's do at least one retry. | |
| 2346 | + */ | |
| 2347 | + cec_write_clr_set(sd, 0x12, 0x70, max(1, attempts - 1) << 4); | |
| 2348 | + | |
| 2349 | + if (len > 16) { | |
| 2350 | + v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len); | |
| 2351 | + return -EINVAL; | |
| 2352 | + } | |
| 2353 | + | |
| 2354 | + /* write data */ | |
| 2355 | + for (i = 0; i < len; i++) | |
| 2356 | + cec_write(sd, i, msg->msg[i]); | |
| 2357 | + | |
| 2358 | + /* set length (data + header) */ | |
| 2359 | + cec_write(sd, 0x10, len); | |
| 2360 | + /* start transmit, enable tx */ | |
| 2361 | + cec_write(sd, 0x11, 0x01); | |
| 2362 | + return 0; | |
| 2363 | +} | |
| 2364 | + | |
| 2365 | +static const struct cec_adap_ops adv7842_cec_adap_ops = { | |
| 2366 | + .adap_enable = adv7842_cec_adap_enable, | |
| 2367 | + .adap_log_addr = adv7842_cec_adap_log_addr, | |
| 2368 | + .adap_transmit = adv7842_cec_adap_transmit, | |
| 2369 | +}; | |
| 2370 | +#endif | |
| 2371 | + | |
| 2173 | 2372 | static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) |
| 2174 | 2373 | { |
| 2175 | 2374 | struct adv7842_state *state = to_state(sd); |
| @@ -2241,6 +2440,11 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) · 65 unmodified lines | ||
| 2241 | 2440 | *handled = true; |
| 2242 | 2441 | } |
| 2243 | 2442 | |
| 2443 | +#if IS_ENABLED(CONFIG_VIDEO_ADV7842_CEC) | |
| 2444 | + /* cec */ | |
| 2445 | + adv7842_cec_isr(sd, handled); | |
| 2446 | +#endif | |
| 2447 | + | |
| 2244 | 2448 | /* tx 5v detect */ |
| 2245 | 2449 | if (irq_status[2] & 0x3) { |
| 2246 | 2450 | v4l2_dbg(1, debug, sd, "%s: irq tx_5v\n", __func__); |
| @@ -2321,10 +2525,12 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e) · 74 unmodified lines | ||
| 2321 | 2525 | case ADV7842_EDID_PORT_A: |
| 2322 | 2526 | case ADV7842_EDID_PORT_B: |
| 2323 | 2527 | memset(&state->hdmi_edid.edid, 0, 256); |
| 2324 | − if (e->blocks) | |
| 2528 | + if (e->blocks) { | |
| 2325 | 2529 | state->hdmi_edid.present |= 0x04 << e->pad; |
| 2326 | − else | |
| 2530 | + } else { | |
| 2327 | 2531 | state->hdmi_edid.present &= ~(0x04 << e->pad); |
| 2532 | + adv7842_s_detect_tx_5v_ctrl(sd); | |
| 2533 | + } | |
| 2328 | 2534 | memcpy(&state->hdmi_edid.edid, e->edid, 128 * e->blocks); |
| 2329 | 2535 | err = edid_write_hdmi_segment(sd, e->pad); |
| 2330 | 2536 | break; |
| @@ -2397,6 +2603,8 @@ static void adv7842_log_infoframes(struct v4l2_subdev *sd) · 66 unmodified lines | ||
| 2397 | 2603 | log_infoframe(sd, &cri[i]); |
| 2398 | 2604 | } |
| 2399 | 2605 | |
| 2606 | +#if 0 | |
| 2607 | +/* Let's keep it here for now, as it could be useful for debug */ | |
| 2400 | 2608 | static const char * const prim_mode_txt[] = { |
| 2401 | 2609 | "SDP", |
| 2402 | 2610 | "Component", |
| @@ -2415,6 +2623,7 @@ static const char * const prim_mode_txt[] = { · 12 unmodified lines | ||
| 2415 | 2623 | "Reserved", |
| 2416 | 2624 | "Reserved", |
| 2417 | 2625 | }; |
| 2626 | +#endif | |
| 2418 | 2627 | |
| 2419 | 2628 | static int adv7842_sdp_log_status(struct v4l2_subdev *sd) |
| 2420 | 2629 | { |
| @@ -2509,8 +2718,19 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) · 88 unmodified lines | ||
| 2509 | 2718 | v4l2_info(sd, "HPD A %s, B %s\n", |
| 2510 | 2719 | reg_io_0x21 & 0x02 ? "enabled" : "disabled", |
| 2511 | 2720 | reg_io_0x21 & 0x01 ? "enabled" : "disabled"); |
| 2512 | − v4l2_info(sd, "CEC %s\n", !!(cec_read(sd, 0x2a) & 0x01) ? | |
| 2721 | + v4l2_info(sd, "CEC: %s\n", state->cec_enabled_adap ? | |
| 2513 | 2722 | "enabled" : "disabled"); |
| 2723 | + if (state->cec_enabled_adap) { | |
| 2724 | + int i; | |
| 2725 | + | |
| 2726 | + for (i = 0; i < ADV7842_MAX_ADDRS; i++) { | |
| 2727 | + bool is_valid = state->cec_valid_addrs & (1 << i); | |
| 2728 | + | |
| 2729 | + if (is_valid) | |
| 2730 | + v4l2_info(sd, "CEC Logical Address: 0x%x\n", | |
| 2731 | + state->cec_addr[i]); | |
| 2732 | + } | |
| 2733 | + } | |
| 2514 | 2734 | |
| 2515 | 2735 | v4l2_info(sd, "-----Signal status-----\n"); |
| 2516 | 2736 | if (state->hdmi_port_a) { |
| @@ -2569,11 +2789,11 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) · 52 unmodified lines | ||
| 2569 | 2789 | rgb_quantization_range_txt[state->rgb_quantization_range]); |
| 2570 | 2790 | v4l2_info(sd, "Input color space: %s\n", |
| 2571 | 2791 | input_color_space_txt[reg_io_0x02 >> 4]); |
| 2572 | − v4l2_info(sd, "Output color space: %s %s, saturator %s\n", | |
| 2792 | + v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n", | |
| 2573 | 2793 | (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", |
| 2574 | − (reg_io_0x02 & 0x04) ? "(16-235)" : "(0-255)", | |
| 2575 | − ((reg_io_0x02 & 0x04) ^ (reg_io_0x02 & 0x01)) ? | |
| 2576 | − "enabled" : "disabled"); | |
| 2794 | + (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? | |
| 2795 | + "(16-235)" : "(0-255)", | |
| 2796 | + (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); | |
| 2577 | 2797 | v4l2_info(sd, "Color space conversion: %s\n", |
| 2578 | 2798 | csc_coeff_sel_rb[cp_read(sd, 0xf4) >> 4]); |
| 2579 | 2799 | |
| @@ -2777,11 +2997,7 @@ static int adv7842_core_init(struct v4l2_subdev *sd) · 197 unmodified lines | ||
| 2777 | 2997 | io_write(sd, 0x15, 0x80); /* Power up pads */ |
| 2778 | 2998 | |
| 2779 | 2999 | /* video format */ |
| 2780 | − io_write(sd, 0x02, | |
| 2781 | − 0xf0 | | |
| 2782 | − pdata->alt_gamma << 3 | | |
| 2783 | − pdata->op_656_range << 2 | | |
| 2784 | − pdata->alt_data_sat << 0); | |
| 3000 | + io_write(sd, 0x02, 0xf0 | pdata->alt_gamma << 3); | |
| 2785 | 3001 | io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 | |
| 2786 | 3002 | pdata->insert_av_codes << 2 | |
| 2787 | 3003 | pdata->replicate_av_codes << 1); |
| @@ -3031,6 +3247,24 @@ static int adv7842_subscribe_event(struct v4l2_subdev *sd, · 243 unmodified lines | ||
| 3031 | 3247 | } |
| 3032 | 3248 | } |
| 3033 | 3249 | |
| 3250 | +static int adv7842_registered(struct v4l2_subdev *sd) | |
| 3251 | +{ | |
| 3252 | + struct adv7842_state *state = to_state(sd); | |
| 3253 | + int err; | |
| 3254 | + | |
| 3255 | + err = cec_register_adapter(state->cec_adap); | |
| 3256 | + if (err) | |
| 3257 | + cec_delete_adapter(state->cec_adap); | |
| 3258 | + return err; | |
| 3259 | +} | |
| 3260 | + | |
| 3261 | +static void adv7842_unregistered(struct v4l2_subdev *sd) | |
| 3262 | +{ | |
| 3263 | + struct adv7842_state *state = to_state(sd); | |
| 3264 | + | |
| 3265 | + cec_unregister_adapter(state->cec_adap); | |
| 3266 | +} | |
| 3267 | + | |
| 3034 | 3268 | /* ----------------------------------------------------------------------- */ |
| 3035 | 3269 | |
| 3036 | 3270 | static const struct v4l2_ctrl_ops adv7842_ctrl_ops = { |
| @@ -3077,6 +3311,11 @@ static const struct v4l2_subdev_ops adv7842_ops = { · 40 unmodified lines | ||
| 3077 | 3311 | .pad = &adv7842_pad_ops, |
| 3078 | 3312 | }; |
| 3079 | 3313 | |
| 3314 | +static const struct v4l2_subdev_internal_ops adv7842_int_ops = { | |
| 3315 | + .registered = adv7842_registered, | |
| 3316 | + .unregistered = adv7842_unregistered, | |
| 3317 | +}; | |
| 3318 | + | |
| 3080 | 3319 | /* -------------------------- custom ctrls ---------------------------------- */ |
| 3081 | 3320 | |
| 3082 | 3321 | static const struct v4l2_ctrl_config adv7842_ctrl_analog_sampling_phase = { |
| @@ -3241,6 +3480,7 @@ static int adv7842_probe(struct i2c_client *client, · 158 unmodified lines | ||
| 3241 | 3480 | sd = &state->sd; |
| 3242 | 3481 | v4l2_i2c_subdev_init(sd, client, &adv7842_ops); |
| 3243 | 3482 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; |
| 3483 | + sd->internal_ops = &adv7842_int_ops; | |
| 3244 | 3484 | state->mode = pdata->mode; |
| 3245 | 3485 | |
| 3246 | 3486 | state->hdmi_port_a = pdata->input == ADV7842_SELECT_HDMI_PORT_A; |
| @@ -3311,13 +3551,6 @@ static int adv7842_probe(struct i2c_client *client, · 64 unmodified lines | ||
| 3311 | 3551 | goto err_i2c; |
| 3312 | 3552 | } |
| 3313 | 3553 | |
| 3314 | − /* work queues */ | |
| 3315 | − state->work_queues = create_singlethread_workqueue(client->name); | |
| 3316 | − if (!state->work_queues) { | |
| 3317 | − v4l2_err(sd, "Could not create work queue\n"); | |
| 3318 | − err = -ENOMEM; | |
| 3319 | − goto err_i2c; | |
| 3320 | − } | |
| 3321 | 3554 | |
| 3322 | 3555 | INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, |
| 3323 | 3556 | adv7842_delayed_work_enable_hotplug); |
| @@ -3331,6 +3564,17 @@ static int adv7842_probe(struct i2c_client *client, · 7 unmodified lines | ||
| 3331 | 3564 | if (err) |
| 3332 | 3565 | goto err_entity; |
| 3333 | 3566 | |
| 3567 | +#if IS_ENABLED(CONFIG_VIDEO_ADV7842_CEC) | |
| 3568 | + state->cec_adap = cec_allocate_adapter(&adv7842_cec_adap_ops, | |
| 3569 | + state, dev_name(&client->dev), | |
| 3570 | + CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | | |
| 3571 | + CEC_CAP_PASSTHROUGH | CEC_CAP_RC, ADV7842_MAX_ADDRS, | |
| 3572 | + &client->dev); | |
| 3573 | + err = PTR_ERR_OR_ZERO(state->cec_adap); | |
| 3574 | + if (err) | |
| 3575 | + goto err_entity; | |
| 3576 | +#endif | |
| 3577 | + | |
| 3334 | 3578 | v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, |
| 3335 | 3579 | client->addr << 1, client->adapter->name); |
| 3336 | 3580 | return 0; |
| @@ -3339,7 +3583,6 @@ err_entity: · 2 unmodified lines | ||
| 3339 | 3583 | media_entity_cleanup(&sd->entity); |
| 3340 | 3584 | err_work_queues: |
| 3341 | 3585 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
| 3342 | − destroy_workqueue(state->work_queues); | |
| 3343 | 3586 | err_i2c: |
| 3344 | 3587 | adv7842_unregister_clients(sd); |
| 3345 | 3588 | err_hdl: |
| @@ -3355,9 +3598,7 @@ static int adv7842_remove(struct i2c_client *client) · 9 unmodified lines | ||
| 3355 | 3598 | struct adv7842_state *state = to_state(sd); |
| 3356 | 3599 | |
| 3357 | 3600 | adv7842_irq_enable(sd, false); |
| 3358 | − | |
| 3359 | 3601 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
| 3360 | − destroy_workqueue(state->work_queues); | |
| 3361 | 3602 | v4l2_device_unregister_subdev(sd); |
| 3362 | 3603 | media_entity_cleanup(&sd->entity); |
| 3363 | 3604 | adv7842_unregister_clients(sd); |
| @@ -121,13 +121,6 @@ static const struct v4l2_ctrl_ops cs53l32a_ctrl_ops = { · 120 unmodified lines | ||
| 121 | 121 | |
| 122 | 122 | static const struct v4l2_subdev_core_ops cs53l32a_core_ops = { |
| 123 | 123 | .log_status = cs53l32a_log_status, |
| 124 | − .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | |
| 125 | − .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | |
| 126 | − .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | |
| 127 | − .g_ctrl = v4l2_subdev_g_ctrl, | |
| 128 | − .s_ctrl = v4l2_subdev_s_ctrl, | |
| 129 | − .queryctrl = v4l2_subdev_queryctrl, | |
| 130 | − .querymenu = v4l2_subdev_querymenu, | |
| 131 | 124 | }; |
| 132 | 125 | |
| 133 | 126 | static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = { |
| @@ -5042,13 +5042,6 @@ static const struct v4l2_ctrl_ops cx25840_ctrl_ops = { · 5041 unmodified lines | ||
| 5042 | 5042 | |
| 5043 | 5043 | static const struct v4l2_subdev_core_ops cx25840_core_ops = { |
| 5044 | 5044 | .log_status = cx25840_log_status, |
| 5045 | − .g_ctrl = v4l2_subdev_g_ctrl, | |
| 5046 | − .s_ctrl = v4l2_subdev_s_ctrl, | |
| 5047 | − .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | |
| 5048 | − .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | |
| 5049 | − .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | |
| 5050 | − .queryctrl = v4l2_subdev_queryctrl, | |
| 5051 | − .querymenu = v4l2_subdev_querymenu, | |
| 5052 | 5045 | .reset = cx25840_reset, |
| 5053 | 5046 | .load_fw = cx25840_load_fw, |
| 5054 | 5047 | .s_io_pin_config = common_s_io_pin_config, |
| @@ -642,13 +642,6 @@ static const struct v4l2_ctrl_ops msp_ctrl_ops = { · 641 unmodified lines | ||
| 642 | 642 | |
| 643 | 643 | static const struct v4l2_subdev_core_ops msp_core_ops = { |
| 644 | 644 | .log_status = msp_log_status, |
| 645 | − .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | |
| 646 | − .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | |
| 647 | − .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | |
| 648 | − .g_ctrl = v4l2_subdev_g_ctrl, | |
| 649 | − .s_ctrl = v4l2_subdev_s_ctrl, | |
| 650 | − .queryctrl = v4l2_subdev_queryctrl, | |
| 651 | − .querymenu = v4l2_subdev_querymenu, | |
| 652 | 645 | }; |
| 653 | 646 | |
| 654 | 647 | static const struct v4l2_subdev_video_ops msp_video_ops = { |
| @@ -233,10 +233,21 @@ static int __mt9t001_set_power(struct mt9t001 *mt9t001, bool on) · 232 unmodified lines | ||
| 233 | 233 | ret = mt9t001_reset(mt9t001); |
| 234 | 234 | if (ret < 0) { |
| 235 | 235 | dev_err(&client->dev, "Failed to reset the camera\n"); |
| 236 | − return ret; | |
| 236 | + goto e_power; | |
| 237 | 237 | } |
| 238 | 238 | |
| 239 | − return v4l2_ctrl_handler_setup(&mt9t001->ctrls); | |
| 239 | + ret = v4l2_ctrl_handler_setup(&mt9t001->ctrls); | |
| 240 | + if (ret < 0) { | |
| 241 | + dev_err(&client->dev, "Failed to set up control handlers\n"); | |
| 242 | + goto e_power; | |
| 243 | + } | |
| 244 | + | |
| 245 | + return 0; | |
| 246 | + | |
| 247 | +e_power: | |
| 248 | + mt9t001_power_off(mt9t001); | |
| 249 | + | |
| 250 | + return ret; | |
| 240 | 251 | } |
| 241 | 252 | |
| 242 | 253 | /* ----------------------------------------------------------------------------- |
| @@ -834,7 +845,7 @@ static struct v4l2_subdev_ops mt9t001_subdev_ops = { · 591 unmodified lines | ||
| 834 | 845 | .pad = &mt9t001_subdev_pad_ops, |
| 835 | 846 | }; |
| 836 | 847 | |
| 837 | −static struct v4l2_subdev_internal_ops mt9t001_subdev_internal_ops = { | |
| 848 | +static const struct v4l2_subdev_internal_ops mt9t001_subdev_internal_ops = { | |
| 838 | 849 | .registered = mt9t001_registered, |
| 839 | 850 | .open = mt9t001_open, |
| 840 | 851 | .close = mt9t001_close, |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <linux/log2.h> |
| 20 | 20 | #include <linux/mutex.h> |
| 21 | 21 | #include <linux/of.h> |
| 22 | −#include <linux/of_gpio.h> | |
| 23 | 22 | #include <linux/regmap.h> |
| 24 | 23 | #include <linux/slab.h> |
| 25 | 24 | #include <linux/videodev2.h> |
| @@ -133,9 +132,16 @@ · 107 unmodified lines | ||
| 133 | 132 | #define MT9V032_TEST_PATTERN_GRAY_DIAGONAL (3 << 11) |
| 134 | 133 | #define MT9V032_TEST_PATTERN_ENABLE (1 << 13) |
| 135 | 134 | #define MT9V032_TEST_PATTERN_FLIP (1 << 14) |
| 135 | +#define MT9V032_AEGC_DESIRED_BIN 0xa5 | |
| 136 | +#define MT9V032_AEC_UPDATE_FREQUENCY 0xa6 | |
| 137 | +#define MT9V032_AEC_LPF 0xa8 | |
| 138 | +#define MT9V032_AGC_UPDATE_FREQUENCY 0xa9 | |
| 139 | +#define MT9V032_AGC_LPF 0xaa | |
| 136 | 140 | #define MT9V032_AEC_AGC_ENABLE 0xaf |
| 137 | 141 | #define MT9V032_AEC_ENABLE (1 << 0) |
| 138 | 142 | #define MT9V032_AGC_ENABLE (1 << 1) |
| 143 | +#define MT9V034_AEC_MAX_SHUTTER_WIDTH 0xad | |
| 144 | +#define MT9V032_AEC_MAX_SHUTTER_WIDTH 0xbd | |
| 139 | 145 | #define MT9V032_THERMAL_INFO 0xc1 |
| 140 | 146 | |
| 141 | 147 | enum mt9v032_model { |
| @@ -162,6 +168,8 @@ struct mt9v032_model_data { · 20 unmodified lines | ||
| 162 | 168 | unsigned int min_shutter; |
| 163 | 169 | unsigned int max_shutter; |
| 164 | 170 | unsigned int pclk_reg; |
| 171 | + unsigned int aec_max_shutter_reg; | |
| 172 | + const struct v4l2_ctrl_config * const aec_max_shutter_v4l2_ctrl; | |
| 165 | 173 | }; |
| 166 | 174 | |
| 167 | 175 | struct mt9v032_model_info { |
| @@ -175,63 +183,6 @@ static const struct mt9v032_model_version mt9v032_versions[] = { · 7 unmodified lines | ||
| 175 | 183 | { MT9V034_CHIP_ID_REV1, "MT9V024/MT9V034 rev1" }, |
| 176 | 184 | }; |
| 177 | 185 | |
| 178 | −static const struct mt9v032_model_data mt9v032_model_data[] = { | |
| 179 | − { | |
| 180 | − /* MT9V022, MT9V032 revisions 1/2/3 */ | |
| 181 | − .min_row_time = 660, | |
| 182 | − .min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN, | |
| 183 | − .min_vblank = MT9V032_VERTICAL_BLANKING_MIN, | |
| 184 | − .max_vblank = MT9V032_VERTICAL_BLANKING_MAX, | |
| 185 | − .min_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MIN, | |
| 186 | − .max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX, | |
| 187 | − .pclk_reg = MT9V032_PIXEL_CLOCK, | |
| 188 | − }, { | |
| 189 | − /* MT9V024, MT9V034 */ | |
| 190 | − .min_row_time = 690, | |
| 191 | − .min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN, | |
| 192 | − .min_vblank = MT9V034_VERTICAL_BLANKING_MIN, | |
| 193 | − .max_vblank = MT9V034_VERTICAL_BLANKING_MAX, | |
| 194 | − .min_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MIN, | |
| 195 | − .max_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MAX, | |
| 196 | − .pclk_reg = MT9V034_PIXEL_CLOCK, | |
| 197 | − }, | |
| 198 | −}; | |
| 199 | − | |
| 200 | −static const struct mt9v032_model_info mt9v032_models[] = { | |
| 201 | − [MT9V032_MODEL_V022_COLOR] = { | |
| 202 | − .data = &mt9v032_model_data[0], | |
| 203 | − .color = true, | |
| 204 | − }, | |
| 205 | − [MT9V032_MODEL_V022_MONO] = { | |
| 206 | − .data = &mt9v032_model_data[0], | |
| 207 | − .color = false, | |
| 208 | − }, | |
| 209 | − [MT9V032_MODEL_V024_COLOR] = { | |
| 210 | − .data = &mt9v032_model_data[1], | |
| 211 | − .color = true, | |
| 212 | − }, | |
| 213 | − [MT9V032_MODEL_V024_MONO] = { | |
| 214 | − .data = &mt9v032_model_data[1], | |
| 215 | − .color = false, | |
| 216 | − }, | |
| 217 | − [MT9V032_MODEL_V032_COLOR] = { | |
| 218 | − .data = &mt9v032_model_data[0], | |
| 219 | − .color = true, | |
| 220 | − }, | |
| 221 | − [MT9V032_MODEL_V032_MONO] = { | |
| 222 | − .data = &mt9v032_model_data[0], | |
| 223 | − .color = false, | |
| 224 | − }, | |
| 225 | − [MT9V032_MODEL_V034_COLOR] = { | |
| 226 | − .data = &mt9v032_model_data[1], | |
| 227 | − .color = true, | |
| 228 | − }, | |
| 229 | − [MT9V032_MODEL_V034_MONO] = { | |
| 230 | − .data = &mt9v032_model_data[1], | |
| 231 | − .color = false, | |
| 232 | − }, | |
| 233 | −}; | |
| 234 | − | |
| 235 | 186 | struct mt9v032 { |
| 236 | 187 | struct v4l2_subdev subdev; |
| 237 | 188 | struct media_pad pad; |
| @@ -349,7 +300,8 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032) · 111 unmodified lines | ||
| 349 | 300 | if (ret < 0) |
| 350 | 301 | return ret; |
| 351 | 302 | |
| 352 | − return regmap_write(map, MT9V032_CHIP_CONTROL, 0); | |
| 303 | + return regmap_write(map, MT9V032_CHIP_CONTROL, | |
| 304 | + MT9V032_CHIP_CONTROL_MASTER_MODE); | |
| 353 | 305 | } |
| 354 | 306 | |
| 355 | 307 | static void mt9v032_power_off(struct mt9v032 *mt9v032) |
| @@ -421,8 +373,7 @@ __mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *c · 65 unmodified lines | ||
| 421 | 373 | |
| 422 | 374 | static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable) |
| 423 | 375 | { |
| 424 | − const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE | |
| 425 | − | MT9V032_CHIP_CONTROL_DOUT_ENABLE | |
| 376 | + const u16 mode = MT9V032_CHIP_CONTROL_DOUT_ENABLE | |
| 426 | 377 | | MT9V032_CHIP_CONTROL_SEQUENTIAL; |
| 427 | 378 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); |
| 428 | 379 | struct v4l2_rect *crop = &mt9v032->crop; |
| @@ -647,6 +598,34 @@ static int mt9v032_set_selection(struct v4l2_subdev *subdev, · 218 unmodified lines | ||
| 647 | 598 | */ |
| 648 | 599 | |
| 649 | 600 | #define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_BASE | 0x1001) |
| 601 | +/* | |
| 602 | + * Value between 1 and 64 to set the desired bin. This is effectively a measure | |
| 603 | + * of how bright the image is supposed to be. Both AGC and AEC try to reach | |
| 604 | + * this. | |
| 605 | + */ | |
| 606 | +#define V4L2_CID_AEGC_DESIRED_BIN (V4L2_CID_USER_BASE | 0x1002) | |
| 607 | +/* | |
| 608 | + * LPF is the low pass filter capability of the chip. Both AEC and AGC have | |
| 609 | + * this setting. This limits the speed in which AGC/AEC adjust their settings. | |
| 610 | + * Possible values are 0-2. 0 means no LPF. For 1 and 2 this equation is used: | |
| 611 | + * | |
| 612 | + * if |(calculated new exp - current exp)| > (current exp / 4) | |
| 613 | + * next exp = calculated new exp | |
| 614 | + * else | |
| 615 | + * next exp = current exp + ((calculated new exp - current exp) / 2^LPF) | |
| 616 | + */ | |
| 617 | +#define V4L2_CID_AEC_LPF (V4L2_CID_USER_BASE | 0x1003) | |
| 618 | +#define V4L2_CID_AGC_LPF (V4L2_CID_USER_BASE | 0x1004) | |
| 619 | +/* | |
| 620 | + * Value between 0 and 15. This is the number of frames being skipped before | |
| 621 | + * updating the auto exposure/gain. | |
| 622 | + */ | |
| 623 | +#define V4L2_CID_AEC_UPDATE_INTERVAL (V4L2_CID_USER_BASE | 0x1005) | |
| 624 | +#define V4L2_CID_AGC_UPDATE_INTERVAL (V4L2_CID_USER_BASE | 0x1006) | |
| 625 | +/* | |
| 626 | + * Maximum shutter width used for AEC. | |
| 627 | + */ | |
| 628 | +#define V4L2_CID_AEC_MAX_SHUTTER_WIDTH (V4L2_CID_USER_BASE | 0x1007) | |
| 650 | 629 | |
| 651 | 630 | static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) |
| 652 | 631 | { |
| @@ -716,6 +695,28 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) · 63 unmodified lines | ||
| 716 | 695 | break; |
| 717 | 696 | } |
| 718 | 697 | return regmap_write(map, MT9V032_TEST_PATTERN, data); |
| 698 | + | |
| 699 | + case V4L2_CID_AEGC_DESIRED_BIN: | |
| 700 | + return regmap_write(map, MT9V032_AEGC_DESIRED_BIN, ctrl->val); | |
| 701 | + | |
| 702 | + case V4L2_CID_AEC_LPF: | |
| 703 | + return regmap_write(map, MT9V032_AEC_LPF, ctrl->val); | |
| 704 | + | |
| 705 | + case V4L2_CID_AGC_LPF: | |
| 706 | + return regmap_write(map, MT9V032_AGC_LPF, ctrl->val); | |
| 707 | + | |
| 708 | + case V4L2_CID_AEC_UPDATE_INTERVAL: | |
| 709 | + return regmap_write(map, MT9V032_AEC_UPDATE_FREQUENCY, | |
| 710 | + ctrl->val); | |
| 711 | + | |
| 712 | + case V4L2_CID_AGC_UPDATE_INTERVAL: | |
| 713 | + return regmap_write(map, MT9V032_AGC_UPDATE_FREQUENCY, | |
| 714 | + ctrl->val); | |
| 715 | + | |
| 716 | + case V4L2_CID_AEC_MAX_SHUTTER_WIDTH: | |
| 717 | + return regmap_write(map, | |
| 718 | + mt9v032->model->data->aec_max_shutter_reg, | |
| 719 | + ctrl->val); | |
| 719 | 720 | } |
| 720 | 721 | |
| 721 | 722 | return 0; |
| @@ -745,6 +746,84 @@ static const struct v4l2_ctrl_config mt9v032_test_pattern_color = { · 23 unmodified lines | ||
| 745 | 746 | .flags = 0, |
| 746 | 747 | }; |
| 747 | 748 | |
| 749 | +static const struct v4l2_ctrl_config mt9v032_aegc_controls[] = { | |
| 750 | + { | |
| 751 | + .ops = &mt9v032_ctrl_ops, | |
| 752 | + .id = V4L2_CID_AEGC_DESIRED_BIN, | |
| 753 | + .type = V4L2_CTRL_TYPE_INTEGER, | |
| 754 | + .name = "AEC/AGC Desired Bin", | |
| 755 | + .min = 1, | |
| 756 | + .max = 64, | |
| 757 | + .step = 1, | |
| 758 | + .def = 58, | |
| 759 | + .flags = 0, | |
| 760 | + }, { | |
| 761 | + .ops = &mt9v032_ctrl_ops, | |
| 762 | + .id = V4L2_CID_AEC_LPF, | |
| 763 | + .type = V4L2_CTRL_TYPE_INTEGER, | |
| 764 | + .name = "AEC Low Pass Filter", | |
| 765 | + .min = 0, | |
| 766 | + .max = 2, | |
| 767 | + .step = 1, | |
| 768 | + .def = 0, | |
| 769 | + .flags = 0, | |
| 770 | + }, { | |
| 771 | + .ops = &mt9v032_ctrl_ops, | |
| 772 | + .id = V4L2_CID_AGC_LPF, | |
| 773 | + .type = V4L2_CTRL_TYPE_INTEGER, | |
| 774 | + .name = "AGC Low Pass Filter", | |
| 775 | + .min = 0, | |
| 776 | + .max = 2, | |
| 777 | + .step = 1, | |
| 778 | + .def = 2, | |
| 779 | + .flags = 0, | |
| 780 | + }, { | |
| 781 | + .ops = &mt9v032_ctrl_ops, | |
| 782 | + .id = V4L2_CID_AEC_UPDATE_INTERVAL, | |
| 783 | + .type = V4L2_CTRL_TYPE_INTEGER, | |
| 784 | + .name = "AEC Update Interval", | |
| 785 | + .min = 0, | |
| 786 | + .max = 16, | |
| 787 | + .step = 1, | |
| 788 | + .def = 2, | |
| 789 | + .flags = 0, | |
| 790 | + }, { | |
| 791 | + .ops = &mt9v032_ctrl_ops, | |
| 792 | + .id = V4L2_CID_AGC_UPDATE_INTERVAL, | |
| 793 | + .type = V4L2_CTRL_TYPE_INTEGER, | |
| 794 | + .name = "AGC Update Interval", | |
| 795 | + .min = 0, | |
| 796 | + .max = 16, | |
| 797 | + .step = 1, | |
| 798 | + .def = 2, | |
| 799 | + .flags = 0, | |
| 800 | + } | |
| 801 | +}; | |
| 802 | + | |
| 803 | +static const struct v4l2_ctrl_config mt9v032_aec_max_shutter_width = { | |
| 804 | + .ops = &mt9v032_ctrl_ops, | |
| 805 | + .id = V4L2_CID_AEC_MAX_SHUTTER_WIDTH, | |
| 806 | + .type = V4L2_CTRL_TYPE_INTEGER, | |
| 807 | + .name = "AEC Max Shutter Width", | |
| 808 | + .min = 1, | |
| 809 | + .max = 2047, | |
| 810 | + .step = 1, | |
| 811 | + .def = 480, | |
| 812 | + .flags = 0, | |
| 813 | +}; | |
| 814 | + | |
| 815 | +static const struct v4l2_ctrl_config mt9v034_aec_max_shutter_width = { | |
| 816 | + .ops = &mt9v032_ctrl_ops, | |
| 817 | + .id = V4L2_CID_AEC_MAX_SHUTTER_WIDTH, | |
| 818 | + .type = V4L2_CTRL_TYPE_INTEGER, | |
| 819 | + .name = "AEC Max Shutter Width", | |
| 820 | + .min = 1, | |
| 821 | + .max = 32765, | |
| 822 | + .step = 1, | |
| 823 | + .def = 480, | |
| 824 | + .flags = 0, | |
| 825 | +}; | |
| 826 | + | |
| 748 | 827 | /* ----------------------------------------------------------------------------- |
| 749 | 828 | * V4L2 subdev core operations |
| 750 | 829 | */ |
| @@ -953,13 +1032,6 @@ static int mt9v032_probe(struct i2c_client *client, · 202 unmodified lines | ||
| 953 | 1032 | unsigned int i; |
| 954 | 1033 | int ret; |
| 955 | 1034 | |
| 956 | − if (!i2c_check_functionality(client->adapter, | |
| 957 | − I2C_FUNC_SMBUS_WORD_DATA)) { | |
| 958 | − dev_warn(&client->adapter->dev, | |
| 959 | − "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); | |
| 960 | − return -EIO; | |
| 961 | − } | |
| 962 | − | |
| 963 | 1035 | mt9v032 = devm_kzalloc(&client->dev, sizeof(*mt9v032), GFP_KERNEL); |
| 964 | 1036 | if (!mt9v032) |
| 965 | 1037 | return -ENOMEM; |
| @@ -986,7 +1058,8 @@ static int mt9v032_probe(struct i2c_client *client, · 20 unmodified lines | ||
| 986 | 1058 | mt9v032->pdata = pdata; |
| 987 | 1059 | mt9v032->model = (const void *)did->driver_data; |
| 988 | 1060 | |
| 989 | − v4l2_ctrl_handler_init(&mt9v032->ctrls, 10); | |
| 1061 | + v4l2_ctrl_handler_init(&mt9v032->ctrls, 11 + | |
| 1062 | + ARRAY_SIZE(mt9v032_aegc_controls)); | |
| 990 | 1063 | |
| 991 | 1064 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, |
| 992 | 1065 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); |
| @@ -1015,6 +1088,13 @@ static int mt9v032_probe(struct i2c_client *client, · 22 unmodified lines | ||
| 1015 | 1088 | mt9v032->test_pattern_color = v4l2_ctrl_new_custom(&mt9v032->ctrls, |
| 1016 | 1089 | &mt9v032_test_pattern_color, NULL); |
| 1017 | 1090 | |
| 1091 | + v4l2_ctrl_new_custom(&mt9v032->ctrls, | |
| 1092 | + mt9v032->model->data->aec_max_shutter_v4l2_ctrl, | |
| 1093 | + NULL); | |
| 1094 | + for (i = 0; i < ARRAY_SIZE(mt9v032_aegc_controls); ++i) | |
| 1095 | + v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_aegc_controls[i], | |
| 1096 | + NULL); | |
| 1097 | + | |
| 1018 | 1098 | v4l2_ctrl_cluster(2, &mt9v032->test_pattern); |
| 1019 | 1099 | |
| 1020 | 1100 | mt9v032->pixel_rate = |
| @@ -1103,6 +1183,67 @@ static int mt9v032_remove(struct i2c_client *client) · 82 unmodified lines | ||
| 1103 | 1183 | return 0; |
| 1104 | 1184 | } |
| 1105 | 1185 | |
| 1186 | +static const struct mt9v032_model_data mt9v032_model_data[] = { | |
| 1187 | + { | |
| 1188 | + /* MT9V022, MT9V032 revisions 1/2/3 */ | |
| 1189 | + .min_row_time = 660, | |
| 1190 | + .min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN, | |
| 1191 | + .min_vblank = MT9V032_VERTICAL_BLANKING_MIN, | |
| 1192 | + .max_vblank = MT9V032_VERTICAL_BLANKING_MAX, | |
| 1193 | + .min_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MIN, | |
| 1194 | + .max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX, | |
| 1195 | + .pclk_reg = MT9V032_PIXEL_CLOCK, | |
| 1196 | + .aec_max_shutter_reg = MT9V032_AEC_MAX_SHUTTER_WIDTH, | |
| 1197 | + .aec_max_shutter_v4l2_ctrl = &mt9v032_aec_max_shutter_width, | |
| 1198 | + }, { | |
| 1199 | + /* MT9V024, MT9V034 */ | |
| 1200 | + .min_row_time = 690, | |
| 1201 | + .min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN, | |
| 1202 | + .min_vblank = MT9V034_VERTICAL_BLANKING_MIN, | |
| 1203 | + .max_vblank = MT9V034_VERTICAL_BLANKING_MAX, | |
| 1204 | + .min_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MIN, | |
| 1205 | + .max_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MAX, | |
| 1206 | + .pclk_reg = MT9V034_PIXEL_CLOCK, | |
| 1207 | + .aec_max_shutter_reg = MT9V034_AEC_MAX_SHUTTER_WIDTH, | |
| 1208 | + .aec_max_shutter_v4l2_ctrl = &mt9v034_aec_max_shutter_width, | |
| 1209 | + }, | |
| 1210 | +}; | |
| 1211 | + | |
| 1212 | +static const struct mt9v032_model_info mt9v032_models[] = { | |
| 1213 | + [MT9V032_MODEL_V022_COLOR] = { | |
| 1214 | + .data = &mt9v032_model_data[0], | |
| 1215 | + .color = true, | |
| 1216 | + }, | |
| 1217 | + [MT9V032_MODEL_V022_MONO] = { | |
| 1218 | + .data = &mt9v032_model_data[0], | |
| 1219 | + .color = false, | |
| 1220 | + }, | |
| 1221 | + [MT9V032_MODEL_V024_COLOR] = { | |
| 1222 | + .data = &mt9v032_model_data[1], | |
| 1223 | + .color = true, | |
| 1224 | + }, | |
| 1225 | + [MT9V032_MODEL_V024_MONO] = { | |
| 1226 | + .data = &mt9v032_model_data[1], | |
| 1227 | + .color = false, | |
| 1228 | + }, | |
| 1229 | + [MT9V032_MODEL_V032_COLOR] = { | |
| 1230 | + .data = &mt9v032_model_data[0], | |
| 1231 | + .color = true, | |
| 1232 | + }, | |
| 1233 | + [MT9V032_MODEL_V032_MONO] = { | |
| 1234 | + .data = &mt9v032_model_data[0], | |
| 1235 | + .color = false, | |
| 1236 | + }, | |
| 1237 | + [MT9V032_MODEL_V034_COLOR] = { | |
| 1238 | + .data = &mt9v032_model_data[1], | |
| 1239 | + .color = true, | |
| 1240 | + }, | |
| 1241 | + [MT9V032_MODEL_V034_MONO] = { | |
| 1242 | + .data = &mt9v032_model_data[1], | |
| 1243 | + .color = false, | |
| 1244 | + }, | |
| 1245 | +}; | |
| 1246 | + | |
| 1106 | 1247 | static const struct i2c_device_id mt9v032_id[] = { |
| 1107 | 1248 | { "mt9v022", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_COLOR] }, |
| 1108 | 1249 | { "mt9v022m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_MONO] }, |
| @@ -1585,13 +1585,6 @@ static const struct v4l2_ctrl_ops saa711x_ctrl_ops = { · 1584 unmodified lines | ||
| 1585 | 1585 | |
| 1586 | 1586 | static const struct v4l2_subdev_core_ops saa711x_core_ops = { |
| 1587 | 1587 | .log_status = saa711x_log_status, |
| 1588 | − .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | |
| 1589 | − .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | |
| 1590 | − .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | |
| 1591 | − .g_ctrl = v4l2_subdev_g_ctrl, | |
| 1592 | − .s_ctrl = v4l2_subdev_s_ctrl, | |
| 1593 | − .queryctrl = v4l2_subdev_queryctrl, | |
| 1594 | − .querymenu = v4l2_subdev_querymenu, | |
| 1595 | 1588 | .reset = saa711x_reset, |
| 1596 | 1589 | .s_gpio = saa711x_s_gpio, |
| 1597 | 1590 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| @@ -3044,10 +3044,8 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) · 3043 unmodified lines | ||
| 3044 | 3044 | pdata->op_sys_clock = devm_kcalloc( |
| 3045 | 3045 | dev, bus_cfg->nr_of_link_frequencies + 1 /* guardian */, |
| 3046 | 3046 | sizeof(*pdata->op_sys_clock), GFP_KERNEL); |
| 3047 | − if (!pdata->op_sys_clock) { | |
| 3048 | − rval = -ENOMEM; | |
| 3047 | + if (!pdata->op_sys_clock) | |
| 3049 | 3048 | goto out_err; |
| 3050 | − } | |
| 3051 | 3049 | |
| 3052 | 3050 | for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) { |
| 3053 | 3051 | pdata->op_sys_clock[i] = bus_cfg->link_frequencies[i]; |
| @@ -89,8 +89,6 @@ struct tc358743_state { · 88 unmodified lines | ||
| 89 | 89 | struct v4l2_ctrl *audio_sampling_rate_ctrl; |
| 90 | 90 | struct v4l2_ctrl *audio_present_ctrl; |
| 91 | 91 | |
| 92 | − /* work queues */ | |
| 93 | − struct workqueue_struct *work_queues; | |
| 94 | 92 | struct delayed_work delayed_work_enable_hotplug; |
| 95 | 93 | |
| 96 | 94 | /* edid */ |
| @@ -425,8 +423,7 @@ static void tc358743_enable_edid(struct v4l2_subdev *sd) · 328 unmodified lines | ||
| 425 | 423 | |
| 426 | 424 | /* Enable hotplug after 100 ms. DDC access to EDID is also enabled when |
| 427 | 425 | * hotplug is enabled. See register DDC_CTL */ |
| 428 | − queue_delayed_work(state->work_queues, | |
| 429 | − &state->delayed_work_enable_hotplug, HZ / 10); | |
| 426 | + schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10); | |
| 430 | 427 | |
| 431 | 428 | tc358743_enable_interrupts(sd, true); |
| 432 | 429 | tc358743_s_ctrl_detect_tx_5v(sd); |
| @@ -1884,14 +1881,6 @@ static int tc358743_probe(struct i2c_client *client, · 1451 unmodified lines | ||
| 1884 | 1881 | goto err_hdl; |
| 1885 | 1882 | } |
| 1886 | 1883 | |
| 1887 | − /* work queues */ | |
| 1888 | − state->work_queues = create_singlethread_workqueue(client->name); | |
| 1889 | − if (!state->work_queues) { | |
| 1890 | − v4l2_err(sd, "Could not create work queue\n"); | |
| 1891 | − err = -ENOMEM; | |
| 1892 | − goto err_hdl; | |
| 1893 | − } | |
| 1894 | − | |
| 1895 | 1884 | state->pad.flags = MEDIA_PAD_FL_SOURCE; |
| 1896 | 1885 | err = media_entity_pads_init(&sd->entity, 1, &state->pad); |
| 1897 | 1886 | if (err < 0) |
| @@ -1940,7 +1929,6 @@ static int tc358743_probe(struct i2c_client *client, · 42 unmodified lines | ||
| 1940 | 1929 | |
| 1941 | 1930 | err_work_queues: |
| 1942 | 1931 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
| 1943 | − destroy_workqueue(state->work_queues); | |
| 1944 | 1932 | mutex_destroy(&state->confctl_mutex); |
| 1945 | 1933 | err_hdl: |
| 1946 | 1934 | media_entity_cleanup(&sd->entity); |
| @@ -1954,7 +1942,6 @@ static int tc358743_remove(struct i2c_client *client) · 7 unmodified lines | ||
| 1954 | 1942 | struct tc358743_state *state = to_state(sd); |
| 1955 | 1943 | |
| 1956 | 1944 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
| 1957 | − destroy_workqueue(state->work_queues); | |
| 1958 | 1945 | v4l2_async_unregister_subdev(sd); |
| 1959 | 1946 | v4l2_device_unregister_subdev(sd); |
| 1960 | 1947 | mutex_destroy(&state->confctl_mutex); |
| @@ -1855,13 +1855,6 @@ static const struct v4l2_ctrl_ops tvaudio_ctrl_ops = { · 1854 unmodified lines | ||
| 1855 | 1855 | |
| 1856 | 1856 | static const struct v4l2_subdev_core_ops tvaudio_core_ops = { |
| 1857 | 1857 | .log_status = tvaudio_log_status, |
| 1858 | − .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | |
| 1859 | − .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | |
| 1860 | − .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | |
| 1861 | − .g_ctrl = v4l2_subdev_g_ctrl, | |
| 1862 | − .s_ctrl = v4l2_subdev_s_ctrl, | |
| 1863 | − .queryctrl = v4l2_subdev_queryctrl, | |
| 1864 | − .querymenu = v4l2_subdev_querymenu, | |
| 1865 | 1858 | }; |
| 1866 | 1859 | |
| 1867 | 1860 | static const struct v4l2_subdev_tuner_ops tvaudio_tuner_ops = { |
| @@ -178,13 +178,6 @@ static const struct v4l2_ctrl_ops wm8775_ctrl_ops = { · 177 unmodified lines | ||
| 178 | 178 | |
| 179 | 179 | static const struct v4l2_subdev_core_ops wm8775_core_ops = { |
| 180 | 180 | .log_status = wm8775_log_status, |
| 181 | − .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | |
| 182 | − .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | |
| 183 | − .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | |
| 184 | − .g_ctrl = v4l2_subdev_g_ctrl, | |
| 185 | − .s_ctrl = v4l2_subdev_s_ctrl, | |
| 186 | − .queryctrl = v4l2_subdev_queryctrl, | |
| 187 | − .querymenu = v4l2_subdev_querymenu, | |
| 188 | 181 | }; |
| 189 | 182 | |
| 190 | 183 | static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = { |
| @@ -423,7 +423,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, · 422 unmodified lines | ||
| 423 | 423 | unsigned long arg) |
| 424 | 424 | { |
| 425 | 425 | struct media_devnode *devnode = media_devnode_data(filp); |
| 426 | − struct media_device *dev = to_media_device(devnode); | |
| 426 | + struct media_device *dev = devnode->media_dev; | |
| 427 | 427 | long ret; |
| 428 | 428 | |
| 429 | 429 | mutex_lock(&dev->graph_mutex); |
| @@ -495,7 +495,7 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd, · 65 unmodified lines | ||
| 495 | 495 | unsigned long arg) |
| 496 | 496 | { |
| 497 | 497 | struct media_devnode *devnode = media_devnode_data(filp); |
| 498 | − struct media_device *dev = to_media_device(devnode); | |
| 498 | + struct media_device *dev = devnode->media_dev; | |
| 499 | 499 | long ret; |
| 500 | 500 | |
| 501 | 501 | switch (cmd) { |
| @@ -531,7 +531,8 @@ static const struct media_file_operations media_device_fops = { · 29 unmodified lines | ||
| 531 | 531 | static ssize_t show_model(struct device *cd, |
| 532 | 532 | struct device_attribute *attr, char *buf) |
| 533 | 533 | { |
| 534 | − struct media_device *mdev = to_media_device(to_media_devnode(cd)); | |
| 534 | + struct media_devnode *devnode = to_media_devnode(cd); | |
| 535 | + struct media_device *mdev = devnode->media_dev; | |
| 535 | 536 | |
| 536 | 537 | return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); |
| 537 | 538 | } |
| @@ -704,23 +705,35 @@ EXPORT_SYMBOL_GPL(media_device_cleanup); · 166 unmodified lines | ||
| 704 | 705 | int __must_check __media_device_register(struct media_device *mdev, |
| 705 | 706 | struct module *owner) |
| 706 | 707 | { |
| 708 | + struct media_devnode *devnode; | |
| 707 | 709 | int ret; |
| 708 | 710 | |
| 711 | + devnode = kzalloc(sizeof(*devnode), GFP_KERNEL); | |
| 712 | + if (!devnode) | |
| 713 | + return -ENOMEM; | |
| 714 | + | |
| 709 | 715 | /* Register the device node. */ |
| 710 | − mdev->devnode.fops = &media_device_fops; | |
| 711 | − mdev->devnode.parent = mdev->dev; | |
| 712 | − mdev->devnode.release = media_device_release; | |
| 716 | + mdev->devnode = devnode; | |
| 717 | + devnode->fops = &media_device_fops; | |
| 718 | + devnode->parent = mdev->dev; | |
| 719 | + devnode->release = media_device_release; | |
| 713 | 720 | |
| 714 | 721 | /* Set version 0 to indicate user-space that the graph is static */ |
| 715 | 722 | mdev->topology_version = 0; |
| 716 | 723 | |
| 717 | − ret = media_devnode_register(&mdev->devnode, owner); | |
| 718 | − if (ret < 0) | |
| 724 | + ret = media_devnode_register(mdev, devnode, owner); | |
| 725 | + if (ret < 0) { | |
| 726 | + /* devnode free is handled in media_devnode_*() */ | |
| 727 | + mdev->devnode = NULL; | |
| 719 | 728 | return ret; |
| 729 | + } | |
| 720 | 730 | |
| 721 | − ret = device_create_file(&mdev->devnode.dev, &dev_attr_model); | |
| 731 | + ret = device_create_file(&devnode->dev, &dev_attr_model); | |
| 722 | 732 | if (ret < 0) { |
| 723 | − media_devnode_unregister(&mdev->devnode); | |
| 733 | + /* devnode free is handled in media_devnode_*() */ | |
| 734 | + mdev->devnode = NULL; | |
| 735 | + media_devnode_unregister_prepare(devnode); | |
| 736 | + media_devnode_unregister(devnode); | |
| 724 | 737 | return ret; |
| 725 | 738 | } |
| 726 | 739 | |
| @@ -771,11 +784,14 @@ void media_device_unregister(struct media_device *mdev) · 44 unmodified lines | ||
| 771 | 784 | mutex_lock(&mdev->graph_mutex); |
| 772 | 785 | |
| 773 | 786 | /* Check if mdev was ever registered at all */ |
| 774 | − if (!media_devnode_is_registered(&mdev->devnode)) { | |
| 787 | + if (!media_devnode_is_registered(mdev->devnode)) { | |
| 775 | 788 | mutex_unlock(&mdev->graph_mutex); |
| 776 | 789 | return; |
| 777 | 790 | } |
| 778 | 791 | |
| 792 | + /* Clear the devnode register bit to avoid races with media dev open */ | |
| 793 | + media_devnode_unregister_prepare(mdev->devnode); | |
| 794 | + | |
| 779 | 795 | /* Remove all entities from the media device */ |
| 780 | 796 | list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) |
| 781 | 797 | __media_device_unregister_entity(entity); |
| @@ -794,9 +810,12 @@ void media_device_unregister(struct media_device *mdev) · 12 unmodified lines | ||
| 794 | 810 | |
| 795 | 811 | mutex_unlock(&mdev->graph_mutex); |
| 796 | 812 | |
| 797 | − device_remove_file(&mdev->devnode.dev, &dev_attr_model); | |
| 798 | − dev_dbg(mdev->dev, "Media device unregistering\n"); | |
| 799 | − media_devnode_unregister(&mdev->devnode); | |
| 813 | + dev_dbg(mdev->dev, "Media device unregistered\n"); | |
| 814 | + | |
| 815 | + device_remove_file(&mdev->devnode->dev, &dev_attr_model); | |
| 816 | + media_devnode_unregister(mdev->devnode); | |
| 817 | + /* devnode free is handled in media_devnode_*() */ | |
| 818 | + mdev->devnode = NULL; | |
| 800 | 819 | } |
| 801 | 820 | EXPORT_SYMBOL_GPL(media_device_unregister); |
| 802 | 821 | |
| @@ -44,6 +44,7 @@ · 43 unmodified lines | ||
| 44 | 44 | #include <linux/uaccess.h> |
| 45 | 45 | |
| 46 | 46 | #include <media/media-devnode.h> |
| 47 | +#include <media/media-device.h> | |
| 47 | 48 | |
| 48 | 49 | #define MEDIA_NUM_DEVICES 256 |
| 49 | 50 | #define MEDIA_NAME "media" |
| @@ -59,21 +60,19 @@ static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES); · 9 unmodified lines | ||
| 59 | 60 | /* Called when the last user of the media device exits. */ |
| 60 | 61 | static void media_devnode_release(struct device *cd) |
| 61 | 62 | { |
| 62 | − struct media_devnode *mdev = to_media_devnode(cd); | |
| 63 | + struct media_devnode *devnode = to_media_devnode(cd); | |
| 63 | 64 | |
| 64 | 65 | mutex_lock(&media_devnode_lock); |
| 65 | − | |
| 66 | − /* Delete the cdev on this minor as well */ | |
| 67 | − cdev_del(&mdev->cdev); | |
| 68 | − | |
| 69 | 66 | /* Mark device node number as free */ |
| 70 | − clear_bit(mdev->minor, media_devnode_nums); | |
| 71 | − | |
| 67 | + clear_bit(devnode->minor, media_devnode_nums); | |
| 72 | 68 | mutex_unlock(&media_devnode_lock); |
| 73 | 69 | |
| 74 | 70 | /* Release media_devnode and perform other cleanups as needed. */ |
| 75 | − if (mdev->release) | |
| 76 | − mdev->release(mdev); | |
| 71 | + if (devnode->release) | |
| 72 | + devnode->release(devnode); | |
| 73 | + | |
| 74 | + kfree(devnode); | |
| 75 | + pr_debug("%s: Media Devnode Deallocated\n", __func__); | |
| 77 | 76 | } |
| 78 | 77 | |
| 79 | 78 | static struct bus_type media_bus_type = { |
| @@ -83,37 +82,37 @@ static struct bus_type media_bus_type = { · 3 unmodified lines | ||
| 83 | 82 | static ssize_t media_read(struct file *filp, char __user *buf, |
| 84 | 83 | size_t sz, loff_t *off) |
| 85 | 84 | { |
| 86 | − struct media_devnode *mdev = media_devnode_data(filp); | |
| 85 | + struct media_devnode *devnode = media_devnode_data(filp); | |
| 87 | 86 | |
| 88 | − if (!mdev->fops->read) | |
| 87 | + if (!devnode->fops->read) | |
| 89 | 88 | return -EINVAL; |
| 90 | − if (!media_devnode_is_registered(mdev)) | |
| 89 | + if (!media_devnode_is_registered(devnode)) | |
| 91 | 90 | return -EIO; |
| 92 | − return mdev->fops->read(filp, buf, sz, off); | |
| 91 | + return devnode->fops->read(filp, buf, sz, off); | |
| 93 | 92 | } |
| 94 | 93 | |
| 95 | 94 | static ssize_t media_write(struct file *filp, const char __user *buf, |
| 96 | 95 | size_t sz, loff_t *off) |
| 97 | 96 | { |
| 98 | − struct media_devnode *mdev = media_devnode_data(filp); | |
| 97 | + struct media_devnode *devnode = media_devnode_data(filp); | |
| 99 | 98 | |
| 100 | − if (!mdev->fops->write) | |
| 99 | + if (!devnode->fops->write) | |
| 101 | 100 | return -EINVAL; |
| 102 | − if (!media_devnode_is_registered(mdev)) | |
| 101 | + if (!media_devnode_is_registered(devnode)) | |
| 103 | 102 | return -EIO; |
| 104 | − return mdev->fops->write(filp, buf, sz, off); | |
| 103 | + return devnode->fops->write(filp, buf, sz, off); | |
| 105 | 104 | } |
| 106 | 105 | |
| 107 | 106 | static unsigned int media_poll(struct file *filp, |
| 108 | 107 | struct poll_table_struct *poll) |
| 109 | 108 | { |
| 110 | − struct media_devnode *mdev = media_devnode_data(filp); | |
| 109 | + struct media_devnode *devnode = media_devnode_data(filp); | |
| 111 | 110 | |
| 112 | − if (!media_devnode_is_registered(mdev)) | |
| 111 | + if (!media_devnode_is_registered(devnode)) | |
| 113 | 112 | return POLLERR | POLLHUP; |
| 114 | − if (!mdev->fops->poll) | |
| 113 | + if (!devnode->fops->poll) | |
| 115 | 114 | return DEFAULT_POLLMASK; |
| 116 | − return mdev->fops->poll(filp, poll); | |
| 115 | + return devnode->fops->poll(filp, poll); | |
| 117 | 116 | } |
| 118 | 117 | |
| 119 | 118 | static long |
| @@ -121,12 +120,12 @@ __media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, · 1 unmodified line | ||
| 121 | 120 | long (*ioctl_func)(struct file *filp, unsigned int cmd, |
| 122 | 121 | unsigned long arg)) |
| 123 | 122 | { |
| 124 | − struct media_devnode *mdev = media_devnode_data(filp); | |
| 123 | + struct media_devnode *devnode = media_devnode_data(filp); | |
| 125 | 124 | |
| 126 | 125 | if (!ioctl_func) |
| 127 | 126 | return -ENOTTY; |
| 128 | 127 | |
| 129 | − if (!media_devnode_is_registered(mdev)) | |
| 128 | + if (!media_devnode_is_registered(devnode)) | |
| 130 | 129 | return -EIO; |
| 131 | 130 | |
| 132 | 131 | return ioctl_func(filp, cmd, arg); |
| @@ -134,9 +133,9 @@ __media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, · 1 unmodified line | ||
| 134 | 133 | |
| 135 | 134 | static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
| 136 | 135 | { |
| 137 | − struct media_devnode *mdev = media_devnode_data(filp); | |
| 136 | + struct media_devnode *devnode = media_devnode_data(filp); | |
| 138 | 137 | |
| 139 | − return __media_ioctl(filp, cmd, arg, mdev->fops->ioctl); | |
| 138 | + return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl); | |
| 140 | 139 | } |
| 141 | 140 | |
| 142 | 141 | #ifdef CONFIG_COMPAT |
| @@ -144,9 +143,9 @@ static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 1 unmodified line | ||
| 144 | 143 | static long media_compat_ioctl(struct file *filp, unsigned int cmd, |
| 145 | 144 | unsigned long arg) |
| 146 | 145 | { |
| 147 | − struct media_devnode *mdev = media_devnode_data(filp); | |
| 146 | + struct media_devnode *devnode = media_devnode_data(filp); | |
| 148 | 147 | |
| 149 | − return __media_ioctl(filp, cmd, arg, mdev->fops->compat_ioctl); | |
| 148 | + return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl); | |
| 150 | 149 | } |
| 151 | 150 | |
| 152 | 151 | #endif /* CONFIG_COMPAT */ |
| @@ -154,7 +153,7 @@ static long media_compat_ioctl(struct file *filp, unsigned int cmd, · 1 unmodified line | ||
| 154 | 153 | /* Override for the open function */ |
| 155 | 154 | static int media_open(struct inode *inode, struct file *filp) |
| 156 | 155 | { |
| 157 | − struct media_devnode *mdev; | |
| 156 | + struct media_devnode *devnode; | |
| 158 | 157 | int ret; |
| 159 | 158 | |
| 160 | 159 | /* Check if the media device is available. This needs to be done with |
| @@ -164,23 +163,23 @@ static int media_open(struct inode *inode, struct file *filp) · 3 unmodified lines | ||
| 164 | 163 | * a crash. |
| 165 | 164 | */ |
| 166 | 165 | mutex_lock(&media_devnode_lock); |
| 167 | − mdev = container_of(inode->i_cdev, struct media_devnode, cdev); | |
| 166 | + devnode = container_of(inode->i_cdev, struct media_devnode, cdev); | |
| 168 | 167 | /* return ENXIO if the media device has been removed |
| 169 | 168 | already or if it is not registered anymore. */ |
| 170 | − if (!media_devnode_is_registered(mdev)) { | |
| 169 | + if (!media_devnode_is_registered(devnode)) { | |
| 171 | 170 | mutex_unlock(&media_devnode_lock); |
| 172 | 171 | return -ENXIO; |
| 173 | 172 | } |
| 174 | 173 | /* and increase the device refcount */ |
| 175 | − get_device(&mdev->dev); | |
| 174 | + get_device(&devnode->dev); | |
| 176 | 175 | mutex_unlock(&media_devnode_lock); |
| 177 | 176 | |
| 178 | − filp->private_data = mdev; | |
| 177 | + filp->private_data = devnode; | |
| 179 | 178 | |
| 180 | − if (mdev->fops->open) { | |
| 181 | − ret = mdev->fops->open(filp); | |
| 179 | + if (devnode->fops->open) { | |
| 180 | + ret = devnode->fops->open(filp); | |
| 182 | 181 | if (ret) { |
| 183 | − put_device(&mdev->dev); | |
| 182 | + put_device(&devnode->dev); | |
| 184 | 183 | filp->private_data = NULL; |
| 185 | 184 | return ret; |
| 186 | 185 | } |
| @@ -192,16 +191,18 @@ static int media_open(struct inode *inode, struct file *filp) · 5 unmodified lines | ||
| 192 | 191 | /* Override for the release function */ |
| 193 | 192 | static int media_release(struct inode *inode, struct file *filp) |
| 194 | 193 | { |
| 195 | − struct media_devnode *mdev = media_devnode_data(filp); | |
| 194 | + struct media_devnode *devnode = media_devnode_data(filp); | |
| 196 | 195 | |
| 197 | − if (mdev->fops->release) | |
| 198 | − mdev->fops->release(filp); | |
| 196 | + if (devnode->fops->release) | |
| 197 | + devnode->fops->release(filp); | |
| 199 | 198 | |
| 200 | 199 | filp->private_data = NULL; |
| 201 | 200 | |
| 202 | 201 | /* decrease the refcount unconditionally since the release() |
| 203 | 202 | return value is ignored. */ |
| 204 | − put_device(&mdev->dev); | |
| 203 | + put_device(&devnode->dev); | |
| 204 | + | |
| 205 | + pr_debug("%s: Media Release\n", __func__); | |
| 205 | 206 | return 0; |
| 206 | 207 | } |
| 207 | 208 | |
| @@ -219,7 +220,8 @@ static const struct file_operations media_devnode_fops = { · 11 unmodified lines | ||
| 219 | 220 | .llseek = no_llseek, |
| 220 | 221 | }; |
| 221 | 222 | |
| 222 | −int __must_check media_devnode_register(struct media_devnode *mdev, | |
| 223 | +int __must_check media_devnode_register(struct media_device *mdev, | |
| 224 | + struct media_devnode *devnode, | |
| 223 | 225 | struct module *owner) |
| 224 | 226 | { |
| 225 | 227 | int minor; |
| @@ -231,61 +233,80 @@ int __must_check media_devnode_register(struct media_devnode *mdev, · 5 unmodified lines | ||
| 231 | 233 | if (minor == MEDIA_NUM_DEVICES) { |
| 232 | 234 | mutex_unlock(&media_devnode_lock); |
| 233 | 235 | pr_err("could not get a free minor\n"); |
| 236 | + kfree(devnode); | |
| 234 | 237 | return -ENFILE; |
| 235 | 238 | } |
| 236 | 239 | |
| 237 | 240 | set_bit(minor, media_devnode_nums); |
| 238 | 241 | mutex_unlock(&media_devnode_lock); |
| 239 | 242 | |
| 240 | − mdev->minor = minor; | |
| 243 | + devnode->minor = minor; | |
| 244 | + devnode->media_dev = mdev; | |
| 245 | + | |
| 246 | + /* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */ | |
| 247 | + devnode->dev.bus = &media_bus_type; | |
| 248 | + devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor); | |
| 249 | + devnode->dev.release = media_devnode_release; | |
| 250 | + if (devnode->parent) | |
| 251 | + devnode->dev.parent = devnode->parent; | |
| 252 | + dev_set_name(&devnode->dev, "media%d", devnode->minor); | |
| 253 | + device_initialize(&devnode->dev); | |
| 241 | 254 | |
| 242 | 255 | /* Part 2: Initialize and register the character device */ |
| 243 | − cdev_init(&mdev->cdev, &media_devnode_fops); | |
| 244 | − mdev->cdev.owner = owner; | |
| 256 | + cdev_init(&devnode->cdev, &media_devnode_fops); | |
| 257 | + devnode->cdev.owner = owner; | |
| 258 | + devnode->cdev.kobj.parent = &devnode->dev.kobj; | |
| 245 | 259 | |
| 246 | − ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1); | |
| 260 | + ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), devnode->minor), 1); | |
| 247 | 261 | if (ret < 0) { |
| 248 | 262 | pr_err("%s: cdev_add failed\n", __func__); |
| 249 | − goto error; | |
| 263 | + goto cdev_add_error; | |
| 250 | 264 | } |
| 251 | 265 | |
| 252 | − /* Part 3: Register the media device */ | |
| 253 | − mdev->dev.bus = &media_bus_type; | |
| 254 | − mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor); | |
| 255 | − mdev->dev.release = media_devnode_release; | |
| 256 | − if (mdev->parent) | |
| 257 | − mdev->dev.parent = mdev->parent; | |
| 258 | − dev_set_name(&mdev->dev, "media%d", mdev->minor); | |
| 259 | − ret = device_register(&mdev->dev); | |
| 266 | + /* Part 3: Add the media device */ | |
| 267 | + ret = device_add(&devnode->dev); | |
| 260 | 268 | if (ret < 0) { |
| 261 | − pr_err("%s: device_register failed\n", __func__); | |
| 262 | − goto error; | |
| 269 | + pr_err("%s: device_add failed\n", __func__); | |
| 270 | + goto device_add_error; | |
| 263 | 271 | } |
| 264 | 272 | |
| 265 | 273 | /* Part 4: Activate this minor. The char device can now be used. */ |
| 266 | − set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); | |
| 274 | + set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); | |
| 267 | 275 | |
| 268 | 276 | return 0; |
| 269 | 277 | |
| 270 | −error: | |
| 278 | +device_add_error: | |
| 279 | + cdev_del(&devnode->cdev); | |
| 280 | +cdev_add_error: | |
| 271 | 281 | mutex_lock(&media_devnode_lock); |
| 272 | − cdev_del(&mdev->cdev); | |
| 273 | − clear_bit(mdev->minor, media_devnode_nums); | |
| 282 | + clear_bit(devnode->minor, media_devnode_nums); | |
| 283 | + devnode->media_dev = NULL; | |
| 274 | 284 | mutex_unlock(&media_devnode_lock); |
| 275 | 285 | |
| 286 | + put_device(&devnode->dev); | |
| 276 | 287 | return ret; |
| 277 | 288 | } |
| 278 | 289 | |
| 279 | −void media_devnode_unregister(struct media_devnode *mdev) | |
| 290 | +void media_devnode_unregister_prepare(struct media_devnode *devnode) | |
| 280 | 291 | { |
| 281 | − /* Check if mdev was ever registered at all */ | |
| 282 | − if (!media_devnode_is_registered(mdev)) | |
| 292 | + /* Check if devnode was ever registered at all */ | |
| 293 | + if (!media_devnode_is_registered(devnode)) | |
| 283 | 294 | return; |
| 284 | 295 | |
| 285 | 296 | mutex_lock(&media_devnode_lock); |
| 286 | − clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); | |
| 297 | + clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); | |
| 298 | + mutex_unlock(&media_devnode_lock); | |
| 299 | +} | |
| 300 | + | |
| 301 | +void media_devnode_unregister(struct media_devnode *devnode) | |
| 302 | +{ | |
| 303 | + mutex_lock(&media_devnode_lock); | |
| 304 | + /* Delete the cdev on this minor as well */ | |
| 305 | + cdev_del(&devnode->cdev); | |
| 287 | 306 | mutex_unlock(&media_devnode_lock); |
| 288 | − device_unregister(&mdev->dev); | |
| 307 | + device_del(&devnode->dev); | |
| 308 | + devnode->media_dev = NULL; | |
| 309 | + put_device(&devnode->dev); | |
| 289 | 310 | } |
| 290 | 311 | |
| 291 | 312 | /* |
| @@ -655,7 +655,6 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct · 654 unmodified lines | ||
| 655 | 655 | static int dst_ca_open(struct inode *inode, struct file *file) |
| 656 | 656 | { |
| 657 | 657 | dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file); |
| 658 | − try_module_get(THIS_MODULE); | |
| 659 | 658 | |
| 660 | 659 | return 0; |
| 661 | 660 | } |
| @@ -663,7 +662,6 @@ static int dst_ca_open(struct inode *inode, struct file *file) · 1 unmodified line | ||
| 663 | 662 | static int dst_ca_release(struct inode *inode, struct file *file) |
| 664 | 663 | { |
| 665 | 664 | dprintk(verbose, DST_CA_DEBUG, 1, " Device closed."); |
| 666 | − module_put(THIS_MODULE); | |
| 667 | 665 | |
| 668 | 666 | return 0; |
| 669 | 667 | } |
| @@ -492,7 +492,6 @@ static int cobalt_subdevs_init(struct cobalt *cobalt) · 491 unmodified lines | ||
| 492 | 492 | .ain_sel = ADV7604_AIN7_8_9_NC_SYNC_3_1, |
| 493 | 493 | .bus_order = ADV7604_BUS_ORDER_BRG, |
| 494 | 494 | .blank_data = 1, |
| 495 | − .op_656_range = 1, | |
| 496 | 495 | .op_format_mode_sel = ADV7604_OP_FORMAT_MODE0, |
| 497 | 496 | .int1_config = ADV76XX_INT1_CONFIG_ACTIVE_HIGH, |
| 498 | 497 | .dr_str_data = ADV76XX_DR_STR_HIGH, |
| @@ -571,7 +570,6 @@ static int cobalt_subdevs_hsma_init(struct cobalt *cobalt) · 72 unmodified lines | ||
| 571 | 570 | .bus_order = ADV7842_BUS_ORDER_RBG, |
| 572 | 571 | .op_format_mode_sel = ADV7842_OP_FORMAT_MODE0, |
| 573 | 572 | .blank_data = 1, |
| 574 | − .op_656_range = 1, | |
| 575 | 573 | .dr_str_data = 3, |
| 576 | 574 | .dr_str_clk = 3, |
| 577 | 575 | .dr_str_sync = 3, |
| @@ -691,17 +689,10 @@ static int cobalt_probe(struct pci_dev *pci_dev, · 113 unmodified lines | ||
| 691 | 689 | cobalt->pci_dev = pci_dev; |
| 692 | 690 | cobalt->instance = i; |
| 693 | 691 | |
| 694 | − cobalt->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); | |
| 695 | − if (IS_ERR(cobalt->alloc_ctx)) { | |
| 696 | − kfree(cobalt); | |
| 697 | − return -ENOMEM; | |
| 698 | − } | |
| 699 | − | |
| 700 | 692 | retval = v4l2_device_register(&pci_dev->dev, &cobalt->v4l2_dev); |
| 701 | 693 | if (retval) { |
| 702 | 694 | pr_err("cobalt: v4l2_device_register of card %d failed\n", |
| 703 | 695 | cobalt->instance); |
| 704 | − vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx); | |
| 705 | 696 | kfree(cobalt); |
| 706 | 697 | return retval; |
| 707 | 698 | } |
| @@ -782,7 +773,6 @@ err: · 74 unmodified lines | ||
| 782 | 773 | cobalt_err("error %d on initialization\n", retval); |
| 783 | 774 | |
| 784 | 775 | v4l2_device_unregister(&cobalt->v4l2_dev); |
| 785 | − vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx); | |
| 786 | 776 | kfree(cobalt); |
| 787 | 777 | return retval; |
| 788 | 778 | } |
| @@ -818,7 +808,6 @@ static void cobalt_remove(struct pci_dev *pci_dev) · 29 unmodified lines | ||
| 818 | 808 | cobalt_info("removed cobalt card\n"); |
| 819 | 809 | |
| 820 | 810 | v4l2_device_unregister(v4l2_dev); |
| 821 | − vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx); | |
| 822 | 811 | kfree(cobalt); |
| 823 | 812 | } |
| 824 | 813 | |
| @@ -262,7 +262,6 @@ struct cobalt { · 261 unmodified lines | ||
| 262 | 262 | int instance; |
| 263 | 263 | struct pci_dev *pci_dev; |
| 264 | 264 | struct v4l2_device v4l2_dev; |
| 265 | − void *alloc_ctx; | |
| 266 | 265 | |
| 267 | 266 | void __iomem *bar0, *bar1; |
| 268 | 267 | |
| @@ -45,7 +45,7 @@ static const struct v4l2_dv_timings cea1080p60 = V4L2_DV_BT_CEA_1920X1080P60; · 44 unmodified lines | ||
| 45 | 45 | |
| 46 | 46 | static int cobalt_queue_setup(struct vb2_queue *q, |
| 47 | 47 | unsigned int *num_buffers, unsigned int *num_planes, |
| 48 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 48 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 49 | 49 | { |
| 50 | 50 | struct cobalt_stream *s = q->drv_priv; |
| 51 | 51 | unsigned size = s->stride * s->height; |
| @@ -54,7 +54,6 @@ static int cobalt_queue_setup(struct vb2_queue *q, · 2 unmodified lines | ||
| 54 | 54 | *num_buffers = 3; |
| 55 | 55 | if (*num_buffers > NR_BUFS) |
| 56 | 56 | *num_buffers = NR_BUFS; |
| 57 | − alloc_ctxs[0] = s->cobalt->alloc_ctx; | |
| 58 | 57 | if (*num_planes) |
| 59 | 58 | return sizes[0] < size ? -EINVAL : 0; |
| 60 | 59 | *num_planes = 1; |
| @@ -1224,6 +1223,7 @@ static int cobalt_node_register(struct cobalt *cobalt, int node) · 1163 unmodified lines | ||
| 1224 | 1223 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1225 | 1224 | q->min_buffers_needed = 2; |
| 1226 | 1225 | q->lock = &s->lock; |
| 1226 | + q->dev = &cobalt->pci_dev->dev; | |
| 1227 | 1227 | vdev->queue = q; |
| 1228 | 1228 | |
| 1229 | 1229 | video_set_drvdata(vdev, s); |
| @@ -93,7 +93,7 @@ static int snd_cx18_mixer_tv_vol_get(struct snd_kcontrol *kctl, · 92 unmodified lines | ||
| 93 | 93 | vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); |
| 94 | 94 | |
| 95 | 95 | snd_cx18_lock(cxsc); |
| 96 | − ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl); | |
| 96 | + ret = v4l2_g_ctrl(cx->sd_av->ctrl_handler, &vctrl); | |
| 97 | 97 | snd_cx18_unlock(cxsc); |
| 98 | 98 | |
| 99 | 99 | if (!ret) |
| @@ -115,14 +115,14 @@ static int snd_cx18_mixer_tv_vol_put(struct snd_kcontrol *kctl, · 15 unmodified lines | ||
| 115 | 115 | snd_cx18_lock(cxsc); |
| 116 | 116 | |
| 117 | 117 | /* Fetch current state */ |
| 118 | − ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl); | |
| 118 | + ret = v4l2_g_ctrl(cx->sd_av->ctrl_handler, &vctrl); | |
| 119 | 119 | |
| 120 | 120 | if (ret || |
| 121 | 121 | (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { |
| 122 | 122 | |
| 123 | 123 | /* Set, if needed */ |
| 124 | 124 | vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); |
| 125 | − ret = v4l2_subdev_call(cx->sd_av, core, s_ctrl, &vctrl); | |
| 125 | + ret = v4l2_s_ctrl(cx->sd_av->ctrl_handler, &vctrl); | |
| 126 | 126 | if (!ret) |
| 127 | 127 | ret = 1; /* Indicate control was changed w/o error */ |
| 128 | 128 | } |
| @@ -560,7 +560,7 @@ static void cx18_process_options(struct cx18 *cx) · 559 unmodified lines | ||
| 560 | 560 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize; |
| 561 | 561 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize; |
| 562 | 562 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize; |
| 563 | − cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_active_samples * 36; | |
| 563 | + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = VBI_ACTIVE_SAMPLES * 36; | |
| 564 | 564 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize; |
| 565 | 565 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */ |
| 566 | 566 | |
| @@ -492,9 +492,9 @@ struct cx18_card; · 491 unmodified lines | ||
| 492 | 492 | * (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line = |
| 493 | 493 | * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples |
| 494 | 494 | */ |
| 495 | −static const u32 vbi_active_samples = 1444; /* 4 byte SAV + 720 Y + 720 U/V */ | |
| 496 | −static const u32 vbi_hblank_samples_60Hz = 272; /* 4 byte EAV + 268 anc/fill */ | |
| 497 | −static const u32 vbi_hblank_samples_50Hz = 284; /* 4 byte EAV + 280 anc/fill */ | |
| 495 | +#define VBI_ACTIVE_SAMPLES 1444 /* 4 byte SAV + 720 Y + 720 U/V */ | |
| 496 | +#define VBI_HBLANK_SAMPLES_60HZ 272 /* 4 byte EAV + 268 anc/fill */ | |
| 497 | +#define VBI_HBLANK_SAMPLES_50HZ 284 /* 4 byte EAV + 280 anc/fill */ | |
| 498 | 498 | |
| 499 | 499 | #define CX18_VBI_FRAMES 32 |
| 500 | 500 | |
| @@ -177,7 +177,7 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, · 176 unmodified lines | ||
| 177 | 177 | |
| 178 | 178 | vbifmt->sampling_rate = 27000000; |
| 179 | 179 | vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */ |
| 180 | − vbifmt->samples_per_line = vbi_active_samples - 4; | |
| 180 | + vbifmt->samples_per_line = VBI_ACTIVE_SAMPLES - 4; | |
| 181 | 181 | vbifmt->sample_format = V4L2_PIX_FMT_GREY; |
| 182 | 182 | vbifmt->start[0] = cx->vbi.start[0]; |
| 183 | 183 | vbifmt->start[1] = cx->vbi.start[1]; |
| @@ -605,9 +605,9 @@ static void cx18_vbi_setup(struct cx18_stream *s) · 604 unmodified lines | ||
| 605 | 605 | /* Lines per field */ |
| 606 | 606 | data[1] = (lines / 2) | ((lines / 2) << 16); |
| 607 | 607 | /* bytes per line */ |
| 608 | − data[2] = (raw ? vbi_active_samples | |
| 609 | − : (cx->is_60hz ? vbi_hblank_samples_60Hz | |
| 610 | − : vbi_hblank_samples_50Hz)); | |
| 608 | + data[2] = (raw ? VBI_ACTIVE_SAMPLES | |
| 609 | + : (cx->is_60hz ? VBI_HBLANK_SAMPLES_60HZ | |
| 610 | + : VBI_HBLANK_SAMPLES_50HZ)); | |
| 611 | 611 | /* Every X number of frames a VBI interrupt arrives |
| 612 | 612 | (frames as in 25 or 30 fps) */ |
| 613 | 613 | data[3] = 1; |
| @@ -761,7 +761,7 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s) · 147 unmodified lines | ||
| 761 | 761 | s->bufs_per_mdl = 1; |
| 762 | 762 | if (cx18_raw_vbi(s->cx)) { |
| 763 | 763 | s->mdl_size = (s->cx->is_60hz ? 12 : 18) |
| 764 | − * 2 * vbi_active_samples; | |
| 764 | + * 2 * VBI_ACTIVE_SAMPLES; | |
| 765 | 765 | } else { |
| 766 | 766 | /* |
| 767 | 767 | * See comment in cx18_vbi_setup() below about the |
| @@ -769,8 +769,8 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s) · 1 unmodified line | ||
| 769 | 769 | * the lines on which EAV RP codes toggle. |
| 770 | 770 | */ |
| 771 | 771 | s->mdl_size = s->cx->is_60hz |
| 772 | − ? (21 - 4 + 1) * 2 * vbi_hblank_samples_60Hz | |
| 773 | − : (23 - 2 + 1) * 2 * vbi_hblank_samples_50Hz; | |
| 772 | + ? (21 - 4 + 1) * 2 * VBI_HBLANK_SAMPLES_60HZ | |
| 773 | + : (23 - 2 + 1) * 2 * VBI_HBLANK_SAMPLES_50HZ; | |
| 774 | 774 | } |
| 775 | 775 | break; |
| 776 | 776 | default: |
| @@ -108,7 +108,7 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) · 107 unmodified lines | ||
| 108 | 108 | /* FIXME - this function ignores the input size. */ |
| 109 | 109 | static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size) |
| 110 | 110 | { |
| 111 | − u32 line_size = vbi_active_samples; | |
| 111 | + u32 line_size = VBI_ACTIVE_SAMPLES; | |
| 112 | 112 | u32 lines = cx->vbi.count * 2; |
| 113 | 113 | u8 *q = buf; |
| 114 | 114 | u8 *p; |
| @@ -145,8 +145,8 @@ static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size, · 30 unmodified lines | ||
| 145 | 145 | struct v4l2_decode_vbi_line vbi; |
| 146 | 146 | int i; |
| 147 | 147 | u32 line = 0; |
| 148 | − u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz | |
| 149 | − : vbi_hblank_samples_50Hz; | |
| 148 | + u32 line_size = cx->is_60hz ? VBI_HBLANK_SAMPLES_60HZ | |
| 149 | + : VBI_HBLANK_SAMPLES_50HZ; | |
| 150 | 150 | |
| 151 | 151 | /* find the first valid line */ |
| 152 | 152 | for (i = hdr_size, buf += hdr_size; i < size; i++, buf++) { |
| @@ -1140,7 +1140,7 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) · 1139 unmodified lines | ||
| 1140 | 1140 | |
| 1141 | 1141 | static int queue_setup(struct vb2_queue *q, |
| 1142 | 1142 | unsigned int *num_buffers, unsigned int *num_planes, |
| 1143 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 1143 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 1144 | 1144 | { |
| 1145 | 1145 | struct cx23885_dev *dev = q->drv_priv; |
| 1146 | 1146 | |
| @@ -1148,7 +1148,6 @@ static int queue_setup(struct vb2_queue *q, · 1 unmodified line | ||
| 1148 | 1148 | dev->ts1.ts_packet_count = mpeglines; |
| 1149 | 1149 | *num_planes = 1; |
| 1150 | 1150 | sizes[0] = mpeglinesize * mpeglines; |
| 1151 | − alloc_ctxs[0] = dev->alloc_ctx; | |
| 1152 | 1151 | *num_buffers = mpegbufs; |
| 1153 | 1152 | return 0; |
| 1154 | 1153 | } |
| @@ -765,6 +765,11 @@ struct cx23885_board cx23885_boards[] = { · 764 unmodified lines | ||
| 765 | 765 | .amux = CX25840_AUDIO7, |
| 766 | 766 | } }, |
| 767 | 767 | }, |
| 768 | + [CX23885_BOARD_HAUPPAUGE_QUADHD_DVB] = { | |
| 769 | + .name = "Hauppauge WinTV-QuadHD-DVB", | |
| 770 | + .portb = CX23885_MPEG_DVB, | |
| 771 | + .portc = CX23885_MPEG_DVB, | |
| 772 | + }, | |
| 768 | 773 | }; |
| 769 | 774 | const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); |
| 770 | 775 | |
| @@ -1060,6 +1065,14 @@ struct cx23885_subid cx23885_subids[] = { · 289 unmodified lines | ||
| 1060 | 1065 | .subvendor = 0x1576, |
| 1061 | 1066 | .subdevice = 0x0460, |
| 1062 | 1067 | .card = CX23885_BOARD_VIEWCAST_460E, |
| 1068 | + }, { | |
| 1069 | + .subvendor = 0x0070, | |
| 1070 | + .subdevice = 0x6a28, | |
| 1071 | + .card = CX23885_BOARD_HAUPPAUGE_QUADHD_DVB, /* Tuner Pair 1 */ | |
| 1072 | + }, { | |
| 1073 | + .subvendor = 0x0070, | |
| 1074 | + .subdevice = 0x6b28, | |
| 1075 | + .card = CX23885_BOARD_HAUPPAUGE_QUADHD_DVB, /* Tuner Pair 2 */ | |
| 1063 | 1076 | }, |
| 1064 | 1077 | }; |
| 1065 | 1078 | const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); |
| @@ -1257,6 +1270,14 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) · 191 unmodified lines | ||
| 1257 | 1270 | case 150329: |
| 1258 | 1271 | /* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */ |
| 1259 | 1272 | break; |
| 1273 | + case 166100: | |
| 1274 | + /* WinTV-QuadHD (DVB) Tuner Pair 1 (PCIe, IR, half height, | |
| 1275 | + DVB-T/T2/C, DVB-T/T2/C */ | |
| 1276 | + break; | |
| 1277 | + case 166101: | |
| 1278 | + /* WinTV-QuadHD (DVB) Tuner Pair 2 (PCIe, IR, half height, | |
| 1279 | + DVB-T/T2/C, DVB-T/T2/C */ | |
| 1280 | + break; | |
| 1260 | 1281 | default: |
| 1261 | 1282 | printk(KERN_WARNING "%s: warning: " |
| 1262 | 1283 | "unknown hauppauge model #%d\n", |
| @@ -1729,20 +1750,22 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) · 466 unmodified lines | ||
| 1729 | 1750 | cx23885_gpio_set(dev, GPIO_2); |
| 1730 | 1751 | break; |
| 1731 | 1752 | case CX23885_BOARD_HAUPPAUGE_HVR5525: |
| 1753 | + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: | |
| 1732 | 1754 | /* |
| 1733 | − * GPIO-00 IR_WIDE | |
| 1734 | − * GPIO-02 wake# | |
| 1735 | − * GPIO-03 VAUX Pres. | |
| 1736 | − * GPIO-07 PROG# | |
| 1737 | − * GPIO-08 SAT_RESN | |
| 1738 | − * GPIO-09 TER_RESN | |
| 1739 | − * GPIO-10 B2_SENSE | |
| 1740 | − * GPIO-11 B1_SENSE | |
| 1741 | − * GPIO-15 IR_LED_STATUS | |
| 1742 | − * GPIO-19 IR_NARROW | |
| 1743 | − * GPIO-20 Blauster1 | |
| 1744 | − * ALTGPIO VAUX_SWITCH | |
| 1745 | − * AUX_PLL_CLK : Blaster2 | |
| 1755 | + * HVR5525 GPIO Details: | |
| 1756 | + * GPIO-00 IR_WIDE | |
| 1757 | + * GPIO-02 wake# | |
| 1758 | + * GPIO-03 VAUX Pres. | |
| 1759 | + * GPIO-07 PROG# | |
| 1760 | + * GPIO-08 SAT_RESN | |
| 1761 | + * GPIO-09 TER_RESN | |
| 1762 | + * GPIO-10 B2_SENSE | |
| 1763 | + * GPIO-11 B1_SENSE | |
| 1764 | + * GPIO-15 IR_LED_STATUS | |
| 1765 | + * GPIO-19 IR_NARROW | |
| 1766 | + * GPIO-20 Blauster1 | |
| 1767 | + * ALTGPIO VAUX_SWITCH | |
| 1768 | + * AUX_PLL_CLK : Blaster2 | |
| 1746 | 1769 | */ |
| 1747 | 1770 | /* Put the parts into reset and back */ |
| 1748 | 1771 | cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1); |
| @@ -1802,6 +1825,7 @@ int cx23885_ir_init(struct cx23885_dev *dev) · 53 unmodified lines | ||
| 1802 | 1825 | case CX23885_BOARD_HAUPPAUGE_HVR1255: |
| 1803 | 1826 | case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: |
| 1804 | 1827 | case CX23885_BOARD_HAUPPAUGE_HVR1210: |
| 1828 | + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: | |
| 1805 | 1829 | /* FIXME: Implement me */ |
| 1806 | 1830 | break; |
| 1807 | 1831 | case CX23885_BOARD_HAUPPAUGE_HVR1270: |
| @@ -2000,6 +2024,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) · 192 unmodified lines | ||
| 2000 | 2024 | case CX23885_BOARD_HAUPPAUGE_STARBURST: |
| 2001 | 2025 | case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE: |
| 2002 | 2026 | case CX23885_BOARD_HAUPPAUGE_HVR5525: |
| 2027 | + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: | |
| 2003 | 2028 | if (dev->i2c_bus[0].i2c_rc == 0) |
| 2004 | 2029 | hauppauge_eeprom(dev, eeprom+0xc0); |
| 2005 | 2030 | break; |
| @@ -2145,6 +2170,14 @@ void cx23885_card_setup(struct cx23885_dev *dev) · 139 unmodified lines | ||
| 2145 | 2170 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ |
| 2146 | 2171 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; |
| 2147 | 2172 | break; |
| 2173 | + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: | |
| 2174 | + ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | |
| 2175 | + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | |
| 2176 | + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | |
| 2177 | + ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | |
| 2178 | + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | |
| 2179 | + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | |
| 2180 | + break; | |
| 2148 | 2181 | case CX23885_BOARD_HAUPPAUGE_HVR1250: |
| 2149 | 2182 | case CX23885_BOARD_HAUPPAUGE_HVR1500: |
| 2150 | 2183 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: |
| @@ -2005,14 +2005,9 @@ static int cx23885_initdev(struct pci_dev *pci_dev, · 2004 unmodified lines | ||
| 2005 | 2005 | err = pci_set_dma_mask(pci_dev, 0xffffffff); |
| 2006 | 2006 | if (err) { |
| 2007 | 2007 | printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); |
| 2008 | − goto fail_context; | |
| 2008 | + goto fail_ctrl; | |
| 2009 | 2009 | } |
| 2010 | 2010 | |
| 2011 | − dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); | |
| 2012 | − if (IS_ERR(dev->alloc_ctx)) { | |
| 2013 | − err = PTR_ERR(dev->alloc_ctx); | |
| 2014 | − goto fail_context; | |
| 2015 | − } | |
| 2016 | 2011 | err = request_irq(pci_dev->irq, cx23885_irq, |
| 2017 | 2012 | IRQF_SHARED, dev->name, dev); |
| 2018 | 2013 | if (err < 0) { |
| @@ -2041,8 +2036,6 @@ static int cx23885_initdev(struct pci_dev *pci_dev, · 22 unmodified lines | ||
| 2041 | 2036 | return 0; |
| 2042 | 2037 | |
| 2043 | 2038 | fail_irq: |
| 2044 | − vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | |
| 2045 | −fail_context: | |
| 2046 | 2039 | cx23885_dev_unregister(dev); |
| 2047 | 2040 | fail_ctrl: |
| 2048 | 2041 | v4l2_ctrl_handler_free(hdl); |
| @@ -2068,7 +2061,6 @@ static void cx23885_finidev(struct pci_dev *pci_dev) · 19 unmodified lines | ||
| 2068 | 2061 | pci_disable_device(pci_dev); |
| 2069 | 2062 | |
| 2070 | 2063 | cx23885_dev_unregister(dev); |
| 2071 | − vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | |
| 2072 | 2064 | v4l2_ctrl_handler_free(&dev->ctrl_handler); |
| 2073 | 2065 | v4l2_device_unregister(v4l2_dev); |
| 2074 | 2066 | kfree(dev); |
| @@ -94,7 +94,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); · 93 unmodified lines | ||
| 94 | 94 | |
| 95 | 95 | static int queue_setup(struct vb2_queue *q, |
| 96 | 96 | unsigned int *num_buffers, unsigned int *num_planes, |
| 97 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 97 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 98 | 98 | { |
| 99 | 99 | struct cx23885_tsport *port = q->drv_priv; |
| 100 | 100 | |
| @@ -102,7 +102,6 @@ static int queue_setup(struct vb2_queue *q, · 1 unmodified line | ||
| 102 | 102 | port->ts_packet_count = 32; |
| 103 | 103 | *num_planes = 1; |
| 104 | 104 | sizes[0] = port->ts_packet_size * port->ts_packet_count; |
| 105 | − alloc_ctxs[0] = port->dev->alloc_ctx; | |
| 106 | 105 | *num_buffers = 32; |
| 107 | 106 | return 0; |
| 108 | 107 | } |
| @@ -2269,9 +2268,107 @@ static int dvb_register(struct cx23885_tsport *port) · 2160 unmodified lines | ||
| 2269 | 2268 | } |
| 2270 | 2269 | break; |
| 2271 | 2270 | } |
| 2271 | + case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: | |
| 2272 | + switch (port->nr) { | |
| 2273 | + /* port b - Terrestrial/cable */ | |
| 2274 | + case 1: | |
| 2275 | + /* attach frontend */ | |
| 2276 | + memset(&si2168_config, 0, sizeof(si2168_config)); | |
| 2277 | + si2168_config.i2c_adapter = &adapter; | |
| 2278 | + si2168_config.fe = &fe0->dvb.frontend; | |
| 2279 | + si2168_config.ts_mode = SI2168_TS_SERIAL; | |
| 2280 | + memset(&info, 0, sizeof(struct i2c_board_info)); | |
| 2281 | + strlcpy(info.type, "si2168", I2C_NAME_SIZE); | |
| 2282 | + info.addr = 0x64; | |
| 2283 | + info.platform_data = &si2168_config; | |
| 2284 | + request_module("%s", info.type); | |
| 2285 | + client_demod = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info); | |
| 2286 | + if (!client_demod || !client_demod->dev.driver) | |
| 2287 | + goto frontend_detach; | |
| 2288 | + if (!try_module_get(client_demod->dev.driver->owner)) { | |
| 2289 | + i2c_unregister_device(client_demod); | |
| 2290 | + goto frontend_detach; | |
| 2291 | + } | |
| 2292 | + port->i2c_client_demod = client_demod; | |
| 2293 | + | |
| 2294 | + /* attach tuner */ | |
| 2295 | + memset(&si2157_config, 0, sizeof(si2157_config)); | |
| 2296 | + si2157_config.fe = fe0->dvb.frontend; | |
| 2297 | + si2157_config.if_port = 1; | |
| 2298 | + memset(&info, 0, sizeof(struct i2c_board_info)); | |
| 2299 | + strlcpy(info.type, "si2157", I2C_NAME_SIZE); | |
| 2300 | + info.addr = 0x60; | |
| 2301 | + info.platform_data = &si2157_config; | |
| 2302 | + request_module("%s", info.type); | |
| 2303 | + client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info); | |
| 2304 | + if (!client_tuner || !client_tuner->dev.driver) { | |
| 2305 | + module_put(client_demod->dev.driver->owner); | |
| 2306 | + i2c_unregister_device(client_demod); | |
| 2307 | + port->i2c_client_demod = NULL; | |
| 2308 | + goto frontend_detach; | |
| 2309 | + } | |
| 2310 | + if (!try_module_get(client_tuner->dev.driver->owner)) { | |
| 2311 | + i2c_unregister_device(client_tuner); | |
| 2312 | + module_put(client_demod->dev.driver->owner); | |
| 2313 | + i2c_unregister_device(client_demod); | |
| 2314 | + port->i2c_client_demod = NULL; | |
| 2315 | + goto frontend_detach; | |
| 2316 | + } | |
| 2317 | + port->i2c_client_tuner = client_tuner; | |
| 2318 | + break; | |
| 2319 | + | |
| 2320 | + /* port c - terrestrial/cable */ | |
| 2321 | + case 2: | |
| 2322 | + /* attach frontend */ | |
| 2323 | + memset(&si2168_config, 0, sizeof(si2168_config)); | |
| 2324 | + si2168_config.i2c_adapter = &adapter; | |
| 2325 | + si2168_config.fe = &fe0->dvb.frontend; | |
| 2326 | + si2168_config.ts_mode = SI2168_TS_SERIAL; | |
| 2327 | + memset(&info, 0, sizeof(struct i2c_board_info)); | |
| 2328 | + strlcpy(info.type, "si2168", I2C_NAME_SIZE); | |
| 2329 | + info.addr = 0x66; | |
| 2330 | + info.platform_data = &si2168_config; | |
| 2331 | + request_module("%s", info.type); | |
| 2332 | + client_demod = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info); | |
| 2333 | + if (!client_demod || !client_demod->dev.driver) | |
| 2334 | + goto frontend_detach; | |
| 2335 | + if (!try_module_get(client_demod->dev.driver->owner)) { | |
| 2336 | + i2c_unregister_device(client_demod); | |
| 2337 | + goto frontend_detach; | |
| 2338 | + } | |
| 2339 | + port->i2c_client_demod = client_demod; | |
| 2340 | + | |
| 2341 | + /* attach tuner */ | |
| 2342 | + memset(&si2157_config, 0, sizeof(si2157_config)); | |
| 2343 | + si2157_config.fe = fe0->dvb.frontend; | |
| 2344 | + si2157_config.if_port = 1; | |
| 2345 | + memset(&info, 0, sizeof(struct i2c_board_info)); | |
| 2346 | + strlcpy(info.type, "si2157", I2C_NAME_SIZE); | |
| 2347 | + info.addr = 0x62; | |
| 2348 | + info.platform_data = &si2157_config; | |
| 2349 | + request_module("%s", info.type); | |
| 2350 | + client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info); | |
| 2351 | + if (!client_tuner || !client_tuner->dev.driver) { | |
| 2352 | + module_put(client_demod->dev.driver->owner); | |
| 2353 | + i2c_unregister_device(client_demod); | |
| 2354 | + port->i2c_client_demod = NULL; | |
| 2355 | + goto frontend_detach; | |
| 2356 | + } | |
| 2357 | + if (!try_module_get(client_tuner->dev.driver->owner)) { | |
| 2358 | + i2c_unregister_device(client_tuner); | |
| 2359 | + module_put(client_demod->dev.driver->owner); | |
| 2360 | + i2c_unregister_device(client_demod); | |
| 2361 | + port->i2c_client_demod = NULL; | |
| 2362 | + goto frontend_detach; | |
| 2363 | + } | |
| 2364 | + port->i2c_client_tuner = client_tuner; | |
| 2365 | + break; | |
| 2366 | + } | |
| 2367 | + break; | |
| 2368 | + | |
| 2272 | 2369 | default: |
| 2273 | 2370 | printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " |
| 2274 | − " isn't supported yet\n", | |
| 2371 | + " isn't supported yet\n", | |
| 2275 | 2372 | dev->name); |
| 2276 | 2373 | break; |
| 2277 | 2374 | } |
| @@ -2397,6 +2494,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port) · 119 unmodified lines | ||
| 2397 | 2494 | q->mem_ops = &vb2_dma_sg_memops; |
| 2398 | 2495 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 2399 | 2496 | q->lock = &dev->lock; |
| 2497 | + q->dev = &dev->pci->dev; | |
| 2400 | 2498 | |
| 2401 | 2499 | err = vb2_queue_init(q); |
| 2402 | 2500 | if (err < 0) |
| @@ -122,7 +122,7 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, · 121 unmodified lines | ||
| 122 | 122 | |
| 123 | 123 | static int queue_setup(struct vb2_queue *q, |
| 124 | 124 | unsigned int *num_buffers, unsigned int *num_planes, |
| 125 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 125 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 126 | 126 | { |
| 127 | 127 | struct cx23885_dev *dev = q->drv_priv; |
| 128 | 128 | unsigned lines = VBI_PAL_LINE_COUNT; |
| @@ -131,7 +131,6 @@ static int queue_setup(struct vb2_queue *q, · 2 unmodified lines | ||
| 131 | 131 | lines = VBI_NTSC_LINE_COUNT; |
| 132 | 132 | *num_planes = 1; |
| 133 | 133 | sizes[0] = lines * VBI_LINE_LENGTH * 2; |
| 134 | − alloc_ctxs[0] = dev->alloc_ctx; | |
| 135 | 134 | return 0; |
| 136 | 135 | } |
| 137 | 136 | |
| @@ -335,13 +335,12 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, · 334 unmodified lines | ||
| 335 | 335 | |
| 336 | 336 | static int queue_setup(struct vb2_queue *q, |
| 337 | 337 | unsigned int *num_buffers, unsigned int *num_planes, |
| 338 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 338 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 339 | 339 | { |
| 340 | 340 | struct cx23885_dev *dev = q->drv_priv; |
| 341 | 341 | |
| 342 | 342 | *num_planes = 1; |
| 343 | 343 | sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3; |
| 344 | − alloc_ctxs[0] = dev->alloc_ctx; | |
| 345 | 344 | return 0; |
| 346 | 345 | } |
| 347 | 346 | |
| @@ -1268,6 +1267,7 @@ int cx23885_video_register(struct cx23885_dev *dev) · 920 unmodified lines | ||
| 1268 | 1267 | q->mem_ops = &vb2_dma_sg_memops; |
| 1269 | 1268 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1270 | 1269 | q->lock = &dev->lock; |
| 1270 | + q->dev = &dev->pci->dev; | |
| 1271 | 1271 | |
| 1272 | 1272 | err = vb2_queue_init(q); |
| 1273 | 1273 | if (err < 0) |
| @@ -1284,6 +1284,7 @@ int cx23885_video_register(struct cx23885_dev *dev) · 10 unmodified lines | ||
| 1284 | 1284 | q->mem_ops = &vb2_dma_sg_memops; |
| 1285 | 1285 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1286 | 1286 | q->lock = &dev->lock; |
| 1287 | + q->dev = &dev->pci->dev; | |
| 1287 | 1288 | |
| 1288 | 1289 | err = vb2_queue_init(q); |
| 1289 | 1290 | if (err < 0) |
| @@ -103,6 +103,7 @@ · 102 unmodified lines | ||
| 103 | 103 | #define CX23885_BOARD_HAUPPAUGE_STARBURST 53 |
| 104 | 104 | #define CX23885_BOARD_VIEWCAST_260E 54 |
| 105 | 105 | #define CX23885_BOARD_VIEWCAST_460E 55 |
| 106 | +#define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB 56 | |
| 106 | 107 | |
| 107 | 108 | #define GPIO_0 0x00000001 |
| 108 | 109 | #define GPIO_1 0x00000002 |
| @@ -430,7 +431,6 @@ struct cx23885_dev { · 321 unmodified lines | ||
| 430 | 431 | struct vb2_queue vb2_vidq; |
| 431 | 432 | struct cx23885_dmaqueue vbiq; |
| 432 | 433 | struct vb2_queue vb2_vbiq; |
| 433 | − void *alloc_ctx; | |
| 434 | 434 | |
| 435 | 435 | spinlock_t slock; |
| 436 | 436 | |
| @@ -693,7 +693,7 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device, · 692 unmodified lines | ||
| 693 | 693 | * Only boards with eeprom and byte 1 at eeprom=1 have it |
| 694 | 694 | */ |
| 695 | 695 | |
| 696 | −static const struct pci_device_id cx25821_audio_pci_tbl[] = { | |
| 696 | +static const struct pci_device_id __maybe_unused cx25821_audio_pci_tbl[] = { | |
| 697 | 697 | {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
| 698 | 698 | {0,} |
| 699 | 699 | }; |
| @@ -1301,15 +1301,10 @@ static int cx25821_initdev(struct pci_dev *pci_dev, · 1300 unmodified lines | ||
| 1301 | 1301 | |
| 1302 | 1302 | goto fail_unregister_device; |
| 1303 | 1303 | } |
| 1304 | − dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); | |
| 1305 | − if (IS_ERR(dev->alloc_ctx)) { | |
| 1306 | − err = PTR_ERR(dev->alloc_ctx); | |
| 1307 | − goto fail_unregister_pci; | |
| 1308 | − } | |
| 1309 | 1304 | |
| 1310 | 1305 | err = cx25821_dev_setup(dev); |
| 1311 | 1306 | if (err) |
| 1312 | − goto fail_free_ctx; | |
| 1307 | + goto fail_unregister_pci; | |
| 1313 | 1308 | |
| 1314 | 1309 | /* print pci info */ |
| 1315 | 1310 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); |
| @@ -1340,8 +1335,6 @@ fail_irq: · 24 unmodified lines | ||
| 1340 | 1335 | pr_info("cx25821_initdev() can't get IRQ !\n"); |
| 1341 | 1336 | cx25821_dev_unregister(dev); |
| 1342 | 1337 | |
| 1343 | −fail_free_ctx: | |
| 1344 | − vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | |
| 1345 | 1338 | fail_unregister_pci: |
| 1346 | 1339 | pci_disable_device(pci_dev); |
| 1347 | 1340 | fail_unregister_device: |
| @@ -1365,7 +1358,6 @@ static void cx25821_finidev(struct pci_dev *pci_dev) · 17 unmodified lines | ||
| 1365 | 1358 | free_irq(pci_dev->irq, dev); |
| 1366 | 1359 | |
| 1367 | 1360 | cx25821_dev_unregister(dev); |
| 1368 | − vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | |
| 1369 | 1361 | v4l2_device_unregister(v4l2_dev); |
| 1370 | 1362 | kfree(dev); |
| 1371 | 1363 | } |
| @@ -143,13 +143,11 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) · 142 unmodified lines | ||
| 143 | 143 | |
| 144 | 144 | static int cx25821_queue_setup(struct vb2_queue *q, |
| 145 | 145 | unsigned int *num_buffers, unsigned int *num_planes, |
| 146 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 146 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 147 | 147 | { |
| 148 | 148 | struct cx25821_channel *chan = q->drv_priv; |
| 149 | 149 | unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3; |
| 150 | 150 | |
| 151 | − alloc_ctxs[0] = chan->dev->alloc_ctx; | |
| 152 | − | |
| 153 | 151 | if (*num_planes) |
| 154 | 152 | return sizes[0] < size ? -EINVAL : 0; |
| 155 | 153 | |
| @@ -759,6 +757,7 @@ int cx25821_video_register(struct cx25821_dev *dev) · 603 unmodified lines | ||
| 759 | 757 | q->mem_ops = &vb2_dma_sg_memops; |
| 760 | 758 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 761 | 759 | q->lock = &dev->lock; |
| 760 | + q->dev = &dev->pci->dev; | |
| 762 | 761 | |
| 763 | 762 | if (!is_output) { |
| 764 | 763 | err = vb2_queue_init(q); |
| @@ -249,7 +249,6 @@ struct cx25821_dev { · 248 unmodified lines | ||
| 249 | 249 | int hwrevision; |
| 250 | 250 | /* used by cx25821-alsa */ |
| 251 | 251 | struct snd_card *card; |
| 252 | − void *alloc_ctx; | |
| 253 | 252 | |
| 254 | 253 | u32 clk_freq; |
| 255 | 254 | |
| @@ -799,13 +799,9 @@ static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol, · 798 unmodified lines | ||
| 799 | 799 | { |
| 800 | 800 | snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); |
| 801 | 801 | struct cx88_core *core = chip->core; |
| 802 | − struct v4l2_control client_ctl; | |
| 803 | − | |
| 804 | − memset(&client_ctl, 0, sizeof(client_ctl)); | |
| 805 | − client_ctl.value = 0 != value->value.integer.value[0]; | |
| 806 | − client_ctl.id = V4L2_CID_AUDIO_LOUDNESS; | |
| 807 | − call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); | |
| 808 | 802 | |
| 803 | + wm8775_s_ctrl(core, V4L2_CID_AUDIO_LOUDNESS, | |
| 804 | + value->value.integer.value[0] != 0); | |
| 809 | 805 | return 0; |
| 810 | 806 | } |
| 811 | 807 | |
| @@ -639,7 +639,7 @@ static int blackbird_stop_codec(struct cx8802_dev *dev) · 638 unmodified lines | ||
| 639 | 639 | |
| 640 | 640 | static int queue_setup(struct vb2_queue *q, |
| 641 | 641 | unsigned int *num_buffers, unsigned int *num_planes, |
| 642 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 642 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 643 | 643 | { |
| 644 | 644 | struct cx8802_dev *dev = q->drv_priv; |
| 645 | 645 | |
| @@ -647,7 +647,6 @@ static int queue_setup(struct vb2_queue *q, · 1 unmodified line | ||
| 647 | 647 | dev->ts_packet_size = 188 * 4; |
| 648 | 648 | dev->ts_packet_count = 32; |
| 649 | 649 | sizes[0] = dev->ts_packet_size * dev->ts_packet_count; |
| 650 | − alloc_ctxs[0] = dev->alloc_ctx; | |
| 651 | 650 | return 0; |
| 652 | 651 | } |
| 653 | 652 | |
| @@ -1183,6 +1182,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) · 529 unmodified lines | ||
| 1183 | 1182 | q->mem_ops = &vb2_dma_sg_memops; |
| 1184 | 1183 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1185 | 1184 | q->lock = &core->lock; |
| 1185 | + q->dev = &dev->pci->dev; | |
| 1186 | 1186 | |
| 1187 | 1187 | err = vb2_queue_init(q); |
| 1188 | 1188 | if (err < 0) |
| @@ -84,7 +84,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); · 83 unmodified lines | ||
| 84 | 84 | |
| 85 | 85 | static int queue_setup(struct vb2_queue *q, |
| 86 | 86 | unsigned int *num_buffers, unsigned int *num_planes, |
| 87 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 87 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 88 | 88 | { |
| 89 | 89 | struct cx8802_dev *dev = q->drv_priv; |
| 90 | 90 | |
| @@ -92,7 +92,6 @@ static int queue_setup(struct vb2_queue *q, · 1 unmodified line | ||
| 92 | 92 | dev->ts_packet_size = 188 * 4; |
| 93 | 93 | dev->ts_packet_count = dvb_buf_tscnt; |
| 94 | 94 | sizes[0] = dev->ts_packet_size * dev->ts_packet_count; |
| 95 | − alloc_ctxs[0] = dev->alloc_ctx; | |
| 96 | 95 | *num_buffers = dvb_buf_tscnt; |
| 97 | 96 | return 0; |
| 98 | 97 | } |
| @@ -1793,6 +1792,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) · 1694 unmodified lines | ||
| 1793 | 1792 | q->mem_ops = &vb2_dma_sg_memops; |
| 1794 | 1793 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1795 | 1794 | q->lock = &core->lock; |
| 1795 | + q->dev = &dev->pci->dev; | |
| 1796 | 1796 | |
| 1797 | 1797 | err = vb2_queue_init(q); |
| 1798 | 1798 | if (err < 0) |
| @@ -726,11 +726,6 @@ static int cx8802_probe(struct pci_dev *pci_dev, · 725 unmodified lines | ||
| 726 | 726 | if (NULL == dev) |
| 727 | 727 | goto fail_core; |
| 728 | 728 | dev->pci = pci_dev; |
| 729 | − dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); | |
| 730 | − if (IS_ERR(dev->alloc_ctx)) { | |
| 731 | − err = PTR_ERR(dev->alloc_ctx); | |
| 732 | − goto fail_dev; | |
| 733 | − } | |
| 734 | 729 | dev->core = core; |
| 735 | 730 | |
| 736 | 731 | /* Maintain a reference so cx88-video can query the 8802 device. */ |
| @@ -738,7 +733,7 @@ static int cx8802_probe(struct pci_dev *pci_dev, · 1 unmodified line | ||
| 738 | 733 | |
| 739 | 734 | err = cx8802_init_common(dev); |
| 740 | 735 | if (err != 0) |
| 741 | − goto fail_free; | |
| 736 | + goto fail_dev; | |
| 742 | 737 | |
| 743 | 738 | INIT_LIST_HEAD(&dev->drvlist); |
| 744 | 739 | mutex_lock(&cx8802_mutex); |
| @@ -749,8 +744,6 @@ static int cx8802_probe(struct pci_dev *pci_dev, · 4 unmodified lines | ||
| 749 | 744 | request_modules(dev); |
| 750 | 745 | return 0; |
| 751 | 746 | |
| 752 | − fail_free: | |
| 753 | − vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | |
| 754 | 747 | fail_dev: |
| 755 | 748 | kfree(dev); |
| 756 | 749 | fail_core: |
| @@ -798,7 +791,6 @@ static void cx8802_remove(struct pci_dev *pci_dev) · 41 unmodified lines | ||
| 798 | 791 | /* common */ |
| 799 | 792 | cx8802_fini_common(dev); |
| 800 | 793 | cx88_core_put(dev->core,dev->pci); |
| 801 | − vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | |
| 802 | 794 | kfree(dev); |
| 803 | 795 | } |
| 804 | 796 | |
| @@ -109,7 +109,7 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, · 108 unmodified lines | ||
| 109 | 109 | |
| 110 | 110 | static int queue_setup(struct vb2_queue *q, |
| 111 | 111 | unsigned int *num_buffers, unsigned int *num_planes, |
| 112 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 112 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 113 | 113 | { |
| 114 | 114 | struct cx8800_dev *dev = q->drv_priv; |
| 115 | 115 | |
| @@ -118,7 +118,6 @@ static int queue_setup(struct vb2_queue *q, · 2 unmodified lines | ||
| 118 | 118 | sizes[0] = VBI_LINE_NTSC_COUNT * VBI_LINE_LENGTH * 2; |
| 119 | 119 | else |
| 120 | 120 | sizes[0] = VBI_LINE_PAL_COUNT * VBI_LINE_LENGTH * 2; |
| 121 | − alloc_ctxs[0] = dev->alloc_ctx; | |
| 122 | 121 | return 0; |
| 123 | 122 | } |
| 124 | 123 | |
| @@ -431,14 +431,13 @@ static int restart_video_queue(struct cx8800_dev *dev, · 430 unmodified lines | ||
| 431 | 431 | |
| 432 | 432 | static int queue_setup(struct vb2_queue *q, |
| 433 | 433 | unsigned int *num_buffers, unsigned int *num_planes, |
| 434 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 434 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 435 | 435 | { |
| 436 | 436 | struct cx8800_dev *dev = q->drv_priv; |
| 437 | 437 | struct cx88_core *core = dev->core; |
| 438 | 438 | |
| 439 | 439 | *num_planes = 1; |
| 440 | 440 | sizes[0] = (dev->fmt->depth * core->width * core->height) >> 3; |
| 441 | − alloc_ctxs[0] = dev->alloc_ctx; | |
| 442 | 441 | return 0; |
| 443 | 442 | } |
| 444 | 443 | |
| @@ -1319,12 +1318,6 @@ static int cx8800_initdev(struct pci_dev *pci_dev, · 874 unmodified lines | ||
| 1319 | 1318 | printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); |
| 1320 | 1319 | goto fail_core; |
| 1321 | 1320 | } |
| 1322 | − dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); | |
| 1323 | − if (IS_ERR(dev->alloc_ctx)) { | |
| 1324 | − err = PTR_ERR(dev->alloc_ctx); | |
| 1325 | − goto fail_core; | |
| 1326 | − } | |
| 1327 | − | |
| 1328 | 1321 | |
| 1329 | 1322 | /* initialize driver struct */ |
| 1330 | 1323 | spin_lock_init(&dev->slock); |
| @@ -1445,6 +1438,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, · 114 unmodified lines | ||
| 1445 | 1438 | q->mem_ops = &vb2_dma_sg_memops; |
| 1446 | 1439 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1447 | 1440 | q->lock = &core->lock; |
| 1441 | + q->dev = &dev->pci->dev; | |
| 1448 | 1442 | |
| 1449 | 1443 | err = vb2_queue_init(q); |
| 1450 | 1444 | if (err < 0) |
| @@ -1461,6 +1455,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, · 10 unmodified lines | ||
| 1461 | 1455 | q->mem_ops = &vb2_dma_sg_memops; |
| 1462 | 1456 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1463 | 1457 | q->lock = &core->lock; |
| 1458 | + q->dev = &dev->pci->dev; | |
| 1464 | 1459 | |
| 1465 | 1460 | err = vb2_queue_init(q); |
| 1466 | 1461 | if (err < 0) |
| @@ -1530,7 +1525,6 @@ fail_unreg: · 63 unmodified lines | ||
| 1530 | 1525 | free_irq(pci_dev->irq, dev); |
| 1531 | 1526 | mutex_unlock(&core->lock); |
| 1532 | 1527 | fail_core: |
| 1533 | − vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | |
| 1534 | 1528 | core->v4ldev = NULL; |
| 1535 | 1529 | cx88_core_put(core,dev->pci); |
| 1536 | 1530 | fail_free: |
| @@ -1564,7 +1558,6 @@ static void cx8800_finidev(struct pci_dev *pci_dev) · 27 unmodified lines | ||
| 1564 | 1558 | |
| 1565 | 1559 | /* free memory */ |
| 1566 | 1560 | cx88_core_put(core,dev->pci); |
| 1567 | − vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | |
| 1568 | 1561 | kfree(dev); |
| 1569 | 1562 | } |
| 1570 | 1563 | |
| @@ -485,7 +485,6 @@ struct cx8800_dev { · 484 unmodified lines | ||
| 485 | 485 | /* pci i/o */ |
| 486 | 486 | struct pci_dev *pci; |
| 487 | 487 | unsigned char pci_rev,pci_lat; |
| 488 | − void *alloc_ctx; | |
| 489 | 488 | |
| 490 | 489 | const struct cx8800_fmt *fmt; |
| 491 | 490 | |
| @@ -549,7 +548,6 @@ struct cx8802_dev { · 57 unmodified lines | ||
| 549 | 548 | /* pci i/o */ |
| 550 | 549 | struct pci_dev *pci; |
| 551 | 550 | unsigned char pci_rev,pci_lat; |
| 552 | − void *alloc_ctx; | |
| 553 | 551 | |
| 554 | 552 | /* dma queues */ |
| 555 | 553 | struct cx88_dmaqueue mpegq; |
| @@ -1569,10 +1569,9 @@ static int ddb_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 1568 unmodified lines | ||
| 1569 | 1569 | if (pci_enable_device(pdev) < 0) |
| 1570 | 1570 | return -ENODEV; |
| 1571 | 1571 | |
| 1572 | − dev = vmalloc(sizeof(struct ddb)); | |
| 1572 | + dev = vzalloc(sizeof(struct ddb)); | |
| 1573 | 1573 | if (dev == NULL) |
| 1574 | 1574 | return -ENOMEM; |
| 1575 | − memset(dev, 0, sizeof(struct ddb)); | |
| 1576 | 1575 | |
| 1577 | 1576 | dev->pdev = pdev; |
| 1578 | 1577 | pci_set_drvdata(pdev, dev); |
| @@ -133,7 +133,7 @@ static int wait_i2c_reg(void __iomem *addr) · 132 unmodified lines | ||
| 133 | 133 | static int |
| 134 | 134 | dt3155_queue_setup(struct vb2_queue *vq, |
| 135 | 135 | unsigned int *nbuffers, unsigned int *num_planes, |
| 136 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 136 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 137 | 137 | |
| 138 | 138 | { |
| 139 | 139 | struct dt3155_priv *pd = vb2_get_drv_priv(vq); |
| @@ -141,7 +141,6 @@ dt3155_queue_setup(struct vb2_queue *vq, · 1 unmodified line | ||
| 141 | 141 | |
| 142 | 142 | if (vq->num_buffers + *nbuffers < 2) |
| 143 | 143 | *nbuffers = 2 - vq->num_buffers; |
| 144 | − alloc_ctxs[0] = pd->alloc_ctx; | |
| 145 | 144 | if (*num_planes) |
| 146 | 145 | return sizes[0] < size ? -EINVAL : 0; |
| 147 | 146 | *num_planes = 1; |
| @@ -544,21 +543,16 @@ static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 396 unmodified lines | ||
| 544 | 543 | pd->vidq.min_buffers_needed = 2; |
| 545 | 544 | pd->vidq.gfp_flags = GFP_DMA32; |
| 546 | 545 | pd->vidq.lock = &pd->mux; /* for locking v4l2_file_operations */ |
| 546 | + pd->vidq.dev = &pdev->dev; | |
| 547 | 547 | pd->vdev.queue = &pd->vidq; |
| 548 | 548 | err = vb2_queue_init(&pd->vidq); |
| 549 | 549 | if (err < 0) |
| 550 | 550 | goto err_v4l2_dev_unreg; |
| 551 | − pd->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | |
| 552 | − if (IS_ERR(pd->alloc_ctx)) { | |
| 553 | − dev_err(&pdev->dev, "Can't allocate buffer context"); | |
| 554 | − err = PTR_ERR(pd->alloc_ctx); | |
| 555 | − goto err_v4l2_dev_unreg; | |
| 556 | − } | |
| 557 | 551 | spin_lock_init(&pd->lock); |
| 558 | 552 | pd->config = ACQ_MODE_EVEN; |
| 559 | 553 | err = pci_enable_device(pdev); |
| 560 | 554 | if (err) |
| 561 | − goto err_free_ctx; | |
| 555 | + goto err_v4l2_dev_unreg; | |
| 562 | 556 | err = pci_request_region(pdev, 0, pci_name(pdev)); |
| 563 | 557 | if (err) |
| 564 | 558 | goto err_pci_disable; |
| @@ -588,8 +582,6 @@ err_free_reg: · 23 unmodified lines | ||
| 588 | 582 | pci_release_region(pdev, 0); |
| 589 | 583 | err_pci_disable: |
| 590 | 584 | pci_disable_device(pdev); |
| 591 | −err_free_ctx: | |
| 592 | − vb2_dma_contig_cleanup_ctx(pd->alloc_ctx); | |
| 593 | 585 | err_v4l2_dev_unreg: |
| 594 | 586 | v4l2_device_unregister(&pd->v4l2_dev); |
| 595 | 587 | return err; |
| @@ -608,7 +600,6 @@ static void dt3155_remove(struct pci_dev *pdev) · 12 unmodified lines | ||
| 608 | 600 | pci_iounmap(pdev, pd->regs); |
| 609 | 601 | pci_release_region(pdev, 0); |
| 610 | 602 | pci_disable_device(pdev); |
| 611 | − vb2_dma_contig_cleanup_ctx(pd->alloc_ctx); | |
| 612 | 603 | } |
| 613 | 604 | |
| 614 | 605 | static const struct pci_device_id pci_ids[] = { |
| @@ -161,7 +161,6 @@ · 160 unmodified lines | ||
| 161 | 161 | * @vdev: video_device structure |
| 162 | 162 | * @pdev: pointer to pci_dev structure |
| 163 | 163 | * @vidq: vb2_queue structure |
| 164 | − * @alloc_ctx: dma_contig allocation context | |
| 165 | 164 | * @curr_buf: pointer to curren buffer |
| 166 | 165 | * @mux: mutex to protect the instance |
| 167 | 166 | * @dmaq: queue for dma buffers |
| @@ -181,7 +180,6 @@ struct dt3155_priv { · 13 unmodified lines | ||
| 181 | 180 | struct video_device vdev; |
| 182 | 181 | struct pci_dev *pdev; |
| 183 | 182 | struct vb2_queue vidq; |
| 184 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 185 | 183 | struct vb2_v4l2_buffer *curr_buf; |
| 186 | 184 | struct mutex mux; |
| 187 | 185 | struct list_head dmaq; |
| @@ -93,7 +93,7 @@ static int snd_ivtv_mixer_tv_vol_get(struct snd_kcontrol *kctl, · 92 unmodified lines | ||
| 93 | 93 | vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]); |
| 94 | 94 | |
| 95 | 95 | snd_ivtv_lock(itvsc); |
| 96 | − ret = v4l2_subdev_call(itv->sd_audio, core, g_ctrl, &vctrl); | |
| 96 | + ret = v4l2_g_ctrl(itv->sd_audio->ctrl_handler, &vctrl); | |
| 97 | 97 | snd_ivtv_unlock(itvsc); |
| 98 | 98 | |
| 99 | 99 | if (!ret) |
| @@ -115,14 +115,14 @@ static int snd_ivtv_mixer_tv_vol_put(struct snd_kcontrol *kctl, · 15 unmodified lines | ||
| 115 | 115 | snd_ivtv_lock(itvsc); |
| 116 | 116 | |
| 117 | 117 | /* Fetch current state */ |
| 118 | − ret = v4l2_subdev_call(itv->sd_audio, core, g_ctrl, &vctrl); | |
| 118 | + ret = v4l2_g_ctrl(itv->sd_audio->ctrl_handler, &vctrl); | |
| 119 | 119 | |
| 120 | 120 | if (ret || |
| 121 | 121 | (cx25840_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { |
| 122 | 122 | |
| 123 | 123 | /* Set, if needed */ |
| 124 | 124 | vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]); |
| 125 | − ret = v4l2_subdev_call(itv->sd_audio, core, s_ctrl, &vctrl); | |
| 125 | + ret = v4l2_s_ctrl(itv->sd_audio->ctrl_handler, &vctrl); | |
| 126 | 126 | if (!ret) |
| 127 | 127 | ret = 1; /* Indicate control was changed w/o error */ |
| 128 | 128 | } |
| @@ -5,8 +5,13 @@ config DVB_NETUP_UNIDVB · 4 unmodified lines | ||
| 5 | 5 | select VIDEOBUF2_VMALLOC |
| 6 | 6 | select DVB_HORUS3A if MEDIA_SUBDRV_AUTOSELECT |
| 7 | 7 | select DVB_ASCOT2E if MEDIA_SUBDRV_AUTOSELECT |
| 8 | + select DVB_HELENE if MEDIA_SUBDRV_AUTOSELECT | |
| 8 | 9 | select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT |
| 9 | 10 | select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT |
| 10 | 11 | ---help--- |
| 11 | 12 | Support for NetUP PCI express Universal DVB card. |
| 12 | − | |
| 13 | + help | |
| 14 | + Say Y when you want to support NetUP Dual Universal DVB card | |
| 15 | + Card can receive two independent streams in following standards: | |
| 16 | + DVB-S/S2, T/T2, C/C2 | |
| 17 | + Two CI slots available for CAM modules. | |
| @@ -50,6 +50,15 @@ · 49 unmodified lines | ||
| 50 | 50 | #define NETUP_UNIDVB_IRQ_CAM0 (1 << 11) |
| 51 | 51 | #define NETUP_UNIDVB_IRQ_CAM1 (1 << 12) |
| 52 | 52 | |
| 53 | +/* NetUP Universal DVB card hardware revisions and it's PCI device id's: | |
| 54 | + * 1.3 - CXD2841ER demod, ASCOT2E and HORUS3A tuners | |
| 55 | + * 1.4 - CXD2854ER demod, HELENE tuner | |
| 56 | +*/ | |
| 57 | +enum netup_hw_rev { | |
| 58 | + NETUP_HW_REV_1_3 = 0x18F6, | |
| 59 | + NETUP_HW_REV_1_4 = 0x18F7 | |
| 60 | +}; | |
| 61 | + | |
| 53 | 62 | struct netup_dma { |
| 54 | 63 | u8 num; |
| 55 | 64 | spinlock_t lock; |
| @@ -119,6 +128,7 @@ struct netup_unidvb_dev { · 63 unmodified lines | ||
| 119 | 128 | struct netup_dma dma[2]; |
| 120 | 129 | struct netup_ci_state ci[2]; |
| 121 | 130 | struct netup_spi *spi; |
| 131 | + enum netup_hw_rev rev; | |
| 122 | 132 | }; |
| 123 | 133 | |
| 124 | 134 | int netup_i2c_register(struct netup_unidvb_dev *ndev); |
| @@ -147,7 +147,7 @@ static int netup_unidvb_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, · 146 unmodified lines | ||
| 147 | 147 | { |
| 148 | 148 | struct netup_ci_state *state = en50221->data; |
| 149 | 149 | struct netup_unidvb_dev *dev = state->dev; |
| 150 | − u8 val = *((u8 __force *)state->membase8_io + addr); | |
| 150 | + u8 val = *((u8 __force *)state->membase8_config + addr); | |
| 151 | 151 | |
| 152 | 152 | dev_dbg(&dev->pci_dev->dev, |
| 153 | 153 | "%s(): addr=0x%x val=0x%x\n", __func__, addr, val); |
| @@ -162,7 +162,7 @@ static int netup_unidvb_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, · 8 unmodified lines | ||
| 162 | 162 | |
| 163 | 163 | dev_dbg(&dev->pci_dev->dev, |
| 164 | 164 | "%s(): addr=0x%x data=0x%x\n", __func__, addr, data); |
| 165 | − *((u8 __force *)state->membase8_io + addr) = data; | |
| 165 | + *((u8 __force *)state->membase8_config + addr) = data; | |
| 166 | 166 | return 0; |
| 167 | 167 | } |
| 168 | 168 | |
| @@ -34,6 +34,7 @@ · 33 unmodified lines | ||
| 34 | 34 | #include "cxd2841er.h" |
| 35 | 35 | #include "horus3a.h" |
| 36 | 36 | #include "ascot2e.h" |
| 37 | +#include "helene.h" | |
| 37 | 38 | #include "lnbh25.h" |
| 38 | 39 | |
| 39 | 40 | static int spi_enable; |
| @@ -120,7 +121,8 @@ static int netup_unidvb_tuner_ctrl(void *priv, int is_dvb_tc); · 80 unmodified lines | ||
| 120 | 121 | static void netup_unidvb_queue_cleanup(struct netup_dma *dma); |
| 121 | 122 | |
| 122 | 123 | static struct cxd2841er_config demod_config = { |
| 123 | − .i2c_addr = 0xc8 | |
| 124 | + .i2c_addr = 0xc8, | |
| 125 | + .xtal = SONY_XTAL_24000 | |
| 124 | 126 | }; |
| 125 | 127 | |
| 126 | 128 | static struct horus3a_config horus3a_conf = { |
| @@ -134,6 +136,12 @@ static struct ascot2e_config ascot2e_conf = { · 7 unmodified lines | ||
| 134 | 136 | .set_tuner_callback = netup_unidvb_tuner_ctrl |
| 135 | 137 | }; |
| 136 | 138 | |
| 139 | +static struct helene_config helene_conf = { | |
| 140 | + .i2c_address = 0xc0, | |
| 141 | + .xtal = SONY_HELENE_XTAL_24000, | |
| 142 | + .set_tuner_callback = netup_unidvb_tuner_ctrl | |
| 143 | +}; | |
| 144 | + | |
| 137 | 145 | static struct lnbh25_config lnbh25_conf = { |
| 138 | 146 | .i2c_address = 0x10, |
| 139 | 147 | .data2_config = LNBH25_TEN | LNBH25_EXTM |
| @@ -152,6 +160,11 @@ static int netup_unidvb_tuner_ctrl(void *priv, int is_dvb_tc) · 12 unmodified lines | ||
| 152 | 160 | __func__, dma->num, is_dvb_tc); |
| 153 | 161 | reg = readb(ndev->bmmio0 + GPIO_REG_IO); |
| 154 | 162 | mask = (dma->num == 0) ? GPIO_RFA_CTL : GPIO_RFB_CTL; |
| 163 | + | |
| 164 | + /* inverted tuner control in hw rev. 1.4 */ | |
| 165 | + if (ndev->rev == NETUP_HW_REV_1_4) | |
| 166 | + is_dvb_tc = !is_dvb_tc; | |
| 167 | + | |
| 155 | 168 | if (!is_dvb_tc) |
| 156 | 169 | reg |= mask; |
| 157 | 170 | else |
| @@ -280,7 +293,7 @@ static int netup_unidvb_queue_setup(struct vb2_queue *vq, · 122 unmodified lines | ||
| 280 | 293 | unsigned int *nbuffers, |
| 281 | 294 | unsigned int *nplanes, |
| 282 | 295 | unsigned int sizes[], |
| 283 | − void *alloc_ctxs[]) | |
| 296 | + struct device *alloc_devs[]) | |
| 284 | 297 | { |
| 285 | 298 | struct netup_dma *dma = vb2_get_drv_priv(vq); |
| 286 | 299 | |
| @@ -372,7 +385,15 @@ static int netup_unidvb_queue_init(struct netup_dma *dma, · 85 unmodified lines | ||
| 372 | 385 | static int netup_unidvb_dvb_init(struct netup_unidvb_dev *ndev, |
| 373 | 386 | int num) |
| 374 | 387 | { |
| 375 | − struct vb2_dvb_frontend *fe0, *fe1, *fe2; | |
| 388 | + int fe_count = 2; | |
| 389 | + int i = 0; | |
| 390 | + struct vb2_dvb_frontend *fes[2]; | |
| 391 | + u8 fe_name[32]; | |
| 392 | + | |
| 393 | + if (ndev->rev == NETUP_HW_REV_1_3) | |
| 394 | + demod_config.xtal = SONY_XTAL_20500; | |
| 395 | + else | |
| 396 | + demod_config.xtal = SONY_XTAL_24000; | |
| 376 | 397 | |
| 377 | 398 | if (num < 0 || num > 1) { |
| 378 | 399 | dev_dbg(&ndev->pci_dev->dev, |
| @@ -381,84 +402,96 @@ static int netup_unidvb_dvb_init(struct netup_unidvb_dev *ndev, · 2 unmodified lines | ||
| 381 | 402 | } |
| 382 | 403 | mutex_init(&ndev->frontends[num].lock); |
| 383 | 404 | INIT_LIST_HEAD(&ndev->frontends[num].felist); |
| 384 | − if (vb2_dvb_alloc_frontend(&ndev->frontends[num], 1) == NULL || | |
| 385 | − vb2_dvb_alloc_frontend( | |
| 386 | − &ndev->frontends[num], 2) == NULL || | |
| 387 | − vb2_dvb_alloc_frontend( | |
| 388 | − &ndev->frontends[num], 3) == NULL) { | |
| 389 | − dev_dbg(&ndev->pci_dev->dev, | |
| 390 | − "%s(): unable to allocate vb2_dvb_frontend\n", | |
| 391 | − __func__); | |
| 392 | − return -ENOMEM; | |
| 405 | + | |
| 406 | + for (i = 0; i < fe_count; i++) { | |
| 407 | + if (vb2_dvb_alloc_frontend(&ndev->frontends[num], i+1) | |
| 408 | + == NULL) { | |
| 409 | + dev_err(&ndev->pci_dev->dev, | |
| 410 | + "%s(): unable to allocate vb2_dvb_frontend\n", | |
| 411 | + __func__); | |
| 412 | + return -ENOMEM; | |
| 413 | + } | |
| 393 | 414 | } |
| 394 | − fe0 = vb2_dvb_get_frontend(&ndev->frontends[num], 1); | |
| 395 | − fe1 = vb2_dvb_get_frontend(&ndev->frontends[num], 2); | |
| 396 | − fe2 = vb2_dvb_get_frontend(&ndev->frontends[num], 3); | |
| 397 | − if (fe0 == NULL || fe1 == NULL || fe2 == NULL) { | |
| 398 | − dev_dbg(&ndev->pci_dev->dev, | |
| 399 | − "%s(): frontends has not been allocated\n", __func__); | |
| 400 | − return -EINVAL; | |
| 415 | + | |
| 416 | + for (i = 0; i < fe_count; i++) { | |
| 417 | + fes[i] = vb2_dvb_get_frontend(&ndev->frontends[num], i+1); | |
| 418 | + if (fes[i] == NULL) { | |
| 419 | + dev_err(&ndev->pci_dev->dev, | |
| 420 | + "%s(): frontends has not been allocated\n", | |
| 421 | + __func__); | |
| 422 | + return -EINVAL; | |
| 423 | + } | |
| 424 | + } | |
| 425 | + | |
| 426 | + for (i = 0; i < fe_count; i++) { | |
| 427 | + netup_unidvb_queue_init(&ndev->dma[num], &fes[i]->dvb.dvbq); | |
| 428 | + snprintf(fe_name, sizeof(fe_name), "netup_fe%d", i); | |
| 429 | + fes[i]->dvb.name = fe_name; | |
| 401 | 430 | } |
| 402 | − netup_unidvb_queue_init(&ndev->dma[num], &fe0->dvb.dvbq); | |
| 403 | − netup_unidvb_queue_init(&ndev->dma[num], &fe1->dvb.dvbq); | |
| 404 | − netup_unidvb_queue_init(&ndev->dma[num], &fe2->dvb.dvbq); | |
| 405 | − fe0->dvb.name = "netup_fe0"; | |
| 406 | − fe1->dvb.name = "netup_fe1"; | |
| 407 | − fe2->dvb.name = "netup_fe2"; | |
| 408 | − fe0->dvb.frontend = dvb_attach(cxd2841er_attach_s, | |
| 431 | + | |
| 432 | + fes[0]->dvb.frontend = dvb_attach(cxd2841er_attach_s, | |
| 409 | 433 | &demod_config, &ndev->i2c[num].adap); |
| 410 | − if (fe0->dvb.frontend == NULL) { | |
| 434 | + if (fes[0]->dvb.frontend == NULL) { | |
| 411 | 435 | dev_dbg(&ndev->pci_dev->dev, |
| 412 | 436 | "%s(): unable to attach DVB-S/S2 frontend\n", |
| 413 | 437 | __func__); |
| 414 | 438 | goto frontend_detach; |
| 415 | 439 | } |
| 416 | − horus3a_conf.set_tuner_priv = &ndev->dma[num]; | |
| 417 | − if (!dvb_attach(horus3a_attach, fe0->dvb.frontend, | |
| 418 | − &horus3a_conf, &ndev->i2c[num].adap)) { | |
| 419 | − dev_dbg(&ndev->pci_dev->dev, | |
| 420 | − "%s(): unable to attach DVB-S/S2 tuner frontend\n", | |
| 421 | − __func__); | |
| 422 | − goto frontend_detach; | |
| 440 | + | |
| 441 | + if (ndev->rev == NETUP_HW_REV_1_3) { | |
| 442 | + horus3a_conf.set_tuner_priv = &ndev->dma[num]; | |
| 443 | + if (!dvb_attach(horus3a_attach, fes[0]->dvb.frontend, | |
| 444 | + &horus3a_conf, &ndev->i2c[num].adap)) { | |
| 445 | + dev_dbg(&ndev->pci_dev->dev, | |
| 446 | + "%s(): unable to attach HORUS3A DVB-S/S2 tuner frontend\n", | |
| 447 | + __func__); | |
| 448 | + goto frontend_detach; | |
| 449 | + } | |
| 450 | + } else { | |
| 451 | + helene_conf.set_tuner_priv = &ndev->dma[num]; | |
| 452 | + if (!dvb_attach(helene_attach_s, fes[0]->dvb.frontend, | |
| 453 | + &helene_conf, &ndev->i2c[num].adap)) { | |
| 454 | + dev_err(&ndev->pci_dev->dev, | |
| 455 | + "%s(): unable to attach HELENE DVB-S/S2 tuner frontend\n", | |
| 456 | + __func__); | |
| 457 | + goto frontend_detach; | |
| 458 | + } | |
| 423 | 459 | } |
| 424 | − if (!dvb_attach(lnbh25_attach, fe0->dvb.frontend, | |
| 460 | + | |
| 461 | + if (!dvb_attach(lnbh25_attach, fes[0]->dvb.frontend, | |
| 425 | 462 | &lnbh25_conf, &ndev->i2c[num].adap)) { |
| 426 | 463 | dev_dbg(&ndev->pci_dev->dev, |
| 427 | 464 | "%s(): unable to attach SEC frontend\n", __func__); |
| 428 | 465 | goto frontend_detach; |
| 429 | 466 | } |
| 467 | + | |
| 430 | 468 | /* DVB-T/T2 frontend */ |
| 431 | − fe1->dvb.frontend = dvb_attach(cxd2841er_attach_t, | |
| 469 | + fes[1]->dvb.frontend = dvb_attach(cxd2841er_attach_t_c, | |
| 432 | 470 | &demod_config, &ndev->i2c[num].adap); |
| 433 | − if (fe1->dvb.frontend == NULL) { | |
| 434 | − dev_dbg(&ndev->pci_dev->dev, | |
| 435 | − "%s(): unable to attach DVB-T frontend\n", __func__); | |
| 436 | − goto frontend_detach; | |
| 437 | − } | |
| 438 | − fe1->dvb.frontend->id = 1; | |
| 439 | − ascot2e_conf.set_tuner_priv = &ndev->dma[num]; | |
| 440 | − if (!dvb_attach(ascot2e_attach, fe1->dvb.frontend, | |
| 441 | − &ascot2e_conf, &ndev->i2c[num].adap)) { | |
| 442 | − dev_dbg(&ndev->pci_dev->dev, | |
| 443 | − "%s(): unable to attach DVB-T tuner frontend\n", | |
| 444 | − __func__); | |
| 445 | − goto frontend_detach; | |
| 446 | − } | |
| 447 | − /* DVB-C/C2 frontend */ | |
| 448 | − fe2->dvb.frontend = dvb_attach(cxd2841er_attach_c, | |
| 449 | − &demod_config, &ndev->i2c[num].adap); | |
| 450 | − if (fe2->dvb.frontend == NULL) { | |
| 471 | + if (fes[1]->dvb.frontend == NULL) { | |
| 451 | 472 | dev_dbg(&ndev->pci_dev->dev, |
| 452 | − "%s(): unable to attach DVB-C frontend\n", __func__); | |
| 473 | + "%s(): unable to attach Ter frontend\n", __func__); | |
| 453 | 474 | goto frontend_detach; |
| 454 | 475 | } |
| 455 | − fe2->dvb.frontend->id = 2; | |
| 456 | − if (!dvb_attach(ascot2e_attach, fe2->dvb.frontend, | |
| 457 | − &ascot2e_conf, &ndev->i2c[num].adap)) { | |
| 458 | − dev_dbg(&ndev->pci_dev->dev, | |
| 459 | − "%s(): unable to attach DVB-T/C tuner frontend\n", | |
| 460 | − __func__); | |
| 461 | − goto frontend_detach; | |
| 476 | + fes[1]->dvb.frontend->id = 1; | |
| 477 | + if (ndev->rev == NETUP_HW_REV_1_3) { | |
| 478 | + ascot2e_conf.set_tuner_priv = &ndev->dma[num]; | |
| 479 | + if (!dvb_attach(ascot2e_attach, fes[1]->dvb.frontend, | |
| 480 | + &ascot2e_conf, &ndev->i2c[num].adap)) { | |
| 481 | + dev_dbg(&ndev->pci_dev->dev, | |
| 482 | + "%s(): unable to attach Ter tuner frontend\n", | |
| 483 | + __func__); | |
| 484 | + goto frontend_detach; | |
| 485 | + } | |
| 486 | + } else { | |
| 487 | + helene_conf.set_tuner_priv = &ndev->dma[num]; | |
| 488 | + if (!dvb_attach(helene_attach, fes[1]->dvb.frontend, | |
| 489 | + &helene_conf, &ndev->i2c[num].adap)) { | |
| 490 | + dev_err(&ndev->pci_dev->dev, | |
| 491 | + "%s(): unable to attach HELENE Ter tuner frontend\n", | |
| 492 | + __func__); | |
| 493 | + goto frontend_detach; | |
| 494 | + } | |
| 462 | 495 | } |
| 463 | 496 | |
| 464 | 497 | if (vb2_dvb_register_bus(&ndev->frontends[num], |
| @@ -730,7 +763,7 @@ static int netup_unidvb_request_mmio(struct pci_dev *pci_dev) · 265 unmodified lines | ||
| 730 | 763 | static int netup_unidvb_request_modules(struct device *dev) |
| 731 | 764 | { |
| 732 | 765 | static const char * const modules[] = { |
| 733 | − "lnbh25", "ascot2e", "horus3a", "cxd2841er", NULL | |
| 766 | + "lnbh25", "ascot2e", "horus3a", "cxd2841er", "helene", NULL | |
| 734 | 767 | }; |
| 735 | 768 | const char * const *curr_mod = modules; |
| 736 | 769 | int err; |
| @@ -774,6 +807,16 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev, · 37 unmodified lines | ||
| 774 | 807 | if (!ndev) |
| 775 | 808 | goto dev_alloc_err; |
| 776 | 809 | |
| 810 | + /* detect hardware revision */ | |
| 811 | + if (pci_dev->device == NETUP_HW_REV_1_3) | |
| 812 | + ndev->rev = NETUP_HW_REV_1_3; | |
| 813 | + else | |
| 814 | + ndev->rev = NETUP_HW_REV_1_4; | |
| 815 | + | |
| 816 | + dev_info(&pci_dev->dev, | |
| 817 | + "%s(): board (0x%x) hardware revision 0x%x\n", | |
| 818 | + __func__, pci_dev->device, ndev->rev); | |
| 819 | + | |
| 777 | 820 | ndev->old_fw = old_firmware; |
| 778 | 821 | ndev->wq = create_singlethread_workqueue(NETUP_UNIDVB_NAME); |
| 779 | 822 | if (!ndev->wq) { |
| @@ -932,7 +975,7 @@ wq_create_err: · 152 unmodified lines | ||
| 932 | 975 | kfree(ndev); |
| 933 | 976 | dev_alloc_err: |
| 934 | 977 | dev_err(&pci_dev->dev, |
| 935 | − "%s(): failed to initizalize device\n", __func__); | |
| 978 | + "%s(): failed to initialize device\n", __func__); | |
| 936 | 979 | return -EIO; |
| 937 | 980 | } |
| 938 | 981 | |
| @@ -972,7 +1015,8 @@ static void netup_unidvb_finidev(struct pci_dev *pci_dev) · 33 unmodified lines | ||
| 972 | 1015 | |
| 973 | 1016 | |
| 974 | 1017 | static struct pci_device_id netup_unidvb_pci_tbl[] = { |
| 975 | − { PCI_DEVICE(0x1b55, 0x18f6) }, | |
| 1018 | + { PCI_DEVICE(0x1b55, 0x18f6) }, /* hw rev. 1.3 */ | |
| 1019 | + { PCI_DEVICE(0x1b55, 0x18f7) }, /* hw rev. 1.4 */ | |
| 976 | 1020 | { 0, } |
| 977 | 1021 | }; |
| 978 | 1022 | MODULE_DEVICE_TABLE(pci, netup_unidvb_pci_tbl); |
| @@ -1164,18 +1164,13 @@ static int saa7134_initdev(struct pci_dev *pci_dev, · 1163 unmodified lines | ||
| 1164 | 1164 | saa7134_board_init1(dev); |
| 1165 | 1165 | saa7134_hwinit1(dev); |
| 1166 | 1166 | |
| 1167 | − dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); | |
| 1168 | − if (IS_ERR(dev->alloc_ctx)) { | |
| 1169 | − err = PTR_ERR(dev->alloc_ctx); | |
| 1170 | − goto fail3; | |
| 1171 | − } | |
| 1172 | 1167 | /* get irq */ |
| 1173 | 1168 | err = request_irq(pci_dev->irq, saa7134_irq, |
| 1174 | 1169 | IRQF_SHARED, dev->name, dev); |
| 1175 | 1170 | if (err < 0) { |
| 1176 | 1171 | pr_err("%s: can't get IRQ %d\n", |
| 1177 | 1172 | dev->name,pci_dev->irq); |
| 1178 | − goto fail4; | |
| 1173 | + goto fail3; | |
| 1179 | 1174 | } |
| 1180 | 1175 | |
| 1181 | 1176 | /* wait a bit, register i2c bus */ |
| @@ -1233,7 +1228,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, · 51 unmodified lines | ||
| 1233 | 1228 | if (err < 0) { |
| 1234 | 1229 | pr_info("%s: can't register video device\n", |
| 1235 | 1230 | dev->name); |
| 1236 | − goto fail5; | |
| 1231 | + goto fail4; | |
| 1237 | 1232 | } |
| 1238 | 1233 | pr_info("%s: registered device %s [v4l2]\n", |
| 1239 | 1234 | dev->name, video_device_node_name(dev->video_dev)); |
| @@ -1246,7 +1241,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, · 6 unmodified lines | ||
| 1246 | 1241 | err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, |
| 1247 | 1242 | vbi_nr[dev->nr]); |
| 1248 | 1243 | if (err < 0) |
| 1249 | − goto fail5; | |
| 1244 | + goto fail4; | |
| 1250 | 1245 | pr_info("%s: registered device %s\n", |
| 1251 | 1246 | dev->name, video_device_node_name(dev->vbi_dev)); |
| 1252 | 1247 | |
| @@ -1257,7 +1252,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, · 4 unmodified lines | ||
| 1257 | 1252 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, |
| 1258 | 1253 | radio_nr[dev->nr]); |
| 1259 | 1254 | if (err < 0) |
| 1260 | − goto fail5; | |
| 1255 | + goto fail4; | |
| 1261 | 1256 | pr_info("%s: registered device %s\n", |
| 1262 | 1257 | dev->name, video_device_node_name(dev->radio_dev)); |
| 1263 | 1258 | } |
| @@ -1268,7 +1263,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, · 4 unmodified lines | ||
| 1268 | 1263 | err = v4l2_mc_create_media_graph(dev->media_dev); |
| 1269 | 1264 | if (err) { |
| 1270 | 1265 | pr_err("failed to create media graph\n"); |
| 1271 | − goto fail5; | |
| 1266 | + goto fail4; | |
| 1272 | 1267 | } |
| 1273 | 1268 | #endif |
| 1274 | 1269 | /* everything worked */ |
| @@ -1287,17 +1282,15 @@ static int saa7134_initdev(struct pci_dev *pci_dev, · 12 unmodified lines | ||
| 1287 | 1282 | #ifdef CONFIG_MEDIA_CONTROLLER |
| 1288 | 1283 | err = media_device_register(dev->media_dev); |
| 1289 | 1284 | if (err) |
| 1290 | − goto fail5; | |
| 1285 | + goto fail4; | |
| 1291 | 1286 | #endif |
| 1292 | 1287 | |
| 1293 | 1288 | return 0; |
| 1294 | 1289 | |
| 1295 | − fail5: | |
| 1290 | + fail4: | |
| 1296 | 1291 | saa7134_unregister_video(dev); |
| 1297 | 1292 | saa7134_i2c_unregister(dev); |
| 1298 | 1293 | free_irq(pci_dev->irq, dev); |
| 1299 | − fail4: | |
| 1300 | − vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | |
| 1301 | 1294 | fail3: |
| 1302 | 1295 | saa7134_hwfini(dev); |
| 1303 | 1296 | iounmap(dev->lmmio); |
| @@ -1367,7 +1360,6 @@ static void saa7134_finidev(struct pci_dev *pci_dev) · 63 unmodified lines | ||
| 1367 | 1360 | |
| 1368 | 1361 | /* release resources */ |
| 1369 | 1362 | free_irq(pci_dev->irq, dev); |
| 1370 | − vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | |
| 1371 | 1363 | iounmap(dev->lmmio); |
| 1372 | 1364 | release_mem_region(pci_resource_start(pci_dev,0), |
| 1373 | 1365 | pci_resource_len(pci_dev,0)); |
| @@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(saa7134_ts_buffer_prepare); · 117 unmodified lines | ||
| 118 | 118 | |
| 119 | 119 | int saa7134_ts_queue_setup(struct vb2_queue *q, |
| 120 | 120 | unsigned int *nbuffers, unsigned int *nplanes, |
| 121 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 121 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 122 | 122 | { |
| 123 | 123 | struct saa7134_dmaqueue *dmaq = q->drv_priv; |
| 124 | 124 | struct saa7134_dev *dev = dmaq->dev; |
| @@ -131,7 +131,6 @@ int saa7134_ts_queue_setup(struct vb2_queue *q, · 6 unmodified lines | ||
| 131 | 131 | *nbuffers = 3; |
| 132 | 132 | *nplanes = 1; |
| 133 | 133 | sizes[0] = size; |
| 134 | − alloc_ctxs[0] = dev->alloc_ctx; | |
| 135 | 134 | return 0; |
| 136 | 135 | } |
| 137 | 136 | EXPORT_SYMBOL_GPL(saa7134_ts_queue_setup); |
| @@ -140,7 +140,7 @@ static int buffer_prepare(struct vb2_buffer *vb2) · 139 unmodified lines | ||
| 140 | 140 | |
| 141 | 141 | static int queue_setup(struct vb2_queue *q, |
| 142 | 142 | unsigned int *nbuffers, unsigned int *nplanes, |
| 143 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 143 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 144 | 144 | { |
| 145 | 145 | struct saa7134_dmaqueue *dmaq = q->drv_priv; |
| 146 | 146 | struct saa7134_dev *dev = dmaq->dev; |
| @@ -155,7 +155,6 @@ static int queue_setup(struct vb2_queue *q, · 8 unmodified lines | ||
| 155 | 155 | *nbuffers = saa7134_buffer_count(size, *nbuffers); |
| 156 | 156 | *nplanes = 1; |
| 157 | 157 | sizes[0] = size; |
| 158 | − alloc_ctxs[0] = dev->alloc_ctx; | |
| 159 | 158 | return 0; |
| 160 | 159 | } |
| 161 | 160 | |
| @@ -963,7 +963,7 @@ static int buffer_prepare(struct vb2_buffer *vb2) · 962 unmodified lines | ||
| 963 | 963 | |
| 964 | 964 | static int queue_setup(struct vb2_queue *q, |
| 965 | 965 | unsigned int *nbuffers, unsigned int *nplanes, |
| 966 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 966 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 967 | 967 | { |
| 968 | 968 | struct saa7134_dmaqueue *dmaq = q->drv_priv; |
| 969 | 969 | struct saa7134_dev *dev = dmaq->dev; |
| @@ -980,7 +980,6 @@ static int queue_setup(struct vb2_queue *q, · 10 unmodified lines | ||
| 980 | 980 | *nbuffers = saa7134_buffer_count(size, *nbuffers); |
| 981 | 981 | *nplanes = 1; |
| 982 | 982 | sizes[0] = size; |
| 983 | − alloc_ctxs[0] = dev->alloc_ctx; | |
| 984 | 983 | |
| 985 | 984 | saa7134_enable_analog_tuner(dev); |
| 986 | 985 | |
| @@ -2173,6 +2172,7 @@ int saa7134_video_init1(struct saa7134_dev *dev) · 1186 unmodified lines | ||
| 2173 | 2172 | q->buf_struct_size = sizeof(struct saa7134_buf); |
| 2174 | 2173 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 2175 | 2174 | q->lock = &dev->lock; |
| 2175 | + q->dev = &dev->pci->dev; | |
| 2176 | 2176 | ret = vb2_queue_init(q); |
| 2177 | 2177 | if (ret) |
| 2178 | 2178 | return ret; |
| @@ -2191,6 +2191,7 @@ int saa7134_video_init1(struct saa7134_dev *dev) · 12 unmodified lines | ||
| 2191 | 2191 | q->buf_struct_size = sizeof(struct saa7134_buf); |
| 2192 | 2192 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 2193 | 2193 | q->lock = &dev->lock; |
| 2194 | + q->dev = &dev->pci->dev; | |
| 2194 | 2195 | ret = vb2_queue_init(q); |
| 2195 | 2196 | if (ret) |
| 2196 | 2197 | return ret; |
| @@ -610,7 +610,6 @@ struct saa7134_dev { · 609 unmodified lines | ||
| 610 | 610 | |
| 611 | 611 | |
| 612 | 612 | /* video+ts+vbi capture */ |
| 613 | − void *alloc_ctx; | |
| 614 | 613 | struct saa7134_dmaqueue video_q; |
| 615 | 614 | struct vb2_queue video_vbq; |
| 616 | 615 | struct saa7134_dmaqueue vbi_q; |
| @@ -854,7 +853,7 @@ int saa7134_ts_buffer_init(struct vb2_buffer *vb2); · 237 unmodified lines | ||
| 854 | 853 | int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2); |
| 855 | 854 | int saa7134_ts_queue_setup(struct vb2_queue *q, |
| 856 | 855 | unsigned int *nbuffers, unsigned int *nplanes, |
| 857 | − unsigned int sizes[], void *alloc_ctxs[]); | |
| 856 | + unsigned int sizes[], struct device *alloc_devs[]); | |
| 858 | 857 | int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count); |
| 859 | 858 | void saa7134_ts_stop_streaming(struct vb2_queue *vq); |
| 860 | 859 | |
| @@ -1022,8 +1022,7 @@ int saa7164_encoder_register(struct saa7164_port *port) · 1021 unmodified lines | ||
| 1022 | 1022 | |
| 1023 | 1023 | dprintk(DBGLVL_ENC, "%s()\n", __func__); |
| 1024 | 1024 | |
| 1025 | − if (port->type != SAA7164_MPEG_ENCODER) | |
| 1026 | − BUG(); | |
| 1025 | + BUG_ON(port->type != SAA7164_MPEG_ENCODER); | |
| 1027 | 1026 | |
| 1028 | 1027 | /* Sanity check that the PCI configuration space is active */ |
| 1029 | 1028 | if (port->hwcfg.BARLocation == 0) { |
| @@ -1151,8 +1150,7 @@ void saa7164_encoder_unregister(struct saa7164_port *port) · 121 unmodified lines | ||
| 1151 | 1150 | |
| 1152 | 1151 | dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr); |
| 1153 | 1152 | |
| 1154 | − if (port->type != SAA7164_MPEG_ENCODER) | |
| 1155 | − BUG(); | |
| 1153 | + BUG_ON(port->type != SAA7164_MPEG_ENCODER); | |
| 1156 | 1154 | |
| 1157 | 1155 | if (port->v4l_device) { |
| 1158 | 1156 | if (port->v4l_device->minor != -1) |
| @@ -263,10 +263,6 @@ struct saa7164_i2c { · 262 unmodified lines | ||
| 263 | 263 | u32 i2c_rc; |
| 264 | 264 | }; |
| 265 | 265 | |
| 266 | −struct saa7164_ctrl { | |
| 267 | − struct v4l2_queryctrl v; | |
| 268 | −}; | |
| 269 | − | |
| 270 | 266 | struct saa7164_tvnorm { |
| 271 | 267 | char *name; |
| 272 | 268 | v4l2_std_id id; |
| @@ -33,7 +33,7 @@ · 32 unmodified lines | ||
| 33 | 33 | #include "solo6x10-jpeg.h" |
| 34 | 34 | |
| 35 | 35 | #define MIN_VID_BUFFERS 2 |
| 36 | −#define FRAME_BUF_SIZE (196 * 1024) | |
| 36 | +#define FRAME_BUF_SIZE (400 * 1024) | |
| 37 | 37 | #define MP4_QS 16 |
| 38 | 38 | #define DMA_ALIGN 4096 |
| 39 | 39 | |
| @@ -664,12 +664,9 @@ static int solo_ring_thread(void *data) · 624 unmodified lines | ||
| 664 | 664 | static int solo_enc_queue_setup(struct vb2_queue *q, |
| 665 | 665 | unsigned int *num_buffers, |
| 666 | 666 | unsigned int *num_planes, unsigned int sizes[], |
| 667 | − void *alloc_ctxs[]) | |
| 667 | + struct device *alloc_devs[]) | |
| 668 | 668 | { |
| 669 | − struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q); | |
| 670 | − | |
| 671 | 669 | sizes[0] = FRAME_BUF_SIZE; |
| 672 | − alloc_ctxs[0] = solo_enc->alloc_ctx; | |
| 673 | 670 | *num_planes = 1; |
| 674 | 671 | |
| 675 | 672 | if (*num_buffers < MIN_VID_BUFFERS) |
| @@ -1239,11 +1236,6 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, · 563 unmodified lines | ||
| 1239 | 1236 | return ERR_PTR(-ENOMEM); |
| 1240 | 1237 | |
| 1241 | 1238 | hdl = &solo_enc->hdl; |
| 1242 | − solo_enc->alloc_ctx = vb2_dma_sg_init_ctx(&solo_dev->pdev->dev); | |
| 1243 | − if (IS_ERR(solo_enc->alloc_ctx)) { | |
| 1244 | − ret = PTR_ERR(solo_enc->alloc_ctx); | |
| 1245 | − goto hdl_free; | |
| 1246 | − } | |
| 1247 | 1239 | v4l2_ctrl_handler_init(hdl, 10); |
| 1248 | 1240 | v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, |
| 1249 | 1241 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); |
| @@ -1299,6 +1291,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, · 49 unmodified lines | ||
| 1299 | 1291 | solo_enc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1300 | 1292 | solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); |
| 1301 | 1293 | solo_enc->vidq.lock = &solo_enc->lock; |
| 1294 | + solo_enc->vidq.dev = &solo_dev->pdev->dev; | |
| 1302 | 1295 | ret = vb2_queue_init(&solo_enc->vidq); |
| 1303 | 1296 | if (ret) |
| 1304 | 1297 | goto hdl_free; |
| @@ -1347,7 +1340,6 @@ pci_free: · 42 unmodified lines | ||
| 1347 | 1340 | solo_enc->desc_items, solo_enc->desc_dma); |
| 1348 | 1341 | hdl_free: |
| 1349 | 1342 | v4l2_ctrl_handler_free(hdl); |
| 1350 | − vb2_dma_sg_cleanup_ctx(solo_enc->alloc_ctx); | |
| 1351 | 1343 | kfree(solo_enc); |
| 1352 | 1344 | return ERR_PTR(ret); |
| 1353 | 1345 | } |
| @@ -1362,7 +1354,6 @@ static void solo_enc_free(struct solo_enc_dev *solo_enc) · 8 unmodified lines | ||
| 1362 | 1354 | solo_enc->desc_items, solo_enc->desc_dma); |
| 1363 | 1355 | video_unregister_device(solo_enc->vfd); |
| 1364 | 1356 | v4l2_ctrl_handler_free(&solo_enc->hdl); |
| 1365 | − vb2_dma_sg_cleanup_ctx(solo_enc->alloc_ctx); | |
| 1366 | 1357 | kfree(solo_enc); |
| 1367 | 1358 | } |
| 1368 | 1359 | |
| @@ -315,12 +315,11 @@ static void solo_stop_thread(struct solo_dev *solo_dev) · 314 unmodified lines | ||
| 315 | 315 | |
| 316 | 316 | static int solo_queue_setup(struct vb2_queue *q, |
| 317 | 317 | unsigned int *num_buffers, unsigned int *num_planes, |
| 318 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 318 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 319 | 319 | { |
| 320 | 320 | struct solo_dev *solo_dev = vb2_get_drv_priv(q); |
| 321 | 321 | |
| 322 | 322 | sizes[0] = solo_image_size(solo_dev); |
| 323 | − alloc_ctxs[0] = solo_dev->alloc_ctx; | |
| 324 | 323 | *num_planes = 1; |
| 325 | 324 | |
| 326 | 325 | if (*num_buffers < MIN_VID_BUFFERS) |
| @@ -386,26 +385,24 @@ static int solo_querycap(struct file *file, void *priv, · 59 unmodified lines | ||
| 386 | 385 | static int solo_enum_ext_input(struct solo_dev *solo_dev, |
| 387 | 386 | struct v4l2_input *input) |
| 388 | 387 | { |
| 389 | − static const char * const dispnames_1[] = { "4UP" }; | |
| 390 | − static const char * const dispnames_2[] = { "4UP-1", "4UP-2" }; | |
| 391 | − static const char * const dispnames_5[] = { | |
| 392 | − "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP" | |
| 393 | − }; | |
| 394 | − const char * const *dispnames; | |
| 388 | + int ext = input->index - solo_dev->nr_chans; | |
| 389 | + unsigned int nup, first; | |
| 395 | 390 | |
| 396 | − if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext)) | |
| 391 | + if (ext >= solo_dev->nr_ext) | |
| 397 | 392 | return -EINVAL; |
| 398 | 393 | |
| 399 | − if (solo_dev->nr_ext == 5) | |
| 400 | − dispnames = dispnames_5; | |
| 401 | − else if (solo_dev->nr_ext == 2) | |
| 402 | − dispnames = dispnames_2; | |
| 403 | − else | |
| 404 | − dispnames = dispnames_1; | |
| 405 | − | |
| 406 | − snprintf(input->name, sizeof(input->name), "Multi %s", | |
| 407 | − dispnames[input->index - solo_dev->nr_chans]); | |
| 408 | − | |
| 394 | + nup = (ext == 4) ? 16 : 4; | |
| 395 | + first = (ext & 3) << 2; /* first channel in the n-up */ | |
| 396 | + snprintf(input->name, sizeof(input->name), | |
| 397 | + "Multi %d-up (cameras %d-%d)", | |
| 398 | + nup, first + 1, first + nup); | |
| 399 | + /* Possible outputs: | |
| 400 | + * Multi 4-up (cameras 1-4) | |
| 401 | + * Multi 4-up (cameras 5-8) | |
| 402 | + * Multi 4-up (cameras 9-12) | |
| 403 | + * Multi 4-up (cameras 13-16) | |
| 404 | + * Multi 16-up (cameras 1-16) | |
| 405 | + */ | |
| 409 | 406 | return 0; |
| 410 | 407 | } |
| 411 | 408 | |
| @@ -681,16 +678,11 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) · 269 unmodified lines | ||
| 681 | 678 | solo_dev->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM; |
| 682 | 679 | solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); |
| 683 | 680 | solo_dev->vidq.lock = &solo_dev->lock; |
| 681 | + solo_dev->vidq.dev = &solo_dev->pdev->dev; | |
| 684 | 682 | ret = vb2_queue_init(&solo_dev->vidq); |
| 685 | 683 | if (ret < 0) |
| 686 | 684 | goto fail; |
| 687 | 685 | |
| 688 | − solo_dev->alloc_ctx = vb2_dma_contig_init_ctx(&solo_dev->pdev->dev); | |
| 689 | − if (IS_ERR(solo_dev->alloc_ctx)) { | |
| 690 | − dev_err(&solo_dev->pdev->dev, "Can't allocate buffer context"); | |
| 691 | − return PTR_ERR(solo_dev->alloc_ctx); | |
| 692 | − } | |
| 693 | − | |
| 694 | 686 | /* Cycle all the channels and clear */ |
| 695 | 687 | for (i = 0; i < solo_dev->nr_chans; i++) { |
| 696 | 688 | solo_v4l2_set_ch(solo_dev, i); |
| @@ -718,7 +710,6 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) · 21 unmodified lines | ||
| 718 | 710 | |
| 719 | 711 | fail: |
| 720 | 712 | video_device_release(solo_dev->vfd); |
| 721 | − vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx); | |
| 722 | 713 | v4l2_ctrl_handler_free(&solo_dev->disp_hdl); |
| 723 | 714 | solo_dev->vfd = NULL; |
| 724 | 715 | return ret; |
| @@ -730,7 +721,6 @@ void solo_v4l2_exit(struct solo_dev *solo_dev) · 5 unmodified lines | ||
| 730 | 721 | return; |
| 731 | 722 | |
| 732 | 723 | video_unregister_device(solo_dev->vfd); |
| 733 | − vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx); | |
| 734 | 724 | v4l2_ctrl_handler_free(&solo_dev->disp_hdl); |
| 735 | 725 | solo_dev->vfd = NULL; |
| 736 | 726 | } |
| @@ -178,7 +178,6 @@ struct solo_enc_dev { · 177 unmodified lines | ||
| 178 | 178 | u32 sequence; |
| 179 | 179 | struct vb2_queue vidq; |
| 180 | 180 | struct list_head vidq_active; |
| 181 | − void *alloc_ctx; | |
| 182 | 181 | int desc_count; |
| 183 | 182 | int desc_nelts; |
| 184 | 183 | struct solo_p2m_desc *desc_items; |
| @@ -269,7 +268,6 @@ struct solo_dev { · 84 unmodified lines | ||
| 269 | 268 | |
| 270 | 269 | /* Buffer handling */ |
| 271 | 270 | struct vb2_queue vidq; |
| 272 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 273 | 271 | u32 sequence; |
| 274 | 272 | struct task_struct *kthread; |
| 275 | 273 | struct mutex lock; |
| @@ -111,7 +111,6 @@ static inline struct vip_buffer *to_vip_buffer(struct vb2_v4l2_buffer *vb2) · 110 unmodified lines | ||
| 111 | 111 | * @input: input line for video signal ( 0 or 1 ) |
| 112 | 112 | * @disabled: Device is in power down state |
| 113 | 113 | * @slock: for excluse acces of registers |
| 114 | − * @alloc_ctx: context for videobuf2 | |
| 115 | 114 | * @vb_vidq: queue maintained by videobuf2 layer |
| 116 | 115 | * @buffer_list: list of buffer in use |
| 117 | 116 | * @sequence: sequence number of acquired buffer |
| @@ -141,7 +140,6 @@ struct sta2x11_vip { · 23 unmodified lines | ||
| 141 | 140 | int disabled; |
| 142 | 141 | spinlock_t slock; |
| 143 | 142 | |
| 144 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 145 | 143 | struct vb2_queue vb_vidq; |
| 146 | 144 | struct list_head buffer_list; |
| 147 | 145 | unsigned int sequence; |
| @@ -267,7 +265,7 @@ static void vip_active_buf_next(struct sta2x11_vip *vip) · 119 unmodified lines | ||
| 267 | 265 | /* Videobuf2 Operations */ |
| 268 | 266 | static int queue_setup(struct vb2_queue *vq, |
| 269 | 267 | unsigned int *nbuffers, unsigned int *nplanes, |
| 270 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 268 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 271 | 269 | { |
| 272 | 270 | struct sta2x11_vip *vip = vb2_get_drv_priv(vq); |
| 273 | 271 | |
| @@ -276,7 +274,6 @@ static int queue_setup(struct vb2_queue *vq, · 2 unmodified lines | ||
| 276 | 274 | |
| 277 | 275 | *nplanes = 1; |
| 278 | 276 | sizes[0] = vip->format.sizeimage; |
| 279 | − alloc_ctxs[0] = vip->alloc_ctx; | |
| 280 | 277 | |
| 281 | 278 | vip->sequence = 0; |
| 282 | 279 | vip->active = NULL; |
| @@ -861,25 +858,15 @@ static int sta2x11_vip_init_buffer(struct sta2x11_vip *vip) · 578 unmodified lines | ||
| 861 | 858 | vip->vb_vidq.ops = &vip_video_qops; |
| 862 | 859 | vip->vb_vidq.mem_ops = &vb2_dma_contig_memops; |
| 863 | 860 | vip->vb_vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 861 | + vip->vb_vidq.dev = &vip->pdev->dev; | |
| 864 | 862 | err = vb2_queue_init(&vip->vb_vidq); |
| 865 | 863 | if (err) |
| 866 | 864 | return err; |
| 867 | 865 | INIT_LIST_HEAD(&vip->buffer_list); |
| 868 | 866 | spin_lock_init(&vip->lock); |
| 869 | − | |
| 870 | − | |
| 871 | − vip->alloc_ctx = vb2_dma_contig_init_ctx(&vip->pdev->dev); | |
| 872 | − if (IS_ERR(vip->alloc_ctx)) { | |
| 873 | − v4l2_err(&vip->v4l2_dev, "Can't allocate buffer context"); | |
| 874 | − return PTR_ERR(vip->alloc_ctx); | |
| 875 | − } | |
| 876 | − | |
| 877 | 867 | return 0; |
| 878 | 868 | } |
| 879 | −static void sta2x11_vip_release_buffer(struct sta2x11_vip *vip) | |
| 880 | −{ | |
| 881 | − vb2_dma_contig_cleanup_ctx(vip->alloc_ctx); | |
| 882 | −} | |
| 869 | + | |
| 883 | 870 | static int sta2x11_vip_init_controls(struct sta2x11_vip *vip) |
| 884 | 871 | { |
| 885 | 872 | /* |
| @@ -1120,7 +1107,6 @@ vrelease: · 234 unmodified lines | ||
| 1120 | 1107 | video_unregister_device(&vip->video_dev); |
| 1121 | 1108 | free_irq(pdev->irq, vip); |
| 1122 | 1109 | release_buf: |
| 1123 | − sta2x11_vip_release_buffer(vip); | |
| 1124 | 1110 | pci_disable_msi(pdev); |
| 1125 | 1111 | unmap: |
| 1126 | 1112 | vb2_queue_release(&vip->vb_vidq); |
| @@ -305,19 +305,13 @@ static int tw68_initdev(struct pci_dev *pci_dev, · 304 unmodified lines | ||
| 305 | 305 | /* Then do any initialisation wanted before interrupts are on */ |
| 306 | 306 | tw68_hw_init1(dev); |
| 307 | 307 | |
| 308 | − dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); | |
| 309 | − if (IS_ERR(dev->alloc_ctx)) { | |
| 310 | − err = PTR_ERR(dev->alloc_ctx); | |
| 311 | − goto fail3; | |
| 312 | − } | |
| 313 | − | |
| 314 | 308 | /* get irq */ |
| 315 | 309 | err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq, |
| 316 | 310 | IRQF_SHARED, dev->name, dev); |
| 317 | 311 | if (err < 0) { |
| 318 | 312 | pr_err("%s: can't get IRQ %d\n", |
| 319 | 313 | dev->name, pci_dev->irq); |
| 320 | − goto fail4; | |
| 314 | + goto fail3; | |
| 321 | 315 | } |
| 322 | 316 | |
| 323 | 317 | /* |
| @@ -331,7 +325,7 @@ static int tw68_initdev(struct pci_dev *pci_dev, · 7 unmodified lines | ||
| 331 | 325 | if (err < 0) { |
| 332 | 326 | pr_err("%s: can't register video device\n", |
| 333 | 327 | dev->name); |
| 334 | − goto fail5; | |
| 328 | + goto fail4; | |
| 335 | 329 | } |
| 336 | 330 | tw_setl(TW68_INTMASK, dev->pci_irqmask); |
| 337 | 331 | |
| @@ -340,10 +334,8 @@ static int tw68_initdev(struct pci_dev *pci_dev, · 2 unmodified lines | ||
| 340 | 334 | |
| 341 | 335 | return 0; |
| 342 | 336 | |
| 343 | −fail5: | |
| 344 | − video_unregister_device(&dev->vdev); | |
| 345 | 337 | fail4: |
| 346 | − vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | |
| 338 | + video_unregister_device(&dev->vdev); | |
| 347 | 339 | fail3: |
| 348 | 340 | iounmap(dev->lmmio); |
| 349 | 341 | fail2: |
| @@ -367,7 +359,6 @@ static void tw68_finidev(struct pci_dev *pci_dev) · 17 unmodified lines | ||
| 367 | 359 | /* unregister */ |
| 368 | 360 | video_unregister_device(&dev->vdev); |
| 369 | 361 | v4l2_ctrl_handler_free(&dev->hdl); |
| 370 | − vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | |
| 371 | 362 | |
| 372 | 363 | /* release resources */ |
| 373 | 364 | iounmap(dev->lmmio); |
| @@ -378,7 +378,7 @@ static int tw68_buffer_count(unsigned int size, unsigned int count) · 377 unmodified lines | ||
| 378 | 378 | |
| 379 | 379 | static int tw68_queue_setup(struct vb2_queue *q, |
| 380 | 380 | unsigned int *num_buffers, unsigned int *num_planes, |
| 381 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 381 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 382 | 382 | { |
| 383 | 383 | struct tw68_dev *dev = vb2_get_drv_priv(q); |
| 384 | 384 | unsigned tot_bufs = q->num_buffers + *num_buffers; |
| @@ -388,7 +388,6 @@ static int tw68_queue_setup(struct vb2_queue *q, · 3 unmodified lines | ||
| 388 | 388 | tot_bufs = 2; |
| 389 | 389 | tot_bufs = tw68_buffer_count(size, tot_bufs); |
| 390 | 390 | *num_buffers = tot_bufs - q->num_buffers; |
| 391 | − alloc_ctxs[0] = dev->alloc_ctx; | |
| 392 | 391 | /* |
| 393 | 392 | * We allow create_bufs, but only if the sizeimage is >= as the |
| 394 | 393 | * current sizeimage. The tw68_buffer_count calculation becomes quite |
| @@ -983,6 +982,7 @@ int tw68_video_init2(struct tw68_dev *dev, int video_nr) · 588 unmodified lines | ||
| 983 | 982 | dev->vidq.buf_struct_size = sizeof(struct tw68_buf); |
| 984 | 983 | dev->vidq.lock = &dev->lock; |
| 985 | 984 | dev->vidq.min_buffers_needed = 2; |
| 985 | + dev->vidq.dev = &dev->pci->dev; | |
| 986 | 986 | ret = vb2_queue_init(&dev->vidq); |
| 987 | 987 | if (ret) |
| 988 | 988 | return ret; |
| @@ -165,7 +165,6 @@ struct tw68_dev { · 164 unmodified lines | ||
| 165 | 165 | unsigned field; |
| 166 | 166 | struct vb2_queue vidq; |
| 167 | 167 | struct list_head active; |
| 168 | − void *alloc_ctx; | |
| 169 | 168 | |
| 170 | 169 | /* various v4l controls */ |
| 171 | 170 | const struct tw68_tvnorm *tvnorm; /* video */ |
| @@ -3,6 +3,8 @@ config VIDEO_TW686X · 2 unmodified lines | ||
| 3 | 3 | depends on PCI && VIDEO_DEV && VIDEO_V4L2 && SND |
| 4 | 4 | depends on HAS_DMA |
| 5 | 5 | select VIDEOBUF2_VMALLOC |
| 6 | + select VIDEOBUF2_DMA_CONTIG | |
| 7 | + select VIDEOBUF2_DMA_SG | |
| 6 | 8 | select SND_PCM |
| 7 | 9 | help |
| 8 | 10 | Support for Intersil/Techwell TW686x-based frame grabber cards. |
| @@ -62,12 +62,22 @@ void tw686x_audio_irq(struct tw686x_dev *dev, unsigned long requests, · 61 unmodified lines | ||
| 62 | 62 | } |
| 63 | 63 | spin_unlock_irqrestore(&ac->lock, flags); |
| 64 | 64 | |
| 65 | + if (!done || !next) | |
| 66 | + continue; | |
| 67 | + /* | |
| 68 | + * Checking for a non-nil dma_desc[pb]->virt buffer is | |
| 69 | + * the same as checking for memcpy DMA mode. | |
| 70 | + */ | |
| 65 | 71 | desc = &ac->dma_descs[pb]; |
| 66 | − if (done && next && desc->virt) { | |
| 67 | − memcpy(done->virt, desc->virt, desc->size); | |
| 68 | − ac->ptr = done->dma - ac->buf[0].dma; | |
| 69 | − snd_pcm_period_elapsed(ac->ss); | |
| 72 | + if (desc->virt) { | |
| 73 | + memcpy(done->virt, desc->virt, | |
| 74 | + dev->period_size); | |
| 75 | + } else { | |
| 76 | + u32 reg = pb ? ADMA_B_ADDR[ch] : ADMA_P_ADDR[ch]; | |
| 77 | + reg_write(dev, reg, next->dma); | |
| 70 | 78 | } |
| 79 | + ac->ptr = done->dma - ac->buf[0].dma; | |
| 80 | + snd_pcm_period_elapsed(ac->ss); | |
| 71 | 81 | } |
| 72 | 82 | } |
| 73 | 83 | |
| @@ -83,10 +93,9 @@ static int tw686x_pcm_hw_free(struct snd_pcm_substream *ss) · 9 unmodified lines | ||
| 83 | 93 | } |
| 84 | 94 | |
| 85 | 95 | /* |
| 86 | − * The audio device rate is global and shared among all | |
| 87 | − * capture channels. The driver makes no effort to prevent | |
| 88 | − * rate modifications. User is free change the rate, but it | |
| 89 | − * means changing the rate for all capture sub-devices. | |
| 96 | + * Audio parameters are global and shared among all | |
| 97 | + * capture channels. The driver prevents changes to | |
| 98 | + * the parameters if any audio channel is capturing. | |
| 90 | 99 | */ |
| 91 | 100 | static const struct snd_pcm_hardware tw686x_capture_hw = { |
| 92 | 101 | .info = (SNDRV_PCM_INFO_MMAP | |
| @@ -99,9 +108,9 @@ static const struct snd_pcm_hardware tw686x_capture_hw = { · 6 unmodified lines | ||
| 99 | 108 | .rate_max = 48000, |
| 100 | 109 | .channels_min = 1, |
| 101 | 110 | .channels_max = 1, |
| 102 | − .buffer_bytes_max = TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ, | |
| 103 | − .period_bytes_min = TW686X_AUDIO_PAGE_SZ, | |
| 104 | − .period_bytes_max = TW686X_AUDIO_PAGE_SZ, | |
| 111 | + .buffer_bytes_max = TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX, | |
| 112 | + .period_bytes_min = AUDIO_DMA_SIZE_MIN, | |
| 113 | + .period_bytes_max = AUDIO_DMA_SIZE_MAX, | |
| 105 | 114 | .periods_min = TW686X_AUDIO_PERIODS_MIN, |
| 106 | 115 | .periods_max = TW686X_AUDIO_PERIODS_MAX, |
| 107 | 116 | }; |
| @@ -143,6 +152,14 @@ static int tw686x_pcm_prepare(struct snd_pcm_substream *ss) · 35 unmodified lines | ||
| 143 | 152 | int i; |
| 144 | 153 | |
| 145 | 154 | spin_lock_irqsave(&dev->lock, flags); |
| 155 | + /* | |
| 156 | + * Given the audio parameters are global (i.e. shared across | |
| 157 | + * DMA channels), we need to check new params are allowed. | |
| 158 | + */ | |
| 159 | + if (((dev->audio_rate != rt->rate) || | |
| 160 | + (dev->period_size != period_size)) && dev->audio_enabled) | |
| 161 | + goto err_audio_busy; | |
| 162 | + | |
| 146 | 163 | tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch); |
| 147 | 164 | spin_unlock_irqrestore(&dev->lock, flags); |
| 148 | 165 | |
| @@ -156,12 +173,21 @@ static int tw686x_pcm_prepare(struct snd_pcm_substream *ss) · 7 unmodified lines | ||
| 156 | 173 | reg_write(dev, AUDIO_CONTROL2, reg); |
| 157 | 174 | } |
| 158 | 175 | |
| 159 | − if (period_size != TW686X_AUDIO_PAGE_SZ || | |
| 160 | − rt->periods < TW686X_AUDIO_PERIODS_MIN || | |
| 161 | − rt->periods > TW686X_AUDIO_PERIODS_MAX) { | |
| 162 | − return -EINVAL; | |
| 176 | + if (dev->period_size != period_size) { | |
| 177 | + u32 reg; | |
| 178 | + | |
| 179 | + dev->period_size = period_size; | |
| 180 | + reg = reg_read(dev, AUDIO_CONTROL1); | |
| 181 | + reg &= ~(AUDIO_DMA_SIZE_MASK << AUDIO_DMA_SIZE_SHIFT); | |
| 182 | + reg |= period_size << AUDIO_DMA_SIZE_SHIFT; | |
| 183 | + | |
| 184 | + reg_write(dev, AUDIO_CONTROL1, reg); | |
| 163 | 185 | } |
| 164 | 186 | |
| 187 | + if (rt->periods < TW686X_AUDIO_PERIODS_MIN || | |
| 188 | + rt->periods > TW686X_AUDIO_PERIODS_MAX) | |
| 189 | + return -EINVAL; | |
| 190 | + | |
| 165 | 191 | spin_lock_irqsave(&ac->lock, flags); |
| 166 | 192 | INIT_LIST_HEAD(&ac->buf_list); |
| 167 | 193 | |
| @@ -181,9 +207,19 @@ static int tw686x_pcm_prepare(struct snd_pcm_substream *ss) · 13 unmodified lines | ||
| 181 | 207 | ac->curr_bufs[0] = p_buf; |
| 182 | 208 | ac->curr_bufs[1] = b_buf; |
| 183 | 209 | ac->ptr = 0; |
| 210 | + | |
| 211 | + if (dev->dma_mode != TW686X_DMA_MODE_MEMCPY) { | |
| 212 | + reg_write(dev, ADMA_P_ADDR[ac->ch], p_buf->dma); | |
| 213 | + reg_write(dev, ADMA_B_ADDR[ac->ch], b_buf->dma); | |
| 214 | + } | |
| 215 | + | |
| 184 | 216 | spin_unlock_irqrestore(&ac->lock, flags); |
| 185 | 217 | |
| 186 | 218 | return 0; |
| 219 | + | |
| 220 | +err_audio_busy: | |
| 221 | + spin_unlock_irqrestore(&dev->lock, flags); | |
| 222 | + return -EBUSY; | |
| 187 | 223 | } |
| 188 | 224 | |
| 189 | 225 | static int tw686x_pcm_trigger(struct snd_pcm_substream *ss, int cmd) |
| @@ -197,6 +233,7 @@ static int tw686x_pcm_trigger(struct snd_pcm_substream *ss, int cmd) · 7 unmodified lines | ||
| 197 | 233 | case SNDRV_PCM_TRIGGER_START: |
| 198 | 234 | if (ac->curr_bufs[0] && ac->curr_bufs[1]) { |
| 199 | 235 | spin_lock_irqsave(&dev->lock, flags); |
| 236 | + dev->audio_enabled = 1; | |
| 200 | 237 | tw686x_enable_channel(dev, |
| 201 | 238 | AUDIO_CHANNEL_OFFSET + ac->ch); |
| 202 | 239 | spin_unlock_irqrestore(&dev->lock, flags); |
| @@ -209,6 +246,7 @@ static int tw686x_pcm_trigger(struct snd_pcm_substream *ss, int cmd) · 6 unmodified lines | ||
| 209 | 246 | break; |
| 210 | 247 | case SNDRV_PCM_TRIGGER_STOP: |
| 211 | 248 | spin_lock_irqsave(&dev->lock, flags); |
| 249 | + dev->audio_enabled = 0; | |
| 212 | 250 | tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch); |
| 213 | 251 | spin_unlock_irqrestore(&dev->lock, flags); |
| 214 | 252 | |
| @@ -266,8 +304,8 @@ static int tw686x_snd_pcm_init(struct tw686x_dev *dev) · 51 unmodified lines | ||
| 266 | 304 | return snd_pcm_lib_preallocate_pages_for_all(pcm, |
| 267 | 305 | SNDRV_DMA_TYPE_DEV, |
| 268 | 306 | snd_dma_pci_data(dev->pci_dev), |
| 269 | − TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ, | |
| 270 | − TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ); | |
| 307 | + TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX, | |
| 308 | + TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX); | |
| 271 | 309 | } |
| 272 | 310 | |
| 273 | 311 | static void tw686x_audio_dma_free(struct tw686x_dev *dev, |
| @@ -290,11 +328,19 @@ static int tw686x_audio_dma_alloc(struct tw686x_dev *dev, · 16 unmodified lines | ||
| 290 | 328 | { |
| 291 | 329 | int pb; |
| 292 | 330 | |
| 331 | + /* | |
| 332 | + * In the memcpy DMA mode we allocate a consistent buffer | |
| 333 | + * and use it for the DMA capture. Otherwise, DMA | |
| 334 | + * acts on the ALSA buffers as received in pcm_prepare. | |
| 335 | + */ | |
| 336 | + if (dev->dma_mode != TW686X_DMA_MODE_MEMCPY) | |
| 337 | + return 0; | |
| 338 | + | |
| 293 | 339 | for (pb = 0; pb < 2; pb++) { |
| 294 | 340 | u32 reg = pb ? ADMA_B_ADDR[ac->ch] : ADMA_P_ADDR[ac->ch]; |
| 295 | 341 | void *virt; |
| 296 | 342 | |
| 297 | − virt = pci_alloc_consistent(dev->pci_dev, TW686X_AUDIO_PAGE_SZ, | |
| 343 | + virt = pci_alloc_consistent(dev->pci_dev, AUDIO_DMA_SIZE_MAX, | |
| 298 | 344 | &ac->dma_descs[pb].phys); |
| 299 | 345 | if (!virt) { |
| 300 | 346 | dev_err(&dev->pci_dev->dev, |
| @@ -303,7 +349,7 @@ static int tw686x_audio_dma_alloc(struct tw686x_dev *dev, · 2 unmodified lines | ||
| 303 | 349 | return -ENOMEM; |
| 304 | 350 | } |
| 305 | 351 | ac->dma_descs[pb].virt = virt; |
| 306 | − ac->dma_descs[pb].size = TW686X_AUDIO_PAGE_SZ; | |
| 352 | + ac->dma_descs[pb].size = AUDIO_DMA_SIZE_MAX; | |
| 307 | 353 | reg_write(dev, reg, ac->dma_descs[pb].phys); |
| 308 | 354 | } |
| 309 | 355 | return 0; |
| @@ -334,12 +380,8 @@ int tw686x_audio_init(struct tw686x_dev *dev) · 24 unmodified lines | ||
| 334 | 380 | struct snd_card *card; |
| 335 | 381 | int err, ch; |
| 336 | 382 | |
| 337 | − /* | |
| 338 | − * AUDIO_CONTROL1 | |
| 339 | − * DMA byte length [31:19] = 4096 (i.e. ALSA period) | |
| 340 | − * External audio enable [0] = enabled | |
| 341 | − */ | |
| 342 | − reg_write(dev, AUDIO_CONTROL1, 0x80000001); | |
| 383 | + /* Enable external audio */ | |
| 384 | + reg_write(dev, AUDIO_CONTROL1, BIT(0)); | |
| 343 | 385 | |
| 344 | 386 | err = snd_card_new(&pci_dev->dev, SNDRV_DEFAULT_IDX1, |
| 345 | 387 | SNDRV_DEFAULT_STR1, |
| @@ -21,12 +21,14 @@ · 20 unmodified lines | ||
| 21 | 21 | * under stress testings it has been found that the machine can |
| 22 | 22 | * freeze completely if DMA registers are programmed while streaming |
| 23 | 23 | * is active. |
| 24 | − * This driver tries to access hardware registers as infrequently | |
| 25 | − * as possible by: | |
| 26 | − * i. allocating fixed DMA buffers and memcpy'ing into | |
| 27 | − * vmalloc'ed buffers | |
| 28 | − * ii. using a timer to mitigate the rate of DMA reset operations, | |
| 29 | − * on DMA channels error. | |
| 24 | + * | |
| 25 | + * Therefore, driver implements a dma_mode called 'memcpy' which | |
| 26 | + * avoids cycling the DMA buffers, and insteads allocates extra DMA buffers | |
| 27 | + * and then copies into vmalloc'ed user buffers. | |
| 28 | + * | |
| 29 | + * In addition to this, when streaming is on, the driver tries to access | |
| 30 | + * hardware registers as infrequently as possible. This is done by using | |
| 31 | + * a timer to limit the rate at which DMA is reset on DMA channels error. | |
| 30 | 32 | */ |
| 31 | 33 | |
| 32 | 34 | #include <linux/init.h> |
| @@ -55,6 +57,42 @@ static u32 dma_interval = 0x00098968; · 22 unmodified lines | ||
| 55 | 57 | module_param(dma_interval, int, 0444); |
| 56 | 58 | MODULE_PARM_DESC(dma_interval, "Minimum time span for DMA interrupting host"); |
| 57 | 59 | |
| 60 | +static unsigned int dma_mode = TW686X_DMA_MODE_MEMCPY; | |
| 61 | +static const char *dma_mode_name(unsigned int mode) | |
| 62 | +{ | |
| 63 | + switch (mode) { | |
| 64 | + case TW686X_DMA_MODE_MEMCPY: | |
| 65 | + return "memcpy"; | |
| 66 | + case TW686X_DMA_MODE_CONTIG: | |
| 67 | + return "contig"; | |
| 68 | + case TW686X_DMA_MODE_SG: | |
| 69 | + return "sg"; | |
| 70 | + default: | |
| 71 | + return "unknown"; | |
| 72 | + } | |
| 73 | +} | |
| 74 | + | |
| 75 | +static int tw686x_dma_mode_get(char *buffer, struct kernel_param *kp) | |
| 76 | +{ | |
| 77 | + return sprintf(buffer, dma_mode_name(dma_mode)); | |
| 78 | +} | |
| 79 | + | |
| 80 | +static int tw686x_dma_mode_set(const char *val, struct kernel_param *kp) | |
| 81 | +{ | |
| 82 | + if (!strcasecmp(val, dma_mode_name(TW686X_DMA_MODE_MEMCPY))) | |
| 83 | + dma_mode = TW686X_DMA_MODE_MEMCPY; | |
| 84 | + else if (!strcasecmp(val, dma_mode_name(TW686X_DMA_MODE_CONTIG))) | |
| 85 | + dma_mode = TW686X_DMA_MODE_CONTIG; | |
| 86 | + else if (!strcasecmp(val, dma_mode_name(TW686X_DMA_MODE_SG))) | |
| 87 | + dma_mode = TW686X_DMA_MODE_SG; | |
| 88 | + else | |
| 89 | + return -EINVAL; | |
| 90 | + return 0; | |
| 91 | +} | |
| 92 | +module_param_call(dma_mode, tw686x_dma_mode_set, tw686x_dma_mode_get, | |
| 93 | + &dma_mode, S_IRUGO|S_IWUSR); | |
| 94 | +MODULE_PARM_DESC(dma_mode, "DMA operation mode (memcpy/contig/sg, default=memcpy)"); | |
| 95 | + | |
| 58 | 96 | void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel) |
| 59 | 97 | { |
| 60 | 98 | u32 dma_en = reg_read(dev, DMA_CHANNEL_ENABLE); |
| @@ -212,6 +250,7 @@ static int tw686x_probe(struct pci_dev *pci_dev, · 151 unmodified lines | ||
| 212 | 250 | if (!dev) |
| 213 | 251 | return -ENOMEM; |
| 214 | 252 | dev->type = pci_id->driver_data; |
| 253 | + dev->dma_mode = dma_mode; | |
| 215 | 254 | sprintf(dev->name, "tw%04X", pci_dev->device); |
| 216 | 255 | |
| 217 | 256 | dev->video_channels = kcalloc(max_channels(dev), |
| @@ -228,9 +267,10 @@ static int tw686x_probe(struct pci_dev *pci_dev, · 10 unmodified lines | ||
| 228 | 267 | goto free_video; |
| 229 | 268 | } |
| 230 | 269 | |
| 231 | − pr_info("%s: PCI %s, IRQ %d, MMIO 0x%lx\n", dev->name, | |
| 270 | + pr_info("%s: PCI %s, IRQ %d, MMIO 0x%lx (%s mode)\n", dev->name, | |
| 232 | 271 | pci_name(pci_dev), pci_dev->irq, |
| 233 | − (unsigned long)pci_resource_start(pci_dev, 0)); | |
| 272 | + (unsigned long)pci_resource_start(pci_dev, 0), | |
| 273 | + dma_mode_name(dma_mode)); | |
| 234 | 274 | |
| 235 | 275 | dev->pci_dev = pci_dev; |
| 236 | 276 | if (pci_enable_device(pci_dev)) { |
| @@ -105,6 +105,10 @@ · 104 unmodified lines | ||
| 105 | 105 | 0x2d0, 0x2d1, 0x2d2, 0x2d3 }) |
| 106 | 106 | |
| 107 | 107 | #define SYS_MODE_DMA_SHIFT 13 |
| 108 | +#define AUDIO_DMA_SIZE_SHIFT 19 | |
| 109 | +#define AUDIO_DMA_SIZE_MIN SZ_512 | |
| 110 | +#define AUDIO_DMA_SIZE_MAX SZ_4K | |
| 111 | +#define AUDIO_DMA_SIZE_MASK (SZ_8K - 1) | |
| 108 | 112 | |
| 109 | 113 | #define DMA_CMD_ENABLE BIT(31) |
| 110 | 114 | #define INT_STATUS_DMA_TOUT BIT(17) |
| @@ -119,4 +123,9 @@ · 8 unmodified lines | ||
| 119 | 123 | #define TW686X_STD_PAL_CN 5 |
| 120 | 124 | #define TW686X_STD_PAL_60 6 |
| 121 | 125 | |
| 126 | +#define TW686X_FIELD_MODE 0x3 | |
| 127 | +#define TW686X_FRAME_MODE 0x2 | |
| 128 | +/* 0x1 is reserved */ | |
| 129 | +#define TW686X_SG_MODE 0x0 | |
| 130 | + | |
| 122 | 131 | #define TW686X_FIFO_ERROR(x) (x & ~(0xff)) |
| @@ -19,6 +19,8 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <linux/slab.h> |
| 20 | 20 | #include <media/v4l2-common.h> |
| 21 | 21 | #include <media/v4l2-event.h> |
| 22 | +#include <media/videobuf2-dma-contig.h> | |
| 23 | +#include <media/videobuf2-dma-sg.h> | |
| 22 | 24 | #include <media/videobuf2-vmalloc.h> |
| 23 | 25 | #include "tw686x.h" |
| 24 | 26 | #include "tw686x-regs.h" |
| @@ -26,6 +28,11 @@ · 1 unmodified line | ||
| 26 | 28 | #define TW686X_INPUTS_PER_CH 4 |
| 27 | 29 | #define TW686X_VIDEO_WIDTH 720 |
| 28 | 30 | #define TW686X_VIDEO_HEIGHT(id) ((id & V4L2_STD_525_60) ? 480 : 576) |
| 31 | +#define TW686X_MAX_FPS(id) ((id & V4L2_STD_525_60) ? 30 : 25) | |
| 32 | + | |
| 33 | +#define TW686X_MAX_SG_ENTRY_SIZE 4096 | |
| 34 | +#define TW686X_MAX_SG_DESC_COUNT 256 /* PAL 720x576 needs 203 4-KB pages */ | |
| 35 | +#define TW686X_SG_TABLE_SIZE (TW686X_MAX_SG_DESC_COUNT * sizeof(struct tw686x_sg_desc)) | |
| 29 | 36 | |
| 30 | 37 | static const struct tw686x_format formats[] = { |
| 31 | 38 | { |
| @@ -43,53 +50,367 @@ static const struct tw686x_format formats[] = { · 11 unmodified lines | ||
| 43 | 50 | } |
| 44 | 51 | }; |
| 45 | 52 | |
| 46 | −static unsigned int tw686x_fields_map(v4l2_std_id std, unsigned int fps) | |
| 53 | +static void tw686x_buf_done(struct tw686x_video_channel *vc, | |
| 54 | + unsigned int pb) | |
| 47 | 55 | { |
| 48 | − static const unsigned int map[15] = { | |
| 49 | − 0x00000000, 0x00000001, 0x00004001, 0x00104001, 0x00404041, | |
| 50 | − 0x01041041, 0x01104411, 0x01111111, 0x04444445, 0x04511445, | |
| 51 | − 0x05145145, 0x05151515, 0x05515455, 0x05551555, 0x05555555 | |
| 52 | − }; | |
| 56 | + struct tw686x_dma_desc *desc = &vc->dma_descs[pb]; | |
| 57 | + struct tw686x_dev *dev = vc->dev; | |
| 58 | + struct vb2_v4l2_buffer *vb; | |
| 59 | + struct vb2_buffer *vb2_buf; | |
| 53 | 60 | |
| 54 | − static const unsigned int std_625_50[26] = { | |
| 55 | − 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, | |
| 56 | − 8, 8, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 0 | |
| 57 | − }; | |
| 61 | + if (vc->curr_bufs[pb]) { | |
| 62 | + vb = &vc->curr_bufs[pb]->vb; | |
| 58 | 63 | |
| 59 | − static const unsigned int std_525_60[31] = { | |
| 60 | − 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, | |
| 61 | − 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 0, 0 | |
| 62 | − }; | |
| 64 | + vb->field = dev->dma_ops->field; | |
| 65 | + vb->sequence = vc->sequence++; | |
| 66 | + vb2_buf = &vb->vb2_buf; | |
| 63 | 67 | |
| 64 | − unsigned int i; | |
| 68 | + if (dev->dma_mode == TW686X_DMA_MODE_MEMCPY) | |
| 69 | + memcpy(vb2_plane_vaddr(vb2_buf, 0), desc->virt, | |
| 70 | + desc->size); | |
| 71 | + vb2_buf->timestamp = ktime_get_ns(); | |
| 72 | + vb2_buffer_done(vb2_buf, VB2_BUF_STATE_DONE); | |
| 73 | + } | |
| 74 | + | |
| 75 | + vc->pb = !pb; | |
| 76 | +} | |
| 77 | + | |
| 78 | +/* | |
| 79 | + * We can call this even when alloc_dma failed for the given channel | |
| 80 | + */ | |
| 81 | +static void tw686x_memcpy_dma_free(struct tw686x_video_channel *vc, | |
| 82 | + unsigned int pb) | |
| 83 | +{ | |
| 84 | + struct tw686x_dma_desc *desc = &vc->dma_descs[pb]; | |
| 85 | + struct tw686x_dev *dev = vc->dev; | |
| 86 | + struct pci_dev *pci_dev; | |
| 87 | + unsigned long flags; | |
| 88 | + | |
| 89 | + /* Check device presence. Shouldn't really happen! */ | |
| 90 | + spin_lock_irqsave(&dev->lock, flags); | |
| 91 | + pci_dev = dev->pci_dev; | |
| 92 | + spin_unlock_irqrestore(&dev->lock, flags); | |
| 93 | + if (!pci_dev) { | |
| 94 | + WARN(1, "trying to deallocate on missing device\n"); | |
| 95 | + return; | |
| 96 | + } | |
| 97 | + | |
| 98 | + if (desc->virt) { | |
| 99 | + pci_free_consistent(dev->pci_dev, desc->size, | |
| 100 | + desc->virt, desc->phys); | |
| 101 | + desc->virt = NULL; | |
| 102 | + } | |
| 103 | +} | |
| 104 | + | |
| 105 | +static int tw686x_memcpy_dma_alloc(struct tw686x_video_channel *vc, | |
| 106 | + unsigned int pb) | |
| 107 | +{ | |
| 108 | + struct tw686x_dev *dev = vc->dev; | |
| 109 | + u32 reg = pb ? VDMA_B_ADDR[vc->ch] : VDMA_P_ADDR[vc->ch]; | |
| 110 | + unsigned int len; | |
| 111 | + void *virt; | |
| 112 | + | |
| 113 | + WARN(vc->dma_descs[pb].virt, | |
| 114 | + "Allocating buffer but previous still here\n"); | |
| 115 | + | |
| 116 | + len = (vc->width * vc->height * vc->format->depth) >> 3; | |
| 117 | + virt = pci_alloc_consistent(dev->pci_dev, len, | |
| 118 | + &vc->dma_descs[pb].phys); | |
| 119 | + if (!virt) { | |
| 120 | + v4l2_err(&dev->v4l2_dev, | |
| 121 | + "dma%d: unable to allocate %s-buffer\n", | |
| 122 | + vc->ch, pb ? "B" : "P"); | |
| 123 | + return -ENOMEM; | |
| 124 | + } | |
| 125 | + vc->dma_descs[pb].size = len; | |
| 126 | + vc->dma_descs[pb].virt = virt; | |
| 127 | + reg_write(dev, reg, vc->dma_descs[pb].phys); | |
| 128 | + | |
| 129 | + return 0; | |
| 130 | +} | |
| 131 | + | |
| 132 | +static void tw686x_memcpy_buf_refill(struct tw686x_video_channel *vc, | |
| 133 | + unsigned int pb) | |
| 134 | +{ | |
| 135 | + struct tw686x_v4l2_buf *buf; | |
| 136 | + | |
| 137 | + while (!list_empty(&vc->vidq_queued)) { | |
| 138 | + | |
| 139 | + buf = list_first_entry(&vc->vidq_queued, | |
| 140 | + struct tw686x_v4l2_buf, list); | |
| 141 | + list_del(&buf->list); | |
| 142 | + | |
| 143 | + vc->curr_bufs[pb] = buf; | |
| 144 | + return; | |
| 145 | + } | |
| 146 | + vc->curr_bufs[pb] = NULL; | |
| 147 | +} | |
| 65 | 148 | |
| 66 | − if (std & V4L2_STD_525_60) { | |
| 67 | − if (fps >= ARRAY_SIZE(std_525_60)) | |
| 68 | − fps = 30; | |
| 69 | − i = std_525_60[fps]; | |
| 149 | +static const struct tw686x_dma_ops memcpy_dma_ops = { | |
| 150 | + .alloc = tw686x_memcpy_dma_alloc, | |
| 151 | + .free = tw686x_memcpy_dma_free, | |
| 152 | + .buf_refill = tw686x_memcpy_buf_refill, | |
| 153 | + .mem_ops = &vb2_vmalloc_memops, | |
| 154 | + .hw_dma_mode = TW686X_FRAME_MODE, | |
| 155 | + .field = V4L2_FIELD_INTERLACED, | |
| 156 | +}; | |
| 157 | + | |
| 158 | +static void tw686x_contig_buf_refill(struct tw686x_video_channel *vc, | |
| 159 | + unsigned int pb) | |
| 160 | +{ | |
| 161 | + struct tw686x_v4l2_buf *buf; | |
| 162 | + | |
| 163 | + while (!list_empty(&vc->vidq_queued)) { | |
| 164 | + u32 reg = pb ? VDMA_B_ADDR[vc->ch] : VDMA_P_ADDR[vc->ch]; | |
| 165 | + dma_addr_t phys; | |
| 166 | + | |
| 167 | + buf = list_first_entry(&vc->vidq_queued, | |
| 168 | + struct tw686x_v4l2_buf, list); | |
| 169 | + list_del(&buf->list); | |
| 170 | + | |
| 171 | + phys = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); | |
| 172 | + reg_write(vc->dev, reg, phys); | |
| 173 | + | |
| 174 | + buf->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; | |
| 175 | + vc->curr_bufs[pb] = buf; | |
| 176 | + return; | |
| 177 | + } | |
| 178 | + vc->curr_bufs[pb] = NULL; | |
| 179 | +} | |
| 180 | + | |
| 181 | +static const struct tw686x_dma_ops contig_dma_ops = { | |
| 182 | + .buf_refill = tw686x_contig_buf_refill, | |
| 183 | + .mem_ops = &vb2_dma_contig_memops, | |
| 184 | + .hw_dma_mode = TW686X_FRAME_MODE, | |
| 185 | + .field = V4L2_FIELD_INTERLACED, | |
| 186 | +}; | |
| 187 | + | |
| 188 | +static int tw686x_sg_desc_fill(struct tw686x_sg_desc *descs, | |
| 189 | + struct tw686x_v4l2_buf *buf, | |
| 190 | + unsigned int buf_len) | |
| 191 | +{ | |
| 192 | + struct sg_table *vbuf = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0); | |
| 193 | + unsigned int len, entry_len; | |
| 194 | + struct scatterlist *sg; | |
| 195 | + int i, count; | |
| 196 | + | |
| 197 | + /* Clear the scatter-gather table */ | |
| 198 | + memset(descs, 0, TW686X_SG_TABLE_SIZE); | |
| 199 | + | |
| 200 | + count = 0; | |
| 201 | + for_each_sg(vbuf->sgl, sg, vbuf->nents, i) { | |
| 202 | + dma_addr_t phys = sg_dma_address(sg); | |
| 203 | + len = sg_dma_len(sg); | |
| 204 | + | |
| 205 | + while (len && buf_len) { | |
| 206 | + | |
| 207 | + if (count == TW686X_MAX_SG_DESC_COUNT) | |
| 208 | + return -ENOMEM; | |
| 209 | + | |
| 210 | + entry_len = min_t(unsigned int, len, | |
| 211 | + TW686X_MAX_SG_ENTRY_SIZE); | |
| 212 | + entry_len = min_t(unsigned int, entry_len, buf_len); | |
| 213 | + descs[count].phys = cpu_to_le32(phys); | |
| 214 | + descs[count++].flags_length = | |
| 215 | + cpu_to_le32(BIT(30) | entry_len); | |
| 216 | + phys += entry_len; | |
| 217 | + len -= entry_len; | |
| 218 | + buf_len -= entry_len; | |
| 219 | + } | |
| 220 | + | |
| 221 | + if (!buf_len) | |
| 222 | + return 0; | |
| 223 | + } | |
| 224 | + | |
| 225 | + return -ENOMEM; | |
| 226 | +} | |
| 227 | + | |
| 228 | +static void tw686x_sg_buf_refill(struct tw686x_video_channel *vc, | |
| 229 | + unsigned int pb) | |
| 230 | +{ | |
| 231 | + struct tw686x_dev *dev = vc->dev; | |
| 232 | + struct tw686x_v4l2_buf *buf; | |
| 233 | + | |
| 234 | + while (!list_empty(&vc->vidq_queued)) { | |
| 235 | + unsigned int buf_len; | |
| 236 | + | |
| 237 | + buf = list_first_entry(&vc->vidq_queued, | |
| 238 | + struct tw686x_v4l2_buf, list); | |
| 239 | + list_del(&buf->list); | |
| 240 | + | |
| 241 | + buf_len = (vc->width * vc->height * vc->format->depth) >> 3; | |
| 242 | + if (tw686x_sg_desc_fill(vc->sg_descs[pb], buf, buf_len)) { | |
| 243 | + v4l2_err(&dev->v4l2_dev, | |
| 244 | + "dma%d: unable to fill %s-buffer\n", | |
| 245 | + vc->ch, pb ? "B" : "P"); | |
| 246 | + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | |
| 247 | + continue; | |
| 248 | + } | |
| 249 | + | |
| 250 | + buf->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; | |
| 251 | + vc->curr_bufs[pb] = buf; | |
| 252 | + return; | |
| 253 | + } | |
| 254 | + | |
| 255 | + vc->curr_bufs[pb] = NULL; | |
| 256 | +} | |
| 257 | + | |
| 258 | +static void tw686x_sg_dma_free(struct tw686x_video_channel *vc, | |
| 259 | + unsigned int pb) | |
| 260 | +{ | |
| 261 | + struct tw686x_dma_desc *desc = &vc->dma_descs[pb]; | |
| 262 | + struct tw686x_dev *dev = vc->dev; | |
| 263 | + | |
| 264 | + if (desc->size) { | |
| 265 | + pci_free_consistent(dev->pci_dev, desc->size, | |
| 266 | + desc->virt, desc->phys); | |
| 267 | + desc->virt = NULL; | |
| 268 | + } | |
| 269 | + | |
| 270 | + vc->sg_descs[pb] = NULL; | |
| 271 | +} | |
| 272 | + | |
| 273 | +static int tw686x_sg_dma_alloc(struct tw686x_video_channel *vc, | |
| 274 | + unsigned int pb) | |
| 275 | +{ | |
| 276 | + struct tw686x_dma_desc *desc = &vc->dma_descs[pb]; | |
| 277 | + struct tw686x_dev *dev = vc->dev; | |
| 278 | + u32 reg = pb ? DMA_PAGE_TABLE1_ADDR[vc->ch] : | |
| 279 | + DMA_PAGE_TABLE0_ADDR[vc->ch]; | |
| 280 | + void *virt; | |
| 281 | + | |
| 282 | + if (desc->size) { | |
| 283 | + | |
| 284 | + virt = pci_alloc_consistent(dev->pci_dev, desc->size, | |
| 285 | + &desc->phys); | |
| 286 | + if (!virt) { | |
| 287 | + v4l2_err(&dev->v4l2_dev, | |
| 288 | + "dma%d: unable to allocate %s-buffer\n", | |
| 289 | + vc->ch, pb ? "B" : "P"); | |
| 290 | + return -ENOMEM; | |
| 291 | + } | |
| 292 | + desc->virt = virt; | |
| 293 | + reg_write(dev, reg, desc->phys); | |
| 70 | 294 | } else { |
| 71 | − if (fps >= ARRAY_SIZE(std_625_50)) | |
| 72 | − fps = 25; | |
| 73 | − i = std_625_50[fps]; | |
| 295 | + virt = dev->video_channels[0].dma_descs[pb].virt + | |
| 296 | + vc->ch * TW686X_SG_TABLE_SIZE; | |
| 74 | 297 | } |
| 75 | 298 | |
| 76 | − return map[i]; | |
| 299 | + vc->sg_descs[pb] = virt; | |
| 300 | + return 0; | |
| 301 | +} | |
| 302 | + | |
| 303 | +static int tw686x_sg_setup(struct tw686x_dev *dev) | |
| 304 | +{ | |
| 305 | + unsigned int sg_table_size, pb, ch, channels; | |
| 306 | + | |
| 307 | + if (is_second_gen(dev)) { | |
| 308 | + /* | |
| 309 | + * TW6865/TW6869: each channel needs a pair of | |
| 310 | + * P-B descriptor tables. | |
| 311 | + */ | |
| 312 | + channels = max_channels(dev); | |
| 313 | + sg_table_size = TW686X_SG_TABLE_SIZE; | |
| 314 | + } else { | |
| 315 | + /* | |
| 316 | + * TW6864/TW6868: we need to allocate a pair of | |
| 317 | + * P-B descriptor tables, common for all channels. | |
| 318 | + * Each table will be bigger than 4 KB. | |
| 319 | + */ | |
| 320 | + channels = 1; | |
| 321 | + sg_table_size = max_channels(dev) * TW686X_SG_TABLE_SIZE; | |
| 322 | + } | |
| 323 | + | |
| 324 | + for (ch = 0; ch < channels; ch++) { | |
| 325 | + struct tw686x_video_channel *vc = &dev->video_channels[ch]; | |
| 326 | + | |
| 327 | + for (pb = 0; pb < 2; pb++) | |
| 328 | + vc->dma_descs[pb].size = sg_table_size; | |
| 329 | + } | |
| 330 | + | |
| 331 | + return 0; | |
| 332 | +} | |
| 333 | + | |
| 334 | +static const struct tw686x_dma_ops sg_dma_ops = { | |
| 335 | + .setup = tw686x_sg_setup, | |
| 336 | + .alloc = tw686x_sg_dma_alloc, | |
| 337 | + .free = tw686x_sg_dma_free, | |
| 338 | + .buf_refill = tw686x_sg_buf_refill, | |
| 339 | + .mem_ops = &vb2_dma_sg_memops, | |
| 340 | + .hw_dma_mode = TW686X_SG_MODE, | |
| 341 | + .field = V4L2_FIELD_SEQ_TB, | |
| 342 | +}; | |
| 343 | + | |
| 344 | +static const unsigned int fps_map[15] = { | |
| 345 | + /* | |
| 346 | + * bit 31 enables selecting the field control register | |
| 347 | + * bits 0-29 are a bitmask with fields that will be output. | |
| 348 | + * For NTSC (and PAL-M, PAL-60), all 30 bits are used. | |
| 349 | + * For other PAL standards, only the first 25 bits are used. | |
| 350 | + */ | |
| 351 | + 0x00000000, /* output all fields */ | |
| 352 | + 0x80000006, /* 2 fps (60Hz), 2 fps (50Hz) */ | |
| 353 | + 0x80018006, /* 4 fps (60Hz), 4 fps (50Hz) */ | |
| 354 | + 0x80618006, /* 6 fps (60Hz), 6 fps (50Hz) */ | |
| 355 | + 0x81818186, /* 8 fps (60Hz), 8 fps (50Hz) */ | |
| 356 | + 0x86186186, /* 10 fps (60Hz), 8 fps (50Hz) */ | |
| 357 | + 0x86619866, /* 12 fps (60Hz), 10 fps (50Hz) */ | |
| 358 | + 0x86666666, /* 14 fps (60Hz), 12 fps (50Hz) */ | |
| 359 | + 0x9999999e, /* 16 fps (60Hz), 14 fps (50Hz) */ | |
| 360 | + 0x99e6799e, /* 18 fps (60Hz), 16 fps (50Hz) */ | |
| 361 | + 0x9e79e79e, /* 20 fps (60Hz), 16 fps (50Hz) */ | |
| 362 | + 0x9e7e7e7e, /* 22 fps (60Hz), 18 fps (50Hz) */ | |
| 363 | + 0x9fe7f9fe, /* 24 fps (60Hz), 20 fps (50Hz) */ | |
| 364 | + 0x9ffe7ffe, /* 26 fps (60Hz), 22 fps (50Hz) */ | |
| 365 | + 0x9ffffffe, /* 28 fps (60Hz), 24 fps (50Hz) */ | |
| 366 | +}; | |
| 367 | + | |
| 368 | +static unsigned int tw686x_real_fps(unsigned int index, unsigned int max_fps) | |
| 369 | +{ | |
| 370 | + unsigned long mask; | |
| 371 | + | |
| 372 | + if (!index || index >= ARRAY_SIZE(fps_map)) | |
| 373 | + return max_fps; | |
| 374 | + | |
| 375 | + mask = GENMASK(max_fps - 1, 0); | |
| 376 | + return hweight_long(fps_map[index] & mask); | |
| 377 | +} | |
| 378 | + | |
| 379 | +static unsigned int tw686x_fps_idx(unsigned int fps, unsigned int max_fps) | |
| 380 | +{ | |
| 381 | + unsigned int idx, real_fps; | |
| 382 | + int delta; | |
| 383 | + | |
| 384 | + /* First guess */ | |
| 385 | + idx = (12 + 15 * fps) / max_fps; | |
| 386 | + | |
| 387 | + /* Minimal possible framerate is 2 frames per second */ | |
| 388 | + if (!idx) | |
| 389 | + return 1; | |
| 390 | + | |
| 391 | + /* Check if the difference is bigger than abs(1) and adjust */ | |
| 392 | + real_fps = tw686x_real_fps(idx, max_fps); | |
| 393 | + delta = real_fps - fps; | |
| 394 | + if (delta < -1) | |
| 395 | + idx++; | |
| 396 | + else if (delta > 1) | |
| 397 | + idx--; | |
| 398 | + | |
| 399 | + /* Max framerate */ | |
| 400 | + if (idx >= 15) | |
| 401 | + return 0; | |
| 402 | + | |
| 403 | + return idx; | |
| 77 | 404 | } |
| 78 | 405 | |
| 79 | 406 | static void tw686x_set_framerate(struct tw686x_video_channel *vc, |
| 80 | 407 | unsigned int fps) |
| 81 | 408 | { |
| 82 | − unsigned int map; | |
| 83 | − | |
| 84 | − if (vc->fps == fps) | |
| 85 | − return; | |
| 409 | + unsigned int i; | |
| 86 | 410 | |
| 87 | − map = tw686x_fields_map(vc->video_standard, fps) << 1; | |
| 88 | − map |= map << 1; | |
| 89 | − if (map > 0) | |
| 90 | − map |= BIT(31); | |
| 91 | − reg_write(vc->dev, VIDEO_FIELD_CTRL[vc->ch], map); | |
| 92 | − vc->fps = fps; | |
| 411 | + i = tw686x_fps_idx(fps, TW686X_MAX_FPS(vc->video_standard)); | |
| 412 | + reg_write(vc->dev, VIDEO_FIELD_CTRL[vc->ch], fps_map[i]); | |
| 413 | + vc->fps = tw686x_real_fps(i, TW686X_MAX_FPS(vc->video_standard)); | |
| 93 | 414 | } |
| 94 | 415 | |
| 95 | 416 | static const struct tw686x_format *format_by_fourcc(unsigned int fourcc) |
| @@ -104,7 +425,7 @@ static const struct tw686x_format *format_by_fourcc(unsigned int fourcc) · 8 unmodified lines | ||
| 104 | 425 | |
| 105 | 426 | static int tw686x_queue_setup(struct vb2_queue *vq, |
| 106 | 427 | unsigned int *nbuffers, unsigned int *nplanes, |
| 107 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 428 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 108 | 429 | { |
| 109 | 430 | struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); |
| 110 | 431 | unsigned int szimage = |
| @@ -152,75 +473,6 @@ static void tw686x_buf_queue(struct vb2_buffer *vb) · 41 unmodified lines | ||
| 152 | 473 | spin_unlock_irqrestore(&vc->qlock, flags); |
| 153 | 474 | } |
| 154 | 475 | |
| 155 | −/* | |
| 156 | − * We can call this even when alloc_dma failed for the given channel | |
| 157 | − */ | |
| 158 | −static void tw686x_free_dma(struct tw686x_video_channel *vc, unsigned int pb) | |
| 159 | −{ | |
| 160 | − struct tw686x_dma_desc *desc = &vc->dma_descs[pb]; | |
| 161 | − struct tw686x_dev *dev = vc->dev; | |
| 162 | − struct pci_dev *pci_dev; | |
| 163 | − unsigned long flags; | |
| 164 | − | |
| 165 | − /* Check device presence. Shouldn't really happen! */ | |
| 166 | − spin_lock_irqsave(&dev->lock, flags); | |
| 167 | − pci_dev = dev->pci_dev; | |
| 168 | − spin_unlock_irqrestore(&dev->lock, flags); | |
| 169 | − if (!pci_dev) { | |
| 170 | − WARN(1, "trying to deallocate on missing device\n"); | |
| 171 | − return; | |
| 172 | − } | |
| 173 | − | |
| 174 | − if (desc->virt) { | |
| 175 | − pci_free_consistent(dev->pci_dev, desc->size, | |
| 176 | − desc->virt, desc->phys); | |
| 177 | − desc->virt = NULL; | |
| 178 | − } | |
| 179 | −} | |
| 180 | − | |
| 181 | −static int tw686x_alloc_dma(struct tw686x_video_channel *vc, unsigned int pb) | |
| 182 | −{ | |
| 183 | − struct tw686x_dev *dev = vc->dev; | |
| 184 | − u32 reg = pb ? VDMA_B_ADDR[vc->ch] : VDMA_P_ADDR[vc->ch]; | |
| 185 | − unsigned int len; | |
| 186 | − void *virt; | |
| 187 | − | |
| 188 | − WARN(vc->dma_descs[pb].virt, | |
| 189 | − "Allocating buffer but previous still here\n"); | |
| 190 | − | |
| 191 | − len = (vc->width * vc->height * vc->format->depth) >> 3; | |
| 192 | − virt = pci_alloc_consistent(dev->pci_dev, len, | |
| 193 | − &vc->dma_descs[pb].phys); | |
| 194 | − if (!virt) { | |
| 195 | − v4l2_err(&dev->v4l2_dev, | |
| 196 | − "dma%d: unable to allocate %s-buffer\n", | |
| 197 | − vc->ch, pb ? "B" : "P"); | |
| 198 | − return -ENOMEM; | |
| 199 | − } | |
| 200 | − vc->dma_descs[pb].size = len; | |
| 201 | − vc->dma_descs[pb].virt = virt; | |
| 202 | − reg_write(dev, reg, vc->dma_descs[pb].phys); | |
| 203 | − | |
| 204 | − return 0; | |
| 205 | −} | |
| 206 | − | |
| 207 | −static void tw686x_buffer_refill(struct tw686x_video_channel *vc, | |
| 208 | − unsigned int pb) | |
| 209 | −{ | |
| 210 | − struct tw686x_v4l2_buf *buf; | |
| 211 | − | |
| 212 | − while (!list_empty(&vc->vidq_queued)) { | |
| 213 | − | |
| 214 | − buf = list_first_entry(&vc->vidq_queued, | |
| 215 | − struct tw686x_v4l2_buf, list); | |
| 216 | − list_del(&buf->list); | |
| 217 | − | |
| 218 | − vc->curr_bufs[pb] = buf; | |
| 219 | − return; | |
| 220 | − } | |
| 221 | − vc->curr_bufs[pb] = NULL; | |
| 222 | −} | |
| 223 | − | |
| 224 | 476 | static void tw686x_clear_queue(struct tw686x_video_channel *vc, |
| 225 | 477 | enum vb2_buffer_state state) |
| 226 | 478 | { |
| @@ -262,7 +514,8 @@ static int tw686x_start_streaming(struct vb2_queue *vq, unsigned int count) · 35 unmodified lines | ||
| 262 | 514 | spin_lock_irqsave(&vc->qlock, flags); |
| 263 | 515 | |
| 264 | 516 | /* Sanity check */ |
| 265 | − if (!vc->dma_descs[0].virt || !vc->dma_descs[1].virt) { | |
| 517 | + if (dev->dma_mode == TW686X_DMA_MODE_MEMCPY && | |
| 518 | + (!vc->dma_descs[0].virt || !vc->dma_descs[1].virt)) { | |
| 266 | 519 | spin_unlock_irqrestore(&vc->qlock, flags); |
| 267 | 520 | v4l2_err(&dev->v4l2_dev, |
| 268 | 521 | "video%d: refusing to start without DMA buffers\n", |
| @@ -272,7 +525,7 @@ static int tw686x_start_streaming(struct vb2_queue *vq, unsigned int count) · 3 unmodified lines | ||
| 272 | 525 | } |
| 273 | 526 | |
| 274 | 527 | for (pb = 0; pb < 2; pb++) |
| 275 | − tw686x_buffer_refill(vc, pb); | |
| 528 | + dev->dma_ops->buf_refill(vc, pb); | |
| 276 | 529 | spin_unlock_irqrestore(&vc->qlock, flags); |
| 277 | 530 | |
| 278 | 531 | vc->sequence = 0; |
| @@ -375,10 +628,11 @@ static int tw686x_g_fmt_vid_cap(struct file *file, void *priv, · 96 unmodified lines | ||
| 375 | 628 | struct v4l2_format *f) |
| 376 | 629 | { |
| 377 | 630 | struct tw686x_video_channel *vc = video_drvdata(file); |
| 631 | + struct tw686x_dev *dev = vc->dev; | |
| 378 | 632 | |
| 379 | 633 | f->fmt.pix.width = vc->width; |
| 380 | 634 | f->fmt.pix.height = vc->height; |
| 381 | − f->fmt.pix.field = V4L2_FIELD_INTERLACED; | |
| 635 | + f->fmt.pix.field = dev->dma_ops->field; | |
| 382 | 636 | f->fmt.pix.pixelformat = vc->format->fourcc; |
| 383 | 637 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
| 384 | 638 | f->fmt.pix.bytesperline = (f->fmt.pix.width * vc->format->depth) / 8; |
| @@ -390,6 +644,7 @@ static int tw686x_try_fmt_vid_cap(struct file *file, void *priv, · 5 unmodified lines | ||
| 390 | 644 | struct v4l2_format *f) |
| 391 | 645 | { |
| 392 | 646 | struct tw686x_video_channel *vc = video_drvdata(file); |
| 647 | + struct tw686x_dev *dev = vc->dev; | |
| 393 | 648 | unsigned int video_height = TW686X_VIDEO_HEIGHT(vc->video_standard); |
| 394 | 649 | const struct tw686x_format *format; |
| 395 | 650 | |
| @@ -412,7 +667,7 @@ static int tw686x_try_fmt_vid_cap(struct file *file, void *priv, · 16 unmodified lines | ||
| 412 | 667 | f->fmt.pix.bytesperline = (f->fmt.pix.width * format->depth) / 8; |
| 413 | 668 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; |
| 414 | 669 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
| 415 | − f->fmt.pix.field = V4L2_FIELD_INTERLACED; | |
| 670 | + f->fmt.pix.field = dev->dma_ops->field; | |
| 416 | 671 | |
| 417 | 672 | return 0; |
| 418 | 673 | } |
| @@ -421,6 +676,7 @@ static int tw686x_s_fmt_vid_cap(struct file *file, void *priv, · 2 unmodified lines | ||
| 421 | 676 | struct v4l2_format *f) |
| 422 | 677 | { |
| 423 | 678 | struct tw686x_video_channel *vc = video_drvdata(file); |
| 679 | + struct tw686x_dev *dev = vc->dev; | |
| 424 | 680 | u32 val, width, line_width, height; |
| 425 | 681 | unsigned long bitsperframe; |
| 426 | 682 | int err, pb; |
| @@ -438,15 +694,16 @@ static int tw686x_s_fmt_vid_cap(struct file *file, void *priv, · 11 unmodified lines | ||
| 438 | 694 | vc->height = f->fmt.pix.height; |
| 439 | 695 | |
| 440 | 696 | /* We need new DMA buffers if the framesize has changed */ |
| 441 | − if (bitsperframe != vc->width * vc->height * vc->format->depth) { | |
| 697 | + if (dev->dma_ops->alloc && | |
| 698 | + bitsperframe != vc->width * vc->height * vc->format->depth) { | |
| 442 | 699 | for (pb = 0; pb < 2; pb++) |
| 443 | − tw686x_free_dma(vc, pb); | |
| 700 | + dev->dma_ops->free(vc, pb); | |
| 444 | 701 | |
| 445 | 702 | for (pb = 0; pb < 2; pb++) { |
| 446 | − err = tw686x_alloc_dma(vc, pb); | |
| 703 | + err = dev->dma_ops->alloc(vc, pb); | |
| 447 | 704 | if (err) { |
| 448 | 705 | if (pb > 0) |
| 449 | − tw686x_free_dma(vc, 0); | |
| 706 | + dev->dma_ops->free(vc, 0); | |
| 450 | 707 | return err; |
| 451 | 708 | } |
| 452 | 709 | } |
| @@ -464,6 +721,19 @@ static int tw686x_s_fmt_vid_cap(struct file *file, void *priv, · 11 unmodified lines | ||
| 464 | 721 | else |
| 465 | 722 | val &= ~BIT(24); |
| 466 | 723 | |
| 724 | + val &= ~0x7ffff; | |
| 725 | + | |
| 726 | + /* Program the DMA scatter-gather */ | |
| 727 | + if (dev->dma_mode == TW686X_DMA_MODE_SG) { | |
| 728 | + u32 start_idx, end_idx; | |
| 729 | + | |
| 730 | + start_idx = is_second_gen(dev) ? | |
| 731 | + 0 : vc->ch * TW686X_MAX_SG_DESC_COUNT; | |
| 732 | + end_idx = start_idx + TW686X_MAX_SG_DESC_COUNT - 1; | |
| 733 | + | |
| 734 | + val |= (end_idx << 10) | start_idx; | |
| 735 | + } | |
| 736 | + | |
| 467 | 737 | val &= ~(0x7 << 20); |
| 468 | 738 | val |= vc->format->mode << 20; |
| 469 | 739 | reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val); |
| @@ -540,6 +810,12 @@ static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id) · 70 unmodified lines | ||
| 540 | 810 | ret = tw686x_g_fmt_vid_cap(file, priv, &f); |
| 541 | 811 | if (!ret) |
| 542 | 812 | tw686x_s_fmt_vid_cap(file, priv, &f); |
| 813 | + | |
| 814 | + /* | |
| 815 | + * Frame decimation depends on the chosen standard, | |
| 816 | + * so reset it to the current value. | |
| 817 | + */ | |
| 818 | + tw686x_set_framerate(vc, vc->fps); | |
| 543 | 819 | return 0; |
| 544 | 820 | } |
| 545 | 821 | |
| @@ -609,6 +885,40 @@ static int tw686x_g_std(struct file *file, void *priv, v4l2_std_id *id) · 63 unmodified lines | ||
| 609 | 885 | return 0; |
| 610 | 886 | } |
| 611 | 887 | |
| 888 | +static int tw686x_g_parm(struct file *file, void *priv, | |
| 889 | + struct v4l2_streamparm *sp) | |
| 890 | +{ | |
| 891 | + struct tw686x_video_channel *vc = video_drvdata(file); | |
| 892 | + struct v4l2_captureparm *cp = &sp->parm.capture; | |
| 893 | + | |
| 894 | + if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
| 895 | + return -EINVAL; | |
| 896 | + sp->parm.capture.readbuffers = 3; | |
| 897 | + | |
| 898 | + cp->capability = V4L2_CAP_TIMEPERFRAME; | |
| 899 | + cp->timeperframe.numerator = 1; | |
| 900 | + cp->timeperframe.denominator = vc->fps; | |
| 901 | + return 0; | |
| 902 | +} | |
| 903 | + | |
| 904 | +static int tw686x_s_parm(struct file *file, void *priv, | |
| 905 | + struct v4l2_streamparm *sp) | |
| 906 | +{ | |
| 907 | + struct tw686x_video_channel *vc = video_drvdata(file); | |
| 908 | + struct v4l2_captureparm *cp = &sp->parm.capture; | |
| 909 | + unsigned int denominator = cp->timeperframe.denominator; | |
| 910 | + unsigned int numerator = cp->timeperframe.numerator; | |
| 911 | + unsigned int fps; | |
| 912 | + | |
| 913 | + if (vb2_is_busy(&vc->vidq)) | |
| 914 | + return -EBUSY; | |
| 915 | + | |
| 916 | + fps = (!numerator || !denominator) ? 0 : denominator / numerator; | |
| 917 | + if (vc->fps != fps) | |
| 918 | + tw686x_set_framerate(vc, fps); | |
| 919 | + return tw686x_g_parm(file, priv, sp); | |
| 920 | +} | |
| 921 | + | |
| 612 | 922 | static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv, |
| 613 | 923 | struct v4l2_fmtdesc *f) |
| 614 | 924 | { |
| @@ -695,6 +1005,9 @@ static const struct v4l2_ioctl_ops tw686x_video_ioctl_ops = { · 80 unmodified lines | ||
| 695 | 1005 | .vidioc_g_std = tw686x_g_std, |
| 696 | 1006 | .vidioc_s_std = tw686x_s_std, |
| 697 | 1007 | |
| 1008 | + .vidioc_g_parm = tw686x_g_parm, | |
| 1009 | + .vidioc_s_parm = tw686x_s_parm, | |
| 1010 | + | |
| 698 | 1011 | .vidioc_enum_input = tw686x_enum_input, |
| 699 | 1012 | .vidioc_g_input = tw686x_g_input, |
| 700 | 1013 | .vidioc_s_input = tw686x_s_input, |
| @@ -713,26 +1026,11 @@ static const struct v4l2_ioctl_ops tw686x_video_ioctl_ops = { · 12 unmodified lines | ||
| 713 | 1026 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
| 714 | 1027 | }; |
| 715 | 1028 | |
| 716 | −static void tw686x_buffer_copy(struct tw686x_video_channel *vc, | |
| 717 | − unsigned int pb, struct vb2_v4l2_buffer *vb) | |
| 718 | −{ | |
| 719 | − struct tw686x_dma_desc *desc = &vc->dma_descs[pb]; | |
| 720 | − struct vb2_buffer *vb2_buf = &vb->vb2_buf; | |
| 721 | − | |
| 722 | − vb->field = V4L2_FIELD_INTERLACED; | |
| 723 | − vb->sequence = vc->sequence++; | |
| 724 | − | |
| 725 | − memcpy(vb2_plane_vaddr(vb2_buf, 0), desc->virt, desc->size); | |
| 726 | − vb2_buf->timestamp = ktime_get_ns(); | |
| 727 | − vb2_buffer_done(vb2_buf, VB2_BUF_STATE_DONE); | |
| 728 | −} | |
| 729 | − | |
| 730 | 1029 | void tw686x_video_irq(struct tw686x_dev *dev, unsigned long requests, |
| 731 | 1030 | unsigned int pb_status, unsigned int fifo_status, |
| 732 | 1031 | unsigned int *reset_ch) |
| 733 | 1032 | { |
| 734 | 1033 | struct tw686x_video_channel *vc; |
| 735 | − struct vb2_v4l2_buffer *vb; | |
| 736 | 1034 | unsigned long flags; |
| 737 | 1035 | unsigned int ch, pb; |
| 738 | 1036 | |
| @@ -781,14 +1079,9 @@ void tw686x_video_irq(struct tw686x_dev *dev, unsigned long requests, · 42 unmodified lines | ||
| 781 | 1079 | continue; |
| 782 | 1080 | } |
| 783 | 1081 | |
| 784 | − /* handle video stream */ | |
| 785 | 1082 | spin_lock_irqsave(&vc->qlock, flags); |
| 786 | − if (vc->curr_bufs[pb]) { | |
| 787 | − vb = &vc->curr_bufs[pb]->vb; | |
| 788 | − tw686x_buffer_copy(vc, pb, vb); | |
| 789 | − } | |
| 790 | − vc->pb = !pb; | |
| 791 | − tw686x_buffer_refill(vc, pb); | |
| 1083 | + tw686x_buf_done(vc, pb); | |
| 1084 | + dev->dma_ops->buf_refill(vc, pb); | |
| 792 | 1085 | spin_unlock_irqrestore(&vc->qlock, flags); |
| 793 | 1086 | } |
| 794 | 1087 | } |
| @@ -803,8 +1096,9 @@ void tw686x_video_free(struct tw686x_dev *dev) · 8 unmodified lines | ||
| 803 | 1096 | if (vc->device) |
| 804 | 1097 | video_unregister_device(vc->device); |
| 805 | 1098 | |
| 806 | − for (pb = 0; pb < 2; pb++) | |
| 807 | − tw686x_free_dma(vc, pb); | |
| 1099 | + if (dev->dma_ops->free) | |
| 1100 | + for (pb = 0; pb < 2; pb++) | |
| 1101 | + dev->dma_ops->free(vc, pb); | |
| 808 | 1102 | } |
| 809 | 1103 | } |
| 810 | 1104 | |
| @@ -813,10 +1107,25 @@ int tw686x_video_init(struct tw686x_dev *dev) · 2 unmodified lines | ||
| 813 | 1107 | unsigned int ch, val, pb; |
| 814 | 1108 | int err; |
| 815 | 1109 | |
| 1110 | + if (dev->dma_mode == TW686X_DMA_MODE_MEMCPY) | |
| 1111 | + dev->dma_ops = &memcpy_dma_ops; | |
| 1112 | + else if (dev->dma_mode == TW686X_DMA_MODE_CONTIG) | |
| 1113 | + dev->dma_ops = &contig_dma_ops; | |
| 1114 | + else if (dev->dma_mode == TW686X_DMA_MODE_SG) | |
| 1115 | + dev->dma_ops = &sg_dma_ops; | |
| 1116 | + else | |
| 1117 | + return -EINVAL; | |
| 1118 | + | |
| 816 | 1119 | err = v4l2_device_register(&dev->pci_dev->dev, &dev->v4l2_dev); |
| 817 | 1120 | if (err) |
| 818 | 1121 | return err; |
| 819 | 1122 | |
| 1123 | + if (dev->dma_ops->setup) { | |
| 1124 | + err = dev->dma_ops->setup(dev); | |
| 1125 | + if (err) | |
| 1126 | + return err; | |
| 1127 | + } | |
| 1128 | + | |
| 820 | 1129 | for (ch = 0; ch < max_channels(dev); ch++) { |
| 821 | 1130 | struct tw686x_video_channel *vc = &dev->video_channels[ch]; |
| 822 | 1131 | struct video_device *vdev; |
| @@ -842,10 +1151,12 @@ int tw686x_video_init(struct tw686x_dev *dev) · 19 unmodified lines | ||
| 842 | 1151 | reg_write(dev, HACTIVE_LO[ch], 0xd0); |
| 843 | 1152 | reg_write(dev, VIDEO_SIZE[ch], 0); |
| 844 | 1153 | |
| 845 | − for (pb = 0; pb < 2; pb++) { | |
| 846 | − err = tw686x_alloc_dma(vc, pb); | |
| 847 | − if (err) | |
| 848 | − goto error; | |
| 1154 | + if (dev->dma_ops->alloc) { | |
| 1155 | + for (pb = 0; pb < 2; pb++) { | |
| 1156 | + err = dev->dma_ops->alloc(vc, pb); | |
| 1157 | + if (err) | |
| 1158 | + goto error; | |
| 1159 | + } | |
| 849 | 1160 | } |
| 850 | 1161 | |
| 851 | 1162 | vc->vidq.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF; |
| @@ -853,11 +1164,12 @@ int tw686x_video_init(struct tw686x_dev *dev) · 1 unmodified line | ||
| 853 | 1164 | vc->vidq.drv_priv = vc; |
| 854 | 1165 | vc->vidq.buf_struct_size = sizeof(struct tw686x_v4l2_buf); |
| 855 | 1166 | vc->vidq.ops = &tw686x_video_qops; |
| 856 | − vc->vidq.mem_ops = &vb2_vmalloc_memops; | |
| 1167 | + vc->vidq.mem_ops = dev->dma_ops->mem_ops; | |
| 857 | 1168 | vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 858 | 1169 | vc->vidq.min_buffers_needed = 2; |
| 859 | 1170 | vc->vidq.lock = &vc->vb_mutex; |
| 860 | 1171 | vc->vidq.gfp_flags = GFP_DMA32; |
| 1172 | + vc->vidq.dev = &dev->pci_dev->dev; | |
| 861 | 1173 | |
| 862 | 1174 | err = vb2_queue_init(&vc->vidq); |
| 863 | 1175 | if (err) { |
| @@ -915,10 +1227,9 @@ int tw686x_video_init(struct tw686x_dev *dev) · 51 unmodified lines | ||
| 915 | 1227 | vc->num = vdev->num; |
| 916 | 1228 | } |
| 917 | 1229 | |
| 918 | − /* Set DMA frame mode on all channels. Only supported mode for now. */ | |
| 919 | 1230 | val = TW686X_DEF_PHASE_REF; |
| 920 | 1231 | for (ch = 0; ch < max_channels(dev); ch++) |
| 921 | − val |= TW686X_FRAME_MODE << (16 + ch * 2); | |
| 1232 | + val |= dev->dma_ops->hw_dma_mode << (16 + ch * 2); | |
| 922 | 1233 | reg_write(dev, PHASE_REF, val); |
| 923 | 1234 | |
| 924 | 1235 | reg_write(dev, MISC2[0], 0xe7); |
| @@ -27,16 +27,14 @@ · 26 unmodified lines | ||
| 27 | 27 | #define TYPE_SECOND_GEN 0x10 |
| 28 | 28 | #define TW686X_DEF_PHASE_REF 0x1518 |
| 29 | 29 | |
| 30 | −#define TW686X_FIELD_MODE 0x3 | |
| 31 | −#define TW686X_FRAME_MODE 0x2 | |
| 32 | −/* 0x1 is reserved */ | |
| 33 | −#define TW686X_SG_MODE 0x0 | |
| 34 | − | |
| 35 | −#define TW686X_AUDIO_PAGE_SZ 4096 | |
| 36 | 30 | #define TW686X_AUDIO_PAGE_MAX 16 |
| 37 | 31 | #define TW686X_AUDIO_PERIODS_MIN 2 |
| 38 | 32 | #define TW686X_AUDIO_PERIODS_MAX TW686X_AUDIO_PAGE_MAX |
| 39 | 33 | |
| 34 | +#define TW686X_DMA_MODE_MEMCPY 0 | |
| 35 | +#define TW686X_DMA_MODE_CONTIG 1 | |
| 36 | +#define TW686X_DMA_MODE_SG 2 | |
| 37 | + | |
| 40 | 38 | struct tw686x_format { |
| 41 | 39 | char *name; |
| 42 | 40 | unsigned int fourcc; |
| @@ -50,6 +48,12 @@ struct tw686x_dma_desc { · 7 unmodified lines | ||
| 50 | 48 | unsigned int size; |
| 51 | 49 | }; |
| 52 | 50 | |
| 51 | +struct tw686x_sg_desc { | |
| 52 | + /* 3 MSBits for flags, 13 LSBits for length */ | |
| 53 | + __le32 flags_length; | |
| 54 | + __le32 phys; | |
| 55 | +}; | |
| 56 | + | |
| 53 | 57 | struct tw686x_audio_buf { |
| 54 | 58 | dma_addr_t dma; |
| 55 | 59 | void *virt; |
| @@ -82,6 +86,7 @@ struct tw686x_video_channel { · 26 unmodified lines | ||
| 82 | 86 | struct video_device *device; |
| 83 | 87 | struct tw686x_v4l2_buf *curr_bufs[2]; |
| 84 | 88 | struct tw686x_dma_desc dma_descs[2]; |
| 89 | + struct tw686x_sg_desc *sg_descs[2]; | |
| 85 | 90 | |
| 86 | 91 | struct v4l2_ctrl_handler ctrl_handler; |
| 87 | 92 | const struct tw686x_format *format; |
| @@ -99,6 +104,16 @@ struct tw686x_video_channel { · 11 unmodified lines | ||
| 99 | 104 | bool no_signal; |
| 100 | 105 | }; |
| 101 | 106 | |
| 107 | +struct tw686x_dma_ops { | |
| 108 | + int (*setup)(struct tw686x_dev *dev); | |
| 109 | + int (*alloc)(struct tw686x_video_channel *vc, unsigned int pb); | |
| 110 | + void (*free)(struct tw686x_video_channel *vc, unsigned int pb); | |
| 111 | + void (*buf_refill)(struct tw686x_video_channel *vc, unsigned int pb); | |
| 112 | + const struct vb2_mem_ops *mem_ops; | |
| 113 | + enum v4l2_field field; | |
| 114 | + u32 hw_dma_mode; | |
| 115 | +}; | |
| 116 | + | |
| 102 | 117 | /** |
| 103 | 118 | * struct tw686x_dev - global device status |
| 104 | 119 | * @lock: spinlock controlling access to the |
| @@ -112,15 +127,18 @@ struct tw686x_dev { · 7 unmodified lines | ||
| 112 | 127 | |
| 113 | 128 | char name[32]; |
| 114 | 129 | unsigned int type; |
| 130 | + unsigned int dma_mode; | |
| 115 | 131 | struct pci_dev *pci_dev; |
| 116 | 132 | __u32 __iomem *mmio; |
| 117 | 133 | |
| 118 | − void *alloc_ctx; | |
| 119 | − | |
| 134 | + const struct tw686x_dma_ops *dma_ops; | |
| 120 | 135 | struct tw686x_video_channel *video_channels; |
| 121 | 136 | struct tw686x_audio_channel *audio_channels; |
| 122 | 137 | |
| 123 | − int audio_rate; /* per-device value */ | |
| 138 | + /* Per-device audio parameters */ | |
| 139 | + int audio_rate; | |
| 140 | + int period_size; | |
| 141 | + int audio_enabled; | |
| 124 | 142 | |
| 125 | 143 | struct timer_list dma_delay_timer; |
| 126 | 144 | u32 pending_dma_en; /* must be protected by lock */ |
| @@ -143,6 +161,12 @@ static inline unsigned int max_channels(struct tw686x_dev *dev) · 16 unmodified lines | ||
| 143 | 161 | return dev->type & TYPE_MAX_CHANNELS; /* 4 or 8 channels */ |
| 144 | 162 | } |
| 145 | 163 | |
| 164 | +static inline unsigned is_second_gen(struct tw686x_dev *dev) | |
| 165 | +{ | |
| 166 | + /* each channel has its own DMA SG table */ | |
| 167 | + return dev->type & TYPE_SECOND_GEN; | |
| 168 | +} | |
| 169 | + | |
| 146 | 170 | void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel); |
| 147 | 171 | void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel); |
| 148 | 172 | |
| @@ -246,10 +246,6 @@ static int zr36016_pushit (struct zr36016 *ptr, · 245 unmodified lines | ||
| 246 | 246 | //TODO// |
| 247 | 247 | ========================================================================= */ |
| 248 | 248 | |
| 249 | −// needed offset values PAL NTSC SECAM | |
| 250 | −static const int zr016_xoff[] = { 20, 20, 20 }; | |
| 251 | −static const int zr016_yoff[] = { 8, 9, 7 }; | |
| 252 | − | |
| 253 | 249 | static void |
| 254 | 250 | zr36016_init (struct zr36016 *ptr) |
| 255 | 251 | { |
| @@ -110,6 +110,7 @@ source "drivers/media/platform/exynos4-is/Kconfig" · 109 unmodified lines | ||
| 110 | 110 | source "drivers/media/platform/s5p-tv/Kconfig" |
| 111 | 111 | source "drivers/media/platform/am437x/Kconfig" |
| 112 | 112 | source "drivers/media/platform/xilinx/Kconfig" |
| 113 | +source "drivers/media/platform/rcar-vin/Kconfig" | |
| 113 | 114 | |
| 114 | 115 | config VIDEO_TI_CAL |
| 115 | 116 | tristate "TI CAL (Camera Adaptation Layer) driver" |
| @@ -152,6 +153,36 @@ config VIDEO_CODA · 36 unmodified lines | ||
| 152 | 153 | Coda is a range of video codec IPs that supports |
| 153 | 154 | H.264, MPEG-4, and other video formats. |
| 154 | 155 | |
| 156 | +config VIDEO_MEDIATEK_VPU | |
| 157 | + tristate "Mediatek Video Processor Unit" | |
| 158 | + depends on VIDEO_DEV && VIDEO_V4L2 | |
| 159 | + depends on ARCH_MEDIATEK || COMPILE_TEST | |
| 160 | + ---help--- | |
| 161 | + This driver provides downloading VPU firmware and | |
| 162 | + communicating with VPU. This driver for hw video | |
| 163 | + codec embedded in Mediatek's MT8173 SOCs. It is able | |
| 164 | + to handle video decoding/encoding in a range of formats. | |
| 165 | + | |
| 166 | + To compile this driver as a module, choose M here: the | |
| 167 | + module will be called mtk-vpu. | |
| 168 | + | |
| 169 | +config VIDEO_MEDIATEK_VCODEC | |
| 170 | + tristate "Mediatek Video Codec driver" | |
| 171 | + depends on MTK_IOMMU || COMPILE_TEST | |
| 172 | + depends on VIDEO_DEV && VIDEO_V4L2 | |
| 173 | + depends on ARCH_MEDIATEK || COMPILE_TEST | |
| 174 | + select VIDEOBUF2_DMA_CONTIG | |
| 175 | + select V4L2_MEM2MEM_DEV | |
| 176 | + select VIDEO_MEDIATEK_VPU | |
| 177 | + default n | |
| 178 | + ---help--- | |
| 179 | + Mediatek video codec driver provides HW capability to | |
| 180 | + encode and decode in a range of video formats | |
| 181 | + This driver rely on VPU driver to communicate with VPU. | |
| 182 | + | |
| 183 | + To compile this driver as a module, choose M here: the | |
| 184 | + module will be called mtk-vcodec | |
| 185 | + | |
| 155 | 186 | config VIDEO_MEM2MEM_DEINTERLACE |
| 156 | 187 | tristate "Deinterlace support" |
| 157 | 188 | depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE |
| @@ -247,10 +278,24 @@ config VIDEO_RENESAS_JPU · 89 unmodified lines | ||
| 247 | 278 | To compile this driver as a module, choose M here: the module |
| 248 | 279 | will be called rcar_jpu. |
| 249 | 280 | |
| 281 | +config VIDEO_RENESAS_FCP | |
| 282 | + tristate "Renesas Frame Compression Processor" | |
| 283 | + depends on ARCH_RENESAS || COMPILE_TEST | |
| 284 | + depends on OF | |
| 285 | + ---help--- | |
| 286 | + This is a driver for the Renesas Frame Compression Processor (FCP). | |
| 287 | + The FCP is a companion module of video processing modules in the | |
| 288 | + Renesas R-Car Gen3 SoCs. It handles memory access for the codec, | |
| 289 | + VSP and FDP modules. | |
| 290 | + | |
| 291 | + To compile this driver as a module, choose M here: the module | |
| 292 | + will be called rcar-fcp. | |
| 293 | + | |
| 250 | 294 | config VIDEO_RENESAS_VSP1 |
| 251 | 295 | tristate "Renesas VSP1 Video Processing Engine" |
| 252 | 296 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA |
| 253 | 297 | depends on (ARCH_RENESAS && OF) || COMPILE_TEST |
| 298 | + depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP | |
| 254 | 299 | select VIDEOBUF2_DMA_CONTIG |
| 255 | 300 | ---help--- |
| 256 | 301 | This is a V4L2 driver for the Renesas VSP1 video processing engine. |
| @@ -46,6 +46,7 @@ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o · 45 unmodified lines | ||
| 46 | 46 | |
| 47 | 47 | obj-$(CONFIG_SOC_CAMERA) += soc_camera/ |
| 48 | 48 | |
| 49 | +obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o | |
| 49 | 50 | obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o |
| 50 | 51 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ |
| 51 | 52 | |
| @@ -55,4 +56,10 @@ obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ · 3 unmodified lines | ||
| 55 | 56 | |
| 56 | 57 | obj-$(CONFIG_VIDEO_XILINX) += xilinx/ |
| 57 | 58 | |
| 59 | +obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin/ | |
| 60 | + | |
| 58 | 61 | ccflags-y += -I$(srctree)/drivers/media/i2c |
| 62 | + | |
| 63 | +obj-$(CONFIG_VIDEO_MEDIATEK_VPU) += mtk-vpu/ | |
| 64 | + | |
| 65 | +obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec/ | |
| @@ -1901,21 +1901,20 @@ static void vpfe_calculate_offsets(struct vpfe_device *vpfe) · 1900 unmodified lines | ||
| 1901 | 1901 | * @nbuffers: ptr to number of buffers requested by application |
| 1902 | 1902 | * @nplanes:: contains number of distinct video planes needed to hold a frame |
| 1903 | 1903 | * @sizes[]: contains the size (in bytes) of each plane. |
| 1904 | − * @alloc_ctxs: ptr to allocation context | |
| 1904 | + * @alloc_devs: ptr to allocation context | |
| 1905 | 1905 | * |
| 1906 | 1906 | * This callback function is called when reqbuf() is called to adjust |
| 1907 | 1907 | * the buffer count and buffer size |
| 1908 | 1908 | */ |
| 1909 | 1909 | static int vpfe_queue_setup(struct vb2_queue *vq, |
| 1910 | 1910 | unsigned int *nbuffers, unsigned int *nplanes, |
| 1911 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 1911 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 1912 | 1912 | { |
| 1913 | 1913 | struct vpfe_device *vpfe = vb2_get_drv_priv(vq); |
| 1914 | 1914 | unsigned size = vpfe->fmt.fmt.pix.sizeimage; |
| 1915 | 1915 | |
| 1916 | 1916 | if (vq->num_buffers + *nbuffers < 3) |
| 1917 | 1917 | *nbuffers = 3 - vq->num_buffers; |
| 1918 | − alloc_ctxs[0] = vpfe->alloc_ctx; | |
| 1919 | 1918 | |
| 1920 | 1919 | if (*nplanes) { |
| 1921 | 1920 | if (sizes[0] < size) |
| @@ -2364,13 +2363,6 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe) · 442 unmodified lines | ||
| 2364 | 2363 | goto probe_out; |
| 2365 | 2364 | |
| 2366 | 2365 | /* Initialize videobuf2 queue as per the buffer type */ |
| 2367 | − vpfe->alloc_ctx = vb2_dma_contig_init_ctx(vpfe->pdev); | |
| 2368 | − if (IS_ERR(vpfe->alloc_ctx)) { | |
| 2369 | − vpfe_err(vpfe, "Failed to get the context\n"); | |
| 2370 | − err = PTR_ERR(vpfe->alloc_ctx); | |
| 2371 | − goto probe_out; | |
| 2372 | − } | |
| 2373 | − | |
| 2374 | 2366 | q = &vpfe->buffer_queue; |
| 2375 | 2367 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 2376 | 2368 | q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; |
| @@ -2381,11 +2373,11 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe) · 4 unmodified lines | ||
| 2381 | 2373 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 2382 | 2374 | q->lock = &vpfe->lock; |
| 2383 | 2375 | q->min_buffers_needed = 1; |
| 2376 | + q->dev = vpfe->pdev; | |
| 2384 | 2377 | |
| 2385 | 2378 | err = vb2_queue_init(q); |
| 2386 | 2379 | if (err) { |
| 2387 | 2380 | vpfe_err(vpfe, "vb2_queue_init() failed\n"); |
| 2388 | − vb2_dma_contig_cleanup_ctx(vpfe->alloc_ctx); | |
| 2389 | 2381 | goto probe_out; |
| 2390 | 2382 | } |
| 2391 | 2383 | |
| @@ -264,8 +264,6 @@ struct vpfe_device { · 263 unmodified lines | ||
| 264 | 264 | struct v4l2_rect crop; |
| 265 | 265 | /* Buffer queue used in video-buf */ |
| 266 | 266 | struct vb2_queue buffer_queue; |
| 267 | − /* Allocator-specific contexts for each plane */ | |
| 268 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 269 | 267 | /* Queue of filled frames */ |
| 270 | 268 | struct list_head dma_queue; |
| 271 | 269 | /* IRQ lock for DMA queue */ |
| @@ -91,8 +91,6 @@ struct bcap_device { · 90 unmodified lines | ||
| 91 | 91 | struct bcap_buffer *cur_frm; |
| 92 | 92 | /* buffer queue used in videobuf2 */ |
| 93 | 93 | struct vb2_queue buffer_queue; |
| 94 | − /* allocator-specific contexts for each plane */ | |
| 95 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 96 | 94 | /* queue of filled frames */ |
| 97 | 95 | struct list_head dma_queue; |
| 98 | 96 | /* used in videobuf2 callback */ |
| @@ -203,13 +201,12 @@ static void bcap_free_sensor_formats(struct bcap_device *bcap_dev) · 104 unmodified lines | ||
| 203 | 201 | |
| 204 | 202 | static int bcap_queue_setup(struct vb2_queue *vq, |
| 205 | 203 | unsigned int *nbuffers, unsigned int *nplanes, |
| 206 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 204 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 207 | 205 | { |
| 208 | 206 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); |
| 209 | 207 | |
| 210 | 208 | if (vq->num_buffers + *nbuffers < 2) |
| 211 | 209 | *nbuffers = 2; |
| 212 | − alloc_ctxs[0] = bcap_dev->alloc_ctx; | |
| 213 | 210 | |
| 214 | 211 | if (*nplanes) |
| 215 | 212 | return sizes[0] < bcap_dev->fmt.sizeimage ? -EINVAL : 0; |
| @@ -820,12 +817,6 @@ static int bcap_probe(struct platform_device *pdev) · 604 unmodified lines | ||
| 820 | 817 | } |
| 821 | 818 | bcap_dev->ppi->priv = bcap_dev; |
| 822 | 819 | |
| 823 | − bcap_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | |
| 824 | − if (IS_ERR(bcap_dev->alloc_ctx)) { | |
| 825 | − ret = PTR_ERR(bcap_dev->alloc_ctx); | |
| 826 | − goto err_free_ppi; | |
| 827 | − } | |
| 828 | − | |
| 829 | 820 | vfd = &bcap_dev->video_dev; |
| 830 | 821 | /* initialize field of video device */ |
| 831 | 822 | vfd->release = video_device_release_empty; |
| @@ -839,7 +830,7 @@ static int bcap_probe(struct platform_device *pdev) · 7 unmodified lines | ||
| 839 | 830 | if (ret) { |
| 840 | 831 | v4l2_err(pdev->dev.driver, |
| 841 | 832 | "Unable to register v4l2 device\n"); |
| 842 | − goto err_cleanup_ctx; | |
| 833 | + goto err_free_ppi; | |
| 843 | 834 | } |
| 844 | 835 | v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n"); |
| 845 | 836 | |
| @@ -863,6 +854,7 @@ static int bcap_probe(struct platform_device *pdev) · 17 unmodified lines | ||
| 863 | 854 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 864 | 855 | q->lock = &bcap_dev->mutex; |
| 865 | 856 | q->min_buffers_needed = 1; |
| 857 | + q->dev = &pdev->dev; | |
| 866 | 858 | |
| 867 | 859 | ret = vb2_queue_init(q); |
| 868 | 860 | if (ret) |
| @@ -967,8 +959,6 @@ err_free_handler: · 98 unmodified lines | ||
| 967 | 959 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); |
| 968 | 960 | err_unreg_v4l2: |
| 969 | 961 | v4l2_device_unregister(&bcap_dev->v4l2_dev); |
| 970 | −err_cleanup_ctx: | |
| 971 | − vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); | |
| 972 | 962 | err_free_ppi: |
| 973 | 963 | ppi_delete_instance(bcap_dev->ppi); |
| 974 | 964 | err_free_dev: |
| @@ -986,7 +976,6 @@ static int bcap_remove(struct platform_device *pdev) · 11 unmodified lines | ||
| 986 | 976 | video_unregister_device(&bcap_dev->video_dev); |
| 987 | 977 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); |
| 988 | 978 | v4l2_device_unregister(v4l2_dev); |
| 989 | − vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); | |
| 990 | 979 | ppi_delete_instance(bcap_dev->ppi); |
| 991 | 980 | kfree(bcap_dev); |
| 992 | 981 | return 0; |
| @@ -1139,7 +1139,7 @@ static void set_default_params(struct coda_ctx *ctx) · 1138 unmodified lines | ||
| 1139 | 1139 | */ |
| 1140 | 1140 | static int coda_queue_setup(struct vb2_queue *vq, |
| 1141 | 1141 | unsigned int *nbuffers, unsigned int *nplanes, |
| 1142 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 1142 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 1143 | 1143 | { |
| 1144 | 1144 | struct coda_ctx *ctx = vb2_get_drv_priv(vq); |
| 1145 | 1145 | struct coda_q_data *q_data; |
| @@ -1151,9 +1151,6 @@ static int coda_queue_setup(struct vb2_queue *vq, · 5 unmodified lines | ||
| 1151 | 1151 | *nplanes = 1; |
| 1152 | 1152 | sizes[0] = size; |
| 1153 | 1153 | |
| 1154 | − /* Set to vb2-dma-contig allocator context, ignored by vb2-vmalloc */ | |
| 1155 | − alloc_ctxs[0] = ctx->dev->alloc_ctx; | |
| 1156 | − | |
| 1157 | 1154 | v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, |
| 1158 | 1155 | "get %d buffer(s) of size %d each.\n", *nbuffers, size); |
| 1159 | 1156 | |
| @@ -1599,6 +1596,7 @@ static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) · 439 unmodified lines | ||
| 1599 | 1596 | * that videobuf2 will keep the value of bytesused intact. |
| 1600 | 1597 | */ |
| 1601 | 1598 | vq->allow_zero_bytesused = 1; |
| 1599 | + vq->dev = &ctx->dev->plat_dev->dev; | |
| 1602 | 1600 | |
| 1603 | 1601 | return vb2_queue_init(vq); |
| 1604 | 1602 | } |
| @@ -2040,16 +2038,10 @@ static void coda_fw_callback(const struct firmware *fw, void *context) · 435 unmodified lines | ||
| 2040 | 2038 | if (ret < 0) |
| 2041 | 2039 | goto put_pm; |
| 2042 | 2040 | |
| 2043 | − dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | |
| 2044 | − if (IS_ERR(dev->alloc_ctx)) { | |
| 2045 | − v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n"); | |
| 2046 | − goto put_pm; | |
| 2047 | − } | |
| 2048 | − | |
| 2049 | 2041 | dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops); |
| 2050 | 2042 | if (IS_ERR(dev->m2m_dev)) { |
| 2051 | 2043 | v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); |
| 2052 | − goto rel_ctx; | |
| 2044 | + goto put_pm; | |
| 2053 | 2045 | } |
| 2054 | 2046 | |
| 2055 | 2047 | for (i = 0; i < dev->devtype->num_vdevs; i++) { |
| @@ -2072,8 +2064,6 @@ rel_vfd: · 16 unmodified lines | ||
| 2072 | 2064 | while (--i >= 0) |
| 2073 | 2065 | video_unregister_device(&dev->vfd[i]); |
| 2074 | 2066 | v4l2_m2m_release(dev->m2m_dev); |
| 2075 | −rel_ctx: | |
| 2076 | − vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); | |
| 2077 | 2067 | put_pm: |
| 2078 | 2068 | pm_runtime_put_sync(&pdev->dev); |
| 2079 | 2069 | } |
| @@ -2226,7 +2216,7 @@ static int coda_probe(struct platform_device *pdev) · 146 unmodified lines | ||
| 2226 | 2216 | dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL); |
| 2227 | 2217 | if (IS_ERR(dev->rstc)) { |
| 2228 | 2218 | ret = PTR_ERR(dev->rstc); |
| 2229 | − if (ret == -ENOENT || ret == -ENOSYS) { | |
| 2219 | + if (ret == -ENOENT || ret == -ENOTSUPP) { | |
| 2230 | 2220 | dev->rstc = NULL; |
| 2231 | 2221 | } else { |
| 2232 | 2222 | dev_err(&pdev->dev, "failed get reset control: %d\n", |
| @@ -2324,8 +2314,6 @@ static int coda_remove(struct platform_device *pdev) · 91 unmodified lines | ||
| 2324 | 2314 | if (dev->m2m_dev) |
| 2325 | 2315 | v4l2_m2m_release(dev->m2m_dev); |
| 2326 | 2316 | pm_runtime_disable(&pdev->dev); |
| 2327 | − if (dev->alloc_ctx) | |
| 2328 | − vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); | |
| 2329 | 2317 | v4l2_device_unregister(&dev->v4l2_dev); |
| 2330 | 2318 | destroy_workqueue(dev->workqueue); |
| 2331 | 2319 | if (dev->iram.vaddr) |
| @@ -92,7 +92,6 @@ struct coda_dev { · 91 unmodified lines | ||
| 92 | 92 | struct mutex coda_mutex; |
| 93 | 93 | struct workqueue_struct *workqueue; |
| 94 | 94 | struct v4l2_m2m_dev *m2m_dev; |
| 95 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 96 | 95 | struct list_head instances; |
| 97 | 96 | unsigned long instance_mask; |
| 98 | 97 | struct dentry *debugfs_root; |
| @@ -80,13 +80,6 @@ struct ccdc_hw_ops { · 79 unmodified lines | ||
| 80 | 80 | /* Pointer to function to get line length */ |
| 81 | 81 | unsigned int (*get_line_length) (void); |
| 82 | 82 | |
| 83 | − /* Query CCDC control IDs */ | |
| 84 | − int (*queryctrl)(struct v4l2_queryctrl *qctrl); | |
| 85 | − /* Set CCDC control */ | |
| 86 | − int (*set_control)(struct v4l2_control *ctrl); | |
| 87 | − /* Get CCDC control */ | |
| 88 | − int (*get_control)(struct v4l2_control *ctrl); | |
| 89 | − | |
| 90 | 83 | /* Pointer to function to set frame buffer address */ |
| 91 | 84 | void (*setfbaddr) (unsigned long addr); |
| 92 | 85 | /* Pointer to function to get field id */ |
| @@ -230,7 +230,7 @@ static int vpbe_buffer_prepare(struct vb2_buffer *vb) · 229 unmodified lines | ||
| 230 | 230 | static int |
| 231 | 231 | vpbe_buffer_queue_setup(struct vb2_queue *vq, |
| 232 | 232 | unsigned int *nbuffers, unsigned int *nplanes, |
| 233 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 233 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 234 | 234 | |
| 235 | 235 | { |
| 236 | 236 | /* Get the file handle object and layer object */ |
| @@ -242,7 +242,6 @@ vpbe_buffer_queue_setup(struct vb2_queue *vq, · 5 unmodified lines | ||
| 242 | 242 | /* Store number of buffers allocated in numbuffer member */ |
| 243 | 243 | if (vq->num_buffers + *nbuffers < VPBE_DEFAULT_NUM_BUFS) |
| 244 | 244 | *nbuffers = VPBE_DEFAULT_NUM_BUFS - vq->num_buffers; |
| 245 | − alloc_ctxs[0] = layer->alloc_ctx; | |
| 246 | 245 | |
| 247 | 246 | if (*nplanes) |
| 248 | 247 | return sizes[0] < layer->pix_fmt.sizeimage ? -EINVAL : 0; |
| @@ -1451,20 +1450,13 @@ static int vpbe_display_probe(struct platform_device *pdev) · 1202 unmodified lines | ||
| 1451 | 1450 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1452 | 1451 | q->min_buffers_needed = 1; |
| 1453 | 1452 | q->lock = &disp_dev->dev[i]->opslock; |
| 1453 | + q->dev = disp_dev->vpbe_dev->pdev; | |
| 1454 | 1454 | err = vb2_queue_init(q); |
| 1455 | 1455 | if (err) { |
| 1456 | 1456 | v4l2_err(v4l2_dev, "vb2_queue_init() failed\n"); |
| 1457 | 1457 | goto probe_out; |
| 1458 | 1458 | } |
| 1459 | 1459 | |
| 1460 | − disp_dev->dev[i]->alloc_ctx = | |
| 1461 | − vb2_dma_contig_init_ctx(disp_dev->vpbe_dev->pdev); | |
| 1462 | − if (IS_ERR(disp_dev->dev[i]->alloc_ctx)) { | |
| 1463 | − v4l2_err(v4l2_dev, "Failed to get the context\n"); | |
| 1464 | − err = PTR_ERR(disp_dev->dev[i]->alloc_ctx); | |
| 1465 | − goto probe_out; | |
| 1466 | − } | |
| 1467 | − | |
| 1468 | 1460 | INIT_LIST_HEAD(&disp_dev->dev[i]->dma_queue); |
| 1469 | 1461 | |
| 1470 | 1462 | if (register_device(disp_dev->dev[i], disp_dev, pdev)) { |
| @@ -1482,7 +1474,6 @@ probe_out: · 11 unmodified lines | ||
| 1482 | 1474 | for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { |
| 1483 | 1475 | /* Unregister video device */ |
| 1484 | 1476 | if (disp_dev->dev[k] != NULL) { |
| 1485 | − vb2_dma_contig_cleanup_ctx(disp_dev->dev[k]->alloc_ctx); | |
| 1486 | 1477 | video_unregister_device(&disp_dev->dev[k]->video_dev); |
| 1487 | 1478 | kfree(disp_dev->dev[k]); |
| 1488 | 1479 | } |
| @@ -1510,7 +1501,6 @@ static int vpbe_display_remove(struct platform_device *pdev) · 21 unmodified lines | ||
| 1510 | 1501 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { |
| 1511 | 1502 | /* Get the pointer to the layer object */ |
| 1512 | 1503 | vpbe_display_layer = disp_dev->dev[i]; |
| 1513 | − vb2_dma_contig_cleanup_ctx(vpbe_display_layer->alloc_ctx); | |
| 1514 | 1504 | /* Unregister video device */ |
| 1515 | 1505 | video_unregister_device(&vpbe_display_layer->video_dev); |
| 1516 | 1506 | |
| @@ -107,14 +107,14 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb) · 106 unmodified lines | ||
| 107 | 107 | * @nbuffers: ptr to number of buffers requested by application |
| 108 | 108 | * @nplanes:: contains number of distinct video planes needed to hold a frame |
| 109 | 109 | * @sizes[]: contains the size (in bytes) of each plane. |
| 110 | − * @alloc_ctxs: ptr to allocation context | |
| 110 | + * @alloc_devs: ptr to allocation context | |
| 111 | 111 | * |
| 112 | 112 | * This callback function is called when reqbuf() is called to adjust |
| 113 | 113 | * the buffer count and buffer size |
| 114 | 114 | */ |
| 115 | 115 | static int vpif_buffer_queue_setup(struct vb2_queue *vq, |
| 116 | 116 | unsigned int *nbuffers, unsigned int *nplanes, |
| 117 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 117 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 118 | 118 | { |
| 119 | 119 | struct channel_obj *ch = vb2_get_drv_priv(vq); |
| 120 | 120 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; |
| @@ -133,7 +133,6 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq, · 12 unmodified lines | ||
| 133 | 133 | |
| 134 | 134 | *nplanes = 1; |
| 135 | 135 | sizes[0] = size; |
| 136 | − alloc_ctxs[0] = common->alloc_ctx; | |
| 137 | 136 | |
| 138 | 137 | /* Calculate the offset for Y and C data in the buffer */ |
| 139 | 138 | vpif_calculate_offsets(ch); |
| @@ -1371,6 +1370,7 @@ static int vpif_probe_complete(void) · 1231 unmodified lines | ||
| 1371 | 1370 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1372 | 1371 | q->min_buffers_needed = 1; |
| 1373 | 1372 | q->lock = &common->lock; |
| 1373 | + q->dev = vpif_dev; | |
| 1374 | 1374 | |
| 1375 | 1375 | err = vb2_queue_init(q); |
| 1376 | 1376 | if (err) { |
| @@ -1378,13 +1378,6 @@ static int vpif_probe_complete(void) · 1 unmodified line | ||
| 1378 | 1378 | goto probe_out; |
| 1379 | 1379 | } |
| 1380 | 1380 | |
| 1381 | − common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev); | |
| 1382 | − if (IS_ERR(common->alloc_ctx)) { | |
| 1383 | − vpif_err("Failed to get the context\n"); | |
| 1384 | − err = PTR_ERR(common->alloc_ctx); | |
| 1385 | − goto probe_out; | |
| 1386 | − } | |
| 1387 | − | |
| 1388 | 1381 | INIT_LIST_HEAD(&common->dma_queue); |
| 1389 | 1382 | |
| 1390 | 1383 | /* Initialize the video_device structure */ |
| @@ -1412,7 +1405,6 @@ probe_out: · 21 unmodified lines | ||
| 1412 | 1405 | /* Get the pointer to the channel object */ |
| 1413 | 1406 | ch = vpif_obj.dev[k]; |
| 1414 | 1407 | common = &ch->common[k]; |
| 1415 | − vb2_dma_contig_cleanup_ctx(common->alloc_ctx); | |
| 1416 | 1408 | /* Unregister video device */ |
| 1417 | 1409 | video_unregister_device(&ch->video_dev); |
| 1418 | 1410 | } |
| @@ -1546,7 +1538,6 @@ static int vpif_remove(struct platform_device *device) · 127 unmodified lines | ||
| 1546 | 1538 | /* Get the pointer to the channel object */ |
| 1547 | 1539 | ch = vpif_obj.dev[i]; |
| 1548 | 1540 | common = &ch->common[VPIF_VIDEO_INDEX]; |
| 1549 | − vb2_dma_contig_cleanup_ctx(common->alloc_ctx); | |
| 1550 | 1541 | /* Unregister video device */ |
| 1551 | 1542 | video_unregister_device(&ch->video_dev); |
| 1552 | 1543 | kfree(vpif_obj.dev[i]); |
| @@ -65,8 +65,6 @@ struct common_obj { · 64 unmodified lines | ||
| 65 | 65 | struct v4l2_format fmt; |
| 66 | 66 | /* Buffer queue used in video-buf */ |
| 67 | 67 | struct vb2_queue buffer_queue; |
| 68 | − /* allocator-specific contexts for each plane */ | |
| 69 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 70 | 68 | /* Queue of filled frames */ |
| 71 | 69 | struct list_head dma_queue; |
| 72 | 70 | /* Used in video-buf */ |
| @@ -102,14 +102,14 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb) · 101 unmodified lines | ||
| 102 | 102 | * @nbuffers: ptr to number of buffers requested by application |
| 103 | 103 | * @nplanes:: contains number of distinct video planes needed to hold a frame |
| 104 | 104 | * @sizes[]: contains the size (in bytes) of each plane. |
| 105 | − * @alloc_ctxs: ptr to allocation context | |
| 105 | + * @alloc_devs: ptr to allocation context | |
| 106 | 106 | * |
| 107 | 107 | * This callback function is called when reqbuf() is called to adjust |
| 108 | 108 | * the buffer count and buffer size |
| 109 | 109 | */ |
| 110 | 110 | static int vpif_buffer_queue_setup(struct vb2_queue *vq, |
| 111 | 111 | unsigned int *nbuffers, unsigned int *nplanes, |
| 112 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 112 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 113 | 113 | { |
| 114 | 114 | struct channel_obj *ch = vb2_get_drv_priv(vq); |
| 115 | 115 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; |
| @@ -126,7 +126,6 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq, · 10 unmodified lines | ||
| 126 | 126 | |
| 127 | 127 | *nplanes = 1; |
| 128 | 128 | sizes[0] = size; |
| 129 | − alloc_ctxs[0] = common->alloc_ctx; | |
| 130 | 129 | |
| 131 | 130 | /* Calculate the offset for Y and C data in the buffer */ |
| 132 | 131 | vpif_calculate_offsets(ch); |
| @@ -1191,19 +1190,13 @@ static int vpif_probe_complete(void) · 1058 unmodified lines | ||
| 1191 | 1190 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1192 | 1191 | q->min_buffers_needed = 1; |
| 1193 | 1192 | q->lock = &common->lock; |
| 1193 | + q->dev = vpif_dev; | |
| 1194 | 1194 | err = vb2_queue_init(q); |
| 1195 | 1195 | if (err) { |
| 1196 | 1196 | vpif_err("vpif_display: vb2_queue_init() failed\n"); |
| 1197 | 1197 | goto probe_out; |
| 1198 | 1198 | } |
| 1199 | 1199 | |
| 1200 | − common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev); | |
| 1201 | − if (IS_ERR(common->alloc_ctx)) { | |
| 1202 | − vpif_err("Failed to get the context\n"); | |
| 1203 | − err = PTR_ERR(common->alloc_ctx); | |
| 1204 | − goto probe_out; | |
| 1205 | − } | |
| 1206 | − | |
| 1207 | 1200 | INIT_LIST_HEAD(&common->dma_queue); |
| 1208 | 1201 | |
| 1209 | 1202 | /* register video device */ |
| @@ -1233,7 +1226,6 @@ probe_out: · 23 unmodified lines | ||
| 1233 | 1226 | for (k = 0; k < j; k++) { |
| 1234 | 1227 | ch = vpif_obj.dev[k]; |
| 1235 | 1228 | common = &ch->common[k]; |
| 1236 | − vb2_dma_contig_cleanup_ctx(common->alloc_ctx); | |
| 1237 | 1229 | video_unregister_device(&ch->video_dev); |
| 1238 | 1230 | } |
| 1239 | 1231 | return err; |
| @@ -1355,7 +1347,6 @@ static int vpif_remove(struct platform_device *device) · 115 unmodified lines | ||
| 1355 | 1347 | /* Get the pointer to the channel object */ |
| 1356 | 1348 | ch = vpif_obj.dev[i]; |
| 1357 | 1349 | common = &ch->common[VPIF_VIDEO_INDEX]; |
| 1358 | − vb2_dma_contig_cleanup_ctx(common->alloc_ctx); | |
| 1359 | 1350 | /* Unregister video device */ |
| 1360 | 1351 | video_unregister_device(&ch->video_dev); |
| 1361 | 1352 | kfree(vpif_obj.dev[i]); |
| @@ -74,8 +74,6 @@ struct common_obj { · 73 unmodified lines | ||
| 74 | 74 | struct v4l2_format fmt; /* Used to store the format */ |
| 75 | 75 | struct vb2_queue buffer_queue; /* Buffer queue used in |
| 76 | 76 | * video-buf */ |
| 77 | − /* allocator-specific contexts for each plane */ | |
| 78 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 79 | 77 | |
| 80 | 78 | struct list_head dma_queue; /* Queue of filled frames */ |
| 81 | 79 | spinlock_t irqlock; /* Used in video-buf */ |
| @@ -1123,19 +1123,13 @@ static int gsc_probe(struct platform_device *pdev) · 1122 unmodified lines | ||
| 1123 | 1123 | if (ret < 0) |
| 1124 | 1124 | goto err_m2m; |
| 1125 | 1125 | |
| 1126 | − /* Initialize continious memory allocator */ | |
| 1127 | − gsc->alloc_ctx = vb2_dma_contig_init_ctx(dev); | |
| 1128 | − if (IS_ERR(gsc->alloc_ctx)) { | |
| 1129 | − ret = PTR_ERR(gsc->alloc_ctx); | |
| 1130 | − goto err_pm; | |
| 1131 | − } | |
| 1126 | + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); | |
| 1132 | 1127 | |
| 1133 | 1128 | dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id); |
| 1134 | 1129 | |
| 1135 | 1130 | pm_runtime_put(dev); |
| 1136 | 1131 | return 0; |
| 1137 | −err_pm: | |
| 1138 | − pm_runtime_put(dev); | |
| 1132 | + | |
| 1139 | 1133 | err_m2m: |
| 1140 | 1134 | gsc_unregister_m2m_device(gsc); |
| 1141 | 1135 | err_v4l2: |
| @@ -1152,7 +1146,7 @@ static int gsc_remove(struct platform_device *pdev) · 10 unmodified lines | ||
| 1152 | 1146 | gsc_unregister_m2m_device(gsc); |
| 1153 | 1147 | v4l2_device_unregister(&gsc->v4l2_dev); |
| 1154 | 1148 | |
| 1155 | − vb2_dma_contig_cleanup_ctx(gsc->alloc_ctx); | |
| 1149 | + vb2_dma_contig_clear_max_seg_size(&pdev->dev); | |
| 1156 | 1150 | pm_runtime_disable(&pdev->dev); |
| 1157 | 1151 | gsc_clk_put(gsc); |
| 1158 | 1152 | |
| @@ -327,7 +327,6 @@ struct gsc_driverdata { · 326 unmodified lines | ||
| 327 | 327 | * @irq_queue: interrupt handler waitqueue |
| 328 | 328 | * @m2m: memory-to-memory V4L2 device information |
| 329 | 329 | * @state: flags used to synchronize m2m and capture mode operation |
| 330 | − * @alloc_ctx: videobuf2 memory allocator context | |
| 331 | 330 | * @vdev: video device for G-Scaler instance |
| 332 | 331 | */ |
| 333 | 332 | struct gsc_dev { |
| @@ -341,7 +340,6 @@ struct gsc_dev { · 7 unmodified lines | ||
| 341 | 340 | wait_queue_head_t irq_queue; |
| 342 | 341 | struct gsc_m2m_device m2m; |
| 343 | 342 | unsigned long state; |
| 344 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 345 | 343 | struct video_device vdev; |
| 346 | 344 | struct v4l2_device v4l2_dev; |
| 347 | 345 | }; |
| @@ -213,7 +213,7 @@ put_device: · 212 unmodified lines | ||
| 213 | 213 | |
| 214 | 214 | static int gsc_m2m_queue_setup(struct vb2_queue *vq, |
| 215 | 215 | unsigned int *num_buffers, unsigned int *num_planes, |
| 216 | − unsigned int sizes[], void *allocators[]) | |
| 216 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 217 | 217 | { |
| 218 | 218 | struct gsc_ctx *ctx = vb2_get_drv_priv(vq); |
| 219 | 219 | struct gsc_frame *frame; |
| @@ -227,10 +227,8 @@ static int gsc_m2m_queue_setup(struct vb2_queue *vq, · 7 unmodified lines | ||
| 227 | 227 | return -EINVAL; |
| 228 | 228 | |
| 229 | 229 | *num_planes = frame->fmt->num_planes; |
| 230 | − for (i = 0; i < frame->fmt->num_planes; i++) { | |
| 230 | + for (i = 0; i < frame->fmt->num_planes; i++) | |
| 231 | 231 | sizes[i] = frame->payload[i]; |
| 232 | − allocators[i] = ctx->gsc_dev->alloc_ctx; | |
| 233 | − } | |
| 234 | 232 | return 0; |
| 235 | 233 | } |
| 236 | 234 | |
| @@ -591,6 +589,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, · 354 unmodified lines | ||
| 591 | 589 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
| 592 | 590 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 593 | 591 | src_vq->lock = &ctx->gsc_dev->lock; |
| 592 | + src_vq->dev = &ctx->gsc_dev->pdev->dev; | |
| 594 | 593 | |
| 595 | 594 | ret = vb2_queue_init(src_vq); |
| 596 | 595 | if (ret) |
| @@ -605,6 +604,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, · 8 unmodified lines | ||
| 605 | 604 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
| 606 | 605 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 607 | 606 | dst_vq->lock = &ctx->gsc_dev->lock; |
| 607 | + dst_vq->dev = &ctx->gsc_dev->pdev->dev; | |
| 608 | 608 | |
| 609 | 609 | return vb2_queue_init(dst_vq); |
| 610 | 610 | } |
| @@ -340,7 +340,7 @@ int fimc_capture_resume(struct fimc_dev *fimc) · 339 unmodified lines | ||
| 340 | 340 | |
| 341 | 341 | static int queue_setup(struct vb2_queue *vq, |
| 342 | 342 | unsigned int *num_buffers, unsigned int *num_planes, |
| 343 | − unsigned int sizes[], void *allocators[]) | |
| 343 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 344 | 344 | { |
| 345 | 345 | struct fimc_ctx *ctx = vq->drv_priv; |
| 346 | 346 | struct fimc_frame *frame = &ctx->d_frame; |
| @@ -354,11 +354,9 @@ static int queue_setup(struct vb2_queue *vq, · 7 unmodified lines | ||
| 354 | 354 | if (*num_planes) { |
| 355 | 355 | if (*num_planes != fmt->memplanes) |
| 356 | 356 | return -EINVAL; |
| 357 | − for (i = 0; i < *num_planes; i++) { | |
| 357 | + for (i = 0; i < *num_planes; i++) | |
| 358 | 358 | if (sizes[i] < (wh * fmt->depth[i]) / 8) |
| 359 | 359 | return -EINVAL; |
| 360 | − allocators[i] = ctx->fimc_dev->alloc_ctx; | |
| 361 | − } | |
| 362 | 360 | return 0; |
| 363 | 361 | } |
| 364 | 362 | |
| @@ -371,8 +369,6 @@ static int queue_setup(struct vb2_queue *vq, · 6 unmodified lines | ||
| 371 | 369 | sizes[i] = frame->payload[i]; |
| 372 | 370 | else |
| 373 | 371 | sizes[i] = max_t(u32, size, frame->payload[i]); |
| 374 | − | |
| 375 | − allocators[i] = ctx->fimc_dev->alloc_ctx; | |
| 376 | 372 | } |
| 377 | 373 | |
| 378 | 374 | return 0; |
| @@ -1779,6 +1775,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, · 1400 unmodified lines | ||
| 1779 | 1775 | q->buf_struct_size = sizeof(struct fimc_vid_buffer); |
| 1780 | 1776 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1781 | 1777 | q->lock = &fimc->lock; |
| 1778 | + q->dev = &fimc->pdev->dev; | |
| 1782 | 1779 | |
| 1783 | 1780 | ret = vb2_queue_init(q); |
| 1784 | 1781 | if (ret) |
| @@ -1018,19 +1018,11 @@ static int fimc_probe(struct platform_device *pdev) · 1017 unmodified lines | ||
| 1018 | 1018 | goto err_sd; |
| 1019 | 1019 | } |
| 1020 | 1020 | |
| 1021 | − /* Initialize contiguous memory allocator */ | |
| 1022 | − fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); | |
| 1023 | − if (IS_ERR(fimc->alloc_ctx)) { | |
| 1024 | − ret = PTR_ERR(fimc->alloc_ctx); | |
| 1025 | − goto err_gclk; | |
| 1026 | − } | |
| 1021 | + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); | |
| 1027 | 1022 | |
| 1028 | 1023 | dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id); |
| 1029 | 1024 | return 0; |
| 1030 | 1025 | |
| 1031 | −err_gclk: | |
| 1032 | − if (!pm_runtime_enabled(dev)) | |
| 1033 | − clk_disable(fimc->clock[CLK_GATE]); | |
| 1034 | 1026 | err_sd: |
| 1035 | 1027 | fimc_unregister_capture_subdev(fimc); |
| 1036 | 1028 | err_sclk: |
| @@ -1123,7 +1115,7 @@ static int fimc_remove(struct platform_device *pdev) · 86 unmodified lines | ||
| 1123 | 1115 | pm_runtime_set_suspended(&pdev->dev); |
| 1124 | 1116 | |
| 1125 | 1117 | fimc_unregister_capture_subdev(fimc); |
| 1126 | − vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); | |
| 1118 | + vb2_dma_contig_clear_max_seg_size(&pdev->dev); | |
| 1127 | 1119 | |
| 1128 | 1120 | clk_disable(fimc->clock[CLK_BUS]); |
| 1129 | 1121 | fimc_clk_put(fimc); |
| @@ -307,7 +307,6 @@ struct fimc_m2m_device { · 306 unmodified lines | ||
| 307 | 307 | */ |
| 308 | 308 | struct fimc_vid_cap { |
| 309 | 309 | struct fimc_ctx *ctx; |
| 310 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 311 | 310 | struct v4l2_subdev subdev; |
| 312 | 311 | struct exynos_video_entity ve; |
| 313 | 312 | struct media_pad vd_pad; |
| @@ -417,7 +416,6 @@ struct fimc_ctx; · 103 unmodified lines | ||
| 417 | 416 | * @m2m: memory-to-memory V4L2 device information |
| 418 | 417 | * @vid_cap: camera capture device information |
| 419 | 418 | * @state: flags used to synchronize m2m and capture mode operation |
| 420 | − * @alloc_ctx: videobuf2 memory allocator context | |
| 421 | 419 | * @pipeline: fimc video capture pipeline data structure |
| 422 | 420 | */ |
| 423 | 421 | struct fimc_dev { |
| @@ -436,7 +434,6 @@ struct fimc_dev { · 12 unmodified lines | ||
| 436 | 434 | struct fimc_m2m_device m2m; |
| 437 | 435 | struct fimc_vid_cap vid_cap; |
| 438 | 436 | unsigned long state; |
| 439 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 440 | 437 | }; |
| 441 | 438 | |
| 442 | 439 | /** |
| @@ -204,9 +204,6 @@ static int fimc_is_register_subdevs(struct fimc_is *is) · 203 unmodified lines | ||
| 204 | 204 | if (ret < 0) |
| 205 | 205 | return ret; |
| 206 | 206 | |
| 207 | − /* Initialize memory allocator context for the ISP DMA. */ | |
| 208 | − is->isp.alloc_ctx = is->alloc_ctx; | |
| 209 | − | |
| 210 | 207 | for_each_compatible_node(i2c_bus, NULL, FIMC_IS_I2C_COMPATIBLE) { |
| 211 | 208 | for_each_available_child_of_node(i2c_bus, child) { |
| 212 | 209 | ret = fimc_is_parse_sensor_config(is, index, child); |
| @@ -847,18 +844,14 @@ static int fimc_is_probe(struct platform_device *pdev) · 634 unmodified lines | ||
| 847 | 844 | if (ret < 0) |
| 848 | 845 | goto err_pm; |
| 849 | 846 | |
| 850 | − is->alloc_ctx = vb2_dma_contig_init_ctx(dev); | |
| 851 | − if (IS_ERR(is->alloc_ctx)) { | |
| 852 | − ret = PTR_ERR(is->alloc_ctx); | |
| 853 | − goto err_pm; | |
| 854 | − } | |
| 847 | + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); | |
| 855 | 848 | /* |
| 856 | 849 | * Register FIMC-IS V4L2 subdevs to this driver. The video nodes |
| 857 | 850 | * will be created within the subdev's registered() callback. |
| 858 | 851 | */ |
| 859 | 852 | ret = fimc_is_register_subdevs(is); |
| 860 | 853 | if (ret < 0) |
| 861 | − goto err_vb; | |
| 854 | + goto err_pm; | |
| 862 | 855 | |
| 863 | 856 | ret = fimc_is_debugfs_create(is); |
| 864 | 857 | if (ret < 0) |
| @@ -877,8 +870,6 @@ err_dfs: · 12 unmodified lines | ||
| 877 | 870 | fimc_is_debugfs_remove(is); |
| 878 | 871 | err_sd: |
| 879 | 872 | fimc_is_unregister_subdevs(is); |
| 880 | −err_vb: | |
| 881 | − vb2_dma_contig_cleanup_ctx(is->alloc_ctx); | |
| 882 | 873 | err_pm: |
| 883 | 874 | if (!pm_runtime_enabled(dev)) |
| 884 | 875 | fimc_is_runtime_suspend(dev); |
| @@ -939,7 +930,7 @@ static int fimc_is_remove(struct platform_device *pdev) · 54 unmodified lines | ||
| 939 | 930 | fimc_is_runtime_suspend(dev); |
| 940 | 931 | free_irq(is->irq, is); |
| 941 | 932 | fimc_is_unregister_subdevs(is); |
| 942 | − vb2_dma_contig_cleanup_ctx(is->alloc_ctx); | |
| 933 | + vb2_dma_contig_clear_max_seg_size(dev); | |
| 943 | 934 | fimc_is_put_clocks(is); |
| 944 | 935 | fimc_is_debugfs_remove(is); |
| 945 | 936 | release_firmware(is->fw.f_w); |
| @@ -233,7 +233,6 @@ struct chain_config { · 232 unmodified lines | ||
| 233 | 233 | * @pdev: pointer to FIMC-IS platform device |
| 234 | 234 | * @pctrl: pointer to pinctrl structure for this device |
| 235 | 235 | * @v4l2_dev: pointer to top the level v4l2_device |
| 236 | − * @alloc_ctx: videobuf2 memory allocator context | |
| 237 | 236 | * @lock: mutex serializing video device and the subdev operations |
| 238 | 237 | * @slock: spinlock protecting this data structure and the hw registers |
| 239 | 238 | * @clocks: FIMC-LITE gate clock |
| @@ -256,7 +255,6 @@ struct fimc_is { · 16 unmodified lines | ||
| 256 | 255 | struct fimc_is_sensor sensor[FIMC_IS_SENSORS_NUM]; |
| 257 | 256 | struct fimc_is_setfile setfile; |
| 258 | 257 | |
| 259 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 260 | 258 | struct v4l2_ctrl_handler ctrl_handler; |
| 261 | 259 | |
| 262 | 260 | struct mutex lock; |
| @@ -40,7 +40,7 @@ · 39 unmodified lines | ||
| 40 | 40 | |
| 41 | 41 | static int isp_video_capture_queue_setup(struct vb2_queue *vq, |
| 42 | 42 | unsigned int *num_buffers, unsigned int *num_planes, |
| 43 | − unsigned int sizes[], void *allocators[]) | |
| 43 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 44 | 44 | { |
| 45 | 45 | struct fimc_isp *isp = vb2_get_drv_priv(vq); |
| 46 | 46 | struct v4l2_pix_format_mplane *vid_fmt = &isp->video_capture.pixfmt; |
| @@ -57,20 +57,16 @@ static int isp_video_capture_queue_setup(struct vb2_queue *vq, · 10 unmodified lines | ||
| 57 | 57 | if (*num_planes) { |
| 58 | 58 | if (*num_planes != fmt->memplanes) |
| 59 | 59 | return -EINVAL; |
| 60 | − for (i = 0; i < *num_planes; i++) { | |
| 60 | + for (i = 0; i < *num_planes; i++) | |
| 61 | 61 | if (sizes[i] < (wh * fmt->depth[i]) / 8) |
| 62 | 62 | return -EINVAL; |
| 63 | − allocators[i] = isp->alloc_ctx; | |
| 64 | − } | |
| 65 | 63 | return 0; |
| 66 | 64 | } |
| 67 | 65 | |
| 68 | 66 | *num_planes = fmt->memplanes; |
| 69 | 67 | |
| 70 | − for (i = 0; i < fmt->memplanes; i++) { | |
| 68 | + for (i = 0; i < fmt->memplanes; i++) | |
| 71 | 69 | sizes[i] = (wh * fmt->depth[i]) / 8; |
| 72 | − allocators[i] = isp->alloc_ctx; | |
| 73 | − } | |
| 74 | 70 | |
| 75 | 71 | return 0; |
| 76 | 72 | } |
| @@ -597,6 +593,7 @@ int fimc_isp_video_device_register(struct fimc_isp *isp, · 520 unmodified lines | ||
| 597 | 593 | q->drv_priv = isp; |
| 598 | 594 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 599 | 595 | q->lock = &isp->video_lock; |
| 596 | + q->dev = &isp->pdev->dev; | |
| 600 | 597 | |
| 601 | 598 | ret = vb2_queue_init(q); |
| 602 | 599 | if (ret < 0) |
| @@ -148,7 +148,6 @@ struct fimc_is_video { · 147 unmodified lines | ||
| 148 | 148 | /** |
| 149 | 149 | * struct fimc_isp - FIMC-IS ISP data structure |
| 150 | 150 | * @pdev: pointer to FIMC-IS platform device |
| 151 | − * @alloc_ctx: videobuf2 memory allocator context | |
| 152 | 151 | * @subdev: ISP v4l2_subdev |
| 153 | 152 | * @subdev_pads: the ISP subdev media pads |
| 154 | 153 | * @test_pattern: test pattern controls |
| @@ -161,7 +160,6 @@ struct fimc_is_video { · 6 unmodified lines | ||
| 161 | 160 | */ |
| 162 | 161 | struct fimc_isp { |
| 163 | 162 | struct platform_device *pdev; |
| 164 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 165 | 163 | struct v4l2_subdev subdev; |
| 166 | 164 | struct media_pad subdev_pads[FIMC_ISP_SD_PADS_NUM]; |
| 167 | 165 | struct v4l2_mbus_framefmt src_fmt; |
| @@ -357,7 +357,7 @@ static void stop_streaming(struct vb2_queue *q) · 356 unmodified lines | ||
| 357 | 357 | |
| 358 | 358 | static int queue_setup(struct vb2_queue *vq, |
| 359 | 359 | unsigned int *num_buffers, unsigned int *num_planes, |
| 360 | − unsigned int sizes[], void *allocators[]) | |
| 360 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 361 | 361 | { |
| 362 | 362 | struct fimc_lite *fimc = vq->drv_priv; |
| 363 | 363 | struct flite_frame *frame = &fimc->out_frame; |
| @@ -371,20 +371,16 @@ static int queue_setup(struct vb2_queue *vq, · 7 unmodified lines | ||
| 371 | 371 | if (*num_planes) { |
| 372 | 372 | if (*num_planes != fmt->memplanes) |
| 373 | 373 | return -EINVAL; |
| 374 | − for (i = 0; i < *num_planes; i++) { | |
| 374 | + for (i = 0; i < *num_planes; i++) | |
| 375 | 375 | if (sizes[i] < (wh * fmt->depth[i]) / 8) |
| 376 | 376 | return -EINVAL; |
| 377 | − allocators[i] = fimc->alloc_ctx; | |
| 378 | − } | |
| 379 | 377 | return 0; |
| 380 | 378 | } |
| 381 | 379 | |
| 382 | 380 | *num_planes = fmt->memplanes; |
| 383 | 381 | |
| 384 | − for (i = 0; i < fmt->memplanes; i++) { | |
| 382 | + for (i = 0; i < fmt->memplanes; i++) | |
| 385 | 383 | sizes[i] = (wh * fmt->depth[i]) / 8; |
| 386 | − allocators[i] = fimc->alloc_ctx; | |
| 387 | − } | |
| 388 | 384 | |
| 389 | 385 | return 0; |
| 390 | 386 | } |
| @@ -1300,6 +1296,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) · 909 unmodified lines | ||
| 1300 | 1296 | q->drv_priv = fimc; |
| 1301 | 1297 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1302 | 1298 | q->lock = &fimc->lock; |
| 1299 | + q->dev = &fimc->pdev->dev; | |
| 1303 | 1300 | |
| 1304 | 1301 | ret = vb2_queue_init(q); |
| 1305 | 1302 | if (ret < 0) |
| @@ -1551,11 +1548,7 @@ static int fimc_lite_probe(struct platform_device *pdev) · 245 unmodified lines | ||
| 1551 | 1548 | goto err_sd; |
| 1552 | 1549 | } |
| 1553 | 1550 | |
| 1554 | − fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); | |
| 1555 | − if (IS_ERR(fimc->alloc_ctx)) { | |
| 1556 | − ret = PTR_ERR(fimc->alloc_ctx); | |
| 1557 | − goto err_clk_dis; | |
| 1558 | − } | |
| 1551 | + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); | |
| 1559 | 1552 | |
| 1560 | 1553 | fimc_lite_set_default_config(fimc); |
| 1561 | 1554 | |
| @@ -1563,9 +1556,6 @@ static int fimc_lite_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 1563 | 1556 | fimc->index); |
| 1564 | 1557 | return 0; |
| 1565 | 1558 | |
| 1566 | −err_clk_dis: | |
| 1567 | − if (!pm_runtime_enabled(dev)) | |
| 1568 | − clk_disable(fimc->clock); | |
| 1569 | 1559 | err_sd: |
| 1570 | 1560 | fimc_lite_unregister_capture_subdev(fimc); |
| 1571 | 1561 | err_clk_put: |
| @@ -1651,7 +1641,7 @@ static int fimc_lite_remove(struct platform_device *pdev) · 79 unmodified lines | ||
| 1651 | 1641 | pm_runtime_disable(dev); |
| 1652 | 1642 | pm_runtime_set_suspended(dev); |
| 1653 | 1643 | fimc_lite_unregister_capture_subdev(fimc); |
| 1654 | − vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); | |
| 1644 | + vb2_dma_contig_clear_max_seg_size(dev); | |
| 1655 | 1645 | fimc_lite_clk_put(fimc); |
| 1656 | 1646 | |
| 1657 | 1647 | dev_info(dev, "Driver unloaded\n"); |
| @@ -113,7 +113,6 @@ struct flite_buffer { · 112 unmodified lines | ||
| 113 | 113 | * @ve: exynos video device entity structure |
| 114 | 114 | * @v4l2_dev: pointer to top the level v4l2_device |
| 115 | 115 | * @fh: v4l2 file handle |
| 116 | − * @alloc_ctx: videobuf2 memory allocator context | |
| 117 | 116 | * @subdev: FIMC-LITE subdev |
| 118 | 117 | * @vd_pad: media (sink) pad for the capture video node |
| 119 | 118 | * @subdev_pads: the subdev media pads |
| @@ -148,7 +147,6 @@ struct fimc_lite { · 28 unmodified lines | ||
| 148 | 147 | struct exynos_video_entity ve; |
| 149 | 148 | struct v4l2_device *v4l2_dev; |
| 150 | 149 | struct v4l2_fh fh; |
| 151 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 152 | 150 | struct v4l2_subdev subdev; |
| 153 | 151 | struct media_pad vd_pad; |
| 154 | 152 | struct media_pad subdev_pads[FLITE_SD_PADS_NUM]; |
| @@ -50,30 +50,28 @@ void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state) · 49 unmodified lines | ||
| 50 | 50 | src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); |
| 51 | 51 | dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); |
| 52 | 52 | |
| 53 | − if (src_vb && dst_vb) { | |
| 53 | + if (src_vb) | |
| 54 | 54 | v4l2_m2m_buf_done(src_vb, vb_state); |
| 55 | + if (dst_vb) | |
| 55 | 56 | v4l2_m2m_buf_done(dst_vb, vb_state); |
| 57 | + if (src_vb && dst_vb) | |
| 56 | 58 | v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev, |
| 57 | 59 | ctx->fh.m2m_ctx); |
| 58 | − } | |
| 59 | 60 | } |
| 60 | 61 | |
| 61 | 62 | /* Complete the transaction which has been scheduled for execution. */ |
| 62 | −static int fimc_m2m_shutdown(struct fimc_ctx *ctx) | |
| 63 | +static void fimc_m2m_shutdown(struct fimc_ctx *ctx) | |
| 63 | 64 | { |
| 64 | 65 | struct fimc_dev *fimc = ctx->fimc_dev; |
| 65 | − int ret; | |
| 66 | 66 | |
| 67 | 67 | if (!fimc_m2m_pending(fimc)) |
| 68 | − return 0; | |
| 68 | + return; | |
| 69 | 69 | |
| 70 | 70 | fimc_ctx_state_set(FIMC_CTX_SHUT, ctx); |
| 71 | 71 | |
| 72 | − ret = wait_event_timeout(fimc->irq_queue, | |
| 73 | − !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx), | |
| 74 | − FIMC_SHUTDOWN_TIMEOUT); | |
| 75 | − | |
| 76 | − return ret == 0 ? -ETIMEDOUT : ret; | |
| 72 | + wait_event_timeout(fimc->irq_queue, | |
| 73 | + !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx), | |
| 74 | + FIMC_SHUTDOWN_TIMEOUT); | |
| 77 | 75 | } |
| 78 | 76 | |
| 79 | 77 | static int start_streaming(struct vb2_queue *q, unsigned int count) |
| @@ -88,12 +86,10 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) · 8 unmodified lines | ||
| 88 | 86 | static void stop_streaming(struct vb2_queue *q) |
| 89 | 87 | { |
| 90 | 88 | struct fimc_ctx *ctx = q->drv_priv; |
| 91 | − int ret; | |
| 92 | 89 | |
| 93 | − ret = fimc_m2m_shutdown(ctx); | |
| 94 | − if (ret == -ETIMEDOUT) | |
| 95 | − fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); | |
| 96 | 90 | |
| 91 | + fimc_m2m_shutdown(ctx); | |
| 92 | + fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); | |
| 97 | 93 | pm_runtime_put(&ctx->fimc_dev->pdev->dev); |
| 98 | 94 | } |
| 99 | 95 | |
| @@ -178,7 +174,7 @@ static void fimc_job_abort(void *priv) · 78 unmodified lines | ||
| 178 | 174 | |
| 179 | 175 | static int fimc_queue_setup(struct vb2_queue *vq, |
| 180 | 176 | unsigned int *num_buffers, unsigned int *num_planes, |
| 181 | − unsigned int sizes[], void *allocators[]) | |
| 177 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 182 | 178 | { |
| 183 | 179 | struct fimc_ctx *ctx = vb2_get_drv_priv(vq); |
| 184 | 180 | struct fimc_frame *f; |
| @@ -195,10 +191,8 @@ static int fimc_queue_setup(struct vb2_queue *vq, · 10 unmodified lines | ||
| 195 | 191 | return -EINVAL; |
| 196 | 192 | |
| 197 | 193 | *num_planes = f->fmt->memplanes; |
| 198 | − for (i = 0; i < f->fmt->memplanes; i++) { | |
| 194 | + for (i = 0; i < f->fmt->memplanes; i++) | |
| 199 | 195 | sizes[i] = f->payload[i]; |
| 200 | − allocators[i] = ctx->fimc_dev->alloc_ctx; | |
| 201 | − } | |
| 202 | 196 | return 0; |
| 203 | 197 | } |
| 204 | 198 | |
| @@ -562,6 +556,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, · 357 unmodified lines | ||
| 562 | 556 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
| 563 | 557 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 564 | 558 | src_vq->lock = &ctx->fimc_dev->lock; |
| 559 | + src_vq->dev = &ctx->fimc_dev->pdev->dev; | |
| 565 | 560 | |
| 566 | 561 | ret = vb2_queue_init(src_vq); |
| 567 | 562 | if (ret) |
| @@ -575,6 +570,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, · 7 unmodified lines | ||
| 575 | 570 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
| 576 | 571 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 577 | 572 | dst_vq->lock = &ctx->fimc_dev->lock; |
| 573 | + dst_vq->dev = &ctx->fimc_dev->pdev->dev; | |
| 578 | 574 | |
| 579 | 575 | return vb2_queue_init(dst_vq); |
| 580 | 576 | } |
| @@ -649,23 +649,6 @@ static int s5pcsis_log_status(struct v4l2_subdev *sd) · 648 unmodified lines | ||
| 649 | 649 | return 0; |
| 650 | 650 | } |
| 651 | 651 | |
| 652 | −static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |
| 653 | −{ | |
| 654 | − struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0); | |
| 655 | − | |
| 656 | − format->colorspace = V4L2_COLORSPACE_JPEG; | |
| 657 | − format->code = s5pcsis_formats[0].code; | |
| 658 | − format->width = S5PCSIS_DEF_PIX_WIDTH; | |
| 659 | − format->height = S5PCSIS_DEF_PIX_HEIGHT; | |
| 660 | − format->field = V4L2_FIELD_NONE; | |
| 661 | − | |
| 662 | − return 0; | |
| 663 | −} | |
| 664 | − | |
| 665 | −static const struct v4l2_subdev_internal_ops s5pcsis_sd_internal_ops = { | |
| 666 | − .open = s5pcsis_open, | |
| 667 | −}; | |
| 668 | − | |
| 669 | 652 | static struct v4l2_subdev_core_ops s5pcsis_core_ops = { |
| 670 | 653 | .s_power = s5pcsis_s_power, |
| 671 | 654 | .log_status = s5pcsis_log_status, |
| @@ -136,7 +136,6 @@ struct deinterlace_dev { · 135 unmodified lines | ||
| 136 | 136 | struct dma_chan *dma_chan; |
| 137 | 137 | |
| 138 | 138 | struct v4l2_m2m_dev *m2m_dev; |
| 139 | − struct vb2_alloc_ctx *alloc_ctx; | |
| 140 | 139 | }; |
| 141 | 140 | |
| 142 | 141 | struct deinterlace_ctx { |
| @@ -799,7 +798,7 @@ struct vb2_dc_conf { · 656 unmodified lines | ||
| 799 | 798 | |
| 800 | 799 | static int deinterlace_queue_setup(struct vb2_queue *vq, |
| 801 | 800 | unsigned int *nbuffers, unsigned int *nplanes, |
| 802 | − unsigned int sizes[], void *alloc_ctxs[]) | |
| 801 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 803 | 802 | { |
| 804 | 803 | struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq); |
| 805 | 804 | struct deinterlace_q_data *q_data; |
| @@ -820,8 +819,6 @@ static int deinterlace_queue_setup(struct vb2_queue *vq, · 14 unmodified lines | ||
| 820 | 819 | *nbuffers = count; |
| 821 | 820 | sizes[0] = size; |
| 822 | 821 | |
| 823 | − alloc_ctxs[0] = ctx->dev->alloc_ctx; | |
| 824 | − | |
| 825 | 822 | dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size); |
| 826 | 823 | |
| 827 | 824 | return 0; |
| @@ -874,6 +871,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, · 46 unmodified lines | ||
| 874 | 871 | src_vq->ops = &deinterlace_qops; |
| 875 | 872 | src_vq->mem_ops = &vb2_dma_contig_memops; |
| 876 | 873 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 874 | + src_vq->dev = ctx->dev->v4l2_dev.dev; | |
| 877 | 875 | q_data[V4L2_M2M_SRC].fmt = &formats[0]; |
| 878 | 876 | q_data[V4L2_M2M_SRC].width = 640; |
| 879 | 877 | q_data[V4L2_M2M_SRC].height = 480; |
| @@ -891,6 +889,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, · 11 unmodified lines | ||
| 891 | 889 | dst_vq->ops = &deinterlace_qops; |
| 892 | 890 | dst_vq->mem_ops = &vb2_dma_contig_memops; |
| 893 | 891 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 892 | + dst_vq->dev = ctx->dev->v4l2_dev.dev; | |
| 894 | 893 | q_data[V4L2_M2M_DST].fmt = &formats[0]; |
| 895 | 894 | q_data[V4L2_M2M_DST].width = 640; |
| 896 | 895 | q_data[V4L2_M2M_DST].height = 480; |
| @@ -1046,13 +1045,6 @@ static int deinterlace_probe(struct platform_device *pdev) · 149 unmodified lines | ||
| 1046 | 1045 | |
| 1047 | 1046 | platform_set_drvdata(pdev, pcdev); |
| 1048 | 1047 | |
| 1049 | − pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | |
| 1050 | − if (IS_ERR(pcdev->alloc_ctx)) { | |
| 1051 | − v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n"); | |
| 1052 | − ret = PTR_ERR(pcdev->alloc_ctx); | |
| 1053 | − goto err_ctx; | |
| 1054 | − } | |
| 1055 | − | |
| 1056 | 1048 | pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops); |
| 1057 | 1049 | if (IS_ERR(pcdev->m2m_dev)) { |
| 1058 | 1050 | v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n"); |
| @@ -1064,8 +1056,6 @@ static int deinterlace_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 1064 | 1056 | |
| 1065 | 1057 | err_m2m: |
| 1066 | 1058 | video_unregister_device(&pcdev->vfd); |
| 1067 | −err_ctx: | |
| 1068 | − vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | |
| 1069 | 1059 | unreg_dev: |
| 1070 | 1060 | v4l2_device_unregister(&pcdev->v4l2_dev); |
| 1071 | 1061 | rel_dma: |
| @@ -1082,7 +1072,6 @@ static int deinterlace_remove(struct platform_device *pdev) · 10 unmodified lines | ||
| 1082 | 1072 | v4l2_m2m_release(pcdev->m2m_dev); |
| 1083 | 1073 | video_unregister_device(&pcdev->vfd); |
| 1084 | 1074 | v4l2_device_unregister(&pcdev->v4l2_dev); |
| 1085 | − vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | |
| 1086 | 1075 | dma_release_channel(pcdev->dma_chan); |
| 1087 | 1076 | |
| 1088 | 1077 | return 0; |
| @@ -973,7 +973,7 @@ static int mcam_cam_set_flip(struct mcam_camera *cam) · 972 unmodified lines | ||
| 973 | 973 | memset(&ctrl, 0, sizeof(ctrl)); |
| 974 | 974 | ctrl.id = V4L2_CID_VFLIP; |
| 975 | 975 | ctrl.value = flip; |
| 976 | − return sensor_call(cam, core, s_ctrl, &ctrl); | |
| 976 | + return v4l2_s_ctrl(NULL, cam->sensor->ctrl_handler, &ctrl); | |
| 977 | 977 | } |
| 978 | 978 | |
| 979 | 979 | |
| @@ -1051,7 +1051,7 @@ static int mcam_read_setup(struct mcam_camera *cam) · 71 unmodified lines | ||
| 1051 | 1051 | static int mcam_vb_queue_setup(struct vb2_queue *vq, |
| 1052 | 1052 | unsigned int *nbufs, |
| 1053 | 1053 | unsigned int *num_planes, unsigned int sizes[], |
| 1054 | − void *alloc_ctxs[]) | |
| 1054 | + struct device *alloc_devs[]) | |
| 1055 | 1055 | { |
| 1056 | 1056 | struct mcam_camera *cam = vb2_get_drv_priv(vq); |
| 1057 | 1057 | int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2; |
| @@ -1059,10 +1059,6 @@ static int mcam_vb_queue_setup(struct vb2_queue *vq, · 1 unmodified line | ||
| 1059 | 1059 | |
| 1060 | 1060 | if (*nbufs < minbufs) |
| 1061 | 1061 | *nbufs = minbufs; |
| 1062 | − if (cam->buffer_mode == B_DMA_contig) | |
| 1063 | − alloc_ctxs[0] = cam->vb_alloc_ctx; | |
| 1064 | − else if (cam->buffer_mode == B_DMA_sg) | |
| 1065 | − alloc_ctxs[0] = cam->vb_alloc_ctx_sg; | |
| 1066 | 1062 | |
| 1067 | 1063 | if (*num_planes) |
| 1068 | 1064 | return sizes[0] < size ? -EINVAL : 0; |
| @@ -1271,6 +1267,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam) · 202 unmodified lines | ||
| 1271 | 1267 | vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1272 | 1268 | vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; |
| 1273 | 1269 | vq->buf_struct_size = sizeof(struct mcam_vb_buffer); |
| 1270 | + vq->dev = cam->dev; | |
| 1274 | 1271 | INIT_LIST_HEAD(&cam->buffers); |
| 1275 | 1272 | switch (cam->buffer_mode) { |
| 1276 | 1273 | case B_DMA_contig: |
| @@ -1279,9 +1276,6 @@ static int mcam_setup_vb2(struct mcam_camera *cam) · 2 unmodified lines | ||
| 1279 | 1276 | vq->mem_ops = &vb2_dma_contig_memops; |
| 1280 | 1277 | cam->dma_setup = mcam_ctlr_dma_contig; |
| 1281 | 1278 | cam->frame_complete = mcam_dma_contig_done; |
| 1282 | − cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev); | |
| 1283 | − if (IS_ERR(cam->vb_alloc_ctx)) | |
| 1284 | − return PTR_ERR(cam->vb_alloc_ctx); | |
| 1285 | 1279 | #endif |
| 1286 | 1280 | break; |
| 1287 | 1281 | case B_DMA_sg: |
| @@ -1290,9 +1284,6 @@ static int mcam_setup_vb2(struct mcam_camera *cam) · 2 unmodified lines | ||
| 1290 | 1284 | vq->mem_ops = &vb2_dma_sg_memops; |
| 1291 | 1285 | cam->dma_setup = mcam_ctlr_dma_sg; |
| 1292 | 1286 | cam->frame_complete = mcam_dma_sg_done; |
| 1293 | − cam->vb_alloc_ctx_sg = vb2_dma_sg_init_ctx(cam->dev); | |
| 1294 | − if (IS_ERR(cam->vb_alloc_ctx_sg)) | |
| 1295 | − return PTR_ERR(cam->vb_alloc_ctx_sg); | |
| 1296 | 1287 | #endif |
| 1297 | 1288 | break; |
| 1298 | 1289 | case B_vmalloc: |
| @@ -1309,18 +1300,6 @@ static int mcam_setup_vb2(struct mcam_camera *cam) · 10 unmodified lines | ||
| 1309 | 1300 | return vb2_queue_init(vq); |
| 1310 | 1301 | } |
| 1311 | 1302 | |
| 1312 | −static void mcam_cleanup_vb2(struct mcam_camera *cam) | |
| 1313 | −{ | |
| 1314 | −#ifdef MCAM_MODE_DMA_CONTIG | |
| 1315 | − if (cam->buffer_mode == B_DMA_contig) | |
| 1316 | − vb2_dma_contig_cleanup_ctx(cam->vb_alloc_ctx); | |
| 1317 | −#endif | |
| 1318 | −#ifdef MCAM_MODE_DMA_SG | |
| 1319 | − if (cam->buffer_mode == B_DMA_sg) | |
| 1320 | − vb2_dma_sg_cleanup_ctx(cam->vb_alloc_ctx_sg); | |
| 1321 | −#endif | |
| 1322 | −} | |
| 1323 | − | |
| 1324 | 1303 | |
| 1325 | 1304 | /* ---------------------------------------------------------------------- */ |
| 1326 | 1305 | /* |
| @@ -1875,7 +1854,6 @@ void mccic_shutdown(struct mcam_camera *cam) · 548 unmodified lines | ||
| 1875 | 1854 | cam_warn(cam, "Removing a device with users!\n"); |
| 1876 | 1855 | mcam_ctlr_power_down(cam); |
| 1877 | 1856 | } |
| 1878 | − mcam_cleanup_vb2(cam); | |
| 1879 | 1857 | if (cam->buffer_mode == B_vmalloc) |
| 1880 | 1858 | mcam_free_dma_bufs(cam); |
| 1881 | 1859 | video_unregister_device(&cam->vdev); |
| @@ -176,8 +176,6 @@ struct mcam_camera { · 175 unmodified lines | ||
| 176 | 176 | |
| 177 | 177 | /* DMA buffers - DMA modes */ |
| 178 | 178 | struct mcam_vb_buffer *vb_bufs[MAX_DMA_BUFS]; |
| 179 | − struct vb2_alloc_ctx *vb_alloc_ctx; | |
| 180 | − struct vb2_alloc_ctx *vb_alloc_ctx_sg; | |
| 181 | 179 | |
| 182 | 180 | /* Mode-specific ops, set at open time */ |
| 183 | 181 | void (*dma_setup)(struct mcam_camera *cam); |
| @@ -0,0 +1,19 @@ | ||
| 1 | + | |
| 2 | + | |
| 3 | +obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-enc.o mtk-vcodec-common.o | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | +mtk-vcodec-enc-y := venc/venc_vp8_if.o \ | |
| 8 | + venc/venc_h264_if.o \ | |
| 9 | + mtk_vcodec_enc.o \ | |
| 10 | + mtk_vcodec_enc_drv.o \ | |
| 11 | + mtk_vcodec_enc_pm.o \ | |
| 12 | + venc_drv_if.o \ | |
| 13 | + venc_vpu_if.o \ | |
| 14 | + | |
| 15 | + | |
| 16 | +mtk-vcodec-common-y := mtk_vcodec_intr.o \ | |
| 17 | + mtk_vcodec_util.o\ | |
| 18 | + | |
| 19 | +ccflags-y += -I$(srctree)/drivers/media/platform/mtk-vpu | |
| @@ -0,0 +1,335 @@ | ||
| 1 | +/* | |
| 2 | +* Copyright (c) 2016 MediaTek Inc. | |
| 3 | +* Author: PC Chen <pc.chen@mediatek.com> | |
| 4 | +* Tiffany Lin <tiffany.lin@mediatek.com> | |
| 5 | +* | |
| 6 | +* This program is free software; you can redistribute it and/or modify | |
| 7 | +* it under the terms of the GNU General Public License version 2 as | |
| 8 | +* published by the Free Software Foundation. | |
| 9 | +* | |
| 10 | +* This program is distributed in the hope that it will be useful, | |
| 11 | +* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | +* GNU General Public License for more details. | |
| 14 | +*/ | |
| 15 | + | |
| 16 | +#ifndef _MTK_VCODEC_DRV_H_ | |
| 17 | +#define _MTK_VCODEC_DRV_H_ | |
| 18 | + | |
| 19 | +#include <linux/platform_device.h> | |
| 20 | +#include <linux/videodev2.h> | |
| 21 | +#include <media/v4l2-ctrls.h> | |
| 22 | +#include <media/v4l2-device.h> | |
| 23 | +#include <media/v4l2-ioctl.h> | |
| 24 | +#include <media/videobuf2-core.h> | |
| 25 | + | |
| 26 | +#include "mtk_vcodec_util.h" | |
| 27 | + | |
| 28 | +#define MTK_VCODEC_DRV_NAME "mtk_vcodec_drv" | |
| 29 | +#define MTK_VCODEC_ENC_NAME "mtk-vcodec-enc" | |
| 30 | +#define MTK_PLATFORM_STR "platform:mt8173" | |
| 31 | + | |
| 32 | + | |
| 33 | +#define MTK_VCODEC_MAX_PLANES 3 | |
| 34 | +#define MTK_V4L2_BENCHMARK 0 | |
| 35 | +#define WAIT_INTR_TIMEOUT_MS 1000 | |
| 36 | + | |
| 37 | +/** | |
| 38 | + * enum mtk_hw_reg_idx - MTK hw register base index | |
| 39 | + */ | |
| 40 | +enum mtk_hw_reg_idx { | |
| 41 | + VDEC_SYS, | |
| 42 | + VDEC_MISC, | |
| 43 | + VDEC_LD, | |
| 44 | + VDEC_TOP, | |
| 45 | + VDEC_CM, | |
| 46 | + VDEC_AD, | |
| 47 | + VDEC_AV, | |
| 48 | + VDEC_PP, | |
| 49 | + VDEC_HWD, | |
| 50 | + VDEC_HWQ, | |
| 51 | + VDEC_HWB, | |
| 52 | + VDEC_HWG, | |
| 53 | + NUM_MAX_VDEC_REG_BASE, | |
| 54 | + /* h264 encoder */ | |
| 55 | + VENC_SYS = NUM_MAX_VDEC_REG_BASE, | |
| 56 | + /* vp8 encoder */ | |
| 57 | + VENC_LT_SYS, | |
| 58 | + NUM_MAX_VCODEC_REG_BASE | |
| 59 | +}; | |
| 60 | + | |
| 61 | +/** | |
| 62 | + * enum mtk_instance_type - The type of an MTK Vcodec instance. | |
| 63 | + */ | |
| 64 | +enum mtk_instance_type { | |
| 65 | + MTK_INST_DECODER = 0, | |
| 66 | + MTK_INST_ENCODER = 1, | |
| 67 | +}; | |
| 68 | + | |
| 69 | +/** | |
| 70 | + * enum mtk_instance_state - The state of an MTK Vcodec instance. | |
| 71 | + * @MTK_STATE_FREE - default state when instance is created | |
| 72 | + * @MTK_STATE_INIT - vcodec instance is initialized | |
| 73 | + * @MTK_STATE_HEADER - vdec had sps/pps header parsed or venc | |
| 74 | + * had sps/pps header encoded | |
| 75 | + * @MTK_STATE_FLUSH - vdec is flushing. Only used by decoder | |
| 76 | + * @MTK_STATE_ABORT - vcodec should be aborted | |
| 77 | + */ | |
| 78 | +enum mtk_instance_state { | |
| 79 | + MTK_STATE_FREE = 0, | |
| 80 | + MTK_STATE_INIT = 1, | |
| 81 | + MTK_STATE_HEADER = 2, | |
| 82 | + MTK_STATE_FLUSH = 3, | |
| 83 | + MTK_STATE_ABORT = 4, | |
| 84 | +}; | |
| 85 | + | |
| 86 | +/** | |
| 87 | + * struct mtk_encode_param - General encoding parameters type | |
| 88 | + */ | |
| 89 | +enum mtk_encode_param { | |
| 90 | + MTK_ENCODE_PARAM_NONE = 0, | |
| 91 | + MTK_ENCODE_PARAM_BITRATE = (1 << 0), | |
| 92 | + MTK_ENCODE_PARAM_FRAMERATE = (1 << 1), | |
| 93 | + MTK_ENCODE_PARAM_INTRA_PERIOD = (1 << 2), | |
| 94 | + MTK_ENCODE_PARAM_FORCE_INTRA = (1 << 3), | |
| 95 | + MTK_ENCODE_PARAM_GOP_SIZE = (1 << 4), | |
| 96 | +}; | |
| 97 | + | |
| 98 | +enum mtk_fmt_type { | |
| 99 | + MTK_FMT_DEC = 0, | |
| 100 | + MTK_FMT_ENC = 1, | |
| 101 | + MTK_FMT_FRAME = 2, | |
| 102 | +}; | |
| 103 | + | |
| 104 | +/** | |
| 105 | + * struct mtk_video_fmt - Structure used to store information about pixelformats | |
| 106 | + */ | |
| 107 | +struct mtk_video_fmt { | |
| 108 | + u32 fourcc; | |
| 109 | + enum mtk_fmt_type type; | |
| 110 | + u32 num_planes; | |
| 111 | +}; | |
| 112 | + | |
| 113 | +/** | |
| 114 | + * struct mtk_codec_framesizes - Structure used to store information about | |
| 115 | + * framesizes | |
| 116 | + */ | |
| 117 | +struct mtk_codec_framesizes { | |
| 118 | + u32 fourcc; | |
| 119 | + struct v4l2_frmsize_stepwise stepwise; | |
| 120 | +}; | |
| 121 | + | |
| 122 | +/** | |
| 123 | + * struct mtk_q_type - Type of queue | |
| 124 | + */ | |
| 125 | +enum mtk_q_type { | |
| 126 | + MTK_Q_DATA_SRC = 0, | |
| 127 | + MTK_Q_DATA_DST = 1, | |
| 128 | +}; | |
| 129 | + | |
| 130 | +/** | |
| 131 | + * struct mtk_q_data - Structure used to store information about queue | |
| 132 | + */ | |
| 133 | +struct mtk_q_data { | |
| 134 | + unsigned int visible_width; | |
| 135 | + unsigned int visible_height; | |
| 136 | + unsigned int coded_width; | |
| 137 | + unsigned int coded_height; | |
| 138 | + enum v4l2_field field; | |
| 139 | + unsigned int bytesperline[MTK_VCODEC_MAX_PLANES]; | |
| 140 | + unsigned int sizeimage[MTK_VCODEC_MAX_PLANES]; | |
| 141 | + struct mtk_video_fmt *fmt; | |
| 142 | +}; | |
| 143 | + | |
| 144 | +/** | |
| 145 | + * struct mtk_enc_params - General encoding parameters | |
| 146 | + * @bitrate: target bitrate in bits per second | |
| 147 | + * @num_b_frame: number of b frames between p-frame | |
| 148 | + * @rc_frame: frame based rate control | |
| 149 | + * @rc_mb: macroblock based rate control | |
| 150 | + * @seq_hdr_mode: H.264 sequence header is encoded separately or joined | |
| 151 | + * with the first frame | |
| 152 | + * @intra_period: I frame period | |
| 153 | + * @gop_size: group of picture size, it's used as the intra frame period | |
| 154 | + * @framerate_num: frame rate numerator. ex: framerate_num=30 and | |
| 155 | + * framerate_denom=1 menas FPS is 30 | |
| 156 | + * @framerate_denom: frame rate denominator. ex: framerate_num=30 and | |
| 157 | + * framerate_denom=1 menas FPS is 30 | |
| 158 | + * @h264_max_qp: Max value for H.264 quantization parameter | |
| 159 | + * @h264_profile: V4L2 defined H.264 profile | |
| 160 | + * @h264_level: V4L2 defined H.264 level | |
| 161 | + * @force_intra: force/insert intra frame | |
| 162 | + */ | |
| 163 | +struct mtk_enc_params { | |
| 164 | + unsigned int bitrate; | |
| 165 | + unsigned int num_b_frame; | |
| 166 | + unsigned int rc_frame; | |
| 167 | + unsigned int rc_mb; | |
| 168 | + unsigned int seq_hdr_mode; | |
| 169 | + unsigned int intra_period; | |
| 170 | + unsigned int gop_size; | |
| 171 | + unsigned int framerate_num; | |
| 172 | + unsigned int framerate_denom; | |
| 173 | + unsigned int h264_max_qp; | |
| 174 | + unsigned int h264_profile; | |
| 175 | + unsigned int h264_level; | |
| 176 | + unsigned int force_intra; | |
| 177 | +}; | |
| 178 | + | |
| 179 | +/** | |
| 180 | + * struct mtk_vcodec_pm - Power management data structure | |
| 181 | + */ | |
| 182 | +struct mtk_vcodec_pm { | |
| 183 | + struct clk *vcodecpll; | |
| 184 | + struct clk *univpll_d2; | |
| 185 | + struct clk *clk_cci400_sel; | |
| 186 | + struct clk *vdecpll; | |
| 187 | + struct clk *vdec_sel; | |
| 188 | + struct clk *vencpll_d2; | |
| 189 | + struct clk *venc_sel; | |
| 190 | + struct clk *univpll1_d2; | |
| 191 | + struct clk *venc_lt_sel; | |
| 192 | + struct device *larbvdec; | |
| 193 | + struct device *larbvenc; | |
| 194 | + struct device *larbvenclt; | |
| 195 | + struct device *dev; | |
| 196 | + struct mtk_vcodec_dev *mtkdev; | |
| 197 | +}; | |
| 198 | + | |
| 199 | +/** | |
| 200 | + * struct mtk_vcodec_ctx - Context (instance) private data. | |
| 201 | + * | |
| 202 | + * @type: type of the instance - decoder or encoder | |
| 203 | + * @dev: pointer to the mtk_vcodec_dev of the device | |
| 204 | + * @list: link to ctx_list of mtk_vcodec_dev | |
| 205 | + * @fh: struct v4l2_fh | |
| 206 | + * @m2m_ctx: pointer to the v4l2_m2m_ctx of the context | |
| 207 | + * @q_data: store information of input and output queue | |
| 208 | + * of the context | |
| 209 | + * @id: index of the context that this structure describes | |
| 210 | + * @state: state of the context | |
| 211 | + * @param_change: indicate encode parameter type | |
| 212 | + * @enc_params: encoding parameters | |
| 213 | + * @enc_if: hoooked encoder driver interface | |
| 214 | + * @drv_handle: driver handle for specific decode/encode instance | |
| 215 | + * | |
| 216 | + * @int_cond: variable used by the waitqueue | |
| 217 | + * @int_type: type of the last interrupt | |
| 218 | + * @queue: waitqueue that can be used to wait for this context to | |
| 219 | + * finish | |
| 220 | + * @irq_status: irq status | |
| 221 | + * | |
| 222 | + * @ctrl_hdl: handler for v4l2 framework | |
| 223 | + * @encode_work: worker for the encoding | |
| 224 | + * | |
| 225 | + * @colorspace: enum v4l2_colorspace; supplemental to pixelformat | |
| 226 | + * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding | |
| 227 | + * @quantization: enum v4l2_quantization, colorspace quantization | |
| 228 | + * @xfer_func: enum v4l2_xfer_func, colorspace transfer function | |
| 229 | + */ | |
| 230 | +struct mtk_vcodec_ctx { | |
| 231 | + enum mtk_instance_type type; | |
| 232 | + struct mtk_vcodec_dev *dev; | |
| 233 | + struct list_head list; | |
| 234 | + | |
| 235 | + struct v4l2_fh fh; | |
| 236 | + struct v4l2_m2m_ctx *m2m_ctx; | |
| 237 | + struct mtk_q_data q_data[2]; | |
| 238 | + int id; | |
| 239 | + enum mtk_instance_state state; | |
| 240 | + enum mtk_encode_param param_change; | |
| 241 | + struct mtk_enc_params enc_params; | |
| 242 | + | |
| 243 | + struct venc_common_if *enc_if; | |
| 244 | + unsigned long drv_handle; | |
| 245 | + | |
| 246 | + int int_cond; | |
| 247 | + int int_type; | |
| 248 | + wait_queue_head_t queue; | |
| 249 | + unsigned int irq_status; | |
| 250 | + | |
| 251 | + struct v4l2_ctrl_handler ctrl_hdl; | |
| 252 | + struct work_struct encode_work; | |
| 253 | + | |
| 254 | + enum v4l2_colorspace colorspace; | |
| 255 | + enum v4l2_ycbcr_encoding ycbcr_enc; | |
| 256 | + enum v4l2_quantization quantization; | |
| 257 | + enum v4l2_xfer_func xfer_func; | |
| 258 | +}; | |
| 259 | + | |
| 260 | +/** | |
| 261 | + * struct mtk_vcodec_dev - driver data | |
| 262 | + * @v4l2_dev: V4L2 device to register video devices for. | |
| 263 | + * @vfd_enc: Video device for encoder. | |
| 264 | + * | |
| 265 | + * @m2m_dev_enc: m2m device for encoder. | |
| 266 | + * @plat_dev: platform device | |
| 267 | + * @vpu_plat_dev: mtk vpu platform device | |
| 268 | + * @ctx_list: list of struct mtk_vcodec_ctx | |
| 269 | + * @irqlock: protect data access by irq handler and work thread | |
| 270 | + * @curr_ctx: The context that is waiting for codec hardware | |
| 271 | + * | |
| 272 | + * @reg_base: Mapped address of MTK Vcodec registers. | |
| 273 | + * | |
| 274 | + * @id_counter: used to identify current opened instance | |
| 275 | + * @num_instances: counter of active MTK Vcodec instances | |
| 276 | + * | |
| 277 | + * @encode_workqueue: encode work queue | |
| 278 | + * | |
| 279 | + * @int_cond: used to identify interrupt condition happen | |
| 280 | + * @int_type: used to identify what kind of interrupt condition happen | |
| 281 | + * @dev_mutex: video_device lock | |
| 282 | + * @queue: waitqueue for waiting for completion of device commands | |
| 283 | + * | |
| 284 | + * @enc_irq: h264 encoder irq resource | |
| 285 | + * @enc_lt_irq: vp8 encoder irq resource | |
| 286 | + * | |
| 287 | + * @enc_mutex: encoder hardware lock. | |
| 288 | + * | |
| 289 | + * @pm: power management control | |
| 290 | + * @dec_capability: used to identify decode capability, ex: 4k | |
| 291 | + * @enc_capability: used to identify encode capability | |
| 292 | + */ | |
| 293 | +struct mtk_vcodec_dev { | |
| 294 | + struct v4l2_device v4l2_dev; | |
| 295 | + struct video_device *vfd_enc; | |
| 296 | + | |
| 297 | + struct v4l2_m2m_dev *m2m_dev_enc; | |
| 298 | + struct platform_device *plat_dev; | |
| 299 | + struct platform_device *vpu_plat_dev; | |
| 300 | + struct list_head ctx_list; | |
| 301 | + spinlock_t irqlock; | |
| 302 | + struct mtk_vcodec_ctx *curr_ctx; | |
| 303 | + void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE]; | |
| 304 | + | |
| 305 | + unsigned long id_counter; | |
| 306 | + int num_instances; | |
| 307 | + | |
| 308 | + struct workqueue_struct *encode_workqueue; | |
| 309 | + | |
| 310 | + int int_cond; | |
| 311 | + int int_type; | |
| 312 | + struct mutex dev_mutex; | |
| 313 | + wait_queue_head_t queue; | |
| 314 | + | |
| 315 | + int enc_irq; | |
| 316 | + int enc_lt_irq; | |
| 317 | + | |
| 318 | + struct mutex enc_mutex; | |
| 319 | + | |
| 320 | + struct mtk_vcodec_pm pm; | |
| 321 | + unsigned int dec_capability; | |
| 322 | + unsigned int enc_capability; | |
| 323 | +}; | |
| 324 | + | |
| 325 | +static inline struct mtk_vcodec_ctx *fh_to_ctx(struct v4l2_fh *fh) | |
| 326 | +{ | |
| 327 | + return container_of(fh, struct mtk_vcodec_ctx, fh); | |
| 328 | +} | |
| 329 | + | |
| 330 | +static inline struct mtk_vcodec_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) | |
| 331 | +{ | |
| 332 | + return container_of(ctrl->handler, struct mtk_vcodec_ctx, ctrl_hdl); | |
| 333 | +} | |
| 334 | + | |
| 335 | +#endif /* _MTK_VCODEC_DRV_H_ */ | |
| @@ -0,0 +1,1292 @@ | ||
| 1 | +/* | |
| 2 | +* Copyright (c) 2016 MediaTek Inc. | |
| 3 | +* Author: PC Chen <pc.chen@mediatek.com> | |
| 4 | +* Tiffany Lin <tiffany.lin@mediatek.com> | |
| 5 | +* | |
| 6 | +* This program is free software; you can redistribute it and/or modify | |
| 7 | +* it under the terms of the GNU General Public License version 2 as | |
| 8 | +* published by the Free Software Foundation. | |
| 9 | +* | |
| 10 | +* This program is distributed in the hope that it will be useful, | |
| 11 | +* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | +* GNU General Public License for more details. | |
| 14 | +*/ | |
| 15 | + | |
| 16 | +#include <media/v4l2-event.h> | |
| 17 | +#include <media/v4l2-mem2mem.h> | |
| 18 | +#include <media/videobuf2-dma-contig.h> | |
| 19 | +#include <soc/mediatek/smi.h> | |
| 20 | + | |
| 21 | +#include "mtk_vcodec_drv.h" | |
| 22 | +#include "mtk_vcodec_enc.h" | |
| 23 | +#include "mtk_vcodec_intr.h" | |
| 24 | +#include "mtk_vcodec_util.h" | |
| 25 | +#include "venc_drv_if.h" | |
| 26 | + | |
| 27 | +#define MTK_VENC_MIN_W 160U | |
| 28 | +#define MTK_VENC_MIN_H 128U | |
| 29 | +#define MTK_VENC_MAX_W 1920U | |
| 30 | +#define MTK_VENC_MAX_H 1088U | |
| 31 | +#define DFT_CFG_WIDTH MTK_VENC_MIN_W | |
| 32 | +#define DFT_CFG_HEIGHT MTK_VENC_MIN_H | |
| 33 | +#define MTK_MAX_CTRLS_HINT 20 | |
| 34 | +#define OUT_FMT_IDX 0 | |
| 35 | +#define CAP_FMT_IDX 4 | |
| 36 | + | |
| 37 | + | |
| 38 | +static void mtk_venc_worker(struct work_struct *work); | |
| 39 | + | |
| 40 | +static struct mtk_video_fmt mtk_video_formats[] = { | |
| 41 | + { | |
| 42 | + .fourcc = V4L2_PIX_FMT_NV12M, | |
| 43 | + .type = MTK_FMT_FRAME, | |
| 44 | + .num_planes = 2, | |
| 45 | + }, | |
| 46 | + { | |
| 47 | + .fourcc = V4L2_PIX_FMT_NV21M, | |
| 48 | + .type = MTK_FMT_FRAME, | |
| 49 | + .num_planes = 2, | |
| 50 | + }, | |
| 51 | + { | |
| 52 | + .fourcc = V4L2_PIX_FMT_YUV420M, | |
| 53 | + .type = MTK_FMT_FRAME, | |
| 54 | + .num_planes = 3, | |
| 55 | + }, | |
| 56 | + { | |
| 57 | + .fourcc = V4L2_PIX_FMT_YVU420M, | |
| 58 | + .type = MTK_FMT_FRAME, | |
| 59 | + .num_planes = 3, | |
| 60 | + }, | |
| 61 | + { | |
| 62 | + .fourcc = V4L2_PIX_FMT_H264, | |
| 63 | + .type = MTK_FMT_ENC, | |
| 64 | + .num_planes = 1, | |
| 65 | + }, | |
| 66 | + { | |
| 67 | + .fourcc = V4L2_PIX_FMT_VP8, | |
| 68 | + .type = MTK_FMT_ENC, | |
| 69 | + .num_planes = 1, | |
| 70 | + }, | |
| 71 | +}; | |
| 72 | + | |
| 73 | +#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) | |
| 74 | + | |
| 75 | +static const struct mtk_codec_framesizes mtk_venc_framesizes[] = { | |
| 76 | + { | |
| 77 | + .fourcc = V4L2_PIX_FMT_H264, | |
| 78 | + .stepwise = { MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16, | |
| 79 | + MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16 }, | |
| 80 | + }, | |
| 81 | + { | |
| 82 | + .fourcc = V4L2_PIX_FMT_VP8, | |
| 83 | + .stepwise = { MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16, | |
| 84 | + MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16 }, | |
| 85 | + }, | |
| 86 | +}; | |
| 87 | + | |
| 88 | +#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_venc_framesizes) | |
| 89 | + | |
| 90 | +static int vidioc_venc_s_ctrl(struct v4l2_ctrl *ctrl) | |
| 91 | +{ | |
| 92 | + struct mtk_vcodec_ctx *ctx = ctrl_to_ctx(ctrl); | |
| 93 | + struct mtk_enc_params *p = &ctx->enc_params; | |
| 94 | + int ret = 0; | |
| 95 | + | |
| 96 | + switch (ctrl->id) { | |
| 97 | + case V4L2_CID_MPEG_VIDEO_BITRATE: | |
| 98 | + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_BITRATE val = %d", | |
| 99 | + ctrl->val); | |
| 100 | + p->bitrate = ctrl->val; | |
| 101 | + ctx->param_change |= MTK_ENCODE_PARAM_BITRATE; | |
| 102 | + break; | |
| 103 | + case V4L2_CID_MPEG_VIDEO_B_FRAMES: | |
| 104 | + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_B_FRAMES val = %d", | |
| 105 | + ctrl->val); | |
| 106 | + p->num_b_frame = ctrl->val; | |
| 107 | + break; | |
| 108 | + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: | |
| 109 | + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE val = %d", | |
| 110 | + ctrl->val); | |
| 111 | + p->rc_frame = ctrl->val; | |
| 112 | + break; | |
| 113 | + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: | |
| 114 | + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_MAX_QP val = %d", | |
| 115 | + ctrl->val); | |
| 116 | + p->h264_max_qp = ctrl->val; | |
| 117 | + break; | |
| 118 | + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: | |
| 119 | + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_HEADER_MODE val = %d", | |
| 120 | + ctrl->val); | |
| 121 | + p->seq_hdr_mode = ctrl->val; | |
| 122 | + break; | |
| 123 | + case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: | |
| 124 | + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE val = %d", | |
| 125 | + ctrl->val); | |
| 126 | + p->rc_mb = ctrl->val; | |
| 127 | + break; | |
| 128 | + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: | |
| 129 | + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_PROFILE val = %d", | |
| 130 | + ctrl->val); | |
| 131 | + p->h264_profile = ctrl->val; | |
| 132 | + break; | |
| 133 | + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: | |
| 134 | + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_LEVEL val = %d", | |
| 135 | + ctrl->val); | |
| 136 | + p->h264_level = ctrl->val; | |
| 137 | + break; | |
| 138 | + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: | |
| 139 | + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_H264_I_PERIOD val = %d", | |
| 140 | + ctrl->val); | |
| 141 | + p->intra_period = ctrl->val; | |
| 142 | + ctx->param_change |= MTK_ENCODE_PARAM_INTRA_PERIOD; | |
| 143 | + break; | |
| 144 | + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | |
| 145 | + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_GOP_SIZE val = %d", | |
| 146 | + ctrl->val); | |
| 147 | + p->gop_size = ctrl->val; | |
| 148 | + ctx->param_change |= MTK_ENCODE_PARAM_GOP_SIZE; | |
| 149 | + break; | |
| 150 | + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: | |
| 151 | + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME"); | |
| 152 | + p->force_intra = 1; | |
| 153 | + ctx->param_change |= MTK_ENCODE_PARAM_FORCE_INTRA; | |
| 154 | + break; | |
| 155 | + default: | |
| 156 | + ret = -EINVAL; | |
| 157 | + break; | |
| 158 | + } | |
| 159 | + | |
| 160 | + return ret; | |
| 161 | +} | |
| 162 | + | |
| 163 | +static const struct v4l2_ctrl_ops mtk_vcodec_enc_ctrl_ops = { | |
| 164 | + .s_ctrl = vidioc_venc_s_ctrl, | |
| 165 | +}; | |
| 166 | + | |
| 167 | +static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) | |
| 168 | +{ | |
| 169 | + struct mtk_video_fmt *fmt; | |
| 170 | + int i, j = 0; | |
| 171 | + | |
| 172 | + for (i = 0; i < NUM_FORMATS; ++i) { | |
| 173 | + if (output_queue && mtk_video_formats[i].type != MTK_FMT_FRAME) | |
| 174 | + continue; | |
| 175 | + if (!output_queue && mtk_video_formats[i].type != MTK_FMT_ENC) | |
| 176 | + continue; | |
| 177 | + | |
| 178 | + if (j == f->index) { | |
| 179 | + fmt = &mtk_video_formats[i]; | |
| 180 | + f->pixelformat = fmt->fourcc; | |
| 181 | + memset(f->reserved, 0, sizeof(f->reserved)); | |
| 182 | + return 0; | |
| 183 | + } | |
| 184 | + ++j; | |
| 185 | + } | |
| 186 | + | |
| 187 | + return -EINVAL; | |
| 188 | +} | |
| 189 | + | |
| 190 | +static int vidioc_enum_framesizes(struct file *file, void *fh, | |
| 191 | + struct v4l2_frmsizeenum *fsize) | |
| 192 | +{ | |
| 193 | + int i = 0; | |
| 194 | + | |
| 195 | + if (fsize->index != 0) | |
| 196 | + return -EINVAL; | |
| 197 | + | |
| 198 | + for (i = 0; i < NUM_SUPPORTED_FRAMESIZE; ++i) { | |
| 199 | + if (fsize->pixel_format != mtk_venc_framesizes[i].fourcc) | |
| 200 | + continue; | |
| 201 | + | |
| 202 | + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; | |
| 203 | + fsize->stepwise = mtk_venc_framesizes[i].stepwise; | |
| 204 | + return 0; | |
| 205 | + } | |
| 206 | + | |
| 207 | + return -EINVAL; | |
| 208 | +} | |
| 209 | + | |
| 210 | +static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, | |
| 211 | + struct v4l2_fmtdesc *f) | |
| 212 | +{ | |
| 213 | + return vidioc_enum_fmt(f, false); | |
| 214 | +} | |
| 215 | + | |
| 216 | +static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov, | |
| 217 | + struct v4l2_fmtdesc *f) | |
| 218 | +{ | |
| 219 | + return vidioc_enum_fmt(f, true); | |
| 220 | +} | |
| 221 | + | |
| 222 | +static int vidioc_venc_querycap(struct file *file, void *priv, | |
| 223 | + struct v4l2_capability *cap) | |
| 224 | +{ | |
| 225 | + strlcpy(cap->driver, MTK_VCODEC_ENC_NAME, sizeof(cap->driver)); | |
| 226 | + strlcpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info)); | |
| 227 | + strlcpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card)); | |
| 228 | + | |
| 229 | + return 0; | |
| 230 | +} | |
| 231 | + | |
| 232 | +static int vidioc_venc_s_parm(struct file *file, void *priv, | |
| 233 | + struct v4l2_streamparm *a) | |
| 234 | +{ | |
| 235 | + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); | |
| 236 | + | |
| 237 | + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | |
| 238 | + return -EINVAL; | |
| 239 | + | |
| 240 | + ctx->enc_params.framerate_num = | |
| 241 | + a->parm.output.timeperframe.denominator; | |
| 242 | + ctx->enc_params.framerate_denom = | |
| 243 | + a->parm.output.timeperframe.numerator; | |
| 244 | + ctx->param_change |= MTK_ENCODE_PARAM_FRAMERATE; | |
| 245 | + | |
| 246 | + return 0; | |
| 247 | +} | |
| 248 | + | |
| 249 | +static int vidioc_venc_g_parm(struct file *file, void *priv, | |
| 250 | + struct v4l2_streamparm *a) | |
| 251 | +{ | |
| 252 | + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); | |
| 253 | + | |
| 254 | + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | |
| 255 | + return -EINVAL; | |
| 256 | + | |
| 257 | + a->parm.output.timeperframe.denominator = | |
| 258 | + ctx->enc_params.framerate_num; | |
| 259 | + a->parm.output.timeperframe.numerator = | |
| 260 | + ctx->enc_params.framerate_denom; | |
| 261 | + | |
| 262 | + return 0; | |
| 263 | +} | |
| 264 | + | |
| 265 | +static struct mtk_q_data *mtk_venc_get_q_data(struct mtk_vcodec_ctx *ctx, | |
| 266 | + enum v4l2_buf_type type) | |
| 267 | +{ | |
| 268 | + if (V4L2_TYPE_IS_OUTPUT(type)) | |
| 269 | + return &ctx->q_data[MTK_Q_DATA_SRC]; | |
| 270 | + | |
| 271 | + return &ctx->q_data[MTK_Q_DATA_DST]; | |
| 272 | +} | |
| 273 | + | |
| 274 | +static struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f) | |
| 275 | +{ | |
| 276 | + struct mtk_video_fmt *fmt; | |
| 277 | + unsigned int k; | |
| 278 | + | |
| 279 | + for (k = 0; k < NUM_FORMATS; k++) { | |
| 280 | + fmt = &mtk_video_formats[k]; | |
| 281 | + if (fmt->fourcc == f->fmt.pix.pixelformat) | |
| 282 | + return fmt; | |
| 283 | + } | |
| 284 | + | |
| 285 | + return NULL; | |
| 286 | +} | |
| 287 | + | |
| 288 | +/* V4L2 specification suggests the driver corrects the format struct if any of | |
| 289 | + * the dimensions is unsupported | |
| 290 | + */ | |
| 291 | +static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt) | |
| 292 | +{ | |
| 293 | + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; | |
| 294 | + int i; | |
| 295 | + | |
| 296 | + pix_fmt_mp->field = V4L2_FIELD_NONE; | |
| 297 | + | |
| 298 | + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
| 299 | + pix_fmt_mp->num_planes = 1; | |
| 300 | + pix_fmt_mp->plane_fmt[0].bytesperline = 0; | |
| 301 | + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | |
| 302 | + int tmp_w, tmp_h; | |
| 303 | + | |
| 304 | + pix_fmt_mp->height = clamp(pix_fmt_mp->height, | |
| 305 | + MTK_VENC_MIN_H, | |
| 306 | + MTK_VENC_MAX_H); | |
| 307 | + pix_fmt_mp->width = clamp(pix_fmt_mp->width, | |
| 308 | + MTK_VENC_MIN_W, | |
| 309 | + MTK_VENC_MAX_W); | |
| 310 | + | |
| 311 | + /* find next closer width align 16, heign align 32, size align | |
| 312 | + * 64 rectangle | |
| 313 | + */ | |
| 314 | + tmp_w = pix_fmt_mp->width; | |
| 315 | + tmp_h = pix_fmt_mp->height; | |
| 316 | + v4l_bound_align_image(&pix_fmt_mp->width, | |
| 317 | + MTK_VENC_MIN_W, | |
| 318 | + MTK_VENC_MAX_W, 4, | |
| 319 | + &pix_fmt_mp->height, | |
| 320 | + MTK_VENC_MIN_H, | |
| 321 | + MTK_VENC_MAX_H, 5, 6); | |
| 322 | + | |
| 323 | + if (pix_fmt_mp->width < tmp_w && | |
| 324 | + (pix_fmt_mp->width + 16) <= MTK_VENC_MAX_W) | |
| 325 | + pix_fmt_mp->width += 16; | |
| 326 | + if (pix_fmt_mp->height < tmp_h && | |
| 327 | + (pix_fmt_mp->height + 32) <= MTK_VENC_MAX_H) | |
| 328 | + pix_fmt_mp->height += 32; | |
| 329 | + | |
| 330 | + mtk_v4l2_debug(0, | |
| 331 | + "before resize width=%d, height=%d, after resize width=%d, height=%d, sizeimage=%d %d", | |
| 332 | + tmp_w, tmp_h, pix_fmt_mp->width, | |
| 333 | + pix_fmt_mp->height, | |
| 334 | + pix_fmt_mp->plane_fmt[0].sizeimage, | |
| 335 | + pix_fmt_mp->plane_fmt[1].sizeimage); | |
| 336 | + | |
| 337 | + pix_fmt_mp->num_planes = fmt->num_planes; | |
| 338 | + pix_fmt_mp->plane_fmt[0].sizeimage = | |
| 339 | + pix_fmt_mp->width * pix_fmt_mp->height + | |
| 340 | + ((ALIGN(pix_fmt_mp->width, 16) * 2) * 16); | |
| 341 | + pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width; | |
| 342 | + | |
| 343 | + if (pix_fmt_mp->num_planes == 2) { | |
| 344 | + pix_fmt_mp->plane_fmt[1].sizeimage = | |
| 345 | + (pix_fmt_mp->width * pix_fmt_mp->height) / 2 + | |
| 346 | + (ALIGN(pix_fmt_mp->width, 16) * 16); | |
| 347 | + pix_fmt_mp->plane_fmt[2].sizeimage = 0; | |
| 348 | + pix_fmt_mp->plane_fmt[1].bytesperline = | |
| 349 | + pix_fmt_mp->width; | |
| 350 | + pix_fmt_mp->plane_fmt[2].bytesperline = 0; | |
| 351 | + } else if (pix_fmt_mp->num_planes == 3) { | |
| 352 | + pix_fmt_mp->plane_fmt[1].sizeimage = | |
| 353 | + pix_fmt_mp->plane_fmt[2].sizeimage = | |
| 354 | + (pix_fmt_mp->width * pix_fmt_mp->height) / 4 + | |
| 355 | + ((ALIGN(pix_fmt_mp->width, 16) / 2) * 16); | |
| 356 | + pix_fmt_mp->plane_fmt[1].bytesperline = | |
| 357 | + pix_fmt_mp->plane_fmt[2].bytesperline = | |
| 358 | + pix_fmt_mp->width / 2; | |
| 359 | + } | |
| 360 | + } | |
| 361 | + | |
| 362 | + for (i = 0; i < pix_fmt_mp->num_planes; i++) | |
| 363 | + memset(&(pix_fmt_mp->plane_fmt[i].reserved[0]), 0x0, | |
| 364 | + sizeof(pix_fmt_mp->plane_fmt[0].reserved)); | |
| 365 | + | |
| 366 | + pix_fmt_mp->flags = 0; | |
| 367 | + memset(&pix_fmt_mp->reserved, 0x0, | |
| 368 | + sizeof(pix_fmt_mp->reserved)); | |
| 369 | + | |
| 370 | + return 0; | |
| 371 | +} | |
| 372 | + | |
| 373 | +static void mtk_venc_set_param(struct mtk_vcodec_ctx *ctx, | |
| 374 | + struct venc_enc_param *param) | |
| 375 | +{ | |
| 376 | + struct mtk_q_data *q_data_src = &ctx->q_data[MTK_Q_DATA_SRC]; | |
| 377 | + struct mtk_enc_params *enc_params = &ctx->enc_params; | |
| 378 | + | |
| 379 | + switch (q_data_src->fmt->fourcc) { | |
| 380 | + case V4L2_PIX_FMT_YUV420M: | |
| 381 | + param->input_yuv_fmt = VENC_YUV_FORMAT_I420; | |
| 382 | + break; | |
| 383 | + case V4L2_PIX_FMT_YVU420M: | |
| 384 | + param->input_yuv_fmt = VENC_YUV_FORMAT_YV12; | |
| 385 | + break; | |
| 386 | + case V4L2_PIX_FMT_NV12M: | |
| 387 | + param->input_yuv_fmt = VENC_YUV_FORMAT_NV12; | |
| 388 | + break; | |
| 389 | + case V4L2_PIX_FMT_NV21M: | |
| 390 | + param->input_yuv_fmt = VENC_YUV_FORMAT_NV21; | |
| 391 | + break; | |
| 392 | + default: | |
| 393 | + mtk_v4l2_err("Unsupport fourcc =%d", q_data_src->fmt->fourcc); | |
| 394 | + break; | |
| 395 | + } | |
| 396 | + param->h264_profile = enc_params->h264_profile; | |
| 397 | + param->h264_level = enc_params->h264_level; | |
| 398 | + | |
| 399 | + /* Config visible resolution */ | |
| 400 | + param->width = q_data_src->visible_width; | |
| 401 | + param->height = q_data_src->visible_height; | |
| 402 | + /* Config coded resolution */ | |
| 403 | + param->buf_width = q_data_src->coded_width; | |
| 404 | + param->buf_height = q_data_src->coded_height; | |
| 405 | + param->frm_rate = enc_params->framerate_num / | |
| 406 | + enc_params->framerate_denom; | |
| 407 | + param->intra_period = enc_params->intra_period; | |
| 408 | + param->gop_size = enc_params->gop_size; | |
| 409 | + param->bitrate = enc_params->bitrate; | |
| 410 | + | |
| 411 | + mtk_v4l2_debug(0, | |
| 412 | + "fmt 0x%x, P/L %d/%d, w/h %d/%d, buf %d/%d, fps/bps %d/%d, gop %d, i_period %d", | |
| 413 | + param->input_yuv_fmt, param->h264_profile, | |
| 414 | + param->h264_level, param->width, param->height, | |
| 415 | + param->buf_width, param->buf_height, | |
| 416 | + param->frm_rate, param->bitrate, | |
| 417 | + param->gop_size, param->intra_period); | |
| 418 | +} | |
| 419 | + | |
| 420 | +static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, | |
| 421 | + struct v4l2_format *f) | |
| 422 | +{ | |
| 423 | + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); | |
| 424 | + struct vb2_queue *vq; | |
| 425 | + struct mtk_q_data *q_data; | |
| 426 | + int i, ret; | |
| 427 | + struct mtk_video_fmt *fmt; | |
| 428 | + | |
| 429 | + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); | |
| 430 | + if (!vq) { | |
| 431 | + mtk_v4l2_err("fail to get vq"); | |
| 432 | + return -EINVAL; | |
| 433 | + } | |
| 434 | + | |
| 435 | + if (vb2_is_busy(vq)) { | |
| 436 | + mtk_v4l2_err("queue busy"); | |
| 437 | + return -EBUSY; | |
| 438 | + } | |
| 439 | + | |
| 440 | + q_data = mtk_venc_get_q_data(ctx, f->type); | |
| 441 | + if (!q_data) { | |
| 442 | + mtk_v4l2_err("fail to get q data"); | |
| 443 | + return -EINVAL; | |
| 444 | + } | |
| 445 | + | |
| 446 | + fmt = mtk_venc_find_format(f); | |
| 447 | + if (!fmt) { | |
| 448 | + f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc; | |
| 449 | + fmt = mtk_venc_find_format(f); | |
| 450 | + } | |
| 451 | + | |
| 452 | + q_data->fmt = fmt; | |
| 453 | + ret = vidioc_try_fmt(f, q_data->fmt); | |
| 454 | + if (ret) | |
| 455 | + return ret; | |
| 456 | + | |
| 457 | + q_data->coded_width = f->fmt.pix_mp.width; | |
| 458 | + q_data->coded_height = f->fmt.pix_mp.height; | |
| 459 | + q_data->field = f->fmt.pix_mp.field; | |
| 460 | + | |
| 461 | + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { | |
| 462 | + struct v4l2_plane_pix_format *plane_fmt; | |
| 463 | + | |
| 464 | + plane_fmt = &f->fmt.pix_mp.plane_fmt[i]; | |
| 465 | + q_data->bytesperline[i] = plane_fmt->bytesperline; | |
| 466 | + q_data->sizeimage[i] = plane_fmt->sizeimage; | |
| 467 | + } | |
| 468 | + | |
| 469 | + if (ctx->state == MTK_STATE_FREE) { | |
| 470 | + ret = venc_if_init(ctx, q_data->fmt->fourcc); | |
| 471 | + if (ret) { | |
| 472 | + mtk_v4l2_err("venc_if_init failed=%d, codec type=%x", | |
| 473 | + ret, q_data->fmt->fourcc); | |
| 474 | + return -EBUSY; | |
| 475 | + } | |
| 476 | + ctx->state = MTK_STATE_INIT; | |
| 477 | + } | |
| 478 | + | |
| 479 | + return 0; | |
| 480 | +} | |
| 481 | + | |
| 482 | +static int vidioc_venc_s_fmt_out(struct file *file, void *priv, | |
| 483 | + struct v4l2_format *f) | |
| 484 | +{ | |
| 485 | + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); | |
| 486 | + struct vb2_queue *vq; | |
| 487 | + struct mtk_q_data *q_data; | |
| 488 | + int ret, i; | |
| 489 | + struct mtk_video_fmt *fmt; | |
| 490 | + unsigned int pitch_w_div16; | |
| 491 | + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; | |
| 492 | + | |
| 493 | + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); | |
| 494 | + if (!vq) { | |
| 495 | + mtk_v4l2_err("fail to get vq"); | |
| 496 | + return -EINVAL; | |
| 497 | + } | |
| 498 | + | |
| 499 | + if (vb2_is_busy(vq)) { | |
| 500 | + mtk_v4l2_err("queue busy"); | |
| 501 | + return -EBUSY; | |
| 502 | + } | |
| 503 | + | |
| 504 | + q_data = mtk_venc_get_q_data(ctx, f->type); | |
| 505 | + if (!q_data) { | |
| 506 | + mtk_v4l2_err("fail to get q data"); | |
| 507 | + return -EINVAL; | |
| 508 | + } | |
| 509 | + | |
| 510 | + fmt = mtk_venc_find_format(f); | |
| 511 | + if (!fmt) { | |
| 512 | + f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc; | |
| 513 | + fmt = mtk_venc_find_format(f); | |
| 514 | + } | |
| 515 | + | |
| 516 | + pix_fmt_mp->height = clamp(pix_fmt_mp->height, | |
| 517 | + MTK_VENC_MIN_H, | |
| 518 | + MTK_VENC_MAX_H); | |
| 519 | + pix_fmt_mp->width = clamp(pix_fmt_mp->width, | |
| 520 | + MTK_VENC_MIN_W, | |
| 521 | + MTK_VENC_MAX_W); | |
| 522 | + | |
| 523 | + q_data->visible_width = f->fmt.pix_mp.width; | |
| 524 | + q_data->visible_height = f->fmt.pix_mp.height; | |
| 525 | + q_data->fmt = fmt; | |
| 526 | + ret = vidioc_try_fmt(f, q_data->fmt); | |
| 527 | + if (ret) | |
| 528 | + return ret; | |
| 529 | + | |
| 530 | + q_data->coded_width = f->fmt.pix_mp.width; | |
| 531 | + q_data->coded_height = f->fmt.pix_mp.height; | |
| 532 | + | |
| 533 | + pitch_w_div16 = DIV_ROUND_UP(q_data->visible_width, 16); | |
| 534 | + if (pitch_w_div16 % 8 != 0) { | |
| 535 | + /* Adjust returned width/height, so application could correctly | |
| 536 | + * allocate hw required memory | |
| 537 | + */ | |
| 538 | + q_data->visible_height += 32; | |
| 539 | + vidioc_try_fmt(f, q_data->fmt); | |
| 540 | + } | |
| 541 | + | |
| 542 | + q_data->field = f->fmt.pix_mp.field; | |
| 543 | + ctx->colorspace = f->fmt.pix_mp.colorspace; | |
| 544 | + ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; | |
| 545 | + ctx->quantization = f->fmt.pix_mp.quantization; | |
| 546 | + ctx->xfer_func = f->fmt.pix_mp.xfer_func; | |
| 547 | + | |
| 548 | + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { | |
| 549 | + struct v4l2_plane_pix_format *plane_fmt; | |
| 550 | + | |
| 551 | + plane_fmt = &f->fmt.pix_mp.plane_fmt[i]; | |
| 552 | + q_data->bytesperline[i] = plane_fmt->bytesperline; | |
| 553 | + q_data->sizeimage[i] = plane_fmt->sizeimage; | |
| 554 | + } | |
| 555 | + | |
| 556 | + return 0; | |
| 557 | +} | |
| 558 | + | |
| 559 | +static int vidioc_venc_g_fmt(struct file *file, void *priv, | |
| 560 | + struct v4l2_format *f) | |
| 561 | +{ | |
| 562 | + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; | |
| 563 | + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); | |
| 564 | + struct vb2_queue *vq; | |
| 565 | + struct mtk_q_data *q_data; | |
| 566 | + int i; | |
| 567 | + | |
| 568 | + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); | |
| 569 | + if (!vq) | |
| 570 | + return -EINVAL; | |
| 571 | + | |
| 572 | + q_data = mtk_venc_get_q_data(ctx, f->type); | |
| 573 | + | |
| 574 | + pix->width = q_data->coded_width; | |
| 575 | + pix->height = q_data->coded_height; | |
| 576 | + pix->pixelformat = q_data->fmt->fourcc; | |
| 577 | + pix->field = q_data->field; | |
| 578 | + pix->num_planes = q_data->fmt->num_planes; | |
| 579 | + for (i = 0; i < pix->num_planes; i++) { | |
| 580 | + pix->plane_fmt[i].bytesperline = q_data->bytesperline[i]; | |
| 581 | + pix->plane_fmt[i].sizeimage = q_data->sizeimage[i]; | |
| 582 | + memset(&(pix->plane_fmt[i].reserved[0]), 0x0, | |
| 583 | + sizeof(pix->plane_fmt[i].reserved)); | |
| 584 | + } | |
| 585 | + | |
| 586 | + pix->flags = 0; | |
| 587 | + pix->colorspace = ctx->colorspace; | |
| 588 | + pix->ycbcr_enc = ctx->ycbcr_enc; | |
| 589 | + pix->quantization = ctx->quantization; | |
| 590 | + pix->xfer_func = ctx->xfer_func; | |
| 591 | + | |
| 592 | + return 0; | |
| 593 | +} | |
| 594 | + | |
| 595 | +static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, | |
| 596 | + struct v4l2_format *f) | |
| 597 | +{ | |
| 598 | + struct mtk_video_fmt *fmt; | |
| 599 | + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); | |
| 600 | + | |
| 601 | + fmt = mtk_venc_find_format(f); | |
| 602 | + if (!fmt) { | |
| 603 | + f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc; | |
| 604 | + fmt = mtk_venc_find_format(f); | |
| 605 | + } | |
| 606 | + f->fmt.pix_mp.colorspace = ctx->colorspace; | |
| 607 | + f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; | |
| 608 | + f->fmt.pix_mp.quantization = ctx->quantization; | |
| 609 | + f->fmt.pix_mp.xfer_func = ctx->xfer_func; | |
| 610 | + | |
| 611 | + return vidioc_try_fmt(f, fmt); | |
| 612 | +} | |
| 613 | + | |
| 614 | +static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, | |
| 615 | + struct v4l2_format *f) | |
| 616 | +{ | |
| 617 | + struct mtk_video_fmt *fmt; | |
| 618 | + | |
| 619 | + fmt = mtk_venc_find_format(f); | |
| 620 | + if (!fmt) { | |
| 621 | + f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc; | |
| 622 | + fmt = mtk_venc_find_format(f); | |
| 623 | + } | |
| 624 | + if (!f->fmt.pix_mp.colorspace) { | |
| 625 | + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; | |
| 626 | + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | |
| 627 | + f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; | |
| 628 | + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; | |
| 629 | + } | |
| 630 | + | |
| 631 | + return vidioc_try_fmt(f, fmt); | |
| 632 | +} | |
| 633 | + | |
| 634 | +static int vidioc_venc_qbuf(struct file *file, void *priv, | |
| 635 | + struct v4l2_buffer *buf) | |
| 636 | +{ | |
| 637 | + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); | |
| 638 | + | |
| 639 | + if (ctx->state == MTK_STATE_ABORT) { | |
| 640 | + mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error", | |
| 641 | + ctx->id); | |
| 642 | + return -EIO; | |
| 643 | + } | |
| 644 | + | |
| 645 | + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); | |
| 646 | +} | |
| 647 | + | |
| 648 | +static int vidioc_venc_dqbuf(struct file *file, void *priv, | |
| 649 | + struct v4l2_buffer *buf) | |
| 650 | +{ | |
| 651 | + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); | |
| 652 | + | |
| 653 | + if (ctx->state == MTK_STATE_ABORT) { | |
| 654 | + mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error", | |
| 655 | + ctx->id); | |
| 656 | + return -EIO; | |
| 657 | + } | |
| 658 | + | |
| 659 | + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); | |
| 660 | +} | |
| 661 | + | |
| 662 | +const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = { | |
| 663 | + .vidioc_streamon = v4l2_m2m_ioctl_streamon, | |
| 664 | + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, | |
| 665 | + | |
| 666 | + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, | |
| 667 | + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, | |
| 668 | + .vidioc_qbuf = vidioc_venc_qbuf, | |
| 669 | + .vidioc_dqbuf = vidioc_venc_dqbuf, | |
| 670 | + | |
| 671 | + .vidioc_querycap = vidioc_venc_querycap, | |
| 672 | + .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, | |
| 673 | + .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, | |
| 674 | + .vidioc_enum_framesizes = vidioc_enum_framesizes, | |
| 675 | + | |
| 676 | + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, | |
| 677 | + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, | |
| 678 | + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, | |
| 679 | + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | |
| 680 | + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | |
| 681 | + | |
| 682 | + .vidioc_s_parm = vidioc_venc_s_parm, | |
| 683 | + .vidioc_g_parm = vidioc_venc_g_parm, | |
| 684 | + .vidioc_s_fmt_vid_cap_mplane = vidioc_venc_s_fmt_cap, | |
| 685 | + .vidioc_s_fmt_vid_out_mplane = vidioc_venc_s_fmt_out, | |
| 686 | + | |
| 687 | + .vidioc_g_fmt_vid_cap_mplane = vidioc_venc_g_fmt, | |
| 688 | + .vidioc_g_fmt_vid_out_mplane = vidioc_venc_g_fmt, | |
| 689 | + | |
| 690 | + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, | |
| 691 | + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, | |
| 692 | +}; | |
| 693 | + | |
| 694 | +static int vb2ops_venc_queue_setup(struct vb2_queue *vq, | |
| 695 | + unsigned int *nbuffers, | |
| 696 | + unsigned int *nplanes, | |
| 697 | + unsigned int sizes[], | |
| 698 | + struct device *alloc_devs[]) | |
| 699 | +{ | |
| 700 | + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vq); | |
| 701 | + struct mtk_q_data *q_data; | |
| 702 | + unsigned int i; | |
| 703 | + | |
| 704 | + q_data = mtk_venc_get_q_data(ctx, vq->type); | |
| 705 | + | |
| 706 | + if (q_data == NULL) | |
| 707 | + return -EINVAL; | |
| 708 | + | |
| 709 | + if (*nplanes) { | |
| 710 | + for (i = 0; i < *nplanes; i++) | |
| 711 | + if (sizes[i] < q_data->sizeimage[i]) | |
| 712 | + return -EINVAL; | |
| 713 | + } else { | |
| 714 | + *nplanes = q_data->fmt->num_planes; | |
| 715 | + for (i = 0; i < *nplanes; i++) | |
| 716 | + sizes[i] = q_data->sizeimage[i]; | |
| 717 | + } | |
| 718 | + | |
| 719 | + return 0; | |
| 720 | +} | |
| 721 | + | |
| 722 | +static int vb2ops_venc_buf_prepare(struct vb2_buffer *vb) | |
| 723 | +{ | |
| 724 | + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | |
| 725 | + struct mtk_q_data *q_data; | |
| 726 | + int i; | |
| 727 | + | |
| 728 | + q_data = mtk_venc_get_q_data(ctx, vb->vb2_queue->type); | |
| 729 | + | |
| 730 | + for (i = 0; i < q_data->fmt->num_planes; i++) { | |
| 731 | + if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) { | |
| 732 | + mtk_v4l2_err("data will not fit into plane %d (%lu < %d)", | |
| 733 | + i, vb2_plane_size(vb, i), | |
| 734 | + q_data->sizeimage[i]); | |
| 735 | + return -EINVAL; | |
| 736 | + } | |
| 737 | + } | |
| 738 | + | |
| 739 | + return 0; | |
| 740 | +} | |
| 741 | + | |
| 742 | +static void vb2ops_venc_buf_queue(struct vb2_buffer *vb) | |
| 743 | +{ | |
| 744 | + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | |
| 745 | + struct vb2_v4l2_buffer *vb2_v4l2 = | |
| 746 | + container_of(vb, struct vb2_v4l2_buffer, vb2_buf); | |
| 747 | + | |
| 748 | + struct mtk_video_enc_buf *mtk_buf = | |
| 749 | + container_of(vb2_v4l2, struct mtk_video_enc_buf, vb); | |
| 750 | + | |
| 751 | + if ((vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) && | |
| 752 | + (ctx->param_change != MTK_ENCODE_PARAM_NONE)) { | |
| 753 | + mtk_v4l2_debug(1, "[%d] Before id=%d encode parameter change %x", | |
| 754 | + ctx->id, | |
| 755 | + mtk_buf->vb.vb2_buf.index, | |
| 756 | + ctx->param_change); | |
| 757 | + mtk_buf->param_change = ctx->param_change; | |
| 758 | + mtk_buf->enc_params = ctx->enc_params; | |
| 759 | + ctx->param_change = MTK_ENCODE_PARAM_NONE; | |
| 760 | + } | |
| 761 | + | |
| 762 | + v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); | |
| 763 | +} | |
| 764 | + | |
| 765 | +static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) | |
| 766 | +{ | |
| 767 | + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); | |
| 768 | + struct venc_enc_param param; | |
| 769 | + int ret; | |
| 770 | + int i; | |
| 771 | + | |
| 772 | + /* Once state turn into MTK_STATE_ABORT, we need stop_streaming | |
| 773 | + * to clear it | |
| 774 | + */ | |
| 775 | + if ((ctx->state == MTK_STATE_ABORT) || (ctx->state == MTK_STATE_FREE)) { | |
| 776 | + ret = -EIO; | |
| 777 | + goto err_set_param; | |
| 778 | + } | |
| 779 | + | |
| 780 | + /* Do the initialization when both start_streaming have been called */ | |
| 781 | + if (V4L2_TYPE_IS_OUTPUT(q->type)) { | |
| 782 | + if (!vb2_start_streaming_called(&ctx->m2m_ctx->cap_q_ctx.q)) | |
| 783 | + return 0; | |
| 784 | + } else { | |
| 785 | + if (!vb2_start_streaming_called(&ctx->m2m_ctx->out_q_ctx.q)) | |
| 786 | + return 0; | |
| 787 | + } | |
| 788 | + | |
| 789 | + mtk_venc_set_param(ctx, ¶m); | |
| 790 | + ret = venc_if_set_param(ctx, VENC_SET_PARAM_ENC, ¶m); | |
| 791 | + if (ret) { | |
| 792 | + mtk_v4l2_err("venc_if_set_param failed=%d", ret); | |
| 793 | + ctx->state = MTK_STATE_ABORT; | |
| 794 | + goto err_set_param; | |
| 795 | + } | |
| 796 | + ctx->param_change = MTK_ENCODE_PARAM_NONE; | |
| 797 | + | |
| 798 | + if ((ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H264) && | |
| 799 | + (ctx->enc_params.seq_hdr_mode != | |
| 800 | + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE)) { | |
| 801 | + ret = venc_if_set_param(ctx, | |
| 802 | + VENC_SET_PARAM_PREPEND_HEADER, | |
| 803 | + NULL); | |
| 804 | + if (ret) { | |
| 805 | + mtk_v4l2_err("venc_if_set_param failed=%d", ret); | |
| 806 | + ctx->state = MTK_STATE_ABORT; | |
| 807 | + goto err_set_param; | |
| 808 | + } | |
| 809 | + ctx->state = MTK_STATE_HEADER; | |
| 810 | + } | |
| 811 | + | |
| 812 | + return 0; | |
| 813 | + | |
| 814 | +err_set_param: | |
| 815 | + for (i = 0; i < q->num_buffers; ++i) { | |
| 816 | + if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) { | |
| 817 | + mtk_v4l2_debug(0, "[%d] id=%d, type=%d, %d -> VB2_BUF_STATE_QUEUED", | |
| 818 | + ctx->id, i, q->type, | |
| 819 | + (int)q->bufs[i]->state); | |
| 820 | + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(q->bufs[i]), | |
| 821 | + VB2_BUF_STATE_QUEUED); | |
| 822 | + } | |
| 823 | + } | |
| 824 | + | |
| 825 | + return ret; | |
| 826 | +} | |
| 827 | + | |
| 828 | +static void vb2ops_venc_stop_streaming(struct vb2_queue *q) | |
| 829 | +{ | |
| 830 | + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); | |
| 831 | + struct vb2_buffer *src_buf, *dst_buf; | |
| 832 | + int ret; | |
| 833 | + | |
| 834 | + mtk_v4l2_debug(2, "[%d]-> type=%d", ctx->id, q->type); | |
| 835 | + | |
| 836 | + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | |
| 837 | + while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { | |
| 838 | + dst_buf->planes[0].bytesused = 0; | |
| 839 | + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), | |
| 840 | + VB2_BUF_STATE_ERROR); | |
| 841 | + } | |
| 842 | + } else { | |
| 843 | + while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) | |
| 844 | + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), | |
| 845 | + VB2_BUF_STATE_ERROR); | |
| 846 | + } | |
| 847 | + | |
| 848 | + if ((q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && | |
| 849 | + vb2_is_streaming(&ctx->m2m_ctx->out_q_ctx.q)) || | |
| 850 | + (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && | |
| 851 | + vb2_is_streaming(&ctx->m2m_ctx->cap_q_ctx.q))) { | |
| 852 | + mtk_v4l2_debug(1, "[%d]-> q type %d out=%d cap=%d", | |
| 853 | + ctx->id, q->type, | |
| 854 | + vb2_is_streaming(&ctx->m2m_ctx->out_q_ctx.q), | |
| 855 | + vb2_is_streaming(&ctx->m2m_ctx->cap_q_ctx.q)); | |
| 856 | + return; | |
| 857 | + } | |
| 858 | + | |
| 859 | + /* Release the encoder if both streams are stopped. */ | |
| 860 | + ret = venc_if_deinit(ctx); | |
| 861 | + if (ret) | |
| 862 | + mtk_v4l2_err("venc_if_deinit failed=%d", ret); | |
| 863 | + | |
| 864 | + ctx->state = MTK_STATE_FREE; | |
| 865 | +} | |
| 866 | + | |
| 867 | +static struct vb2_ops mtk_venc_vb2_ops = { | |
| 868 | + .queue_setup = vb2ops_venc_queue_setup, | |
| 869 | + .buf_prepare = vb2ops_venc_buf_prepare, | |
| 870 | + .buf_queue = vb2ops_venc_buf_queue, | |
| 871 | + .wait_prepare = vb2_ops_wait_prepare, | |
| 872 | + .wait_finish = vb2_ops_wait_finish, | |
| 873 | + .start_streaming = vb2ops_venc_start_streaming, | |
| 874 | + .stop_streaming = vb2ops_venc_stop_streaming, | |
| 875 | +}; | |
| 876 | + | |
| 877 | +static int mtk_venc_encode_header(void *priv) | |
| 878 | +{ | |
| 879 | + struct mtk_vcodec_ctx *ctx = priv; | |
| 880 | + int ret; | |
| 881 | + struct vb2_buffer *dst_buf; | |
| 882 | + struct mtk_vcodec_mem bs_buf; | |
| 883 | + struct venc_done_result enc_result; | |
| 884 | + | |
| 885 | + dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); | |
| 886 | + if (!dst_buf) { | |
| 887 | + mtk_v4l2_debug(1, "No dst buffer"); | |
| 888 | + return -EINVAL; | |
| 889 | + } | |
| 890 | + | |
| 891 | + bs_buf.va = vb2_plane_vaddr(dst_buf, 0); | |
| 892 | + bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); | |
| 893 | + bs_buf.size = (size_t)dst_buf->planes[0].length; | |
| 894 | + | |
| 895 | + mtk_v4l2_debug(1, | |
| 896 | + "[%d] buf id=%d va=0x%p dma_addr=0x%llx size=%zu", | |
| 897 | + ctx->id, | |
| 898 | + dst_buf->index, bs_buf.va, | |
| 899 | + (u64)bs_buf.dma_addr, | |
| 900 | + bs_buf.size); | |
| 901 | + | |
| 902 | + ret = venc_if_encode(ctx, | |
| 903 | + VENC_START_OPT_ENCODE_SEQUENCE_HEADER, | |
| 904 | + NULL, &bs_buf, &enc_result); | |
| 905 | + | |
| 906 | + if (ret) { | |
| 907 | + dst_buf->planes[0].bytesused = 0; | |
| 908 | + ctx->state = MTK_STATE_ABORT; | |
| 909 | + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), | |
| 910 | + VB2_BUF_STATE_ERROR); | |
| 911 | + mtk_v4l2_err("venc_if_encode failed=%d", ret); | |
| 912 | + return -EINVAL; | |
| 913 | + } | |
| 914 | + | |
| 915 | + ctx->state = MTK_STATE_HEADER; | |
| 916 | + dst_buf->planes[0].bytesused = enc_result.bs_size; | |
| 917 | + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), VB2_BUF_STATE_DONE); | |
| 918 | + | |
| 919 | + return 0; | |
| 920 | +} | |
| 921 | + | |
| 922 | +static int mtk_venc_param_change(struct mtk_vcodec_ctx *ctx) | |
| 923 | +{ | |
| 924 | + struct venc_enc_param enc_prm; | |
| 925 | + struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); | |
| 926 | + struct vb2_v4l2_buffer *vb2_v4l2 = | |
| 927 | + container_of(vb, struct vb2_v4l2_buffer, vb2_buf); | |
| 928 | + struct mtk_video_enc_buf *mtk_buf = | |
| 929 | + container_of(vb2_v4l2, struct mtk_video_enc_buf, vb); | |
| 930 | + | |
| 931 | + int ret = 0; | |
| 932 | + | |
| 933 | + memset(&enc_prm, 0, sizeof(enc_prm)); | |
| 934 | + if (mtk_buf->param_change == MTK_ENCODE_PARAM_NONE) | |
| 935 | + return 0; | |
| 936 | + | |
| 937 | + if (mtk_buf->param_change & MTK_ENCODE_PARAM_BITRATE) { | |
| 938 | + enc_prm.bitrate = mtk_buf->enc_params.bitrate; | |
| 939 | + mtk_v4l2_debug(1, "[%d] id=%d, change param br=%d", | |
| 940 | + ctx->id, | |
| 941 | + mtk_buf->vb.vb2_buf.index, | |
| 942 | + enc_prm.bitrate); | |
| 943 | + ret |= venc_if_set_param(ctx, | |
| 944 | + VENC_SET_PARAM_ADJUST_BITRATE, | |
| 945 | + &enc_prm); | |
| 946 | + } | |
| 947 | + if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_FRAMERATE) { | |
| 948 | + enc_prm.frm_rate = mtk_buf->enc_params.framerate_num / | |
| 949 | + mtk_buf->enc_params.framerate_denom; | |
| 950 | + mtk_v4l2_debug(1, "[%d] id=%d, change param fr=%d", | |
| 951 | + ctx->id, | |
| 952 | + mtk_buf->vb.vb2_buf.index, | |
| 953 | + enc_prm.frm_rate); | |
| 954 | + ret |= venc_if_set_param(ctx, | |
| 955 | + VENC_SET_PARAM_ADJUST_FRAMERATE, | |
| 956 | + &enc_prm); | |
| 957 | + } | |
| 958 | + if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_GOP_SIZE) { | |
| 959 | + enc_prm.gop_size = mtk_buf->enc_params.gop_size; | |
| 960 | + mtk_v4l2_debug(1, "change param intra period=%d", | |
| 961 | + enc_prm.gop_size); | |
| 962 | + ret |= venc_if_set_param(ctx, | |
| 963 | + VENC_SET_PARAM_GOP_SIZE, | |
| 964 | + &enc_prm); | |
| 965 | + } | |
| 966 | + if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_FORCE_INTRA) { | |
| 967 | + mtk_v4l2_debug(1, "[%d] id=%d, change param force I=%d", | |
| 968 | + ctx->id, | |
| 969 | + mtk_buf->vb.vb2_buf.index, | |
| 970 | + mtk_buf->enc_params.force_intra); | |
| 971 | + if (mtk_buf->enc_params.force_intra) | |
| 972 | + ret |= venc_if_set_param(ctx, | |
| 973 | + VENC_SET_PARAM_FORCE_INTRA, | |
| 974 | + NULL); | |
| 975 | + } | |
| 976 | + | |
| 977 | + mtk_buf->param_change = MTK_ENCODE_PARAM_NONE; | |
| 978 | + | |
| 979 | + if (ret) { | |
| 980 | + ctx->state = MTK_STATE_ABORT; | |
| 981 | + mtk_v4l2_err("venc_if_set_param %d failed=%d", | |
| 982 | + mtk_buf->param_change, ret); | |
| 983 | + return -1; | |
| 984 | + } | |
| 985 | + | |
| 986 | + return 0; | |
| 987 | +} | |
| 988 | + | |
| 989 | +/* | |
| 990 | + * v4l2_m2m_streamoff() holds dev_mutex and waits mtk_venc_worker() | |
| 991 | + * to call v4l2_m2m_job_finish(). | |
| 992 | + * If mtk_venc_worker() tries to acquire dev_mutex, it will deadlock. | |
| 993 | + * So this function must not try to acquire dev->dev_mutex. | |
| 994 | + * This means v4l2 ioctls and mtk_venc_worker() can run at the same time. | |
| 995 | + * mtk_venc_worker() should be carefully implemented to avoid bugs. | |
| 996 | + */ | |
| 997 | +static void mtk_venc_worker(struct work_struct *work) | |
| 998 | +{ | |
| 999 | + struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx, | |
| 1000 | + encode_work); | |
| 1001 | + struct vb2_buffer *src_buf, *dst_buf; | |
| 1002 | + struct venc_frm_buf frm_buf; | |
| 1003 | + struct mtk_vcodec_mem bs_buf; | |
| 1004 | + struct venc_done_result enc_result; | |
| 1005 | + int ret, i; | |
| 1006 | + struct vb2_v4l2_buffer *vb2_v4l2; | |
| 1007 | + | |
| 1008 | + /* check dst_buf, dst_buf may be removed in device_run | |
| 1009 | + * to stored encdoe header so we need check dst_buf and | |
| 1010 | + * call job_finish here to prevent recursion | |
| 1011 | + */ | |
| 1012 | + dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); | |
| 1013 | + if (!dst_buf) { | |
| 1014 | + v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx); | |
| 1015 | + return; | |
| 1016 | + } | |
| 1017 | + | |
| 1018 | + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); | |
| 1019 | + memset(&frm_buf, 0, sizeof(frm_buf)); | |
| 1020 | + for (i = 0; i < src_buf->num_planes ; i++) { | |
| 1021 | + frm_buf.fb_addr[i].va = vb2_plane_vaddr(src_buf, i); | |
| 1022 | + frm_buf.fb_addr[i].dma_addr = | |
| 1023 | + vb2_dma_contig_plane_dma_addr(src_buf, i); | |
| 1024 | + frm_buf.fb_addr[i].size = | |
| 1025 | + (size_t)src_buf->planes[i].length; | |
| 1026 | + } | |
| 1027 | + bs_buf.va = vb2_plane_vaddr(dst_buf, 0); | |
| 1028 | + bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); | |
| 1029 | + bs_buf.size = (size_t)dst_buf->planes[0].length; | |
| 1030 | + | |
| 1031 | + mtk_v4l2_debug(2, | |
| 1032 | + "Framebuf VA=%p PA=%llx Size=0x%zx;VA=%p PA=0x%llx Size=0x%zx;VA=%p PA=0x%llx Size=%zu", | |
| 1033 | + frm_buf.fb_addr[0].va, | |
| 1034 | + (u64)frm_buf.fb_addr[0].dma_addr, | |
| 1035 | + frm_buf.fb_addr[0].size, | |
| 1036 | + frm_buf.fb_addr[1].va, | |
| 1037 | + (u64)frm_buf.fb_addr[1].dma_addr, | |
| 1038 | + frm_buf.fb_addr[1].size, | |
| 1039 | + frm_buf.fb_addr[2].va, | |
| 1040 | + (u64)frm_buf.fb_addr[2].dma_addr, | |
| 1041 | + frm_buf.fb_addr[2].size); | |
| 1042 | + | |
| 1043 | + ret = venc_if_encode(ctx, VENC_START_OPT_ENCODE_FRAME, | |
| 1044 | + &frm_buf, &bs_buf, &enc_result); | |
| 1045 | + | |
| 1046 | + vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf); | |
| 1047 | + if (enc_result.is_key_frm) | |
| 1048 | + vb2_v4l2->flags |= V4L2_BUF_FLAG_KEYFRAME; | |
| 1049 | + | |
| 1050 | + if (ret) { | |
| 1051 | + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), | |
| 1052 | + VB2_BUF_STATE_ERROR); | |
| 1053 | + dst_buf->planes[0].bytesused = 0; | |
| 1054 | + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), | |
| 1055 | + VB2_BUF_STATE_ERROR); | |
| 1056 | + mtk_v4l2_err("venc_if_encode failed=%d", ret); | |
| 1057 | + } else { | |
| 1058 | + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), | |
| 1059 | + VB2_BUF_STATE_DONE); | |
| 1060 | + dst_buf->planes[0].bytesused = enc_result.bs_size; | |
| 1061 | + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), | |
| 1062 | + VB2_BUF_STATE_DONE); | |
| 1063 | + mtk_v4l2_debug(2, "venc_if_encode bs size=%d", | |
| 1064 | + enc_result.bs_size); | |
| 1065 | + } | |
| 1066 | + | |
| 1067 | + v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx); | |
| 1068 | + | |
| 1069 | + mtk_v4l2_debug(1, "<=== src_buf[%d] dst_buf[%d] venc_if_encode ret=%d Size=%u===>", | |
| 1070 | + src_buf->index, dst_buf->index, ret, | |
| 1071 | + enc_result.bs_size); | |
| 1072 | +} | |
| 1073 | + | |
| 1074 | +static void m2mops_venc_device_run(void *priv) | |
| 1075 | +{ | |
| 1076 | + struct mtk_vcodec_ctx *ctx = priv; | |
| 1077 | + | |
| 1078 | + if ((ctx->q_data[MTK_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_H264) && | |
| 1079 | + (ctx->state != MTK_STATE_HEADER)) { | |
| 1080 | + /* encode h264 sps/pps header */ | |
| 1081 | + mtk_venc_encode_header(ctx); | |
| 1082 | + queue_work(ctx->dev->encode_workqueue, &ctx->encode_work); | |
| 1083 | + return; | |
| 1084 | + } | |
| 1085 | + | |
| 1086 | + mtk_venc_param_change(ctx); | |
| 1087 | + queue_work(ctx->dev->encode_workqueue, &ctx->encode_work); | |
| 1088 | +} | |
| 1089 | + | |
| 1090 | +static int m2mops_venc_job_ready(void *m2m_priv) | |
| 1091 | +{ | |
| 1092 | + struct mtk_vcodec_ctx *ctx = m2m_priv; | |
| 1093 | + | |
| 1094 | + if (ctx->state == MTK_STATE_ABORT || ctx->state == MTK_STATE_FREE) { | |
| 1095 | + mtk_v4l2_debug(3, "[%d]Not ready: state=0x%x.", | |
| 1096 | + ctx->id, ctx->state); | |
| 1097 | + return 0; | |
| 1098 | + } | |
| 1099 | + | |
| 1100 | + return 1; | |
| 1101 | +} | |
| 1102 | + | |
| 1103 | +static void m2mops_venc_job_abort(void *priv) | |
| 1104 | +{ | |
| 1105 | + struct mtk_vcodec_ctx *ctx = priv; | |
| 1106 | + | |
| 1107 | + ctx->state = MTK_STATE_ABORT; | |
| 1108 | +} | |
| 1109 | + | |
| 1110 | +static void m2mops_venc_lock(void *m2m_priv) | |
| 1111 | +{ | |
| 1112 | + struct mtk_vcodec_ctx *ctx = m2m_priv; | |
| 1113 | + | |
| 1114 | + mutex_lock(&ctx->dev->dev_mutex); | |
| 1115 | +} | |
| 1116 | + | |
| 1117 | +static void m2mops_venc_unlock(void *m2m_priv) | |
| 1118 | +{ | |
| 1119 | + struct mtk_vcodec_ctx *ctx = m2m_priv; | |
| 1120 | + | |
| 1121 | + mutex_unlock(&ctx->dev->dev_mutex); | |
| 1122 | +} | |
| 1123 | + | |
| 1124 | +const struct v4l2_m2m_ops mtk_venc_m2m_ops = { | |
| 1125 | + .device_run = m2mops_venc_device_run, | |
| 1126 | + .job_ready = m2mops_venc_job_ready, | |
| 1127 | + .job_abort = m2mops_venc_job_abort, | |
| 1128 | + .lock = m2mops_venc_lock, | |
| 1129 | + .unlock = m2mops_venc_unlock, | |
| 1130 | +}; | |
| 1131 | + | |
| 1132 | +void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx) | |
| 1133 | +{ | |
| 1134 | + struct mtk_q_data *q_data; | |
| 1135 | + | |
| 1136 | + ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex; | |
| 1137 | + ctx->fh.m2m_ctx = ctx->m2m_ctx; | |
| 1138 | + ctx->fh.ctrl_handler = &ctx->ctrl_hdl; | |
| 1139 | + INIT_WORK(&ctx->encode_work, mtk_venc_worker); | |
| 1140 | + | |
| 1141 | + ctx->colorspace = V4L2_COLORSPACE_REC709; | |
| 1142 | + ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | |
| 1143 | + ctx->quantization = V4L2_QUANTIZATION_DEFAULT; | |
| 1144 | + ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; | |
| 1145 | + | |
| 1146 | + q_data = &ctx->q_data[MTK_Q_DATA_SRC]; | |
| 1147 | + memset(q_data, 0, sizeof(struct mtk_q_data)); | |
| 1148 | + q_data->visible_width = DFT_CFG_WIDTH; | |
| 1149 | + q_data->visible_height = DFT_CFG_HEIGHT; | |
| 1150 | + q_data->coded_width = DFT_CFG_WIDTH; | |
| 1151 | + q_data->coded_height = DFT_CFG_HEIGHT; | |
| 1152 | + q_data->field = V4L2_FIELD_NONE; | |
| 1153 | + | |
| 1154 | + q_data->fmt = &mtk_video_formats[OUT_FMT_IDX]; | |
| 1155 | + | |
| 1156 | + v4l_bound_align_image(&q_data->coded_width, | |
| 1157 | + MTK_VENC_MIN_W, | |
| 1158 | + MTK_VENC_MAX_W, 4, | |
| 1159 | + &q_data->coded_height, | |
| 1160 | + MTK_VENC_MIN_H, | |
| 1161 | + MTK_VENC_MAX_H, 5, 6); | |
| 1162 | + | |
| 1163 | + if (q_data->coded_width < DFT_CFG_WIDTH && | |
| 1164 | + (q_data->coded_width + 16) <= MTK_VENC_MAX_W) | |
| 1165 | + q_data->coded_width += 16; | |
| 1166 | + if (q_data->coded_height < DFT_CFG_HEIGHT && | |
| 1167 | + (q_data->coded_height + 32) <= MTK_VENC_MAX_H) | |
| 1168 | + q_data->coded_height += 32; | |
| 1169 | + | |
| 1170 | + q_data->sizeimage[0] = | |
| 1171 | + q_data->coded_width * q_data->coded_height+ | |
| 1172 | + ((ALIGN(q_data->coded_width, 16) * 2) * 16); | |
| 1173 | + q_data->bytesperline[0] = q_data->coded_width; | |
| 1174 | + q_data->sizeimage[1] = | |
| 1175 | + (q_data->coded_width * q_data->coded_height) / 2 + | |
| 1176 | + (ALIGN(q_data->coded_width, 16) * 16); | |
| 1177 | + q_data->bytesperline[1] = q_data->coded_width; | |
| 1178 | + | |
| 1179 | + q_data = &ctx->q_data[MTK_Q_DATA_DST]; | |
| 1180 | + memset(q_data, 0, sizeof(struct mtk_q_data)); | |
| 1181 | + q_data->coded_width = DFT_CFG_WIDTH; | |
| 1182 | + q_data->coded_height = DFT_CFG_HEIGHT; | |
| 1183 | + q_data->fmt = &mtk_video_formats[CAP_FMT_IDX]; | |
| 1184 | + q_data->field = V4L2_FIELD_NONE; | |
| 1185 | + ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] = | |
| 1186 | + DFT_CFG_WIDTH * DFT_CFG_HEIGHT; | |
| 1187 | + ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = 0; | |
| 1188 | + | |
| 1189 | +} | |
| 1190 | + | |
| 1191 | +int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx) | |
| 1192 | +{ | |
| 1193 | + const struct v4l2_ctrl_ops *ops = &mtk_vcodec_enc_ctrl_ops; | |
| 1194 | + struct v4l2_ctrl_handler *handler = &ctx->ctrl_hdl; | |
| 1195 | + | |
| 1196 | + v4l2_ctrl_handler_init(handler, MTK_MAX_CTRLS_HINT); | |
| 1197 | + | |
| 1198 | + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE, | |
| 1199 | + 1, 4000000, 1, 4000000); | |
| 1200 | + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_B_FRAMES, | |
| 1201 | + 0, 2, 1, 0); | |
| 1202 | + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, | |
| 1203 | + 0, 1, 1, 1); | |
| 1204 | + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_MAX_QP, | |
| 1205 | + 0, 51, 1, 51); | |
| 1206 | + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, | |
| 1207 | + 0, 65535, 1, 0); | |
| 1208 | + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, | |
| 1209 | + 0, 65535, 1, 0); | |
| 1210 | + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, | |
| 1211 | + 0, 1, 1, 0); | |
| 1212 | + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, | |
| 1213 | + 0, 0, 0, 0); | |
| 1214 | + v4l2_ctrl_new_std_menu(handler, ops, | |
| 1215 | + V4L2_CID_MPEG_VIDEO_HEADER_MODE, | |
| 1216 | + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, | |
| 1217 | + 0, V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE); | |
| 1218 | + v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, | |
| 1219 | + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, | |
| 1220 | + 0, V4L2_MPEG_VIDEO_H264_PROFILE_MAIN); | |
| 1221 | + v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, | |
| 1222 | + V4L2_MPEG_VIDEO_H264_LEVEL_4_2, | |
| 1223 | + 0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0); | |
| 1224 | + if (handler->error) { | |
| 1225 | + mtk_v4l2_err("Init control handler fail %d", | |
| 1226 | + handler->error); | |
| 1227 | + return handler->error; | |
| 1228 | + } | |
| 1229 | + | |
| 1230 | + v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); | |
| 1231 | + | |
| 1232 | + return 0; | |
| 1233 | +} | |
| 1234 | + | |
| 1235 | +int mtk_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq, | |
| 1236 | + struct vb2_queue *dst_vq) | |
| 1237 | +{ | |
| 1238 | + struct mtk_vcodec_ctx *ctx = priv; | |
| 1239 | + int ret; | |
| 1240 | + | |
| 1241 | + /* Note: VB2_USERPTR works with dma-contig because mt8173 | |
| 1242 | + * support iommu | |
| 1243 | + * https://patchwork.kernel.org/patch/8335461/ | |
| 1244 | + * https://patchwork.kernel.org/patch/7596181/ | |
| 1245 | + */ | |
| 1246 | + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | |
| 1247 | + src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; | |
| 1248 | + src_vq->drv_priv = ctx; | |
| 1249 | + src_vq->buf_struct_size = sizeof(struct mtk_video_enc_buf); | |
| 1250 | + src_vq->ops = &mtk_venc_vb2_ops; | |
| 1251 | + src_vq->mem_ops = &vb2_dma_contig_memops; | |
| 1252 | + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | |
| 1253 | + src_vq->lock = &ctx->dev->dev_mutex; | |
| 1254 | + src_vq->dev = &ctx->dev->plat_dev->dev; | |
| 1255 | + | |
| 1256 | + ret = vb2_queue_init(src_vq); | |
| 1257 | + if (ret) | |
| 1258 | + return ret; | |
| 1259 | + | |
| 1260 | + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
| 1261 | + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; | |
| 1262 | + dst_vq->drv_priv = ctx; | |
| 1263 | + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | |
| 1264 | + dst_vq->ops = &mtk_venc_vb2_ops; | |
| 1265 | + dst_vq->mem_ops = &vb2_dma_contig_memops; | |
| 1266 | + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | |
| 1267 | + dst_vq->lock = &ctx->dev->dev_mutex; | |
| 1268 | + dst_vq->dev = &ctx->dev->plat_dev->dev; | |
| 1269 | + | |
| 1270 | + return vb2_queue_init(dst_vq); | |
| 1271 | +} | |
| 1272 | + | |
| 1273 | +int mtk_venc_unlock(struct mtk_vcodec_ctx *ctx) | |
| 1274 | +{ | |
| 1275 | + struct mtk_vcodec_dev *dev = ctx->dev; | |
| 1276 | + | |
| 1277 | + mutex_unlock(&dev->enc_mutex); | |
| 1278 | + return 0; | |
| 1279 | +} | |
| 1280 | + | |
| 1281 | +int mtk_venc_lock(struct mtk_vcodec_ctx *ctx) | |
| 1282 | +{ | |
| 1283 | + struct mtk_vcodec_dev *dev = ctx->dev; | |
| 1284 | + | |
| 1285 | + mutex_lock(&dev->enc_mutex); | |
| 1286 | + return 0; | |
| 1287 | +} | |
| 1288 | + | |
| 1289 | +void mtk_vcodec_enc_release(struct mtk_vcodec_ctx *ctx) | |
| 1290 | +{ | |
| 1291 | + venc_if_deinit(ctx); | |
| 1292 | +} | |
| @@ -0,0 +1,58 @@ | ||
| 1 | +/* | |
| 2 | +* Copyright (c) 2016 MediaTek Inc. | |
| 3 | +* Author: PC Chen <pc.chen@mediatek.com> | |
| 4 | +* Tiffany Lin <tiffany.lin@mediatek.com> | |
| 5 | +* | |
| 6 | +* This program is free software; you can redistribute it and/or modify | |
| 7 | +* it under the terms of the GNU General Public License version 2 as | |
| 8 | +* published by the Free Software Foundation. | |
| 9 | +* | |
| 10 | +* This program is distributed in the hope that it will be useful, | |
| 11 | +* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | +* GNU General Public License for more details. | |
| 14 | +*/ | |
| 15 | + | |
| 16 | +#ifndef _MTK_VCODEC_ENC_H_ | |
| 17 | +#define _MTK_VCODEC_ENC_H_ | |
| 18 | + | |
| 19 | +#include <media/videobuf2-core.h> | |
| 20 | +#include <media/videobuf2-v4l2.h> | |
| 21 | + | |
| 22 | +#define MTK_VENC_IRQ_STATUS_SPS 0x1 | |
| 23 | +#define MTK_VENC_IRQ_STATUS_PPS 0x2 | |
| 24 | +#define MTK_VENC_IRQ_STATUS_FRM 0x4 | |
| 25 | +#define MTK_VENC_IRQ_STATUS_DRAM 0x8 | |
| 26 | +#define MTK_VENC_IRQ_STATUS_PAUSE 0x10 | |
| 27 | +#define MTK_VENC_IRQ_STATUS_SWITCH 0x20 | |
| 28 | + | |
| 29 | +#define MTK_VENC_IRQ_STATUS_OFFSET 0x05C | |
| 30 | +#define MTK_VENC_IRQ_ACK_OFFSET 0x060 | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * struct mtk_video_enc_buf - Private data related to each VB2 buffer. | |
| 34 | + * @vb: Pointer to related VB2 buffer. | |
| 35 | + * @list: list that buffer link to | |
| 36 | + * @param_change: Types of encode parameter change before encoding this | |
| 37 | + * buffer | |
| 38 | + * @enc_params: Encode parameters changed before encode this buffer | |
| 39 | + */ | |
| 40 | +struct mtk_video_enc_buf { | |
| 41 | + struct vb2_v4l2_buffer vb; | |
| 42 | + struct list_head list; | |
| 43 | + u32 param_change; | |
| 44 | + struct mtk_enc_params enc_params; | |
| 45 | +}; | |
| 46 | + | |
| 47 | +extern const struct v4l2_ioctl_ops mtk_venc_ioctl_ops; | |
| 48 | +extern const struct v4l2_m2m_ops mtk_venc_m2m_ops; | |
| 49 | + | |
| 50 | +int mtk_venc_unlock(struct mtk_vcodec_ctx *ctx); | |
| 51 | +int mtk_venc_lock(struct mtk_vcodec_ctx *ctx); | |
| 52 | +int mtk_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq, | |
| 53 | + struct vb2_queue *dst_vq); | |
| 54 | +void mtk_vcodec_enc_release(struct mtk_vcodec_ctx *ctx); | |
| 55 | +int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx); | |
| 56 | +void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx); | |
| 57 | + | |
| 58 | +#endif /* _MTK_VCODEC_ENC_H_ */ | |
| @@ -0,0 +1,439 @@ | ||
| 1 | +/* | |
| 2 | +* Copyright (c) 2016 MediaTek Inc. | |
| 3 | +* Author: PC Chen <pc.chen@mediatek.com> | |
| 4 | +* Tiffany Lin <tiffany.lin@mediatek.com> | |
| 5 | +* | |
| 6 | +* This program is free software; you can redistribute it and/or modify | |
| 7 | +* it under the terms of the GNU General Public License version 2 as | |
| 8 | +* published by the Free Software Foundation. | |
| 9 | +* | |
| 10 | +* This program is distributed in the hope that it will be useful, | |
| 11 | +* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | +* GNU General Public License for more details. | |
| 14 | +*/ | |
| 15 | + | |
| 16 | +#include <linux/slab.h> | |
| 17 | +#include <linux/interrupt.h> | |
| 18 | +#include <linux/irq.h> | |
| 19 | +#include <linux/module.h> | |
| 20 | +#include <linux/of_device.h> | |
| 21 | +#include <linux/of.h> | |
| 22 | +#include <media/v4l2-event.h> | |
| 23 | +#include <media/v4l2-mem2mem.h> | |
| 24 | +#include <media/videobuf2-dma-contig.h> | |
| 25 | +#include <linux/pm_runtime.h> | |
| 26 | + | |
| 27 | +#include "mtk_vcodec_drv.h" | |
| 28 | +#include "mtk_vcodec_enc.h" | |
| 29 | +#include "mtk_vcodec_enc_pm.h" | |
| 30 | +#include "mtk_vcodec_intr.h" | |
| 31 | +#include "mtk_vcodec_util.h" | |
| 32 | +#include "mtk_vpu.h" | |
| 33 | + | |
| 34 | +module_param(mtk_v4l2_dbg_level, int, S_IRUGO | S_IWUSR); | |
| 35 | +module_param(mtk_vcodec_dbg, bool, S_IRUGO | S_IWUSR); | |
| 36 | + | |
| 37 | +/* Wake up context wait_queue */ | |
| 38 | +static void wake_up_ctx(struct mtk_vcodec_ctx *ctx, unsigned int reason) | |
| 39 | +{ | |
| 40 | + ctx->int_cond = 1; | |
| 41 | + ctx->int_type = reason; | |
| 42 | + wake_up_interruptible(&ctx->queue); | |
| 43 | +} | |
| 44 | + | |
| 45 | +static void clean_irq_status(unsigned int irq_status, void __iomem *addr) | |
| 46 | +{ | |
| 47 | + if (irq_status & MTK_VENC_IRQ_STATUS_PAUSE) | |
| 48 | + writel(MTK_VENC_IRQ_STATUS_PAUSE, addr); | |
| 49 | + | |
| 50 | + if (irq_status & MTK_VENC_IRQ_STATUS_SWITCH) | |
| 51 | + writel(MTK_VENC_IRQ_STATUS_SWITCH, addr); | |
| 52 | + | |
| 53 | + if (irq_status & MTK_VENC_IRQ_STATUS_DRAM) | |
| 54 | + writel(MTK_VENC_IRQ_STATUS_DRAM, addr); | |
| 55 | + | |
| 56 | + if (irq_status & MTK_VENC_IRQ_STATUS_SPS) | |
| 57 | + writel(MTK_VENC_IRQ_STATUS_SPS, addr); | |
| 58 | + | |
| 59 | + if (irq_status & MTK_VENC_IRQ_STATUS_PPS) | |
| 60 | + writel(MTK_VENC_IRQ_STATUS_PPS, addr); | |
| 61 | + | |
| 62 | + if (irq_status & MTK_VENC_IRQ_STATUS_FRM) | |
| 63 | + writel(MTK_VENC_IRQ_STATUS_FRM, addr); | |
| 64 | + | |
| 65 | +} | |
| 66 | +static irqreturn_t mtk_vcodec_enc_irq_handler(int irq, void *priv) | |
| 67 | +{ | |
| 68 | + struct mtk_vcodec_dev *dev = priv; | |
| 69 | + struct mtk_vcodec_ctx *ctx; | |
| 70 | + unsigned long flags; | |
| 71 | + void __iomem *addr; | |
| 72 | + | |
| 73 | + spin_lock_irqsave(&dev->irqlock, flags); | |
| 74 | + ctx = dev->curr_ctx; | |
| 75 | + spin_unlock_irqrestore(&dev->irqlock, flags); | |
| 76 | + | |
| 77 | + mtk_v4l2_debug(1, "id=%d", ctx->id); | |
| 78 | + addr = dev->reg_base[VENC_SYS] + MTK_VENC_IRQ_ACK_OFFSET; | |
| 79 | + | |
| 80 | + ctx->irq_status = readl(dev->reg_base[VENC_SYS] + | |
| 81 | + (MTK_VENC_IRQ_STATUS_OFFSET)); | |
| 82 | + | |
| 83 | + clean_irq_status(ctx->irq_status, addr); | |
| 84 | + | |
| 85 | + wake_up_ctx(ctx, MTK_INST_IRQ_RECEIVED); | |
| 86 | + return IRQ_HANDLED; | |
| 87 | +} | |
| 88 | + | |
| 89 | +static irqreturn_t mtk_vcodec_enc_lt_irq_handler(int irq, void *priv) | |
| 90 | +{ | |
| 91 | + struct mtk_vcodec_dev *dev = priv; | |
| 92 | + struct mtk_vcodec_ctx *ctx; | |
| 93 | + unsigned long flags; | |
| 94 | + void __iomem *addr; | |
| 95 | + | |
| 96 | + spin_lock_irqsave(&dev->irqlock, flags); | |
| 97 | + ctx = dev->curr_ctx; | |
| 98 | + spin_unlock_irqrestore(&dev->irqlock, flags); | |
| 99 | + | |
| 100 | + mtk_v4l2_debug(1, "id=%d", ctx->id); | |
| 101 | + ctx->irq_status = readl(dev->reg_base[VENC_LT_SYS] + | |
| 102 | + (MTK_VENC_IRQ_STATUS_OFFSET)); | |
| 103 | + | |
| 104 | + addr = dev->reg_base[VENC_LT_SYS] + MTK_VENC_IRQ_ACK_OFFSET; | |
| 105 | + | |
| 106 | + clean_irq_status(ctx->irq_status, addr); | |
| 107 | + | |
| 108 | + wake_up_ctx(ctx, MTK_INST_IRQ_RECEIVED); | |
| 109 | + return IRQ_HANDLED; | |
| 110 | +} | |
| 111 | + | |
| 112 | +static void mtk_vcodec_enc_reset_handler(void *priv) | |
| 113 | +{ | |
| 114 | + struct mtk_vcodec_dev *dev = priv; | |
| 115 | + struct mtk_vcodec_ctx *ctx; | |
| 116 | + | |
| 117 | + mtk_v4l2_debug(0, "Watchdog timeout!!"); | |
| 118 | + | |
| 119 | + mutex_lock(&dev->dev_mutex); | |
| 120 | + list_for_each_entry(ctx, &dev->ctx_list, list) { | |
| 121 | + ctx->state = MTK_STATE_ABORT; | |
| 122 | + mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ABORT", | |
| 123 | + ctx->id); | |
| 124 | + } | |
| 125 | + mutex_unlock(&dev->dev_mutex); | |
| 126 | +} | |
| 127 | + | |
| 128 | +static int fops_vcodec_open(struct file *file) | |
| 129 | +{ | |
| 130 | + struct mtk_vcodec_dev *dev = video_drvdata(file); | |
| 131 | + struct mtk_vcodec_ctx *ctx = NULL; | |
| 132 | + int ret = 0; | |
| 133 | + | |
| 134 | + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | |
| 135 | + if (!ctx) | |
| 136 | + return -ENOMEM; | |
| 137 | + | |
| 138 | + mutex_lock(&dev->dev_mutex); | |
| 139 | + /* | |
| 140 | + * Use simple counter to uniquely identify this context. Only | |
| 141 | + * used for logging. | |
| 142 | + */ | |
| 143 | + ctx->id = dev->id_counter++; | |
| 144 | + v4l2_fh_init(&ctx->fh, video_devdata(file)); | |
| 145 | + file->private_data = &ctx->fh; | |
| 146 | + v4l2_fh_add(&ctx->fh); | |
| 147 | + INIT_LIST_HEAD(&ctx->list); | |
| 148 | + ctx->dev = dev; | |
| 149 | + init_waitqueue_head(&ctx->queue); | |
| 150 | + | |
| 151 | + ctx->type = MTK_INST_ENCODER; | |
| 152 | + ret = mtk_vcodec_enc_ctrls_setup(ctx); | |
| 153 | + if (ret) { | |
| 154 | + mtk_v4l2_err("Failed to setup controls() (%d)", | |
| 155 | + ret); | |
| 156 | + goto err_ctrls_setup; | |
| 157 | + } | |
| 158 | + ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_enc, ctx, | |
| 159 | + &mtk_vcodec_enc_queue_init); | |
| 160 | + if (IS_ERR((__force void *)ctx->m2m_ctx)) { | |
| 161 | + ret = PTR_ERR((__force void *)ctx->m2m_ctx); | |
| 162 | + mtk_v4l2_err("Failed to v4l2_m2m_ctx_init() (%d)", | |
| 163 | + ret); | |
| 164 | + goto err_m2m_ctx_init; | |
| 165 | + } | |
| 166 | + mtk_vcodec_enc_set_default_params(ctx); | |
| 167 | + | |
| 168 | + if (v4l2_fh_is_singular(&ctx->fh)) { | |
| 169 | + /* | |
| 170 | + * vpu_load_firmware checks if it was loaded already and | |
| 171 | + * does nothing in that case | |
| 172 | + */ | |
| 173 | + ret = vpu_load_firmware(dev->vpu_plat_dev); | |
| 174 | + if (ret < 0) { | |
| 175 | + /* | |
| 176 | + * Return 0 if downloading firmware successfully, | |
| 177 | + * otherwise it is failed | |
| 178 | + */ | |
| 179 | + mtk_v4l2_err("vpu_load_firmware failed!"); | |
| 180 | + goto err_load_fw; | |
| 181 | + } | |
| 182 | + | |
| 183 | + dev->enc_capability = | |
| 184 | + vpu_get_venc_hw_capa(dev->vpu_plat_dev); | |
| 185 | + mtk_v4l2_debug(0, "encoder capability %x", dev->enc_capability); | |
| 186 | + } | |
| 187 | + | |
| 188 | + mtk_v4l2_debug(2, "Create instance [%d]@%p m2m_ctx=%p ", | |
| 189 | + ctx->id, ctx, ctx->m2m_ctx); | |
| 190 | + | |
| 191 | + dev->num_instances++; | |
| 192 | + list_add(&ctx->list, &dev->ctx_list); | |
| 193 | + | |
| 194 | + mutex_unlock(&dev->dev_mutex); | |
| 195 | + mtk_v4l2_debug(0, "%s encoder [%d]", dev_name(&dev->plat_dev->dev), | |
| 196 | + ctx->id); | |
| 197 | + return ret; | |
| 198 | + | |
| 199 | + /* Deinit when failure occurred */ | |
| 200 | +err_load_fw: | |
| 201 | + v4l2_m2m_ctx_release(ctx->m2m_ctx); | |
| 202 | +err_m2m_ctx_init: | |
| 203 | + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); | |
| 204 | +err_ctrls_setup: | |
| 205 | + v4l2_fh_del(&ctx->fh); | |
| 206 | + v4l2_fh_exit(&ctx->fh); | |
| 207 | + kfree(ctx); | |
| 208 | + mutex_unlock(&dev->dev_mutex); | |
| 209 | + | |
| 210 | + return ret; | |
| 211 | +} | |
| 212 | + | |
| 213 | +static int fops_vcodec_release(struct file *file) | |
| 214 | +{ | |
| 215 | + struct mtk_vcodec_dev *dev = video_drvdata(file); | |
| 216 | + struct mtk_vcodec_ctx *ctx = fh_to_ctx(file->private_data); | |
| 217 | + | |
| 218 | + mtk_v4l2_debug(1, "[%d] encoder", ctx->id); | |
| 219 | + mutex_lock(&dev->dev_mutex); | |
| 220 | + | |
| 221 | + mtk_vcodec_enc_release(ctx); | |
| 222 | + v4l2_fh_del(&ctx->fh); | |
| 223 | + v4l2_fh_exit(&ctx->fh); | |
| 224 | + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); | |
| 225 | + v4l2_m2m_ctx_release(ctx->m2m_ctx); | |
| 226 | + | |
| 227 | + list_del_init(&ctx->list); | |
| 228 | + dev->num_instances--; | |
| 229 | + kfree(ctx); | |
| 230 | + mutex_unlock(&dev->dev_mutex); | |
| 231 | + return 0; | |
| 232 | +} | |
| 233 | + | |
| 234 | +static const struct v4l2_file_operations mtk_vcodec_fops = { | |
| 235 | + .owner = THIS_MODULE, | |
| 236 | + .open = fops_vcodec_open, | |
| 237 | + .release = fops_vcodec_release, | |
| 238 | + .poll = v4l2_m2m_fop_poll, | |
| 239 | + .unlocked_ioctl = video_ioctl2, | |
| 240 | + .mmap = v4l2_m2m_fop_mmap, | |
| 241 | +}; | |
| 242 | + | |
| 243 | +static int mtk_vcodec_probe(struct platform_device *pdev) | |
| 244 | +{ | |
| 245 | + struct mtk_vcodec_dev *dev; | |
| 246 | + struct video_device *vfd_enc; | |
| 247 | + struct resource *res; | |
| 248 | + int i, j, ret; | |
| 249 | + DEFINE_DMA_ATTRS(attrs); | |
| 250 | + | |
| 251 | + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); | |
| 252 | + if (!dev) | |
| 253 | + return -ENOMEM; | |
| 254 | + | |
| 255 | + INIT_LIST_HEAD(&dev->ctx_list); | |
| 256 | + dev->plat_dev = pdev; | |
| 257 | + | |
| 258 | + dev->vpu_plat_dev = vpu_get_plat_device(dev->plat_dev); | |
| 259 | + if (dev->vpu_plat_dev == NULL) { | |
| 260 | + mtk_v4l2_err("[VPU] vpu device in not ready"); | |
| 261 | + return -EPROBE_DEFER; | |
| 262 | + } | |
| 263 | + | |
| 264 | + vpu_wdt_reg_handler(dev->vpu_plat_dev, mtk_vcodec_enc_reset_handler, | |
| 265 | + dev, VPU_RST_ENC); | |
| 266 | + | |
| 267 | + ret = mtk_vcodec_init_enc_pm(dev); | |
| 268 | + if (ret < 0) { | |
| 269 | + dev_err(&pdev->dev, "Failed to get mt vcodec clock source!"); | |
| 270 | + return ret; | |
| 271 | + } | |
| 272 | + | |
| 273 | + for (i = VENC_SYS, j = 0; i < NUM_MAX_VCODEC_REG_BASE; i++, j++) { | |
| 274 | + res = platform_get_resource(pdev, IORESOURCE_MEM, j); | |
| 275 | + if (res == NULL) { | |
| 276 | + dev_err(&pdev->dev, "get memory resource failed."); | |
| 277 | + ret = -ENXIO; | |
| 278 | + goto err_res; | |
| 279 | + } | |
| 280 | + dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res); | |
| 281 | + if (IS_ERR((__force void *)dev->reg_base[i])) { | |
| 282 | + ret = PTR_ERR((__force void *)dev->reg_base[i]); | |
| 283 | + goto err_res; | |
| 284 | + } | |
| 285 | + mtk_v4l2_debug(2, "reg[%d] base=0x%p", i, dev->reg_base[i]); | |
| 286 | + } | |
| 287 | + | |
| 288 | + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | |
| 289 | + if (res == NULL) { | |
| 290 | + dev_err(&pdev->dev, "failed to get irq resource"); | |
| 291 | + ret = -ENOENT; | |
| 292 | + goto err_res; | |
| 293 | + } | |
| 294 | + | |
| 295 | + dev->enc_irq = platform_get_irq(pdev, 0); | |
| 296 | + ret = devm_request_irq(&pdev->dev, dev->enc_irq, | |
| 297 | + mtk_vcodec_enc_irq_handler, | |
| 298 | + 0, pdev->name, dev); | |
| 299 | + if (ret) { | |
| 300 | + dev_err(&pdev->dev, "Failed to install dev->enc_irq %d (%d)", | |
| 301 | + dev->enc_irq, | |
| 302 | + ret); | |
| 303 | + ret = -EINVAL; | |
| 304 | + goto err_res; | |
| 305 | + } | |
| 306 | + | |
| 307 | + dev->enc_lt_irq = platform_get_irq(pdev, 1); | |
| 308 | + ret = devm_request_irq(&pdev->dev, | |
| 309 | + dev->enc_lt_irq, mtk_vcodec_enc_lt_irq_handler, | |
| 310 | + 0, pdev->name, dev); | |
| 311 | + if (ret) { | |
| 312 | + dev_err(&pdev->dev, | |
| 313 | + "Failed to install dev->enc_lt_irq %d (%d)", | |
| 314 | + dev->enc_lt_irq, ret); | |
| 315 | + ret = -EINVAL; | |
| 316 | + goto err_res; | |
| 317 | + } | |
| 318 | + | |
| 319 | + disable_irq(dev->enc_irq); | |
| 320 | + disable_irq(dev->enc_lt_irq); /* VENC_LT */ | |
| 321 | + mutex_init(&dev->enc_mutex); | |
| 322 | + mutex_init(&dev->dev_mutex); | |
| 323 | + spin_lock_init(&dev->irqlock); | |
| 324 | + | |
| 325 | + snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", | |
| 326 | + "[MTK_V4L2_VENC]"); | |
| 327 | + | |
| 328 | + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); | |
| 329 | + if (ret) { | |
| 330 | + mtk_v4l2_err("v4l2_device_register err=%d", ret); | |
| 331 | + goto err_res; | |
| 332 | + } | |
| 333 | + | |
| 334 | + init_waitqueue_head(&dev->queue); | |
| 335 | + | |
| 336 | + /* allocate video device for encoder and register it */ | |
| 337 | + vfd_enc = video_device_alloc(); | |
| 338 | + if (!vfd_enc) { | |
| 339 | + mtk_v4l2_err("Failed to allocate video device"); | |
| 340 | + ret = -ENOMEM; | |
| 341 | + goto err_enc_alloc; | |
| 342 | + } | |
| 343 | + vfd_enc->fops = &mtk_vcodec_fops; | |
| 344 | + vfd_enc->ioctl_ops = &mtk_venc_ioctl_ops; | |
| 345 | + vfd_enc->release = video_device_release; | |
| 346 | + vfd_enc->lock = &dev->dev_mutex; | |
| 347 | + vfd_enc->v4l2_dev = &dev->v4l2_dev; | |
| 348 | + vfd_enc->vfl_dir = VFL_DIR_M2M; | |
| 349 | + vfd_enc->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | | |
| 350 | + V4L2_CAP_STREAMING; | |
| 351 | + | |
| 352 | + snprintf(vfd_enc->name, sizeof(vfd_enc->name), "%s", | |
| 353 | + MTK_VCODEC_ENC_NAME); | |
| 354 | + video_set_drvdata(vfd_enc, dev); | |
| 355 | + dev->vfd_enc = vfd_enc; | |
| 356 | + platform_set_drvdata(pdev, dev); | |
| 357 | + | |
| 358 | + dev->m2m_dev_enc = v4l2_m2m_init(&mtk_venc_m2m_ops); | |
| 359 | + if (IS_ERR((__force void *)dev->m2m_dev_enc)) { | |
| 360 | + mtk_v4l2_err("Failed to init mem2mem enc device"); | |
| 361 | + ret = PTR_ERR((__force void *)dev->m2m_dev_enc); | |
| 362 | + goto err_enc_mem_init; | |
| 363 | + } | |
| 364 | + | |
| 365 | + dev->encode_workqueue = | |
| 366 | + alloc_ordered_workqueue(MTK_VCODEC_ENC_NAME, | |
| 367 | + WQ_MEM_RECLAIM | | |
| 368 | + WQ_FREEZABLE); | |
| 369 | + if (!dev->encode_workqueue) { | |
| 370 | + mtk_v4l2_err("Failed to create encode workqueue"); | |
| 371 | + ret = -EINVAL; | |
| 372 | + goto err_event_workq; | |
| 373 | + } | |
| 374 | + | |
| 375 | + ret = video_register_device(vfd_enc, VFL_TYPE_GRABBER, 1); | |
| 376 | + if (ret) { | |
| 377 | + mtk_v4l2_err("Failed to register video device"); | |
| 378 | + goto err_enc_reg; | |
| 379 | + } | |
| 380 | + | |
| 381 | + /* Avoid the iommu eat big hunks */ | |
| 382 | + dma_set_attr(DMA_ATTR_ALLOC_SINGLE_PAGES, &attrs); | |
| 383 | + | |
| 384 | + mtk_v4l2_debug(0, "encoder registered as /dev/video%d", | |
| 385 | + vfd_enc->num); | |
| 386 | + | |
| 387 | + return 0; | |
| 388 | + | |
| 389 | +err_enc_reg: | |
| 390 | + destroy_workqueue(dev->encode_workqueue); | |
| 391 | +err_event_workq: | |
| 392 | + v4l2_m2m_release(dev->m2m_dev_enc); | |
| 393 | +err_enc_mem_init: | |
| 394 | + video_unregister_device(vfd_enc); | |
| 395 | +err_enc_alloc: | |
| 396 | + v4l2_device_unregister(&dev->v4l2_dev); | |
| 397 | +err_res: | |
| 398 | + mtk_vcodec_release_enc_pm(dev); | |
| 399 | + return ret; | |
| 400 | +} | |
| 401 | + | |
| 402 | +static const struct of_device_id mtk_vcodec_enc_match[] = { | |
| 403 | + {.compatible = "mediatek,mt8173-vcodec-enc",}, | |
| 404 | + {}, | |
| 405 | +}; | |
| 406 | +MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match); | |
| 407 | + | |
| 408 | +static int mtk_vcodec_enc_remove(struct platform_device *pdev) | |
| 409 | +{ | |
| 410 | + struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev); | |
| 411 | + | |
| 412 | + mtk_v4l2_debug_enter(); | |
| 413 | + flush_workqueue(dev->encode_workqueue); | |
| 414 | + destroy_workqueue(dev->encode_workqueue); | |
| 415 | + if (dev->m2m_dev_enc) | |
| 416 | + v4l2_m2m_release(dev->m2m_dev_enc); | |
| 417 | + | |
| 418 | + if (dev->vfd_enc) | |
| 419 | + video_unregister_device(dev->vfd_enc); | |
| 420 | + | |
| 421 | + v4l2_device_unregister(&dev->v4l2_dev); | |
| 422 | + mtk_vcodec_release_enc_pm(dev); | |
| 423 | + return 0; | |
| 424 | +} | |
| 425 | + | |
| 426 | +static struct platform_driver mtk_vcodec_enc_driver = { | |
| 427 | + .probe = mtk_vcodec_probe, | |
| 428 | + .remove = mtk_vcodec_enc_remove, | |
| 429 | + .driver = { | |
| 430 | + .name = MTK_VCODEC_ENC_NAME, | |
| 431 | + .of_match_table = mtk_vcodec_enc_match, | |
| 432 | + }, | |
| 433 | +}; | |
| 434 | + | |
| 435 | +module_platform_driver(mtk_vcodec_enc_driver); | |
| 436 | + | |
| 437 | + | |
| 438 | +MODULE_LICENSE("GPL v2"); | |
| 439 | +MODULE_DESCRIPTION("Mediatek video codec V4L2 encoder driver"); | |
| @@ -0,0 +1,137 @@ | ||
| 1 | +/* | |
| 2 | +* Copyright (c) 2016 MediaTek Inc. | |
| 3 | +* Author: Tiffany Lin <tiffany.lin@mediatek.com> | |
| 4 | +* | |
| 5 | +* This program is free software; you can redistribute it and/or modify | |
| 6 | +* it under the terms of the GNU General Public License version 2 as | |
| 7 | +* published by the Free Software Foundation. | |
| 8 | +* | |
| 9 | +* This program is distributed in the hope that it will be useful, | |
| 10 | +* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | +* GNU General Public License for more details. | |
| 13 | +*/ | |
| 14 | + | |
| 15 | +#include <linux/clk.h> | |
| 16 | +#include <linux/of_address.h> | |
| 17 | +#include <linux/of_platform.h> | |
| 18 | +#include <linux/pm_runtime.h> | |
| 19 | +#include <soc/mediatek/smi.h> | |
| 20 | + | |
| 21 | +#include "mtk_vcodec_enc_pm.h" | |
| 22 | +#include "mtk_vcodec_util.h" | |
| 23 | +#include "mtk_vpu.h" | |
| 24 | + | |
| 25 | + | |
| 26 | +int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) | |
| 27 | +{ | |
| 28 | + struct device_node *node; | |
| 29 | + struct platform_device *pdev; | |
| 30 | + struct device *dev; | |
| 31 | + struct mtk_vcodec_pm *pm; | |
| 32 | + int ret = 0; | |
| 33 | + | |
| 34 | + pdev = mtkdev->plat_dev; | |
| 35 | + pm = &mtkdev->pm; | |
| 36 | + memset(pm, 0, sizeof(struct mtk_vcodec_pm)); | |
| 37 | + pm->mtkdev = mtkdev; | |
| 38 | + pm->dev = &pdev->dev; | |
| 39 | + dev = &pdev->dev; | |
| 40 | + | |
| 41 | + node = of_parse_phandle(dev->of_node, "mediatek,larb", 0); | |
| 42 | + if (!node) { | |
| 43 | + mtk_v4l2_err("no mediatek,larb found"); | |
| 44 | + return -1; | |
| 45 | + } | |
| 46 | + pdev = of_find_device_by_node(node); | |
| 47 | + if (!pdev) { | |
| 48 | + mtk_v4l2_err("no mediatek,larb device found"); | |
| 49 | + return -1; | |
| 50 | + } | |
| 51 | + pm->larbvenc = &pdev->dev; | |
| 52 | + | |
| 53 | + node = of_parse_phandle(dev->of_node, "mediatek,larb", 1); | |
| 54 | + if (!node) { | |
| 55 | + mtk_v4l2_err("no mediatek,larb found"); | |
| 56 | + return -1; | |
| 57 | + } | |
| 58 | + | |
| 59 | + pdev = of_find_device_by_node(node); | |
| 60 | + if (!pdev) { | |
| 61 | + mtk_v4l2_err("no mediatek,larb device found"); | |
| 62 | + return -1; | |
| 63 | + } | |
| 64 | + | |
| 65 | + pm->larbvenclt = &pdev->dev; | |
| 66 | + pdev = mtkdev->plat_dev; | |
| 67 | + pm->dev = &pdev->dev; | |
| 68 | + | |
| 69 | + pm->vencpll_d2 = devm_clk_get(&pdev->dev, "venc_sel_src"); | |
| 70 | + if (IS_ERR(pm->vencpll_d2)) { | |
| 71 | + mtk_v4l2_err("devm_clk_get vencpll_d2 fail"); | |
| 72 | + ret = PTR_ERR(pm->vencpll_d2); | |
| 73 | + } | |
| 74 | + | |
| 75 | + pm->venc_sel = devm_clk_get(&pdev->dev, "venc_sel"); | |
| 76 | + if (IS_ERR(pm->venc_sel)) { | |
| 77 | + mtk_v4l2_err("devm_clk_get venc_sel fail"); | |
| 78 | + ret = PTR_ERR(pm->venc_sel); | |
| 79 | + } | |
| 80 | + | |
| 81 | + pm->univpll1_d2 = devm_clk_get(&pdev->dev, "venc_lt_sel_src"); | |
| 82 | + if (IS_ERR(pm->univpll1_d2)) { | |
| 83 | + mtk_v4l2_err("devm_clk_get univpll1_d2 fail"); | |
| 84 | + ret = PTR_ERR(pm->univpll1_d2); | |
| 85 | + } | |
| 86 | + | |
| 87 | + pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel"); | |
| 88 | + if (IS_ERR(pm->venc_lt_sel)) { | |
| 89 | + mtk_v4l2_err("devm_clk_get venc_lt_sel fail"); | |
| 90 | + ret = PTR_ERR(pm->venc_lt_sel); | |
| 91 | + } | |
| 92 | + | |
| 93 | + return ret; | |
| 94 | +} | |
| 95 | + | |
| 96 | +void mtk_vcodec_release_enc_pm(struct mtk_vcodec_dev *mtkdev) | |
| 97 | +{ | |
| 98 | +} | |
| 99 | + | |
| 100 | + | |
| 101 | +void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm) | |
| 102 | +{ | |
| 103 | + int ret; | |
| 104 | + | |
| 105 | + ret = clk_prepare_enable(pm->venc_sel); | |
| 106 | + if (ret) | |
| 107 | + mtk_v4l2_err("clk_prepare_enable fail %d", ret); | |
| 108 | + | |
| 109 | + ret = clk_set_parent(pm->venc_sel, pm->vencpll_d2); | |
| 110 | + if (ret) | |
| 111 | + mtk_v4l2_err("clk_set_parent fail %d", ret); | |
| 112 | + | |
| 113 | + ret = clk_prepare_enable(pm->venc_lt_sel); | |
| 114 | + if (ret) | |
| 115 | + mtk_v4l2_err("clk_prepare_enable fail %d", ret); | |
| 116 | + | |
| 117 | + ret = clk_set_parent(pm->venc_lt_sel, pm->univpll1_d2); | |
| 118 | + if (ret) | |
| 119 | + mtk_v4l2_err("clk_set_parent fail %d", ret); | |
| 120 | + | |
| 121 | + ret = mtk_smi_larb_get(pm->larbvenc); | |
| 122 | + if (ret) | |
| 123 | + mtk_v4l2_err("mtk_smi_larb_get larb3 fail %d", ret); | |
| 124 | + | |
| 125 | + ret = mtk_smi_larb_get(pm->larbvenclt); | |
| 126 | + if (ret) | |
| 127 | + mtk_v4l2_err("mtk_smi_larb_get larb4 fail %d", ret); | |
| 128 | + | |
| 129 | +} | |
| 130 | + | |
| 131 | +void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm) | |
| 132 | +{ | |
| 133 | + mtk_smi_larb_put(pm->larbvenc); | |
| 134 | + mtk_smi_larb_put(pm->larbvenclt); | |
| 135 | + clk_disable_unprepare(pm->venc_lt_sel); | |
| 136 | + clk_disable_unprepare(pm->venc_sel); | |
| 137 | +} | |
| @@ -0,0 +1,26 @@ | ||
| 1 | +/* | |
| 2 | +* Copyright (c) 2016 MediaTek Inc. | |
| 3 | +* Author: Tiffany Lin <tiffany.lin@mediatek.com> | |
| 4 | +* | |
| 5 | +* This program is free software; you can redistribute it and/or modify | |
| 6 | +* it under the terms of the GNU General Public License version 2 as | |
| 7 | +* published by the Free Software Foundation. | |
| 8 | +* | |
| 9 | +* This program is distributed in the hope that it will be useful, | |
| 10 | +* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | +* GNU General Public License for more details. | |
| 13 | +*/ | |
| 14 | + | |
| 15 | +#ifndef _MTK_VCODEC_ENC_PM_H_ | |
| 16 | +#define _MTK_VCODEC_ENC_PM_H_ | |
| 17 | + | |
| 18 | +#include "mtk_vcodec_drv.h" | |
| 19 | + | |
| 20 | +int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *dev); | |
| 21 | +void mtk_vcodec_release_enc_pm(struct mtk_vcodec_dev *dev); | |
| 22 | + | |
| 23 | +void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm); | |
| 24 | +void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm); | |
| 25 | + | |
| 26 | +#endif /* _MTK_VCODEC_ENC_PM_H_ */ | |
| @@ -0,0 +1,54 @@ | ||
| 1 | +/* | |
| 2 | +* Copyright (c) 2016 MediaTek Inc. | |
| 3 | +* Author: Tiffany Lin <tiffany.lin@mediatek.com> | |
| 4 | +* | |
| 5 | +* This program is free software; you can redistribute it and/or modify | |
| 6 | +* it under the terms of the GNU General Public License version 2 as | |
| 7 | +* published by the Free Software Foundation. | |
| 8 | +* | |
| 9 | +* This program is distributed in the hope that it will be useful, | |
| 10 | +* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | +* GNU General Public License for more details. | |
| 13 | +*/ | |
| 14 | + | |
| 15 | +#include <linux/errno.h> | |
| 16 | +#include <linux/wait.h> | |
| 17 | + | |
| 18 | +#include "mtk_vcodec_drv.h" | |
| 19 | +#include "mtk_vcodec_intr.h" | |
| 20 | +#include "mtk_vcodec_util.h" | |
| 21 | + | |
| 22 | +int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx *ctx, int command, | |
| 23 | + unsigned int timeout_ms) | |
| 24 | +{ | |
| 25 | + wait_queue_head_t *waitqueue; | |
| 26 | + long timeout_jiff, ret; | |
| 27 | + int status = 0; | |
| 28 | + | |
| 29 | + waitqueue = (wait_queue_head_t *)&ctx->queue; | |
| 30 | + timeout_jiff = msecs_to_jiffies(timeout_ms); | |
| 31 | + | |
| 32 | + ret = wait_event_interruptible_timeout(*waitqueue, | |
| 33 | + (ctx->int_cond && | |
| 34 | + (ctx->int_type == command)), | |
| 35 | + timeout_jiff); | |
| 36 | + | |
| 37 | + if (!ret) { | |
| 38 | + status = -1; /* timeout */ | |
| 39 | + mtk_v4l2_err("[%d] cmd=%d, ctx->type=%d, wait_event_interruptible_timeout time=%ums out %d %d!", | |
| 40 | + ctx->id, ctx->type, command, timeout_ms, | |
| 41 | + ctx->int_cond, ctx->int_type); | |
| 42 | + } else if (-ERESTARTSYS == ret) { | |
| 43 | + mtk_v4l2_err("[%d] cmd=%d, ctx->type=%d, wait_event_interruptible_timeout interrupted by a signal %d %d", | |
| 44 | + ctx->id, ctx->type, command, ctx->int_cond, | |
| 45 | + ctx->int_type); | |
| 46 | + status = -1; | |
| 47 | + } | |
| 48 | + | |
| 49 | + ctx->int_cond = 0; | |
| 50 | + ctx->int_type = 0; | |
| 51 | + | |
| 52 | + return status; | |
| 53 | +} | |
| 54 | +EXPORT_SYMBOL(mtk_vcodec_wait_for_done_ctx); | |
| @@ -0,0 +1,27 @@ | ||
| 1 | +/* | |
| 2 | +* Copyright (c) 2016 MediaTek Inc. | |
| 3 | +* Author: Tiffany Lin <tiffany.lin@mediatek.com> | |
| 4 | +* | |
| 5 | +* This program is free software; you can redistribute it and/or modify | |
| 6 | +* it under the terms of the GNU General Public License version 2 as | |
| 7 | +* published by the Free Software Foundation. | |
| 8 | +* | |
| 9 | +* This program is distributed in the hope that it will be useful, | |
| 10 | +* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | +* GNU General Public License for more details. | |
| 13 | +*/ | |
| 14 | + | |
| 15 | +#ifndef _MTK_VCODEC_INTR_H_ | |
| 16 | +#define _MTK_VCODEC_INTR_H_ | |
| 17 | + | |
| 18 | +#define MTK_INST_IRQ_RECEIVED 0x1 | |
| 19 | +#define MTK_INST_WORK_THREAD_ABORT_DONE 0x2 | |
| 20 | + | |
| 21 | +struct mtk_vcodec_ctx; | |
| 22 | + | |
| 23 | +/* timeout is ms */ | |
| 24 | +int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx *data, int command, | |
| 25 | + unsigned int timeout_ms); | |
| 26 | + | |
| 27 | +#endif /* _MTK_VCODEC_INTR_H_ */ | |
| @@ -0,0 +1,94 @@ | ||
| 1 | +/* | |
| 2 | +* Copyright (c) 2016 MediaTek Inc. | |
| 3 | +* Author: PC Chen <pc.chen@mediatek.com> | |
| 4 | +* Tiffany Lin <tiffany.lin@mediatek.com> | |
| 5 | +* | |
| 6 | +* This program is free software; you can redistribute it and/or modify | |
| 7 | +* it under the terms of the GNU General Public License version 2 as | |
| 8 | +* published by the Free Software Foundation. | |
| 9 | +* | |
| 10 | +* This program is distributed in the hope that it will be useful, | |
| 11 | +* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | +* GNU General Public License for more details. | |
| 14 | +*/ | |
| 15 | + | |
| 16 | +#include <linux/module.h> | |
| 17 | + | |
| 18 | +#include "mtk_vcodec_drv.h" | |
| 19 | +#include "mtk_vcodec_util.h" | |
| 20 | +#include "mtk_vpu.h" | |
| 21 | + | |
| 22 | +/* For encoder, this will enable logs in venc/*/ | |
| 23 | +bool mtk_vcodec_dbg; | |
| 24 | +EXPORT_SYMBOL(mtk_vcodec_dbg); | |
| 25 | + | |
| 26 | +/* The log level of v4l2 encoder or decoder driver. | |
| 27 | + * That is, files under mtk-vcodec/. | |
| 28 | + */ | |
| 29 | +int mtk_v4l2_dbg_level; | |
| 30 | +EXPORT_SYMBOL(mtk_v4l2_dbg_level); | |
| 31 | + | |
| 32 | +void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data, | |
| 33 | + unsigned int reg_idx) | |
| 34 | +{ | |
| 35 | + struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data; | |
| 36 | + | |
| 37 | + if (!data || reg_idx >= NUM_MAX_VCODEC_REG_BASE) { | |
| 38 | + mtk_v4l2_err("Invalid arguments, reg_idx=%d", reg_idx); | |
| 39 | + return NULL; | |
| 40 | + } | |
| 41 | + return ctx->dev->reg_base[reg_idx]; | |
| 42 | +} | |
| 43 | +EXPORT_SYMBOL(mtk_vcodec_get_reg_addr); | |
| 44 | + | |
| 45 | +int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data, | |
| 46 | + struct mtk_vcodec_mem *mem) | |
| 47 | +{ | |
| 48 | + unsigned long size = mem->size; | |
| 49 | + struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data; | |
| 50 | + struct device *dev = &ctx->dev->plat_dev->dev; | |
| 51 | + | |
| 52 | + mem->va = dma_alloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL); | |
| 53 | + | |
| 54 | + if (!mem->va) { | |
| 55 | + mtk_v4l2_err("%s dma_alloc size=%ld failed!", dev_name(dev), | |
| 56 | + size); | |
| 57 | + return -ENOMEM; | |
| 58 | + } | |
| 59 | + | |
| 60 | + memset(mem->va, 0, size); | |
| 61 | + | |
| 62 | + mtk_v4l2_debug(3, "[%d] - va = %p", ctx->id, mem->va); | |
| 63 | + mtk_v4l2_debug(3, "[%d] - dma = 0x%lx", ctx->id, | |
| 64 | + (unsigned long)mem->dma_addr); | |
| 65 | + mtk_v4l2_debug(3, "[%d] size = 0x%lx", ctx->id, size); | |
| 66 | + | |
| 67 | + return 0; | |
| 68 | +} | |
| 69 | +EXPORT_SYMBOL(mtk_vcodec_mem_alloc); | |
| 70 | + | |
| 71 | +void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data, | |
| 72 | + struct mtk_vcodec_mem *mem) | |
| 73 | +{ | |
| 74 | + unsigned long size = mem->size; | |
| 75 | + struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data; | |
| 76 | + struct device *dev = &ctx->dev->plat_dev->dev; | |
| 77 | + | |
| 78 | + if (!mem->va) { | |
| 79 | + mtk_v4l2_err("%s dma_free size=%ld failed!", dev_name(dev), | |
| 80 | + size); | |
| 81 | + return; | |
| 82 | + } | |
| 83 | + | |
| 84 | + dma_free_coherent(dev, size, mem->va, mem->dma_addr); | |
| 85 | + mem->va = NULL; | |
| 86 | + mem->dma_addr = 0; | |
| 87 | + mem->size = 0; | |
| 88 | + | |
| 89 | + mtk_v4l2_debug(3, "[%d] - va = %p", ctx->id, mem->va); | |
| 90 | + mtk_v4l2_debug(3, "[%d] - dma = 0x%lx", ctx->id, | |
| 91 | + (unsigned long)mem->dma_addr); | |
| 92 | + mtk_v4l2_debug(3, "[%d] size = 0x%lx", ctx->id, size); | |
| 93 | +} | |
| 94 | +EXPORT_SYMBOL(mtk_vcodec_mem_free); | |
| @@ -0,0 +1,87 @@ | ||
| 1 | +/* | |
| 2 | +* Copyright (c) 2016 MediaTek Inc. | |
| 3 | +* Author: PC Chen <pc.chen@mediatek.com> | |
| 4 | +* Tiffany Lin <tiffany.lin@mediatek.com> | |
| 5 | +* | |
| 6 | +* This program is free software; you can redistribute it and/or modify | |
| 7 | +* it under the terms of the GNU General Public License version 2 as | |
| 8 | +* published by the Free Software Foundation. | |
| 9 | +* | |
| 10 | +* This program is distributed in the hope that it will be useful, | |
| 11 | +* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | +* GNU General Public License for more details. | |
| 14 | +*/ | |
| 15 | + | |
| 16 | +#ifndef _MTK_VCODEC_UTIL_H_ | |
| 17 | +#define _MTK_VCODEC_UTIL_H_ | |
| 18 | + | |
| 19 | +#include <linux/types.h> | |
| 20 | +#include <linux/dma-direction.h> | |
| 21 | + | |
| 22 | +struct mtk_vcodec_mem { | |
| 23 | + size_t size; | |
| 24 | + void *va; | |
| 25 | + dma_addr_t dma_addr; | |
| 26 | +}; | |
| 27 | + | |
| 28 | +struct mtk_vcodec_ctx; | |
| 29 | + | |
| 30 | +extern int mtk_v4l2_dbg_level; | |
| 31 | +extern bool mtk_vcodec_dbg; | |
| 32 | + | |
| 33 | +#define DEBUG 1 | |
| 34 | + | |
| 35 | +#if defined(DEBUG) | |
| 36 | + | |
| 37 | +#define mtk_v4l2_debug(level, fmt, args...) \ | |
| 38 | + do { \ | |
| 39 | + if (mtk_v4l2_dbg_level >= level) \ | |
| 40 | + pr_info("[MTK_V4L2] level=%d %s(),%d: " fmt "\n",\ | |
| 41 | + level, __func__, __LINE__, ##args); \ | |
| 42 | + } while (0) | |
| 43 | + | |
| 44 | +#define mtk_v4l2_err(fmt, args...) \ | |
| 45 | + pr_err("[MTK_V4L2][ERROR] %s:%d: " fmt "\n", __func__, __LINE__, \ | |
| 46 | + ##args) | |
| 47 | + | |
| 48 | + | |
| 49 | +#define mtk_v4l2_debug_enter() mtk_v4l2_debug(3, "+") | |
| 50 | +#define mtk_v4l2_debug_leave() mtk_v4l2_debug(3, "-") | |
| 51 | + | |
| 52 | +#define mtk_vcodec_debug(h, fmt, args...) \ | |
| 53 | + do { \ | |
| 54 | + if (mtk_vcodec_dbg) \ | |
| 55 | + pr_info("[MTK_VCODEC][%d]: %s() " fmt "\n", \ | |
| 56 | + ((struct mtk_vcodec_ctx *)h->ctx)->id, \ | |
| 57 | + __func__, ##args); \ | |
| 58 | + } while (0) | |
| 59 | + | |
| 60 | +#define mtk_vcodec_err(h, fmt, args...) \ | |
| 61 | + pr_err("[MTK_VCODEC][ERROR][%d]: %s() " fmt "\n", \ | |
| 62 | + ((struct mtk_vcodec_ctx *)h->ctx)->id, __func__, ##args) | |
| 63 | + | |
| 64 | +#define mtk_vcodec_debug_enter(h) mtk_vcodec_debug(h, "+") | |
| 65 | +#define mtk_vcodec_debug_leave(h) mtk_vcodec_debug(h, "-") | |
| 66 | + | |
| 67 | +#else | |
| 68 | + | |
| 69 | +#define mtk_v4l2_debug(level, fmt, args...) | |
| 70 | +#define mtk_v4l2_err(fmt, args...) | |
| 71 | +#define mtk_v4l2_debug_enter() | |
| 72 | +#define mtk_v4l2_debug_leave() | |
| 73 | + | |
| 74 | +#define mtk_vcodec_debug(h, fmt, args...) | |
| 75 | +#define mtk_vcodec_err(h, fmt, args...) | |
| 76 | +#define mtk_vcodec_debug_enter(h) | |
| 77 | +#define mtk_vcodec_debug_leave(h) | |
| 78 | + | |
| 79 | +#endif | |
| 80 | + | |
| 81 | +void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data, | |
| 82 | + unsigned int reg_idx); | |
| 83 | +int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data, | |
| 84 | + struct mtk_vcodec_mem *mem); | |
| 85 | +void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data, | |
| 86 | + struct mtk_vcodec_mem *mem); | |
| 87 | +#endif /* _MTK_VCODEC_UTIL_H_ */ | |
| @@ -0,0 +1,679 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2016 MediaTek Inc. | |
| 3 | + * Author: Jungchang Tsao <jungchang.tsao@mediatek.com> | |
| 4 | + * Daniel Hsiao <daniel.hsiao@mediatek.com> | |
| 5 | + * PoChun Lin <pochun.lin@mediatek.com> | |
| 6 | + * | |
| 7 | + * This program is free software; you can redistribute it and/or | |
| 8 | + * modify | |
| 9 | + * it under the terms of the GNU General Public License version 2 as | |
| 10 | + * published by the Free Software Foundation. | |
| 11 | + * | |
| 12 | + * This program is distributed in the hope that it will be useful, | |
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 15 | + * GNU General Public License for more details. | |
| 16 | + */ | |
| 17 | + | |
| 18 | +#include <linux/interrupt.h> | |
| 19 | +#include <linux/kernel.h> | |
| 20 | +#include <linux/slab.h> | |
| 21 | + | |
| 22 | +#include "../mtk_vcodec_drv.h" | |
| 23 | +#include "../mtk_vcodec_util.h" | |
| 24 | +#include "../mtk_vcodec_intr.h" | |
| 25 | +#include "../mtk_vcodec_enc.h" | |
| 26 | +#include "../mtk_vcodec_enc_pm.h" | |
| 27 | +#include "../venc_drv_base.h" | |
| 28 | +#include "../venc_ipi_msg.h" | |
| 29 | +#include "../venc_vpu_if.h" | |
| 30 | +#include "mtk_vpu.h" | |
| 31 | + | |
| 32 | +static const char h264_filler_marker[] = {0x0, 0x0, 0x0, 0x1, 0xc}; | |
| 33 | + | |
| 34 | +#define H264_FILLER_MARKER_SIZE ARRAY_SIZE(h264_filler_marker) | |
| 35 | +#define VENC_PIC_BITSTREAM_BYTE_CNT 0x0098 | |
| 36 | + | |
| 37 | +/** | |
| 38 | + * enum venc_h264_vpu_work_buf - h264 encoder buffer index | |
| 39 | + */ | |
| 40 | +enum venc_h264_vpu_work_buf { | |
| 41 | + VENC_H264_VPU_WORK_BUF_RC_INFO, | |
| 42 | + VENC_H264_VPU_WORK_BUF_RC_CODE, | |
| 43 | + VENC_H264_VPU_WORK_BUF_REC_LUMA, | |
| 44 | + VENC_H264_VPU_WORK_BUF_REC_CHROMA, | |
| 45 | + VENC_H264_VPU_WORK_BUF_REF_LUMA, | |
| 46 | + VENC_H264_VPU_WORK_BUF_REF_CHROMA, | |
| 47 | + VENC_H264_VPU_WORK_BUF_MV_INFO_1, | |
| 48 | + VENC_H264_VPU_WORK_BUF_MV_INFO_2, | |
| 49 | + VENC_H264_VPU_WORK_BUF_SKIP_FRAME, | |
| 50 | + VENC_H264_VPU_WORK_BUF_MAX, | |
| 51 | +}; | |
| 52 | + | |
| 53 | +/** | |
| 54 | + * enum venc_h264_bs_mode - for bs_mode argument in h264_enc_vpu_encode | |
| 55 | + */ | |
| 56 | +enum venc_h264_bs_mode { | |
| 57 | + H264_BS_MODE_SPS, | |
| 58 | + H264_BS_MODE_PPS, | |
| 59 | + H264_BS_MODE_FRAME, | |
| 60 | +}; | |
| 61 | + | |
| 62 | +/* | |
| 63 | + * struct venc_h264_vpu_config - Structure for h264 encoder configuration | |
| 64 | + * @input_fourcc: input fourcc | |
| 65 | + * @bitrate: target bitrate (in bps) | |
| 66 | + * @pic_w: picture width. Picture size is visible stream resolution, in pixels, | |
| 67 | + * to be used for display purposes; must be smaller or equal to buffer | |
| 68 | + * size. | |
| 69 | + * @pic_h: picture height | |
| 70 | + * @buf_w: buffer width. Buffer size is stream resolution in pixels aligned to | |
| 71 | + * hardware requirements. | |
| 72 | + * @buf_h: buffer height | |
| 73 | + * @gop_size: group of picture size (idr frame) | |
| 74 | + * @intra_period: intra frame period | |
| 75 | + * @framerate: frame rate in fps | |
| 76 | + * @profile: as specified in standard | |
| 77 | + * @level: as specified in standard | |
| 78 | + * @wfd: WFD mode 1:on, 0:off | |
| 79 | + */ | |
| 80 | +struct venc_h264_vpu_config { | |
| 81 | + u32 input_fourcc; | |
| 82 | + u32 bitrate; | |
| 83 | + u32 pic_w; | |
| 84 | + u32 pic_h; | |
| 85 | + u32 buf_w; | |
| 86 | + u32 buf_h; | |
| 87 | + u32 gop_size; | |
| 88 | + u32 intra_period; | |
| 89 | + u32 framerate; | |
| 90 | + u32 profile; | |
| 91 | + u32 level; | |
| 92 | + u32 wfd; | |
| 93 | +}; | |
| 94 | + | |
| 95 | +/* | |
| 96 | + * struct venc_h264_vpu_buf - Structure for buffer information | |
| 97 | + * @align: buffer alignment (in bytes) | |
| 98 | + * @iova: IO virtual address | |
| 99 | + * @vpua: VPU side memory addr which is used by RC_CODE | |
| 100 | + * @size: buffer size (in bytes) | |
| 101 | + */ | |
| 102 | +struct venc_h264_vpu_buf { | |
| 103 | + u32 align; | |
| 104 | + u32 iova; | |
| 105 | + u32 vpua; | |
| 106 | + u32 size; | |
| 107 | +}; | |
| 108 | + | |
| 109 | +/* | |
| 110 | + * struct venc_h264_vsi - Structure for VPU driver control and info share | |
| 111 | + * This structure is allocated in VPU side and shared to AP side. | |
| 112 | + * @config: h264 encoder configuration | |
| 113 | + * @work_bufs: working buffer information in VPU side | |
| 114 | + * The work_bufs here is for storing the 'size' info shared to AP side. | |
| 115 | + * The similar item in struct venc_h264_inst is for memory allocation | |
| 116 | + * in AP side. The AP driver will copy the 'size' from here to the one in | |
| 117 | + * struct mtk_vcodec_mem, then invoke mtk_vcodec_mem_alloc to allocate | |
| 118 | + * the buffer. After that, bypass the 'dma_addr' to the 'iova' field here for | |
| 119 | + * register setting in VPU side. | |
| 120 | + */ | |
| 121 | +struct venc_h264_vsi { | |
| 122 | + struct venc_h264_vpu_config config; | |
| 123 | + struct venc_h264_vpu_buf work_bufs[VENC_H264_VPU_WORK_BUF_MAX]; | |
| 124 | +}; | |
| 125 | + | |
| 126 | +/* | |
| 127 | + * struct venc_h264_inst - h264 encoder AP driver instance | |
| 128 | + * @hw_base: h264 encoder hardware register base | |
| 129 | + * @work_bufs: working buffer | |
| 130 | + * @pps_buf: buffer to store the pps bitstream | |
| 131 | + * @work_buf_allocated: working buffer allocated flag | |
| 132 | + * @frm_cnt: encoded frame count | |
| 133 | + * @prepend_hdr: when the v4l2 layer send VENC_SET_PARAM_PREPEND_HEADER cmd | |
| 134 | + * through h264_enc_set_param interface, it will set this flag and prepend the | |
| 135 | + * sps/pps in h264_enc_encode function. | |
| 136 | + * @vpu_inst: VPU instance to exchange information between AP and VPU | |
| 137 | + * @vsi: driver structure allocated by VPU side and shared to AP side for | |
| 138 | + * control and info share | |
| 139 | + * @ctx: context for v4l2 layer integration | |
| 140 | + */ | |
| 141 | +struct venc_h264_inst { | |
| 142 | + void __iomem *hw_base; | |
| 143 | + struct mtk_vcodec_mem work_bufs[VENC_H264_VPU_WORK_BUF_MAX]; | |
| 144 | + struct mtk_vcodec_mem pps_buf; | |
| 145 | + bool work_buf_allocated; | |
| 146 | + unsigned int frm_cnt; | |
| 147 | + unsigned int prepend_hdr; | |
| 148 | + struct venc_vpu_inst vpu_inst; | |
| 149 | + struct venc_h264_vsi *vsi; | |
| 150 | + struct mtk_vcodec_ctx *ctx; | |
| 151 | +}; | |
| 152 | + | |
| 153 | +static inline void h264_write_reg(struct venc_h264_inst *inst, u32 addr, | |
| 154 | + u32 val) | |
| 155 | +{ | |
| 156 | + writel(val, inst->hw_base + addr); | |
| 157 | +} | |
| 158 | + | |
| 159 | +static inline u32 h264_read_reg(struct venc_h264_inst *inst, u32 addr) | |
| 160 | +{ | |
| 161 | + return readl(inst->hw_base + addr); | |
| 162 | +} | |
| 163 | + | |
| 164 | +static unsigned int h264_get_profile(struct venc_h264_inst *inst, | |
| 165 | + unsigned int profile) | |
| 166 | +{ | |
| 167 | + switch (profile) { | |
| 168 | + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: | |
| 169 | + return 66; | |
| 170 | + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: | |
| 171 | + return 77; | |
| 172 | + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: | |
| 173 | + return 100; | |
| 174 | + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: | |
| 175 | + mtk_vcodec_err(inst, "unsupported CONSTRAINED_BASELINE"); | |
| 176 | + return 0; | |
| 177 | + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: | |
| 178 | + mtk_vcodec_err(inst, "unsupported EXTENDED"); | |
| 179 | + return 0; | |
| 180 | + default: | |
| 181 | + mtk_vcodec_debug(inst, "unsupported profile %d", profile); | |
| 182 | + return 100; | |
| 183 | + } | |
| 184 | +} | |
| 185 | + | |
| 186 | +static unsigned int h264_get_level(struct venc_h264_inst *inst, | |
| 187 | + unsigned int level) | |
| 188 | +{ | |
| 189 | + switch (level) { | |
| 190 | + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: | |
| 191 | + mtk_vcodec_err(inst, "unsupported 1B"); | |
| 192 | + return 0; | |
| 193 | + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: | |
| 194 | + return 10; | |
| 195 | + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: | |
| 196 | + return 11; | |
| 197 | + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: | |
| 198 | + return 12; | |
| 199 | + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: | |
| 200 | + return 13; | |
| 201 | + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: | |
| 202 | + return 20; | |
| 203 | + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: | |
| 204 | + return 21; | |
| 205 | + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: | |
| 206 | + return 22; | |
| 207 | + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: | |
| 208 | + return 30; | |
| 209 | + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: | |
| 210 | + return 31; | |
| 211 | + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: | |
| 212 | + return 32; | |
| 213 | + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: | |
| 214 | + return 40; | |
| 215 | + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: | |
| 216 | + return 41; | |
| 217 | + default: | |
| 218 | + mtk_vcodec_debug(inst, "unsupported level %d", level); | |
| 219 | + return 31; | |
| 220 | + } | |
| 221 | +} | |
| 222 | + | |
| 223 | +static void h264_enc_free_work_buf(struct venc_h264_inst *inst) | |
| 224 | +{ | |
| 225 | + int i; | |
| 226 | + | |
| 227 | + mtk_vcodec_debug_enter(inst); | |
| 228 | + | |
| 229 | + /* Except the SKIP_FRAME buffers, | |
| 230 | + * other buffers need to be freed by AP. | |
| 231 | + */ | |
| 232 | + for (i = 0; i < VENC_H264_VPU_WORK_BUF_MAX; i++) { | |
| 233 | + if (i != VENC_H264_VPU_WORK_BUF_SKIP_FRAME) | |
| 234 | + mtk_vcodec_mem_free(inst->ctx, &inst->work_bufs[i]); | |
| 235 | + } | |
| 236 | + | |
| 237 | + mtk_vcodec_mem_free(inst->ctx, &inst->pps_buf); | |
| 238 | + | |
| 239 | + mtk_vcodec_debug_leave(inst); | |
| 240 | +} | |
| 241 | + | |
| 242 | +static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst) | |
| 243 | +{ | |
| 244 | + int i; | |
| 245 | + int ret = 0; | |
| 246 | + struct venc_h264_vpu_buf *wb = inst->vsi->work_bufs; | |
| 247 | + | |
| 248 | + mtk_vcodec_debug_enter(inst); | |
| 249 | + | |
| 250 | + for (i = 0; i < VENC_H264_VPU_WORK_BUF_MAX; i++) { | |
| 251 | + /* | |
| 252 | + * This 'wb' structure is set by VPU side and shared to AP for | |
| 253 | + * buffer allocation and IO virtual addr mapping. For most of | |
| 254 | + * the buffers, AP will allocate the buffer according to 'size' | |
| 255 | + * field and store the IO virtual addr in 'iova' field. There | |
| 256 | + * are two exceptions: | |
| 257 | + * (1) RC_CODE buffer, it's pre-allocated in the VPU side, and | |
| 258 | + * save the VPU addr in the 'vpua' field. The AP will translate | |
| 259 | + * the VPU addr to the corresponding IO virtual addr and store | |
| 260 | + * in 'iova' field for reg setting in VPU side. | |
| 261 | + * (2) SKIP_FRAME buffer, it's pre-allocated in the VPU side, | |
| 262 | + * and save the VPU addr in the 'vpua' field. The AP will | |
| 263 | + * translate the VPU addr to the corresponding AP side virtual | |
| 264 | + * address and do some memcpy access to move to bitstream buffer | |
| 265 | + * assigned by v4l2 layer. | |
| 266 | + */ | |
| 267 | + inst->work_bufs[i].size = wb[i].size; | |
| 268 | + if (i == VENC_H264_VPU_WORK_BUF_SKIP_FRAME) { | |
| 269 | + inst->work_bufs[i].va = vpu_mapping_dm_addr( | |
| 270 | + inst->vpu_inst.dev, wb[i].vpua); | |
| 271 | + inst->work_bufs[i].dma_addr = 0; | |
| 272 | + } else { | |
| 273 | + ret = mtk_vcodec_mem_alloc(inst->ctx, | |
| 274 | + &inst->work_bufs[i]); | |
| 275 | + if (ret) { | |
| 276 | + mtk_vcodec_err(inst, | |
| 277 | + "cannot allocate buf %d", i); | |
| 278 | + goto err_alloc; | |
| 279 | + } | |
| 280 | + /* | |
| 281 | + * This RC_CODE is pre-allocated by VPU and saved in VPU | |
| 282 | + * addr. So we need use memcpy to copy RC_CODE from VPU | |
| 283 | + * addr into IO virtual addr in 'iova' field for reg | |
| 284 | + * setting in VPU side. | |
| 285 | + */ | |
| 286 | + if (i == VENC_H264_VPU_WORK_BUF_RC_CODE) { | |
| 287 | + void *tmp_va; | |
| 288 | + | |
| 289 | + tmp_va = vpu_mapping_dm_addr(inst->vpu_inst.dev, | |
| 290 | + wb[i].vpua); | |
| 291 | + memcpy(inst->work_bufs[i].va, tmp_va, | |
| 292 | + wb[i].size); | |
| 293 | + } | |
| 294 | + } | |
| 295 | + wb[i].iova = inst->work_bufs[i].dma_addr; | |
| 296 | + | |
| 297 | + mtk_vcodec_debug(inst, | |
| 298 | + "work_buf[%d] va=0x%p iova=%pad size=%zu", | |
| 299 | + i, inst->work_bufs[i].va, | |
| 300 | + &inst->work_bufs[i].dma_addr, | |
| 301 | + inst->work_bufs[i].size); | |
| 302 | + } | |
| 303 | + | |
| 304 | + /* the pps_buf is used by AP side only */ | |
| 305 | + inst->pps_buf.size = 128; | |
| 306 | + ret = mtk_vcodec_mem_alloc(inst->ctx, &inst->pps_buf); | |
| 307 | + if (ret) { | |
| 308 | + mtk_vcodec_err(inst, "cannot allocate pps_buf"); | |
| 309 | + goto err_alloc; | |
| 310 | + } | |
| 311 | + | |
| 312 | + mtk_vcodec_debug_leave(inst); | |
| 313 | + | |
| 314 | + return ret; | |
| 315 | + | |
| 316 | +err_alloc: | |
| 317 | + h264_enc_free_work_buf(inst); | |
| 318 | + | |
| 319 | + return ret; | |
| 320 | +} | |
| 321 | + | |
| 322 | +static unsigned int h264_enc_wait_venc_done(struct venc_h264_inst *inst) | |
| 323 | +{ | |
| 324 | + unsigned int irq_status = 0; | |
| 325 | + struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)inst->ctx; | |
| 326 | + | |
| 327 | + if (!mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED, | |
| 328 | + WAIT_INTR_TIMEOUT_MS)) { | |
| 329 | + irq_status = ctx->irq_status; | |
| 330 | + mtk_vcodec_debug(inst, "irq_status %x <-", irq_status); | |
| 331 | + } | |
| 332 | + return irq_status; | |
| 333 | +} | |
| 334 | + | |
| 335 | +static int h264_encode_sps(struct venc_h264_inst *inst, | |
| 336 | + struct mtk_vcodec_mem *bs_buf, | |
| 337 | + unsigned int *bs_size) | |
| 338 | +{ | |
| 339 | + int ret = 0; | |
| 340 | + unsigned int irq_status; | |
| 341 | + | |
| 342 | + mtk_vcodec_debug_enter(inst); | |
| 343 | + | |
| 344 | + ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_SPS, NULL, | |
| 345 | + bs_buf, bs_size); | |
| 346 | + if (ret) | |
| 347 | + return ret; | |
| 348 | + | |
| 349 | + irq_status = h264_enc_wait_venc_done(inst); | |
| 350 | + if (irq_status != MTK_VENC_IRQ_STATUS_SPS) { | |
| 351 | + mtk_vcodec_err(inst, "expect irq status %d", | |
| 352 | + MTK_VENC_IRQ_STATUS_SPS); | |
| 353 | + return -EINVAL; | |
| 354 | + } | |
| 355 | + | |
| 356 | + *bs_size = h264_read_reg(inst, VENC_PIC_BITSTREAM_BYTE_CNT); | |
| 357 | + mtk_vcodec_debug(inst, "bs size %d <-", *bs_size); | |
| 358 | + | |
| 359 | + return ret; | |
| 360 | +} | |
| 361 | + | |
| 362 | +static int h264_encode_pps(struct venc_h264_inst *inst, | |
| 363 | + struct mtk_vcodec_mem *bs_buf, | |
| 364 | + unsigned int *bs_size) | |
| 365 | +{ | |
| 366 | + int ret = 0; | |
| 367 | + unsigned int irq_status; | |
| 368 | + | |
| 369 | + mtk_vcodec_debug_enter(inst); | |
| 370 | + | |
| 371 | + ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_PPS, NULL, | |
| 372 | + bs_buf, bs_size); | |
| 373 | + if (ret) | |
| 374 | + return ret; | |
| 375 | + | |
| 376 | + irq_status = h264_enc_wait_venc_done(inst); | |
| 377 | + if (irq_status != MTK_VENC_IRQ_STATUS_PPS) { | |
| 378 | + mtk_vcodec_err(inst, "expect irq status %d", | |
| 379 | + MTK_VENC_IRQ_STATUS_PPS); | |
| 380 | + return -EINVAL; | |
| 381 | + } | |
| 382 | + | |
| 383 | + *bs_size = h264_read_reg(inst, VENC_PIC_BITSTREAM_BYTE_CNT); | |
| 384 | + mtk_vcodec_debug(inst, "bs size %d <-", *bs_size); | |
| 385 | + | |
| 386 | + return ret; | |
| 387 | +} | |
| 388 | + | |
| 389 | +static int h264_encode_header(struct venc_h264_inst *inst, | |
| 390 | + struct mtk_vcodec_mem *bs_buf, | |
| 391 | + unsigned int *bs_size) | |
| 392 | +{ | |
| 393 | + int ret = 0; | |
| 394 | + unsigned int bs_size_sps; | |
| 395 | + unsigned int bs_size_pps; | |
| 396 | + | |
| 397 | + ret = h264_encode_sps(inst, bs_buf, &bs_size_sps); | |
| 398 | + if (ret) | |
| 399 | + return ret; | |
| 400 | + | |
| 401 | + ret = h264_encode_pps(inst, &inst->pps_buf, &bs_size_pps); | |
| 402 | + if (ret) | |
| 403 | + return ret; | |
| 404 | + | |
| 405 | + memcpy(bs_buf->va + bs_size_sps, inst->pps_buf.va, bs_size_pps); | |
| 406 | + *bs_size = bs_size_sps + bs_size_pps; | |
| 407 | + | |
| 408 | + return ret; | |
| 409 | +} | |
| 410 | + | |
| 411 | +static int h264_encode_frame(struct venc_h264_inst *inst, | |
| 412 | + struct venc_frm_buf *frm_buf, | |
| 413 | + struct mtk_vcodec_mem *bs_buf, | |
| 414 | + unsigned int *bs_size) | |
| 415 | +{ | |
| 416 | + int ret = 0; | |
| 417 | + unsigned int irq_status; | |
| 418 | + | |
| 419 | + mtk_vcodec_debug_enter(inst); | |
| 420 | + | |
| 421 | + ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_FRAME, frm_buf, | |
| 422 | + bs_buf, bs_size); | |
| 423 | + if (ret) | |
| 424 | + return ret; | |
| 425 | + | |
| 426 | + /* | |
| 427 | + * skip frame case: The skip frame buffer is composed by vpu side only, | |
| 428 | + * it does not trigger the hw, so skip the wait interrupt operation. | |
| 429 | + */ | |
| 430 | + if (inst->vpu_inst.state == VEN_IPI_MSG_ENC_STATE_SKIP) { | |
| 431 | + *bs_size = inst->vpu_inst.bs_size; | |
| 432 | + memcpy(bs_buf->va, | |
| 433 | + inst->work_bufs[VENC_H264_VPU_WORK_BUF_SKIP_FRAME].va, | |
| 434 | + *bs_size); | |
| 435 | + ++inst->frm_cnt; | |
| 436 | + return ret; | |
| 437 | + } | |
| 438 | + | |
| 439 | + irq_status = h264_enc_wait_venc_done(inst); | |
| 440 | + if (irq_status != MTK_VENC_IRQ_STATUS_FRM) { | |
| 441 | + mtk_vcodec_err(inst, "irq_status=%d failed", irq_status); | |
| 442 | + return -EIO; | |
| 443 | + } | |
| 444 | + | |
| 445 | + *bs_size = h264_read_reg(inst, VENC_PIC_BITSTREAM_BYTE_CNT); | |
| 446 | + | |
| 447 | + ++inst->frm_cnt; | |
| 448 | + mtk_vcodec_debug(inst, "frm %d bs_size %d key_frm %d <-", | |
| 449 | + inst->frm_cnt, *bs_size, inst->vpu_inst.is_key_frm); | |
| 450 | + | |
| 451 | + return ret; | |
| 452 | +} | |
| 453 | + | |
| 454 | +static void h264_encode_filler(struct venc_h264_inst *inst, void *buf, | |
| 455 | + int size) | |
| 456 | +{ | |
| 457 | + unsigned char *p = buf; | |
| 458 | + | |
| 459 | + if (size < H264_FILLER_MARKER_SIZE) { | |
| 460 | + mtk_vcodec_err(inst, "filler size too small %d", size); | |
| 461 | + return; | |
| 462 | + } | |
| 463 | + | |
| 464 | + memcpy(p, h264_filler_marker, ARRAY_SIZE(h264_filler_marker)); | |
| 465 | + size -= H264_FILLER_MARKER_SIZE; | |
| 466 | + p += H264_FILLER_MARKER_SIZE; | |
| 467 | + memset(p, 0xff, size); | |
| 468 | +} | |
| 469 | + | |
| 470 | +static int h264_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle) | |
| 471 | +{ | |
| 472 | + int ret = 0; | |
| 473 | + struct venc_h264_inst *inst; | |
| 474 | + | |
| 475 | + inst = kzalloc(sizeof(*inst), GFP_KERNEL); | |
| 476 | + if (!inst) | |
| 477 | + return -ENOMEM; | |
| 478 | + | |
| 479 | + inst->ctx = ctx; | |
| 480 | + inst->vpu_inst.ctx = ctx; | |
| 481 | + inst->vpu_inst.dev = ctx->dev->vpu_plat_dev; | |
| 482 | + inst->vpu_inst.id = IPI_VENC_H264; | |
| 483 | + inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_SYS); | |
| 484 | + | |
| 485 | + mtk_vcodec_debug_enter(inst); | |
| 486 | + | |
| 487 | + ret = vpu_enc_init(&inst->vpu_inst); | |
| 488 | + | |
| 489 | + inst->vsi = (struct venc_h264_vsi *)inst->vpu_inst.vsi; | |
| 490 | + | |
| 491 | + mtk_vcodec_debug_leave(inst); | |
| 492 | + | |
| 493 | + if (ret) | |
| 494 | + kfree(inst); | |
| 495 | + else | |
| 496 | + (*handle) = (unsigned long)inst; | |
| 497 | + | |
| 498 | + return ret; | |
| 499 | +} | |
| 500 | + | |
| 501 | +static int h264_enc_encode(unsigned long handle, | |
| 502 | + enum venc_start_opt opt, | |
| 503 | + struct venc_frm_buf *frm_buf, | |
| 504 | + struct mtk_vcodec_mem *bs_buf, | |
| 505 | + struct venc_done_result *result) | |
| 506 | +{ | |
| 507 | + int ret = 0; | |
| 508 | + struct venc_h264_inst *inst = (struct venc_h264_inst *)handle; | |
| 509 | + struct mtk_vcodec_ctx *ctx = inst->ctx; | |
170 more lines aren’t shown here.
This diff is large: its 487 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 114 lines aren’t shown here.
This diff is large: its 164 lines aren’t shown here.
This diff is large: its 211 lines aren’t shown here.
This diff is large: its 239 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 947 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 207 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 182 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 335 lines aren’t shown here.
This diff is large: its 1188 lines aren’t shown here.
This diff is large: its 875 lines aren’t shown here.
This diff is large: its 164 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 339 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 318 lines aren’t shown here.
This diff is large: its 312 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 242 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 231 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 293 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 413 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 174 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 143 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 229 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 183 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 589 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 263 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 821 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 122 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 205 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 151 lines aren’t shown here.
This diff is large: its 149 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 158 lines aren’t shown here.
This diff is large: its 163 lines aren’t shown here.
This diff is large: its 155 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 202 lines aren’t shown here.
This diff is large: its 131 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 125 lines aren’t shown here.
This diff is large: its 154 lines aren’t shown here.
This diff is large: its 114 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 1655 lines aren’t shown here.
This diff is large: its 580 lines aren’t shown here.
This diff is large: its 410 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 1637 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 1265 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 1703 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 506 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 210 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 295 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 871 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 1900 lines aren’t shown here.
This diff is large: its 1012 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 242 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.