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 | !Iinclude/media/media-devnode.h | 300 | !Iinclude/media/media-devnode.h |
| 301 | !Iinclude/media/media-entity.h | 301 | !Iinclude/media/media-entity.h |
| 302 | </sect1> | 302 | </sect1> |
| 303 | <sect1><title>Consumer Electronics Control devices</title> | ||
| 304 | !Iinclude/media/cec-edid.h | ||
| 305 | </sect1> | ||
| 303 | 306 | ||
| 304 | </chapter> | 307 | </chapter> |
| 305 | 308 | ||
| @@ -64,6 +64,7 @@ IOCTLS = \ · 63 unmodified lines | |||
| 64 | $(shell perl -ne 'print "$$1 " if /\#define\s+([A-Z][^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/net.h) \ | 64 | $(shell perl -ne 'print "$$1 " if /\#define\s+([A-Z][^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/net.h) \ |
| 65 | $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/video.h) \ | 65 | $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/video.h) \ |
| 66 | $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/media.h) \ | 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 | $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \ | 68 | $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \ |
| 68 | 69 | ||
| 69 | DEFINES = \ | 70 | DEFINES = \ |
| @@ -100,6 +101,7 @@ STRUCTS = \ · 30 unmodified lines | |||
| 100 | $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/ && !/_old/)' $(srctree)/include/uapi/linux/dvb/net.h) \ | 101 | $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/ && !/_old/)' $(srctree)/include/uapi/linux/dvb/net.h) \ |
| 101 | $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/video.h) \ | 102 | $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/video.h) \ |
| 102 | $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/media.h) \ | 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 | $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \ | 105 | $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \ |
| 104 | $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-mediabus.h) | 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 | <subtitle>Specification Version 1.4a</subtitle> | 342 | <subtitle>Specification Version 1.4a</subtitle> |
| 343 | </biblioentry> | 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 | <biblioentry id="dp"> | 355 | <biblioentry id="dp"> |
| 346 | <abbrev>DP</abbrev> | 356 | <abbrev>DP</abbrev> |
| 347 | <authorgroup> | 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 | <structfield>capabilities</structfield> field of &v4l2-capability; | 88 | <structfield>capabilities</structfield> field of &v4l2-capability; |
| 89 | returned by the &VIDIOC-QUERYCAP; ioctl is set. There are two | 89 | returned by the &VIDIOC-QUERYCAP; ioctl is set. There are two |
| 90 | streaming methods, to determine if the memory mapping flavor is | 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 | <para>Streaming is an I/O method where only pointers to buffers | 93 | <para>Streaming is an I/O method where only pointers to buffers |
| 94 | are exchanged between application and driver, the data itself is not | 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 | <structfield>capabilities</structfield> field of &v4l2-capability; | 369 | <structfield>capabilities</structfield> field of &v4l2-capability; |
| 370 | returned by the &VIDIOC-QUERYCAP; ioctl is set. If the particular user | 370 | returned by the &VIDIOC-QUERYCAP; ioctl is set. If the particular user |
| 371 | pointer method (not only memory mapping) is supported must be | 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 | <para>This I/O method combines advantages of the read/write and | 374 | <para>This I/O method combines advantages of the read/write and |
| 375 | memory mapping methods. Buffers (planes) are allocated by the application | 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 | <varlistentry> | 157 | <varlistentry> |
| 158 | <term>LIRC_SET_{SEND,REC}_CARRIER</term> | 158 | <term>LIRC_SET_{SEND,REC}_CARRIER</term> |
| 159 | <listitem> | 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 | </listitem> | 161 | </listitem> |
| 162 | </varlistentry> | 162 | </varlistentry> |
| 163 | <varlistentry> | 163 | <varlistentry> |
| @@ -121,6 +121,70 @@ · 120 unmodified lines | |||
| 121 | <entry><constant>MEDIA_ENT_F_AUDIO_MIXER</constant></entry> | 121 | <entry><constant>MEDIA_ENT_F_AUDIO_MIXER</constant></entry> |
| 122 | <entry>Audio Mixer Function Entity.</entry> | 122 | <entry>Audio Mixer Function Entity.</entry> |
| 123 | </row> | 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 | </tbody> | 188 | </tbody> |
| 125 | </tgroup> | 189 | </tgroup> |
| 126 | </table> | 190 | </table> |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | |||
| 5 | </refmeta> | 5 | </refmeta> |
| 6 | <refnamediv> | 6 | <refnamediv> |
| 7 | <refname><constant>V4L2_PIX_FMT_Z16</constant></refname> | 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 | </refnamediv> | 9 | </refnamediv> |
| 10 | <refsect1> | 10 | <refsect1> |
| 11 | <title>Description</title> | 11 | <title>Description</title> |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | |||
| 6 | 6 | ||
| 7 | <refnamediv> | 7 | <refnamediv> |
| 8 | <refname>VIDIOC_REQBUFS</refname> | 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 | </refnamediv> | 10 | </refnamediv> |
| 11 | 11 | ||
| 12 | <refsynopsisdiv> | 12 | <refsynopsisdiv> |
| @@ -75,7 +75,7 @@ · 74 unmodified lines | |||
| 75 | </mediaobject> | 75 | </mediaobject> |
| 76 | </figure> | 76 | </figure> |
| 77 | <para>The media infrastructure API was designed to control such | 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 | <para>The first part covers radio, video capture and output, | 79 | <para>The first part covers radio, video capture and output, |
| 80 | cameras, analog TV devices and codecs.</para> | 80 | cameras, analog TV devices and codecs.</para> |
| 81 | <para>The second part covers the | 81 | <para>The second part covers the |
| @@ -87,6 +87,7 @@ · 5 unmodified lines | |||
| 87 | <xref linkend="fe-delivery-system-t" />.</para> | 87 | <xref linkend="fe-delivery-system-t" />.</para> |
| 88 | <para>The third part covers the Remote Controller API.</para> | 88 | <para>The third part covers the Remote Controller API.</para> |
| 89 | <para>The fourth part covers the Media Controller API.</para> | 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 | <para>It should also be noted that a media device may also have audio | 91 | <para>It should also be noted that a media device may also have audio |
| 91 | components, like mixers, PCM capture, PCM playback, etc, which | 92 | components, like mixers, PCM capture, PCM playback, etc, which |
| 92 | are controlled via ALSA API.</para> | 93 | are controlled via ALSA API.</para> |
| @@ -107,6 +108,9 @@ · 14 unmodified lines | |||
| 107 | <part id="media_common"> | 108 | <part id="media_common"> |
| 108 | &sub-media-controller; | 109 | &sub-media-controller; |
| 109 | </part> | 110 | </part> |
| 111 | <part id="cec"> | ||
| 112 | &sub-cec-api; | ||
| 113 | </part> | ||
| 110 | 114 | ||
| 111 | <chapter id="gen_errors"> | 115 | <chapter id="gen_errors"> |
| 112 | &sub-gen-errors; | 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 | - interrupts: VSP interrupt specifier. | 14 | - interrupts: VSP interrupt specifier. |
| 15 | - clocks: A phandle + clock-specifier pair for the VSP functional clock. | 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 | Example: R8A7790 (R-Car H2) VSP1-S node | 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 | - clock-names : from common clock binding: must contain "mfc", | 21 | - clock-names : from common clock binding: must contain "mfc", |
| 22 | corresponding to entry in the clocks property. | 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 | Optional properties: | 24 | Optional properties: |
| 31 | - power-domains : power-domain property defined with a phandle | 25 | - power-domains : power-domain property defined with a phandle |
| 32 | to respective power domain. | 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 | Example: | 37 | Example: |
| 35 | SoC specific DT entry: | 38 | SoC specific DT entry: |
| @@ -43,9 +46,29 @@ mfc: codec@13400000 { · 7 unmodified lines | |||
| 43 | clock-names = "mfc"; | 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 | Board specific DT entry: | 70 | Board specific DT entry: |
| 47 | 71 | ||
| 48 | codec@13400000 { | 72 | codec@13400000 { |
| 49 | samsung,mfc-r = <0x43000000 0x800000>; | 73 | memory-region = <&mfc_left>, <&mfc_right>; |
| 50 | samsung,mfc-l = <0x51000000 0x800000>; | ||
| 51 | }; | 74 | }; |
| @@ -54,3 +54,4 @@ · 53 unmodified lines | |||
| 54 | 53 -> Hauppauge WinTV Starburst [0070:c12a] | 54 | 53 -> Hauppauge WinTV Starburst [0070:c12a] |
| 55 | 54 -> ViewCast 260e [1576:0260] | 55 | 54 -> ViewCast 260e [1576:0260] |
| 56 | 55 -> ViewCast 460e [1576:0460] | 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 | Where foo->sd is of type struct v4l2_subdev. | 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 | 1.4) Clean up the handler at the end: | 99 | 1.4) Clean up the handler at the end: |
| 115 | 100 | ||
| 116 | v4l2_ctrl_handler_free(&foo->ctrl_handler); | 101 | v4l2_ctrl_handler_free(&foo->ctrl_handler); |
| @@ -74,7 +74,8 @@ Section 11: Cropping, Composing, Scaling · 73 unmodified lines | |||
| 74 | Section 12: Formats | 74 | Section 12: Formats |
| 75 | Section 13: Capture Overlay | 75 | Section 13: Capture Overlay |
| 76 | Section 14: Output Overlay | 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 | Section 1: Configuring the driver | 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 | is provided. You can only set the EDID for HDMI inputs. Internally, however, | 365 | is provided. You can only set the EDID for HDMI inputs. Internally, however, |
| 365 | the EDID is shared between all HDMI inputs. | 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 | Section 3: Video Output | 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 | An HDMI output has a valid EDID which can be obtained through VIDIOC_G_EDID. | 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 | Section 4: VBI Capture | 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 | to be done per pixel. | 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 | Just as a reminder and in no particular order: | 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 | - Fix sequence/field numbering when looping of video with alternate fields | 1148 | - Fix sequence/field numbering when looping of video with alternate fields |
| 1122 | - Add support for V4L2_CID_BG_COLOR for video outputs | 1149 | - Add support for V4L2_CID_BG_COLOR for video outputs |
| 1123 | - Add ARGB888 overlay support: better testing of the alpha channel | 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 | - Improve pixel aspect support in the tpg code by passing a real v4l2_fract | 1151 | - Improve pixel aspect support in the tpg code by passing a real v4l2_fract |
| 1127 | - Use per-queue locks and/or per-device locks to improve throughput | 1152 | - Use per-queue locks and/or per-device locks to improve throughput |
| 1128 | - Add support to loop from a specific output to a specific input across | 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 | - Make a thread for the RDS generation, that would help in particular for the | 1158 | - Make a thread for the RDS generation, that would help in particular for the |
| 1134 | "Controls" RDS Rx I/O Mode as the read-only RDS controls could be updated | 1159 | "Controls" RDS Rx I/O Mode as the read-only RDS controls could be updated |
| 1135 | in real-time. | 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 | S: Maintained | 1648 | S: Maintained |
| 1649 | F: drivers/media/platform/s5p-tv/ | 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 | ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT | 1658 | ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT |
| 1652 | M: Andrzej Pietrasiewicz <andrzej.p@samsung.com> | 1659 | M: Andrzej Pietrasiewicz <andrzej.p@samsung.com> |
| 1653 | M: Jacek Anaszewski <j.anaszewski@samsung.com> | 1660 | M: Jacek Anaszewski <j.anaszewski@samsung.com> |
| @@ -2851,6 +2858,22 @@ F: drivers/net/ieee802154/cc2520.c · 1197 unmodified lines | |||
| 2851 | F: include/linux/spi/cc2520.h | 2858 | F: include/linux/spi/cc2520.h |
| 2852 | F: Documentation/devicetree/bindings/net/ieee802154/cc2520.txt | 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 | CELL BROADBAND ENGINE ARCHITECTURE | 2877 | CELL BROADBAND ENGINE ARCHITECTURE |
| 2855 | M: Arnd Bergmann <arnd@arndb.de> | 2878 | M: Arnd Bergmann <arnd@arndb.de> |
| 2856 | L: linuxppc-dev@lists.ozlabs.org | 2879 | L: linuxppc-dev@lists.ozlabs.org |
| @@ -5177,10 +5200,10 @@ S: Maintained · 2320 unmodified lines | |||
| 5177 | F: drivers/media/usb/gspca/m5602/ | 5200 | F: drivers/media/usb/gspca/m5602/ |
| 5178 | 5201 | ||
| 5179 | GSPCA PAC207 SONIXB SUBDRIVER | 5202 | GSPCA PAC207 SONIXB SUBDRIVER |
| 5180 | M: Hans de Goede <hdegoede@redhat.com> | 5203 | M: Hans Verkuil <hverkuil@xs4all.nl> |
| 5181 | L: linux-media@vger.kernel.org | 5204 | L: linux-media@vger.kernel.org |
| 5182 | T: git git://linuxtv.org/media_tree.git | 5205 | T: git git://linuxtv.org/media_tree.git |
| 5183 | S: Maintained | 5206 | S: Odd Fixes |
| 5184 | F: drivers/media/usb/gspca/pac207.c | 5207 | F: drivers/media/usb/gspca/pac207.c |
| 5185 | 5208 | ||
| 5186 | GSPCA SN9C20X SUBDRIVER | 5209 | GSPCA SN9C20X SUBDRIVER |
| @@ -5198,10 +5221,10 @@ S: Maintained · 11 unmodified lines | |||
| 5198 | F: drivers/media/usb/gspca/t613.c | 5221 | F: drivers/media/usb/gspca/t613.c |
| 5199 | 5222 | ||
| 5200 | GSPCA USB WEBCAM DRIVER | 5223 | GSPCA USB WEBCAM DRIVER |
| 5201 | M: Hans de Goede <hdegoede@redhat.com> | 5224 | M: Hans Verkuil <hverkuil@xs4all.nl> |
| 5202 | L: linux-media@vger.kernel.org | 5225 | L: linux-media@vger.kernel.org |
| 5203 | T: git git://linuxtv.org/media_tree.git | 5226 | T: git git://linuxtv.org/media_tree.git |
| 5204 | S: Maintained | 5227 | S: Odd Fixes |
| 5205 | F: drivers/media/usb/gspca/ | 5228 | F: drivers/media/usb/gspca/ |
| 5206 | 5229 | ||
| 5207 | GUID PARTITION TABLE (GPT) | 5230 | GUID PARTITION TABLE (GPT) |
| @@ -7344,6 +7367,16 @@ L: linux-iio@vger.kernel.org · 2136 unmodified lines | |||
| 7344 | S: Maintained | 7367 | S: Maintained |
| 7345 | F: drivers/iio/potentiometer/mcp4531.c | 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 | MEDIA DRIVERS FOR RENESAS - VSP1 | 7380 | MEDIA DRIVERS FOR RENESAS - VSP1 |
| 7348 | M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 7381 | M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| 7349 | L: linux-media@vger.kernel.org | 7382 | L: linux-media@vger.kernel.org |
| @@ -7353,8 +7386,18 @@ S: Supported · 3 unmodified lines | |||
| 7353 | F: Documentation/devicetree/bindings/media/renesas,vsp1.txt | 7386 | F: Documentation/devicetree/bindings/media/renesas,vsp1.txt |
| 7354 | F: drivers/media/platform/vsp1/ | 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 | MEDIA DRIVERS FOR ASCOT2E | 7398 | MEDIA DRIVERS FOR ASCOT2E |
| 7357 | M: Sergey Kozlov <serjk@netup.ru> | 7399 | M: Sergey Kozlov <serjk@netup.ru> |
| 7400 | M: Abylay Ospan <aospan@netup.ru> | ||
| 7358 | L: linux-media@vger.kernel.org | 7401 | L: linux-media@vger.kernel.org |
| 7359 | W: https://linuxtv.org | 7402 | W: https://linuxtv.org |
| 7360 | W: http://netup.tv/ | 7403 | W: http://netup.tv/ |
| @@ -7364,6 +7407,7 @@ F: drivers/media/dvb-frontends/ascot2e* · 3 unmodified lines | |||
| 7364 | 7407 | ||
| 7365 | MEDIA DRIVERS FOR CXD2841ER | 7408 | MEDIA DRIVERS FOR CXD2841ER |
| 7366 | M: Sergey Kozlov <serjk@netup.ru> | 7409 | M: Sergey Kozlov <serjk@netup.ru> |
| 7410 | M: Abylay Ospan <aospan@netup.ru> | ||
| 7367 | L: linux-media@vger.kernel.org | 7411 | L: linux-media@vger.kernel.org |
| 7368 | W: https://linuxtv.org | 7412 | W: https://linuxtv.org |
| 7369 | W: http://netup.tv/ | 7413 | W: http://netup.tv/ |
| @@ -7373,6 +7417,7 @@ F: drivers/media/dvb-frontends/cxd2841er* · 3 unmodified lines | |||
| 7373 | 7417 | ||
| 7374 | MEDIA DRIVERS FOR HORUS3A | 7418 | MEDIA DRIVERS FOR HORUS3A |
| 7375 | M: Sergey Kozlov <serjk@netup.ru> | 7419 | M: Sergey Kozlov <serjk@netup.ru> |
| 7420 | M: Abylay Ospan <aospan@netup.ru> | ||
| 7376 | L: linux-media@vger.kernel.org | 7421 | L: linux-media@vger.kernel.org |
| 7377 | W: https://linuxtv.org | 7422 | W: https://linuxtv.org |
| 7378 | W: http://netup.tv/ | 7423 | W: http://netup.tv/ |
| @@ -7382,6 +7427,7 @@ F: drivers/media/dvb-frontends/horus3a* · 3 unmodified lines | |||
| 7382 | 7427 | ||
| 7383 | MEDIA DRIVERS FOR LNBH25 | 7428 | MEDIA DRIVERS FOR LNBH25 |
| 7384 | M: Sergey Kozlov <serjk@netup.ru> | 7429 | M: Sergey Kozlov <serjk@netup.ru> |
| 7430 | M: Abylay Ospan <aospan@netup.ru> | ||
| 7385 | L: linux-media@vger.kernel.org | 7431 | L: linux-media@vger.kernel.org |
| 7386 | W: https://linuxtv.org | 7432 | W: https://linuxtv.org |
| 7387 | W: http://netup.tv/ | 7433 | W: http://netup.tv/ |
| @@ -7391,6 +7437,7 @@ F: drivers/media/dvb-frontends/lnbh25* · 3 unmodified lines | |||
| 7391 | 7437 | ||
| 7392 | MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices | 7438 | MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices |
| 7393 | M: Sergey Kozlov <serjk@netup.ru> | 7439 | M: Sergey Kozlov <serjk@netup.ru> |
| 7440 | M: Abylay Ospan <aospan@netup.ru> | ||
| 7394 | L: linux-media@vger.kernel.org | 7441 | L: linux-media@vger.kernel.org |
| 7395 | W: https://linuxtv.org | 7442 | W: https://linuxtv.org |
| 7396 | W: http://netup.tv/ | 7443 | W: http://netup.tv/ |
| @@ -7640,10 +7687,8 @@ L: linux-media@vger.kernel.org · 243 unmodified lines | |||
| 7640 | W: https://linuxtv.org | 7687 | W: https://linuxtv.org |
| 7641 | W: http://palosaari.fi/linux/ | 7688 | W: http://palosaari.fi/linux/ |
| 7642 | Q: http://patchwork.linuxtv.org/project/linux-media/list/ | 7689 | Q: http://patchwork.linuxtv.org/project/linux-media/list/ |
| 7643 | T: git git://linuxtv.org/anttip/media_tree.git | ||
| 7644 | S: Maintained | 7690 | S: Maintained |
| 7645 | F: drivers/staging/media/mn88472/ | 7691 | F: drivers/media/dvb-frontends/mn88472* |
| 7646 | F: drivers/media/dvb-frontends/mn88472.h | ||
| 7647 | 7692 | ||
| 7648 | MN88473 MEDIA DRIVER | 7693 | MN88473 MEDIA DRIVER |
| 7649 | M: Antti Palosaari <crope@iki.fi> | 7694 | M: Antti Palosaari <crope@iki.fi> |
| @@ -9255,6 +9300,13 @@ F: include/linux/tracehook.h · 1605 unmodified lines | |||
| 9255 | F: include/uapi/linux/ptrace.h | 9300 | F: include/uapi/linux/ptrace.h |
| 9256 | F: kernel/ptrace.c | 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 | PVRUSB2 VIDEO4LINUX DRIVER | 9310 | PVRUSB2 VIDEO4LINUX DRIVER |
| 9259 | M: Mike Isely <isely@pobox.com> | 9311 | M: Mike Isely <isely@pobox.com> |
| 9260 | L: pvrusb2@isely.net (subscribers-only) | 9312 | L: pvrusb2@isely.net (subscribers-only) |
| @@ -9266,10 +9318,10 @@ F: Documentation/video4linux/README.pvrusb2 · 5 unmodified lines | |||
| 9266 | F: drivers/media/usb/pvrusb2/ | 9318 | F: drivers/media/usb/pvrusb2/ |
| 9267 | 9319 | ||
| 9268 | PWC WEBCAM DRIVER | 9320 | PWC WEBCAM DRIVER |
| 9269 | M: Hans de Goede <hdegoede@redhat.com> | 9321 | M: Hans Verkuil <hverkuil@xs4all.nl> |
| 9270 | L: linux-media@vger.kernel.org | 9322 | L: linux-media@vger.kernel.org |
| 9271 | T: git git://linuxtv.org/media_tree.git | 9323 | T: git git://linuxtv.org/media_tree.git |
| 9272 | S: Maintained | 9324 | S: Odd Fixes |
| 9273 | F: drivers/media/usb/pwc/* | 9325 | F: drivers/media/usb/pwc/* |
| 9274 | 9326 | ||
| 9275 | PWM FAN DRIVER | 9327 | PWM FAN DRIVER |
| @@ -9485,14 +9537,14 @@ F: drivers/video/fbdev/aty/radeon* · 209 unmodified lines | |||
| 9485 | F: include/uapi/linux/radeonfb.h | 9537 | F: include/uapi/linux/radeonfb.h |
| 9486 | 9538 | ||
| 9487 | RADIOSHARK RADIO DRIVER | 9539 | RADIOSHARK RADIO DRIVER |
| 9488 | M: Hans de Goede <hdegoede@redhat.com> | 9540 | M: Hans Verkuil <hverkuil@xs4all.nl> |
| 9489 | L: linux-media@vger.kernel.org | 9541 | L: linux-media@vger.kernel.org |
| 9490 | T: git git://linuxtv.org/media_tree.git | 9542 | T: git git://linuxtv.org/media_tree.git |
| 9491 | S: Maintained | 9543 | S: Maintained |
| 9492 | F: drivers/media/radio/radio-shark.c | 9544 | F: drivers/media/radio/radio-shark.c |
| 9493 | 9545 | ||
| 9494 | RADIOSHARK2 RADIO DRIVER | 9546 | RADIOSHARK2 RADIO DRIVER |
| 9495 | M: Hans de Goede <hdegoede@redhat.com> | 9547 | M: Hans Verkuil <hverkuil@xs4all.nl> |
| 9496 | L: linux-media@vger.kernel.org | 9548 | L: linux-media@vger.kernel.org |
| 9497 | T: git git://linuxtv.org/media_tree.git | 9549 | T: git git://linuxtv.org/media_tree.git |
| 9498 | S: Maintained | 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 | timer { | 183 | timer { |
| 172 | compatible = "arm,armv8-timer"; | 184 | compatible = "arm,armv8-timer"; |
| 173 | interrupt-parent = <&gic>; | 185 | interrupt-parent = <&gic>; |
| @@ -312,6 +324,17 @@ · 138 unmodified lines | |||
| 312 | clock-names = "spi", "wrap"; | 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 | sysirq: intpol-controller@10200620 { | 338 | sysirq: intpol-controller@10200620 { |
| 316 | compatible = "mediatek,mt8173-sysirq", | 339 | compatible = "mediatek,mt8173-sysirq", |
| 317 | "mediatek,mt6577-sysirq"; | 340 | "mediatek,mt6577-sysirq"; |
| @@ -754,6 +777,45 @@ · 436 unmodified lines | |||
| 754 | clock-names = "apb", "smi"; | 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 | vencltsys: clock-controller@19000000 { | 819 | vencltsys: clock-controller@19000000 { |
| 758 | compatible = "mediatek,mt8173-vencltsys", "syscon"; | 820 | compatible = "mediatek,mt8173-vencltsys", "syscon"; |
| 759 | reg = <0 0x19000000 0 0x1000>; | 821 | reg = <0 0x19000000 0 0x1000>; |
| @@ -1002,14 +1002,12 @@ static struct adv7842_output_format adv7842_opf[] = { · 1001 unmodified lines | |||
| 1002 | { | 1002 | { |
| 1003 | .op_ch_sel = ADV7842_OP_CH_SEL_BRG, | 1003 | .op_ch_sel = ADV7842_OP_CH_SEL_BRG, |
| 1004 | .op_format_sel = ADV7842_OP_FORMAT_SEL_SDR_ITU656_8, | 1004 | .op_format_sel = ADV7842_OP_FORMAT_SEL_SDR_ITU656_8, |
| 1005 | .op_656_range = 1, | ||
| 1006 | .blank_data = 1, | 1005 | .blank_data = 1, |
| 1007 | .insert_av_codes = 1, | 1006 | .insert_av_codes = 1, |
| 1008 | }, | 1007 | }, |
| 1009 | { | 1008 | { |
| 1010 | .op_ch_sel = ADV7842_OP_CH_SEL_RGB, | 1009 | .op_ch_sel = ADV7842_OP_CH_SEL_RGB, |
| 1011 | .op_format_sel = ADV7842_OP_FORMAT_SEL_SDR_ITU656_16, | 1010 | .op_format_sel = ADV7842_OP_FORMAT_SEL_SDR_ITU656_16, |
| 1012 | .op_656_range = 1, | ||
| 1013 | .blank_data = 1, | 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 | struct rcar_du_vsp_plane_state *state = | 148 | struct rcar_du_vsp_plane_state *state = |
| 149 | to_rcar_vsp_plane_state(plane->plane.state); | 149 | to_rcar_vsp_plane_state(plane->plane.state); |
| 150 | struct drm_framebuffer *fb = plane->plane.state->fb; | 150 | struct drm_framebuffer *fb = plane->plane.state->fb; |
| 151 | struct v4l2_rect src; | 151 | struct vsp1_du_atomic_config cfg = { |
| 152 | struct v4l2_rect dst; | 152 | .pixelformat = 0, |
| 153 | dma_addr_t paddr[2] = { 0, }; | 153 | .pitch = fb->pitches[0], |
| 154 | u32 pixelformat = 0; | 154 | .alpha = state->alpha, |
| 155 | .zpos = state->zpos, | ||
| 156 | }; | ||
| 155 | unsigned int i; | 157 | unsigned int i; |
| 156 | 158 | ||
| 157 | src.left = state->state.src_x >> 16; | 159 | cfg.src.left = state->state.src_x >> 16; |
| 158 | src.top = state->state.src_y >> 16; | 160 | cfg.src.top = state->state.src_y >> 16; |
| 159 | src.width = state->state.src_w >> 16; | 161 | cfg.src.width = state->state.src_w >> 16; |
| 160 | src.height = state->state.src_h >> 16; | 162 | cfg.src.height = state->state.src_h >> 16; |
| 161 | 163 | ||
| 162 | dst.left = state->state.crtc_x; | 164 | cfg.dst.left = state->state.crtc_x; |
| 163 | dst.top = state->state.crtc_y; | 165 | cfg.dst.top = state->state.crtc_y; |
| 164 | dst.width = state->state.crtc_w; | 166 | cfg.dst.width = state->state.crtc_w; |
| 165 | dst.height = state->state.crtc_h; | 167 | cfg.dst.height = state->state.crtc_h; |
| 166 | 168 | ||
| 167 | for (i = 0; i < state->format->planes; ++i) { | 169 | for (i = 0; i < state->format->planes; ++i) { |
| 168 | struct drm_gem_cma_object *gem; | 170 | struct drm_gem_cma_object *gem; |
| 169 | 171 | ||
| 170 | gem = drm_fb_cma_get_gem_obj(fb, i); | 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 | for (i = 0; i < ARRAY_SIZE(formats_kms); ++i) { | 176 | for (i = 0; i < ARRAY_SIZE(formats_kms); ++i) { |
| 175 | if (formats_kms[i] == state->format->fourcc) { | 177 | if (formats_kms[i] == state->format->fourcc) { |
| 176 | pixelformat = formats_v4l2[i]; | 178 | cfg.pixelformat = formats_v4l2[i]; |
| 177 | break; | 179 | break; |
| 178 | } | 180 | } |
| 179 | } | 181 | } |
| 180 | 182 | ||
| 181 | WARN_ON(!pixelformat); | 183 | vsp1_du_atomic_update(plane->vsp->vsp, plane->index, &cfg); |
| 182 | |||
| 183 | vsp1_du_atomic_update(plane->vsp->vsp, plane->index, pixelformat, | ||
| 184 | fb->pitches[0], paddr, &src, &dst); | ||
| 185 | } | 184 | } |
| 186 | 185 | ||
| 187 | static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane, | 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 | if (plane->state->crtc) | 219 | if (plane->state->crtc) |
| 221 | rcar_du_vsp_plane_setup(rplane); | 220 | rcar_du_vsp_plane_setup(rplane); |
| 222 | else | 221 | else |
| 223 | vsp1_du_atomic_update(rplane->vsp->vsp, rplane->index, 0, 0, 0, | 222 | vsp1_du_atomic_update(rplane->vsp->vsp, rplane->index, NULL); |
| 224 | NULL, NULL); | ||
| 225 | } | 223 | } |
| 226 | 224 | ||
| 227 | static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = { | 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 | return; | 267 | return; |
| 270 | 268 | ||
| 271 | state->alpha = 255; | 269 | state->alpha = 255; |
| 270 | state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1; | ||
| 272 | 271 | ||
| 273 | plane->state = &state->state; | 272 | plane->state = &state->state; |
| 274 | plane->state->plane = plane; | 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 | if (property == rcdu->props.alpha) | 283 | if (property == rcdu->props.alpha) |
| 285 | rstate->alpha = val; | 284 | rstate->alpha = val; |
| 285 | else if (property == rcdu->props.zpos) | ||
| 286 | rstate->zpos = val; | ||
| 286 | else | 287 | else |
| 287 | return -EINVAL; | 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 | if (property == rcdu->props.alpha) | 301 | if (property == rcdu->props.alpha) |
| 301 | *val = rstate->alpha; | 302 | *val = rstate->alpha; |
| 303 | else if (property == rcdu->props.zpos) | ||
| 304 | *val = rstate->zpos; | ||
| 302 | else | 305 | else |
| 303 | return -EINVAL; | 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 | drm_object_attach_property(&plane->plane.base, | 382 | drm_object_attach_property(&plane->plane.base, |
| 380 | rcdu->props.alpha, 255); | 383 | rcdu->props.alpha, 255); |
| 384 | drm_object_attach_property(&plane->plane.base, | ||
| 385 | rcdu->props.zpos, 1); | ||
| 381 | } | 386 | } |
| 382 | 387 | ||
| 383 | return 0; | 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 | * @state: base DRM plane state | 44 | * @state: base DRM plane state |
| 45 | * @format: information about the pixel format used by the plane | 45 | * @format: information about the pixel format used by the plane |
| 46 | * @alpha: value of the plane alpha property | 46 | * @alpha: value of the plane alpha property |
| 47 | * @zpos: value of the plane zpos property | ||
| 47 | */ | 48 | */ |
| 48 | struct rcar_du_vsp_plane_state { | 49 | struct rcar_du_vsp_plane_state { |
| 49 | struct drm_plane_state state; | 50 | struct drm_plane_state state; |
| @@ -51,6 +52,7 @@ struct rcar_du_vsp_plane_state { · 1 unmodified line | |||
| 51 | const struct rcar_du_format_info *format; | 52 | const struct rcar_du_format_info *format; |
| 52 | 53 | ||
| 53 | unsigned int alpha; | 54 | unsigned int alpha; |
| 55 | unsigned int zpos; | ||
| 54 | }; | 56 | }; |
| 55 | 57 | ||
| 56 | static inline struct rcar_du_vsp_plane_state * | 58 | static inline struct rcar_du_vsp_plane_state * |
| @@ -126,7 +126,7 @@ struct sur40_image_header { · 125 unmodified lines | |||
| 126 | #define VIDEO_PACKET_SIZE 16384 | 126 | #define VIDEO_PACKET_SIZE 16384 |
| 127 | 127 | ||
| 128 | /* polling interval (ms) */ | 128 | /* polling interval (ms) */ |
| 129 | #define POLL_INTERVAL 4 | 129 | #define POLL_INTERVAL 1 |
| 130 | 130 | ||
| 131 | /* maximum number of contacts FIXME: this is a guess? */ | 131 | /* maximum number of contacts FIXME: this is a guess? */ |
| 132 | #define MAX_CONTACTS 64 | 132 | #define MAX_CONTACTS 64 |
| @@ -151,7 +151,6 @@ struct sur40_state { · 18 unmodified lines | |||
| 151 | struct mutex lock; | 151 | struct mutex lock; |
| 152 | 152 | ||
| 153 | struct vb2_queue queue; | 153 | struct vb2_queue queue; |
| 154 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 155 | struct list_head buf_list; | 154 | struct list_head buf_list; |
| 156 | spinlock_t qlock; | 155 | spinlock_t qlock; |
| 157 | int sequence; | 156 | int sequence; |
| @@ -448,7 +447,7 @@ static void sur40_process_video(struct sur40_state *sur40) · 290 unmodified lines | |||
| 448 | 447 | ||
| 449 | /* return error if streaming was stopped in the meantime */ | 448 | /* return error if streaming was stopped in the meantime */ |
| 450 | if (sur40->sequence == -1) | 449 | if (sur40->sequence == -1) |
| 451 | goto err_poll; | 450 | return; |
| 452 | 451 | ||
| 453 | /* mark as finished */ | 452 | /* mark as finished */ |
| 454 | new_buf->vb.vb2_buf.timestamp = ktime_get_ns(); | 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 | sur40->queue = sur40_queue; | 579 | sur40->queue = sur40_queue; |
| 581 | sur40->queue.drv_priv = sur40; | 580 | sur40->queue.drv_priv = sur40; |
| 582 | sur40->queue.lock = &sur40->lock; | 581 | sur40->queue.lock = &sur40->lock; |
| 582 | sur40->queue.dev = sur40->dev; | ||
| 583 | 583 | ||
| 584 | /* initialize the queue */ | 584 | /* initialize the queue */ |
| 585 | error = vb2_queue_init(&sur40->queue); | 585 | error = vb2_queue_init(&sur40->queue); |
| 586 | if (error) | 586 | if (error) |
| 587 | goto err_unreg_v4l2; | 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 | sur40->vdev = sur40_video_device; | 589 | sur40->vdev = sur40_video_device; |
| 597 | sur40->vdev.v4l2_dev = &sur40->v4l2; | 590 | sur40->vdev.v4l2_dev = &sur40->v4l2; |
| 598 | sur40->vdev.lock = &sur40->lock; | 591 | sur40->vdev.lock = &sur40->lock; |
| @@ -633,7 +626,6 @@ static void sur40_disconnect(struct usb_interface *interface) · 34 unmodified lines | |||
| 633 | 626 | ||
| 634 | video_unregister_device(&sur40->vdev); | 627 | video_unregister_device(&sur40->vdev); |
| 635 | v4l2_device_unregister(&sur40->v4l2); | 628 | v4l2_device_unregister(&sur40->v4l2); |
| 636 | vb2_dma_sg_cleanup_ctx(sur40->alloc_ctx); | ||
| 637 | 629 | ||
| 638 | input_unregister_polled_device(sur40->input); | 630 | input_unregister_polled_device(sur40->input); |
| 639 | input_free_polled_device(sur40->input); | 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 | static int sur40_queue_setup(struct vb2_queue *q, | 646 | static int sur40_queue_setup(struct vb2_queue *q, |
| 655 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | if (q->num_buffers + *nbuffers < 3) | 650 | if (q->num_buffers + *nbuffers < 3) |
| 661 | *nbuffers = 3 - q->num_buffers; | 651 | *nbuffers = 3 - q->num_buffers; |
| 662 | alloc_ctxs[0] = sur40->alloc_ctx; | ||
| 663 | 652 | ||
| 664 | if (*nplanes) | 653 | if (*nplanes) |
| 665 | return sizes[0] < sur40_video_format.sizeimage ? -EINVAL : 0; | 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 | static void sur40_stop_streaming(struct vb2_queue *vq) | 725 | static void sur40_stop_streaming(struct vb2_queue *vq) |
| 737 | { | 726 | { |
| 738 | struct sur40_state *sur40 = vb2_get_drv_priv(vq); | 727 | struct sur40_state *sur40 = vb2_get_drv_priv(vq); |
| 728 | vb2_wait_for_all_buffers(vq); | ||
| 739 | sur40->sequence = -1; | 729 | sur40->sequence = -1; |
| 740 | 730 | ||
| 741 | /* Release all active buffers */ | 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 | if (f->index != 0) | 784 | if (f->index != 0) |
| 795 | return -EINVAL; | 785 | return -EINVAL; |
| 796 | strlcpy(f->description, "8-bit greyscale", sizeof(f->description)); | ||
| 797 | f->pixelformat = V4L2_PIX_FMT_GREY; | 786 | f->pixelformat = V4L2_PIX_FMT_GREY; |
| 798 | f->flags = 0; | 787 | f->flags = 0; |
| 799 | return 0; | 788 | return 0; |
| @@ -80,6 +80,9 @@ config MEDIA_RC_SUPPORT · 79 unmodified lines | |||
| 80 | 80 | ||
| 81 | Say Y when you have a TV or an IR device. | 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 | # Media controller | 87 | # Media controller |
| 85 | # Selectable only for webcam/grabbers, as other drivers don't use it | 88 | # Selectable only for webcam/grabbers, as other drivers don't use it |
| @@ -2,6 +2,10 @@ · 1 unmodified line | |||
| 2 | # Makefile for the kernel multimedia device drivers. | 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 | media-objs := media-device.o media-devnode.o media-entity.o | 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 | * Remember that r, g and b are still in the 0 - 0xff0 range. | 777 | * Remember that r, g and b are still in the 0 - 0xff0 range. |
| 778 | */ | 778 | */ |
| 779 | if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED && | 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 | * Convert from full range (which is what r, g and b are) | 782 | * Convert from full range (which is what r, g and b are) |
| 783 | * to limited range (which is the 'real' RGB range), which | 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 | g = (g * 219) / 255 + (16 << 4); | 787 | g = (g * 219) / 255 + (16 << 4); |
| 788 | b = (b * 219) / 255 + (16 << 4); | 788 | b = (b * 219) / 255 + (16 << 4); |
| 789 | } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED && | 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 | * Clamp r, g and b to the limited range and convert to full | 792 | * Clamp r, g and b to the limited range and convert to full |
| 793 | * range since that's what we deliver. | 793 | * range since that's what we deliver. |
| @@ -143,7 +143,7 @@ struct dmx_ts_feed { · 142 unmodified lines | |||
| 143 | int type, | 143 | int type, |
| 144 | enum dmx_ts_pes pes_type, | 144 | enum dmx_ts_pes pes_type, |
| 145 | size_t circular_buffer_size, | 145 | size_t circular_buffer_size, |
| 146 | struct timespec timeout); | 146 | ktime_t timeout); |
| 147 | int (*start_filtering)(struct dmx_ts_feed *feed); | 147 | int (*start_filtering)(struct dmx_ts_feed *feed); |
| 148 | int (*stop_filtering)(struct dmx_ts_feed *feed); | 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 | struct dmxdev_filter *filter, | 556 | struct dmxdev_filter *filter, |
| 557 | struct dmxdev_feed *feed) | 557 | struct dmxdev_feed *feed) |
| 558 | { | 558 | { |
| 559 | struct timespec timeout = { 0 }; | 559 | ktime_t timeout = ktime_set(0, 0); |
| 560 | struct dmx_pes_filter_params *para = &filter->params.pes; | 560 | struct dmx_pes_filter_params *para = &filter->params.pes; |
| 561 | dmx_output_t otype; | 561 | dmx_output_t otype; |
| 562 | int ret; | 562 | int ret; |
| @@ -123,6 +123,7 @@ struct dvb_ca_slot { · 122 unmodified lines | |||
| 123 | 123 | ||
| 124 | /* Private CA-interface information */ | 124 | /* Private CA-interface information */ |
| 125 | struct dvb_ca_private { | 125 | struct dvb_ca_private { |
| 126 | struct kref refcount; | ||
| 126 | 127 | ||
| 127 | /* pointer back to the public data structure */ | 128 | /* pointer back to the public data structure */ |
| 128 | struct dvb_ca_en50221 *pub; | 129 | struct dvb_ca_en50221 *pub; |
| @@ -161,6 +162,34 @@ struct dvb_ca_private { · 32 unmodified lines | |||
| 161 | struct mutex ioctl_mutex; | 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 | static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); | 193 | static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); |
| 165 | static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); | 194 | static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); |
| 166 | static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); | 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 | dvb_ca_en50221_thread_update_delay(ca); | 1587 | dvb_ca_en50221_thread_update_delay(ca); |
| 1559 | dvb_ca_en50221_thread_wakeup(ca); | 1588 | dvb_ca_en50221_thread_wakeup(ca); |
| 1560 | 1589 | ||
| 1590 | dvb_ca_private_get(ca); | ||
| 1591 | |||
| 1561 | return 0; | 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 | module_put(ca->pub->owner); | 1618 | module_put(ca->pub->owner); |
| 1588 | 1619 | ||
| 1620 | dvb_ca_private_put(ca); | ||
| 1621 | |||
| 1589 | return err; | 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 | ret = -ENOMEM; | 1714 | ret = -ENOMEM; |
| 1682 | goto exit; | 1715 | goto exit; |
| 1683 | } | 1716 | } |
| 1717 | kref_init(&ca->refcount); | ||
| 1684 | ca->pub = pubca; | 1718 | ca->pub = pubca; |
| 1685 | ca->flags = flags; | 1719 | ca->flags = flags; |
| 1686 | ca->slot_count = slot_count; | 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 | for (i = 0; i < ca->slot_count; i++) { | 1794 | for (i = 0; i < ca->slot_count; i++) { |
| 1761 | dvb_ca_en50221_slot_shutdown(ca, i); | 1795 | dvb_ca_en50221_slot_shutdown(ca, i); |
| 1762 | vfree(ca->slot_info[i].rx_buffer.data); | ||
| 1763 | } | 1796 | } |
| 1764 | kfree(ca->slot_info); | 1797 | dvb_ca_private_put(ca); |
| 1765 | dvb_unregister_device(ca->dvbdev); | ||
| 1766 | kfree(ca); | ||
| 1767 | pubca->private = NULL; | 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 | int dvr_done = 0; | 398 | int dvr_done = 0; |
| 399 | 399 | ||
| 400 | if (dvb_demux_speedcheck) { | 400 | if (dvb_demux_speedcheck) { |
| 401 | struct timespec cur_time, delta_time; | 401 | ktime_t cur_time; |
| 402 | u64 speed_bytes, speed_timedelta; | 402 | u64 speed_bytes, speed_timedelta; |
| 403 | 403 | ||
| 404 | demux->speed_pkts_cnt++; | 404 | demux->speed_pkts_cnt++; |
| 405 | 405 | ||
| 406 | /* show speed every SPEED_PKTS_INTERVAL packets */ | 406 | /* show speed every SPEED_PKTS_INTERVAL packets */ |
| 407 | if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) { | 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 && | 410 | if (ktime_to_ns(demux->speed_last_time) != 0) { |
| 411 | demux->speed_last_time.tv_nsec != 0) { | ||
| 412 | delta_time = timespec_sub(cur_time, | ||
| 413 | demux->speed_last_time); | ||
| 414 | speed_bytes = (u64)demux->speed_pkts_cnt | 411 | speed_bytes = (u64)demux->speed_pkts_cnt |
| 415 | * 188 * 8; | 412 | * 188 * 8; |
| 416 | /* convert to 1024 basis */ | 413 | /* convert to 1024 basis */ |
| 417 | speed_bytes = 1000 * div64_u64(speed_bytes, | 414 | speed_bytes = 1000 * div64_u64(speed_bytes, |
| 418 | 1024); | 415 | 1024); |
| 419 | speed_timedelta = | 416 | speed_timedelta = ktime_ms_delta(cur_time, |
| 420 | (u64)timespec_to_ns(&delta_time); | 417 | demux->speed_last_time); |
| 421 | speed_timedelta = div64_u64(speed_timedelta, | ||
| 422 | 1000000); /* nsec -> usec */ | ||
| 423 | printk(KERN_INFO "TS speed %llu Kbits/sec \n", | 418 | printk(KERN_INFO "TS speed %llu Kbits/sec \n", |
| 424 | div64_u64(speed_bytes, | 419 | div64_u64(speed_bytes, |
| 425 | speed_timedelta)); | 420 | speed_timedelta)); |
| @@ -666,7 +661,7 @@ out: · 240 unmodified lines | |||
| 666 | 661 | ||
| 667 | static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, | 662 | static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, |
| 668 | enum dmx_ts_pes pes_type, | 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 | struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; | 666 | struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; |
| 672 | struct dvb_demux *demux = feed->demux; | 667 | struct dvb_demux *demux = feed->demux; |
| @@ -83,7 +83,7 @@ struct dvb_demux_feed { · 82 unmodified lines | |||
| 83 | u8 *buffer; | 83 | u8 *buffer; |
| 84 | int buffer_size; | 84 | int buffer_size; |
| 85 | 85 | ||
| 86 | struct timespec timeout; | 86 | ktime_t timeout; |
| 87 | struct dvb_demux_filter *filter; | 87 | struct dvb_demux_filter *filter; |
| 88 | 88 | ||
| 89 | int ts_type; | 89 | int ts_type; |
| @@ -134,7 +134,7 @@ struct dvb_demux { · 44 unmodified lines | |||
| 134 | 134 | ||
| 135 | uint8_t *cnt_storage; /* for TS continuity check */ | 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 | uint32_t speed_pkts_cnt; /* for TS speed check */ | 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 | static DEFINE_MUTEX(frontend_mutex); | 99 | static DEFINE_MUTEX(frontend_mutex); |
| 100 | 100 | ||
| 101 | struct dvb_frontend_private { | 101 | struct dvb_frontend_private { |
| 102 | struct kref refcount; | ||
| 102 | 103 | ||
| 103 | /* thread/frontend values */ | 104 | /* thread/frontend values */ |
| 104 | struct dvb_device *dvbdev; | 105 | struct dvb_device *dvbdev; |
| @@ -137,6 +138,23 @@ struct dvb_frontend_private { · 32 unmodified lines | |||
| 137 | #endif | 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 | static void dvb_frontend_wakeup(struct dvb_frontend *fe); | 158 | static void dvb_frontend_wakeup(struct dvb_frontend *fe); |
| 141 | static int dtv_get_frontend(struct dvb_frontend *fe, | 159 | static int dtv_get_frontend(struct dvb_frontend *fe, |
| 142 | struct dtv_frontend_properties *c, | 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 | fepriv->events.eventr = fepriv->events.eventw = 0; | 2561 | fepriv->events.eventr = fepriv->events.eventw = 0; |
| 2544 | } | 2562 | } |
| 2545 | 2563 | ||
| 2564 | dvb_frontend_private_get(fepriv); | ||
| 2565 | |||
| 2546 | if (adapter->mfe_shared) | 2566 | if (adapter->mfe_shared) |
| 2547 | mutex_unlock (&adapter->mfe_lock); | 2567 | mutex_unlock (&adapter->mfe_lock); |
| 2548 | return ret; | 2568 | return ret; |
| @@ -2591,6 +2611,8 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) · 42 unmodified lines | |||
| 2591 | fe->ops.ts_bus_ctrl(fe, 0); | 2611 | fe->ops.ts_bus_ctrl(fe, 0); |
| 2592 | } | 2612 | } |
| 2593 | 2613 | ||
| 2614 | dvb_frontend_private_put(fepriv); | ||
| 2615 | |||
| 2594 | return ret; | 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 | fepriv = fe->frontend_priv; | 2702 | fepriv = fe->frontend_priv; |
| 2681 | 2703 | ||
| 2704 | kref_init(&fepriv->refcount); | ||
| 2705 | |||
| 2682 | sema_init(&fepriv->sem, 1); | 2706 | sema_init(&fepriv->sem, 1); |
| 2683 | init_waitqueue_head (&fepriv->wait_queue); | 2707 | init_waitqueue_head (&fepriv->wait_queue); |
| 2684 | init_waitqueue_head (&fepriv->events.wait_queue); | 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 | mutex_lock(&frontend_mutex); | 2738 | mutex_lock(&frontend_mutex); |
| 2715 | dvb_frontend_stop (fe); | 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 | dvb_unregister_device (fepriv->dvbdev); | 2740 | dvb_unregister_device (fepriv->dvbdev); |
| 2724 | 2741 | ||
| 2725 | /* fe is invalid now */ | 2742 | /* fe is invalid now */ |
| 2726 | kfree(fepriv); | ||
| 2727 | mutex_unlock(&frontend_mutex); | 2743 | mutex_unlock(&frontend_mutex); |
| 2744 | dvb_frontend_private_put(fepriv); | ||
| 2728 | return 0; | 2745 | return 0; |
| 2729 | } | 2746 | } |
| 2730 | EXPORT_SYMBOL(dvb_unregister_frontend); | 2747 | EXPORT_SYMBOL(dvb_unregister_frontend); |
| @@ -997,7 +997,7 @@ static int dvb_net_feed_start(struct net_device *dev) · 996 unmodified lines | |||
| 997 | netdev_dbg(dev, "start filtering\n"); | 997 | netdev_dbg(dev, "start filtering\n"); |
| 998 | priv->secfeed->start_filtering(priv->secfeed); | 998 | priv->secfeed->start_filtering(priv->secfeed); |
| 999 | } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { | 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 | /* we have payloads encapsulated in TS */ | 1002 | /* we have payloads encapsulated in TS */ |
| 1003 | netdev_dbg(dev, "alloc tsfeed\n"); | 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 | int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf) | 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 | ssize_t free; | 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 | if (free <= 0) | 79 | if (free <= 0) |
| 69 | free += rbuf->size; | 80 | free += rbuf->size; |
| 70 | return free-1; | 81 | return free-1; |
| @@ -76,7 +87,11 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf) · 5 unmodified lines | |||
| 76 | { | 87 | { |
| 77 | ssize_t avail; | 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 | if (avail < 0) | 95 | if (avail < 0) |
| 81 | avail += rbuf->size; | 96 | avail += rbuf->size; |
| 82 | return avail; | 97 | return avail; |
| @@ -86,14 +101,25 @@ ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf) · 3 unmodified lines | |||
| 86 | 101 | ||
| 87 | void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf) | 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 | rbuf->error = 0; | 111 | rbuf->error = 0; |
| 91 | } | 112 | } |
| 92 | EXPORT_SYMBOL(dvb_ringbuffer_flush); | 113 | EXPORT_SYMBOL(dvb_ringbuffer_flush); |
| 93 | 114 | ||
| 94 | void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf) | 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 | rbuf->error = 0; | 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 | return -EFAULT; | 145 | return -EFAULT; |
| 120 | buf += split; | 146 | buf += split; |
| 121 | todo -= split; | 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 | if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) | 154 | if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) |
| 125 | return -EFAULT; | 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 | return len; | 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 | memcpy(buf, rbuf->data+rbuf->pread, split); | 170 | memcpy(buf, rbuf->data+rbuf->pread, split); |
| 140 | buf += split; | 171 | buf += split; |
| 141 | todo -= split; | 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 | memcpy(buf, rbuf->data+rbuf->pread, todo); | 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 | memcpy(rbuf->data+rbuf->pwrite, buf, split); | 194 | memcpy(rbuf->data+rbuf->pwrite, buf, split); |
| 159 | buf += split; | 195 | buf += split; |
| 160 | todo -= split; | 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 | memcpy(rbuf->data+rbuf->pwrite, buf, todo); | 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 | return len; | 208 | return len; |
| 167 | } | 209 | } |
| @@ -181,12 +223,18 @@ ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, · 13 unmodified lines | |||
| 181 | return len - todo; | 223 | return len - todo; |
| 182 | buf += split; | 224 | buf += split; |
| 183 | todo -= split; | 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 | status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo); | 233 | status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo); |
| 187 | if (status) | 234 | if (status) |
| 188 | return len - todo; | 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 | return len; | 239 | return len; |
| 192 | } | 240 | } |
| @@ -73,6 +73,14 @@ config DVB_SI2165 · 72 unmodified lines | |||
| 73 | 73 | ||
| 74 | Say Y when you want to support this frontend. | 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 | config DVB_MN88473 | 84 | config DVB_MN88473 |
| 77 | tristate "Panasonic MN88473" | 85 | tristate "Panasonic MN88473" |
| 78 | depends on DVB_CORE && I2C | 86 | depends on DVB_CORE && I2C |
| @@ -853,6 +861,13 @@ config DVB_ASCOT2E · 774 unmodified lines | |||
| 853 | help | 861 | help |
| 854 | Say Y when you want to support this frontend. | 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 | comment "Tools to develop new frontends" | 871 | comment "Tools to develop new frontends" |
| 857 | 872 | ||
| 858 | config DVB_DUMMY_FE | 873 | config DVB_DUMMY_FE |
| @@ -95,6 +95,7 @@ obj-$(CONFIG_DVB_STV0900) += stv0900.o · 94 unmodified lines | |||
| 95 | obj-$(CONFIG_DVB_STV090x) += stv090x.o | 95 | obj-$(CONFIG_DVB_STV090x) += stv090x.o |
| 96 | obj-$(CONFIG_DVB_STV6110x) += stv6110x.o | 96 | obj-$(CONFIG_DVB_STV6110x) += stv6110x.o |
| 97 | obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o | 97 | obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o |
| 98 | obj-$(CONFIG_DVB_MN88472) += mn88472.o | ||
| 98 | obj-$(CONFIG_DVB_MN88473) += mn88473.o | 99 | obj-$(CONFIG_DVB_MN88473) += mn88473.o |
| 99 | obj-$(CONFIG_DVB_ISL6423) += isl6423.o | 100 | obj-$(CONFIG_DVB_ISL6423) += isl6423.o |
| 100 | obj-$(CONFIG_DVB_EC100) += ec100.o | 101 | obj-$(CONFIG_DVB_EC100) += ec100.o |
| @@ -123,3 +124,4 @@ obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o · 22 unmodified lines | |||
| 123 | obj-$(CONFIG_DVB_TC90522) += tc90522.o | 124 | obj-$(CONFIG_DVB_TC90522) += tc90522.o |
| 124 | obj-$(CONFIG_DVB_HORUS3A) += horus3a.o | 125 | obj-$(CONFIG_DVB_HORUS3A) += horus3a.o |
| 125 | obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o | 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 | u64 post_bit_count; | 41 | u64 post_bit_count; |
| 42 | u64 error_block_count; | 42 | u64 error_block_count; |
| 43 | u64 total_block_count; | 43 | u64 total_block_count; |
| 44 | struct delayed_work stat_work; | ||
| 45 | }; | 44 | }; |
| 46 | 45 | ||
| 47 | /* write multiple registers */ | 46 | /* write multiple registers */ |
| @@ -468,8 +467,6 @@ static int af9033_init(struct dvb_frontend *fe) · 420 unmodified lines | |||
| 468 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 467 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 469 | c->post_bit_error.len = 1; | 468 | c->post_bit_error.len = 1; |
| 470 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 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 | return 0; | 471 | return 0; |
| 475 | 472 | ||
| @@ -485,9 +482,6 @@ static int af9033_sleep(struct dvb_frontend *fe) · 9 unmodified lines | |||
| 485 | int ret, i; | 482 | int ret, i; |
| 486 | u8 tmp; | 483 | u8 tmp; |
| 487 | 484 | ||
| 488 | /* stop statistics polling */ | ||
| 489 | cancel_delayed_work_sync(&dev->stat_work); | ||
| 490 | |||
| 491 | ret = af9033_wr_reg(dev, 0x80004c, 1); | 485 | ret = af9033_wr_reg(dev, 0x80004c, 1); |
| 492 | if (ret < 0) | 486 | if (ret < 0) |
| 493 | goto err; | 487 | goto err; |
| @@ -821,36 +815,39 @@ err: · 327 unmodified lines | |||
| 821 | static int af9033_read_status(struct dvb_frontend *fe, enum fe_status *status) | 815 | static int af9033_read_status(struct dvb_frontend *fe, enum fe_status *status) |
| 822 | { | 816 | { |
| 823 | struct af9033_dev *dev = fe->demodulator_priv; | 817 | struct af9033_dev *dev = fe->demodulator_priv; |
| 824 | int ret; | 818 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| 825 | u8 tmp; | 819 | int ret, i, tmp = 0; |
| 820 | u8 u8tmp, buf[7]; | ||
| 821 | |||
| 822 | dev_dbg(&dev->client->dev, "\n"); | ||
| 826 | 823 | ||
| 827 | *status = 0; | 824 | *status = 0; |
| 828 | 825 | ||
| 829 | /* radio channel status, 0=no result, 1=has signal, 2=no signal */ | 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 | if (ret < 0) | 828 | if (ret < 0) |
| 832 | goto err; | 829 | goto err; |
| 833 | 830 | ||
| 834 | /* has signal */ | 831 | /* has signal */ |
| 835 | if (tmp == 0x01) | 832 | if (u8tmp == 0x01) |
| 836 | *status |= FE_HAS_SIGNAL; | 833 | *status |= FE_HAS_SIGNAL; |
| 837 | 834 | ||
| 838 | if (tmp != 0x02) { | 835 | if (u8tmp != 0x02) { |
| 839 | /* TPS lock */ | 836 | /* TPS lock */ |
| 840 | ret = af9033_rd_reg_mask(dev, 0x80f5a9, &tmp, 0x01); | 837 | ret = af9033_rd_reg_mask(dev, 0x80f5a9, &u8tmp, 0x01); |
| 841 | if (ret < 0) | 838 | if (ret < 0) |
| 842 | goto err; | 839 | goto err; |
| 843 | 840 | ||
| 844 | if (tmp) | 841 | if (u8tmp) |
| 845 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | 842 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | |
| 846 | FE_HAS_VITERBI; | 843 | FE_HAS_VITERBI; |
| 847 | 844 | ||
| 848 | /* full lock */ | 845 | /* full lock */ |
| 849 | ret = af9033_rd_reg_mask(dev, 0x80f999, &tmp, 0x01); | 846 | ret = af9033_rd_reg_mask(dev, 0x80f999, &u8tmp, 0x01); |
| 850 | if (ret < 0) | 847 | if (ret < 0) |
| 851 | goto err; | 848 | goto err; |
| 852 | 849 | ||
| 853 | if (tmp) | 850 | if (u8tmp) |
| 854 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | | 851 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | |
| 855 | FE_HAS_VITERBI | FE_HAS_SYNC | | 852 | FE_HAS_VITERBI | FE_HAS_SYNC | |
| 856 | FE_HAS_LOCK; | 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 | dev->fe_status = *status; | 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 | return 0; | 1000 | return 0; |
| 862 | 1001 | ||
| 863 | err: | 1002 | err: |
| @@ -1059,159 +1198,6 @@ err: · 195 unmodified lines | |||
| 1059 | return ret; | 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 | static struct dvb_frontend_ops af9033_ops = { | 1201 | static struct dvb_frontend_ops af9033_ops = { |
| 1216 | .delsys = { SYS_DVBT }, | 1202 | .delsys = { SYS_DVBT }, |
| 1217 | .info = { | 1203 | .info = { |
| @@ -1272,7 +1258,6 @@ static int af9033_probe(struct i2c_client *client, · 54 unmodified lines | |||
| 1272 | 1258 | ||
| 1273 | /* setup the state */ | 1259 | /* setup the state */ |
| 1274 | dev->client = client; | 1260 | dev->client = client; |
| 1275 | INIT_DELAYED_WORK(&dev->stat_work, af9033_stat_work); | ||
| 1276 | memcpy(&dev->cfg, cfg, sizeof(struct af9033_config)); | 1261 | memcpy(&dev->cfg, cfg, sizeof(struct af9033_config)); |
| 1277 | 1262 | ||
| 1278 | if (dev->cfg.clock != 12000000) { | 1263 | if (dev->cfg.clock != 12000000) { |
| @@ -1372,9 +1357,6 @@ static int af9033_remove(struct i2c_client *client) · 93 unmodified lines | |||
| 1372 | 1357 | ||
| 1373 | dev_dbg(&dev->client->dev, "\n"); | 1358 | dev_dbg(&dev->client->dev, "\n"); |
| 1374 | 1359 | ||
| 1375 | /* stop statistics polling */ | ||
| 1376 | cancel_delayed_work_sync(&dev->stat_work); | ||
| 1377 | |||
| 1378 | dev->fe.ops.release = NULL; | 1360 | dev->fe.ops.release = NULL; |
| 1379 | dev->fe.demodulator_priv = NULL; | 1361 | dev->fe.demodulator_priv = NULL; |
| 1380 | kfree(dev); | 1362 | kfree(dev); |
| @@ -1391,6 +1373,7 @@ MODULE_DEVICE_TABLE(i2c, af9033_id_table); · 10 unmodified lines | |||
| 1391 | static struct i2c_driver af9033_driver = { | 1373 | static struct i2c_driver af9033_driver = { |
| 1392 | .driver = { | 1374 | .driver = { |
| 1393 | .name = "af9033", | 1375 | .name = "af9033", |
| 1376 | .suppress_bind_attrs = true, | ||
| 1394 | }, | 1377 | }, |
| 1395 | .probe = af9033_probe, | 1378 | .probe = af9033_probe, |
| 1396 | .remove = af9033_remove, | 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 | dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n", | 136 | dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n", |
| 137 | reg, len + 1); | 137 | reg, len + 1); |
| 138 | return -E2BIG; | 138 | return -E2BIG; |
| @@ -1,7 +1,9 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * cxd2841er.c | 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 | * Copyright 2012 Sony Corporation | 8 | * Copyright 2012 Sony Corporation |
| 7 | * Copyright (C) 2014 NetUP Inc. | 9 | * Copyright (C) 2014 NetUP Inc. |
| @@ -34,6 +36,16 @@ · 26 unmodified lines | |||
| 34 | #include "cxd2841er_priv.h" | 36 | #include "cxd2841er_priv.h" |
| 35 | 37 | ||
| 36 | #define MAX_WRITE_REGSIZE 16 | 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 | enum cxd2841er_state { | 50 | enum cxd2841er_state { |
| 39 | STATE_SHUTDOWN = 0, | 51 | STATE_SHUTDOWN = 0, |
| @@ -51,6 +63,8 @@ struct cxd2841er_priv { · 11 unmodified lines | |||
| 51 | const struct cxd2841er_config *config; | 63 | const struct cxd2841er_config *config; |
| 52 | enum cxd2841er_state state; | 64 | enum cxd2841er_state state; |
| 53 | u8 system; | 65 | u8 system; |
| 66 | enum cxd2841er_xtal xtal; | ||
| 67 | enum fe_caps caps; | ||
| 54 | }; | 68 | }; |
| 55 | 69 | ||
| 56 | static const struct cxd2841er_cnr_data s_cn_data[] = { | 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 | #define MAKE_IFFREQ_CONFIG(iffreq) ((u32)(((iffreq)/41.0)*16777216.0 + 0.5)) | 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 | static void cxd2841er_i2c_debug(struct cxd2841er_priv *priv, | 209 | static void cxd2841er_i2c_debug(struct cxd2841er_priv *priv, |
| 193 | u8 addr, u8 reg, u8 write, | 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 | if (len + 1 >= sizeof(buf)) { | 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 | reg, len + 1); | 238 | reg, len + 1); |
| 222 | return -E2BIG; | 239 | return -E2BIG; |
| 223 | } | 240 | } |
| @@ -282,6 +299,7 @@ static int cxd2841er_read_regs(struct cxd2841er_priv *priv, · 58 unmodified lines | |||
| 282 | KBUILD_MODNAME, ret, i2c_addr, reg); | 299 | KBUILD_MODNAME, ret, i2c_addr, reg); |
| 283 | return ret; | 300 | return ret; |
| 284 | } | 301 | } |
| 302 | cxd2841er_i2c_debug(priv, i2c_addr, reg, 0, val, len); | ||
| 285 | return 0; | 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 | static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv, | 445 | static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv, |
| 428 | u32 bandwidth); | 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 | static int cxd2841er_retune_active(struct cxd2841er_priv *priv, | 457 | static int cxd2841er_retune_active(struct cxd2841er_priv *priv, |
| 431 | struct dtv_frontend_properties *p) | 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 | priv, p->bandwidth_hz); | 481 | priv, p->bandwidth_hz); |
| 455 | case SYS_DVBC_ANNEX_A: | 482 | case SYS_DVBC_ANNEX_A: |
| 456 | return cxd2841er_sleep_tc_to_active_c_band( | 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 | dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n", | 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 | return 0; | 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 | static int cxd2841er_shutdown_to_sleep_s(struct cxd2841er_priv *priv) | 744 | static int cxd2841er_shutdown_to_sleep_s(struct cxd2841er_priv *priv) |
| 673 | { | 745 | { |
| 674 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 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 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); | 758 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); |
| 687 | /* Set demod SW reset */ | 759 | /* Set demod SW reset */ |
| 688 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01); | 760 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01); |
| 689 | /* Set X'tal clock to 20.5Mhz */ | 761 | |
| 690 | cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x00); | 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 | /* Set demod mode */ | 780 | /* Set demod mode */ |
| 692 | cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x0a); | 781 | cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x0a); |
| 693 | /* Clear demod SW reset */ | 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 | static int cxd2841er_shutdown_to_sleep_tc(struct cxd2841er_priv *priv) | 802 | static int cxd2841er_shutdown_to_sleep_tc(struct cxd2841er_priv *priv) |
| 714 | { | 803 | { |
| 804 | u8 data = 0; | ||
| 805 | |||
| 715 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 806 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 716 | if (priv->state != STATE_SHUTDOWN) { | 807 | if (priv->state != STATE_SHUTDOWN) { |
| 717 | dev_dbg(&priv->i2c->dev, "%s(): invalid demod state %d\n", | 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 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); | 818 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); |
| 728 | /* Set demod SW reset */ | 819 | /* Set demod SW reset */ |
| 729 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01); | 820 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01); |
| 730 | /* Set X'tal clock to 20.5Mhz */ | 821 | /* Select ADC clock mode */ |
| 731 | cxd2841er_write_reg(priv, I2C_SLVX, 0x13, 0x00); | 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 | /* Clear demod SW reset */ | 839 | /* Clear demod SW reset */ |
| 734 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x00); | 840 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x00); |
| 735 | usleep_range(1000, 2000); | 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 | static u8 cxd2841er_chip_id(struct cxd2841er_priv *priv) | 916 | static u8 cxd2841er_chip_id(struct cxd2841er_priv *priv) |
| 811 | { | 917 | { |
| 812 | u8 chip_id; | 918 | u8 chip_id = 0; |
| 813 | 919 | ||
| 814 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 920 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 815 | cxd2841er_write_reg(priv, I2C_SLVT, 0, 0); | 921 | if (cxd2841er_write_reg(priv, I2C_SLVT, 0, 0) == 0) |
| 816 | cxd2841er_read_reg(priv, I2C_SLVT, 0xfd, &chip_id); | 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 | return chip_id; | 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 | return 0; | 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 | static int cxd2841er_read_status_tc(struct dvb_frontend *fe, | 1027 | static int cxd2841er_read_status_tc(struct dvb_frontend *fe, |
| 900 | enum fe_status *status) | 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 | FE_HAS_SYNC; | 1049 | FE_HAS_SYNC; |
| 922 | if (tslock) | 1050 | if (tslock) |
| 923 | *status |= FE_HAS_LOCK; | 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 | } else if (priv->system == SYS_DVBC_ANNEX_A) { | 1066 | } else if (priv->system == SYS_DVBC_ANNEX_A) { |
| 925 | ret = cxd2841er_read_status_c(priv, &tslock); | 1067 | ret = cxd2841er_read_status_c(priv, &tslock); |
| 926 | if (ret) | 1068 | if (ret) |
| @@ -997,6 +1139,76 @@ static int cxd2841er_get_carrier_offset_s_s2(struct cxd2841er_priv *priv, · 70 unmodified lines | |||
| 997 | return 0; | 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 | static int cxd2841er_get_carrier_offset_t2(struct cxd2841er_priv *priv, | 1212 | static int cxd2841er_get_carrier_offset_t2(struct cxd2841er_priv *priv, |
| 1001 | u32 bandwidth, int *offset) | 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 | return 0; | 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 | static int cxd2841er_read_packet_errors_t( | 1293 | static int cxd2841er_read_packet_errors_t( |
| 1064 | struct cxd2841er_priv *priv, u32 *penum) | 1294 | struct cxd2841er_priv *priv, u32 *penum) |
| 1065 | { | 1295 | { |
| @@ -1096,11 +1326,85 @@ static int cxd2841er_read_packet_errors_t2( · 30 unmodified lines | |||
| 1096 | return 0; | 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 | u8 data[11]; | 1407 | u8 data[11]; |
| 1102 | u32 bit_error, bit_count; | ||
| 1103 | u32 temp_q, temp_r; | ||
| 1104 | 1408 | ||
| 1105 | /* Set SLV-T Bank : 0xA0 */ | 1409 | /* Set SLV-T Bank : 0xA0 */ |
| 1106 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0); | 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 | cxd2841er_read_regs(priv, I2C_SLVT, 0x35, data, 11); | 1421 | cxd2841er_read_regs(priv, I2C_SLVT, 0x35, data, 11); |
| 1118 | if (data[0] & 0x01) { | 1422 | if (data[0] & 0x01) { |
| 1119 | bit_error = ((u32)(data[1] & 0x3F) << 16) | | 1423 | *bit_error = ((u32)(data[1] & 0x3F) << 16) | |
| 1120 | ((u32)(data[2] & 0xFF) << 8) | | 1424 | ((u32)(data[2] & 0xFF) << 8) | |
| 1121 | (u32)(data[3] & 0xFF); | 1425 | (u32)(data[3] & 0xFF); |
| 1122 | bit_count = ((u32)(data[8] & 0x3F) << 16) | | 1426 | *bit_count = ((u32)(data[8] & 0x3F) << 16) | |
| 1123 | ((u32)(data[9] & 0xFF) << 8) | | 1427 | ((u32)(data[9] & 0xFF) << 8) | |
| 1124 | (u32)(data[10] & 0xFF); | 1428 | (u32)(data[10] & 0xFF); |
| 1125 | /* | 1429 | if ((*bit_count == 0) || (*bit_error > *bit_count)) { |
| 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)) { | ||
| 1131 | dev_dbg(&priv->i2c->dev, | 1430 | dev_dbg(&priv->i2c->dev, |
| 1132 | "%s(): invalid bit_error %d, bit_count %d\n", | 1431 | "%s(): invalid bit_error %d, bit_count %d\n", |
| 1133 | __func__, bit_error, bit_count); | 1432 | __func__, *bit_error, *bit_count); |
| 1134 | return 0; | 1433 | return -EINVAL; |
| 1135 | } | 1434 | } |
| 1136 | temp_q = div_u64_rem(10000000ULL * bit_error, | 1435 | return 0; |
| 1137 | bit_count, &temp_r); | ||
| 1138 | if (bit_count != 1 && temp_r >= bit_count / 2) | ||
| 1139 | temp_q++; | ||
| 1140 | return temp_q; | ||
| 1141 | } | 1436 | } |
| 1142 | dev_dbg(&priv->i2c->dev, "%s(): no data available\n", __func__); | 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 | u8 data[5]; | 1445 | u8 data[5]; |
| 1150 | u32 bit_error, period; | 1446 | u32 period; |
| 1151 | u32 temp_q, temp_r; | ||
| 1152 | u32 result = 0; | ||
| 1153 | 1447 | ||
| 1154 | /* Set SLV-T Bank : 0xB2 */ | 1448 | /* Set SLV-T Bank : 0xB2 */ |
| 1155 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xb2); | 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 | cxd2841er_read_regs(priv, I2C_SLVT, 0x30, data, 5); | 1458 | cxd2841er_read_regs(priv, I2C_SLVT, 0x30, data, 5); |
| 1165 | if (data[0] & 0x01) { | 1459 | if (data[0] & 0x01) { |
| 1166 | /* Bit error count */ | 1460 | /* Bit error count */ |
| 1167 | bit_error = ((u32)(data[1] & 0x0F) << 24) | | 1461 | *bit_error = ((u32)(data[1] & 0x0F) << 24) | |
| 1168 | ((u32)(data[2] & 0xFF) << 16) | | 1462 | ((u32)(data[2] & 0xFF) << 16) | |
| 1169 | ((u32)(data[3] & 0xFF) << 8) | | 1463 | ((u32)(data[3] & 0xFF) << 8) | |
| 1170 | (u32)(data[4] & 0xFF); | 1464 | (u32)(data[4] & 0xFF); |
| 1171 | 1465 | ||
| 1172 | /* Set SLV-T Bank : 0xA0 */ | 1466 | /* Set SLV-T Bank : 0xA0 */ |
| 1173 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0); | 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 | if (period == 0) { | 1471 | if (period == 0) { |
| 1178 | dev_dbg(&priv->i2c->dev, | 1472 | dev_dbg(&priv->i2c->dev, |
| 1179 | "%s(): period is 0\n", __func__); | 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 | dev_dbg(&priv->i2c->dev, | 1477 | dev_dbg(&priv->i2c->dev, |
| 1184 | "%s(): invalid bit_err 0x%x period 0x%x\n", | 1478 | "%s(): invalid bit_err 0x%x period 0x%x\n", |
| 1185 | __func__, bit_error, period); | 1479 | __func__, *bit_error, period); |
| 1186 | return 0; | 1480 | return -EINVAL; |
| 1187 | } | 1481 | } |
| 1188 | /* | 1482 | *bit_count = period * 64800; |
| 1189 | * BER = bitError / (period * 64800) | 1483 | |
| 1190 | * = (bitError * 10^7) / (period * 64800) | 1484 | return 0; |
| 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; | ||
| 1200 | } else { | 1485 | } else { |
| 1201 | dev_dbg(&priv->i2c->dev, | 1486 | dev_dbg(&priv->i2c->dev, |
| 1202 | "%s(): no data available\n", __func__); | 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 | u8 data[4]; | 1495 | u8 data[4]; |
| 1210 | u32 div, q, r; | 1496 | u32 period_exp, n_ldpc; |
| 1211 | u32 bit_err, period_exp, n_ldpc; | ||
| 1212 | 1497 | ||
| 1213 | *ber = 0; | ||
| 1214 | if (priv->state != STATE_ACTIVE_TC) { | 1498 | if (priv->state != STATE_ACTIVE_TC) { |
| 1215 | dev_dbg(&priv->i2c->dev, | 1499 | dev_dbg(&priv->i2c->dev, |
| 1216 | "%s(): invalid state %d\n", __func__, priv->state); | 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 | if (!(data[0] & 0x10)) { | 1505 | if (!(data[0] & 0x10)) { |
| 1222 | dev_dbg(&priv->i2c->dev, | 1506 | dev_dbg(&priv->i2c->dev, |
| 1223 | "%s(): no valid BER data\n", __func__); | 1507 | "%s(): no valid BER data\n", __func__); |
| 1224 | return 0; | 1508 | return -EINVAL; |
| 1225 | } | 1509 | } |
| 1226 | bit_err = ((u32)(data[0] & 0x0f) << 24) | | 1510 | *bit_error = ((u32)(data[0] & 0x0f) << 24) | |
| 1227 | ((u32)data[1] << 16) | | 1511 | ((u32)data[1] << 16) | |
| 1228 | ((u32)data[2] << 8) | | 1512 | ((u32)data[2] << 8) | |
| 1229 | (u32)data[3]; | 1513 | (u32)data[3]; |
| 1230 | cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data); | 1514 | cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data); |
| 1231 | period_exp = data[0] & 0x0f; | 1515 | period_exp = data[0] & 0x0f; |
| 1232 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x22); | 1516 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x22); |
| 1233 | cxd2841er_read_reg(priv, I2C_SLVT, 0x5e, data); | 1517 | cxd2841er_read_reg(priv, I2C_SLVT, 0x5e, data); |
| 1234 | n_ldpc = ((data[0] & 0x03) == 0 ? 16200 : 64800); | 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 | dev_dbg(&priv->i2c->dev, | 1520 | dev_dbg(&priv->i2c->dev, |
| 1237 | "%s(): invalid BER value\n", __func__); | 1521 | "%s(): invalid BER value\n", __func__); |
| 1238 | return -EINVAL; | 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 | if (period_exp >= 4) { | 1530 | if (period_exp >= 4) { |
| 1241 | div = (1U << (period_exp - 4)) * (n_ldpc / 200); | 1531 | *bit_count = (1U << (period_exp - 4)) * (n_ldpc / 200); |
| 1242 | q = div_u64_rem(3125ULL * bit_err, div, &r); | 1532 | *bit_error *= 3125ULL; |
| 1243 | } else { | 1533 | } else { |
| 1244 | div = (1U << period_exp) * (n_ldpc / 200); | 1534 | *bit_count = (1U << period_exp) * (n_ldpc / 200); |
| 1245 | q = div_u64_rem(50000ULL * bit_err, div, &r); | 1535 | *bit_error *= 50000ULL; |
| 1246 | } | 1536 | } |
| 1247 | *ber = (r >= div / 2) ? q + 1 : q; | ||
| 1248 | return 0; | 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 | u8 data[2]; | 1543 | u8 data[2]; |
| 1254 | u32 div, q, r; | 1544 | u32 period; |
| 1255 | u32 bit_err, period; | ||
| 1256 | 1545 | ||
| 1257 | *ber = 0; | ||
| 1258 | if (priv->state != STATE_ACTIVE_TC) { | 1546 | if (priv->state != STATE_ACTIVE_TC) { |
| 1259 | dev_dbg(&priv->i2c->dev, | 1547 | dev_dbg(&priv->i2c->dev, |
| 1260 | "%s(): invalid state %d\n", __func__, priv->state); | 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 | return 0; | 1556 | return 0; |
| 1269 | } | 1557 | } |
| 1270 | cxd2841er_read_regs(priv, I2C_SLVT, 0x22, data, sizeof(data)); | 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 | cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data); | 1560 | cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data); |
| 1273 | period = ((data[0] & 0x07) == 0) ? 256 : (4096 << (data[0] & 0x07)); | 1561 | period = ((data[0] & 0x07) == 0) ? 256 : (4096 << (data[0] & 0x07)); |
| 1274 | div = period / 128; | 1562 | |
| 1275 | q = div_u64_rem(78125ULL * bit_err, div, &r); | 1563 | /* |
| 1276 | *ber = (r >= div / 2) ? q + 1 : q; | 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 | return 0; | 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 | u8 data[3]; | 1576 | u8 data[3]; |
| 1283 | u32 res = 0, value; | 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 | } else { | 1629 | } else { |
| 1336 | dev_dbg(&priv->i2c->dev, | 1630 | dev_dbg(&priv->i2c->dev, |
| 1337 | "%s(): no data available\n", __func__); | 1631 | "%s(): no data available\n", __func__); |
| 1632 | return -EINVAL; | ||
| 1338 | } | 1633 | } |
| 1339 | done: | 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 | static int cxd2841er_read_snr_t(struct cxd2841er_priv *priv, u32 *snr) | 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 | return 0; | 1747 | return 0; |
| 1392 | } | 1748 | } |
| 1393 | 1749 | ||
| 1394 | static u16 cxd2841er_read_agc_gain_t_t2(struct cxd2841er_priv *priv, | 1750 | static int cxd2841er_read_snr_i(struct cxd2841er_priv *priv, u32 *snr) |
| 1395 | u8 delsys) | 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 | u8 data[2]; | 1799 | u8 data[2]; |
| 1398 | 1800 | ||
| 1399 | cxd2841er_write_reg( | 1801 | cxd2841er_write_reg( |
| 1400 | priv, I2C_SLVT, 0x00, (delsys == SYS_DVBT ? 0x10 : 0x20)); | 1802 | priv, I2C_SLVT, 0x00, (delsys == SYS_DVBT ? 0x10 : 0x20)); |
| 1401 | cxd2841er_read_regs(priv, I2C_SLVT, 0x26, data, 2); | 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 | return ((((u16)data[0] & 0x0F) << 8) | (u16)(data[1] & 0xFF)) << 4; | 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 | return ((((u16)data[0] & 0x1F) << 8) | (u16)(data[1] & 0xFF)) << 3; | 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 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 1844 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 1423 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 1845 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 1846 | u32 ret, bit_error = 0, bit_count = 0; | ||
| 1424 | 1847 | ||
| 1425 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 1848 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1426 | *ber = 0; | ||
| 1427 | switch (p->delivery_system) { | 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 | case SYS_DVBS: | 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 | break; | 1857 | break; |
| 1431 | case SYS_DVBS2: | 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 | break; | 1860 | break; |
| 1434 | case SYS_DVBT: | 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 | case SYS_DVBT2: | 1864 | case SYS_DVBT2: |
| 1437 | return cxd2841er_read_ber_t2(priv, ber); | 1865 | ret = cxd2841er_read_ber_t2(priv, &bit_error, &bit_count); |
| 1438 | default: | ||
| 1439 | *ber = 0; | ||
| 1440 | break; | 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, | 1884 | static void cxd2841er_read_signal_strength(struct dvb_frontend *fe) |
| 1446 | u16 *strength) | ||
| 1447 | { | 1885 | { |
| 1448 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 1886 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 1449 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 1887 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 1888 | s32 strength; | ||
| 1450 | 1889 | ||
| 1451 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 1890 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1452 | switch (p->delivery_system) { | 1891 | switch (p->delivery_system) { |
| 1453 | case SYS_DVBT: | 1892 | case SYS_DVBT: |
| 1454 | case SYS_DVBT2: | 1893 | case SYS_DVBT2: |
| 1455 | *strength = 65535 - cxd2841er_read_agc_gain_t_t2( | 1894 | strength = cxd2841er_read_agc_gain_t_t2(priv, |
| 1456 | priv, p->delivery_system); | 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 | break; | 1921 | break; |
| 1458 | case SYS_DVBS: | 1922 | case SYS_DVBS: |
| 1459 | case SYS_DVBS2: | 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 | break; | 1927 | break; |
| 1462 | default: | 1928 | default: |
| 1463 | *strength = 0; | 1929 | p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 1464 | break; | 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 | u32 tmp = 0; | 1936 | u32 tmp = 0; |
| 1937 | int ret = 0; | ||
| 1472 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 1938 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 1473 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 1939 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 1474 | 1940 | ||
| 1475 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 1941 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1476 | switch (p->delivery_system) { | 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 | case SYS_DVBT: | 1948 | case SYS_DVBT: |
| 1478 | cxd2841er_read_snr_t(priv, &tmp); | 1949 | ret = cxd2841er_read_snr_t(priv, &tmp); |
| 1479 | break; | 1950 | break; |
| 1480 | case SYS_DVBT2: | 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 | break; | 1956 | break; |
| 1483 | case SYS_DVBS: | 1957 | case SYS_DVBS: |
| 1484 | case SYS_DVBS2: | 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 | break; | 1960 | break; |
| 1487 | default: | 1961 | default: |
| 1488 | dev_dbg(&priv->i2c->dev, "%s(): unknown delivery system %d\n", | 1962 | dev_dbg(&priv->i2c->dev, "%s(): unknown delivery system %d\n", |
| 1489 | __func__, p->delivery_system); | 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 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 1978 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 1499 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 1979 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 1980 | u32 ucblocks; | ||
| 1500 | 1981 | ||
| 1501 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 1982 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1502 | switch (p->delivery_system) { | 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 | case SYS_DVBT: | 1989 | case SYS_DVBT: |
| 1504 | cxd2841er_read_packet_errors_t(priv, ucblocks); | 1990 | cxd2841er_read_packet_errors_t(priv, &ucblocks); |
| 1505 | break; | 1991 | break; |
| 1506 | case SYS_DVBT2: | 1992 | case SYS_DVBT2: |
| 1507 | cxd2841er_read_packet_errors_t2(priv, ucblocks); | 1993 | cxd2841er_read_packet_errors_t2(priv, &ucblocks); |
| 1508 | break; | 1994 | break; |
| 1509 | default: | 1995 | case SYS_ISDBT: |
| 1510 | *ucblocks = 0; | 1996 | cxd2841er_read_packet_errors_i(priv, &ucblocks); |
| 1511 | break; | 1997 | break; |
| 1998 | default: | ||
| 1999 | p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
| 2000 | return; | ||
| 1512 | } | 2001 | } |
| 1513 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 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 | static int cxd2841er_dvbt2_set_profile( | 2008 | static int cxd2841er_dvbt2_set_profile( |
| @@ -1524,15 +2015,18 @@ static int cxd2841er_dvbt2_set_profile( · 6 unmodified lines | |||
| 1524 | switch (profile) { | 2015 | switch (profile) { |
| 1525 | case DVBT2_PROFILE_BASE: | 2016 | case DVBT2_PROFILE_BASE: |
| 1526 | tune_mode = 0x01; | 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 | break; | 2020 | break; |
| 1529 | case DVBT2_PROFILE_LITE: | 2021 | case DVBT2_PROFILE_LITE: |
| 1530 | tune_mode = 0x05; | 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 | break; | 2025 | break; |
| 1533 | case DVBT2_PROFILE_ANY: | 2026 | case DVBT2_PROFILE_ANY: |
| 1534 | tune_mode = 0x00; | 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 | break; | 2030 | break; |
| 1537 | default: | 2031 | default: |
| 1538 | return -EINVAL; | 2032 | return -EINVAL; |
| @@ -1574,254 +2068,617 @@ static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv, · 35 unmodified lines | |||
| 1574 | u32 bandwidth) | 2068 | u32 bandwidth) |
| 1575 | { | 2069 | { |
| 1576 | u32 iffreq; | 2070 | u32 iffreq; |
| 1577 | u8 b20_9f[5]; | 2071 | u8 data[MAX_WRITE_REGSIZE]; |
| 1578 | u8 b10_a6[14]; | 2072 | |
| 1579 | u8 b10_b6[3]; | 2073 | const uint8_t nominalRate8bw[3][5] = { |
| 1580 | u8 b10_d7; | 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 | switch (bandwidth) { | 2156 | switch (bandwidth) { |
| 1584 | case 8000000: | 2157 | case 8000000: |
| 1585 | /* bank 0x20, reg 0x9f */ | 2158 | /* <Timing Recovery setting> */ |
| 1586 | b20_9f[0] = 0x11; | 2159 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1587 | b20_9f[1] = 0xf0; | 2160 | 0x9F, nominalRate8bw[priv->xtal], 5); |
| 1588 | b20_9f[2] = 0x00; | 2161 | |
| 1589 | b20_9f[3] = 0x00; | 2162 | /* Set SLV-T Bank : 0x27 */ |
| 1590 | b20_9f[4] = 0x00; | 2163 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); |
| 1591 | /* bank 0x10, reg 0xa6 */ | 2164 | cxd2841er_set_reg_bits(priv, I2C_SLVT, |
| 1592 | b10_a6[0] = 0x26; | 2165 | 0x7a, 0x00, 0x0f); |
| 1593 | b10_a6[1] = 0xaf; | 2166 | |
| 1594 | b10_a6[2] = 0x06; | 2167 | /* Set SLV-T Bank : 0x10 */ |
| 1595 | b10_a6[3] = 0xcd; | 2168 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
| 1596 | b10_a6[4] = 0x13; | 2169 | |
| 1597 | b10_a6[5] = 0xbb; | 2170 | /* Group delay equaliser settings for |
| 1598 | b10_a6[6] = 0x28; | 2171 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
| 1599 | b10_a6[7] = 0xba; | 2172 | */ |
| 1600 | b10_a6[8] = 0x23; | 2173 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1601 | b10_a6[9] = 0xa9; | 2174 | 0xA6, itbCoef8bw[priv->xtal], 14); |
| 1602 | b10_a6[10] = 0x1f; | 2175 | /* <IF freq setting> */ |
| 1603 | b10_a6[11] = 0xa8; | 2176 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.80); |
| 1604 | b10_a6[12] = 0x2c; | 2177 | data[0] = (u8) ((iffreq >> 16) & 0xff); |
| 1605 | b10_a6[13] = 0xc8; | 2178 | data[1] = (u8)((iffreq >> 8) & 0xff); |
| 1606 | iffreq = MAKE_IFFREQ_CONFIG(4.80); | 2179 | data[2] = (u8)(iffreq & 0xff); |
| 1607 | b10_d7 = 0x00; | 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 | break; | 2184 | break; |
| 1609 | case 7000000: | 2185 | case 7000000: |
| 1610 | /* bank 0x20, reg 0x9f */ | 2186 | /* <Timing Recovery setting> */ |
| 1611 | b20_9f[0] = 0x14; | 2187 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1612 | b20_9f[1] = 0x80; | 2188 | 0x9F, nominalRate7bw[priv->xtal], 5); |
| 1613 | b20_9f[2] = 0x00; | 2189 | |
| 1614 | b20_9f[3] = 0x00; | 2190 | /* Set SLV-T Bank : 0x27 */ |
| 1615 | b20_9f[4] = 0x00; | 2191 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); |
| 1616 | /* bank 0x10, reg 0xa6 */ | 2192 | cxd2841er_set_reg_bits(priv, I2C_SLVT, |
| 1617 | b10_a6[0] = 0x2C; | 2193 | 0x7a, 0x00, 0x0f); |
| 1618 | b10_a6[1] = 0xBD; | 2194 | |
| 1619 | b10_a6[2] = 0x02; | 2195 | /* Set SLV-T Bank : 0x10 */ |
| 1620 | b10_a6[3] = 0xCF; | 2196 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
| 1621 | b10_a6[4] = 0x04; | 2197 | |
| 1622 | b10_a6[5] = 0xF8; | 2198 | /* Group delay equaliser settings for |
| 1623 | b10_a6[6] = 0x23; | 2199 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
| 1624 | b10_a6[7] = 0xA6; | 2200 | */ |
| 1625 | b10_a6[8] = 0x29; | 2201 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1626 | b10_a6[9] = 0xB0; | 2202 | 0xA6, itbCoef7bw[priv->xtal], 14); |
| 1627 | b10_a6[10] = 0x26; | 2203 | /* <IF freq setting> */ |
| 1628 | b10_a6[11] = 0xA9; | 2204 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.20); |
| 1629 | b10_a6[12] = 0x21; | 2205 | data[0] = (u8) ((iffreq >> 16) & 0xff); |
| 1630 | b10_a6[13] = 0xA5; | 2206 | data[1] = (u8)((iffreq >> 8) & 0xff); |
| 1631 | iffreq = MAKE_IFFREQ_CONFIG(4.2); | 2207 | data[2] = (u8)(iffreq & 0xff); |
| 1632 | b10_d7 = 0x02; | 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 | break; | 2212 | break; |
| 1634 | case 6000000: | 2213 | case 6000000: |
| 1635 | /* bank 0x20, reg 0x9f */ | 2214 | /* <Timing Recovery setting> */ |
| 1636 | b20_9f[0] = 0x17; | 2215 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1637 | b20_9f[1] = 0xEA; | 2216 | 0x9F, nominalRate6bw[priv->xtal], 5); |
| 1638 | b20_9f[2] = 0xAA; | 2217 | |
| 1639 | b20_9f[3] = 0xAA; | 2218 | /* Set SLV-T Bank : 0x27 */ |
| 1640 | b20_9f[4] = 0xAA; | 2219 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); |
| 1641 | /* bank 0x10, reg 0xa6 */ | 2220 | cxd2841er_set_reg_bits(priv, I2C_SLVT, |
| 1642 | b10_a6[0] = 0x27; | 2221 | 0x7a, 0x00, 0x0f); |
| 1643 | b10_a6[1] = 0xA7; | 2222 | |
| 1644 | b10_a6[2] = 0x28; | 2223 | /* Set SLV-T Bank : 0x10 */ |
| 1645 | b10_a6[3] = 0xB3; | 2224 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
| 1646 | b10_a6[4] = 0x02; | 2225 | |
| 1647 | b10_a6[5] = 0xF0; | 2226 | /* Group delay equaliser settings for |
| 1648 | b10_a6[6] = 0x01; | 2227 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
| 1649 | b10_a6[7] = 0xE8; | 2228 | */ |
| 1650 | b10_a6[8] = 0x00; | 2229 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1651 | b10_a6[9] = 0xCF; | 2230 | 0xA6, itbCoef6bw[priv->xtal], 14); |
| 1652 | b10_a6[10] = 0x00; | 2231 | /* <IF freq setting> */ |
| 1653 | b10_a6[11] = 0xE6; | 2232 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.60); |
| 1654 | b10_a6[12] = 0x23; | 2233 | data[0] = (u8) ((iffreq >> 16) & 0xff); |
| 1655 | b10_a6[13] = 0xA4; | 2234 | data[1] = (u8)((iffreq >> 8) & 0xff); |
| 1656 | iffreq = MAKE_IFFREQ_CONFIG(3.6); | 2235 | data[2] = (u8)(iffreq & 0xff); |
| 1657 | b10_d7 = 0x04; | 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 | break; | 2240 | break; |
| 1659 | case 5000000: | 2241 | case 5000000: |
| 1660 | /* bank 0x20, reg 0x9f */ | 2242 | /* <Timing Recovery setting> */ |
| 1661 | b20_9f[0] = 0x1C; | 2243 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1662 | b20_9f[1] = 0xB3; | 2244 | 0x9F, nominalRate5bw[priv->xtal], 5); |
| 1663 | b20_9f[2] = 0x33; | 2245 | |
| 1664 | b20_9f[3] = 0x33; | 2246 | /* Set SLV-T Bank : 0x27 */ |
| 1665 | b20_9f[4] = 0x33; | 2247 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); |
| 1666 | /* bank 0x10, reg 0xa6 */ | 2248 | cxd2841er_set_reg_bits(priv, I2C_SLVT, |
| 1667 | b10_a6[0] = 0x27; | 2249 | 0x7a, 0x00, 0x0f); |
| 1668 | b10_a6[1] = 0xA7; | 2250 | |
| 1669 | b10_a6[2] = 0x28; | 2251 | /* Set SLV-T Bank : 0x10 */ |
| 1670 | b10_a6[3] = 0xB3; | 2252 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
| 1671 | b10_a6[4] = 0x02; | 2253 | |
| 1672 | b10_a6[5] = 0xF0; | 2254 | /* Group delay equaliser settings for |
| 1673 | b10_a6[6] = 0x01; | 2255 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
| 1674 | b10_a6[7] = 0xE8; | 2256 | */ |
| 1675 | b10_a6[8] = 0x00; | 2257 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1676 | b10_a6[9] = 0xCF; | 2258 | 0xA6, itbCoef5bw[priv->xtal], 14); |
| 1677 | b10_a6[10] = 0x00; | 2259 | /* <IF freq setting> */ |
| 1678 | b10_a6[11] = 0xE6; | 2260 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.60); |
| 1679 | b10_a6[12] = 0x23; | 2261 | data[0] = (u8) ((iffreq >> 16) & 0xff); |
| 1680 | b10_a6[13] = 0xA4; | 2262 | data[1] = (u8)((iffreq >> 8) & 0xff); |
| 1681 | iffreq = MAKE_IFFREQ_CONFIG(3.6); | 2263 | data[2] = (u8)(iffreq & 0xff); |
| 1682 | b10_d7 = 0x06; | 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 | break; | 2268 | break; |
| 1684 | case 1712000: | 2269 | case 1712000: |
| 1685 | /* bank 0x20, reg 0x9f */ | 2270 | /* <Timing Recovery setting> */ |
| 1686 | b20_9f[0] = 0x58; | 2271 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1687 | b20_9f[1] = 0xE2; | 2272 | 0x9F, nominalRate17bw[priv->xtal], 5); |
| 1688 | b20_9f[2] = 0xAF; | 2273 | |
| 1689 | b20_9f[3] = 0xE0; | 2274 | /* Set SLV-T Bank : 0x27 */ |
| 1690 | b20_9f[4] = 0xBC; | 2275 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); |
| 1691 | /* bank 0x10, reg 0xa6 */ | 2276 | cxd2841er_set_reg_bits(priv, I2C_SLVT, |
| 1692 | b10_a6[0] = 0x25; | 2277 | 0x7a, 0x03, 0x0f); |
| 1693 | b10_a6[1] = 0xA0; | 2278 | |
| 1694 | b10_a6[2] = 0x36; | 2279 | /* Set SLV-T Bank : 0x10 */ |
| 1695 | b10_a6[3] = 0x8D; | 2280 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
| 1696 | b10_a6[4] = 0x2E; | 2281 | |
| 1697 | b10_a6[5] = 0x94; | 2282 | /* Group delay equaliser settings for |
| 1698 | b10_a6[6] = 0x28; | 2283 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
| 1699 | b10_a6[7] = 0x9B; | 2284 | */ |
| 1700 | b10_a6[8] = 0x32; | 2285 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1701 | b10_a6[9] = 0x90; | 2286 | 0xA6, itbCoef17bw[priv->xtal], 14); |
| 1702 | b10_a6[10] = 0x2C; | 2287 | /* <IF freq setting> */ |
| 1703 | b10_a6[11] = 0x9D; | 2288 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.50); |
| 1704 | b10_a6[12] = 0x29; | 2289 | data[0] = (u8) ((iffreq >> 16) & 0xff); |
| 1705 | b10_a6[13] = 0x99; | 2290 | data[1] = (u8)((iffreq >> 8) & 0xff); |
| 1706 | iffreq = MAKE_IFFREQ_CONFIG(3.5); | 2291 | data[2] = (u8)(iffreq & 0xff); |
| 1707 | b10_d7 = 0x03; | 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 | break; | 2296 | break; |
| 1709 | default: | 2297 | default: |
| 1710 | return -EINVAL; | 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 | return 0; | 2300 | return 0; |
| 1732 | } | 2301 | } |
| 1733 | 2302 | ||
| 1734 | static int cxd2841er_sleep_tc_to_active_t_band( | 2303 | static int cxd2841er_sleep_tc_to_active_t_band( |
| 1735 | struct cxd2841er_priv *priv, u32 bandwidth) | 2304 | struct cxd2841er_priv *priv, u32 bandwidth) |
| 1736 | { | 2305 | { |
| 1737 | u8 b13_9c[2] = { 0x01, 0x14 }; | 2306 | u8 data[MAX_WRITE_REGSIZE]; |
| 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; | ||
| 1760 | u32 iffreq; | 2307 | u32 iffreq; |
| 1761 | u8 *b10_9f; | 2308 | u8 nominalRate8bw[3][5] = { |
| 1762 | u8 *b10_a6; | 2309 | /* TRCG Nominal Rate [37:0] */ |
| 1763 | u8 *b10_d9; | 2310 | {0x11, 0xF0, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ |
| 1764 | u8 *b17_38; | 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 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x13); | 2367 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x13); |
| 1768 | /* Echo performance optimization setting */ | 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 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | 2374 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
| 1771 | 2375 | ||
| 1772 | switch (bandwidth) { | 2376 | switch (bandwidth) { |
| 1773 | case 8000000: | 2377 | case 8000000: |
| 1774 | b10_9f = bw8mhz_b10_9f; | 2378 | /* <Timing Recovery setting> */ |
| 1775 | b10_a6 = bw8mhz_b10_a6; | 2379 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1776 | b10_d9 = bw8mhz_b10_d9; | 2380 | 0x9F, nominalRate8bw[priv->xtal], 5); |
| 1777 | b17_38 = bw8mhz_b17_38; | 2381 | /* Group delay equaliser settings for |
| 1778 | d7val = 0; | 2382 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
| 1779 | iffreq = MAKE_IFFREQ_CONFIG(4.80); | 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 | break; | 2411 | break; |
| 1781 | case 7000000: | 2412 | case 7000000: |
| 1782 | b10_9f = bw7mhz_b10_9f; | 2413 | /* <Timing Recovery setting> */ |
| 1783 | b10_a6 = bw7mhz_b10_a6; | 2414 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1784 | b10_d9 = bw7mhz_b10_d9; | 2415 | 0x9F, nominalRate7bw[priv->xtal], 5); |
| 1785 | b17_38 = bw7mhz_b17_38; | 2416 | /* Group delay equaliser settings for |
| 1786 | d7val = 2; | 2417 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
| 1787 | iffreq = MAKE_IFFREQ_CONFIG(4.20); | 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 | break; | 2446 | break; |
| 1789 | case 6000000: | 2447 | case 6000000: |
| 1790 | b10_9f = bw6mhz_b10_9f; | 2448 | /* <Timing Recovery setting> */ |
| 1791 | b10_a6 = bw6mhz_b10_a6; | 2449 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1792 | b10_d9 = bw6mhz_b10_d9; | 2450 | 0x9F, nominalRate6bw[priv->xtal], 5); |
| 1793 | b17_38 = bw6mhz_b17_38; | 2451 | /* Group delay equaliser settings for |
| 1794 | d7val = 4; | 2452 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
| 1795 | iffreq = MAKE_IFFREQ_CONFIG(3.60); | 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 | break; | 2481 | break; |
| 1797 | case 5000000: | 2482 | case 5000000: |
| 1798 | b10_9f = bw5mhz_b10_9f; | 2483 | /* <Timing Recovery setting> */ |
| 1799 | b10_a6 = bw5mhz_b10_a6; | 2484 | cxd2841er_write_regs(priv, I2C_SLVT, |
| 1800 | b10_d9 = bw5mhz_b10_d9; | 2485 | 0x9F, nominalRate5bw[priv->xtal], 5); |
| 1801 | b17_38 = bw5mhz_b17_38; | 2486 | /* Group delay equaliser settings for |
| 1802 | d7val = 6; | 2487 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
| 1803 | iffreq = MAKE_IFFREQ_CONFIG(3.60); | 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 | break; | 2676 | break; |
| 1805 | default: | 2677 | default: |
| 1806 | dev_dbg(&priv->i2c->dev, "%s(): invalid bandwidth %d\n", | 2678 | dev_dbg(&priv->i2c->dev, "%s(): invalid bandwidth %d\n", |
| 1807 | __func__, bandwidth); | 2679 | __func__, bandwidth); |
| 1808 | return -EINVAL; | 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 | return 0; | 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 | u8 b10_b6[3]; | 2694 | u8 b10_b6[3]; |
| 1838 | u32 iffreq; | 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 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | 2698 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
| 1842 | switch (bandwidth) { | 2699 | switch (bandwidth) { |
| 1843 | case 8000000: | 2700 | case 8000000: |
| @@ -1854,7 +2711,7 @@ static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv, · 10 unmodified lines | |||
| 1854 | iffreq = MAKE_IFFREQ_CONFIG(3.7); | 2711 | iffreq = MAKE_IFFREQ_CONFIG(3.7); |
| 1855 | break; | 2712 | break; |
| 1856 | default: | 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 | __func__, bandwidth); | 2715 | __func__, bandwidth); |
| 1859 | return -EINVAL; | 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 | u32 bandwidth) | 2759 | u32 bandwidth) |
| 1903 | { | 2760 | { |
| 1904 | u8 data[2] = { 0x09, 0x54 }; | 2761 | u8 data[2] = { 0x09, 0x54 }; |
| 2762 | u8 data24m[3] = {0xDC, 0x6C, 0x00}; | ||
| 1905 | 2763 | ||
| 1906 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 2764 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1907 | cxd2841er_set_ts_clock_mode(priv, SYS_DVBT); | 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 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); | 2777 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); |
| 1920 | /* Enable ADC 1 */ | 2778 | /* Enable ADC 1 */ |
| 1921 | cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a); | 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 | cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2); | 2785 | cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2); |
| 1924 | /* Enable ADC 4 */ | 2786 | /* Enable ADC 4 */ |
| 1925 | cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00); | 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 | /* TSIF setting */ | 2809 | /* TSIF setting */ |
| 1948 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01); | 2810 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01); |
| 1949 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01); | 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 | cxd2841er_sleep_tc_to_active_t_band(priv, bandwidth); | 2821 | cxd2841er_sleep_tc_to_active_t_band(priv, bandwidth); |
| 1951 | /* Set SLV-T Bank : 0x00 */ | 2822 | /* Set SLV-T Bank : 0x00 */ |
| 1952 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | 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 | static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, | 2832 | static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, |
| 1962 | u32 bandwidth) | 2833 | u32 bandwidth) |
| 1963 | { | 2834 | { |
| 1964 | u8 data[2] = { 0x09, 0x54 }; | 2835 | u8 data[MAX_WRITE_REGSIZE]; |
| 1965 | 2836 | ||
| 1966 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 2837 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 1967 | cxd2841er_set_ts_clock_mode(priv, SYS_DVBT2); | 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 | /* Enable demod clock */ | 2845 | /* Enable demod clock */ |
| 1975 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01); | 2846 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01); |
| 1976 | /* Disable RF level monitor */ | 2847 | /* Disable RF level monitor */ |
| 2848 | cxd2841er_write_reg(priv, I2C_SLVT, 0x59, 0x00); | ||
| 1977 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00); | 2849 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00); |
| 1978 | /* Enable ADC clock */ | 2850 | /* Enable ADC clock */ |
| 1979 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); | 2851 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); |
| 1980 | /* Enable ADC 1 */ | 2852 | /* Enable ADC 1 */ |
| 1981 | cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a); | 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 | cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2); | 2863 | cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2); |
| 1984 | /* Enable ADC 4 */ | 2864 | /* Enable ADC 4 */ |
| 1985 | cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00); | 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 | /* Set SLV-T Bank : 0x2b */ | 2882 | /* Set SLV-T Bank : 0x2b */ |
| 2003 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b); | 2883 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b); |
| 2004 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x76, 0x20, 0x70); | 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 | /* Set SLV-T Bank : 0x00 */ | 2889 | /* Set SLV-T Bank : 0x00 */ |
| 2006 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | 2890 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); |
| 2007 | /* TSIF setting */ | 2891 | /* TSIF setting */ |
| @@ -2020,6 +2904,72 @@ static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, · 12 unmodified lines | |||
| 2020 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b); | 2904 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b); |
| 2021 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x11, 0x20, 0x3f); | 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 | cxd2841er_sleep_tc_to_active_t2_band(priv, bandwidth); | 2973 | cxd2841er_sleep_tc_to_active_t2_band(priv, bandwidth); |
| 2024 | 2974 | ||
| 2025 | /* Set SLV-T Bank : 0x00 */ | 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 | return 0; | 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 | static int cxd2841er_sleep_tc_to_active_c(struct cxd2841er_priv *priv, | 3063 | static int cxd2841er_sleep_tc_to_active_c(struct cxd2841er_priv *priv, |
| 2036 | u32 bandwidth) | 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 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01); | 3107 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01); |
| 2080 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01); | 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 | /* Set SLV-T Bank : 0x00 */ | 3111 | /* Set SLV-T Bank : 0x00 */ |
| 2084 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | 3112 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); |
| 2085 | /* Disable HiZ Setting 1 */ | 3113 | /* Disable HiZ Setting 1 */ |
| @@ -2094,8 +3122,6 @@ static int cxd2841er_get_frontend(struct dvb_frontend *fe, · 8 unmodified lines | |||
| 2094 | struct dtv_frontend_properties *p) | 3122 | struct dtv_frontend_properties *p) |
| 2095 | { | 3123 | { |
| 2096 | enum fe_status status = 0; | 3124 | enum fe_status status = 0; |
| 2097 | u16 strength = 0, snr = 0; | ||
| 2098 | u32 errors = 0, ber = 0; | ||
| 2099 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 3125 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 2100 | 3126 | ||
| 2101 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 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 | else if (priv->state == STATE_ACTIVE_TC) | 3130 | else if (priv->state == STATE_ACTIVE_TC) |
| 2105 | cxd2841er_read_status_tc(fe, &status); | 3131 | cxd2841er_read_status_tc(fe, &status); |
| 2106 | 3132 | ||
| 3133 | cxd2841er_read_signal_strength(fe); | ||
| 3134 | |||
| 2107 | if (status & FE_HAS_LOCK) { | 3135 | if (status & FE_HAS_LOCK) { |
| 2108 | cxd2841er_read_signal_strength(fe, &strength); | 3136 | cxd2841er_read_snr(fe); |
| 2109 | p->strength.len = 1; | 3137 | cxd2841er_read_ucblocks(fe); |
| 2110 | p->strength.stat[0].scale = FE_SCALE_RELATIVE; | 3138 | |
| 2111 | p->strength.stat[0].uvalue = strength; | 3139 | cxd2841er_read_ber(fe); |
| 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; | ||
| 2124 | } else { | 3140 | } else { |
| 2125 | p->strength.len = 1; | ||
| 2126 | p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
| 2127 | p->cnr.len = 1; | ||
| 2128 | p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 3141 | p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 2129 | p->block_error.len = 1; | ||
| 2130 | p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 3142 | p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 2131 | p->post_bit_error.len = 1; | ||
| 2132 | p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 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 | return 0; | 3146 | return 0; |
| 2135 | } | 3147 | } |
| @@ -2142,10 +3154,10 @@ static int cxd2841er_set_frontend_s(struct dvb_frontend *fe) · 6 unmodified lines | |||
| 2142 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 3154 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
| 2143 | u32 symbol_rate = p->symbol_rate/1000; | 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 | __func__, | 3158 | __func__, |
| 2147 | (p->delivery_system == SYS_DVBS ? "DVB-S" : "DVB-S2"), | 3159 | (p->delivery_system == SYS_DVBS ? "DVB-S" : "DVB-S2"), |
| 2148 | p->frequency, symbol_rate); | 3160 | p->frequency, symbol_rate, priv->xtal); |
| 2149 | switch (priv->state) { | 3161 | switch (priv->state) { |
| 2150 | case STATE_SLEEP_S: | 3162 | case STATE_SLEEP_S: |
| 2151 | ret = cxd2841er_sleep_s_to_active_s( | 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 | __func__, carr_offset); | 3201 | __func__, carr_offset); |
| 2190 | } | 3202 | } |
| 2191 | done: | 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 | return ret; | 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 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 3218 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 2200 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 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 | if (p->delivery_system == SYS_DVBT) { | 3223 | if (p->delivery_system == SYS_DVBT) { |
| 2204 | priv->system = SYS_DVBT; | 3224 | priv->system = SYS_DVBT; |
| 2205 | switch (priv->state) { | 3225 | switch (priv->state) { |
| @@ -2233,9 +3253,33 @@ static int cxd2841er_set_frontend_tc(struct dvb_frontend *fe) · 27 unmodified lines | |||
| 2233 | __func__, priv->state); | 3253 | __func__, priv->state); |
| 2234 | ret = -EINVAL; | 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 | } else if (p->delivery_system == SYS_DVBC_ANNEX_A || | 3271 | } else if (p->delivery_system == SYS_DVBC_ANNEX_A || |
| 2237 | p->delivery_system == SYS_DVBC_ANNEX_C) { | 3272 | p->delivery_system == SYS_DVBC_ANNEX_C) { |
| 2238 | priv->system = SYS_DVBC_ANNEX_A; | 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 | switch (priv->state) { | 3283 | switch (priv->state) { |
| 2240 | case STATE_SLEEP_TC: | 3284 | case STATE_SLEEP_TC: |
| 2241 | ret = cxd2841er_sleep_tc_to_active_c( | 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 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 3365 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
| 2322 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 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 | if (re_tune) { | 3370 | if (re_tune) { |
| 2326 | ret = cxd2841er_set_frontend_tc(fe); | 3371 | ret = cxd2841er_set_frontend_tc(fe); |
| 2327 | if (ret) | 3372 | if (ret) |
| @@ -2329,7 +3374,16 @@ static int cxd2841er_tune_tc(struct dvb_frontend *fe, · 1 unmodified line | |||
| 2329 | cxd2841er_read_status_tc(fe, status); | 3374 | cxd2841er_read_status_tc(fe, status); |
| 2330 | if (*status & FE_HAS_LOCK) { | 3375 | if (*status & FE_HAS_LOCK) { |
| 2331 | switch (priv->system) { | 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 | case SYS_DVBT: | 3382 | case SYS_DVBT: |
| 3383 | ret = cxd2841er_get_carrier_offset_t( | ||
| 3384 | priv, p->bandwidth_hz, | ||
| 3385 | &carrier_offset); | ||
| 3386 | break; | ||
| 2333 | case SYS_DVBT2: | 3387 | case SYS_DVBT2: |
| 2334 | ret = cxd2841er_get_carrier_offset_t2( | 3388 | ret = cxd2841er_get_carrier_offset_t2( |
| 2335 | priv, p->bandwidth_hz, | 3389 | priv, p->bandwidth_hz, |
| @@ -2382,6 +3436,9 @@ static int cxd2841er_sleep_tc(struct dvb_frontend *fe) · 46 unmodified lines | |||
| 2382 | case SYS_DVBT2: | 3436 | case SYS_DVBT2: |
| 2383 | cxd2841er_active_t2_to_sleep_tc(priv); | 3437 | cxd2841er_active_t2_to_sleep_tc(priv); |
| 2384 | break; | 3438 | break; |
| 3439 | case SYS_ISDBT: | ||
| 3440 | cxd2841er_active_i_to_sleep_tc(priv); | ||
| 3441 | break; | ||
| 2385 | case SYS_DVBC_ANNEX_A: | 3442 | case SYS_DVBC_ANNEX_A: |
| 2386 | cxd2841er_active_c_to_sleep_tc(priv); | 3443 | cxd2841er_active_c_to_sleep_tc(priv); |
| 2387 | break; | 3444 | break; |
| @@ -2512,23 +3569,57 @@ static enum dvbfe_algo cxd2841er_get_algo(struct dvb_frontend *fe) · 124 unmodified lines | |||
| 2512 | return DVBFE_ALGO_HW; | 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 | static int cxd2841er_init_s(struct dvb_frontend *fe) | 3589 | static int cxd2841er_init_s(struct dvb_frontend *fe) |
| 2516 | { | 3590 | { |
| 2517 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 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 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 3605 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
| 2520 | cxd2841er_shutdown_to_sleep_s(priv); | 3606 | cxd2841er_shutdown_to_sleep_s(priv); |
| 2521 | /* SONY_DEMOD_CONFIG_SAT_IFAGCNEG set to 1 */ | 3607 | /* SONY_DEMOD_CONFIG_SAT_IFAGCNEG set to 1 */ |
| 2522 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0); | 3608 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0); |
| 2523 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xb9, 0x01, 0x01); | 3609 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xb9, 0x01, 0x01); |
| 3610 | |||
| 3611 | cxd2841er_init_stats(fe); | ||
| 3612 | |||
| 2524 | return 0; | 3613 | return 0; |
| 2525 | } | 3614 | } |
| 2526 | 3615 | ||
| 2527 | static int cxd2841er_init_tc(struct dvb_frontend *fe) | 3616 | static int cxd2841er_init_tc(struct dvb_frontend *fe) |
| 2528 | { | 3617 | { |
| 2529 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 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 | cxd2841er_shutdown_to_sleep_tc(priv); | 3623 | cxd2841er_shutdown_to_sleep_tc(priv); |
| 2533 | /* SONY_DEMOD_CONFIG_IFAGCNEG = 1 */ | 3624 | /* SONY_DEMOD_CONFIG_IFAGCNEG = 1 */ |
| 2534 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | 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 | /* SONY_DEMOD_CONFIG_PARALLEL_SEL = 1 */ | 3629 | /* SONY_DEMOD_CONFIG_PARALLEL_SEL = 1 */ |
| 2539 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | 3630 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); |
| 2540 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xc4, 0x00, 0x80); | 3631 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xc4, 0x00, 0x80); |
| 3632 | |||
| 3633 | cxd2841er_init_stats(fe); | ||
| 3634 | |||
| 2541 | return 0; | 3635 | return 0; |
| 2542 | } | 3636 | } |
| 2543 | 3637 | ||
| 2544 | static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops; | 3638 | static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops; |
| 2545 | static struct dvb_frontend_ops cxd2841er_dvbt_t2_ops; | 3639 | static struct dvb_frontend_ops cxd2841er_t_c_ops; |
| 2546 | static struct dvb_frontend_ops cxd2841er_dvbc_ops; | ||
| 2547 | 3640 | ||
| 2548 | static struct dvb_frontend *cxd2841er_attach(struct cxd2841er_config *cfg, | 3641 | static struct dvb_frontend *cxd2841er_attach(struct cxd2841er_config *cfg, |
| 2549 | struct i2c_adapter *i2c, | 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 | u8 chip_id = 0; | 3645 | u8 chip_id = 0; |
| 2553 | const char *type; | 3646 | const char *type; |
| 3647 | const char *name; | ||
| 2554 | struct cxd2841er_priv *priv = NULL; | 3648 | struct cxd2841er_priv *priv = NULL; |
| 2555 | 3649 | ||
| 2556 | /* allocate memory for the internal state */ | 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 | priv->config = cfg; | 3655 | priv->config = cfg; |
| 2562 | priv->i2c_addr_slvx = (cfg->i2c_addr + 4) >> 1; | 3656 | priv->i2c_addr_slvx = (cfg->i2c_addr + 4) >> 1; |
| 2563 | priv->i2c_addr_slvt = (cfg->i2c_addr) >> 1; | 3657 | priv->i2c_addr_slvt = (cfg->i2c_addr) >> 1; |
| 2564 | /* create dvb_frontend */ | 3658 | priv->xtal = cfg->xtal; |
| 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 | } | ||
| 2588 | priv->frontend.demodulator_priv = priv; | 3659 | priv->frontend.demodulator_priv = priv; |
| 2589 | dev_info(&priv->i2c->dev, | ||
| 2590 | "%s(): attaching CXD2841ER DVB-%s frontend\n", | ||
| 2591 | __func__, type); | ||
| 2592 | dev_info(&priv->i2c->dev, | 3660 | dev_info(&priv->i2c->dev, |
| 2593 | "%s(): I2C adapter %p SLVX addr %x SLVT addr %x\n", | 3661 | "%s(): I2C adapter %p SLVX addr %x SLVT addr %x\n", |
| 2594 | __func__, priv->i2c, | 3662 | __func__, priv->i2c, |
| 2595 | priv->i2c_addr_slvx, priv->i2c_addr_slvt); | 3663 | priv->i2c_addr_slvx, priv->i2c_addr_slvt); |
| 2596 | chip_id = cxd2841er_chip_id(priv); | 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 | dev_err(&priv->i2c->dev, "%s(): invalid chip ID 0x%02x\n", | 3678 | dev_err(&priv->i2c->dev, "%s(): invalid chip ID 0x%02x\n", |
| 2599 | __func__, chip_id); | 3679 | __func__, chip_id); |
| 2600 | priv->frontend.demodulator_priv = NULL; | 3680 | priv->frontend.demodulator_priv = NULL; |
| 2601 | kfree(priv); | 3681 | kfree(priv); |
| 2602 | return NULL; | 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 | dev_info(&priv->i2c->dev, "%s(): chip ID 0x%02x OK.\n", | 3701 | dev_info(&priv->i2c->dev, "%s(): chip ID 0x%02x OK.\n", |
| 2605 | __func__, chip_id); | 3702 | __func__, chip_id); |
| 2606 | return &priv->frontend; | 3703 | return &priv->frontend; |
| @@ -2613,19 +3710,12 @@ struct dvb_frontend *cxd2841er_attach_s(struct cxd2841er_config *cfg, · 6 unmodified lines | |||
| 2613 | } | 3710 | } |
| 2614 | EXPORT_SYMBOL(cxd2841er_attach_s); | 3711 | EXPORT_SYMBOL(cxd2841er_attach_s); |
| 2615 | 3712 | ||
| 2616 | struct dvb_frontend *cxd2841er_attach_t(struct cxd2841er_config *cfg, | 3713 | struct dvb_frontend *cxd2841er_attach_t_c(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, | ||
| 2624 | struct i2c_adapter *i2c) | 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 | static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = { | 3720 | static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = { |
| 2631 | .delsys = { SYS_DVBS, SYS_DVBS2 }, | 3721 | .delsys = { SYS_DVBS, SYS_DVBS2 }, |
| @@ -2655,10 +3745,10 @@ static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = { · 23 unmodified lines | |||
| 2655 | .tune = cxd2841er_tune_s | 3745 | .tune = cxd2841er_tune_s |
| 2656 | }; | 3746 | }; |
| 2657 | 3747 | ||
| 2658 | static struct dvb_frontend_ops cxd2841er_dvbt_t2_ops = { | 3748 | static struct dvb_frontend_ops cxd2841er_t_c_ops = { |
| 2659 | .delsys = { SYS_DVBT, SYS_DVBT2 }, | 3749 | .delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A }, |
| 2660 | .info = { | 3750 | .info = { |
| 2661 | .name = "Sony CXD2841ER DVB-T/T2 demodulator", | 3751 | .name = "", /* will set in attach function */ |
| 2662 | .caps = FE_CAN_FEC_1_2 | | 3752 | .caps = FE_CAN_FEC_1_2 | |
| 2663 | FE_CAN_FEC_2_3 | | 3753 | FE_CAN_FEC_2_3 | |
| 2664 | FE_CAN_FEC_3_4 | | 3754 | FE_CAN_FEC_3_4 | |
| @@ -2691,37 +3781,6 @@ static struct dvb_frontend_ops cxd2841er_dvbt_t2_ops = { · 26 unmodified lines | |||
| 2691 | .get_frontend_algo = cxd2841er_get_algo | 3781 | .get_frontend_algo = cxd2841er_get_algo |
| 2692 | }; | 3782 | }; |
| 2693 | 3783 | ||
| 2694 | static struct dvb_frontend_ops cxd2841er_dvbc_ops = { | 3784 | MODULE_DESCRIPTION("Sony CXD2841ER/CXD2854ER DVB-C/C2/T/T2/S/S2 demodulator driver"); |
| 2695 | .delsys = { SYS_DVBC_ANNEX_A }, | 3785 | MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>, Abylay Ospan <aospan@netup.ru>"); |
| 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>"); | ||
| 2727 | MODULE_LICENSE("GPL"); | 3786 | MODULE_LICENSE("GPL"); |
| @@ -25,41 +25,39 @@ · 24 unmodified lines | |||
| 25 | #include <linux/kconfig.h> | 25 | #include <linux/kconfig.h> |
| 26 | #include <linux/dvb/frontend.h> | 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 | struct cxd2841er_config { | 34 | struct cxd2841er_config { |
| 29 | u8 i2c_addr; | 35 | u8 i2c_addr; |
| 36 | enum cxd2841er_xtal xtal; | ||
| 30 | }; | 37 | }; |
| 31 | 38 | ||
| 32 | #if IS_REACHABLE(CONFIG_DVB_CXD2841ER) | 39 | #if IS_REACHABLE(CONFIG_DVB_CXD2841ER) |
| 33 | extern struct dvb_frontend *cxd2841er_attach_s(struct cxd2841er_config *cfg, | 40 | extern struct dvb_frontend *cxd2841er_attach_s(struct cxd2841er_config *cfg, |
| 34 | struct i2c_adapter *i2c); | 41 | struct i2c_adapter *i2c); |
| 35 | 42 | ||
| 36 | extern struct dvb_frontend *cxd2841er_attach_t(struct cxd2841er_config *cfg, | 43 | extern struct dvb_frontend *cxd2841er_attach_t_c(struct cxd2841er_config *cfg, |
| 37 | struct i2c_adapter *i2c); | ||
| 38 | |||
| 39 | extern struct dvb_frontend *cxd2841er_attach_c(struct cxd2841er_config *cfg, | ||
| 40 | struct i2c_adapter *i2c); | 44 | struct i2c_adapter *i2c); |
| 41 | #else | 45 | #else |
| 42 | static inline struct dvb_frontend *cxd2841er_attach_s( | 46 | static inline struct dvb_frontend *cxd2841er_attach_s( |
| 43 | struct cxd2841er_config *cfg, | 47 | struct cxd2841er_config *cfg, |
| 44 | struct i2c_adapter *i2c) | 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 | return NULL; | 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 | struct cxd2841er_config *cfg, struct i2c_adapter *i2c) | 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 | return NULL; | 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 | #endif | 61 | #endif |
| 64 | 62 | ||
| 65 | #endif | 63 | #endif |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | |||
| 26 | #define I2C_SLVT 1 | 26 | #define I2C_SLVT 1 |
| 27 | 27 | ||
| 28 | #define CXD2841ER_CHIP_ID 0xa7 | 28 | #define CXD2841ER_CHIP_ID 0xa7 |
| 29 | #define CXD2854ER_CHIP_ID 0xc1 | ||
| 29 | 30 | ||
| 30 | #define CXD2841ER_DVBS_POLLING_INVL 10 | 31 | #define CXD2841ER_DVBS_POLLING_INVL 10 |
| 31 | 32 | ||
| @@ -797,6 +797,8 @@ static const u16 bb_ramp_pwm_normal[] = { · 796 unmodified lines | |||
| 797 | (0 << 9) | 400, /* BB_RAMP6 */ | 797 | (0 << 9) | 400, /* BB_RAMP6 */ |
| 798 | }; | 798 | }; |
| 799 | 799 | ||
| 800 | #if 0 | ||
| 801 | /* Currently unused */ | ||
| 800 | static const u16 bb_ramp_pwm_boost[] = { | 802 | static const u16 bb_ramp_pwm_boost[] = { |
| 801 | 550, /* max BB gain in 10th of dB */ | 803 | 550, /* max BB gain in 10th of dB */ |
| 802 | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */ | 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 | (2 << 9) | 208, /* BB_RAMP5 = 29dB */ | 808 | (2 << 9) | 208, /* BB_RAMP5 = 29dB */ |
| 807 | (0 << 9) | 440, /* BB_RAMP6 */ | 809 | (0 << 9) | 440, /* BB_RAMP6 */ |
| 808 | }; | 810 | }; |
| 811 | #endif | ||
| 809 | 812 | ||
| 810 | static const u16 rf_ramp_pwm_cband[] = { | 813 | static const u16 rf_ramp_pwm_cband[] = { |
| 811 | 314, /* max RF gain in 10th of dB */ | 814 | 314, /* max RF gain in 10th of dB */ |
| @@ -849,6 +852,8 @@ static const u16 rf_ramp_pwm_uhf[] = { · 37 unmodified lines | |||
| 849 | (0 << 10) | 580, /* GAIN_4_2, LNA 4 */ | 852 | (0 << 10) | 580, /* GAIN_4_2, LNA 4 */ |
| 850 | }; | 853 | }; |
| 851 | 854 | ||
| 855 | #if 0 | ||
| 856 | /* Currently unused */ | ||
| 852 | static const u16 rf_ramp_pwm_sband[] = { | 857 | static const u16 rf_ramp_pwm_sband[] = { |
| 853 | 253, /* max RF gain in 10th of dB */ | 858 | 253, /* max RF gain in 10th of dB */ |
| 854 | 38, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ | 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 | (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */ | 867 | (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */ |
| 863 | (0 << 10) | 0, /* GAIN_4_2, LNA 4 */ | 868 | (0 << 10) | 0, /* GAIN_4_2, LNA 4 */ |
| 864 | }; | 869 | }; |
| 870 | #endif | ||
| 865 | 871 | ||
| 866 | struct slope { | 872 | struct slope { |
| 867 | s16 range; | 873 | s16 range; |
| @@ -1240,12 +1240,15 @@ static u32 frac_times1e6(u32 N, u32 D) · 1239 unmodified lines | |||
| 1240 | * and rounded. For calc used formula: 16*10^(prescaleGain[dB]/20). | 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 | static const u16 nicam_presc_table_val[43] = { | 1245 | static const u16 nicam_presc_table_val[43] = { |
| 1244 | 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, | 1246 | 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, |
| 1245 | 5, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16, | 1247 | 5, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16, |
| 1246 | 18, 20, 23, 25, 28, 32, 36, 40, 45, | 1248 | 18, 20, 23, 25, 28, 32, 36, 40, 45, |
| 1247 | 51, 57, 64, 71, 80, 90, 101, 113, 127 | 1249 | 51, 57, 64, 71, 80, 90, 101, 113, 127 |
| 1248 | }; | 1250 | }; |
| 1251 | #endif | ||
| 1249 | 1252 | ||
| 1250 | /*============================================================================*/ | 1253 | /*============================================================================*/ |
| 1251 | /*== END HELPER FUNCTIONS ==*/ | 1254 | /*== END HELPER FUNCTIONS ==*/ |
| @@ -959,6 +959,15 @@ static int ds3000_set_frontend(struct dvb_frontend *fe) · 958 unmodified lines | |||
| 959 | /* enable ac coupling */ | 959 | /* enable ac coupling */ |
| 960 | ds3000_writereg(state, 0x25, 0x8a); | 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 | /* enhance symbol rate performance */ | 971 | /* enhance symbol rate performance */ |
| 963 | if ((c->symbol_rate / 1000) <= 5000) { | 972 | if ((c->symbol_rate / 1000) <= 5000) { |
| 964 | value = 29777 / (c->symbol_rate / 1000) + 1; | 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 | dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n", | 70 | dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n", |
| 71 | reg, len + 1); | 71 | reg, len + 1); |
| 72 | return -E2BIG; | 72 | return -E2BIG; |
| @@ -272,24 +272,6 @@ static int horus3a_set_params(struct dvb_frontend *fe) · 199 unmodified lines | |||
| 272 | if (fc_lpf > 36) | 272 | if (fc_lpf > 36) |
| 273 | fc_lpf = 36; | 273 | fc_lpf = 36; |
| 274 | } else if (p->delivery_system == SYS_DVBS2) { | 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 | * SR <= 4.5: | 276 | * SR <= 4.5: |
| 295 | * fc_lpf = 5 | 277 | * fc_lpf = 5 |
| @@ -302,11 +284,9 @@ static int horus3a_set_params(struct dvb_frontend *fe) · 6 unmodified lines | |||
| 302 | if (symbol_rate <= 4500) | 284 | if (symbol_rate <= 4500) |
| 303 | fc_lpf = 5; | 285 | fc_lpf = 5; |
| 304 | else if (symbol_rate <= 10000) | 286 | else if (symbol_rate <= 10000) |
| 305 | fc_lpf = (u8)DIV_ROUND_UP( | 287 | fc_lpf = (u8)((symbol_rate * 11 + (10000-1)) / 10000); |
| 306 | symbol_rate * (200 + rolloff), 200000); | ||
| 307 | else | 288 | else |
| 308 | fc_lpf = (u8)DIV_ROUND_UP( | 289 | fc_lpf = (u8)((symbol_rate * 3 + (5000-1)) / 5000 + 5); |
| 309 | symbol_rate * (100 + rolloff), 200000) + 5; | ||
| 310 | /* 5 <= fc_lpf <= 36 is valid */ | 290 | /* 5 <= fc_lpf <= 36 is valid */ |
| 311 | if (fc_lpf > 36) | 291 | if (fc_lpf > 36) |
| 312 | fc_lpf = 36; | 292 | fc_lpf = 36; |
| @@ -306,8 +306,8 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 305 unmodified lines | |||
| 306 | const struct m88ds3103_reg_val *init; | 306 | const struct m88ds3103_reg_val *init; |
| 307 | u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */ | 307 | u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */ |
| 308 | u8 buf[3]; | 308 | u8 buf[3]; |
| 309 | u16 u16tmp, divide_ratio = 0; | 309 | u16 u16tmp; |
| 310 | u32 tuner_frequency, target_mclk; | 310 | u32 tuner_frequency_khz, target_mclk; |
| 311 | s32 s32tmp; | 311 | s32 s32tmp; |
| 312 | 312 | ||
| 313 | dev_dbg(&client->dev, | 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 | if (fe->ops.tuner_ops.get_frequency) { | 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 | if (ret) | 348 | if (ret) |
| 349 | goto err; | 349 | goto err; |
| 350 | } else { | 350 | } else { |
| @@ -353,20 +353,20 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 2 unmodified lines | |||
| 353 | * actual frequency used. Carrier offset calculation is not | 353 | * actual frequency used. Carrier offset calculation is not |
| 354 | * valid. | 354 | * valid. |
| 355 | */ | 355 | */ |
| 356 | tuner_frequency = c->frequency; | 356 | tuner_frequency_khz = c->frequency; |
| 357 | } | 357 | } |
| 358 | 358 | ||
| 359 | /* select M88RS6000 demod main mclk and ts mclk from tuner die. */ | 359 | /* select M88RS6000 demod main mclk and ts mclk from tuner die. */ |
| 360 | if (dev->chip_id == M88RS6000_CHIP_ID) { | 360 | if (dev->chip_id == M88RS6000_CHIP_ID) { |
| 361 | if (c->symbol_rate > 45010000) | 361 | if (c->symbol_rate > 45010000) |
| 362 | dev->mclk_khz = 110250; | 362 | dev->mclk = 110250000; |
| 363 | else | 363 | else |
| 364 | dev->mclk_khz = 96000; | 364 | dev->mclk = 96000000; |
| 365 | 365 | ||
| 366 | if (c->delivery_system == SYS_DVBS) | 366 | if (c->delivery_system == SYS_DVBS) |
| 367 | target_mclk = 96000; | 367 | target_mclk = 96000000; |
| 368 | else | 368 | else |
| 369 | target_mclk = 144000; | 369 | target_mclk = 144000000; |
| 370 | 370 | ||
| 371 | /* Enable demod clock path */ | 371 | /* Enable demod clock path */ |
| 372 | ret = regmap_write(dev->regmap, 0x06, 0x00); | 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 | usleep_range(10000, 20000); | 375 | usleep_range(10000, 20000); |
| 376 | } else { | 376 | } else { |
| 377 | /* set M88DS3103 mclk and ts mclk. */ | 377 | /* set M88DS3103 mclk and ts mclk. */ |
| 378 | dev->mclk_khz = 96000; | 378 | dev->mclk = 96000000; |
| 379 | 379 | ||
| 380 | switch (dev->cfg->ts_mode) { | 380 | switch (dev->cfg->ts_mode) { |
| 381 | case M88DS3103_TS_SERIAL: | 381 | case M88DS3103_TS_SERIAL: |
| @@ -385,14 +385,14 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 3 unmodified lines | |||
| 385 | case M88DS3103_TS_PARALLEL: | 385 | case M88DS3103_TS_PARALLEL: |
| 386 | case M88DS3103_TS_CI: | 386 | case M88DS3103_TS_CI: |
| 387 | if (c->delivery_system == SYS_DVBS) | 387 | if (c->delivery_system == SYS_DVBS) |
| 388 | target_mclk = 96000; | 388 | target_mclk = 96000000; |
| 389 | else { | 389 | else { |
| 390 | if (c->symbol_rate < 18000000) | 390 | if (c->symbol_rate < 18000000) |
| 391 | target_mclk = 96000; | 391 | target_mclk = 96000000; |
| 392 | else if (c->symbol_rate < 28000000) | 392 | else if (c->symbol_rate < 28000000) |
| 393 | target_mclk = 144000; | 393 | target_mclk = 144000000; |
| 394 | else | 394 | else |
| 395 | target_mclk = 192000; | 395 | target_mclk = 192000000; |
| 396 | } | 396 | } |
| 397 | break; | 397 | break; |
| 398 | default: | 398 | default: |
| @@ -402,15 +402,15 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 3 unmodified lines | |||
| 402 | } | 402 | } |
| 403 | 403 | ||
| 404 | switch (target_mclk) { | 404 | switch (target_mclk) { |
| 405 | case 96000: | 405 | case 96000000: |
| 406 | u8tmp1 = 0x02; /* 0b10 */ | 406 | u8tmp1 = 0x02; /* 0b10 */ |
| 407 | u8tmp2 = 0x01; /* 0b01 */ | 407 | u8tmp2 = 0x01; /* 0b01 */ |
| 408 | break; | 408 | break; |
| 409 | case 144000: | 409 | case 144000000: |
| 410 | u8tmp1 = 0x00; /* 0b00 */ | 410 | u8tmp1 = 0x00; /* 0b00 */ |
| 411 | u8tmp2 = 0x01; /* 0b01 */ | 411 | u8tmp2 = 0x01; /* 0b01 */ |
| 412 | break; | 412 | break; |
| 413 | case 192000: | 413 | case 192000000: |
| 414 | u8tmp1 = 0x03; /* 0b11 */ | 414 | u8tmp1 = 0x03; /* 0b11 */ |
| 415 | u8tmp2 = 0x00; /* 0b00 */ | 415 | u8tmp2 = 0x00; /* 0b00 */ |
| 416 | break; | 416 | break; |
| @@ -464,8 +464,8 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 47 unmodified lines | |||
| 464 | } | 464 | } |
| 465 | 465 | ||
| 466 | if (dev->chip_id == M88RS6000_CHIP_ID) { | 466 | if (dev->chip_id == M88RS6000_CHIP_ID) { |
| 467 | if ((c->delivery_system == SYS_DVBS2) | 467 | if (c->delivery_system == SYS_DVBS2 && |
| 468 | && ((c->symbol_rate / 1000) <= 5000)) { | 468 | c->symbol_rate <= 5000000) { |
| 469 | ret = regmap_write(dev->regmap, 0xc0, 0x04); | 469 | ret = regmap_write(dev->regmap, 0xc0, 0x04); |
| 470 | if (ret) | 470 | if (ret) |
| 471 | goto err; | 471 | goto err; |
| @@ -522,37 +522,25 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 50 unmodified lines | |||
| 522 | ret = m88ds3103_update_bits(dev, 0x29, 0x20, u8tmp1); | 522 | ret = m88ds3103_update_bits(dev, 0x29, 0x20, u8tmp1); |
| 523 | if (ret) | 523 | if (ret) |
| 524 | goto err; | 524 | goto err; |
| 525 | u8tmp1 = 0; | 525 | u16tmp = 0; |
| 526 | u8tmp2 = 0; | 526 | u8tmp1 = 0x3f; |
| 527 | u8tmp2 = 0x3f; | ||
| 527 | break; | 528 | break; |
| 528 | default: | 529 | default: |
| 529 | if (dev->cfg->ts_clk) { | 530 | u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk); |
| 530 | divide_ratio = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk); | 531 | u8tmp1 = u16tmp / 2 - 1; |
| 531 | u8tmp1 = divide_ratio / 2; | 532 | u8tmp2 = DIV_ROUND_UP(u16tmp, 2) - 1; |
| 532 | u8tmp2 = DIV_ROUND_UP(divide_ratio, 2); | ||
| 533 | } | ||
| 534 | } | 533 | } |
| 535 | 534 | ||
| 536 | dev_dbg(&client->dev, | 535 | dev_dbg(&client->dev, "target_mclk=%u ts_clk=%u ts_clk_divide_ratio=%u\n", |
| 537 | "target_mclk=%d ts_clk=%d divide_ratio=%d\n", | 536 | target_mclk, dev->cfg->ts_clk, u16tmp); |
| 538 | target_mclk, dev->cfg->ts_clk, divide_ratio); | ||
| 539 | 537 | ||
| 540 | u8tmp1--; | ||
| 541 | u8tmp2--; | ||
| 542 | /* u8tmp1[5:2] => fe[3:0], u8tmp1[1:0] => ea[7:6] */ | 538 | /* u8tmp1[5:2] => fe[3:0], u8tmp1[1:0] => ea[7:6] */ |
| 543 | u8tmp1 &= 0x3f; | ||
| 544 | /* u8tmp2[5:0] => ea[5:0] */ | 539 | /* u8tmp2[5:0] => ea[5:0] */ |
| 545 | u8tmp2 &= 0x3f; | 540 | u8tmp = (u8tmp1 >> 2) & 0x0f; |
| 546 | 541 | ret = regmap_update_bits(dev->regmap, 0xfe, 0x0f, u8tmp); | |
| 547 | ret = regmap_bulk_read(dev->regmap, 0xfe, &u8tmp, 1); | ||
| 548 | if (ret) | 542 | if (ret) |
| 549 | goto err; | 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 | u8tmp = ((u8tmp1 & 0x03) << 6) | u8tmp2 >> 0; | 544 | u8tmp = ((u8tmp1 & 0x03) << 6) | u8tmp2 >> 0; |
| 557 | ret = regmap_write(dev->regmap, 0xea, u8tmp); | 545 | ret = regmap_write(dev->regmap, 0xea, u8tmp); |
| 558 | if (ret) | 546 | if (ret) |
| @@ -581,7 +569,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 22 unmodified lines | |||
| 581 | if (ret) | 569 | if (ret) |
| 582 | goto err; | 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 | buf[0] = (u16tmp >> 0) & 0xff; | 573 | buf[0] = (u16tmp >> 0) & 0xff; |
| 586 | buf[1] = (u16tmp >> 8) & 0xff; | 574 | buf[1] = (u16tmp >> 8) & 0xff; |
| 587 | ret = regmap_bulk_write(dev->regmap, 0x61, buf, 2); | 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 | goto err; | 589 | goto err; |
| 602 | 590 | ||
| 603 | dev_dbg(&client->dev, "carrier offset=%d\n", | 591 | dev_dbg(&client->dev, "carrier offset=%d\n", |
| 604 | (tuner_frequency - c->frequency)); | 592 | (tuner_frequency_khz - 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; | ||
| 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 | buf[0] = (s32tmp >> 0) & 0xff; | 597 | buf[0] = (s32tmp >> 0) & 0xff; |
| 612 | buf[1] = (s32tmp >> 8) & 0xff; | 598 | buf[1] = (s32tmp >> 8) & 0xff; |
| 613 | ret = regmap_bulk_write(dev->regmap, 0x5e, buf, 2); | 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 | struct m88ds3103_dev *dev = fe->demodulator_priv; | 621 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
| 636 | struct i2c_client *client = dev->client; | 622 | struct i2c_client *client = dev->client; |
| 637 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 623 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| 638 | int ret, len, remaining; | 624 | int ret, len, rem; |
| 639 | unsigned int utmp; | 625 | unsigned int utmp; |
| 640 | const struct firmware *fw = NULL; | 626 | const struct firmware *firmware; |
| 641 | u8 *fw_file; | 627 | const char *name; |
| 642 | 628 | ||
| 643 | dev_dbg(&client->dev, "\n"); | 629 | dev_dbg(&client->dev, "\n"); |
| 644 | 630 | ||
| @@ -664,7 +650,7 @@ static int m88ds3103_init(struct dvb_frontend *fe) · 19 unmodified lines | |||
| 664 | dev_dbg(&client->dev, "firmware=%02x\n", utmp); | 650 | dev_dbg(&client->dev, "firmware=%02x\n", utmp); |
| 665 | 651 | ||
| 666 | if (utmp) | 652 | if (utmp) |
| 667 | goto skip_fw_download; | 653 | goto warm; |
| 668 | 654 | ||
| 669 | /* global reset, global diseqc reset, golbal fec reset */ | 655 | /* global reset, global diseqc reset, golbal fec reset */ |
| 670 | ret = regmap_write(dev->regmap, 0x07, 0xe0); | 656 | ret = regmap_write(dev->regmap, 0x07, 0xe0); |
| @@ -679,52 +665,47 @@ static int m88ds3103_init(struct dvb_frontend *fe) · 8 unmodified lines | |||
| 679 | m88ds3103_ops.info.name); | 665 | m88ds3103_ops.info.name); |
| 680 | 666 | ||
| 681 | if (dev->chip_id == M88RS6000_CHIP_ID) | 667 | if (dev->chip_id == M88RS6000_CHIP_ID) |
| 682 | fw_file = M88RS6000_FIRMWARE; | 668 | name = M88RS6000_FIRMWARE; |
| 683 | else | 669 | else |
| 684 | fw_file = M88DS3103_FIRMWARE; | 670 | name = M88DS3103_FIRMWARE; |
| 685 | /* request the firmware, this will block and timeout */ | 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 | if (ret) { | 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 | goto err; | 675 | goto err; |
| 690 | } | 676 | } |
| 691 | 677 | ||
| 692 | dev_info(&client->dev, "downloading firmware from file '%s'\n", | 678 | dev_info(&client->dev, "downloading firmware from file '%s'\n", name); |
| 693 | fw_file); | ||
| 694 | 679 | ||
| 695 | ret = regmap_write(dev->regmap, 0xb2, 0x01); | 680 | ret = regmap_write(dev->regmap, 0xb2, 0x01); |
| 696 | if (ret) | 681 | if (ret) |
| 697 | goto error_fw_release; | 682 | goto err_release_firmware; |
| 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); | ||
| 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 | ret = regmap_bulk_write(dev->regmap, 0xb0, | 686 | ret = regmap_bulk_write(dev->regmap, 0xb0, |
| 706 | &fw->data[fw->size - remaining], len); | 687 | &firmware->data[firmware->size - rem], |
| 688 | len); | ||
| 707 | if (ret) { | 689 | if (ret) { |
| 708 | dev_err(&client->dev, "firmware download failed=%d\n", | 690 | dev_err(&client->dev, "firmware download failed %d\n", |
| 709 | ret); | 691 | ret); |
| 710 | goto error_fw_release; | 692 | goto err_release_firmware; |
| 711 | } | 693 | } |
| 712 | } | 694 | } |
| 713 | 695 | ||
| 714 | ret = regmap_write(dev->regmap, 0xb2, 0x00); | 696 | ret = regmap_write(dev->regmap, 0xb2, 0x00); |
| 715 | if (ret) | 697 | if (ret) |
| 716 | goto error_fw_release; | 698 | goto err_release_firmware; |
| 717 | 699 | ||
| 718 | release_firmware(fw); | 700 | release_firmware(firmware); |
| 719 | fw = NULL; | ||
| 720 | 701 | ||
| 721 | ret = regmap_read(dev->regmap, 0xb9, &utmp); | 702 | ret = regmap_read(dev->regmap, 0xb9, &utmp); |
| 722 | if (ret) | 703 | if (ret) |
| 723 | goto err; | 704 | goto err; |
| 724 | 705 | ||
| 725 | if (!utmp) { | 706 | if (!utmp) { |
| 707 | ret = -EINVAL; | ||
| 726 | dev_info(&client->dev, "firmware did not run\n"); | 708 | dev_info(&client->dev, "firmware did not run\n"); |
| 727 | ret = -EFAULT; | ||
| 728 | goto err; | 709 | goto err; |
| 729 | } | 710 | } |
| 730 | 711 | ||
| @@ -733,7 +714,7 @@ static int m88ds3103_init(struct dvb_frontend *fe) · 2 unmodified lines | |||
| 733 | dev_info(&client->dev, "firmware version: %X.%X\n", | 714 | dev_info(&client->dev, "firmware version: %X.%X\n", |
| 734 | (utmp >> 4) & 0xf, (utmp >> 0 & 0xf)); | 715 | (utmp >> 4) & 0xf, (utmp >> 0 & 0xf)); |
| 735 | 716 | ||
| 736 | skip_fw_download: | 717 | warm: |
| 737 | /* warm state */ | 718 | /* warm state */ |
| 738 | dev->warm = true; | 719 | dev->warm = true; |
| 739 | 720 | ||
| @@ -746,8 +727,8 @@ skip_fw_download: · 6 unmodified lines | |||
| 746 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 727 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 747 | 728 | ||
| 748 | return 0; | 729 | return 0; |
| 749 | error_fw_release: | 730 | err_release_firmware: |
| 750 | release_firmware(fw); | 731 | release_firmware(firmware); |
| 751 | err: | 732 | err: |
| 752 | dev_dbg(&client->dev, "failed=%d\n", ret); | 733 | dev_dbg(&client->dev, "failed=%d\n", ret); |
| 753 | return ret; | 734 | return ret; |
| @@ -952,8 +933,7 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe, · 198 unmodified lines | |||
| 952 | if (ret) | 933 | if (ret) |
| 953 | goto err; | 934 | goto err; |
| 954 | 935 | ||
| 955 | c->symbol_rate = 1ull * ((buf[1] << 8) | (buf[0] << 0)) * | 936 | c->symbol_rate = DIV_ROUND_CLOSEST_ULL((u64)(buf[1] << 8 | buf[0] << 0) * dev->mclk, 0x10000); |
| 956 | dev->mclk_khz * 1000 / 0x10000; | ||
| 957 | 937 | ||
| 958 | return 0; | 938 | return 0; |
| 959 | err: | 939 | err: |
| @@ -1119,8 +1099,9 @@ static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe, · 159 unmodified lines | |||
| 1119 | #define SEND_MASTER_CMD_TIMEOUT 120 | 1099 | #define SEND_MASTER_CMD_TIMEOUT 120 |
| 1120 | timeout = jiffies + msecs_to_jiffies(SEND_MASTER_CMD_TIMEOUT); | 1100 | timeout = jiffies + msecs_to_jiffies(SEND_MASTER_CMD_TIMEOUT); |
| 1121 | 1101 | ||
| 1122 | /* DiSEqC message typical period is 54 ms */ | 1102 | /* DiSEqC message period is 13.5 ms per byte */ |
| 1123 | usleep_range(50000, 54000); | 1103 | utmp = diseqc_cmd->msg_len * 13500; |
| 1104 | usleep_range(utmp - 4000, utmp); | ||
| 1124 | 1105 | ||
| 1125 | for (utmp = 1; !time_after(jiffies, timeout) && utmp;) { | 1106 | for (utmp = 1; !time_after(jiffies, timeout) && utmp;) { |
| 1126 | ret = regmap_read(dev->regmap, 0xa1, &utmp); | 1107 | ret = regmap_read(dev->regmap, 0xa1, &utmp); |
| @@ -1395,7 +1376,7 @@ static int m88ds3103_probe(struct i2c_client *client, · 268 unmodified lines | |||
| 1395 | dev->config.clock = pdata->clk; | 1376 | dev->config.clock = pdata->clk; |
| 1396 | dev->config.i2c_wr_max = pdata->i2c_wr_max; | 1377 | dev->config.i2c_wr_max = pdata->i2c_wr_max; |
| 1397 | dev->config.ts_mode = pdata->ts_mode; | 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 | dev->config.ts_clk_pol = pdata->ts_clk_pol; | 1380 | dev->config.ts_clk_pol = pdata->ts_clk_pol; |
| 1400 | dev->config.spec_inv = pdata->spec_inv; | 1381 | dev->config.spec_inv = pdata->spec_inv; |
| 1401 | dev->config.agc_inv = pdata->agc_inv; | 1382 | dev->config.agc_inv = pdata->agc_inv; |
| @@ -1446,6 +1427,11 @@ static int m88ds3103_probe(struct i2c_client *client, · 44 unmodified lines | |||
| 1446 | goto err_kfree; | 1427 | goto err_kfree; |
| 1447 | } | 1428 | } |
| 1448 | 1429 | ||
| 1430 | if (!pdata->ts_clk) { | ||
| 1431 | ret = -EINVAL; | ||
| 1432 | goto err_kfree; | ||
| 1433 | } | ||
| 1434 | |||
| 1449 | /* 0x29 register is defined differently for m88rs6000. */ | 1435 | /* 0x29 register is defined differently for m88rs6000. */ |
| 1450 | /* set internal tuner address to 0x21 */ | 1436 | /* set internal tuner address to 0x21 */ |
| 1451 | if (dev->chip_id == M88RS6000_CHIP_ID) | 1437 | if (dev->chip_id == M88RS6000_CHIP_ID) |
| @@ -27,7 +27,6 @@ · 26 unmodified lines | |||
| 27 | 27 | ||
| 28 | #define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw" | 28 | #define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw" |
| 29 | #define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw" | 29 | #define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw" |
| 30 | #define M88DS3103_MCLK_KHZ 96000 | ||
| 31 | #define M88RS6000_CHIP_ID 0x74 | 30 | #define M88RS6000_CHIP_ID 0x74 |
| 32 | #define M88DS3103_CHIP_ID 0x70 | 31 | #define M88DS3103_CHIP_ID 0x70 |
| 33 | 32 | ||
| @@ -46,7 +45,7 @@ struct m88ds3103_dev { · 12 unmodified lines | |||
| 46 | /* auto detect chip id to do different config */ | 45 | /* auto detect chip id to do different config */ |
| 47 | u8 chip_id; | 46 | u8 chip_id; |
| 48 | /* main mclk is calculated for M88RS6000 dynamically */ | 47 | /* main mclk is calculated for M88RS6000 dynamically */ |
| 49 | s32 mclk_khz; | 48 | s32 mclk; |
| 50 | u64 post_bit_error; | 49 | u64 post_bit_error; |
| 51 | u64 post_bit_count; | 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 | struct m88rs2000_state *state = fe->demodulator_priv; | 610 | struct m88rs2000_state *state = fe->demodulator_priv; |
| 611 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 611 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| 612 | enum fe_status status; | 612 | enum fe_status status = 0; |
| 613 | int i, ret = 0; | 613 | int i, ret = 0; |
| 614 | u32 tuner_freq; | 614 | u32 tuner_freq; |
| 615 | s16 offset = 0; | 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 | *status = 0; | 302 | *status = 0; |
| 303 | 303 | ||
| 304 | val = mb86a20s_readreg(state, 0x0a) & 0xf; | 304 | val = mb86a20s_readreg(state, 0x0a); |
| 305 | if (val < 0) | 305 | if (val < 0) |
| 306 | return val; | 306 | return val; |
| 307 | 307 | ||
| 308 | val &= 0xf; | ||
| 308 | if (val >= 2) | 309 | if (val >= 2) |
| 309 | *status |= FE_HAS_SIGNAL; | 310 | *status |= FE_HAS_SIGNAL; |
| 310 | 311 | ||
| @@ -17,28 +17,90 @@ · 16 unmodified lines | |||
| 17 | #include "mn88472_priv.h" | 17 | #include "mn88472_priv.h" |
| 18 | 18 | ||
| 19 | static int mn88472_get_tune_settings(struct dvb_frontend *fe, | 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 | return 0; | 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 | static int mn88472_set_frontend(struct dvb_frontend *fe) | 86 | static int mn88472_set_frontend(struct dvb_frontend *fe) |
| 27 | { | 87 | { |
| 28 | struct i2c_client *client = fe->demodulator_priv; | 88 | struct i2c_client *client = fe->demodulator_priv; |
| 29 | struct mn88472_dev *dev = i2c_get_clientdata(client); | 89 | struct mn88472_dev *dev = i2c_get_clientdata(client); |
| 30 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 90 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| 31 | int ret, i; | 91 | int ret, i; |
| 32 | u32 if_frequency = 0; | 92 | unsigned int utmp; |
| 33 | u64 tmp; | 93 | u32 if_frequency; |
| 34 | u8 delivery_system_val, if_val[3], bw_val[7], bw_val2; | 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 | dev_dbg(&client->dev, | 98 | dev_dbg(&client->dev, |
| 37 | "delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d\n", | 99 | "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%d stream_id=%d\n", |
| 38 | c->delivery_system, c->modulation, | 100 | c->delivery_system, c->modulation, c->frequency, |
| 39 | c->frequency, c->symbol_rate, c->inversion); | 101 | c->bandwidth_hz, c->symbol_rate, c->inversion, c->stream_id); |
| 40 | 102 | ||
| 41 | if (!dev->warm) { | 103 | if (!dev->active) { |
| 42 | ret = -EAGAIN; | 104 | ret = -EAGAIN; |
| 43 | goto err; | 105 | goto err; |
| 44 | } | 106 | } |
| @@ -46,39 +108,64 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) · 1 unmodified line | |||
| 46 | switch (c->delivery_system) { | 108 | switch (c->delivery_system) { |
| 47 | case SYS_DVBT: | 109 | case SYS_DVBT: |
| 48 | delivery_system_val = 0x02; | 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 | break; | 115 | break; |
| 50 | case SYS_DVBT2: | 116 | case SYS_DVBT2: |
| 51 | delivery_system_val = 0x03; | 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 | break; | 122 | break; |
| 53 | case SYS_DVBC_ANNEX_A: | 123 | case SYS_DVBC_ANNEX_A: |
| 54 | delivery_system_val = 0x04; | 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 | break; | 129 | break; |
| 56 | default: | 130 | default: |
| 57 | ret = -EINVAL; | 131 | ret = -EINVAL; |
| 58 | goto err; | 132 | goto err; |
| 59 | } | 133 | } |
| 60 | 134 | ||
| 61 | if (c->bandwidth_hz <= 5000000) { | 135 | switch (c->delivery_system) { |
| 62 | memcpy(bw_val, "\xe5\x99\x9a\x1b\xa9\x1b\xa9", 7); | 136 | case SYS_DVBT: |
| 63 | bw_val2 = 0x03; | 137 | case SYS_DVBT2: |
| 64 | } else if (c->bandwidth_hz <= 6000000) { | 138 | switch (c->bandwidth_hz) { |
| 65 | /* IF 3570000 Hz, BW 6000000 Hz */ | 139 | case 5000000: |
| 66 | memcpy(bw_val, "\xbf\x55\x55\x15\x6b\x15\x6b", 7); | 140 | bandwidth_vals_ptr = "\xe5\x99\x9a\x1b\xa9\x1b\xa9"; |
| 67 | bw_val2 = 0x02; | 141 | bandwidth_val = 0x03; |
| 68 | } else if (c->bandwidth_hz <= 7000000) { | 142 | break; |
| 69 | /* IF 4570000 Hz, BW 7000000 Hz */ | 143 | case 6000000: |
| 70 | memcpy(bw_val, "\xa4\x00\x00\x0f\x2c\x0f\x2c", 7); | 144 | bandwidth_vals_ptr = "\xbf\x55\x55\x15\x6b\x15\x6b"; |
| 71 | bw_val2 = 0x01; | 145 | bandwidth_val = 0x02; |
| 72 | } else if (c->bandwidth_hz <= 8000000) { | 146 | break; |
| 73 | /* IF 4570000 Hz, BW 8000000 Hz */ | 147 | case 7000000: |
| 74 | memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7); | 148 | bandwidth_vals_ptr = "\xa4\x00\x00\x0f\x2c\x0f\x2c"; |
| 75 | bw_val2 = 0x00; | 149 | bandwidth_val = 0x01; |
| 76 | } else { | 150 | break; |
| 77 | ret = -EINVAL; | 151 | case 8000000: |
| 78 | goto err; | 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 | if (fe->ops.tuner_ops.set_params) { | 169 | if (fe->ops.tuner_ops.set_params) { |
| 83 | ret = fe->ops.tuner_ops.set_params(fe); | 170 | ret = fe->ops.tuner_ops.set_params(fe); |
| 84 | if (ret) | 171 | if (ret) |
| @@ -91,20 +178,10 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) · 6 unmodified lines | |||
| 91 | goto err; | 178 | goto err; |
| 92 | 179 | ||
| 93 | dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency); | 180 | dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency); |
| 94 | } | 181 | } else { |
| 95 | 182 | ret = -EINVAL; | |
| 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) | ||
| 107 | goto err; | 183 | goto err; |
| 184 | } | ||
| 108 | 185 | ||
| 109 | ret = regmap_write(dev->regmap[2], 0x00, 0x66); | 186 | ret = regmap_write(dev->regmap[2], 0x00, 0x66); |
| 110 | if (ret) | 187 | if (ret) |
| @@ -118,157 +195,81 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) · 7 unmodified lines | |||
| 118 | ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val); | 195 | ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val); |
| 119 | if (ret) | 196 | if (ret) |
| 120 | goto err; | 197 | goto err; |
| 121 | ret = regmap_write(dev->regmap[2], 0x04, bw_val2); | 198 | ret = regmap_write(dev->regmap[2], 0x04, bandwidth_val); |
| 122 | if (ret) | 199 | if (ret) |
| 123 | goto err; | 200 | goto err; |
| 124 | 201 | ||
| 125 | for (i = 0; i < sizeof(if_val); i++) { | 202 | /* IF */ |
| 126 | ret = regmap_write(dev->regmap[2], 0x10 + i, if_val[i]); | 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 | if (ret) | 209 | if (ret) |
| 128 | goto err; | 210 | goto err; |
| 129 | } | 211 | } |
| 130 | 212 | ||
| 131 | for (i = 0; i < sizeof(bw_val); i++) { | 213 | /* Bandwidth */ |
| 132 | ret = regmap_write(dev->regmap[2], 0x13 + i, bw_val[i]); | 214 | if (bandwidth_vals_ptr) { |
| 133 | if (ret) | 215 | for (i = 0; i < 7; i++) { |
| 134 | goto err; | 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 | switch (c->delivery_system) { | 236 | switch (c->delivery_system) { |
| 138 | case SYS_DVBT: | 237 | case SYS_DVBT: |
| 139 | ret = regmap_write(dev->regmap[0], 0x07, 0x26); | 238 | ret = regmap_write(dev->regmap[0], 0x07, 0x26); |
| 140 | ret = regmap_write(dev->regmap[0], 0xb0, 0x0a); | 239 | if (ret) |
| 141 | ret = regmap_write(dev->regmap[0], 0xb4, 0x00); | 240 | goto err; |
| 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); | ||
| 145 | ret = regmap_write(dev->regmap[0], 0x00, 0xba); | 241 | ret = regmap_write(dev->regmap[0], 0x00, 0xba); |
| 242 | if (ret) | ||
| 243 | goto err; | ||
| 146 | ret = regmap_write(dev->regmap[0], 0x01, 0x13); | 244 | ret = regmap_write(dev->regmap[0], 0x01, 0x13); |
| 147 | if (ret) | 245 | if (ret) |
| 148 | goto err; | 246 | goto err; |
| 149 | break; | 247 | break; |
| 150 | case SYS_DVBT2: | 248 | case SYS_DVBT2: |
| 151 | ret = regmap_write(dev->regmap[2], 0x2b, 0x13); | 249 | ret = regmap_write(dev->regmap[2], 0x2b, 0x13); |
| 250 | if (ret) | ||
| 251 | goto err; | ||
| 152 | ret = regmap_write(dev->regmap[2], 0x4f, 0x05); | 252 | ret = regmap_write(dev->regmap[2], 0x4f, 0x05); |
| 253 | if (ret) | ||
| 254 | goto err; | ||
| 153 | ret = regmap_write(dev->regmap[1], 0xf6, 0x05); | 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 | if (ret) | 256 | if (ret) |
| 162 | goto err; | 257 | goto err; |
| 163 | break; | 258 | ret = regmap_write(dev->regmap[2], 0x32, c->stream_id); |
| 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); | ||
| 171 | if (ret) | 259 | if (ret) |
| 172 | goto err; | 260 | goto err; |
| 173 | break; | 261 | break; |
| 174 | default: | 262 | case SYS_DVBC_ANNEX_A: |
| 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); | ||
| 188 | break; | 263 | break; |
| 189 | default: | 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 | break; | 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 | ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); | 269 | ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); |
| 210 | if (ret) | 270 | if (ret) |
| 211 | goto err; | 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 | return 0; | 273 | return 0; |
| 273 | err: | 274 | err: |
| 274 | dev_dbg(&client->dev, "failed=%d\n", ret); | 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 | struct i2c_client *client = fe->demodulator_priv; | 281 | struct i2c_client *client = fe->demodulator_priv; |
| 281 | struct mn88472_dev *dev = i2c_get_clientdata(client); | 282 | struct mn88472_dev *dev = i2c_get_clientdata(client); |
| 282 | int ret, len, remaining; | 283 | int ret, len, rem; |
| 283 | const struct firmware *fw = NULL; | 284 | unsigned int utmp; |
| 284 | u8 *fw_file = MN88472_FIRMWARE; | 285 | const struct firmware *firmware; |
| 285 | unsigned int tmp; | 286 | const char *name = MN88472_FIRMWARE; |
| 286 | 287 | ||
| 287 | dev_dbg(&client->dev, "\n"); | 288 | dev_dbg(&client->dev, "\n"); |
| 288 | 289 | ||
| 289 | /* set cold state by default */ | 290 | /* Power up */ |
| 290 | dev->warm = false; | ||
| 291 | |||
| 292 | /* power on */ | ||
| 293 | ret = regmap_write(dev->regmap[2], 0x05, 0x00); | 291 | ret = regmap_write(dev->regmap[2], 0x05, 0x00); |
| 294 | if (ret) | 292 | if (ret) |
| 295 | goto err; | 293 | goto err; |
| 296 | 294 | ret = regmap_write(dev->regmap[2], 0x0b, 0x00); | |
| 297 | ret = regmap_bulk_write(dev->regmap[2], 0x0b, "\x00\x00", 2); | ||
| 298 | if (ret) | 295 | if (ret) |
| 299 | goto err; | 296 | goto err; |
| 300 | 297 | ret = regmap_write(dev->regmap[2], 0x0c, 0x00); | |
| 301 | /* check if firmware is already running */ | ||
| 302 | ret = regmap_read(dev->regmap[0], 0xf5, &tmp); | ||
| 303 | if (ret) | 298 | if (ret) |
| 304 | goto err; | 299 | goto err; |
| 305 | 300 | ||
| 306 | if (!(tmp & 0x1)) { | 301 | /* Check if firmware is already running */ |
| 307 | dev_info(&client->dev, "firmware already running\n"); | 302 | ret = regmap_read(dev->regmap[0], 0xf5, &utmp); |
| 308 | dev->warm = true; | 303 | if (ret) |
| 309 | return 0; | 304 | goto err; |
| 310 | } | 305 | if (!(utmp & 0x01)) |
| 306 | goto warm; | ||
| 311 | 307 | ||
| 312 | /* request the firmware, this will block and timeout */ | 308 | ret = request_firmware(&firmware, name, &client->dev); |
| 313 | ret = request_firmware(&fw, fw_file, &client->dev); | ||
| 314 | if (ret) { | 309 | if (ret) { |
| 315 | dev_err(&client->dev, "firmare file '%s' not found\n", | 310 | dev_err(&client->dev, "firmware file '%s' not found\n", name); |
| 316 | fw_file); | ||
| 317 | goto err; | 311 | goto err; |
| 318 | } | 312 | } |
| 319 | 313 | ||
| 320 | dev_info(&client->dev, "downloading firmware from file '%s'\n", | 314 | dev_info(&client->dev, "downloading firmware from file '%s'\n", name); |
| 321 | fw_file); | ||
| 322 | 315 | ||
| 323 | ret = regmap_write(dev->regmap[0], 0xf5, 0x03); | 316 | ret = regmap_write(dev->regmap[0], 0xf5, 0x03); |
| 324 | if (ret) | 317 | if (ret) |
| 325 | goto firmware_release; | 318 | goto err_release_firmware; |
| 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; | ||
| 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 | ret = regmap_bulk_write(dev->regmap[0], 0xf6, | 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 | if (ret) { | 325 | if (ret) { |
| 336 | dev_err(&client->dev, | 326 | dev_err(&client->dev, "firmware download failed %d\n", |
| 337 | "firmware download failed=%d\n", ret); | 327 | ret); |
| 338 | goto firmware_release; | 328 | goto err_release_firmware; |
| 339 | } | 329 | } |
| 340 | } | 330 | } |
| 341 | 331 | ||
| 342 | /* parity check of firmware */ | 332 | /* Parity check of firmware */ |
| 343 | ret = regmap_read(dev->regmap[0], 0xf8, &tmp); | 333 | ret = regmap_read(dev->regmap[0], 0xf8, &utmp); |
| 344 | if (ret) { | 334 | if (ret) |
| 345 | dev_err(&client->dev, | 335 | goto err_release_firmware; |
| 346 | "parity reg read failed=%d\n", ret); | 336 | if (utmp & 0x10) { |
| 347 | goto firmware_release; | 337 | ret = -EINVAL; |
| 348 | } | 338 | dev_err(&client->dev, "firmware did not run\n"); |
| 349 | if (tmp & 0x10) { | 339 | goto err_release_firmware; |
| 350 | dev_err(&client->dev, | ||
| 351 | "firmware parity check failed=0x%x\n", tmp); | ||
| 352 | goto firmware_release; | ||
| 353 | } | 340 | } |
| 354 | dev_err(&client->dev, "firmware parity check succeeded=0x%x\n", tmp); | ||
| 355 | 341 | ||
| 356 | ret = regmap_write(dev->regmap[0], 0xf5, 0x00); | 342 | ret = regmap_write(dev->regmap[0], 0xf5, 0x00); |
| 357 | if (ret) | 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); | 364 | switch (dev->ts_clk) { |
| 361 | fw = NULL; | 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 */ | 379 | dev->active = true; |
| 364 | dev->warm = true; | ||
| 365 | 380 | ||
| 366 | return 0; | 381 | return 0; |
| 367 | firmware_release: | 382 | err_release_firmware: |
| 368 | release_firmware(fw); | 383 | release_firmware(firmware); |
| 369 | err: | 384 | err: |
| 370 | dev_dbg(&client->dev, "failed=%d\n", ret); | 385 | dev_dbg(&client->dev, "failed=%d\n", ret); |
| 371 | return ret; | 386 | return ret; |
| @@ -379,18 +394,17 @@ static int mn88472_sleep(struct dvb_frontend *fe) · 7 unmodified lines | |||
| 379 | 394 | ||
| 380 | dev_dbg(&client->dev, "\n"); | 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 | ret = regmap_write(dev->regmap[2], 0x0b, 0x30); | 401 | ret = regmap_write(dev->regmap[2], 0x0b, 0x30); |
| 384 | |||
| 385 | if (ret) | 402 | if (ret) |
| 386 | goto err; | 403 | goto err; |
| 387 | |||
| 388 | ret = regmap_write(dev->regmap[2], 0x05, 0x3e); | 404 | ret = regmap_write(dev->regmap[2], 0x05, 0x3e); |
| 389 | if (ret) | 405 | if (ret) |
| 390 | goto err; | 406 | goto err; |
| 391 | 407 | ||
| 392 | dev->delivery_system = SYS_UNDEFINED; | ||
| 393 | |||
| 394 | return 0; | 408 | return 0; |
| 395 | err: | 409 | err: |
| 396 | dev_dbg(&client->dev, "failed=%d\n", ret); | 410 | dev_dbg(&client->dev, "failed=%d\n", ret); |
| @@ -434,10 +448,19 @@ static struct dvb_frontend_ops mn88472_ops = { · 37 unmodified lines | |||
| 434 | .read_status = mn88472_read_status, | 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 | static int mn88472_probe(struct i2c_client *client, | 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 | struct mn88472_dev *dev; | 464 | struct mn88472_dev *dev; |
| 442 | int ret; | 465 | int ret; |
| 443 | unsigned int utmp; | 466 | unsigned int utmp; |
| @@ -448,23 +471,16 @@ static int mn88472_probe(struct i2c_client *client, · 4 unmodified lines | |||
| 448 | 471 | ||
| 449 | dev_dbg(&client->dev, "\n"); | 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 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 474 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
| 459 | if (!dev) { | 475 | if (!dev) { |
| 460 | ret = -ENOMEM; | 476 | ret = -ENOMEM; |
| 461 | goto err; | 477 | goto err; |
| 462 | } | 478 | } |
| 463 | 479 | ||
| 464 | dev->i2c_wr_max = config->i2c_wr_max; | 480 | dev->i2c_write_max = pdata->i2c_wr_max ? pdata->i2c_wr_max : ~0; |
| 465 | dev->xtal = config->xtal; | 481 | dev->clk = pdata->xtal; |
| 466 | dev->ts_mode = config->ts_mode; | 482 | dev->ts_mode = pdata->ts_mode; |
| 467 | dev->ts_clock = config->ts_clock; | 483 | dev->ts_clk = pdata->ts_clock; |
| 468 | dev->client[0] = client; | 484 | dev->client[0] = client; |
| 469 | dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); | 485 | dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); |
| 470 | if (IS_ERR(dev->regmap[0])) { | 486 | if (IS_ERR(dev->regmap[0])) { |
| @@ -472,15 +488,25 @@ static int mn88472_probe(struct i2c_client *client, · 1 unmodified line | |||
| 472 | goto err_kfree; | 488 | goto err_kfree; |
| 473 | } | 489 | } |
| 474 | 490 | ||
| 475 | /* check demod answers to I2C */ | 491 | /* Check demod answers with correct chip id */ |
| 476 | ret = regmap_read(dev->regmap[0], 0x00, &utmp); | 492 | ret = regmap_read(dev->regmap[0], 0xff, &utmp); |
| 477 | if (ret) | 493 | if (ret) |
| 478 | goto err_regmap_0_regmap_exit; | 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 | * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients, | 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 | dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); | 511 | dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); |
| 486 | if (!dev->client[1]) { | 512 | if (!dev->client[1]) { |
| @@ -510,15 +536,25 @@ static int mn88472_probe(struct i2c_client *client, · 23 unmodified lines | |||
| 510 | } | 536 | } |
| 511 | i2c_set_clientdata(dev->client[2], dev); | 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 | memcpy(&dev->fe.ops, &mn88472_ops, sizeof(struct dvb_frontend_ops)); | 545 | memcpy(&dev->fe.ops, &mn88472_ops, sizeof(struct dvb_frontend_ops)); |
| 515 | dev->fe.demodulator_priv = client; | 546 | dev->fe.demodulator_priv = client; |
| 516 | *config->fe = &dev->fe; | 547 | *pdata->fe = &dev->fe; |
| 517 | i2c_set_clientdata(client, dev); | 548 | i2c_set_clientdata(client, dev); |
| 518 | 549 | ||
| 519 | dev_info(&client->dev, "Panasonic MN88472 successfully attached\n"); | 550 | /* Setup callbacks */ |
| 520 | return 0; | 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 | err_client_2_i2c_unregister_device: | 558 | err_client_2_i2c_unregister_device: |
| 523 | i2c_unregister_device(dev->client[2]); | 559 | i2c_unregister_device(dev->client[2]); |
| 524 | err_regmap_1_regmap_exit: | 560 | err_regmap_1_regmap_exit: |
| @@ -561,11 +597,12 @@ MODULE_DEVICE_TABLE(i2c, mn88472_id_table); · 36 unmodified lines | |||
| 561 | 597 | ||
| 562 | static struct i2c_driver mn88472_driver = { | 598 | static struct i2c_driver mn88472_driver = { |
| 563 | .driver = { | 599 | .driver = { |
| 564 | .name = "mn88472", | 600 | .name = "mn88472", |
| 601 | .suppress_bind_attrs = true, | ||
| 565 | }, | 602 | }, |
| 566 | .probe = mn88472_probe, | 603 | .probe = mn88472_probe, |
| 567 | .remove = mn88472_remove, | 604 | .remove = mn88472_remove, |
| 568 | .id_table = mn88472_id_table, | 605 | .id_table = mn88472_id_table, |
| 569 | }; | 606 | }; |
| 570 | 607 | ||
| 571 | module_i2c_driver(mn88472_driver); | 608 | module_i2c_driver(mn88472_driver); |
| @@ -19,23 +19,33 @@ · 18 unmodified lines | |||
| 19 | 19 | ||
| 20 | #include <linux/dvb/frontend.h> | 20 | #include <linux/dvb/frontend.h> |
| 21 | 21 | ||
| 22 | enum ts_clock { | 22 | /** |
| 23 | VARIABLE_TS_CLOCK, | 23 | * struct mn88472_config - Platform data for the mn88472 driver |
| 24 | FIXED_TS_CLOCK, | 24 | * @xtal: Clock frequency. |
| 25 | }; | 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 { | 31 | /* Define old names for backward compatibility */ |
| 28 | SERIAL_TS_MODE, | 32 | #define VARIABLE_TS_CLOCK MN88472_TS_CLK_VARIABLE |
| 29 | PARALLEL_TS_MODE, | 33 | #define FIXED_TS_CLOCK MN88472_TS_CLK_FIXED |
| 30 | }; | 34 | #define SERIAL_TS_MODE MN88472_TS_MODE_SERIAL |
| 35 | #define PARALLEL_TS_MODE MN88472_TS_MODE_PARALLEL | ||
| 31 | 36 | ||
| 32 | struct mn88472_config { | 37 | struct mn88472_config { |
| 33 | /* | 38 | unsigned int xtal; |
| 34 | * Max num of bytes given I2C adapter could write at once. | 39 | |
| 35 | * Default: none | 40 | #define MN88472_TS_MODE_SERIAL 0 |
| 36 | */ | 41 | #define MN88472_TS_MODE_PARALLEL 1 |
| 37 | u16 i2c_wr_max; | 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 | /* Everything after that is returned by the driver. */ | 50 | /* Everything after that is returned by the driver. */ |
| 41 | 51 | ||
| @@ -43,14 +53,7 @@ struct mn88472_config { · 1 unmodified line | |||
| 43 | * DVB frontend. | 53 | * DVB frontend. |
| 44 | */ | 54 | */ |
| 45 | struct dvb_frontend **fe; | 55 | struct dvb_frontend **fe; |
| 46 | 56 | struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); | |
| 47 | /* | ||
| 48 | * Xtal frequency. | ||
| 49 | * Hz | ||
| 50 | */ | ||
| 51 | u32 xtal; | ||
| 52 | int ts_mode; | ||
| 53 | int ts_clock; | ||
| 54 | }; | 57 | }; |
| 55 | 58 | ||
| 56 | #endif | 59 | #endif |
| @@ -28,12 +28,11 @@ struct mn88472_dev { · 27 unmodified lines | |||
| 28 | struct i2c_client *client[3]; | 28 | struct i2c_client *client[3]; |
| 29 | struct regmap *regmap[3]; | 29 | struct regmap *regmap[3]; |
| 30 | struct dvb_frontend fe; | 30 | struct dvb_frontend fe; |
| 31 | u16 i2c_wr_max; | 31 | u16 i2c_write_max; |
| 32 | enum fe_delivery_system delivery_system; | 32 | unsigned int clk; |
| 33 | bool warm; /* FW running */ | 33 | unsigned int active:1; |
| 34 | u32 xtal; | 34 | unsigned int ts_mode:1; |
| 35 | int ts_mode; | 35 | unsigned int ts_clk:1; |
| 36 | int ts_clock; | ||
| 37 | }; | 36 | }; |
| 38 | 37 | ||
| 39 | #endif | 38 | #endif |
| @@ -330,7 +330,7 @@ static int mn88473_init(struct dvb_frontend *fe) · 329 unmodified lines | |||
| 330 | /* Request the firmware, this will block and timeout */ | 330 | /* Request the firmware, this will block and timeout */ |
| 331 | ret = request_firmware(&fw, name, &client->dev); | 331 | ret = request_firmware(&fw, name, &client->dev); |
| 332 | if (ret) { | 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 | goto err; | 334 | goto err; |
| 335 | } | 335 | } |
| 336 | 336 | ||
| @@ -536,7 +536,7 @@ static int mn88473_probe(struct i2c_client *client, · 199 unmodified lines | |||
| 536 | /* Sleep because chip is active by default */ | 536 | /* Sleep because chip is active by default */ |
| 537 | ret = regmap_write(dev->regmap[2], 0x05, 0x3e); | 537 | ret = regmap_write(dev->regmap[2], 0x05, 0x3e); |
| 538 | if (ret) | 538 | if (ret) |
| 539 | goto err_client_2_i2c_unregister_device; | 539 | goto err_regmap_2_regmap_exit; |
| 540 | 540 | ||
| 541 | /* Create dvb frontend */ | 541 | /* Create dvb frontend */ |
| 542 | memcpy(&dev->frontend.ops, &mn88473_ops, sizeof(dev->frontend.ops)); | 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 | dev_info(&client->dev, "Panasonic MN88473 successfully identified\n"); | 547 | dev_info(&client->dev, "Panasonic MN88473 successfully identified\n"); |
| 548 | 548 | ||
| 549 | return 0; | 549 | return 0; |
| 550 | 550 | err_regmap_2_regmap_exit: | |
| 551 | regmap_exit(dev->regmap[2]); | ||
| 551 | err_client_2_i2c_unregister_device: | 552 | err_client_2_i2c_unregister_device: |
| 552 | i2c_unregister_device(dev->client[2]); | 553 | i2c_unregister_device(dev->client[2]); |
| 553 | err_regmap_1_regmap_exit: | 554 | err_regmap_1_regmap_exit: |
| @@ -135,8 +135,6 @@ static int rtl2830_init(struct dvb_frontend *fe) · 134 unmodified lines | |||
| 135 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 135 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
| 136 | c->post_bit_count.len = 1; | 136 | c->post_bit_count.len = 1; |
| 137 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | 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 | dev->sleeping = false; | 139 | dev->sleeping = false; |
| 142 | 140 | ||
| @@ -152,8 +150,6 @@ static int rtl2830_sleep(struct dvb_frontend *fe) · 9 unmodified lines | |||
| 152 | struct rtl2830_dev *dev = i2c_get_clientdata(client); | 150 | struct rtl2830_dev *dev = i2c_get_clientdata(client); |
| 153 | 151 | ||
| 154 | dev->sleeping = true; | 152 | dev->sleeping = true; |
| 155 | /* stop statistics polling */ | ||
| 156 | cancel_delayed_work_sync(&dev->stat_work); | ||
| 157 | dev->fe_status = 0; | 153 | dev->fe_status = 0; |
| 158 | 154 | ||
| 159 | return 0; | 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 | struct i2c_client *client = fe->demodulator_priv; | 393 | struct i2c_client *client = fe->demodulator_priv; |
| 398 | struct rtl2830_dev *dev = i2c_get_clientdata(client); | 394 | struct rtl2830_dev *dev = i2c_get_clientdata(client); |
| 399 | int ret; | 395 | struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; |
| 400 | u8 u8tmp; | 396 | int ret, stmp; |
| 397 | unsigned int utmp; | ||
| 398 | u8 u8tmp, buf[2]; | ||
| 401 | 399 | ||
| 402 | *status = 0; | 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 | dev->fe_status = *status; | 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 | return ret; | 503 | return ret; |
| 423 | err: | 504 | err: |
| 424 | dev_dbg(&client->dev, "failed=%d\n", ret); | 505 | dev_dbg(&client->dev, "failed=%d\n", ret); |
| @@ -503,109 +584,6 @@ static struct dvb_frontend_ops rtl2830_ops = { · 78 unmodified lines | |||
| 503 | .read_signal_strength = rtl2830_read_signal_strength, | 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 | static int rtl2830_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) | 587 | static int rtl2830_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) |
| 610 | { | 588 | { |
| 611 | struct i2c_client *client = fe->demodulator_priv; | 589 | struct i2c_client *client = fe->demodulator_priv; |
| @@ -851,7 +829,6 @@ static int rtl2830_probe(struct i2c_client *client, · 239 unmodified lines | |||
| 851 | dev->client = client; | 829 | dev->client = client; |
| 852 | dev->pdata = client->dev.platform_data; | 830 | dev->pdata = client->dev.platform_data; |
| 853 | dev->sleeping = true; | 831 | dev->sleeping = true; |
| 854 | INIT_DELAYED_WORK(&dev->stat_work, rtl2830_stat_work); | ||
| 855 | dev->regmap = regmap_init(&client->dev, ®map_bus, client, | 832 | dev->regmap = regmap_init(&client->dev, ®map_bus, client, |
| 856 | ®map_config); | 833 | ®map_config); |
| 857 | if (IS_ERR(dev->regmap)) { | 834 | if (IS_ERR(dev->regmap)) { |
| @@ -904,9 +881,6 @@ static int rtl2830_remove(struct i2c_client *client) · 46 unmodified lines | |||
| 904 | 881 | ||
| 905 | dev_dbg(&client->dev, "\n"); | 882 | dev_dbg(&client->dev, "\n"); |
| 906 | 883 | ||
| 907 | /* stop statistics polling */ | ||
| 908 | cancel_delayed_work_sync(&dev->stat_work); | ||
| 909 | |||
| 910 | i2c_mux_del_adapters(dev->muxc); | 884 | i2c_mux_del_adapters(dev->muxc); |
| 911 | regmap_exit(dev->regmap); | 885 | regmap_exit(dev->regmap); |
| 912 | kfree(dev); | 886 | kfree(dev); |
| @@ -922,7 +896,8 @@ MODULE_DEVICE_TABLE(i2c, rtl2830_id_table); · 9 unmodified lines | |||
| 922 | 896 | ||
| 923 | static struct i2c_driver rtl2830_driver = { | 897 | static struct i2c_driver rtl2830_driver = { |
| 924 | .driver = { | 898 | .driver = { |
| 925 | .name = "rtl2830", | 899 | .name = "rtl2830", |
| 900 | .suppress_bind_attrs = true, | ||
| 926 | }, | 901 | }, |
| 927 | .probe = rtl2830_probe, | 902 | .probe = rtl2830_probe, |
| 928 | .remove = rtl2830_remove, | 903 | .remove = rtl2830_remove, |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | |||
| 24 | #include <linux/i2c-mux.h> | 24 | #include <linux/i2c-mux.h> |
| 25 | #include <linux/math64.h> | 25 | #include <linux/math64.h> |
| 26 | #include <linux/regmap.h> | 26 | #include <linux/regmap.h> |
| 27 | #include <linux/bitops.h> | ||
| 27 | 28 | ||
| 28 | struct rtl2830_dev { | 29 | struct rtl2830_dev { |
| 29 | struct rtl2830_platform_data *pdata; | 30 | struct rtl2830_platform_data *pdata; |
| @@ -33,7 +34,6 @@ struct rtl2830_dev { · 3 unmodified lines | |||
| 33 | struct dvb_frontend fe; | 34 | struct dvb_frontend fe; |
| 34 | bool sleeping; | 35 | bool sleeping; |
| 35 | unsigned long filters; | 36 | unsigned long filters; |
| 36 | struct delayed_work stat_work; | ||
| 37 | enum fe_status fe_status; | 37 | enum fe_status fe_status; |
| 38 | u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */ | 38 | u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */ |
| 39 | u64 post_bit_error; | 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 | goto err; | 947 | goto err; |
| 948 | } | 948 | } |
| 949 | 949 | ||
| 950 | dev->slave_ts = enable; | ||
| 951 | |||
| 950 | return 0; | 952 | return 0; |
| 951 | err: | 953 | err: |
| 952 | dev_dbg(&client->dev, "failed=%d\n", ret); | 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 | int ret; | 962 | int ret; |
| 961 | u8 u8tmp; | 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 | /* enable / disable PID filter */ | 967 | /* enable / disable PID filter */ |
| 966 | if (onoff) | 968 | if (onoff) |
| @@ -968,7 +970,10 @@ static int rtl2832_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) · 1 unmodified line | |||
| 968 | else | 970 | else |
| 969 | u8tmp = 0x00; | 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 | if (ret) | 977 | if (ret) |
| 973 | goto err; | 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 | int ret; | 991 | int ret; |
| 987 | u8 buf[4]; | 992 | u8 buf[4]; |
| 988 | 993 | ||
| 989 | dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d\n", | 994 | dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d slave_ts=%d\n", |
| 990 | index, pid, onoff); | 995 | index, pid, onoff, dev->slave_ts); |
| 991 | 996 | ||
| 992 | /* skip invalid PIDs (0x2000) */ | 997 | /* skip invalid PIDs (0x2000) */ |
| 993 | if (pid > 0x1fff || index > 32) | 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 | buf[1] = (dev->filters >> 8) & 0xff; | 1008 | buf[1] = (dev->filters >> 8) & 0xff; |
| 1004 | buf[2] = (dev->filters >> 16) & 0xff; | 1009 | buf[2] = (dev->filters >> 16) & 0xff; |
| 1005 | buf[3] = (dev->filters >> 24) & 0xff; | 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 | if (ret) | 1016 | if (ret) |
| 1008 | goto err; | 1017 | goto err; |
| 1009 | 1018 | ||
| 1010 | /* add PID */ | 1019 | /* add PID */ |
| 1011 | buf[0] = (pid >> 8) & 0xff; | 1020 | buf[0] = (pid >> 8) & 0xff; |
| 1012 | buf[1] = (pid >> 0) & 0xff; | 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 | if (ret) | 1027 | if (ret) |
| 1015 | goto err; | 1028 | goto err; |
| 1016 | 1029 | ||
| @@ -1135,6 +1148,7 @@ MODULE_DEVICE_TABLE(i2c, rtl2832_id_table); · 118 unmodified lines | |||
| 1135 | static struct i2c_driver rtl2832_driver = { | 1148 | static struct i2c_driver rtl2832_driver = { |
| 1136 | .driver = { | 1149 | .driver = { |
| 1137 | .name = "rtl2832", | 1150 | .name = "rtl2832", |
| 1151 | .suppress_bind_attrs = true, | ||
| 1138 | }, | 1152 | }, |
| 1139 | .probe = rtl2832_probe, | 1153 | .probe = rtl2832_probe, |
| 1140 | .remove = rtl2832_remove, | 1154 | .remove = rtl2832_remove, |
| @@ -44,6 +44,7 @@ struct rtl2832_dev { · 43 unmodified lines | |||
| 44 | bool sleeping; | 44 | bool sleeping; |
| 45 | struct delayed_work i2c_gate_work; | 45 | struct delayed_work i2c_gate_work; |
| 46 | unsigned long filters; /* PID filter */ | 46 | unsigned long filters; /* PID filter */ |
| 47 | bool slave_ts; | ||
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| 49 | struct rtl2832_reg_entry { | 50 | struct rtl2832_reg_entry { |
| @@ -452,7 +452,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh, · 451 unmodified lines | |||
| 452 | /* Videobuf2 operations */ | 452 | /* Videobuf2 operations */ |
| 453 | static int rtl2832_sdr_queue_setup(struct vb2_queue *vq, | 453 | static int rtl2832_sdr_queue_setup(struct vb2_queue *vq, |
| 454 | unsigned int *nbuffers, | 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 | struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq); | 457 | struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq); |
| 458 | struct platform_device *pdev = dev->pdev; | 458 | struct platform_device *pdev = dev->pdev; |
| @@ -357,9 +357,7 @@ static int si2168_init(struct dvb_frontend *fe) · 356 unmodified lines | |||
| 357 | struct si2168_dev *dev = i2c_get_clientdata(client); | 357 | struct si2168_dev *dev = i2c_get_clientdata(client); |
| 358 | int ret, len, remaining; | 358 | int ret, len, remaining; |
| 359 | const struct firmware *fw; | 359 | const struct firmware *fw; |
| 360 | const char *fw_name; | ||
| 361 | struct si2168_cmd cmd; | 360 | struct si2168_cmd cmd; |
| 362 | unsigned int chip_id; | ||
| 363 | 361 | ||
| 364 | dev_dbg(&client->dev, "\n"); | 362 | dev_dbg(&client->dev, "\n"); |
| 365 | 363 | ||
| @@ -371,7 +369,7 @@ static int si2168_init(struct dvb_frontend *fe) · 5 unmodified lines | |||
| 371 | if (ret) | 369 | if (ret) |
| 372 | goto err; | 370 | goto err; |
| 373 | 371 | ||
| 374 | if (dev->fw_loaded) { | 372 | if (dev->warm) { |
| 375 | /* resume */ | 373 | /* resume */ |
| 376 | memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8); | 374 | memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8); |
| 377 | cmd.wlen = 8; | 375 | cmd.wlen = 8; |
| @@ -398,49 +396,14 @@ static int si2168_init(struct dvb_frontend *fe) · 20 unmodified lines | |||
| 398 | if (ret) | 396 | if (ret) |
| 399 | goto err; | 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 | /* request the firmware, this will block and timeout */ | 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 | if (ret) { | 401 | if (ret) { |
| 440 | /* fallback mechanism to handle old name for Si2168 B40 fw */ | 402 | /* fallback mechanism to handle old name for Si2168 B40 fw */ |
| 441 | if (chip_id == SI2168_B40) { | 403 | if (dev->chip_id == SI2168_CHIP_ID_B40) { |
| 442 | fw_name = SI2168_B40_FIRMWARE_FALLBACK; | 404 | dev->firmware_name = SI2168_B40_FIRMWARE_FALLBACK; |
| 443 | ret = request_firmware(&fw, fw_name, &client->dev); | 405 | ret = request_firmware(&fw, dev->firmware_name, |
| 406 | &client->dev); | ||
| 444 | } | 407 | } |
| 445 | 408 | ||
| 446 | if (ret == 0) { | 409 | if (ret == 0) { |
| @@ -450,13 +413,13 @@ static int si2168_init(struct dvb_frontend *fe) · 3 unmodified lines | |||
| 450 | } else { | 413 | } else { |
| 451 | dev_err(&client->dev, | 414 | dev_err(&client->dev, |
| 452 | "firmware file '%s' not found\n", | 415 | "firmware file '%s' not found\n", |
| 453 | fw_name); | 416 | dev->firmware_name); |
| 454 | goto err_release_firmware; | 417 | goto err_release_firmware; |
| 455 | } | 418 | } |
| 456 | } | 419 | } |
| 457 | 420 | ||
| 458 | dev_info(&client->dev, "downloading firmware from file '%s'\n", | 421 | dev_info(&client->dev, "downloading firmware from file '%s'\n", |
| 459 | fw_name); | 422 | dev->firmware_name); |
| 460 | 423 | ||
| 461 | if ((fw->size % 17 == 0) && (fw->data[0] > 5)) { | 424 | if ((fw->size % 17 == 0) && (fw->data[0] > 5)) { |
| 462 | /* firmware is in the new format */ | 425 | /* firmware is in the new format */ |
| @@ -511,8 +474,11 @@ static int si2168_init(struct dvb_frontend *fe) · 48 unmodified lines | |||
| 511 | if (ret) | 474 | if (ret) |
| 512 | goto err; | 475 | goto err; |
| 513 | 476 | ||
| 514 | dev_info(&client->dev, "firmware version: %c.%c.%d\n", | 477 | dev->version = (cmd.args[9] + '@') << 24 | (cmd.args[6] - '0') << 16 | |
| 515 | cmd.args[6], cmd.args[7], cmd.args[8]); | 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 | /* set ts mode */ | 483 | /* set ts mode */ |
| 518 | memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); | 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 | if (ret) | 491 | if (ret) |
| 526 | goto err; | 492 | goto err; |
| 527 | 493 | ||
| 528 | dev->fw_loaded = true; | 494 | dev->warm = true; |
| 529 | warm: | 495 | warm: |
| 530 | dev->active = true; | 496 | dev->active = true; |
| 531 | 497 | ||
| @@ -549,6 +515,10 @@ static int si2168_sleep(struct dvb_frontend *fe) · 17 unmodified lines | |||
| 549 | 515 | ||
| 550 | dev->active = false; | 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 | memcpy(cmd.args, "\x13", 1); | 522 | memcpy(cmd.args, "\x13", 1); |
| 553 | cmd.wlen = 1; | 523 | cmd.wlen = 1; |
| 554 | cmd.rlen = 0; | 524 | cmd.rlen = 0; |
| @@ -653,6 +623,7 @@ static int si2168_probe(struct i2c_client *client, · 98 unmodified lines | |||
| 653 | struct si2168_config *config = client->dev.platform_data; | 623 | struct si2168_config *config = client->dev.platform_data; |
| 654 | struct si2168_dev *dev; | 624 | struct si2168_dev *dev; |
| 655 | int ret; | 625 | int ret; |
| 626 | struct si2168_cmd cmd; | ||
| 656 | 627 | ||
| 657 | dev_dbg(&client->dev, "\n"); | 628 | dev_dbg(&client->dev, "\n"); |
| 658 | 629 | ||
| @@ -663,8 +634,56 @@ static int si2168_probe(struct i2c_client *client, · 4 unmodified lines | |||
| 663 | goto err; | 634 | goto err; |
| 664 | } | 635 | } |
| 665 | 636 | ||
| 637 | i2c_set_clientdata(client, dev); | ||
| 666 | mutex_init(&dev->i2c_mutex); | 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 | /* create mux i2c adapter for tuner */ | 687 | /* create mux i2c adapter for tuner */ |
| 669 | dev->muxc = i2c_mux_alloc(client->adapter, &client->dev, | 688 | dev->muxc = i2c_mux_alloc(client->adapter, &client->dev, |
| 670 | 1, 0, I2C_MUX_LOCKED, | 689 | 1, 0, I2C_MUX_LOCKED, |
| @@ -686,11 +705,14 @@ static int si2168_probe(struct i2c_client *client, · 15 unmodified lines | |||
| 686 | dev->ts_mode = config->ts_mode; | 705 | dev->ts_mode = config->ts_mode; |
| 687 | dev->ts_clock_inv = config->ts_clock_inv; | 706 | dev->ts_clock_inv = config->ts_clock_inv; |
| 688 | dev->ts_clock_gapped = config->ts_clock_gapped; | 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 | return 0; | 716 | return 0; |
| 695 | err_kfree: | 717 | err_kfree: |
| 696 | kfree(dev); | 718 | kfree(dev); |
| @@ -723,7 +745,8 @@ MODULE_DEVICE_TABLE(i2c, si2168_id_table); · 26 unmodified lines | |||
| 723 | 745 | ||
| 724 | static struct i2c_driver si2168_driver = { | 746 | static struct i2c_driver si2168_driver = { |
| 725 | .driver = { | 747 | .driver = { |
| 726 | .name = "si2168", | 748 | .name = "si2168", |
| 749 | .suppress_bind_attrs = true, | ||
| 727 | }, | 750 | }, |
| 728 | .probe = si2168_probe, | 751 | .probe = si2168_probe, |
| 729 | .remove = si2168_remove, | 752 | .remove = si2168_remove, |
| @@ -34,8 +34,14 @@ struct si2168_dev { · 33 unmodified lines | |||
| 34 | struct dvb_frontend fe; | 34 | struct dvb_frontend fe; |
| 35 | enum fe_delivery_system delivery_system; | 35 | enum fe_delivery_system delivery_system; |
| 36 | enum fe_status fe_status; | 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 | bool active; | 43 | bool active; |
| 38 | bool fw_loaded; | 44 | bool warm; |
| 39 | u8 ts_mode; | 45 | u8 ts_mode; |
| 40 | bool ts_clock_inv; | 46 | bool ts_clock_inv; |
| 41 | bool ts_clock_gapped; | 47 | bool ts_clock_gapped; |
| @@ -209,6 +209,7 @@ config VIDEO_ADV7604 · 208 unmodified lines | |||
| 209 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API | 209 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
| 210 | depends on GPIOLIB || COMPILE_TEST | 210 | depends on GPIOLIB || COMPILE_TEST |
| 211 | select HDMI | 211 | select HDMI |
| 212 | select MEDIA_CEC_EDID | ||
| 212 | ---help--- | 213 | ---help--- |
| 213 | Support for the Analog Devices ADV7604 video decoder. | 214 | Support for the Analog Devices ADV7604 video decoder. |
| 214 | 215 | ||
| @@ -218,10 +219,18 @@ config VIDEO_ADV7604 · 3 unmodified lines | |||
| 218 | To compile this driver as a module, choose M here: the | 219 | To compile this driver as a module, choose M here: the |
| 219 | module will be called adv7604. | 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 | config VIDEO_ADV7842 | 229 | config VIDEO_ADV7842 |
| 222 | tristate "Analog Devices ADV7842 decoder" | 230 | tristate "Analog Devices ADV7842 decoder" |
| 223 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API | 231 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
| 224 | select HDMI | 232 | select HDMI |
| 233 | select MEDIA_CEC_EDID | ||
| 225 | ---help--- | 234 | ---help--- |
| 226 | Support for the Analog Devices ADV7842 video decoder. | 235 | Support for the Analog Devices ADV7842 video decoder. |
| 227 | 236 | ||
| @@ -231,6 +240,13 @@ config VIDEO_ADV7842 · 3 unmodified lines | |||
| 231 | To compile this driver as a module, choose M here: the | 240 | To compile this driver as a module, choose M here: the |
| 232 | module will be called adv7842. | 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 | config VIDEO_BT819 | 250 | config VIDEO_BT819 |
| 235 | tristate "BT819A VideoStream decoder" | 251 | tristate "BT819A VideoStream decoder" |
| 236 | depends on VIDEO_V4L2 && I2C | 252 | depends on VIDEO_V4L2 && I2C |
| @@ -447,6 +463,7 @@ config VIDEO_ADV7511 · 210 unmodified lines | |||
| 447 | tristate "Analog Devices ADV7511 encoder" | 463 | tristate "Analog Devices ADV7511 encoder" |
| 448 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API | 464 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
| 449 | select HDMI | 465 | select HDMI |
| 466 | select MEDIA_CEC_EDID | ||
| 450 | ---help--- | 467 | ---help--- |
| 451 | Support for the Analog Devices ADV7511 video encoder. | 468 | Support for the Analog Devices ADV7511 video encoder. |
| 452 | 469 | ||
| @@ -455,6 +472,13 @@ config VIDEO_ADV7511 · 2 unmodified lines | |||
| 455 | To compile this driver as a module, choose M here: the | 472 | To compile this driver as a module, choose M here: the |
| 456 | module will be called adv7511. | 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 | config VIDEO_AD9389B | 482 | config VIDEO_AD9389B |
| 459 | tristate "Analog Devices AD9389B encoder" | 483 | tristate "Analog Devices AD9389B encoder" |
| 460 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API | 484 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
| @@ -33,6 +33,7 @@ · 32 unmodified lines | |||
| 33 | #include <media/v4l2-ctrls.h> | 33 | #include <media/v4l2-ctrls.h> |
| 34 | #include <media/v4l2-dv-timings.h> | 34 | #include <media/v4l2-dv-timings.h> |
| 35 | #include <media/i2c/adv7511.h> | 35 | #include <media/i2c/adv7511.h> |
| 36 | #include <media/cec.h> | ||
| 36 | 37 | ||
| 37 | static int debug; | 38 | static int debug; |
| 38 | module_param(debug, int, 0644); | 39 | module_param(debug, int, 0644); |
| @@ -59,6 +60,8 @@ MODULE_LICENSE("GPL v2"); · 20 unmodified lines | |||
| 59 | #define ADV7511_MIN_PIXELCLOCK 20000000 | 60 | #define ADV7511_MIN_PIXELCLOCK 20000000 |
| 60 | #define ADV7511_MAX_PIXELCLOCK 225000000 | 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 | struct v4l2_ctrl_handler hdl; | 93 | struct v4l2_ctrl_handler hdl; |
| 91 | int chip_revision; | 94 | int chip_revision; |
| 92 | u8 i2c_edid_addr; | 95 | u8 i2c_edid_addr; |
| 93 | u8 i2c_cec_addr; | ||
| 94 | u8 i2c_pktmem_addr; | 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 | /* Is the adv7511 powered on? */ | 105 | /* Is the adv7511 powered on? */ |
| 96 | bool power_on; | 106 | bool power_on; |
| 97 | /* Did we receive hotplug and rx-sense signals? */ | 107 | /* Did we receive hotplug and rx-sense signals? */ |
| 98 | bool have_monitor; | 108 | bool have_monitor; |
| 109 | bool enabled_irq; | ||
| 99 | /* timings from s_dv_timings */ | 110 | /* timings from s_dv_timings */ |
| 100 | struct v4l2_dv_timings dv_timings; | 111 | struct v4l2_dv_timings dv_timings; |
| 101 | u32 fmt_code; | 112 | u32 fmt_code; |
| @@ -227,7 +238,7 @@ static int adv_smbus_read_i2c_block_data(struct i2c_client *client, · 125 unmodified lines | |||
| 227 | return ret; | 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 | struct adv7511_state *state = get_adv7511_state(sd); | 243 | struct adv7511_state *state = get_adv7511_state(sd); |
| 233 | int i; | 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 | v4l2_err(sd, "%s: i2c read error\n", __func__); | 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 | static int adv7511_pktmem_rd(struct v4l2_subdev *sd, u8 reg) | 284 | static int adv7511_pktmem_rd(struct v4l2_subdev *sd, u8 reg) |
| 246 | { | 285 | { |
| 247 | struct adv7511_state *state = get_adv7511_state(sd); | 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 | struct adv7511_state *state = get_adv7511_state(sd); | 387 | struct adv7511_state *state = get_adv7511_state(sd); |
| 349 | if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { | 388 | |
| 350 | /* CE format, not IT */ | 389 | /* Only makes sense for RGB formats */ |
| 351 | adv7511_wr_and_or(sd, 0x57, 0x7f, 0x00); | 390 | if (state->fmt_code != MEDIA_BUS_FMT_RGB888_1X24) { |
| 352 | } else { | 391 | /* so just keep quantization */ |
| 353 | /* IT format */ | 392 | adv7511_csc_rgb_full2limit(sd, false); |
| 354 | adv7511_wr_and_or(sd, 0x57, 0x7f, 0x80); | 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 | switch (ctrl->val) { | 396 | switch (ctrl->val) { |
| 361 | default: | 397 | case V4L2_DV_RGB_RANGE_AUTO: |
| 362 | return -EINVAL; | ||
| 363 | break; | ||
| 364 | case V4L2_DV_RGB_RANGE_AUTO: { | ||
| 365 | /* automatic */ | 398 | /* automatic */ |
| 366 | struct adv7511_state *state = get_adv7511_state(sd); | ||
| 367 | |||
| 368 | if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { | 399 | if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { |
| 369 | /* CE format, RGB limited range (16-235) */ | 400 | /* CE format, RGB limited range (16-235) */ |
| 370 | adv7511_csc_rgb_full2limit(sd, true); | 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 | /* not CE format, RGB full range (0-255) */ | 403 | /* not CE format, RGB full range (0-255) */ |
| 373 | adv7511_csc_rgb_full2limit(sd, false); | 404 | adv7511_csc_rgb_full2limit(sd, false); |
| 374 | } | 405 | } |
| 375 | } | ||
| 376 | break; | 406 | break; |
| 377 | case V4L2_DV_RGB_RANGE_LIMITED: | 407 | case V4L2_DV_RGB_RANGE_LIMITED: |
| 378 | /* RGB limited range (16-235) */ | 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 | adv7511_csc_rgb_full2limit(sd, false); | 413 | adv7511_csc_rgb_full2limit(sd, false); |
| 384 | break; | 414 | break; |
| 385 | } | 415 | } |
| 386 | return 0; | ||
| 387 | } | 416 | } |
| 388 | 417 | ||
| 389 | /* ------------------------------ CTRL OPS ------------------------------ */ | 418 | /* ------------------------------ CTRL OPS ------------------------------ */ |
| @@ -400,8 +429,10 @@ static int adv7511_s_ctrl(struct v4l2_ctrl *ctrl) · 10 unmodified lines | |||
| 400 | adv7511_wr_and_or(sd, 0xaf, 0xfd, ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00); | 429 | adv7511_wr_and_or(sd, 0xaf, 0xfd, ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00); |
| 401 | return 0; | 430 | return 0; |
| 402 | } | 431 | } |
| 403 | if (state->rgb_quantization_range_ctrl == ctrl) | 432 | if (state->rgb_quantization_range_ctrl == ctrl) { |
| 404 | return adv7511_set_rgb_quantization_mode(sd, ctrl); | 433 | adv7511_set_rgb_quantization_mode(sd, ctrl); |
| 434 | return 0; | ||
| 435 | } | ||
| 405 | if (state->content_type_ctrl == ctrl) { | 436 | if (state->content_type_ctrl == ctrl) { |
| 406 | u8 itc, cn; | 437 | u8 itc, cn; |
| 407 | 438 | ||
| @@ -425,16 +456,28 @@ static const struct v4l2_ctrl_ops adv7511_ctrl_ops = { · 17 unmodified lines | |||
| 425 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 456 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 426 | static void adv7511_inv_register(struct v4l2_subdev *sd) | 457 | static void adv7511_inv_register(struct v4l2_subdev *sd) |
| 427 | { | 458 | { |
| 459 | struct adv7511_state *state = get_adv7511_state(sd); | ||
| 460 | |||
| 428 | v4l2_info(sd, "0x000-0x0ff: Main Map\n"); | 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 | static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | 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 | reg->size = 1; | 470 | reg->size = 1; |
| 434 | switch (reg->reg >> 8) { | 471 | switch (reg->reg >> 8) { |
| 435 | case 0: | 472 | case 0: |
| 436 | reg->val = adv7511_rd(sd, reg->reg & 0xff); | 473 | reg->val = adv7511_rd(sd, reg->reg & 0xff); |
| 437 | break; | 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 | default: | 481 | default: |
| 439 | v4l2_info(sd, "Register %03llx not supported\n", reg->reg); | 482 | v4l2_info(sd, "Register %03llx not supported\n", reg->reg); |
| 440 | adv7511_inv_register(sd); | 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 | static int adv7511_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) | 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 | switch (reg->reg >> 8) { | 493 | switch (reg->reg >> 8) { |
| 449 | case 0: | 494 | case 0: |
| 450 | adv7511_wr(sd, reg->reg & 0xff, reg->val & 0xff); | 495 | adv7511_wr(sd, reg->reg & 0xff, reg->val & 0xff); |
| 451 | break; | 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 | default: | 503 | default: |
| 453 | v4l2_info(sd, "Register %03llx not supported\n", reg->reg); | 504 | v4l2_info(sd, "Register %03llx not supported\n", reg->reg); |
| 454 | adv7511_inv_register(sd); | 505 | adv7511_inv_register(sd); |
| @@ -536,6 +587,7 @@ static int adv7511_log_status(struct v4l2_subdev *sd) · 81 unmodified lines | |||
| 536 | { | 587 | { |
| 537 | struct adv7511_state *state = get_adv7511_state(sd); | 588 | struct adv7511_state *state = get_adv7511_state(sd); |
| 538 | struct adv7511_state_edid *edid = &state->edid; | 589 | struct adv7511_state_edid *edid = &state->edid; |
| 590 | int i; | ||
| 539 | 591 | ||
| 540 | static const char * const states[] = { | 592 | static const char * const states[] = { |
| 541 | "in reset", | 593 | "in reset", |
| @@ -605,7 +657,23 @@ static int adv7511_log_status(struct v4l2_subdev *sd) · 63 unmodified lines | |||
| 605 | else | 657 | else |
| 606 | v4l2_info(sd, "no timings set\n"); | 658 | v4l2_info(sd, "no timings set\n"); |
| 607 | v4l2_info(sd, "i2c edid addr: 0x%x\n", state->i2c_edid_addr); | 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 | v4l2_info(sd, "i2c cec addr: 0x%x\n", state->i2c_cec_addr); | 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 | v4l2_info(sd, "i2c pktmem addr: 0x%x\n", state->i2c_pktmem_addr); | 677 | v4l2_info(sd, "i2c pktmem addr: 0x%x\n", state->i2c_pktmem_addr); |
| 610 | return 0; | 678 | return 0; |
| 611 | } | 679 | } |
| @@ -663,15 +731,197 @@ static int adv7511_s_power(struct v4l2_subdev *sd, int on) · 51 unmodified lines | |||
| 663 | return true; | 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 | /* Enable interrupts */ | 911 | /* Enable interrupts */ |
| 667 | static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) | 912 | static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) |
| 668 | { | 913 | { |
| 914 | struct adv7511_state *state = get_adv7511_state(sd); | ||
| 669 | u8 irqs = MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT; | 915 | u8 irqs = MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT; |
| 670 | u8 irqs_rd; | 916 | u8 irqs_rd; |
| 671 | int retries = 100; | 917 | int retries = 100; |
| 672 | 918 | ||
| 673 | v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? "enable" : "disable"); | 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 | /* The datasheet says that the EDID ready interrupt should be | 925 | /* The datasheet says that the EDID ready interrupt should be |
| 676 | disabled if there is no hotplug. */ | 926 | disabled if there is no hotplug. */ |
| 677 | if (!enable) | 927 | if (!enable) |
| @@ -679,6 +929,9 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) · 1 unmodified line | |||
| 679 | else if (adv7511_have_hotplug(sd)) | 929 | else if (adv7511_have_hotplug(sd)) |
| 680 | irqs |= MASK_ADV7511_EDID_RDY_INT; | 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 | * This i2c write can fail (approx. 1 in 1000 writes). But it | 936 | * This i2c write can fail (approx. 1 in 1000 writes). But it |
| 684 | * is essential that this register is correct, so retry it | 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 | static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | 954 | static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled) |
| 702 | { | 955 | { |
| 703 | u8 irq_status; | 956 | u8 irq_status; |
| 957 | u8 cec_irq; | ||
| 704 | 958 | ||
| 705 | /* disable interrupts to prevent a race condition */ | 959 | /* disable interrupts to prevent a race condition */ |
| 706 | adv7511_set_isr(sd, false); | 960 | adv7511_set_isr(sd, false); |
| 707 | irq_status = adv7511_rd(sd, 0x96); | 961 | irq_status = adv7511_rd(sd, 0x96); |
| 962 | cec_irq = adv7511_rd(sd, 0x97); | ||
| 708 | /* clear detected interrupts */ | 963 | /* clear detected interrupts */ |
| 709 | adv7511_wr(sd, 0x96, irq_status); | 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 | if (irq_status & (MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT)) | 970 | if (irq_status & (MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT)) |
| 714 | adv7511_check_monitor_present_status(sd); | 971 | adv7511_check_monitor_present_status(sd); |
| 715 | if (irq_status & MASK_ADV7511_EDID_RDY_INT) | 972 | if (irq_status & MASK_ADV7511_EDID_RDY_INT) |
| 716 | adv7511_check_edid_status(sd); | 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 | /* enable interrupts */ | 1004 | /* enable interrupts */ |
| 719 | adv7511_set_isr(sd, true); | 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 | /* save timings */ | 1057 | /* save timings */ |
| 772 | state->dv_timings = *timings; | 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 | /* update quantization range based on new dv_timings */ | 1065 | /* update quantization range based on new dv_timings */ |
| 775 | adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl); | 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 | return 0; | 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 | static void adv7511_fill_format(struct adv7511_state *state, | 1244 | static void adv7511_fill_format(struct adv7511_state *state, |
| 957 | struct v4l2_mbus_framefmt *format) | 1245 | struct v4l2_mbus_framefmt *format) |
| 958 | { | 1246 | { |
| 959 | memset(format, 0, sizeof(*format)); | ||
| 960 | |||
| 961 | format->width = state->dv_timings.bt.width; | 1247 | format->width = state->dv_timings.bt.width; |
| 962 | format->height = state->dv_timings.bt.height; | 1248 | format->height = state->dv_timings.bt.height; |
| 963 | format->field = V4L2_FIELD_NONE; | 1249 | format->field = V4L2_FIELD_NONE; |
| @@ -972,6 +1258,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd, · 8 unmodified lines | |||
| 972 | if (format->pad != 0) | 1258 | if (format->pad != 0) |
| 973 | return -EINVAL; | 1259 | return -EINVAL; |
| 974 | 1260 | ||
| 1261 | memset(&format->format, 0, sizeof(format->format)); | ||
| 975 | adv7511_fill_format(state, &format->format); | 1262 | adv7511_fill_format(state, &format->format); |
| 976 | 1263 | ||
| 977 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) { | 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 | adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2) | (itc << 7)); | 1419 | adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2) | (itc << 7)); |
| 1133 | adv7511_wr_and_or(sd, 0x59, 0x0f, (yq << 6) | (cn << 4)); | 1420 | adv7511_wr_and_or(sd, 0x59, 0x0f, (yq << 6) | (cn << 4)); |
| 1134 | adv7511_wr_and_or(sd, 0x4a, 0xff, 1); | 1421 | adv7511_wr_and_or(sd, 0x4a, 0xff, 1); |
| 1422 | adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl); | ||
| 1135 | 1423 | ||
| 1136 | return 0; | 1424 | return 0; |
| 1137 | } | 1425 | } |
| @@ -1183,6 +1471,8 @@ static void adv7511_notify_no_edid(struct v4l2_subdev *sd) · 45 unmodified lines | |||
| 1183 | /* We failed to read the EDID, so send an event for this. */ | 1471 | /* We failed to read the EDID, so send an event for this. */ |
| 1184 | ed.present = false; | 1472 | ed.present = false; |
| 1185 | ed.segment = adv7511_rd(sd, 0xc4); | 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 | v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed); | 1476 | v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed); |
| 1187 | v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x0); | 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 | v4l2_dbg(1, debug, sd, "%s: edid complete with %d segment(s)\n", __func__, state->edid.segments); | 1697 | v4l2_dbg(1, debug, sd, "%s: edid complete with %d segment(s)\n", __func__, state->edid.segments); |
| 1408 | state->edid.complete = true; | 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 | /* report when we have all segments | 1702 | /* report when we have all segments |
| 1411 | but report only for segment 0 | 1703 | but report only for segment 0 |
| 1412 | */ | 1704 | */ |
| 1413 | ed.present = true; | 1705 | ed.present = true; |
| 1414 | ed.segment = 0; | 1706 | ed.segment = 0; |
| 1415 | state->edid_detect_counter++; | 1707 | state->edid_detect_counter++; |
| 1708 | cec_s_phys_addr(state->cec_adap, ed.phys_addr, false); | ||
| 1416 | v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed); | 1709 | v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed); |
| 1417 | return ed.present; | 1710 | return ed.present; |
| 1418 | } | 1711 | } |
| @@ -1420,17 +1713,43 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd) · 1 unmodified line | |||
| 1420 | return false; | 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 | /* Setup ADV7511 */ | 1740 | /* Setup ADV7511 */ |
| 1425 | static void adv7511_init_setup(struct v4l2_subdev *sd) | 1741 | static void adv7511_init_setup(struct v4l2_subdev *sd) |
| 1426 | { | 1742 | { |
| 1427 | struct adv7511_state *state = get_adv7511_state(sd); | 1743 | struct adv7511_state *state = get_adv7511_state(sd); |
| 1428 | struct adv7511_state_edid *edid = &state->edid; | 1744 | struct adv7511_state_edid *edid = &state->edid; |
| 1745 | u32 cec_clk = state->pdata.cec_clk; | ||
| 1746 | u8 ratio; | ||
| 1429 | 1747 | ||
| 1430 | v4l2_dbg(1, debug, sd, "%s\n", __func__); | 1748 | v4l2_dbg(1, debug, sd, "%s\n", __func__); |
| 1431 | 1749 | ||
| 1432 | /* clear all interrupts */ | 1750 | /* clear all interrupts */ |
| 1433 | adv7511_wr(sd, 0x96, 0xff); | 1751 | adv7511_wr(sd, 0x96, 0xff); |
| 1752 | adv7511_wr(sd, 0x97, 0xff); | ||
| 1434 | /* | 1753 | /* |
| 1435 | * Stop HPD from resetting a lot of registers. | 1754 | * Stop HPD from resetting a lot of registers. |
| 1436 | * It might leave the chip in a partly un-initialized state, | 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 | adv7511_set_isr(sd, false); | 1761 | adv7511_set_isr(sd, false); |
| 1443 | adv7511_s_stream(sd, false); | 1762 | adv7511_s_stream(sd, false); |
| 1444 | adv7511_s_audio_stream(sd, false); | 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 | static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *id) | 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 | client->addr << 1); | 1814 | client->addr << 1); |
| 1477 | 1815 | ||
| 1478 | v4l2_i2c_subdev_init(sd, client, &adv7511_ops); | 1816 | v4l2_i2c_subdev_init(sd, client, &adv7511_ops); |
| 1817 | sd->internal_ops = &adv7511_int_ops; | ||
| 1479 | 1818 | ||
| 1480 | hdl = &state->hdl; | 1819 | hdl = &state->hdl; |
| 1481 | v4l2_ctrl_handler_init(hdl, 10); | 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 | chip_id[0] = adv7511_rd(sd, 0xf5); | 1855 | chip_id[0] = adv7511_rd(sd, 0xf5); |
| 1517 | chip_id[1] = adv7511_rd(sd, 0xf6); | 1856 | chip_id[1] = adv7511_rd(sd, 0xf6); |
| 1518 | if (chip_id[0] != 0x75 || chip_id[1] != 0x11) { | 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 | err = -EIO; | 1860 | err = -EIO; |
| 1521 | goto err_entity; | 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 | if (state->i2c_edid == NULL) { | 1866 | if (state->i2c_edid == NULL) { |
| 1526 | v4l2_err(sd, "failed to register edid i2c client\n"); | 1867 | v4l2_err(sd, "failed to register edid i2c client\n"); |
| 1527 | err = -ENOMEM; | 1868 | err = -ENOMEM; |
| 1528 | goto err_entity; | 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 | state->i2c_pktmem = i2c_new_dummy(client->adapter, state->i2c_pktmem_addr >> 1); | 1892 | state->i2c_pktmem = i2c_new_dummy(client->adapter, state->i2c_pktmem_addr >> 1); |
| 1532 | if (state->i2c_pktmem == NULL) { | 1893 | if (state->i2c_pktmem == NULL) { |
| 1533 | v4l2_err(sd, "failed to register pktmem i2c client\n"); | 1894 | v4l2_err(sd, "failed to register pktmem i2c client\n"); |
| 1534 | err = -ENOMEM; | 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 | state->work_queue = create_singlethread_workqueue(sd->name); | 1899 | state->work_queue = create_singlethread_workqueue(sd->name); |
| 1540 | if (state->work_queue == NULL) { | 1900 | if (state->work_queue == NULL) { |
| 1541 | v4l2_err(sd, "could not create workqueue\n"); | 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 | INIT_DELAYED_WORK(&state->edid_handler, adv7511_edid_handler); | 1906 | INIT_DELAYED_WORK(&state->edid_handler, adv7511_edid_handler); |
| 1547 | 1907 | ||
| 1548 | adv7511_init_setup(sd); | 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 | adv7511_set_isr(sd, true); | 1922 | adv7511_set_isr(sd, true); |
| 1550 | adv7511_check_monitor_present_status(sd); | 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 | err_unreg_pktmem: | 1929 | err_unreg_pktmem: |
| 1557 | i2c_unregister_device(state->i2c_pktmem); | 1930 | i2c_unregister_device(state->i2c_pktmem); |
| 1931 | err_unreg_cec: | ||
| 1932 | if (state->i2c_cec) | ||
| 1933 | i2c_unregister_device(state->i2c_cec); | ||
| 1558 | err_unreg_edid: | 1934 | err_unreg_edid: |
| 1559 | i2c_unregister_device(state->i2c_edid); | 1935 | i2c_unregister_device(state->i2c_edid); |
| 1560 | err_entity: | 1936 | err_entity: |
| @@ -1576,9 +1952,12 @@ static int adv7511_remove(struct i2c_client *client) · 15 unmodified lines | |||
| 1576 | v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name, | 1952 | v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name, |
| 1577 | client->addr << 1, client->adapter->name); | 1953 | client->addr << 1, client->adapter->name); |
| 1578 | 1954 | ||
| 1955 | adv7511_set_isr(sd, false); | ||
| 1579 | adv7511_init_setup(sd); | 1956 | adv7511_init_setup(sd); |
| 1580 | cancel_delayed_work(&state->edid_handler); | 1957 | cancel_delayed_work(&state->edid_handler); |
| 1581 | i2c_unregister_device(state->i2c_edid); | 1958 | i2c_unregister_device(state->i2c_edid); |
| 1959 | if (state->i2c_cec) | ||
| 1960 | i2c_unregister_device(state->i2c_cec); | ||
| 1582 | i2c_unregister_device(state->i2c_pktmem); | 1961 | i2c_unregister_device(state->i2c_pktmem); |
| 1583 | destroy_workqueue(state->work_queue); | 1962 | destroy_workqueue(state->work_queue); |
| 1584 | v4l2_device_unregister_subdev(sd); | 1963 | v4l2_device_unregister_subdev(sd); |
| @@ -40,6 +40,7 @@ · 39 unmodified lines | |||
| 40 | #include <linux/regmap.h> | 40 | #include <linux/regmap.h> |
| 41 | 41 | ||
| 42 | #include <media/i2c/adv7604.h> | 42 | #include <media/i2c/adv7604.h> |
| 43 | #include <media/cec.h> | ||
| 43 | #include <media/v4l2-ctrls.h> | 44 | #include <media/v4l2-ctrls.h> |
| 44 | #include <media/v4l2-device.h> | 45 | #include <media/v4l2-device.h> |
| 45 | #include <media/v4l2-event.h> | 46 | #include <media/v4l2-event.h> |
| @@ -80,6 +81,8 @@ MODULE_LICENSE("GPL"); · 34 unmodified lines | |||
| 80 | 81 | ||
| 81 | #define ADV76XX_OP_SWAP_CB_CR (1 << 0) | 82 | #define ADV76XX_OP_SWAP_CB_CR (1 << 0) |
| 82 | 83 | ||
| 84 | #define ADV76XX_MAX_ADDRS (3) | ||
| 85 | |||
| 83 | enum adv76xx_type { | 86 | enum adv76xx_type { |
| 84 | ADV7604, | 87 | ADV7604, |
| 85 | ADV7611, | 88 | ADV7611, |
| @@ -164,6 +167,7 @@ struct adv76xx_state { · 78 unmodified lines | |||
| 164 | struct adv76xx_platform_data pdata; | 167 | struct adv76xx_platform_data pdata; |
| 165 | 168 | ||
| 166 | struct gpio_desc *hpd_gpio[4]; | 169 | struct gpio_desc *hpd_gpio[4]; |
| 170 | struct gpio_desc *reset_gpio; | ||
| 167 | 171 | ||
| 168 | struct v4l2_subdev sd; | 172 | struct v4l2_subdev sd; |
| 169 | struct media_pad pads[ADV76XX_PAD_MAX]; | 173 | struct media_pad pads[ADV76XX_PAD_MAX]; |
| @@ -184,10 +188,15 @@ struct adv76xx_state { · 14 unmodified lines | |||
| 184 | u16 spa_port_a[2]; | 188 | u16 spa_port_a[2]; |
| 185 | struct v4l2_fract aspect_ratio; | 189 | struct v4l2_fract aspect_ratio; |
| 186 | u32 rgb_quantization_range; | 190 | u32 rgb_quantization_range; |
| 187 | struct workqueue_struct *work_queues; | ||
| 188 | struct delayed_work delayed_work_enable_hotplug; | 191 | struct delayed_work delayed_work_enable_hotplug; |
| 189 | bool restart_stdi_once; | 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 | /* i2c clients */ | 200 | /* i2c clients */ |
| 192 | struct i2c_client *i2c_clients[ADV76XX_PAGE_MAX]; | 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 | return regmap_write(state->regmap[ADV76XX_PAGE_IO], reg, val); | 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 | return io_write(sd, reg, (io_read(sd, reg) & ~mask) | val); | 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 | return regmap_write(state->regmap[ADV76XX_PAGE_CEC], reg, val); | 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 | static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) | 433 | static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) |
| 418 | { | 434 | { |
| 419 | struct adv76xx_state *state = to_state(sd); | 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 | struct adv76xx_state *state = to_state(sd); | 909 | struct adv76xx_state *state = to_state(sd); |
| 894 | const struct adv76xx_chip_info *info = state->info; | 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, | 913 | return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, cable_det); |
| 897 | info->read_cable_det(sd)); | ||
| 898 | } | 914 | } |
| 899 | 915 | ||
| 900 | static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, | 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 | struct adv76xx_state *state = to_state(sd); | 1102 | struct adv76xx_state *state = to_state(sd); |
| 1087 | bool rgb_output = io_read(sd, 0x02) & 0x02; | 1103 | bool rgb_output = io_read(sd, 0x02) & 0x02; |
| 1088 | bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; | 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 | v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n", | 1110 | v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n", |
| 1091 | __func__, state->rgb_quantization_range, | 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 | adv76xx_set_gain(sd, true, 0x0, 0x0, 0x0); | 1114 | adv76xx_set_gain(sd, true, 0x0, 0x0, 0x0); |
| 1095 | adv76xx_set_offset(sd, true, 0x0, 0x0, 0x0); | 1115 | adv76xx_set_offset(sd, true, 0x0, 0x0, 0x0); |
| 1116 | io_write_clr_set(sd, 0x02, 0x04, rgb_output ? 0 : 4); | ||
| 1096 | 1117 | ||
| 1097 | switch (state->rgb_quantization_range) { | 1118 | switch (state->rgb_quantization_range) { |
| 1098 | case V4L2_DV_RGB_RANGE_AUTO: | 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 | break; | 1163 | break; |
| 1143 | } | 1164 | } |
| 1144 | 1165 | ||
| 1166 | if (y != HDMI_COLORSPACE_RGB) | ||
| 1167 | break; | ||
| 1168 | |||
| 1145 | /* RGB limited range (16-235) */ | 1169 | /* RGB limited range (16-235) */ |
| 1146 | io_write_clr_set(sd, 0x02, 0xf0, 0x00); | 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 | break; | 1177 | break; |
| 1154 | } | 1178 | } |
| 1155 | 1179 | ||
| 1180 | if (y != HDMI_COLORSPACE_RGB) | ||
| 1181 | break; | ||
| 1182 | |||
| 1156 | /* RGB full range (0-255) */ | 1183 | /* RGB full range (0-255) */ |
| 1157 | io_write_clr_set(sd, 0x02, 0xf0, 0x10); | 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 | io_write_clr_set(sd, 0x04, 0xe0, adv76xx_op_ch_sel(state)); | 1876 | io_write_clr_set(sd, 0x04, 0xe0, adv76xx_op_ch_sel(state)); |
| 1850 | io_write_clr_set(sd, 0x05, 0x01, | 1877 | io_write_clr_set(sd, 0x05, 0x01, |
| 1851 | state->format->swap_cb_cr ? ADV76XX_OP_SWAP_CB_CR : 0); | 1878 | state->format->swap_cb_cr ? ADV76XX_OP_SWAP_CB_CR : 0); |
| 1879 | set_rgb_quantization_range(sd); | ||
| 1852 | } | 1880 | } |
| 1853 | 1881 | ||
| 1854 | static int adv76xx_get_format(struct v4l2_subdev *sd, | 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 | return 0; | 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 | static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | 2159 | static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) |
| 1928 | { | 2160 | { |
| 1929 | struct adv76xx_state *state = to_state(sd); | 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 | *handled = true; | 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 | /* tx 5v detect */ | 2209 | /* tx 5v detect */ |
| 1973 | tx_5v = irq_reg_0x70 & info->cable_det_mask; | 2210 | tx_5v = irq_reg_0x70 & info->cable_det_mask; |
| 1974 | if (tx_5v) { | 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 | return 0; | 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 | static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) | 2258 | static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) |
| 2050 | { | 2259 | { |
| 2051 | struct adv76xx_state *state = to_state(sd); | 2260 | struct adv76xx_state *state = to_state(sd); |
| 2052 | const struct adv76xx_chip_info *info = state->info; | 2261 | const struct adv76xx_chip_info *info = state->info; |
| 2053 | int spa_loc; | 2262 | unsigned int spa_loc; |
| 2263 | u16 pa; | ||
| 2054 | int err; | 2264 | int err; |
| 2055 | int i; | 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 | edid->blocks = 2; | 2291 | edid->blocks = 2; |
| 2082 | return -E2BIG; | 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 | v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n", | 2299 | v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n", |
| 2086 | __func__, edid->pad, state->edid.present); | 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 | adv76xx_set_hpd(state, 0); | 2304 | adv76xx_set_hpd(state, 0); |
| 2091 | rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00); | 2305 | rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00); |
| 2092 | 2306 | ||
| 2093 | spa_loc = get_edid_spa_location(edid->edid); | 2307 | /* |
| 2094 | if (spa_loc < 0) | 2308 | * Return an error if no location of the source physical address |
| 2095 | spa_loc = 0xc0; /* Default value [REF_02, p. 116] */ | 2309 | * was found. |
| 2310 | */ | ||
| 2311 | if (spa_loc == 0) | ||
| 2312 | return -EINVAL; | ||
| 2096 | 2313 | ||
| 2097 | switch (edid->pad) { | 2314 | switch (edid->pad) { |
| 2098 | case ADV76XX_PAD_HDMI_PORT_A: | 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 | v4l2_err(sd, "error enabling edid (0x%x)\n", state->edid.present); | 2369 | v4l2_err(sd, "error enabling edid (0x%x)\n", state->edid.present); |
| 2153 | return -EIO; | 2370 | return -EIO; |
| 2154 | } | 2371 | } |
| 2372 | cec_s_phys_addr(state->cec_adap, pa, false); | ||
| 2155 | 2373 | ||
| 2156 | /* enable hotplug after 100 ms */ | 2374 | /* enable hotplug after 100 ms */ |
| 2157 | queue_delayed_work(state->work_queues, | 2375 | schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10); |
| 2158 | &state->delayed_work_enable_hotplug, HZ / 10); | ||
| 2159 | return 0; | 2376 | return 0; |
| 2160 | } | 2377 | } |
| 2161 | 2378 | ||
| @@ -2276,8 +2493,19 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) · 114 unmodified lines | |||
| 2276 | ((edid_enabled & 0x02) ? "Yes" : "No"), | 2493 | ((edid_enabled & 0x02) ? "Yes" : "No"), |
| 2277 | ((edid_enabled & 0x04) ? "Yes" : "No"), | 2494 | ((edid_enabled & 0x04) ? "Yes" : "No"), |
| 2278 | ((edid_enabled & 0x08) ? "Yes" : "No")); | 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 | "enabled" : "disabled"); | 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 | v4l2_info(sd, "-----Signal status-----\n"); | 2510 | v4l2_info(sd, "-----Signal status-----\n"); |
| 2283 | cable_det = info->read_cable_det(sd); | 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 | rgb_quantization_range_txt[state->rgb_quantization_range]); | 2551 | rgb_quantization_range_txt[state->rgb_quantization_range]); |
| 2324 | v4l2_info(sd, "Input color space: %s\n", | 2552 | v4l2_info(sd, "Input color space: %s\n", |
| 2325 | input_color_space_txt[reg_io_0x02 >> 4]); | 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 | (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", | 2555 | (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", |
| 2328 | (reg_io_0x02 & 0x04) ? "(16-235)" : "(0-255)", | ||
| 2329 | (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? | 2556 | (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? |
| 2330 | "enabled" : "disabled", | 2557 | "(16-235)" : "(0-255)", |
| 2331 | (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); | 2558 | (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); |
| 2332 | v4l2_info(sd, "Color space conversion: %s\n", | 2559 | v4l2_info(sd, "Color space conversion: %s\n", |
| 2333 | csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]); | 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 | static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = { | 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 | .pad = &adv76xx_pad_ops, | 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 | /* -------------------------- custom ctrls ---------------------------------- */ | 2683 | /* -------------------------- custom ctrls ---------------------------------- */ |
| 2434 | 2684 | ||
| 2435 | static const struct v4l2_ctrl_config adv7604_ctrl_analog_sampling_phase = { | 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 | cp_write(sd, 0xcf, 0x01); /* Power down macrovision */ | 2742 | cp_write(sd, 0xcf, 0x01); /* Power down macrovision */ |
| 2493 | 2743 | ||
| 2494 | /* video format */ | 2744 | /* video format */ |
| 2495 | io_write_clr_set(sd, 0x02, 0x0f, | 2745 | io_write_clr_set(sd, 0x02, 0x0f, pdata->alt_gamma << 3); |
| 2496 | pdata->alt_gamma << 3 | | ||
| 2497 | pdata->op_656_range << 2 | | ||
| 2498 | pdata->alt_data_sat << 0); | ||
| 2499 | io_write_clr_set(sd, 0x05, 0x0e, pdata->blank_data << 3 | | 2746 | io_write_clr_set(sd, 0x05, 0x0e, pdata->blank_data << 3 | |
| 2500 | pdata->insert_av_codes << 2 | | 2747 | pdata->insert_av_codes << 2 | |
| 2501 | pdata->replicate_av_codes << 1); | 2748 | pdata->replicate_av_codes << 1); |
| @@ -2845,10 +3092,8 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) · 343 unmodified lines | |||
| 2845 | if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) | 3092 | if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) |
| 2846 | state->pdata.inv_llc_pol = 1; | 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 | state->pdata.insert_av_codes = 1; | 3096 | state->pdata.insert_av_codes = 1; |
| 2850 | state->pdata.op_656_range = 1; | ||
| 2851 | } | ||
| 2852 | 3097 | ||
| 2853 | /* Disable the interrupt for now as no DT-based board uses it. */ | 3098 | /* Disable the interrupt for now as no DT-based board uses it. */ |
| 2854 | state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED; | 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 | state->pdata.disable_pwrdnb = 0; | 3116 | state->pdata.disable_pwrdnb = 0; |
| 2872 | state->pdata.disable_cable_det_rst = 0; | 3117 | state->pdata.disable_cable_det_rst = 0; |
| 2873 | state->pdata.blank_data = 1; | 3118 | state->pdata.blank_data = 1; |
| 2874 | state->pdata.alt_data_sat = 1; | ||
| 2875 | state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0; | 3119 | state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0; |
| 2876 | state->pdata.bus_order = ADV7604_BUS_ORDER_RGB; | 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 | return 0; | 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 | static int adv76xx_probe(struct i2c_client *client, | 3280 | static int adv76xx_probe(struct i2c_client *client, |
| 3024 | const struct i2c_device_id *id) | 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 | if (state->hpd_gpio[i]) | 3340 | if (state->hpd_gpio[i]) |
| 3084 | v4l_info(client, "Handling HPD %u GPIO\n", i); | 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 | state->timings = cea640x480; | 3350 | state->timings = cea640x480; |
| 3088 | state->format = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); | 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 | id->name, i2c_adapter_id(client->adapter), | 3356 | id->name, i2c_adapter_id(client->adapter), |
| 3094 | client->addr); | 3357 | client->addr); |
| 3095 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; | 3358 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; |
| 3359 | sd->internal_ops = &adv76xx_int_ops; | ||
| 3096 | 3360 | ||
| 3097 | /* Configure IO Regmap region */ | 3361 | /* Configure IO Regmap region */ |
| 3098 | err = configure_regmap(state, ADV76XX_PAGE_IO); | 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 | INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, | 3473 | INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, |
| 3218 | adv76xx_delayed_work_enable_hotplug); | 3474 | adv76xx_delayed_work_enable_hotplug); |
| 3219 | 3475 | ||
| @@ -3236,6 +3492,18 @@ static int adv76xx_probe(struct i2c_client *client, · 16 unmodified lines | |||
| 3236 | err = adv76xx_core_init(sd); | 3492 | err = adv76xx_core_init(sd); |
| 3237 | if (err) | 3493 | if (err) |
| 3238 | goto err_entity; | 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 | v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, | 3507 | v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, |
| 3240 | client->addr << 1, client->adapter->name); | 3508 | client->addr << 1, client->adapter->name); |
| 3241 | 3509 | ||
| @@ -3249,7 +3517,6 @@ err_entity: · 7 unmodified lines | |||
| 3249 | media_entity_cleanup(&sd->entity); | 3517 | media_entity_cleanup(&sd->entity); |
| 3250 | err_work_queues: | 3518 | err_work_queues: |
| 3251 | cancel_delayed_work(&state->delayed_work_enable_hotplug); | 3519 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
| 3252 | destroy_workqueue(state->work_queues); | ||
| 3253 | err_i2c: | 3520 | err_i2c: |
| 3254 | adv76xx_unregister_clients(state); | 3521 | adv76xx_unregister_clients(state); |
| 3255 | err_hdl: | 3522 | err_hdl: |
| @@ -3264,8 +3531,14 @@ static int adv76xx_remove(struct i2c_client *client) · 8 unmodified lines | |||
| 3264 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 3531 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
| 3265 | struct adv76xx_state *state = to_state(sd); | 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 | cancel_delayed_work(&state->delayed_work_enable_hotplug); | 3541 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
| 3268 | destroy_workqueue(state->work_queues); | ||
| 3269 | v4l2_async_unregister_subdev(sd); | 3542 | v4l2_async_unregister_subdev(sd); |
| 3270 | media_entity_cleanup(&sd->entity); | 3543 | media_entity_cleanup(&sd->entity); |
| 3271 | adv76xx_unregister_clients(to_state(sd)); | 3544 | adv76xx_unregister_clients(to_state(sd)); |
| @@ -39,6 +39,7 @@ · 38 unmodified lines | |||
| 39 | #include <linux/workqueue.h> | 39 | #include <linux/workqueue.h> |
| 40 | #include <linux/v4l2-dv-timings.h> | 40 | #include <linux/v4l2-dv-timings.h> |
| 41 | #include <linux/hdmi.h> | 41 | #include <linux/hdmi.h> |
| 42 | #include <media/cec.h> | ||
| 42 | #include <media/v4l2-device.h> | 43 | #include <media/v4l2-device.h> |
| 43 | #include <media/v4l2-event.h> | 44 | #include <media/v4l2-event.h> |
| 44 | #include <media/v4l2-ctrls.h> | 45 | #include <media/v4l2-ctrls.h> |
| @@ -79,6 +80,8 @@ MODULE_LICENSE("GPL"); · 34 unmodified lines | |||
| 79 | 80 | ||
| 80 | #define ADV7842_OP_SWAP_CB_CR (1 << 0) | 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 | struct v4l2_fract aspect_ratio; | 121 | struct v4l2_fract aspect_ratio; |
| 119 | u32 rgb_quantization_range; | 122 | u32 rgb_quantization_range; |
| 120 | bool is_cea_format; | 123 | bool is_cea_format; |
| 121 | struct workqueue_struct *work_queues; | ||
| 122 | struct delayed_work delayed_work_enable_hotplug; | 124 | struct delayed_work delayed_work_enable_hotplug; |
| 123 | bool restart_stdi_once; | 125 | bool restart_stdi_once; |
| 124 | bool hdmi_port_a; | 126 | bool hdmi_port_a; |
| @@ -142,6 +144,11 @@ struct adv7842_state { · 17 unmodified lines | |||
| 142 | struct v4l2_ctrl *free_run_color_ctrl_manual; | 144 | struct v4l2_ctrl *free_run_color_ctrl_manual; |
| 143 | struct v4l2_ctrl *free_run_color_ctrl; | 145 | struct v4l2_ctrl *free_run_color_ctrl; |
| 144 | struct v4l2_ctrl *rgb_quantization_range_ctrl; | 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 | /* Unsupported timings. This device cannot support 720p30. */ | 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 | return adv_smbus_write_byte_data(state->i2c_cec, reg, val); | 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 | static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) | 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 | static void adv7842_delayed_work_enable_hotplug(struct work_struct *work) | 718 | static void adv7842_delayed_work_enable_hotplug(struct work_struct *work) |
| 700 | { | 719 | { |
| 701 | struct delayed_work *dwork = to_delayed_work(work); | 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 | /* enable hotplug after 200 ms */ | 777 | /* enable hotplug after 200 ms */ |
| 759 | queue_delayed_work(state->work_queues, | 778 | schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 5); |
| 760 | &state->delayed_work_enable_hotplug, HZ / 5); | ||
| 761 | 779 | ||
| 762 | return 0; | 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 | static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) | 783 | static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) |
| 799 | { | 784 | { |
| 800 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 785 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 801 | struct adv7842_state *state = to_state(sd); | 786 | struct adv7842_state *state = to_state(sd); |
| 802 | const u8 *val = state->hdmi_edid.edid; | 787 | const u8 *edid = state->hdmi_edid.edid; |
| 803 | int spa_loc = edid_spa_location(val); | 788 | int spa_loc; |
| 789 | u16 pa; | ||
| 804 | int err = 0; | 790 | int err = 0; |
| 805 | int i; | 791 | int i; |
| 806 | 792 | ||
| 807 | v4l2_dbg(2, debug, sd, "%s: write EDID on port %c (spa at 0x%x)\n", | 793 | v4l2_dbg(2, debug, sd, "%s: write EDID on port %c\n", |
| 808 | __func__, (port == ADV7842_EDID_PORT_A) ? 'A' : 'B', spa_loc); | 794 | __func__, (port == ADV7842_EDID_PORT_A) ? 'A' : 'B'); |
| 809 | 795 | ||
| 810 | /* HPA disable on port A and B */ | 796 | /* HPA disable on port A and B */ |
| 811 | io_write_and_or(sd, 0x20, 0xcf, 0x00); | 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 | if (!state->hdmi_edid.present) | 802 | if (!state->hdmi_edid.present) |
| 817 | return 0; | 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 | /* edid segment pointer '0' for HDMI ports */ | 817 | /* edid segment pointer '0' for HDMI ports */ |
| 820 | rep_write_and_or(sd, 0x77, 0xef, 0x00); | 818 | rep_write_and_or(sd, 0x77, 0xef, 0x00); |
| 821 | 819 | ||
| 822 | for (i = 0; !err && i < 256; i += I2C_SMBUS_BLOCK_MAX) | 820 | for (i = 0; !err && i < 256; i += I2C_SMBUS_BLOCK_MAX) |
| 823 | err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, | 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 | if (err) | 823 | if (err) |
| 826 | return err; | 824 | return err; |
| 827 | 825 | ||
| 828 | if (spa_loc < 0) | ||
| 829 | spa_loc = 0xc0; /* Default value [REF_02, p. 199] */ | ||
| 830 | |||
| 831 | if (port == ADV7842_EDID_PORT_A) { | 826 | if (port == ADV7842_EDID_PORT_A) { |
| 832 | rep_write(sd, 0x72, val[spa_loc]); | 827 | rep_write(sd, 0x72, edid[spa_loc]); |
| 833 | rep_write(sd, 0x73, val[spa_loc + 1]); | 828 | rep_write(sd, 0x73, edid[spa_loc + 1]); |
| 834 | } else { | 829 | } else { |
| 835 | rep_write(sd, 0x74, val[spa_loc]); | 830 | rep_write(sd, 0x74, edid[spa_loc]); |
| 836 | rep_write(sd, 0x75, val[spa_loc + 1]); | 831 | rep_write(sd, 0x75, edid[spa_loc + 1]); |
| 837 | } | 832 | } |
| 838 | rep_write(sd, 0x76, spa_loc & 0xff); | 833 | rep_write(sd, 0x76, spa_loc & 0xff); |
| 839 | rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40); | 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 | (port == ADV7842_EDID_PORT_A) ? 'A' : 'B'); | 848 | (port == ADV7842_EDID_PORT_A) ? 'A' : 'B'); |
| 854 | return -EIO; | 849 | return -EIO; |
| 855 | } | 850 | } |
| 851 | cec_s_phys_addr(state->cec_adap, pa, false); | ||
| 856 | 852 | ||
| 857 | /* enable hotplug after 200 ms */ | 853 | /* enable hotplug after 200 ms */ |
| 858 | queue_delayed_work(state->work_queues, | 854 | schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 5); |
| 859 | &state->delayed_work_enable_hotplug, HZ / 5); | ||
| 860 | 855 | ||
| 861 | return 0; | 856 | return 0; |
| 862 | } | 857 | } |
| @@ -983,20 +978,11 @@ static int adv7842_s_register(struct v4l2_subdev *sd, · 120 unmodified lines | |||
| 983 | static int adv7842_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) | 978 | static int adv7842_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) |
| 984 | { | 979 | { |
| 985 | struct adv7842_state *state = to_state(sd); | 980 | struct adv7842_state *state = to_state(sd); |
| 986 | int prev = v4l2_ctrl_g_ctrl(state->detect_tx_5v_ctrl); | 981 | u16 cable_det = adv7842_read_cable_det(sd); |
| 987 | u8 reg_io_6f = io_read(sd, 0x6f); | ||
| 988 | int val = 0; | ||
| 989 | 982 | ||
| 990 | if (reg_io_6f & 0x02) | 983 | v4l2_dbg(1, debug, sd, "%s: 0x%x\n", __func__, cable_det); |
| 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); | ||
| 996 | 984 | ||
| 997 | if (val != prev) | 985 | return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, cable_det); |
| 998 | return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, val); | ||
| 999 | return 0; | ||
| 1000 | } | 986 | } |
| 1001 | 987 | ||
| 1002 | static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, | 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 | struct adv7842_state *state = to_state(sd); | 1184 | struct adv7842_state *state = to_state(sd); |
| 1199 | bool rgb_output = io_read(sd, 0x02) & 0x02; | 1185 | bool rgb_output = io_read(sd, 0x02) & 0x02; |
| 1200 | bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; | 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 | v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n", | 1192 | v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n", |
| 1203 | __func__, state->rgb_quantization_range, | 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 | adv7842_set_gain(sd, true, 0x0, 0x0, 0x0); | 1196 | adv7842_set_gain(sd, true, 0x0, 0x0, 0x0); |
| 1207 | adv7842_set_offset(sd, true, 0x0, 0x0, 0x0); | 1197 | adv7842_set_offset(sd, true, 0x0, 0x0, 0x0); |
| 1198 | io_write_clr_set(sd, 0x02, 0x04, rgb_output ? 0 : 4); | ||
| 1208 | 1199 | ||
| 1209 | switch (state->rgb_quantization_range) { | 1200 | switch (state->rgb_quantization_range) { |
| 1210 | case V4L2_DV_RGB_RANGE_AUTO: | 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 | break; | 1245 | break; |
| 1255 | } | 1246 | } |
| 1256 | 1247 | ||
| 1248 | if (y != HDMI_COLORSPACE_RGB) | ||
| 1249 | break; | ||
| 1250 | |||
| 1257 | /* RGB limited range (16-235) */ | 1251 | /* RGB limited range (16-235) */ |
| 1258 | io_write_and_or(sd, 0x02, 0x0f, 0x00); | 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 | break; | 1259 | break; |
| 1266 | } | 1260 | } |
| 1267 | 1261 | ||
| 1262 | if (y != HDMI_COLORSPACE_RGB) | ||
| 1263 | break; | ||
| 1264 | |||
| 1268 | /* RGB full range (0-255) */ | 1265 | /* RGB full range (0-255) */ |
| 1269 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | 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 | io_write_clr_set(sd, 0x04, 0xe0, adv7842_op_ch_sel(state)); | 2069 | io_write_clr_set(sd, 0x04, 0xe0, adv7842_op_ch_sel(state)); |
| 2073 | io_write_clr_set(sd, 0x05, 0x01, | 2070 | io_write_clr_set(sd, 0x05, 0x01, |
| 2074 | state->format->swap_cb_cr ? ADV7842_OP_SWAP_CB_CR : 0); | 2071 | state->format->swap_cb_cr ? ADV7842_OP_SWAP_CB_CR : 0); |
| 2072 | set_rgb_quantization_range(sd); | ||
| 2075 | } | 2073 | } |
| 2076 | 2074 | ||
| 2077 | static int adv7842_get_format(struct v4l2_subdev *sd, | 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 | static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | 2372 | static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) |
| 2174 | { | 2373 | { |
| 2175 | struct adv7842_state *state = to_state(sd); | 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 | *handled = true; | 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 | /* tx 5v detect */ | 2448 | /* tx 5v detect */ |
| 2245 | if (irq_status[2] & 0x3) { | 2449 | if (irq_status[2] & 0x3) { |
| 2246 | v4l2_dbg(1, debug, sd, "%s: irq tx_5v\n", __func__); | 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 | case ADV7842_EDID_PORT_A: | 2525 | case ADV7842_EDID_PORT_A: |
| 2322 | case ADV7842_EDID_PORT_B: | 2526 | case ADV7842_EDID_PORT_B: |
| 2323 | memset(&state->hdmi_edid.edid, 0, 256); | 2527 | memset(&state->hdmi_edid.edid, 0, 256); |
| 2324 | if (e->blocks) | 2528 | if (e->blocks) { |
| 2325 | state->hdmi_edid.present |= 0x04 << e->pad; | 2529 | state->hdmi_edid.present |= 0x04 << e->pad; |
| 2326 | else | 2530 | } else { |
| 2327 | state->hdmi_edid.present &= ~(0x04 << e->pad); | 2531 | state->hdmi_edid.present &= ~(0x04 << e->pad); |
| 2532 | adv7842_s_detect_tx_5v_ctrl(sd); | ||
| 2533 | } | ||
| 2328 | memcpy(&state->hdmi_edid.edid, e->edid, 128 * e->blocks); | 2534 | memcpy(&state->hdmi_edid.edid, e->edid, 128 * e->blocks); |
| 2329 | err = edid_write_hdmi_segment(sd, e->pad); | 2535 | err = edid_write_hdmi_segment(sd, e->pad); |
| 2330 | break; | 2536 | break; |
| @@ -2397,6 +2603,8 @@ static void adv7842_log_infoframes(struct v4l2_subdev *sd) · 66 unmodified lines | |||
| 2397 | log_infoframe(sd, &cri[i]); | 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 | static const char * const prim_mode_txt[] = { | 2608 | static const char * const prim_mode_txt[] = { |
| 2401 | "SDP", | 2609 | "SDP", |
| 2402 | "Component", | 2610 | "Component", |
| @@ -2415,6 +2623,7 @@ static const char * const prim_mode_txt[] = { · 12 unmodified lines | |||
| 2415 | "Reserved", | 2623 | "Reserved", |
| 2416 | "Reserved", | 2624 | "Reserved", |
| 2417 | }; | 2625 | }; |
| 2626 | #endif | ||
| 2418 | 2627 | ||
| 2419 | static int adv7842_sdp_log_status(struct v4l2_subdev *sd) | 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 | v4l2_info(sd, "HPD A %s, B %s\n", | 2718 | v4l2_info(sd, "HPD A %s, B %s\n", |
| 2510 | reg_io_0x21 & 0x02 ? "enabled" : "disabled", | 2719 | reg_io_0x21 & 0x02 ? "enabled" : "disabled", |
| 2511 | reg_io_0x21 & 0x01 ? "enabled" : "disabled"); | 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 | "enabled" : "disabled"); | 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 | v4l2_info(sd, "-----Signal status-----\n"); | 2735 | v4l2_info(sd, "-----Signal status-----\n"); |
| 2516 | if (state->hdmi_port_a) { | 2736 | if (state->hdmi_port_a) { |
| @@ -2569,11 +2789,11 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) · 52 unmodified lines | |||
| 2569 | rgb_quantization_range_txt[state->rgb_quantization_range]); | 2789 | rgb_quantization_range_txt[state->rgb_quantization_range]); |
| 2570 | v4l2_info(sd, "Input color space: %s\n", | 2790 | v4l2_info(sd, "Input color space: %s\n", |
| 2571 | input_color_space_txt[reg_io_0x02 >> 4]); | 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 | (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", | 2793 | (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", |
| 2574 | (reg_io_0x02 & 0x04) ? "(16-235)" : "(0-255)", | 2794 | (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? |
| 2575 | ((reg_io_0x02 & 0x04) ^ (reg_io_0x02 & 0x01)) ? | 2795 | "(16-235)" : "(0-255)", |
| 2576 | "enabled" : "disabled"); | 2796 | (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); |
| 2577 | v4l2_info(sd, "Color space conversion: %s\n", | 2797 | v4l2_info(sd, "Color space conversion: %s\n", |
| 2578 | csc_coeff_sel_rb[cp_read(sd, 0xf4) >> 4]); | 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 | io_write(sd, 0x15, 0x80); /* Power up pads */ | 2997 | io_write(sd, 0x15, 0x80); /* Power up pads */ |
| 2778 | 2998 | ||
| 2779 | /* video format */ | 2999 | /* video format */ |
| 2780 | io_write(sd, 0x02, | 3000 | io_write(sd, 0x02, 0xf0 | pdata->alt_gamma << 3); |
| 2781 | 0xf0 | | ||
| 2782 | pdata->alt_gamma << 3 | | ||
| 2783 | pdata->op_656_range << 2 | | ||
| 2784 | pdata->alt_data_sat << 0); | ||
| 2785 | io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 | | 3001 | io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 | |
| 2786 | pdata->insert_av_codes << 2 | | 3002 | pdata->insert_av_codes << 2 | |
| 2787 | pdata->replicate_av_codes << 1); | 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 | static const struct v4l2_ctrl_ops adv7842_ctrl_ops = { | 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 | .pad = &adv7842_pad_ops, | 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 | /* -------------------------- custom ctrls ---------------------------------- */ | 3319 | /* -------------------------- custom ctrls ---------------------------------- */ |
| 3081 | 3320 | ||
| 3082 | static const struct v4l2_ctrl_config adv7842_ctrl_analog_sampling_phase = { | 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 | sd = &state->sd; | 3480 | sd = &state->sd; |
| 3242 | v4l2_i2c_subdev_init(sd, client, &adv7842_ops); | 3481 | v4l2_i2c_subdev_init(sd, client, &adv7842_ops); |
| 3243 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; | 3482 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; |
| 3483 | sd->internal_ops = &adv7842_int_ops; | ||
| 3244 | state->mode = pdata->mode; | 3484 | state->mode = pdata->mode; |
| 3245 | 3485 | ||
| 3246 | state->hdmi_port_a = pdata->input == ADV7842_SELECT_HDMI_PORT_A; | 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 | goto err_i2c; | 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 | INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, | 3555 | INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, |
| 3323 | adv7842_delayed_work_enable_hotplug); | 3556 | adv7842_delayed_work_enable_hotplug); |
| @@ -3331,6 +3564,17 @@ static int adv7842_probe(struct i2c_client *client, · 7 unmodified lines | |||
| 3331 | if (err) | 3564 | if (err) |
| 3332 | goto err_entity; | 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 | v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, | 3578 | v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, |
| 3335 | client->addr << 1, client->adapter->name); | 3579 | client->addr << 1, client->adapter->name); |
| 3336 | return 0; | 3580 | return 0; |
| @@ -3339,7 +3583,6 @@ err_entity: · 2 unmodified lines | |||
| 3339 | media_entity_cleanup(&sd->entity); | 3583 | media_entity_cleanup(&sd->entity); |
| 3340 | err_work_queues: | 3584 | err_work_queues: |
| 3341 | cancel_delayed_work(&state->delayed_work_enable_hotplug); | 3585 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
| 3342 | destroy_workqueue(state->work_queues); | ||
| 3343 | err_i2c: | 3586 | err_i2c: |
| 3344 | adv7842_unregister_clients(sd); | 3587 | adv7842_unregister_clients(sd); |
| 3345 | err_hdl: | 3588 | err_hdl: |
| @@ -3355,9 +3598,7 @@ static int adv7842_remove(struct i2c_client *client) · 9 unmodified lines | |||
| 3355 | struct adv7842_state *state = to_state(sd); | 3598 | struct adv7842_state *state = to_state(sd); |
| 3356 | 3599 | ||
| 3357 | adv7842_irq_enable(sd, false); | 3600 | adv7842_irq_enable(sd, false); |
| 3358 | |||
| 3359 | cancel_delayed_work(&state->delayed_work_enable_hotplug); | 3601 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
| 3360 | destroy_workqueue(state->work_queues); | ||
| 3361 | v4l2_device_unregister_subdev(sd); | 3602 | v4l2_device_unregister_subdev(sd); |
| 3362 | media_entity_cleanup(&sd->entity); | 3603 | media_entity_cleanup(&sd->entity); |
| 3363 | adv7842_unregister_clients(sd); | 3604 | adv7842_unregister_clients(sd); |
| @@ -121,13 +121,6 @@ static const struct v4l2_ctrl_ops cs53l32a_ctrl_ops = { · 120 unmodified lines | |||
| 121 | 121 | ||
| 122 | static const struct v4l2_subdev_core_ops cs53l32a_core_ops = { | 122 | static const struct v4l2_subdev_core_ops cs53l32a_core_ops = { |
| 123 | .log_status = cs53l32a_log_status, | 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 | static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = { | 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 | static const struct v4l2_subdev_core_ops cx25840_core_ops = { | 5043 | static const struct v4l2_subdev_core_ops cx25840_core_ops = { |
| 5044 | .log_status = cx25840_log_status, | 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 | .reset = cx25840_reset, | 5045 | .reset = cx25840_reset, |
| 5053 | .load_fw = cx25840_load_fw, | 5046 | .load_fw = cx25840_load_fw, |
| 5054 | .s_io_pin_config = common_s_io_pin_config, | 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 | static const struct v4l2_subdev_core_ops msp_core_ops = { | 643 | static const struct v4l2_subdev_core_ops msp_core_ops = { |
| 644 | .log_status = msp_log_status, | 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 | static const struct v4l2_subdev_video_ops msp_video_ops = { | 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 | ret = mt9t001_reset(mt9t001); | 233 | ret = mt9t001_reset(mt9t001); |
| 234 | if (ret < 0) { | 234 | if (ret < 0) { |
| 235 | dev_err(&client->dev, "Failed to reset the camera\n"); | 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 | .pad = &mt9t001_subdev_pad_ops, | 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 | .registered = mt9t001_registered, | 849 | .registered = mt9t001_registered, |
| 839 | .open = mt9t001_open, | 850 | .open = mt9t001_open, |
| 840 | .close = mt9t001_close, | 851 | .close = mt9t001_close, |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | |||
| 19 | #include <linux/log2.h> | 19 | #include <linux/log2.h> |
| 20 | #include <linux/mutex.h> | 20 | #include <linux/mutex.h> |
| 21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
| 22 | #include <linux/of_gpio.h> | ||
| 23 | #include <linux/regmap.h> | 22 | #include <linux/regmap.h> |
| 24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| 25 | #include <linux/videodev2.h> | 24 | #include <linux/videodev2.h> |
| @@ -133,9 +132,16 @@ · 107 unmodified lines | |||
| 133 | #define MT9V032_TEST_PATTERN_GRAY_DIAGONAL (3 << 11) | 132 | #define MT9V032_TEST_PATTERN_GRAY_DIAGONAL (3 << 11) |
| 134 | #define MT9V032_TEST_PATTERN_ENABLE (1 << 13) | 133 | #define MT9V032_TEST_PATTERN_ENABLE (1 << 13) |
| 135 | #define MT9V032_TEST_PATTERN_FLIP (1 << 14) | 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 | #define MT9V032_AEC_AGC_ENABLE 0xaf | 140 | #define MT9V032_AEC_AGC_ENABLE 0xaf |
| 137 | #define MT9V032_AEC_ENABLE (1 << 0) | 141 | #define MT9V032_AEC_ENABLE (1 << 0) |
| 138 | #define MT9V032_AGC_ENABLE (1 << 1) | 142 | #define MT9V032_AGC_ENABLE (1 << 1) |
| 143 | #define MT9V034_AEC_MAX_SHUTTER_WIDTH 0xad | ||
| 144 | #define MT9V032_AEC_MAX_SHUTTER_WIDTH 0xbd | ||
| 139 | #define MT9V032_THERMAL_INFO 0xc1 | 145 | #define MT9V032_THERMAL_INFO 0xc1 |
| 140 | 146 | ||
| 141 | enum mt9v032_model { | 147 | enum mt9v032_model { |
| @@ -162,6 +168,8 @@ struct mt9v032_model_data { · 20 unmodified lines | |||
| 162 | unsigned int min_shutter; | 168 | unsigned int min_shutter; |
| 163 | unsigned int max_shutter; | 169 | unsigned int max_shutter; |
| 164 | unsigned int pclk_reg; | 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 | struct mt9v032_model_info { | 175 | struct mt9v032_model_info { |
| @@ -175,63 +183,6 @@ static const struct mt9v032_model_version mt9v032_versions[] = { · 7 unmodified lines | |||
| 175 | { MT9V034_CHIP_ID_REV1, "MT9V024/MT9V034 rev1" }, | 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 | struct mt9v032 { | 186 | struct mt9v032 { |
| 236 | struct v4l2_subdev subdev; | 187 | struct v4l2_subdev subdev; |
| 237 | struct media_pad pad; | 188 | struct media_pad pad; |
| @@ -349,7 +300,8 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032) · 111 unmodified lines | |||
| 349 | if (ret < 0) | 300 | if (ret < 0) |
| 350 | return ret; | 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 | static void mt9v032_power_off(struct mt9v032 *mt9v032) | 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 | static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable) | 374 | static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable) |
| 423 | { | 375 | { |
| 424 | const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE | 376 | const u16 mode = MT9V032_CHIP_CONTROL_DOUT_ENABLE |
| 425 | | MT9V032_CHIP_CONTROL_DOUT_ENABLE | ||
| 426 | | MT9V032_CHIP_CONTROL_SEQUENTIAL; | 377 | | MT9V032_CHIP_CONTROL_SEQUENTIAL; |
| 427 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | 378 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); |
| 428 | struct v4l2_rect *crop = &mt9v032->crop; | 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 | #define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_BASE | 0x1001) | 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 | static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) | 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 | break; | 695 | break; |
| 717 | } | 696 | } |
| 718 | return regmap_write(map, MT9V032_TEST_PATTERN, data); | 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 | return 0; | 722 | return 0; |
| @@ -745,6 +746,84 @@ static const struct v4l2_ctrl_config mt9v032_test_pattern_color = { · 23 unmodified lines | |||
| 745 | .flags = 0, | 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 | * V4L2 subdev core operations | 828 | * V4L2 subdev core operations |
| 750 | */ | 829 | */ |
| @@ -953,13 +1032,6 @@ static int mt9v032_probe(struct i2c_client *client, · 202 unmodified lines | |||
| 953 | unsigned int i; | 1032 | unsigned int i; |
| 954 | int ret; | 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 | mt9v032 = devm_kzalloc(&client->dev, sizeof(*mt9v032), GFP_KERNEL); | 1035 | mt9v032 = devm_kzalloc(&client->dev, sizeof(*mt9v032), GFP_KERNEL); |
| 964 | if (!mt9v032) | 1036 | if (!mt9v032) |
| 965 | return -ENOMEM; | 1037 | return -ENOMEM; |
| @@ -986,7 +1058,8 @@ static int mt9v032_probe(struct i2c_client *client, · 20 unmodified lines | |||
| 986 | mt9v032->pdata = pdata; | 1058 | mt9v032->pdata = pdata; |
| 987 | mt9v032->model = (const void *)did->driver_data; | 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 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, | 1064 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, |
| 992 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | 1065 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); |
| @@ -1015,6 +1088,13 @@ static int mt9v032_probe(struct i2c_client *client, · 22 unmodified lines | |||
| 1015 | mt9v032->test_pattern_color = v4l2_ctrl_new_custom(&mt9v032->ctrls, | 1088 | mt9v032->test_pattern_color = v4l2_ctrl_new_custom(&mt9v032->ctrls, |
| 1016 | &mt9v032_test_pattern_color, NULL); | 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 | v4l2_ctrl_cluster(2, &mt9v032->test_pattern); | 1098 | v4l2_ctrl_cluster(2, &mt9v032->test_pattern); |
| 1019 | 1099 | ||
| 1020 | mt9v032->pixel_rate = | 1100 | mt9v032->pixel_rate = |
| @@ -1103,6 +1183,67 @@ static int mt9v032_remove(struct i2c_client *client) · 82 unmodified lines | |||
| 1103 | return 0; | 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 | static const struct i2c_device_id mt9v032_id[] = { | 1247 | static const struct i2c_device_id mt9v032_id[] = { |
| 1107 | { "mt9v022", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_COLOR] }, | 1248 | { "mt9v022", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_COLOR] }, |
| 1108 | { "mt9v022m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_MONO] }, | 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 | static const struct v4l2_subdev_core_ops saa711x_core_ops = { | 1586 | static const struct v4l2_subdev_core_ops saa711x_core_ops = { |
| 1587 | .log_status = saa711x_log_status, | 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 | .reset = saa711x_reset, | 1588 | .reset = saa711x_reset, |
| 1596 | .s_gpio = saa711x_s_gpio, | 1589 | .s_gpio = saa711x_s_gpio, |
| 1597 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 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 | pdata->op_sys_clock = devm_kcalloc( | 3044 | pdata->op_sys_clock = devm_kcalloc( |
| 3045 | dev, bus_cfg->nr_of_link_frequencies + 1 /* guardian */, | 3045 | dev, bus_cfg->nr_of_link_frequencies + 1 /* guardian */, |
| 3046 | sizeof(*pdata->op_sys_clock), GFP_KERNEL); | 3046 | sizeof(*pdata->op_sys_clock), GFP_KERNEL); |
| 3047 | if (!pdata->op_sys_clock) { | 3047 | if (!pdata->op_sys_clock) |
| 3048 | rval = -ENOMEM; | ||
| 3049 | goto out_err; | 3048 | goto out_err; |
| 3050 | } | ||
| 3051 | 3049 | ||
| 3052 | for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) { | 3050 | for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) { |
| 3053 | pdata->op_sys_clock[i] = bus_cfg->link_frequencies[i]; | 3051 | pdata->op_sys_clock[i] = bus_cfg->link_frequencies[i]; |
| @@ -89,8 +89,6 @@ struct tc358743_state { · 88 unmodified lines | |||
| 89 | struct v4l2_ctrl *audio_sampling_rate_ctrl; | 89 | struct v4l2_ctrl *audio_sampling_rate_ctrl; |
| 90 | struct v4l2_ctrl *audio_present_ctrl; | 90 | struct v4l2_ctrl *audio_present_ctrl; |
| 91 | 91 | ||
| 92 | /* work queues */ | ||
| 93 | struct workqueue_struct *work_queues; | ||
| 94 | struct delayed_work delayed_work_enable_hotplug; | 92 | struct delayed_work delayed_work_enable_hotplug; |
| 95 | 93 | ||
| 96 | /* edid */ | 94 | /* edid */ |
| @@ -425,8 +423,7 @@ static void tc358743_enable_edid(struct v4l2_subdev *sd) · 328 unmodified lines | |||
| 425 | 423 | ||
| 426 | /* Enable hotplug after 100 ms. DDC access to EDID is also enabled when | 424 | /* Enable hotplug after 100 ms. DDC access to EDID is also enabled when |
| 427 | * hotplug is enabled. See register DDC_CTL */ | 425 | * hotplug is enabled. See register DDC_CTL */ |
| 428 | queue_delayed_work(state->work_queues, | 426 | schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10); |
| 429 | &state->delayed_work_enable_hotplug, HZ / 10); | ||
| 430 | 427 | ||
| 431 | tc358743_enable_interrupts(sd, true); | 428 | tc358743_enable_interrupts(sd, true); |
| 432 | tc358743_s_ctrl_detect_tx_5v(sd); | 429 | tc358743_s_ctrl_detect_tx_5v(sd); |
| @@ -1884,14 +1881,6 @@ static int tc358743_probe(struct i2c_client *client, · 1451 unmodified lines | |||
| 1884 | goto err_hdl; | 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 | state->pad.flags = MEDIA_PAD_FL_SOURCE; | 1884 | state->pad.flags = MEDIA_PAD_FL_SOURCE; |
| 1896 | err = media_entity_pads_init(&sd->entity, 1, &state->pad); | 1885 | err = media_entity_pads_init(&sd->entity, 1, &state->pad); |
| 1897 | if (err < 0) | 1886 | if (err < 0) |
| @@ -1940,7 +1929,6 @@ static int tc358743_probe(struct i2c_client *client, · 42 unmodified lines | |||
| 1940 | 1929 | ||
| 1941 | err_work_queues: | 1930 | err_work_queues: |
| 1942 | cancel_delayed_work(&state->delayed_work_enable_hotplug); | 1931 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
| 1943 | destroy_workqueue(state->work_queues); | ||
| 1944 | mutex_destroy(&state->confctl_mutex); | 1932 | mutex_destroy(&state->confctl_mutex); |
| 1945 | err_hdl: | 1933 | err_hdl: |
| 1946 | media_entity_cleanup(&sd->entity); | 1934 | media_entity_cleanup(&sd->entity); |
| @@ -1954,7 +1942,6 @@ static int tc358743_remove(struct i2c_client *client) · 7 unmodified lines | |||
| 1954 | struct tc358743_state *state = to_state(sd); | 1942 | struct tc358743_state *state = to_state(sd); |
| 1955 | 1943 | ||
| 1956 | cancel_delayed_work(&state->delayed_work_enable_hotplug); | 1944 | cancel_delayed_work(&state->delayed_work_enable_hotplug); |
| 1957 | destroy_workqueue(state->work_queues); | ||
| 1958 | v4l2_async_unregister_subdev(sd); | 1945 | v4l2_async_unregister_subdev(sd); |
| 1959 | v4l2_device_unregister_subdev(sd); | 1946 | v4l2_device_unregister_subdev(sd); |
| 1960 | mutex_destroy(&state->confctl_mutex); | 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 | static const struct v4l2_subdev_core_ops tvaudio_core_ops = { | 1856 | static const struct v4l2_subdev_core_ops tvaudio_core_ops = { |
| 1857 | .log_status = tvaudio_log_status, | 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 | static const struct v4l2_subdev_tuner_ops tvaudio_tuner_ops = { | 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 | static const struct v4l2_subdev_core_ops wm8775_core_ops = { | 179 | static const struct v4l2_subdev_core_ops wm8775_core_ops = { |
| 180 | .log_status = wm8775_log_status, | 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 | static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = { | 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 | unsigned long arg) | 423 | unsigned long arg) |
| 424 | { | 424 | { |
| 425 | struct media_devnode *devnode = media_devnode_data(filp); | 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 | long ret; | 427 | long ret; |
| 428 | 428 | ||
| 429 | mutex_lock(&dev->graph_mutex); | 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 | unsigned long arg) | 495 | unsigned long arg) |
| 496 | { | 496 | { |
| 497 | struct media_devnode *devnode = media_devnode_data(filp); | 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 | long ret; | 499 | long ret; |
| 500 | 500 | ||
| 501 | switch (cmd) { | 501 | switch (cmd) { |
| @@ -531,7 +531,8 @@ static const struct media_file_operations media_device_fops = { · 29 unmodified lines | |||
| 531 | static ssize_t show_model(struct device *cd, | 531 | static ssize_t show_model(struct device *cd, |
| 532 | struct device_attribute *attr, char *buf) | 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 | return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); | 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 | int __must_check __media_device_register(struct media_device *mdev, | 705 | int __must_check __media_device_register(struct media_device *mdev, |
| 705 | struct module *owner) | 706 | struct module *owner) |
| 706 | { | 707 | { |
| 708 | struct media_devnode *devnode; | ||
| 707 | int ret; | 709 | int ret; |
| 708 | 710 | ||
| 711 | devnode = kzalloc(sizeof(*devnode), GFP_KERNEL); | ||
| 712 | if (!devnode) | ||
| 713 | return -ENOMEM; | ||
| 714 | |||
| 709 | /* Register the device node. */ | 715 | /* Register the device node. */ |
| 710 | mdev->devnode.fops = &media_device_fops; | 716 | mdev->devnode = devnode; |
| 711 | mdev->devnode.parent = mdev->dev; | 717 | devnode->fops = &media_device_fops; |
| 712 | mdev->devnode.release = media_device_release; | 718 | devnode->parent = mdev->dev; |
| 719 | devnode->release = media_device_release; | ||
| 713 | 720 | ||
| 714 | /* Set version 0 to indicate user-space that the graph is static */ | 721 | /* Set version 0 to indicate user-space that the graph is static */ |
| 715 | mdev->topology_version = 0; | 722 | mdev->topology_version = 0; |
| 716 | 723 | ||
| 717 | ret = media_devnode_register(&mdev->devnode, owner); | 724 | ret = media_devnode_register(mdev, devnode, owner); |
| 718 | if (ret < 0) | 725 | if (ret < 0) { |
| 726 | /* devnode free is handled in media_devnode_*() */ | ||
| 727 | mdev->devnode = NULL; | ||
| 719 | return ret; | 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 | if (ret < 0) { | 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 | return ret; | 737 | return ret; |
| 725 | } | 738 | } |
| 726 | 739 | ||
| @@ -771,11 +784,14 @@ void media_device_unregister(struct media_device *mdev) · 44 unmodified lines | |||
| 771 | mutex_lock(&mdev->graph_mutex); | 784 | mutex_lock(&mdev->graph_mutex); |
| 772 | 785 | ||
| 773 | /* Check if mdev was ever registered at all */ | 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 | mutex_unlock(&mdev->graph_mutex); | 788 | mutex_unlock(&mdev->graph_mutex); |
| 776 | return; | 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 | /* Remove all entities from the media device */ | 795 | /* Remove all entities from the media device */ |
| 780 | list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) | 796 | list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) |
| 781 | __media_device_unregister_entity(entity); | 797 | __media_device_unregister_entity(entity); |
| @@ -794,9 +810,12 @@ void media_device_unregister(struct media_device *mdev) · 12 unmodified lines | |||
| 794 | 810 | ||
| 795 | mutex_unlock(&mdev->graph_mutex); | 811 | mutex_unlock(&mdev->graph_mutex); |
| 796 | 812 | ||
| 797 | device_remove_file(&mdev->devnode.dev, &dev_attr_model); | 813 | dev_dbg(mdev->dev, "Media device unregistered\n"); |
| 798 | dev_dbg(mdev->dev, "Media device unregistering\n"); | 814 | |
| 799 | media_devnode_unregister(&mdev->devnode); | 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 | EXPORT_SYMBOL_GPL(media_device_unregister); | 820 | EXPORT_SYMBOL_GPL(media_device_unregister); |
| 802 | 821 | ||
| @@ -44,6 +44,7 @@ · 43 unmodified lines | |||
| 44 | #include <linux/uaccess.h> | 44 | #include <linux/uaccess.h> |
| 45 | 45 | ||
| 46 | #include <media/media-devnode.h> | 46 | #include <media/media-devnode.h> |
| 47 | #include <media/media-device.h> | ||
| 47 | 48 | ||
| 48 | #define MEDIA_NUM_DEVICES 256 | 49 | #define MEDIA_NUM_DEVICES 256 |
| 49 | #define MEDIA_NAME "media" | 50 | #define MEDIA_NAME "media" |
| @@ -59,21 +60,19 @@ static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES); · 9 unmodified lines | |||
| 59 | /* Called when the last user of the media device exits. */ | 60 | /* Called when the last user of the media device exits. */ |
| 60 | static void media_devnode_release(struct device *cd) | 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 | mutex_lock(&media_devnode_lock); | 65 | mutex_lock(&media_devnode_lock); |
| 65 | |||
| 66 | /* Delete the cdev on this minor as well */ | ||
| 67 | cdev_del(&mdev->cdev); | ||
| 68 | |||
| 69 | /* Mark device node number as free */ | 66 | /* Mark device node number as free */ |
| 70 | clear_bit(mdev->minor, media_devnode_nums); | 67 | clear_bit(devnode->minor, media_devnode_nums); |
| 71 | |||
| 72 | mutex_unlock(&media_devnode_lock); | 68 | mutex_unlock(&media_devnode_lock); |
| 73 | 69 | ||
| 74 | /* Release media_devnode and perform other cleanups as needed. */ | 70 | /* Release media_devnode and perform other cleanups as needed. */ |
| 75 | if (mdev->release) | 71 | if (devnode->release) |
| 76 | mdev->release(mdev); | 72 | devnode->release(devnode); |
| 73 | |||
| 74 | kfree(devnode); | ||
| 75 | pr_debug("%s: Media Devnode Deallocated\n", __func__); | ||
| 77 | } | 76 | } |
| 78 | 77 | ||
| 79 | static struct bus_type media_bus_type = { | 78 | static struct bus_type media_bus_type = { |
| @@ -83,37 +82,37 @@ static struct bus_type media_bus_type = { · 3 unmodified lines | |||
| 83 | static ssize_t media_read(struct file *filp, char __user *buf, | 82 | static ssize_t media_read(struct file *filp, char __user *buf, |
| 84 | size_t sz, loff_t *off) | 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 | return -EINVAL; | 88 | return -EINVAL; |
| 90 | if (!media_devnode_is_registered(mdev)) | 89 | if (!media_devnode_is_registered(devnode)) |
| 91 | return -EIO; | 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 | static ssize_t media_write(struct file *filp, const char __user *buf, | 94 | static ssize_t media_write(struct file *filp, const char __user *buf, |
| 96 | size_t sz, loff_t *off) | 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 | return -EINVAL; | 100 | return -EINVAL; |
| 102 | if (!media_devnode_is_registered(mdev)) | 101 | if (!media_devnode_is_registered(devnode)) |
| 103 | return -EIO; | 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 | static unsigned int media_poll(struct file *filp, | 106 | static unsigned int media_poll(struct file *filp, |
| 108 | struct poll_table_struct *poll) | 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 | return POLLERR | POLLHUP; | 112 | return POLLERR | POLLHUP; |
| 114 | if (!mdev->fops->poll) | 113 | if (!devnode->fops->poll) |
| 115 | return DEFAULT_POLLMASK; | 114 | return DEFAULT_POLLMASK; |
| 116 | return mdev->fops->poll(filp, poll); | 115 | return devnode->fops->poll(filp, poll); |
| 117 | } | 116 | } |
| 118 | 117 | ||
| 119 | static long | 118 | static long |
| @@ -121,12 +120,12 @@ __media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, · 1 unmodified line | |||
| 121 | long (*ioctl_func)(struct file *filp, unsigned int cmd, | 120 | long (*ioctl_func)(struct file *filp, unsigned int cmd, |
| 122 | unsigned long arg)) | 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 | if (!ioctl_func) | 125 | if (!ioctl_func) |
| 127 | return -ENOTTY; | 126 | return -ENOTTY; |
| 128 | 127 | ||
| 129 | if (!media_devnode_is_registered(mdev)) | 128 | if (!media_devnode_is_registered(devnode)) |
| 130 | return -EIO; | 129 | return -EIO; |
| 131 | 130 | ||
| 132 | return ioctl_func(filp, cmd, arg); | 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 | static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 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 | #ifdef CONFIG_COMPAT | 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 | static long media_compat_ioctl(struct file *filp, unsigned int cmd, | 143 | static long media_compat_ioctl(struct file *filp, unsigned int cmd, |
| 145 | unsigned long arg) | 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 | #endif /* CONFIG_COMPAT */ | 151 | #endif /* CONFIG_COMPAT */ |
| @@ -154,7 +153,7 @@ static long media_compat_ioctl(struct file *filp, unsigned int cmd, · 1 unmodified line | |||
| 154 | /* Override for the open function */ | 153 | /* Override for the open function */ |
| 155 | static int media_open(struct inode *inode, struct file *filp) | 154 | static int media_open(struct inode *inode, struct file *filp) |
| 156 | { | 155 | { |
| 157 | struct media_devnode *mdev; | 156 | struct media_devnode *devnode; |
| 158 | int ret; | 157 | int ret; |
| 159 | 158 | ||
| 160 | /* Check if the media device is available. This needs to be done with | 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 | * a crash. | 163 | * a crash. |
| 165 | */ | 164 | */ |
| 166 | mutex_lock(&media_devnode_lock); | 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 | /* return ENXIO if the media device has been removed | 167 | /* return ENXIO if the media device has been removed |
| 169 | already or if it is not registered anymore. */ | 168 | already or if it is not registered anymore. */ |
| 170 | if (!media_devnode_is_registered(mdev)) { | 169 | if (!media_devnode_is_registered(devnode)) { |
| 171 | mutex_unlock(&media_devnode_lock); | 170 | mutex_unlock(&media_devnode_lock); |
| 172 | return -ENXIO; | 171 | return -ENXIO; |
| 173 | } | 172 | } |
| 174 | /* and increase the device refcount */ | 173 | /* and increase the device refcount */ |
| 175 | get_device(&mdev->dev); | 174 | get_device(&devnode->dev); |
| 176 | mutex_unlock(&media_devnode_lock); | 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) { | 179 | if (devnode->fops->open) { |
| 181 | ret = mdev->fops->open(filp); | 180 | ret = devnode->fops->open(filp); |
| 182 | if (ret) { | 181 | if (ret) { |
| 183 | put_device(&mdev->dev); | 182 | put_device(&devnode->dev); |
| 184 | filp->private_data = NULL; | 183 | filp->private_data = NULL; |
| 185 | return ret; | 184 | return ret; |
| 186 | } | 185 | } |
| @@ -192,16 +191,18 @@ static int media_open(struct inode *inode, struct file *filp) · 5 unmodified lines | |||
| 192 | /* Override for the release function */ | 191 | /* Override for the release function */ |
| 193 | static int media_release(struct inode *inode, struct file *filp) | 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) | 196 | if (devnode->fops->release) |
| 198 | mdev->fops->release(filp); | 197 | devnode->fops->release(filp); |
| 199 | 198 | ||
| 200 | filp->private_data = NULL; | 199 | filp->private_data = NULL; |
| 201 | 200 | ||
| 202 | /* decrease the refcount unconditionally since the release() | 201 | /* decrease the refcount unconditionally since the release() |
| 203 | return value is ignored. */ | 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 | return 0; | 206 | return 0; |
| 206 | } | 207 | } |
| 207 | 208 | ||
| @@ -219,7 +220,8 @@ static const struct file_operations media_devnode_fops = { · 11 unmodified lines | |||
| 219 | .llseek = no_llseek, | 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 | struct module *owner) | 225 | struct module *owner) |
| 224 | { | 226 | { |
| 225 | int minor; | 227 | int minor; |
| @@ -231,61 +233,80 @@ int __must_check media_devnode_register(struct media_devnode *mdev, · 5 unmodified lines | |||
| 231 | if (minor == MEDIA_NUM_DEVICES) { | 233 | if (minor == MEDIA_NUM_DEVICES) { |
| 232 | mutex_unlock(&media_devnode_lock); | 234 | mutex_unlock(&media_devnode_lock); |
| 233 | pr_err("could not get a free minor\n"); | 235 | pr_err("could not get a free minor\n"); |
| 236 | kfree(devnode); | ||
| 234 | return -ENFILE; | 237 | return -ENFILE; |
| 235 | } | 238 | } |
| 236 | 239 | ||
| 237 | set_bit(minor, media_devnode_nums); | 240 | set_bit(minor, media_devnode_nums); |
| 238 | mutex_unlock(&media_devnode_lock); | 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 | /* Part 2: Initialize and register the character device */ | 255 | /* Part 2: Initialize and register the character device */ |
| 243 | cdev_init(&mdev->cdev, &media_devnode_fops); | 256 | cdev_init(&devnode->cdev, &media_devnode_fops); |
| 244 | mdev->cdev.owner = owner; | 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 | if (ret < 0) { | 261 | if (ret < 0) { |
| 248 | pr_err("%s: cdev_add failed\n", __func__); | 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 */ | 266 | /* Part 3: Add the media device */ |
| 253 | mdev->dev.bus = &media_bus_type; | 267 | ret = device_add(&devnode->dev); |
| 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); | ||
| 260 | if (ret < 0) { | 268 | if (ret < 0) { |
| 261 | pr_err("%s: device_register failed\n", __func__); | 269 | pr_err("%s: device_add failed\n", __func__); |
| 262 | goto error; | 270 | goto device_add_error; |
| 263 | } | 271 | } |
| 264 | 272 | ||
| 265 | /* Part 4: Activate this minor. The char device can now be used. */ | 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 | return 0; | 276 | return 0; |
| 269 | 277 | ||
| 270 | error: | 278 | device_add_error: |
| 279 | cdev_del(&devnode->cdev); | ||
| 280 | cdev_add_error: | ||
| 271 | mutex_lock(&media_devnode_lock); | 281 | mutex_lock(&media_devnode_lock); |
| 272 | cdev_del(&mdev->cdev); | 282 | clear_bit(devnode->minor, media_devnode_nums); |
| 273 | clear_bit(mdev->minor, media_devnode_nums); | 283 | devnode->media_dev = NULL; |
| 274 | mutex_unlock(&media_devnode_lock); | 284 | mutex_unlock(&media_devnode_lock); |
| 275 | 285 | ||
| 286 | put_device(&devnode->dev); | ||
| 276 | return ret; | 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 */ | 292 | /* Check if devnode was ever registered at all */ |
| 282 | if (!media_devnode_is_registered(mdev)) | 293 | if (!media_devnode_is_registered(devnode)) |
| 283 | return; | 294 | return; |
| 284 | 295 | ||
| 285 | mutex_lock(&media_devnode_lock); | 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 | mutex_unlock(&media_devnode_lock); | 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 | static int dst_ca_open(struct inode *inode, struct file *file) | 655 | static int dst_ca_open(struct inode *inode, struct file *file) |
| 656 | { | 656 | { |
| 657 | dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file); | 657 | dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file); |
| 658 | try_module_get(THIS_MODULE); | ||
| 659 | 658 | ||
| 660 | return 0; | 659 | return 0; |
| 661 | } | 660 | } |
| @@ -663,7 +662,6 @@ static int dst_ca_open(struct inode *inode, struct file *file) · 1 unmodified line | |||
| 663 | static int dst_ca_release(struct inode *inode, struct file *file) | 662 | static int dst_ca_release(struct inode *inode, struct file *file) |
| 664 | { | 663 | { |
| 665 | dprintk(verbose, DST_CA_DEBUG, 1, " Device closed."); | 664 | dprintk(verbose, DST_CA_DEBUG, 1, " Device closed."); |
| 666 | module_put(THIS_MODULE); | ||
| 667 | 665 | ||
| 668 | return 0; | 666 | return 0; |
| 669 | } | 667 | } |
| @@ -492,7 +492,6 @@ static int cobalt_subdevs_init(struct cobalt *cobalt) · 491 unmodified lines | |||
| 492 | .ain_sel = ADV7604_AIN7_8_9_NC_SYNC_3_1, | 492 | .ain_sel = ADV7604_AIN7_8_9_NC_SYNC_3_1, |
| 493 | .bus_order = ADV7604_BUS_ORDER_BRG, | 493 | .bus_order = ADV7604_BUS_ORDER_BRG, |
| 494 | .blank_data = 1, | 494 | .blank_data = 1, |
| 495 | .op_656_range = 1, | ||
| 496 | .op_format_mode_sel = ADV7604_OP_FORMAT_MODE0, | 495 | .op_format_mode_sel = ADV7604_OP_FORMAT_MODE0, |
| 497 | .int1_config = ADV76XX_INT1_CONFIG_ACTIVE_HIGH, | 496 | .int1_config = ADV76XX_INT1_CONFIG_ACTIVE_HIGH, |
| 498 | .dr_str_data = ADV76XX_DR_STR_HIGH, | 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 | .bus_order = ADV7842_BUS_ORDER_RBG, | 570 | .bus_order = ADV7842_BUS_ORDER_RBG, |
| 572 | .op_format_mode_sel = ADV7842_OP_FORMAT_MODE0, | 571 | .op_format_mode_sel = ADV7842_OP_FORMAT_MODE0, |
| 573 | .blank_data = 1, | 572 | .blank_data = 1, |
| 574 | .op_656_range = 1, | ||
| 575 | .dr_str_data = 3, | 573 | .dr_str_data = 3, |
| 576 | .dr_str_clk = 3, | 574 | .dr_str_clk = 3, |
| 577 | .dr_str_sync = 3, | 575 | .dr_str_sync = 3, |
| @@ -691,17 +689,10 @@ static int cobalt_probe(struct pci_dev *pci_dev, · 113 unmodified lines | |||
| 691 | cobalt->pci_dev = pci_dev; | 689 | cobalt->pci_dev = pci_dev; |
| 692 | cobalt->instance = i; | 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 | retval = v4l2_device_register(&pci_dev->dev, &cobalt->v4l2_dev); | 692 | retval = v4l2_device_register(&pci_dev->dev, &cobalt->v4l2_dev); |
| 701 | if (retval) { | 693 | if (retval) { |
| 702 | pr_err("cobalt: v4l2_device_register of card %d failed\n", | 694 | pr_err("cobalt: v4l2_device_register of card %d failed\n", |
| 703 | cobalt->instance); | 695 | cobalt->instance); |
| 704 | vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx); | ||
| 705 | kfree(cobalt); | 696 | kfree(cobalt); |
| 706 | return retval; | 697 | return retval; |
| 707 | } | 698 | } |
| @@ -782,7 +773,6 @@ err: · 74 unmodified lines | |||
| 782 | cobalt_err("error %d on initialization\n", retval); | 773 | cobalt_err("error %d on initialization\n", retval); |
| 783 | 774 | ||
| 784 | v4l2_device_unregister(&cobalt->v4l2_dev); | 775 | v4l2_device_unregister(&cobalt->v4l2_dev); |
| 785 | vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx); | ||
| 786 | kfree(cobalt); | 776 | kfree(cobalt); |
| 787 | return retval; | 777 | return retval; |
| 788 | } | 778 | } |
| @@ -818,7 +808,6 @@ static void cobalt_remove(struct pci_dev *pci_dev) · 29 unmodified lines | |||
| 818 | cobalt_info("removed cobalt card\n"); | 808 | cobalt_info("removed cobalt card\n"); |
| 819 | 809 | ||
| 820 | v4l2_device_unregister(v4l2_dev); | 810 | v4l2_device_unregister(v4l2_dev); |
| 821 | vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx); | ||
| 822 | kfree(cobalt); | 811 | kfree(cobalt); |
| 823 | } | 812 | } |
| 824 | 813 | ||
| @@ -262,7 +262,6 @@ struct cobalt { · 261 unmodified lines | |||
| 262 | int instance; | 262 | int instance; |
| 263 | struct pci_dev *pci_dev; | 263 | struct pci_dev *pci_dev; |
| 264 | struct v4l2_device v4l2_dev; | 264 | struct v4l2_device v4l2_dev; |
| 265 | void *alloc_ctx; | ||
| 266 | 265 | ||
| 267 | void __iomem *bar0, *bar1; | 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 | static int cobalt_queue_setup(struct vb2_queue *q, | 46 | static int cobalt_queue_setup(struct vb2_queue *q, |
| 47 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct cobalt_stream *s = q->drv_priv; | 50 | struct cobalt_stream *s = q->drv_priv; |
| 51 | unsigned size = s->stride * s->height; | 51 | unsigned size = s->stride * s->height; |
| @@ -54,7 +54,6 @@ static int cobalt_queue_setup(struct vb2_queue *q, · 2 unmodified lines | |||
| 54 | *num_buffers = 3; | 54 | *num_buffers = 3; |
| 55 | if (*num_buffers > NR_BUFS) | 55 | if (*num_buffers > NR_BUFS) |
| 56 | *num_buffers = NR_BUFS; | 56 | *num_buffers = NR_BUFS; |
| 57 | alloc_ctxs[0] = s->cobalt->alloc_ctx; | ||
| 58 | if (*num_planes) | 57 | if (*num_planes) |
| 59 | return sizes[0] < size ? -EINVAL : 0; | 58 | return sizes[0] < size ? -EINVAL : 0; |
| 60 | *num_planes = 1; | 59 | *num_planes = 1; |
| @@ -1224,6 +1223,7 @@ static int cobalt_node_register(struct cobalt *cobalt, int node) · 1163 unmodified lines | |||
| 1224 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1223 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1225 | q->min_buffers_needed = 2; | 1224 | q->min_buffers_needed = 2; |
| 1226 | q->lock = &s->lock; | 1225 | q->lock = &s->lock; |
| 1226 | q->dev = &cobalt->pci_dev->dev; | ||
| 1227 | vdev->queue = q; | 1227 | vdev->queue = q; |
| 1228 | 1228 | ||
| 1229 | video_set_drvdata(vdev, s); | 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 | vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); | 93 | vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); |
| 94 | 94 | ||
| 95 | snd_cx18_lock(cxsc); | 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 | snd_cx18_unlock(cxsc); | 97 | snd_cx18_unlock(cxsc); |
| 98 | 98 | ||
| 99 | if (!ret) | 99 | if (!ret) |
| @@ -115,14 +115,14 @@ static int snd_cx18_mixer_tv_vol_put(struct snd_kcontrol *kctl, · 15 unmodified lines | |||
| 115 | snd_cx18_lock(cxsc); | 115 | snd_cx18_lock(cxsc); |
| 116 | 116 | ||
| 117 | /* Fetch current state */ | 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 | if (ret || | 120 | if (ret || |
| 121 | (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { | 121 | (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { |
| 122 | 122 | ||
| 123 | /* Set, if needed */ | 123 | /* Set, if needed */ |
| 124 | vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); | 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 | if (!ret) | 126 | if (!ret) |
| 127 | ret = 1; /* Indicate control was changed w/o error */ | 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 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize; | 560 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize; |
| 561 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize; | 561 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize; |
| 562 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize; | 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 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize; | 564 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize; |
| 565 | cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */ | 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 | * (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line = | 492 | * (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line = |
| 493 | * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples | 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 */ | 495 | #define 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 */ | 496 | #define 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 */ | 497 | #define VBI_HBLANK_SAMPLES_50HZ 284 /* 4 byte EAV + 280 anc/fill */ |
| 498 | 498 | ||
| 499 | #define CX18_VBI_FRAMES 32 | 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 | vbifmt->sampling_rate = 27000000; | 178 | vbifmt->sampling_rate = 27000000; |
| 179 | vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */ | 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 | vbifmt->sample_format = V4L2_PIX_FMT_GREY; | 181 | vbifmt->sample_format = V4L2_PIX_FMT_GREY; |
| 182 | vbifmt->start[0] = cx->vbi.start[0]; | 182 | vbifmt->start[0] = cx->vbi.start[0]; |
| 183 | vbifmt->start[1] = cx->vbi.start[1]; | 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 | /* Lines per field */ | 605 | /* Lines per field */ |
| 606 | data[1] = (lines / 2) | ((lines / 2) << 16); | 606 | data[1] = (lines / 2) | ((lines / 2) << 16); |
| 607 | /* bytes per line */ | 607 | /* bytes per line */ |
| 608 | data[2] = (raw ? vbi_active_samples | 608 | data[2] = (raw ? VBI_ACTIVE_SAMPLES |
| 609 | : (cx->is_60hz ? vbi_hblank_samples_60Hz | 609 | : (cx->is_60hz ? VBI_HBLANK_SAMPLES_60HZ |
| 610 | : vbi_hblank_samples_50Hz)); | 610 | : VBI_HBLANK_SAMPLES_50HZ)); |
| 611 | /* Every X number of frames a VBI interrupt arrives | 611 | /* Every X number of frames a VBI interrupt arrives |
| 612 | (frames as in 25 or 30 fps) */ | 612 | (frames as in 25 or 30 fps) */ |
| 613 | data[3] = 1; | 613 | data[3] = 1; |
| @@ -761,7 +761,7 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s) · 147 unmodified lines | |||
| 761 | s->bufs_per_mdl = 1; | 761 | s->bufs_per_mdl = 1; |
| 762 | if (cx18_raw_vbi(s->cx)) { | 762 | if (cx18_raw_vbi(s->cx)) { |
| 763 | s->mdl_size = (s->cx->is_60hz ? 12 : 18) | 763 | s->mdl_size = (s->cx->is_60hz ? 12 : 18) |
| 764 | * 2 * vbi_active_samples; | 764 | * 2 * VBI_ACTIVE_SAMPLES; |
| 765 | } else { | 765 | } else { |
| 766 | /* | 766 | /* |
| 767 | * See comment in cx18_vbi_setup() below about the | 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 | * the lines on which EAV RP codes toggle. | 769 | * the lines on which EAV RP codes toggle. |
| 770 | */ | 770 | */ |
| 771 | s->mdl_size = s->cx->is_60hz | 771 | s->mdl_size = s->cx->is_60hz |
| 772 | ? (21 - 4 + 1) * 2 * vbi_hblank_samples_60Hz | 772 | ? (21 - 4 + 1) * 2 * VBI_HBLANK_SAMPLES_60HZ |
| 773 | : (23 - 2 + 1) * 2 * vbi_hblank_samples_50Hz; | 773 | : (23 - 2 + 1) * 2 * VBI_HBLANK_SAMPLES_50HZ; |
| 774 | } | 774 | } |
| 775 | break; | 775 | break; |
| 776 | default: | 776 | default: |
| @@ -108,7 +108,7 @@ static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) · 107 unmodified lines | |||
| 108 | /* FIXME - this function ignores the input size. */ | 108 | /* FIXME - this function ignores the input size. */ |
| 109 | static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size) | 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 | u32 lines = cx->vbi.count * 2; | 112 | u32 lines = cx->vbi.count * 2; |
| 113 | u8 *q = buf; | 113 | u8 *q = buf; |
| 114 | u8 *p; | 114 | u8 *p; |
| @@ -145,8 +145,8 @@ static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size, · 30 unmodified lines | |||
| 145 | struct v4l2_decode_vbi_line vbi; | 145 | struct v4l2_decode_vbi_line vbi; |
| 146 | int i; | 146 | int i; |
| 147 | u32 line = 0; | 147 | u32 line = 0; |
| 148 | u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz | 148 | u32 line_size = cx->is_60hz ? VBI_HBLANK_SAMPLES_60HZ |
| 149 | : vbi_hblank_samples_50Hz; | 149 | : VBI_HBLANK_SAMPLES_50HZ; |
| 150 | 150 | ||
| 151 | /* find the first valid line */ | 151 | /* find the first valid line */ |
| 152 | for (i = hdr_size, buf += hdr_size; i < size; i++, buf++) { | 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 | static int queue_setup(struct vb2_queue *q, | 1141 | static int queue_setup(struct vb2_queue *q, |
| 1142 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct cx23885_dev *dev = q->drv_priv; | 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 | dev->ts1.ts_packet_count = mpeglines; | 1148 | dev->ts1.ts_packet_count = mpeglines; |
| 1149 | *num_planes = 1; | 1149 | *num_planes = 1; |
| 1150 | sizes[0] = mpeglinesize * mpeglines; | 1150 | sizes[0] = mpeglinesize * mpeglines; |
| 1151 | alloc_ctxs[0] = dev->alloc_ctx; | ||
| 1152 | *num_buffers = mpegbufs; | 1151 | *num_buffers = mpegbufs; |
| 1153 | return 0; | 1152 | return 0; |
| 1154 | } | 1153 | } |
| @@ -765,6 +765,11 @@ struct cx23885_board cx23885_boards[] = { · 764 unmodified lines | |||
| 765 | .amux = CX25840_AUDIO7, | 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 | const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); | 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 | .subvendor = 0x1576, | 1065 | .subvendor = 0x1576, |
| 1061 | .subdevice = 0x0460, | 1066 | .subdevice = 0x0460, |
| 1062 | .card = CX23885_BOARD_VIEWCAST_460E, | 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 | const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); | 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 | case 150329: | 1270 | case 150329: |
| 1258 | /* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */ | 1271 | /* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */ |
| 1259 | break; | 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 | default: | 1281 | default: |
| 1261 | printk(KERN_WARNING "%s: warning: " | 1282 | printk(KERN_WARNING "%s: warning: " |
| 1262 | "unknown hauppauge model #%d\n", | 1283 | "unknown hauppauge model #%d\n", |
| @@ -1729,20 +1750,22 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) · 466 unmodified lines | |||
| 1729 | cx23885_gpio_set(dev, GPIO_2); | 1750 | cx23885_gpio_set(dev, GPIO_2); |
| 1730 | break; | 1751 | break; |
| 1731 | case CX23885_BOARD_HAUPPAUGE_HVR5525: | 1752 | case CX23885_BOARD_HAUPPAUGE_HVR5525: |
| 1753 | case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: | ||
| 1732 | /* | 1754 | /* |
| 1733 | * GPIO-00 IR_WIDE | 1755 | * HVR5525 GPIO Details: |
| 1734 | * GPIO-02 wake# | 1756 | * GPIO-00 IR_WIDE |
| 1735 | * GPIO-03 VAUX Pres. | 1757 | * GPIO-02 wake# |
| 1736 | * GPIO-07 PROG# | 1758 | * GPIO-03 VAUX Pres. |
| 1737 | * GPIO-08 SAT_RESN | 1759 | * GPIO-07 PROG# |
| 1738 | * GPIO-09 TER_RESN | 1760 | * GPIO-08 SAT_RESN |
| 1739 | * GPIO-10 B2_SENSE | 1761 | * GPIO-09 TER_RESN |
| 1740 | * GPIO-11 B1_SENSE | 1762 | * GPIO-10 B2_SENSE |
| 1741 | * GPIO-15 IR_LED_STATUS | 1763 | * GPIO-11 B1_SENSE |
| 1742 | * GPIO-19 IR_NARROW | 1764 | * GPIO-15 IR_LED_STATUS |
| 1743 | * GPIO-20 Blauster1 | 1765 | * GPIO-19 IR_NARROW |
| 1744 | * ALTGPIO VAUX_SWITCH | 1766 | * GPIO-20 Blauster1 |
| 1745 | * AUX_PLL_CLK : Blaster2 | 1767 | * ALTGPIO VAUX_SWITCH |
| 1768 | * AUX_PLL_CLK : Blaster2 | ||
| 1746 | */ | 1769 | */ |
| 1747 | /* Put the parts into reset and back */ | 1770 | /* Put the parts into reset and back */ |
| 1748 | cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1); | 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 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | 1825 | case CX23885_BOARD_HAUPPAUGE_HVR1255: |
| 1803 | case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: | 1826 | case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: |
| 1804 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | 1827 | case CX23885_BOARD_HAUPPAUGE_HVR1210: |
| 1828 | case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: | ||
| 1805 | /* FIXME: Implement me */ | 1829 | /* FIXME: Implement me */ |
| 1806 | break; | 1830 | break; |
| 1807 | case CX23885_BOARD_HAUPPAUGE_HVR1270: | 1831 | case CX23885_BOARD_HAUPPAUGE_HVR1270: |
| @@ -2000,6 +2024,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) · 192 unmodified lines | |||
| 2000 | case CX23885_BOARD_HAUPPAUGE_STARBURST: | 2024 | case CX23885_BOARD_HAUPPAUGE_STARBURST: |
| 2001 | case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE: | 2025 | case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE: |
| 2002 | case CX23885_BOARD_HAUPPAUGE_HVR5525: | 2026 | case CX23885_BOARD_HAUPPAUGE_HVR5525: |
| 2027 | case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB: | ||
| 2003 | if (dev->i2c_bus[0].i2c_rc == 0) | 2028 | if (dev->i2c_bus[0].i2c_rc == 0) |
| 2004 | hauppauge_eeprom(dev, eeprom+0xc0); | 2029 | hauppauge_eeprom(dev, eeprom+0xc0); |
| 2005 | break; | 2030 | break; |
| @@ -2145,6 +2170,14 @@ void cx23885_card_setup(struct cx23885_dev *dev) · 139 unmodified lines | |||
| 2145 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | 2170 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ |
| 2146 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | 2171 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; |
| 2147 | break; | 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 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | 2181 | case CX23885_BOARD_HAUPPAUGE_HVR1250: |
| 2149 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | 2182 | case CX23885_BOARD_HAUPPAUGE_HVR1500: |
| 2150 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | 2183 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: |
| @@ -2005,14 +2005,9 @@ static int cx23885_initdev(struct pci_dev *pci_dev, · 2004 unmodified lines | |||
| 2005 | err = pci_set_dma_mask(pci_dev, 0xffffffff); | 2005 | err = pci_set_dma_mask(pci_dev, 0xffffffff); |
| 2006 | if (err) { | 2006 | if (err) { |
| 2007 | printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); | 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 | err = request_irq(pci_dev->irq, cx23885_irq, | 2011 | err = request_irq(pci_dev->irq, cx23885_irq, |
| 2017 | IRQF_SHARED, dev->name, dev); | 2012 | IRQF_SHARED, dev->name, dev); |
| 2018 | if (err < 0) { | 2013 | if (err < 0) { |
| @@ -2041,8 +2036,6 @@ static int cx23885_initdev(struct pci_dev *pci_dev, · 22 unmodified lines | |||
| 2041 | return 0; | 2036 | return 0; |
| 2042 | 2037 | ||
| 2043 | fail_irq: | 2038 | fail_irq: |
| 2044 | vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | ||
| 2045 | fail_context: | ||
| 2046 | cx23885_dev_unregister(dev); | 2039 | cx23885_dev_unregister(dev); |
| 2047 | fail_ctrl: | 2040 | fail_ctrl: |
| 2048 | v4l2_ctrl_handler_free(hdl); | 2041 | v4l2_ctrl_handler_free(hdl); |
| @@ -2068,7 +2061,6 @@ static void cx23885_finidev(struct pci_dev *pci_dev) · 19 unmodified lines | |||
| 2068 | pci_disable_device(pci_dev); | 2061 | pci_disable_device(pci_dev); |
| 2069 | 2062 | ||
| 2070 | cx23885_dev_unregister(dev); | 2063 | cx23885_dev_unregister(dev); |
| 2071 | vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | ||
| 2072 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | 2064 | v4l2_ctrl_handler_free(&dev->ctrl_handler); |
| 2073 | v4l2_device_unregister(v4l2_dev); | 2065 | v4l2_device_unregister(v4l2_dev); |
| 2074 | kfree(dev); | 2066 | kfree(dev); |
| @@ -94,7 +94,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); · 93 unmodified lines | |||
| 94 | 94 | ||
| 95 | static int queue_setup(struct vb2_queue *q, | 95 | static int queue_setup(struct vb2_queue *q, |
| 96 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct cx23885_tsport *port = q->drv_priv; | 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 | port->ts_packet_count = 32; | 102 | port->ts_packet_count = 32; |
| 103 | *num_planes = 1; | 103 | *num_planes = 1; |
| 104 | sizes[0] = port->ts_packet_size * port->ts_packet_count; | 104 | sizes[0] = port->ts_packet_size * port->ts_packet_count; |
| 105 | alloc_ctxs[0] = port->dev->alloc_ctx; | ||
| 106 | *num_buffers = 32; | 105 | *num_buffers = 32; |
| 107 | return 0; | 106 | return 0; |
| 108 | } | 107 | } |
| @@ -2269,9 +2268,107 @@ static int dvb_register(struct cx23885_tsport *port) · 2160 unmodified lines | |||
| 2269 | } | 2268 | } |
| 2270 | break; | 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 | default: | 2369 | default: |
| 2273 | printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " | 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 | dev->name); | 2372 | dev->name); |
| 2276 | break; | 2373 | break; |
| 2277 | } | 2374 | } |
| @@ -2397,6 +2494,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port) · 119 unmodified lines | |||
| 2397 | q->mem_ops = &vb2_dma_sg_memops; | 2494 | q->mem_ops = &vb2_dma_sg_memops; |
| 2398 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 2495 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 2399 | q->lock = &dev->lock; | 2496 | q->lock = &dev->lock; |
| 2497 | q->dev = &dev->pci->dev; | ||
| 2400 | 2498 | ||
| 2401 | err = vb2_queue_init(q); | 2499 | err = vb2_queue_init(q); |
| 2402 | if (err < 0) | 2500 | if (err < 0) |
| @@ -122,7 +122,7 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, · 121 unmodified lines | |||
| 122 | 122 | ||
| 123 | static int queue_setup(struct vb2_queue *q, | 123 | static int queue_setup(struct vb2_queue *q, |
| 124 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct cx23885_dev *dev = q->drv_priv; | 127 | struct cx23885_dev *dev = q->drv_priv; |
| 128 | unsigned lines = VBI_PAL_LINE_COUNT; | 128 | unsigned lines = VBI_PAL_LINE_COUNT; |
| @@ -131,7 +131,6 @@ static int queue_setup(struct vb2_queue *q, · 2 unmodified lines | |||
| 131 | lines = VBI_NTSC_LINE_COUNT; | 131 | lines = VBI_NTSC_LINE_COUNT; |
| 132 | *num_planes = 1; | 132 | *num_planes = 1; |
| 133 | sizes[0] = lines * VBI_LINE_LENGTH * 2; | 133 | sizes[0] = lines * VBI_LINE_LENGTH * 2; |
| 134 | alloc_ctxs[0] = dev->alloc_ctx; | ||
| 135 | return 0; | 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 | static int queue_setup(struct vb2_queue *q, | 336 | static int queue_setup(struct vb2_queue *q, |
| 337 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct cx23885_dev *dev = q->drv_priv; | 340 | struct cx23885_dev *dev = q->drv_priv; |
| 341 | 341 | ||
| 342 | *num_planes = 1; | 342 | *num_planes = 1; |
| 343 | sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3; | 343 | sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3; |
| 344 | alloc_ctxs[0] = dev->alloc_ctx; | ||
| 345 | return 0; | 344 | return 0; |
| 346 | } | 345 | } |
| 347 | 346 | ||
| @@ -1268,6 +1267,7 @@ int cx23885_video_register(struct cx23885_dev *dev) · 920 unmodified lines | |||
| 1268 | q->mem_ops = &vb2_dma_sg_memops; | 1267 | q->mem_ops = &vb2_dma_sg_memops; |
| 1269 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1268 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1270 | q->lock = &dev->lock; | 1269 | q->lock = &dev->lock; |
| 1270 | q->dev = &dev->pci->dev; | ||
| 1271 | 1271 | ||
| 1272 | err = vb2_queue_init(q); | 1272 | err = vb2_queue_init(q); |
| 1273 | if (err < 0) | 1273 | if (err < 0) |
| @@ -1284,6 +1284,7 @@ int cx23885_video_register(struct cx23885_dev *dev) · 10 unmodified lines | |||
| 1284 | q->mem_ops = &vb2_dma_sg_memops; | 1284 | q->mem_ops = &vb2_dma_sg_memops; |
| 1285 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1285 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1286 | q->lock = &dev->lock; | 1286 | q->lock = &dev->lock; |
| 1287 | q->dev = &dev->pci->dev; | ||
| 1287 | 1288 | ||
| 1288 | err = vb2_queue_init(q); | 1289 | err = vb2_queue_init(q); |
| 1289 | if (err < 0) | 1290 | if (err < 0) |
| @@ -103,6 +103,7 @@ · 102 unmodified lines | |||
| 103 | #define CX23885_BOARD_HAUPPAUGE_STARBURST 53 | 103 | #define CX23885_BOARD_HAUPPAUGE_STARBURST 53 |
| 104 | #define CX23885_BOARD_VIEWCAST_260E 54 | 104 | #define CX23885_BOARD_VIEWCAST_260E 54 |
| 105 | #define CX23885_BOARD_VIEWCAST_460E 55 | 105 | #define CX23885_BOARD_VIEWCAST_460E 55 |
| 106 | #define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB 56 | ||
| 106 | 107 | ||
| 107 | #define GPIO_0 0x00000001 | 108 | #define GPIO_0 0x00000001 |
| 108 | #define GPIO_1 0x00000002 | 109 | #define GPIO_1 0x00000002 |
| @@ -430,7 +431,6 @@ struct cx23885_dev { · 321 unmodified lines | |||
| 430 | struct vb2_queue vb2_vidq; | 431 | struct vb2_queue vb2_vidq; |
| 431 | struct cx23885_dmaqueue vbiq; | 432 | struct cx23885_dmaqueue vbiq; |
| 432 | struct vb2_queue vb2_vbiq; | 433 | struct vb2_queue vb2_vbiq; |
| 433 | void *alloc_ctx; | ||
| 434 | 434 | ||
| 435 | spinlock_t slock; | 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 | * Only boards with eeprom and byte 1 at eeprom=1 have it | 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 | {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | 697 | {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
| 698 | {0,} | 698 | {0,} |
| 699 | }; | 699 | }; |
| @@ -1301,15 +1301,10 @@ static int cx25821_initdev(struct pci_dev *pci_dev, · 1300 unmodified lines | |||
| 1301 | 1301 | ||
| 1302 | goto fail_unregister_device; | 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 | err = cx25821_dev_setup(dev); | 1305 | err = cx25821_dev_setup(dev); |
| 1311 | if (err) | 1306 | if (err) |
| 1312 | goto fail_free_ctx; | 1307 | goto fail_unregister_pci; |
| 1313 | 1308 | ||
| 1314 | /* print pci info */ | 1309 | /* print pci info */ |
| 1315 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); | 1310 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); |
| @@ -1340,8 +1335,6 @@ fail_irq: · 24 unmodified lines | |||
| 1340 | pr_info("cx25821_initdev() can't get IRQ !\n"); | 1335 | pr_info("cx25821_initdev() can't get IRQ !\n"); |
| 1341 | cx25821_dev_unregister(dev); | 1336 | cx25821_dev_unregister(dev); |
| 1342 | 1337 | ||
| 1343 | fail_free_ctx: | ||
| 1344 | vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | ||
| 1345 | fail_unregister_pci: | 1338 | fail_unregister_pci: |
| 1346 | pci_disable_device(pci_dev); | 1339 | pci_disable_device(pci_dev); |
| 1347 | fail_unregister_device: | 1340 | fail_unregister_device: |
| @@ -1365,7 +1358,6 @@ static void cx25821_finidev(struct pci_dev *pci_dev) · 17 unmodified lines | |||
| 1365 | free_irq(pci_dev->irq, dev); | 1358 | free_irq(pci_dev->irq, dev); |
| 1366 | 1359 | ||
| 1367 | cx25821_dev_unregister(dev); | 1360 | cx25821_dev_unregister(dev); |
| 1368 | vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | ||
| 1369 | v4l2_device_unregister(v4l2_dev); | 1361 | v4l2_device_unregister(v4l2_dev); |
| 1370 | kfree(dev); | 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 | static int cx25821_queue_setup(struct vb2_queue *q, | 144 | static int cx25821_queue_setup(struct vb2_queue *q, |
| 145 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct cx25821_channel *chan = q->drv_priv; | 148 | struct cx25821_channel *chan = q->drv_priv; |
| 149 | unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3; | 149 | unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3; |
| 150 | 150 | ||
| 151 | alloc_ctxs[0] = chan->dev->alloc_ctx; | ||
| 152 | |||
| 153 | if (*num_planes) | 151 | if (*num_planes) |
| 154 | return sizes[0] < size ? -EINVAL : 0; | 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 | q->mem_ops = &vb2_dma_sg_memops; | 757 | q->mem_ops = &vb2_dma_sg_memops; |
| 760 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 758 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 761 | q->lock = &dev->lock; | 759 | q->lock = &dev->lock; |
| 760 | q->dev = &dev->pci->dev; | ||
| 762 | 761 | ||
| 763 | if (!is_output) { | 762 | if (!is_output) { |
| 764 | err = vb2_queue_init(q); | 763 | err = vb2_queue_init(q); |
| @@ -249,7 +249,6 @@ struct cx25821_dev { · 248 unmodified lines | |||
| 249 | int hwrevision; | 249 | int hwrevision; |
| 250 | /* used by cx25821-alsa */ | 250 | /* used by cx25821-alsa */ |
| 251 | struct snd_card *card; | 251 | struct snd_card *card; |
| 252 | void *alloc_ctx; | ||
| 253 | 252 | ||
| 254 | u32 clk_freq; | 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 | snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); | 800 | snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); |
| 801 | struct cx88_core *core = chip->core; | 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 | return 0; | 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 | static int queue_setup(struct vb2_queue *q, | 640 | static int queue_setup(struct vb2_queue *q, |
| 641 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct cx8802_dev *dev = q->drv_priv; | 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 | dev->ts_packet_size = 188 * 4; | 647 | dev->ts_packet_size = 188 * 4; |
| 648 | dev->ts_packet_count = 32; | 648 | dev->ts_packet_count = 32; |
| 649 | sizes[0] = dev->ts_packet_size * dev->ts_packet_count; | 649 | sizes[0] = dev->ts_packet_size * dev->ts_packet_count; |
| 650 | alloc_ctxs[0] = dev->alloc_ctx; | ||
| 651 | return 0; | 650 | return 0; |
| 652 | } | 651 | } |
| 653 | 652 | ||
| @@ -1183,6 +1182,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) · 529 unmodified lines | |||
| 1183 | q->mem_ops = &vb2_dma_sg_memops; | 1182 | q->mem_ops = &vb2_dma_sg_memops; |
| 1184 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1183 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1185 | q->lock = &core->lock; | 1184 | q->lock = &core->lock; |
| 1185 | q->dev = &dev->pci->dev; | ||
| 1186 | 1186 | ||
| 1187 | err = vb2_queue_init(q); | 1187 | err = vb2_queue_init(q); |
| 1188 | if (err < 0) | 1188 | if (err < 0) |
| @@ -84,7 +84,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); · 83 unmodified lines | |||
| 84 | 84 | ||
| 85 | static int queue_setup(struct vb2_queue *q, | 85 | static int queue_setup(struct vb2_queue *q, |
| 86 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct cx8802_dev *dev = q->drv_priv; | 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 | dev->ts_packet_size = 188 * 4; | 92 | dev->ts_packet_size = 188 * 4; |
| 93 | dev->ts_packet_count = dvb_buf_tscnt; | 93 | dev->ts_packet_count = dvb_buf_tscnt; |
| 94 | sizes[0] = dev->ts_packet_size * dev->ts_packet_count; | 94 | sizes[0] = dev->ts_packet_size * dev->ts_packet_count; |
| 95 | alloc_ctxs[0] = dev->alloc_ctx; | ||
| 96 | *num_buffers = dvb_buf_tscnt; | 95 | *num_buffers = dvb_buf_tscnt; |
| 97 | return 0; | 96 | return 0; |
| 98 | } | 97 | } |
| @@ -1793,6 +1792,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) · 1694 unmodified lines | |||
| 1793 | q->mem_ops = &vb2_dma_sg_memops; | 1792 | q->mem_ops = &vb2_dma_sg_memops; |
| 1794 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1793 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1795 | q->lock = &core->lock; | 1794 | q->lock = &core->lock; |
| 1795 | q->dev = &dev->pci->dev; | ||
| 1796 | 1796 | ||
| 1797 | err = vb2_queue_init(q); | 1797 | err = vb2_queue_init(q); |
| 1798 | if (err < 0) | 1798 | if (err < 0) |
| @@ -726,11 +726,6 @@ static int cx8802_probe(struct pci_dev *pci_dev, · 725 unmodified lines | |||
| 726 | if (NULL == dev) | 726 | if (NULL == dev) |
| 727 | goto fail_core; | 727 | goto fail_core; |
| 728 | dev->pci = pci_dev; | 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 | dev->core = core; | 729 | dev->core = core; |
| 735 | 730 | ||
| 736 | /* Maintain a reference so cx88-video can query the 8802 device. */ | 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 | err = cx8802_init_common(dev); | 734 | err = cx8802_init_common(dev); |
| 740 | if (err != 0) | 735 | if (err != 0) |
| 741 | goto fail_free; | 736 | goto fail_dev; |
| 742 | 737 | ||
| 743 | INIT_LIST_HEAD(&dev->drvlist); | 738 | INIT_LIST_HEAD(&dev->drvlist); |
| 744 | mutex_lock(&cx8802_mutex); | 739 | mutex_lock(&cx8802_mutex); |
| @@ -749,8 +744,6 @@ static int cx8802_probe(struct pci_dev *pci_dev, · 4 unmodified lines | |||
| 749 | request_modules(dev); | 744 | request_modules(dev); |
| 750 | return 0; | 745 | return 0; |
| 751 | 746 | ||
| 752 | fail_free: | ||
| 753 | vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | ||
| 754 | fail_dev: | 747 | fail_dev: |
| 755 | kfree(dev); | 748 | kfree(dev); |
| 756 | fail_core: | 749 | fail_core: |
| @@ -798,7 +791,6 @@ static void cx8802_remove(struct pci_dev *pci_dev) · 41 unmodified lines | |||
| 798 | /* common */ | 791 | /* common */ |
| 799 | cx8802_fini_common(dev); | 792 | cx8802_fini_common(dev); |
| 800 | cx88_core_put(dev->core,dev->pci); | 793 | cx88_core_put(dev->core,dev->pci); |
| 801 | vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | ||
| 802 | kfree(dev); | 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 | static int queue_setup(struct vb2_queue *q, | 110 | static int queue_setup(struct vb2_queue *q, |
| 111 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct cx8800_dev *dev = q->drv_priv; | 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 | sizes[0] = VBI_LINE_NTSC_COUNT * VBI_LINE_LENGTH * 2; | 118 | sizes[0] = VBI_LINE_NTSC_COUNT * VBI_LINE_LENGTH * 2; |
| 119 | else | 119 | else |
| 120 | sizes[0] = VBI_LINE_PAL_COUNT * VBI_LINE_LENGTH * 2; | 120 | sizes[0] = VBI_LINE_PAL_COUNT * VBI_LINE_LENGTH * 2; |
| 121 | alloc_ctxs[0] = dev->alloc_ctx; | ||
| 122 | return 0; | 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 | static int queue_setup(struct vb2_queue *q, | 432 | static int queue_setup(struct vb2_queue *q, |
| 433 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct cx8800_dev *dev = q->drv_priv; | 436 | struct cx8800_dev *dev = q->drv_priv; |
| 437 | struct cx88_core *core = dev->core; | 437 | struct cx88_core *core = dev->core; |
| 438 | 438 | ||
| 439 | *num_planes = 1; | 439 | *num_planes = 1; |
| 440 | sizes[0] = (dev->fmt->depth * core->width * core->height) >> 3; | 440 | sizes[0] = (dev->fmt->depth * core->width * core->height) >> 3; |
| 441 | alloc_ctxs[0] = dev->alloc_ctx; | ||
| 442 | return 0; | 441 | return 0; |
| 443 | } | 442 | } |
| 444 | 443 | ||
| @@ -1319,12 +1318,6 @@ static int cx8800_initdev(struct pci_dev *pci_dev, · 874 unmodified lines | |||
| 1319 | printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); | 1318 | printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); |
| 1320 | goto fail_core; | 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 | /* initialize driver struct */ | 1322 | /* initialize driver struct */ |
| 1330 | spin_lock_init(&dev->slock); | 1323 | spin_lock_init(&dev->slock); |
| @@ -1445,6 +1438,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, · 114 unmodified lines | |||
| 1445 | q->mem_ops = &vb2_dma_sg_memops; | 1438 | q->mem_ops = &vb2_dma_sg_memops; |
| 1446 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1439 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1447 | q->lock = &core->lock; | 1440 | q->lock = &core->lock; |
| 1441 | q->dev = &dev->pci->dev; | ||
| 1448 | 1442 | ||
| 1449 | err = vb2_queue_init(q); | 1443 | err = vb2_queue_init(q); |
| 1450 | if (err < 0) | 1444 | if (err < 0) |
| @@ -1461,6 +1455,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, · 10 unmodified lines | |||
| 1461 | q->mem_ops = &vb2_dma_sg_memops; | 1455 | q->mem_ops = &vb2_dma_sg_memops; |
| 1462 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1456 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1463 | q->lock = &core->lock; | 1457 | q->lock = &core->lock; |
| 1458 | q->dev = &dev->pci->dev; | ||
| 1464 | 1459 | ||
| 1465 | err = vb2_queue_init(q); | 1460 | err = vb2_queue_init(q); |
| 1466 | if (err < 0) | 1461 | if (err < 0) |
| @@ -1530,7 +1525,6 @@ fail_unreg: · 63 unmodified lines | |||
| 1530 | free_irq(pci_dev->irq, dev); | 1525 | free_irq(pci_dev->irq, dev); |
| 1531 | mutex_unlock(&core->lock); | 1526 | mutex_unlock(&core->lock); |
| 1532 | fail_core: | 1527 | fail_core: |
| 1533 | vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | ||
| 1534 | core->v4ldev = NULL; | 1528 | core->v4ldev = NULL; |
| 1535 | cx88_core_put(core,dev->pci); | 1529 | cx88_core_put(core,dev->pci); |
| 1536 | fail_free: | 1530 | fail_free: |
| @@ -1564,7 +1558,6 @@ static void cx8800_finidev(struct pci_dev *pci_dev) · 27 unmodified lines | |||
| 1564 | 1558 | ||
| 1565 | /* free memory */ | 1559 | /* free memory */ |
| 1566 | cx88_core_put(core,dev->pci); | 1560 | cx88_core_put(core,dev->pci); |
| 1567 | vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | ||
| 1568 | kfree(dev); | 1561 | kfree(dev); |
| 1569 | } | 1562 | } |
| 1570 | 1563 | ||
| @@ -485,7 +485,6 @@ struct cx8800_dev { · 484 unmodified lines | |||
| 485 | /* pci i/o */ | 485 | /* pci i/o */ |
| 486 | struct pci_dev *pci; | 486 | struct pci_dev *pci; |
| 487 | unsigned char pci_rev,pci_lat; | 487 | unsigned char pci_rev,pci_lat; |
| 488 | void *alloc_ctx; | ||
| 489 | 488 | ||
| 490 | const struct cx8800_fmt *fmt; | 489 | const struct cx8800_fmt *fmt; |
| 491 | 490 | ||
| @@ -549,7 +548,6 @@ struct cx8802_dev { · 57 unmodified lines | |||
| 549 | /* pci i/o */ | 548 | /* pci i/o */ |
| 550 | struct pci_dev *pci; | 549 | struct pci_dev *pci; |
| 551 | unsigned char pci_rev,pci_lat; | 550 | unsigned char pci_rev,pci_lat; |
| 552 | void *alloc_ctx; | ||
| 553 | 551 | ||
| 554 | /* dma queues */ | 552 | /* dma queues */ |
| 555 | struct cx88_dmaqueue mpegq; | 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 | if (pci_enable_device(pdev) < 0) | 1569 | if (pci_enable_device(pdev) < 0) |
| 1570 | return -ENODEV; | 1570 | return -ENODEV; |
| 1571 | 1571 | ||
| 1572 | dev = vmalloc(sizeof(struct ddb)); | 1572 | dev = vzalloc(sizeof(struct ddb)); |
| 1573 | if (dev == NULL) | 1573 | if (dev == NULL) |
| 1574 | return -ENOMEM; | 1574 | return -ENOMEM; |
| 1575 | memset(dev, 0, sizeof(struct ddb)); | ||
| 1576 | 1575 | ||
| 1577 | dev->pdev = pdev; | 1576 | dev->pdev = pdev; |
| 1578 | pci_set_drvdata(pdev, dev); | 1577 | pci_set_drvdata(pdev, dev); |
| @@ -133,7 +133,7 @@ static int wait_i2c_reg(void __iomem *addr) · 132 unmodified lines | |||
| 133 | static int | 133 | static int |
| 134 | dt3155_queue_setup(struct vb2_queue *vq, | 134 | dt3155_queue_setup(struct vb2_queue *vq, |
| 135 | unsigned int *nbuffers, unsigned int *num_planes, | 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 | struct dt3155_priv *pd = vb2_get_drv_priv(vq); | 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 | if (vq->num_buffers + *nbuffers < 2) | 142 | if (vq->num_buffers + *nbuffers < 2) |
| 143 | *nbuffers = 2 - vq->num_buffers; | 143 | *nbuffers = 2 - vq->num_buffers; |
| 144 | alloc_ctxs[0] = pd->alloc_ctx; | ||
| 145 | if (*num_planes) | 144 | if (*num_planes) |
| 146 | return sizes[0] < size ? -EINVAL : 0; | 145 | return sizes[0] < size ? -EINVAL : 0; |
| 147 | *num_planes = 1; | 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 | pd->vidq.min_buffers_needed = 2; | 543 | pd->vidq.min_buffers_needed = 2; |
| 545 | pd->vidq.gfp_flags = GFP_DMA32; | 544 | pd->vidq.gfp_flags = GFP_DMA32; |
| 546 | pd->vidq.lock = &pd->mux; /* for locking v4l2_file_operations */ | 545 | pd->vidq.lock = &pd->mux; /* for locking v4l2_file_operations */ |
| 546 | pd->vidq.dev = &pdev->dev; | ||
| 547 | pd->vdev.queue = &pd->vidq; | 547 | pd->vdev.queue = &pd->vidq; |
| 548 | err = vb2_queue_init(&pd->vidq); | 548 | err = vb2_queue_init(&pd->vidq); |
| 549 | if (err < 0) | 549 | if (err < 0) |
| 550 | goto err_v4l2_dev_unreg; | 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 | spin_lock_init(&pd->lock); | 551 | spin_lock_init(&pd->lock); |
| 558 | pd->config = ACQ_MODE_EVEN; | 552 | pd->config = ACQ_MODE_EVEN; |
| 559 | err = pci_enable_device(pdev); | 553 | err = pci_enable_device(pdev); |
| 560 | if (err) | 554 | if (err) |
| 561 | goto err_free_ctx; | 555 | goto err_v4l2_dev_unreg; |
| 562 | err = pci_request_region(pdev, 0, pci_name(pdev)); | 556 | err = pci_request_region(pdev, 0, pci_name(pdev)); |
| 563 | if (err) | 557 | if (err) |
| 564 | goto err_pci_disable; | 558 | goto err_pci_disable; |
| @@ -588,8 +582,6 @@ err_free_reg: · 23 unmodified lines | |||
| 588 | pci_release_region(pdev, 0); | 582 | pci_release_region(pdev, 0); |
| 589 | err_pci_disable: | 583 | err_pci_disable: |
| 590 | pci_disable_device(pdev); | 584 | pci_disable_device(pdev); |
| 591 | err_free_ctx: | ||
| 592 | vb2_dma_contig_cleanup_ctx(pd->alloc_ctx); | ||
| 593 | err_v4l2_dev_unreg: | 585 | err_v4l2_dev_unreg: |
| 594 | v4l2_device_unregister(&pd->v4l2_dev); | 586 | v4l2_device_unregister(&pd->v4l2_dev); |
| 595 | return err; | 587 | return err; |
| @@ -608,7 +600,6 @@ static void dt3155_remove(struct pci_dev *pdev) · 12 unmodified lines | |||
| 608 | pci_iounmap(pdev, pd->regs); | 600 | pci_iounmap(pdev, pd->regs); |
| 609 | pci_release_region(pdev, 0); | 601 | pci_release_region(pdev, 0); |
| 610 | pci_disable_device(pdev); | 602 | pci_disable_device(pdev); |
| 611 | vb2_dma_contig_cleanup_ctx(pd->alloc_ctx); | ||
| 612 | } | 603 | } |
| 613 | 604 | ||
| 614 | static const struct pci_device_id pci_ids[] = { | 605 | static const struct pci_device_id pci_ids[] = { |
| @@ -161,7 +161,6 @@ · 160 unmodified lines | |||
| 161 | * @vdev: video_device structure | 161 | * @vdev: video_device structure |
| 162 | * @pdev: pointer to pci_dev structure | 162 | * @pdev: pointer to pci_dev structure |
| 163 | * @vidq: vb2_queue structure | 163 | * @vidq: vb2_queue structure |
| 164 | * @alloc_ctx: dma_contig allocation context | ||
| 165 | * @curr_buf: pointer to curren buffer | 164 | * @curr_buf: pointer to curren buffer |
| 166 | * @mux: mutex to protect the instance | 165 | * @mux: mutex to protect the instance |
| 167 | * @dmaq: queue for dma buffers | 166 | * @dmaq: queue for dma buffers |
| @@ -181,7 +180,6 @@ struct dt3155_priv { · 13 unmodified lines | |||
| 181 | struct video_device vdev; | 180 | struct video_device vdev; |
| 182 | struct pci_dev *pdev; | 181 | struct pci_dev *pdev; |
| 183 | struct vb2_queue vidq; | 182 | struct vb2_queue vidq; |
| 184 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 185 | struct vb2_v4l2_buffer *curr_buf; | 183 | struct vb2_v4l2_buffer *curr_buf; |
| 186 | struct mutex mux; | 184 | struct mutex mux; |
| 187 | struct list_head dmaq; | 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 | vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]); | 93 | vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]); |
| 94 | 94 | ||
| 95 | snd_ivtv_lock(itvsc); | 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 | snd_ivtv_unlock(itvsc); | 97 | snd_ivtv_unlock(itvsc); |
| 98 | 98 | ||
| 99 | if (!ret) | 99 | if (!ret) |
| @@ -115,14 +115,14 @@ static int snd_ivtv_mixer_tv_vol_put(struct snd_kcontrol *kctl, · 15 unmodified lines | |||
| 115 | snd_ivtv_lock(itvsc); | 115 | snd_ivtv_lock(itvsc); |
| 116 | 116 | ||
| 117 | /* Fetch current state */ | 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 | if (ret || | 120 | if (ret || |
| 121 | (cx25840_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { | 121 | (cx25840_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { |
| 122 | 122 | ||
| 123 | /* Set, if needed */ | 123 | /* Set, if needed */ |
| 124 | vctrl.value = dB_to_cx25840_vol(uctl->value.integer.value[0]); | 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 | if (!ret) | 126 | if (!ret) |
| 127 | ret = 1; /* Indicate control was changed w/o error */ | 127 | ret = 1; /* Indicate control was changed w/o error */ |
| 128 | } | 128 | } |
| @@ -5,8 +5,13 @@ config DVB_NETUP_UNIDVB · 4 unmodified lines | |||
| 5 | select VIDEOBUF2_VMALLOC | 5 | select VIDEOBUF2_VMALLOC |
| 6 | select DVB_HORUS3A if MEDIA_SUBDRV_AUTOSELECT | 6 | select DVB_HORUS3A if MEDIA_SUBDRV_AUTOSELECT |
| 7 | select DVB_ASCOT2E if MEDIA_SUBDRV_AUTOSELECT | 7 | select DVB_ASCOT2E if MEDIA_SUBDRV_AUTOSELECT |
| 8 | select DVB_HELENE if MEDIA_SUBDRV_AUTOSELECT | ||
| 8 | select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT | 9 | select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT |
| 9 | select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT | 10 | select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT |
| 10 | ---help--- | 11 | ---help--- |
| 11 | Support for NetUP PCI express Universal DVB card. | 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 | #define NETUP_UNIDVB_IRQ_CAM0 (1 << 11) | 50 | #define NETUP_UNIDVB_IRQ_CAM0 (1 << 11) |
| 51 | #define NETUP_UNIDVB_IRQ_CAM1 (1 << 12) | 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 | struct netup_dma { | 62 | struct netup_dma { |
| 54 | u8 num; | 63 | u8 num; |
| 55 | spinlock_t lock; | 64 | spinlock_t lock; |
| @@ -119,6 +128,7 @@ struct netup_unidvb_dev { · 63 unmodified lines | |||
| 119 | struct netup_dma dma[2]; | 128 | struct netup_dma dma[2]; |
| 120 | struct netup_ci_state ci[2]; | 129 | struct netup_ci_state ci[2]; |
| 121 | struct netup_spi *spi; | 130 | struct netup_spi *spi; |
| 131 | enum netup_hw_rev rev; | ||
| 122 | }; | 132 | }; |
| 123 | 133 | ||
| 124 | int netup_i2c_register(struct netup_unidvb_dev *ndev); | 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 | struct netup_ci_state *state = en50221->data; | 148 | struct netup_ci_state *state = en50221->data; |
| 149 | struct netup_unidvb_dev *dev = state->dev; | 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 | dev_dbg(&dev->pci_dev->dev, | 152 | dev_dbg(&dev->pci_dev->dev, |
| 153 | "%s(): addr=0x%x val=0x%x\n", __func__, addr, val); | 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 | dev_dbg(&dev->pci_dev->dev, | 163 | dev_dbg(&dev->pci_dev->dev, |
| 164 | "%s(): addr=0x%x data=0x%x\n", __func__, addr, data); | 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 | return 0; | 166 | return 0; |
| 167 | } | 167 | } |
| 168 | 168 | ||
| @@ -34,6 +34,7 @@ · 33 unmodified lines | |||
| 34 | #include "cxd2841er.h" | 34 | #include "cxd2841er.h" |
| 35 | #include "horus3a.h" | 35 | #include "horus3a.h" |
| 36 | #include "ascot2e.h" | 36 | #include "ascot2e.h" |
| 37 | #include "helene.h" | ||
| 37 | #include "lnbh25.h" | 38 | #include "lnbh25.h" |
| 38 | 39 | ||
| 39 | static int spi_enable; | 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 | static void netup_unidvb_queue_cleanup(struct netup_dma *dma); | 121 | static void netup_unidvb_queue_cleanup(struct netup_dma *dma); |
| 121 | 122 | ||
| 122 | static struct cxd2841er_config demod_config = { | 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 | static struct horus3a_config horus3a_conf = { | 128 | static struct horus3a_config horus3a_conf = { |
| @@ -134,6 +136,12 @@ static struct ascot2e_config ascot2e_conf = { · 7 unmodified lines | |||
| 134 | .set_tuner_callback = netup_unidvb_tuner_ctrl | 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 | static struct lnbh25_config lnbh25_conf = { | 145 | static struct lnbh25_config lnbh25_conf = { |
| 138 | .i2c_address = 0x10, | 146 | .i2c_address = 0x10, |
| 139 | .data2_config = LNBH25_TEN | LNBH25_EXTM | 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 | __func__, dma->num, is_dvb_tc); | 160 | __func__, dma->num, is_dvb_tc); |
| 153 | reg = readb(ndev->bmmio0 + GPIO_REG_IO); | 161 | reg = readb(ndev->bmmio0 + GPIO_REG_IO); |
| 154 | mask = (dma->num == 0) ? GPIO_RFA_CTL : GPIO_RFB_CTL; | 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 | if (!is_dvb_tc) | 168 | if (!is_dvb_tc) |
| 156 | reg |= mask; | 169 | reg |= mask; |
| 157 | else | 170 | else |
| @@ -280,7 +293,7 @@ static int netup_unidvb_queue_setup(struct vb2_queue *vq, · 122 unmodified lines | |||
| 280 | unsigned int *nbuffers, | 293 | unsigned int *nbuffers, |
| 281 | unsigned int *nplanes, | 294 | unsigned int *nplanes, |
| 282 | unsigned int sizes[], | 295 | unsigned int sizes[], |
| 283 | void *alloc_ctxs[]) | 296 | struct device *alloc_devs[]) |
| 284 | { | 297 | { |
| 285 | struct netup_dma *dma = vb2_get_drv_priv(vq); | 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 | static int netup_unidvb_dvb_init(struct netup_unidvb_dev *ndev, | 385 | static int netup_unidvb_dvb_init(struct netup_unidvb_dev *ndev, |
| 373 | int num) | 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 | if (num < 0 || num > 1) { | 398 | if (num < 0 || num > 1) { |
| 378 | dev_dbg(&ndev->pci_dev->dev, | 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 | mutex_init(&ndev->frontends[num].lock); | 403 | mutex_init(&ndev->frontends[num].lock); |
| 383 | INIT_LIST_HEAD(&ndev->frontends[num].felist); | 404 | INIT_LIST_HEAD(&ndev->frontends[num].felist); |
| 384 | if (vb2_dvb_alloc_frontend(&ndev->frontends[num], 1) == NULL || | 405 | |
| 385 | vb2_dvb_alloc_frontend( | 406 | for (i = 0; i < fe_count; i++) { |
| 386 | &ndev->frontends[num], 2) == NULL || | 407 | if (vb2_dvb_alloc_frontend(&ndev->frontends[num], i+1) |
| 387 | vb2_dvb_alloc_frontend( | 408 | == NULL) { |
| 388 | &ndev->frontends[num], 3) == NULL) { | 409 | dev_err(&ndev->pci_dev->dev, |
| 389 | dev_dbg(&ndev->pci_dev->dev, | 410 | "%s(): unable to allocate vb2_dvb_frontend\n", |
| 390 | "%s(): unable to allocate vb2_dvb_frontend\n", | 411 | __func__); |
| 391 | __func__); | 412 | return -ENOMEM; |
| 392 | return -ENOMEM; | 413 | } |
| 393 | } | 414 | } |
| 394 | fe0 = vb2_dvb_get_frontend(&ndev->frontends[num], 1); | 415 | |
| 395 | fe1 = vb2_dvb_get_frontend(&ndev->frontends[num], 2); | 416 | for (i = 0; i < fe_count; i++) { |
| 396 | fe2 = vb2_dvb_get_frontend(&ndev->frontends[num], 3); | 417 | fes[i] = vb2_dvb_get_frontend(&ndev->frontends[num], i+1); |
| 397 | if (fe0 == NULL || fe1 == NULL || fe2 == NULL) { | 418 | if (fes[i] == NULL) { |
| 398 | dev_dbg(&ndev->pci_dev->dev, | 419 | dev_err(&ndev->pci_dev->dev, |
| 399 | "%s(): frontends has not been allocated\n", __func__); | 420 | "%s(): frontends has not been allocated\n", |
| 400 | return -EINVAL; | 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); | 431 | |
| 403 | netup_unidvb_queue_init(&ndev->dma[num], &fe1->dvb.dvbq); | 432 | fes[0]->dvb.frontend = dvb_attach(cxd2841er_attach_s, |
| 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, | ||
| 409 | &demod_config, &ndev->i2c[num].adap); | 433 | &demod_config, &ndev->i2c[num].adap); |
| 410 | if (fe0->dvb.frontend == NULL) { | 434 | if (fes[0]->dvb.frontend == NULL) { |
| 411 | dev_dbg(&ndev->pci_dev->dev, | 435 | dev_dbg(&ndev->pci_dev->dev, |
| 412 | "%s(): unable to attach DVB-S/S2 frontend\n", | 436 | "%s(): unable to attach DVB-S/S2 frontend\n", |
| 413 | __func__); | 437 | __func__); |
| 414 | goto frontend_detach; | 438 | goto frontend_detach; |
| 415 | } | 439 | } |
| 416 | horus3a_conf.set_tuner_priv = &ndev->dma[num]; | 440 | |
| 417 | if (!dvb_attach(horus3a_attach, fe0->dvb.frontend, | 441 | if (ndev->rev == NETUP_HW_REV_1_3) { |
| 418 | &horus3a_conf, &ndev->i2c[num].adap)) { | 442 | horus3a_conf.set_tuner_priv = &ndev->dma[num]; |
| 419 | dev_dbg(&ndev->pci_dev->dev, | 443 | if (!dvb_attach(horus3a_attach, fes[0]->dvb.frontend, |
| 420 | "%s(): unable to attach DVB-S/S2 tuner frontend\n", | 444 | &horus3a_conf, &ndev->i2c[num].adap)) { |
| 421 | __func__); | 445 | dev_dbg(&ndev->pci_dev->dev, |
| 422 | goto frontend_detach; | 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 | &lnbh25_conf, &ndev->i2c[num].adap)) { | 462 | &lnbh25_conf, &ndev->i2c[num].adap)) { |
| 426 | dev_dbg(&ndev->pci_dev->dev, | 463 | dev_dbg(&ndev->pci_dev->dev, |
| 427 | "%s(): unable to attach SEC frontend\n", __func__); | 464 | "%s(): unable to attach SEC frontend\n", __func__); |
| 428 | goto frontend_detach; | 465 | goto frontend_detach; |
| 429 | } | 466 | } |
| 467 | |||
| 430 | /* DVB-T/T2 frontend */ | 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 | &demod_config, &ndev->i2c[num].adap); | 470 | &demod_config, &ndev->i2c[num].adap); |
| 433 | if (fe1->dvb.frontend == NULL) { | 471 | if (fes[1]->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) { | ||
| 451 | dev_dbg(&ndev->pci_dev->dev, | 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 | goto frontend_detach; | 474 | goto frontend_detach; |
| 454 | } | 475 | } |
| 455 | fe2->dvb.frontend->id = 2; | 476 | fes[1]->dvb.frontend->id = 1; |
| 456 | if (!dvb_attach(ascot2e_attach, fe2->dvb.frontend, | 477 | if (ndev->rev == NETUP_HW_REV_1_3) { |
| 457 | &ascot2e_conf, &ndev->i2c[num].adap)) { | 478 | ascot2e_conf.set_tuner_priv = &ndev->dma[num]; |
| 458 | dev_dbg(&ndev->pci_dev->dev, | 479 | if (!dvb_attach(ascot2e_attach, fes[1]->dvb.frontend, |
| 459 | "%s(): unable to attach DVB-T/C tuner frontend\n", | 480 | &ascot2e_conf, &ndev->i2c[num].adap)) { |
| 460 | __func__); | 481 | dev_dbg(&ndev->pci_dev->dev, |
| 461 | goto frontend_detach; | 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 | if (vb2_dvb_register_bus(&ndev->frontends[num], | 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 | static int netup_unidvb_request_modules(struct device *dev) | 763 | static int netup_unidvb_request_modules(struct device *dev) |
| 731 | { | 764 | { |
| 732 | static const char * const modules[] = { | 765 | static const char * const modules[] = { |
| 733 | "lnbh25", "ascot2e", "horus3a", "cxd2841er", NULL | 766 | "lnbh25", "ascot2e", "horus3a", "cxd2841er", "helene", NULL |
| 734 | }; | 767 | }; |
| 735 | const char * const *curr_mod = modules; | 768 | const char * const *curr_mod = modules; |
| 736 | int err; | 769 | int err; |
| @@ -774,6 +807,16 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev, · 37 unmodified lines | |||
| 774 | if (!ndev) | 807 | if (!ndev) |
| 775 | goto dev_alloc_err; | 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 | ndev->old_fw = old_firmware; | 820 | ndev->old_fw = old_firmware; |
| 778 | ndev->wq = create_singlethread_workqueue(NETUP_UNIDVB_NAME); | 821 | ndev->wq = create_singlethread_workqueue(NETUP_UNIDVB_NAME); |
| 779 | if (!ndev->wq) { | 822 | if (!ndev->wq) { |
| @@ -932,7 +975,7 @@ wq_create_err: · 152 unmodified lines | |||
| 932 | kfree(ndev); | 975 | kfree(ndev); |
| 933 | dev_alloc_err: | 976 | dev_alloc_err: |
| 934 | dev_err(&pci_dev->dev, | 977 | dev_err(&pci_dev->dev, |
| 935 | "%s(): failed to initizalize device\n", __func__); | 978 | "%s(): failed to initialize device\n", __func__); |
| 936 | return -EIO; | 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 | static struct pci_device_id netup_unidvb_pci_tbl[] = { | 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 | { 0, } | 1020 | { 0, } |
| 977 | }; | 1021 | }; |
| 978 | MODULE_DEVICE_TABLE(pci, netup_unidvb_pci_tbl); | 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 | saa7134_board_init1(dev); | 1164 | saa7134_board_init1(dev); |
| 1165 | saa7134_hwinit1(dev); | 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 | /* get irq */ | 1167 | /* get irq */ |
| 1173 | err = request_irq(pci_dev->irq, saa7134_irq, | 1168 | err = request_irq(pci_dev->irq, saa7134_irq, |
| 1174 | IRQF_SHARED, dev->name, dev); | 1169 | IRQF_SHARED, dev->name, dev); |
| 1175 | if (err < 0) { | 1170 | if (err < 0) { |
| 1176 | pr_err("%s: can't get IRQ %d\n", | 1171 | pr_err("%s: can't get IRQ %d\n", |
| 1177 | dev->name,pci_dev->irq); | 1172 | dev->name,pci_dev->irq); |
| 1178 | goto fail4; | 1173 | goto fail3; |
| 1179 | } | 1174 | } |
| 1180 | 1175 | ||
| 1181 | /* wait a bit, register i2c bus */ | 1176 | /* wait a bit, register i2c bus */ |
| @@ -1233,7 +1228,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, · 51 unmodified lines | |||
| 1233 | if (err < 0) { | 1228 | if (err < 0) { |
| 1234 | pr_info("%s: can't register video device\n", | 1229 | pr_info("%s: can't register video device\n", |
| 1235 | dev->name); | 1230 | dev->name); |
| 1236 | goto fail5; | 1231 | goto fail4; |
| 1237 | } | 1232 | } |
| 1238 | pr_info("%s: registered device %s [v4l2]\n", | 1233 | pr_info("%s: registered device %s [v4l2]\n", |
| 1239 | dev->name, video_device_node_name(dev->video_dev)); | 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 | err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, | 1241 | err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, |
| 1247 | vbi_nr[dev->nr]); | 1242 | vbi_nr[dev->nr]); |
| 1248 | if (err < 0) | 1243 | if (err < 0) |
| 1249 | goto fail5; | 1244 | goto fail4; |
| 1250 | pr_info("%s: registered device %s\n", | 1245 | pr_info("%s: registered device %s\n", |
| 1251 | dev->name, video_device_node_name(dev->vbi_dev)); | 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 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, | 1252 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, |
| 1258 | radio_nr[dev->nr]); | 1253 | radio_nr[dev->nr]); |
| 1259 | if (err < 0) | 1254 | if (err < 0) |
| 1260 | goto fail5; | 1255 | goto fail4; |
| 1261 | pr_info("%s: registered device %s\n", | 1256 | pr_info("%s: registered device %s\n", |
| 1262 | dev->name, video_device_node_name(dev->radio_dev)); | 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 | err = v4l2_mc_create_media_graph(dev->media_dev); | 1263 | err = v4l2_mc_create_media_graph(dev->media_dev); |
| 1269 | if (err) { | 1264 | if (err) { |
| 1270 | pr_err("failed to create media graph\n"); | 1265 | pr_err("failed to create media graph\n"); |
| 1271 | goto fail5; | 1266 | goto fail4; |
| 1272 | } | 1267 | } |
| 1273 | #endif | 1268 | #endif |
| 1274 | /* everything worked */ | 1269 | /* everything worked */ |
| @@ -1287,17 +1282,15 @@ static int saa7134_initdev(struct pci_dev *pci_dev, · 12 unmodified lines | |||
| 1287 | #ifdef CONFIG_MEDIA_CONTROLLER | 1282 | #ifdef CONFIG_MEDIA_CONTROLLER |
| 1288 | err = media_device_register(dev->media_dev); | 1283 | err = media_device_register(dev->media_dev); |
| 1289 | if (err) | 1284 | if (err) |
| 1290 | goto fail5; | 1285 | goto fail4; |
| 1291 | #endif | 1286 | #endif |
| 1292 | 1287 | ||
| 1293 | return 0; | 1288 | return 0; |
| 1294 | 1289 | ||
| 1295 | fail5: | 1290 | fail4: |
| 1296 | saa7134_unregister_video(dev); | 1291 | saa7134_unregister_video(dev); |
| 1297 | saa7134_i2c_unregister(dev); | 1292 | saa7134_i2c_unregister(dev); |
| 1298 | free_irq(pci_dev->irq, dev); | 1293 | free_irq(pci_dev->irq, dev); |
| 1299 | fail4: | ||
| 1300 | vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | ||
| 1301 | fail3: | 1294 | fail3: |
| 1302 | saa7134_hwfini(dev); | 1295 | saa7134_hwfini(dev); |
| 1303 | iounmap(dev->lmmio); | 1296 | iounmap(dev->lmmio); |
| @@ -1367,7 +1360,6 @@ static void saa7134_finidev(struct pci_dev *pci_dev) · 63 unmodified lines | |||
| 1367 | 1360 | ||
| 1368 | /* release resources */ | 1361 | /* release resources */ |
| 1369 | free_irq(pci_dev->irq, dev); | 1362 | free_irq(pci_dev->irq, dev); |
| 1370 | vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | ||
| 1371 | iounmap(dev->lmmio); | 1363 | iounmap(dev->lmmio); |
| 1372 | release_mem_region(pci_resource_start(pci_dev,0), | 1364 | release_mem_region(pci_resource_start(pci_dev,0), |
| 1373 | pci_resource_len(pci_dev,0)); | 1365 | pci_resource_len(pci_dev,0)); |
| @@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(saa7134_ts_buffer_prepare); · 117 unmodified lines | |||
| 118 | 118 | ||
| 119 | int saa7134_ts_queue_setup(struct vb2_queue *q, | 119 | int saa7134_ts_queue_setup(struct vb2_queue *q, |
| 120 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | struct saa7134_dmaqueue *dmaq = q->drv_priv; | 123 | struct saa7134_dmaqueue *dmaq = q->drv_priv; |
| 124 | struct saa7134_dev *dev = dmaq->dev; | 124 | struct saa7134_dev *dev = dmaq->dev; |
| @@ -131,7 +131,6 @@ int saa7134_ts_queue_setup(struct vb2_queue *q, · 6 unmodified lines | |||
| 131 | *nbuffers = 3; | 131 | *nbuffers = 3; |
| 132 | *nplanes = 1; | 132 | *nplanes = 1; |
| 133 | sizes[0] = size; | 133 | sizes[0] = size; |
| 134 | alloc_ctxs[0] = dev->alloc_ctx; | ||
| 135 | return 0; | 134 | return 0; |
| 136 | } | 135 | } |
| 137 | EXPORT_SYMBOL_GPL(saa7134_ts_queue_setup); | 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 | static int queue_setup(struct vb2_queue *q, | 141 | static int queue_setup(struct vb2_queue *q, |
| 142 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | struct saa7134_dmaqueue *dmaq = q->drv_priv; | 145 | struct saa7134_dmaqueue *dmaq = q->drv_priv; |
| 146 | struct saa7134_dev *dev = dmaq->dev; | 146 | struct saa7134_dev *dev = dmaq->dev; |
| @@ -155,7 +155,6 @@ static int queue_setup(struct vb2_queue *q, · 8 unmodified lines | |||
| 155 | *nbuffers = saa7134_buffer_count(size, *nbuffers); | 155 | *nbuffers = saa7134_buffer_count(size, *nbuffers); |
| 156 | *nplanes = 1; | 156 | *nplanes = 1; |
| 157 | sizes[0] = size; | 157 | sizes[0] = size; |
| 158 | alloc_ctxs[0] = dev->alloc_ctx; | ||
| 159 | return 0; | 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 | static int queue_setup(struct vb2_queue *q, | 964 | static int queue_setup(struct vb2_queue *q, |
| 965 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | struct saa7134_dmaqueue *dmaq = q->drv_priv; | 968 | struct saa7134_dmaqueue *dmaq = q->drv_priv; |
| 969 | struct saa7134_dev *dev = dmaq->dev; | 969 | struct saa7134_dev *dev = dmaq->dev; |
| @@ -980,7 +980,6 @@ static int queue_setup(struct vb2_queue *q, · 10 unmodified lines | |||
| 980 | *nbuffers = saa7134_buffer_count(size, *nbuffers); | 980 | *nbuffers = saa7134_buffer_count(size, *nbuffers); |
| 981 | *nplanes = 1; | 981 | *nplanes = 1; |
| 982 | sizes[0] = size; | 982 | sizes[0] = size; |
| 983 | alloc_ctxs[0] = dev->alloc_ctx; | ||
| 984 | 983 | ||
| 985 | saa7134_enable_analog_tuner(dev); | 984 | saa7134_enable_analog_tuner(dev); |
| 986 | 985 | ||
| @@ -2173,6 +2172,7 @@ int saa7134_video_init1(struct saa7134_dev *dev) · 1186 unmodified lines | |||
| 2173 | q->buf_struct_size = sizeof(struct saa7134_buf); | 2172 | q->buf_struct_size = sizeof(struct saa7134_buf); |
| 2174 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 2173 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 2175 | q->lock = &dev->lock; | 2174 | q->lock = &dev->lock; |
| 2175 | q->dev = &dev->pci->dev; | ||
| 2176 | ret = vb2_queue_init(q); | 2176 | ret = vb2_queue_init(q); |
| 2177 | if (ret) | 2177 | if (ret) |
| 2178 | return ret; | 2178 | return ret; |
| @@ -2191,6 +2191,7 @@ int saa7134_video_init1(struct saa7134_dev *dev) · 12 unmodified lines | |||
| 2191 | q->buf_struct_size = sizeof(struct saa7134_buf); | 2191 | q->buf_struct_size = sizeof(struct saa7134_buf); |
| 2192 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 2192 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 2193 | q->lock = &dev->lock; | 2193 | q->lock = &dev->lock; |
| 2194 | q->dev = &dev->pci->dev; | ||
| 2194 | ret = vb2_queue_init(q); | 2195 | ret = vb2_queue_init(q); |
| 2195 | if (ret) | 2196 | if (ret) |
| 2196 | return ret; | 2197 | return ret; |
| @@ -610,7 +610,6 @@ struct saa7134_dev { · 609 unmodified lines | |||
| 610 | 610 | ||
| 611 | 611 | ||
| 612 | /* video+ts+vbi capture */ | 612 | /* video+ts+vbi capture */ |
| 613 | void *alloc_ctx; | ||
| 614 | struct saa7134_dmaqueue video_q; | 613 | struct saa7134_dmaqueue video_q; |
| 615 | struct vb2_queue video_vbq; | 614 | struct vb2_queue video_vbq; |
| 616 | struct saa7134_dmaqueue vbi_q; | 615 | struct saa7134_dmaqueue vbi_q; |
| @@ -854,7 +853,7 @@ int saa7134_ts_buffer_init(struct vb2_buffer *vb2); · 237 unmodified lines | |||
| 854 | int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2); | 853 | int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2); |
| 855 | int saa7134_ts_queue_setup(struct vb2_queue *q, | 854 | int saa7134_ts_queue_setup(struct vb2_queue *q, |
| 856 | unsigned int *nbuffers, unsigned int *nplanes, | 855 | unsigned int *nbuffers, unsigned int *nplanes, |
| 857 | unsigned int sizes[], void *alloc_ctxs[]); | 856 | unsigned int sizes[], struct device *alloc_devs[]); |
| 858 | int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count); | 857 | int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count); |
| 859 | void saa7134_ts_stop_streaming(struct vb2_queue *vq); | 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 | dprintk(DBGLVL_ENC, "%s()\n", __func__); | 1023 | dprintk(DBGLVL_ENC, "%s()\n", __func__); |
| 1024 | 1024 | ||
| 1025 | if (port->type != SAA7164_MPEG_ENCODER) | 1025 | BUG_ON(port->type != SAA7164_MPEG_ENCODER); |
| 1026 | BUG(); | ||
| 1027 | 1026 | ||
| 1028 | /* Sanity check that the PCI configuration space is active */ | 1027 | /* Sanity check that the PCI configuration space is active */ |
| 1029 | if (port->hwcfg.BARLocation == 0) { | 1028 | if (port->hwcfg.BARLocation == 0) { |
| @@ -1151,8 +1150,7 @@ void saa7164_encoder_unregister(struct saa7164_port *port) · 121 unmodified lines | |||
| 1151 | 1150 | ||
| 1152 | dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr); | 1151 | dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr); |
| 1153 | 1152 | ||
| 1154 | if (port->type != SAA7164_MPEG_ENCODER) | 1153 | BUG_ON(port->type != SAA7164_MPEG_ENCODER); |
| 1155 | BUG(); | ||
| 1156 | 1154 | ||
| 1157 | if (port->v4l_device) { | 1155 | if (port->v4l_device) { |
| 1158 | if (port->v4l_device->minor != -1) | 1156 | if (port->v4l_device->minor != -1) |
| @@ -263,10 +263,6 @@ struct saa7164_i2c { · 262 unmodified lines | |||
| 263 | u32 i2c_rc; | 263 | u32 i2c_rc; |
| 264 | }; | 264 | }; |
| 265 | 265 | ||
| 266 | struct saa7164_ctrl { | ||
| 267 | struct v4l2_queryctrl v; | ||
| 268 | }; | ||
| 269 | |||
| 270 | struct saa7164_tvnorm { | 266 | struct saa7164_tvnorm { |
| 271 | char *name; | 267 | char *name; |
| 272 | v4l2_std_id id; | 268 | v4l2_std_id id; |
| @@ -33,7 +33,7 @@ · 32 unmodified lines | |||
| 33 | #include "solo6x10-jpeg.h" | 33 | #include "solo6x10-jpeg.h" |
| 34 | 34 | ||
| 35 | #define MIN_VID_BUFFERS 2 | 35 | #define MIN_VID_BUFFERS 2 |
| 36 | #define FRAME_BUF_SIZE (196 * 1024) | 36 | #define FRAME_BUF_SIZE (400 * 1024) |
| 37 | #define MP4_QS 16 | 37 | #define MP4_QS 16 |
| 38 | #define DMA_ALIGN 4096 | 38 | #define DMA_ALIGN 4096 |
| 39 | 39 | ||
| @@ -664,12 +664,9 @@ static int solo_ring_thread(void *data) · 624 unmodified lines | |||
| 664 | static int solo_enc_queue_setup(struct vb2_queue *q, | 664 | static int solo_enc_queue_setup(struct vb2_queue *q, |
| 665 | unsigned int *num_buffers, | 665 | unsigned int *num_buffers, |
| 666 | unsigned int *num_planes, unsigned int sizes[], | 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 | sizes[0] = FRAME_BUF_SIZE; | 669 | sizes[0] = FRAME_BUF_SIZE; |
| 672 | alloc_ctxs[0] = solo_enc->alloc_ctx; | ||
| 673 | *num_planes = 1; | 670 | *num_planes = 1; |
| 674 | 671 | ||
| 675 | if (*num_buffers < MIN_VID_BUFFERS) | 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 | return ERR_PTR(-ENOMEM); | 1236 | return ERR_PTR(-ENOMEM); |
| 1240 | 1237 | ||
| 1241 | hdl = &solo_enc->hdl; | 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 | v4l2_ctrl_handler_init(hdl, 10); | 1239 | v4l2_ctrl_handler_init(hdl, 10); |
| 1248 | v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, | 1240 | v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, |
| 1249 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); | 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 | solo_enc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1291 | solo_enc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1300 | solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); | 1292 | solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); |
| 1301 | solo_enc->vidq.lock = &solo_enc->lock; | 1293 | solo_enc->vidq.lock = &solo_enc->lock; |
| 1294 | solo_enc->vidq.dev = &solo_dev->pdev->dev; | ||
| 1302 | ret = vb2_queue_init(&solo_enc->vidq); | 1295 | ret = vb2_queue_init(&solo_enc->vidq); |
| 1303 | if (ret) | 1296 | if (ret) |
| 1304 | goto hdl_free; | 1297 | goto hdl_free; |
| @@ -1347,7 +1340,6 @@ pci_free: · 42 unmodified lines | |||
| 1347 | solo_enc->desc_items, solo_enc->desc_dma); | 1340 | solo_enc->desc_items, solo_enc->desc_dma); |
| 1348 | hdl_free: | 1341 | hdl_free: |
| 1349 | v4l2_ctrl_handler_free(hdl); | 1342 | v4l2_ctrl_handler_free(hdl); |
| 1350 | vb2_dma_sg_cleanup_ctx(solo_enc->alloc_ctx); | ||
| 1351 | kfree(solo_enc); | 1343 | kfree(solo_enc); |
| 1352 | return ERR_PTR(ret); | 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 | solo_enc->desc_items, solo_enc->desc_dma); | 1354 | solo_enc->desc_items, solo_enc->desc_dma); |
| 1363 | video_unregister_device(solo_enc->vfd); | 1355 | video_unregister_device(solo_enc->vfd); |
| 1364 | v4l2_ctrl_handler_free(&solo_enc->hdl); | 1356 | v4l2_ctrl_handler_free(&solo_enc->hdl); |
| 1365 | vb2_dma_sg_cleanup_ctx(solo_enc->alloc_ctx); | ||
| 1366 | kfree(solo_enc); | 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 | static int solo_queue_setup(struct vb2_queue *q, | 316 | static int solo_queue_setup(struct vb2_queue *q, |
| 317 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct solo_dev *solo_dev = vb2_get_drv_priv(q); | 320 | struct solo_dev *solo_dev = vb2_get_drv_priv(q); |
| 321 | 321 | ||
| 322 | sizes[0] = solo_image_size(solo_dev); | 322 | sizes[0] = solo_image_size(solo_dev); |
| 323 | alloc_ctxs[0] = solo_dev->alloc_ctx; | ||
| 324 | *num_planes = 1; | 323 | *num_planes = 1; |
| 325 | 324 | ||
| 326 | if (*num_buffers < MIN_VID_BUFFERS) | 325 | if (*num_buffers < MIN_VID_BUFFERS) |
| @@ -386,26 +385,24 @@ static int solo_querycap(struct file *file, void *priv, · 59 unmodified lines | |||
| 386 | static int solo_enum_ext_input(struct solo_dev *solo_dev, | 385 | static int solo_enum_ext_input(struct solo_dev *solo_dev, |
| 387 | struct v4l2_input *input) | 386 | struct v4l2_input *input) |
| 388 | { | 387 | { |
| 389 | static const char * const dispnames_1[] = { "4UP" }; | 388 | int ext = input->index - solo_dev->nr_chans; |
| 390 | static const char * const dispnames_2[] = { "4UP-1", "4UP-2" }; | 389 | unsigned int nup, first; |
| 391 | static const char * const dispnames_5[] = { | ||
| 392 | "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP" | ||
| 393 | }; | ||
| 394 | const char * const *dispnames; | ||
| 395 | 390 | ||
| 396 | if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext)) | 391 | if (ext >= solo_dev->nr_ext) |
| 397 | return -EINVAL; | 392 | return -EINVAL; |
| 398 | 393 | ||
| 399 | if (solo_dev->nr_ext == 5) | 394 | nup = (ext == 4) ? 16 : 4; |
| 400 | dispnames = dispnames_5; | 395 | first = (ext & 3) << 2; /* first channel in the n-up */ |
| 401 | else if (solo_dev->nr_ext == 2) | 396 | snprintf(input->name, sizeof(input->name), |
| 402 | dispnames = dispnames_2; | 397 | "Multi %d-up (cameras %d-%d)", |
| 403 | else | 398 | nup, first + 1, first + nup); |
| 404 | dispnames = dispnames_1; | 399 | /* Possible outputs: |
| 405 | 400 | * Multi 4-up (cameras 1-4) | |
| 406 | snprintf(input->name, sizeof(input->name), "Multi %s", | 401 | * Multi 4-up (cameras 5-8) |
| 407 | dispnames[input->index - solo_dev->nr_chans]); | 402 | * Multi 4-up (cameras 9-12) |
| 408 | 403 | * Multi 4-up (cameras 13-16) | |
| 404 | * Multi 16-up (cameras 1-16) | ||
| 405 | */ | ||
| 409 | return 0; | 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 | solo_dev->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM; | 678 | solo_dev->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM; |
| 682 | solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); | 679 | solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); |
| 683 | solo_dev->vidq.lock = &solo_dev->lock; | 680 | solo_dev->vidq.lock = &solo_dev->lock; |
| 681 | solo_dev->vidq.dev = &solo_dev->pdev->dev; | ||
| 684 | ret = vb2_queue_init(&solo_dev->vidq); | 682 | ret = vb2_queue_init(&solo_dev->vidq); |
| 685 | if (ret < 0) | 683 | if (ret < 0) |
| 686 | goto fail; | 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 | /* Cycle all the channels and clear */ | 686 | /* Cycle all the channels and clear */ |
| 695 | for (i = 0; i < solo_dev->nr_chans; i++) { | 687 | for (i = 0; i < solo_dev->nr_chans; i++) { |
| 696 | solo_v4l2_set_ch(solo_dev, i); | 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 | fail: | 711 | fail: |
| 720 | video_device_release(solo_dev->vfd); | 712 | video_device_release(solo_dev->vfd); |
| 721 | vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx); | ||
| 722 | v4l2_ctrl_handler_free(&solo_dev->disp_hdl); | 713 | v4l2_ctrl_handler_free(&solo_dev->disp_hdl); |
| 723 | solo_dev->vfd = NULL; | 714 | solo_dev->vfd = NULL; |
| 724 | return ret; | 715 | return ret; |
| @@ -730,7 +721,6 @@ void solo_v4l2_exit(struct solo_dev *solo_dev) · 5 unmodified lines | |||
| 730 | return; | 721 | return; |
| 731 | 722 | ||
| 732 | video_unregister_device(solo_dev->vfd); | 723 | video_unregister_device(solo_dev->vfd); |
| 733 | vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx); | ||
| 734 | v4l2_ctrl_handler_free(&solo_dev->disp_hdl); | 724 | v4l2_ctrl_handler_free(&solo_dev->disp_hdl); |
| 735 | solo_dev->vfd = NULL; | 725 | solo_dev->vfd = NULL; |
| 736 | } | 726 | } |
| @@ -178,7 +178,6 @@ struct solo_enc_dev { · 177 unmodified lines | |||
| 178 | u32 sequence; | 178 | u32 sequence; |
| 179 | struct vb2_queue vidq; | 179 | struct vb2_queue vidq; |
| 180 | struct list_head vidq_active; | 180 | struct list_head vidq_active; |
| 181 | void *alloc_ctx; | ||
| 182 | int desc_count; | 181 | int desc_count; |
| 183 | int desc_nelts; | 182 | int desc_nelts; |
| 184 | struct solo_p2m_desc *desc_items; | 183 | struct solo_p2m_desc *desc_items; |
| @@ -269,7 +268,6 @@ struct solo_dev { · 84 unmodified lines | |||
| 269 | 268 | ||
| 270 | /* Buffer handling */ | 269 | /* Buffer handling */ |
| 271 | struct vb2_queue vidq; | 270 | struct vb2_queue vidq; |
| 272 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 273 | u32 sequence; | 271 | u32 sequence; |
| 274 | struct task_struct *kthread; | 272 | struct task_struct *kthread; |
| 275 | struct mutex lock; | 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 | * @input: input line for video signal ( 0 or 1 ) | 111 | * @input: input line for video signal ( 0 or 1 ) |
| 112 | * @disabled: Device is in power down state | 112 | * @disabled: Device is in power down state |
| 113 | * @slock: for excluse acces of registers | 113 | * @slock: for excluse acces of registers |
| 114 | * @alloc_ctx: context for videobuf2 | ||
| 115 | * @vb_vidq: queue maintained by videobuf2 layer | 114 | * @vb_vidq: queue maintained by videobuf2 layer |
| 116 | * @buffer_list: list of buffer in use | 115 | * @buffer_list: list of buffer in use |
| 117 | * @sequence: sequence number of acquired buffer | 116 | * @sequence: sequence number of acquired buffer |
| @@ -141,7 +140,6 @@ struct sta2x11_vip { · 23 unmodified lines | |||
| 141 | int disabled; | 140 | int disabled; |
| 142 | spinlock_t slock; | 141 | spinlock_t slock; |
| 143 | 142 | ||
| 144 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 145 | struct vb2_queue vb_vidq; | 143 | struct vb2_queue vb_vidq; |
| 146 | struct list_head buffer_list; | 144 | struct list_head buffer_list; |
| 147 | unsigned int sequence; | 145 | unsigned int sequence; |
| @@ -267,7 +265,7 @@ static void vip_active_buf_next(struct sta2x11_vip *vip) · 119 unmodified lines | |||
| 267 | /* Videobuf2 Operations */ | 265 | /* Videobuf2 Operations */ |
| 268 | static int queue_setup(struct vb2_queue *vq, | 266 | static int queue_setup(struct vb2_queue *vq, |
| 269 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | struct sta2x11_vip *vip = vb2_get_drv_priv(vq); | 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 | *nplanes = 1; | 275 | *nplanes = 1; |
| 278 | sizes[0] = vip->format.sizeimage; | 276 | sizes[0] = vip->format.sizeimage; |
| 279 | alloc_ctxs[0] = vip->alloc_ctx; | ||
| 280 | 277 | ||
| 281 | vip->sequence = 0; | 278 | vip->sequence = 0; |
| 282 | vip->active = NULL; | 279 | vip->active = NULL; |
| @@ -861,25 +858,15 @@ static int sta2x11_vip_init_buffer(struct sta2x11_vip *vip) · 578 unmodified lines | |||
| 861 | vip->vb_vidq.ops = &vip_video_qops; | 858 | vip->vb_vidq.ops = &vip_video_qops; |
| 862 | vip->vb_vidq.mem_ops = &vb2_dma_contig_memops; | 859 | vip->vb_vidq.mem_ops = &vb2_dma_contig_memops; |
| 863 | vip->vb_vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 860 | vip->vb_vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 861 | vip->vb_vidq.dev = &vip->pdev->dev; | ||
| 864 | err = vb2_queue_init(&vip->vb_vidq); | 862 | err = vb2_queue_init(&vip->vb_vidq); |
| 865 | if (err) | 863 | if (err) |
| 866 | return err; | 864 | return err; |
| 867 | INIT_LIST_HEAD(&vip->buffer_list); | 865 | INIT_LIST_HEAD(&vip->buffer_list); |
| 868 | spin_lock_init(&vip->lock); | 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 | return 0; | 867 | return 0; |
| 878 | } | 868 | } |
| 879 | static void sta2x11_vip_release_buffer(struct sta2x11_vip *vip) | 869 | |
| 880 | { | ||
| 881 | vb2_dma_contig_cleanup_ctx(vip->alloc_ctx); | ||
| 882 | } | ||
| 883 | static int sta2x11_vip_init_controls(struct sta2x11_vip *vip) | 870 | static int sta2x11_vip_init_controls(struct sta2x11_vip *vip) |
| 884 | { | 871 | { |
| 885 | /* | 872 | /* |
| @@ -1120,7 +1107,6 @@ vrelease: · 234 unmodified lines | |||
| 1120 | video_unregister_device(&vip->video_dev); | 1107 | video_unregister_device(&vip->video_dev); |
| 1121 | free_irq(pdev->irq, vip); | 1108 | free_irq(pdev->irq, vip); |
| 1122 | release_buf: | 1109 | release_buf: |
| 1123 | sta2x11_vip_release_buffer(vip); | ||
| 1124 | pci_disable_msi(pdev); | 1110 | pci_disable_msi(pdev); |
| 1125 | unmap: | 1111 | unmap: |
| 1126 | vb2_queue_release(&vip->vb_vidq); | 1112 | vb2_queue_release(&vip->vb_vidq); |
| @@ -305,19 +305,13 @@ static int tw68_initdev(struct pci_dev *pci_dev, · 304 unmodified lines | |||
| 305 | /* Then do any initialisation wanted before interrupts are on */ | 305 | /* Then do any initialisation wanted before interrupts are on */ |
| 306 | tw68_hw_init1(dev); | 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 | /* get irq */ | 308 | /* get irq */ |
| 315 | err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq, | 309 | err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq, |
| 316 | IRQF_SHARED, dev->name, dev); | 310 | IRQF_SHARED, dev->name, dev); |
| 317 | if (err < 0) { | 311 | if (err < 0) { |
| 318 | pr_err("%s: can't get IRQ %d\n", | 312 | pr_err("%s: can't get IRQ %d\n", |
| 319 | dev->name, pci_dev->irq); | 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 | if (err < 0) { | 325 | if (err < 0) { |
| 332 | pr_err("%s: can't register video device\n", | 326 | pr_err("%s: can't register video device\n", |
| 333 | dev->name); | 327 | dev->name); |
| 334 | goto fail5; | 328 | goto fail4; |
| 335 | } | 329 | } |
| 336 | tw_setl(TW68_INTMASK, dev->pci_irqmask); | 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 | return 0; | 335 | return 0; |
| 342 | 336 | ||
| 343 | fail5: | ||
| 344 | video_unregister_device(&dev->vdev); | ||
| 345 | fail4: | 337 | fail4: |
| 346 | vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | 338 | video_unregister_device(&dev->vdev); |
| 347 | fail3: | 339 | fail3: |
| 348 | iounmap(dev->lmmio); | 340 | iounmap(dev->lmmio); |
| 349 | fail2: | 341 | fail2: |
| @@ -367,7 +359,6 @@ static void tw68_finidev(struct pci_dev *pci_dev) · 17 unmodified lines | |||
| 367 | /* unregister */ | 359 | /* unregister */ |
| 368 | video_unregister_device(&dev->vdev); | 360 | video_unregister_device(&dev->vdev); |
| 369 | v4l2_ctrl_handler_free(&dev->hdl); | 361 | v4l2_ctrl_handler_free(&dev->hdl); |
| 370 | vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); | ||
| 371 | 362 | ||
| 372 | /* release resources */ | 363 | /* release resources */ |
| 373 | iounmap(dev->lmmio); | 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 | static int tw68_queue_setup(struct vb2_queue *q, | 379 | static int tw68_queue_setup(struct vb2_queue *q, |
| 380 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct tw68_dev *dev = vb2_get_drv_priv(q); | 383 | struct tw68_dev *dev = vb2_get_drv_priv(q); |
| 384 | unsigned tot_bufs = q->num_buffers + *num_buffers; | 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 | tot_bufs = 2; | 388 | tot_bufs = 2; |
| 389 | tot_bufs = tw68_buffer_count(size, tot_bufs); | 389 | tot_bufs = tw68_buffer_count(size, tot_bufs); |
| 390 | *num_buffers = tot_bufs - q->num_buffers; | 390 | *num_buffers = tot_bufs - q->num_buffers; |
| 391 | alloc_ctxs[0] = dev->alloc_ctx; | ||
| 392 | /* | 391 | /* |
| 393 | * We allow create_bufs, but only if the sizeimage is >= as the | 392 | * We allow create_bufs, but only if the sizeimage is >= as the |
| 394 | * current sizeimage. The tw68_buffer_count calculation becomes quite | 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 | dev->vidq.buf_struct_size = sizeof(struct tw68_buf); | 982 | dev->vidq.buf_struct_size = sizeof(struct tw68_buf); |
| 984 | dev->vidq.lock = &dev->lock; | 983 | dev->vidq.lock = &dev->lock; |
| 985 | dev->vidq.min_buffers_needed = 2; | 984 | dev->vidq.min_buffers_needed = 2; |
| 985 | dev->vidq.dev = &dev->pci->dev; | ||
| 986 | ret = vb2_queue_init(&dev->vidq); | 986 | ret = vb2_queue_init(&dev->vidq); |
| 987 | if (ret) | 987 | if (ret) |
| 988 | return ret; | 988 | return ret; |
| @@ -165,7 +165,6 @@ struct tw68_dev { · 164 unmodified lines | |||
| 165 | unsigned field; | 165 | unsigned field; |
| 166 | struct vb2_queue vidq; | 166 | struct vb2_queue vidq; |
| 167 | struct list_head active; | 167 | struct list_head active; |
| 168 | void *alloc_ctx; | ||
| 169 | 168 | ||
| 170 | /* various v4l controls */ | 169 | /* various v4l controls */ |
| 171 | const struct tw68_tvnorm *tvnorm; /* video */ | 170 | const struct tw68_tvnorm *tvnorm; /* video */ |
| @@ -3,6 +3,8 @@ config VIDEO_TW686X · 2 unmodified lines | |||
| 3 | depends on PCI && VIDEO_DEV && VIDEO_V4L2 && SND | 3 | depends on PCI && VIDEO_DEV && VIDEO_V4L2 && SND |
| 4 | depends on HAS_DMA | 4 | depends on HAS_DMA |
| 5 | select VIDEOBUF2_VMALLOC | 5 | select VIDEOBUF2_VMALLOC |
| 6 | select VIDEOBUF2_DMA_CONTIG | ||
| 7 | select VIDEOBUF2_DMA_SG | ||
| 6 | select SND_PCM | 8 | select SND_PCM |
| 7 | help | 9 | help |
| 8 | Support for Intersil/Techwell TW686x-based frame grabber cards. | 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 | spin_unlock_irqrestore(&ac->lock, flags); | 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 | desc = &ac->dma_descs[pb]; | 71 | desc = &ac->dma_descs[pb]; |
| 66 | if (done && next && desc->virt) { | 72 | if (desc->virt) { |
| 67 | memcpy(done->virt, desc->virt, desc->size); | 73 | memcpy(done->virt, desc->virt, |
| 68 | ac->ptr = done->dma - ac->buf[0].dma; | 74 | dev->period_size); |
| 69 | snd_pcm_period_elapsed(ac->ss); | 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 | 96 | * Audio parameters are global and shared among all |
| 87 | * capture channels. The driver makes no effort to prevent | 97 | * capture channels. The driver prevents changes to |
| 88 | * rate modifications. User is free change the rate, but it | 98 | * the parameters if any audio channel is capturing. |
| 89 | * means changing the rate for all capture sub-devices. | ||
| 90 | */ | 99 | */ |
| 91 | static const struct snd_pcm_hardware tw686x_capture_hw = { | 100 | static const struct snd_pcm_hardware tw686x_capture_hw = { |
| 92 | .info = (SNDRV_PCM_INFO_MMAP | | 101 | .info = (SNDRV_PCM_INFO_MMAP | |
| @@ -99,9 +108,9 @@ static const struct snd_pcm_hardware tw686x_capture_hw = { · 6 unmodified lines | |||
| 99 | .rate_max = 48000, | 108 | .rate_max = 48000, |
| 100 | .channels_min = 1, | 109 | .channels_min = 1, |
| 101 | .channels_max = 1, | 110 | .channels_max = 1, |
| 102 | .buffer_bytes_max = TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ, | 111 | .buffer_bytes_max = TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX, |
| 103 | .period_bytes_min = TW686X_AUDIO_PAGE_SZ, | 112 | .period_bytes_min = AUDIO_DMA_SIZE_MIN, |
| 104 | .period_bytes_max = TW686X_AUDIO_PAGE_SZ, | 113 | .period_bytes_max = AUDIO_DMA_SIZE_MAX, |
| 105 | .periods_min = TW686X_AUDIO_PERIODS_MIN, | 114 | .periods_min = TW686X_AUDIO_PERIODS_MIN, |
| 106 | .periods_max = TW686X_AUDIO_PERIODS_MAX, | 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 | int i; | 152 | int i; |
| 144 | 153 | ||
| 145 | spin_lock_irqsave(&dev->lock, flags); | 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 | tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch); | 163 | tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch); |
| 147 | spin_unlock_irqrestore(&dev->lock, flags); | 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 | reg_write(dev, AUDIO_CONTROL2, reg); | 173 | reg_write(dev, AUDIO_CONTROL2, reg); |
| 157 | } | 174 | } |
| 158 | 175 | ||
| 159 | if (period_size != TW686X_AUDIO_PAGE_SZ || | 176 | if (dev->period_size != period_size) { |
| 160 | rt->periods < TW686X_AUDIO_PERIODS_MIN || | 177 | u32 reg; |
| 161 | rt->periods > TW686X_AUDIO_PERIODS_MAX) { | 178 | |
| 162 | return -EINVAL; | 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 | spin_lock_irqsave(&ac->lock, flags); | 191 | spin_lock_irqsave(&ac->lock, flags); |
| 166 | INIT_LIST_HEAD(&ac->buf_list); | 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 | ac->curr_bufs[0] = p_buf; | 207 | ac->curr_bufs[0] = p_buf; |
| 182 | ac->curr_bufs[1] = b_buf; | 208 | ac->curr_bufs[1] = b_buf; |
| 183 | ac->ptr = 0; | 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 | spin_unlock_irqrestore(&ac->lock, flags); | 216 | spin_unlock_irqrestore(&ac->lock, flags); |
| 185 | 217 | ||
| 186 | return 0; | 218 | return 0; |
| 219 | |||
| 220 | err_audio_busy: | ||
| 221 | spin_unlock_irqrestore(&dev->lock, flags); | ||
| 222 | return -EBUSY; | ||
| 187 | } | 223 | } |
| 188 | 224 | ||
| 189 | static int tw686x_pcm_trigger(struct snd_pcm_substream *ss, int cmd) | 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 | case SNDRV_PCM_TRIGGER_START: | 233 | case SNDRV_PCM_TRIGGER_START: |
| 198 | if (ac->curr_bufs[0] && ac->curr_bufs[1]) { | 234 | if (ac->curr_bufs[0] && ac->curr_bufs[1]) { |
| 199 | spin_lock_irqsave(&dev->lock, flags); | 235 | spin_lock_irqsave(&dev->lock, flags); |
| 236 | dev->audio_enabled = 1; | ||
| 200 | tw686x_enable_channel(dev, | 237 | tw686x_enable_channel(dev, |
| 201 | AUDIO_CHANNEL_OFFSET + ac->ch); | 238 | AUDIO_CHANNEL_OFFSET + ac->ch); |
| 202 | spin_unlock_irqrestore(&dev->lock, flags); | 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 | break; | 246 | break; |
| 210 | case SNDRV_PCM_TRIGGER_STOP: | 247 | case SNDRV_PCM_TRIGGER_STOP: |
| 211 | spin_lock_irqsave(&dev->lock, flags); | 248 | spin_lock_irqsave(&dev->lock, flags); |
| 249 | dev->audio_enabled = 0; | ||
| 212 | tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch); | 250 | tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch); |
| 213 | spin_unlock_irqrestore(&dev->lock, flags); | 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 | return snd_pcm_lib_preallocate_pages_for_all(pcm, | 304 | return snd_pcm_lib_preallocate_pages_for_all(pcm, |
| 267 | SNDRV_DMA_TYPE_DEV, | 305 | SNDRV_DMA_TYPE_DEV, |
| 268 | snd_dma_pci_data(dev->pci_dev), | 306 | snd_dma_pci_data(dev->pci_dev), |
| 269 | TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ, | 307 | TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX, |
| 270 | TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ); | 308 | TW686X_AUDIO_PAGE_MAX * AUDIO_DMA_SIZE_MAX); |
| 271 | } | 309 | } |
| 272 | 310 | ||
| 273 | static void tw686x_audio_dma_free(struct tw686x_dev *dev, | 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 | int pb; | 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 | for (pb = 0; pb < 2; pb++) { | 339 | for (pb = 0; pb < 2; pb++) { |
| 294 | u32 reg = pb ? ADMA_B_ADDR[ac->ch] : ADMA_P_ADDR[ac->ch]; | 340 | u32 reg = pb ? ADMA_B_ADDR[ac->ch] : ADMA_P_ADDR[ac->ch]; |
| 295 | void *virt; | 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 | &ac->dma_descs[pb].phys); | 344 | &ac->dma_descs[pb].phys); |
| 299 | if (!virt) { | 345 | if (!virt) { |
| 300 | dev_err(&dev->pci_dev->dev, | 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 | return -ENOMEM; | 349 | return -ENOMEM; |
| 304 | } | 350 | } |
| 305 | ac->dma_descs[pb].virt = virt; | 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 | reg_write(dev, reg, ac->dma_descs[pb].phys); | 353 | reg_write(dev, reg, ac->dma_descs[pb].phys); |
| 308 | } | 354 | } |
| 309 | return 0; | 355 | return 0; |
| @@ -334,12 +380,8 @@ int tw686x_audio_init(struct tw686x_dev *dev) · 24 unmodified lines | |||
| 334 | struct snd_card *card; | 380 | struct snd_card *card; |
| 335 | int err, ch; | 381 | int err, ch; |
| 336 | 382 | ||
| 337 | /* | 383 | /* Enable external audio */ |
| 338 | * AUDIO_CONTROL1 | 384 | reg_write(dev, AUDIO_CONTROL1, BIT(0)); |
| 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); | ||
| 343 | 385 | ||
| 344 | err = snd_card_new(&pci_dev->dev, SNDRV_DEFAULT_IDX1, | 386 | err = snd_card_new(&pci_dev->dev, SNDRV_DEFAULT_IDX1, |
| 345 | SNDRV_DEFAULT_STR1, | 387 | SNDRV_DEFAULT_STR1, |
| @@ -21,12 +21,14 @@ · 20 unmodified lines | |||
| 21 | * under stress testings it has been found that the machine can | 21 | * under stress testings it has been found that the machine can |
| 22 | * freeze completely if DMA registers are programmed while streaming | 22 | * freeze completely if DMA registers are programmed while streaming |
| 23 | * is active. | 23 | * is active. |
| 24 | * This driver tries to access hardware registers as infrequently | 24 | * |
| 25 | * as possible by: | 25 | * Therefore, driver implements a dma_mode called 'memcpy' which |
| 26 | * i. allocating fixed DMA buffers and memcpy'ing into | 26 | * avoids cycling the DMA buffers, and insteads allocates extra DMA buffers |
| 27 | * vmalloc'ed buffers | 27 | * and then copies into vmalloc'ed user buffers. |
| 28 | * ii. using a timer to mitigate the rate of DMA reset operations, | 28 | * |
| 29 | * on DMA channels error. | 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 | #include <linux/init.h> | 34 | #include <linux/init.h> |
| @@ -55,6 +57,42 @@ static u32 dma_interval = 0x00098968; · 22 unmodified lines | |||
| 55 | module_param(dma_interval, int, 0444); | 57 | module_param(dma_interval, int, 0444); |
| 56 | MODULE_PARM_DESC(dma_interval, "Minimum time span for DMA interrupting host"); | 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 | void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel) | 96 | void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel) |
| 59 | { | 97 | { |
| 60 | u32 dma_en = reg_read(dev, DMA_CHANNEL_ENABLE); | 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 | if (!dev) | 250 | if (!dev) |
| 213 | return -ENOMEM; | 251 | return -ENOMEM; |
| 214 | dev->type = pci_id->driver_data; | 252 | dev->type = pci_id->driver_data; |
| 253 | dev->dma_mode = dma_mode; | ||
| 215 | sprintf(dev->name, "tw%04X", pci_dev->device); | 254 | sprintf(dev->name, "tw%04X", pci_dev->device); |
| 216 | 255 | ||
| 217 | dev->video_channels = kcalloc(max_channels(dev), | 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 | goto free_video; | 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 | pci_name(pci_dev), pci_dev->irq, | 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 | dev->pci_dev = pci_dev; | 275 | dev->pci_dev = pci_dev; |
| 236 | if (pci_enable_device(pci_dev)) { | 276 | if (pci_enable_device(pci_dev)) { |
| @@ -105,6 +105,10 @@ · 104 unmodified lines | |||
| 105 | 0x2d0, 0x2d1, 0x2d2, 0x2d3 }) | 105 | 0x2d0, 0x2d1, 0x2d2, 0x2d3 }) |
| 106 | 106 | ||
| 107 | #define SYS_MODE_DMA_SHIFT 13 | 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 | #define DMA_CMD_ENABLE BIT(31) | 113 | #define DMA_CMD_ENABLE BIT(31) |
| 110 | #define INT_STATUS_DMA_TOUT BIT(17) | 114 | #define INT_STATUS_DMA_TOUT BIT(17) |
| @@ -119,4 +123,9 @@ · 8 unmodified lines | |||
| 119 | #define TW686X_STD_PAL_CN 5 | 123 | #define TW686X_STD_PAL_CN 5 |
| 120 | #define TW686X_STD_PAL_60 6 | 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 | #define TW686X_FIFO_ERROR(x) (x & ~(0xff)) | 131 | #define TW686X_FIFO_ERROR(x) (x & ~(0xff)) |
| @@ -19,6 +19,8 @@ · 18 unmodified lines | |||
| 19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
| 20 | #include <media/v4l2-common.h> | 20 | #include <media/v4l2-common.h> |
| 21 | #include <media/v4l2-event.h> | 21 | #include <media/v4l2-event.h> |
| 22 | #include <media/videobuf2-dma-contig.h> | ||
| 23 | #include <media/videobuf2-dma-sg.h> | ||
| 22 | #include <media/videobuf2-vmalloc.h> | 24 | #include <media/videobuf2-vmalloc.h> |
| 23 | #include "tw686x.h" | 25 | #include "tw686x.h" |
| 24 | #include "tw686x-regs.h" | 26 | #include "tw686x-regs.h" |
| @@ -26,6 +28,11 @@ · 1 unmodified line | |||
| 26 | #define TW686X_INPUTS_PER_CH 4 | 28 | #define TW686X_INPUTS_PER_CH 4 |
| 27 | #define TW686X_VIDEO_WIDTH 720 | 29 | #define TW686X_VIDEO_WIDTH 720 |
| 28 | #define TW686X_VIDEO_HEIGHT(id) ((id & V4L2_STD_525_60) ? 480 : 576) | 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 | static const struct tw686x_format formats[] = { | 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] = { | 56 | struct tw686x_dma_desc *desc = &vc->dma_descs[pb]; |
| 49 | 0x00000000, 0x00000001, 0x00004001, 0x00104001, 0x00404041, | 57 | struct tw686x_dev *dev = vc->dev; |
| 50 | 0x01041041, 0x01104411, 0x01111111, 0x04444445, 0x04511445, | 58 | struct vb2_v4l2_buffer *vb; |
| 51 | 0x05145145, 0x05151515, 0x05515455, 0x05551555, 0x05555555 | 59 | struct vb2_buffer *vb2_buf; |
| 52 | }; | ||
| 53 | 60 | ||
| 54 | static const unsigned int std_625_50[26] = { | 61 | if (vc->curr_bufs[pb]) { |
| 55 | 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, | 62 | vb = &vc->curr_bufs[pb]->vb; |
| 56 | 8, 8, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 0 | ||
| 57 | }; | ||
| 58 | 63 | ||
| 59 | static const unsigned int std_525_60[31] = { | 64 | vb->field = dev->dma_ops->field; |
| 60 | 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, | 65 | vb->sequence = vc->sequence++; |
| 61 | 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 0, 0 | 66 | vb2_buf = &vb->vb2_buf; |
| 62 | }; | ||
| 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) { | 149 | static const struct tw686x_dma_ops memcpy_dma_ops = { |
| 67 | if (fps >= ARRAY_SIZE(std_525_60)) | 150 | .alloc = tw686x_memcpy_dma_alloc, |
| 68 | fps = 30; | 151 | .free = tw686x_memcpy_dma_free, |
| 69 | i = std_525_60[fps]; | 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 | } else { | 294 | } else { |
| 71 | if (fps >= ARRAY_SIZE(std_625_50)) | 295 | virt = dev->video_channels[0].dma_descs[pb].virt + |
| 72 | fps = 25; | 296 | vc->ch * TW686X_SG_TABLE_SIZE; |
| 73 | i = std_625_50[fps]; | ||
| 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 | static void tw686x_set_framerate(struct tw686x_video_channel *vc, | 406 | static void tw686x_set_framerate(struct tw686x_video_channel *vc, |
| 80 | unsigned int fps) | 407 | unsigned int fps) |
| 81 | { | 408 | { |
| 82 | unsigned int map; | 409 | unsigned int i; |
| 83 | |||
| 84 | if (vc->fps == fps) | ||
| 85 | return; | ||
| 86 | 410 | ||
| 87 | map = tw686x_fields_map(vc->video_standard, fps) << 1; | 411 | i = tw686x_fps_idx(fps, TW686X_MAX_FPS(vc->video_standard)); |
| 88 | map |= map << 1; | 412 | reg_write(vc->dev, VIDEO_FIELD_CTRL[vc->ch], fps_map[i]); |
| 89 | if (map > 0) | 413 | vc->fps = tw686x_real_fps(i, TW686X_MAX_FPS(vc->video_standard)); |
| 90 | map |= BIT(31); | ||
| 91 | reg_write(vc->dev, VIDEO_FIELD_CTRL[vc->ch], map); | ||
| 92 | vc->fps = fps; | ||
| 93 | } | 414 | } |
| 94 | 415 | ||
| 95 | static const struct tw686x_format *format_by_fourcc(unsigned int fourcc) | 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 | static int tw686x_queue_setup(struct vb2_queue *vq, | 426 | static int tw686x_queue_setup(struct vb2_queue *vq, |
| 106 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); | 430 | struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); |
| 110 | unsigned int szimage = | 431 | unsigned int szimage = |
| @@ -152,75 +473,6 @@ static void tw686x_buf_queue(struct vb2_buffer *vb) · 41 unmodified lines | |||
| 152 | spin_unlock_irqrestore(&vc->qlock, flags); | 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 | static void tw686x_clear_queue(struct tw686x_video_channel *vc, | 476 | static void tw686x_clear_queue(struct tw686x_video_channel *vc, |
| 225 | enum vb2_buffer_state state) | 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 | spin_lock_irqsave(&vc->qlock, flags); | 514 | spin_lock_irqsave(&vc->qlock, flags); |
| 263 | 515 | ||
| 264 | /* Sanity check */ | 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 | spin_unlock_irqrestore(&vc->qlock, flags); | 519 | spin_unlock_irqrestore(&vc->qlock, flags); |
| 267 | v4l2_err(&dev->v4l2_dev, | 520 | v4l2_err(&dev->v4l2_dev, |
| 268 | "video%d: refusing to start without DMA buffers\n", | 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 | for (pb = 0; pb < 2; pb++) | 527 | for (pb = 0; pb < 2; pb++) |
| 275 | tw686x_buffer_refill(vc, pb); | 528 | dev->dma_ops->buf_refill(vc, pb); |
| 276 | spin_unlock_irqrestore(&vc->qlock, flags); | 529 | spin_unlock_irqrestore(&vc->qlock, flags); |
| 277 | 530 | ||
| 278 | vc->sequence = 0; | 531 | vc->sequence = 0; |
| @@ -375,10 +628,11 @@ static int tw686x_g_fmt_vid_cap(struct file *file, void *priv, · 96 unmodified lines | |||
| 375 | struct v4l2_format *f) | 628 | struct v4l2_format *f) |
| 376 | { | 629 | { |
| 377 | struct tw686x_video_channel *vc = video_drvdata(file); | 630 | struct tw686x_video_channel *vc = video_drvdata(file); |
| 631 | struct tw686x_dev *dev = vc->dev; | ||
| 378 | 632 | ||
| 379 | f->fmt.pix.width = vc->width; | 633 | f->fmt.pix.width = vc->width; |
| 380 | f->fmt.pix.height = vc->height; | 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 | f->fmt.pix.pixelformat = vc->format->fourcc; | 636 | f->fmt.pix.pixelformat = vc->format->fourcc; |
| 383 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | 637 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
| 384 | f->fmt.pix.bytesperline = (f->fmt.pix.width * vc->format->depth) / 8; | 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 | struct v4l2_format *f) | 644 | struct v4l2_format *f) |
| 391 | { | 645 | { |
| 392 | struct tw686x_video_channel *vc = video_drvdata(file); | 646 | struct tw686x_video_channel *vc = video_drvdata(file); |
| 647 | struct tw686x_dev *dev = vc->dev; | ||
| 393 | unsigned int video_height = TW686X_VIDEO_HEIGHT(vc->video_standard); | 648 | unsigned int video_height = TW686X_VIDEO_HEIGHT(vc->video_standard); |
| 394 | const struct tw686x_format *format; | 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 | f->fmt.pix.bytesperline = (f->fmt.pix.width * format->depth) / 8; | 667 | f->fmt.pix.bytesperline = (f->fmt.pix.width * format->depth) / 8; |
| 413 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | 668 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; |
| 414 | f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | 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 | return 0; | 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 | struct v4l2_format *f) | 676 | struct v4l2_format *f) |
| 422 | { | 677 | { |
| 423 | struct tw686x_video_channel *vc = video_drvdata(file); | 678 | struct tw686x_video_channel *vc = video_drvdata(file); |
| 679 | struct tw686x_dev *dev = vc->dev; | ||
| 424 | u32 val, width, line_width, height; | 680 | u32 val, width, line_width, height; |
| 425 | unsigned long bitsperframe; | 681 | unsigned long bitsperframe; |
| 426 | int err, pb; | 682 | int err, pb; |
| @@ -438,15 +694,16 @@ static int tw686x_s_fmt_vid_cap(struct file *file, void *priv, · 11 unmodified lines | |||
| 438 | vc->height = f->fmt.pix.height; | 694 | vc->height = f->fmt.pix.height; |
| 439 | 695 | ||
| 440 | /* We need new DMA buffers if the framesize has changed */ | 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 | for (pb = 0; pb < 2; pb++) | 699 | for (pb = 0; pb < 2; pb++) |
| 443 | tw686x_free_dma(vc, pb); | 700 | dev->dma_ops->free(vc, pb); |
| 444 | 701 | ||
| 445 | for (pb = 0; pb < 2; pb++) { | 702 | for (pb = 0; pb < 2; pb++) { |
| 446 | err = tw686x_alloc_dma(vc, pb); | 703 | err = dev->dma_ops->alloc(vc, pb); |
| 447 | if (err) { | 704 | if (err) { |
| 448 | if (pb > 0) | 705 | if (pb > 0) |
| 449 | tw686x_free_dma(vc, 0); | 706 | dev->dma_ops->free(vc, 0); |
| 450 | return err; | 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 | else | 721 | else |
| 465 | val &= ~BIT(24); | 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 | val &= ~(0x7 << 20); | 737 | val &= ~(0x7 << 20); |
| 468 | val |= vc->format->mode << 20; | 738 | val |= vc->format->mode << 20; |
| 469 | reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val); | 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 | ret = tw686x_g_fmt_vid_cap(file, priv, &f); | 810 | ret = tw686x_g_fmt_vid_cap(file, priv, &f); |
| 541 | if (!ret) | 811 | if (!ret) |
| 542 | tw686x_s_fmt_vid_cap(file, priv, &f); | 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 | return 0; | 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 | return 0; | 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 | static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv, | 922 | static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv, |
| 613 | struct v4l2_fmtdesc *f) | 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 | .vidioc_g_std = tw686x_g_std, | 1005 | .vidioc_g_std = tw686x_g_std, |
| 696 | .vidioc_s_std = tw686x_s_std, | 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 | .vidioc_enum_input = tw686x_enum_input, | 1011 | .vidioc_enum_input = tw686x_enum_input, |
| 699 | .vidioc_g_input = tw686x_g_input, | 1012 | .vidioc_g_input = tw686x_g_input, |
| 700 | .vidioc_s_input = tw686x_s_input, | 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 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | 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 | void tw686x_video_irq(struct tw686x_dev *dev, unsigned long requests, | 1029 | void tw686x_video_irq(struct tw686x_dev *dev, unsigned long requests, |
| 731 | unsigned int pb_status, unsigned int fifo_status, | 1030 | unsigned int pb_status, unsigned int fifo_status, |
| 732 | unsigned int *reset_ch) | 1031 | unsigned int *reset_ch) |
| 733 | { | 1032 | { |
| 734 | struct tw686x_video_channel *vc; | 1033 | struct tw686x_video_channel *vc; |
| 735 | struct vb2_v4l2_buffer *vb; | ||
| 736 | unsigned long flags; | 1034 | unsigned long flags; |
| 737 | unsigned int ch, pb; | 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 | continue; | 1079 | continue; |
| 782 | } | 1080 | } |
| 783 | 1081 | ||
| 784 | /* handle video stream */ | ||
| 785 | spin_lock_irqsave(&vc->qlock, flags); | 1082 | spin_lock_irqsave(&vc->qlock, flags); |
| 786 | if (vc->curr_bufs[pb]) { | 1083 | tw686x_buf_done(vc, pb); |
| 787 | vb = &vc->curr_bufs[pb]->vb; | 1084 | dev->dma_ops->buf_refill(vc, pb); |
| 788 | tw686x_buffer_copy(vc, pb, vb); | ||
| 789 | } | ||
| 790 | vc->pb = !pb; | ||
| 791 | tw686x_buffer_refill(vc, pb); | ||
| 792 | spin_unlock_irqrestore(&vc->qlock, flags); | 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 | if (vc->device) | 1096 | if (vc->device) |
| 804 | video_unregister_device(vc->device); | 1097 | video_unregister_device(vc->device); |
| 805 | 1098 | ||
| 806 | for (pb = 0; pb < 2; pb++) | 1099 | if (dev->dma_ops->free) |
| 807 | tw686x_free_dma(vc, pb); | 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 | unsigned int ch, val, pb; | 1107 | unsigned int ch, val, pb; |
| 814 | int err; | 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 | err = v4l2_device_register(&dev->pci_dev->dev, &dev->v4l2_dev); | 1119 | err = v4l2_device_register(&dev->pci_dev->dev, &dev->v4l2_dev); |
| 817 | if (err) | 1120 | if (err) |
| 818 | return err; | 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 | for (ch = 0; ch < max_channels(dev); ch++) { | 1129 | for (ch = 0; ch < max_channels(dev); ch++) { |
| 821 | struct tw686x_video_channel *vc = &dev->video_channels[ch]; | 1130 | struct tw686x_video_channel *vc = &dev->video_channels[ch]; |
| 822 | struct video_device *vdev; | 1131 | struct video_device *vdev; |
| @@ -842,10 +1151,12 @@ int tw686x_video_init(struct tw686x_dev *dev) · 19 unmodified lines | |||
| 842 | reg_write(dev, HACTIVE_LO[ch], 0xd0); | 1151 | reg_write(dev, HACTIVE_LO[ch], 0xd0); |
| 843 | reg_write(dev, VIDEO_SIZE[ch], 0); | 1152 | reg_write(dev, VIDEO_SIZE[ch], 0); |
| 844 | 1153 | ||
| 845 | for (pb = 0; pb < 2; pb++) { | 1154 | if (dev->dma_ops->alloc) { |
| 846 | err = tw686x_alloc_dma(vc, pb); | 1155 | for (pb = 0; pb < 2; pb++) { |
| 847 | if (err) | 1156 | err = dev->dma_ops->alloc(vc, pb); |
| 848 | goto error; | 1157 | if (err) |
| 1158 | goto error; | ||
| 1159 | } | ||
| 849 | } | 1160 | } |
| 850 | 1161 | ||
| 851 | vc->vidq.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF; | 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 | vc->vidq.drv_priv = vc; | 1164 | vc->vidq.drv_priv = vc; |
| 854 | vc->vidq.buf_struct_size = sizeof(struct tw686x_v4l2_buf); | 1165 | vc->vidq.buf_struct_size = sizeof(struct tw686x_v4l2_buf); |
| 855 | vc->vidq.ops = &tw686x_video_qops; | 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 | vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1168 | vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 858 | vc->vidq.min_buffers_needed = 2; | 1169 | vc->vidq.min_buffers_needed = 2; |
| 859 | vc->vidq.lock = &vc->vb_mutex; | 1170 | vc->vidq.lock = &vc->vb_mutex; |
| 860 | vc->vidq.gfp_flags = GFP_DMA32; | 1171 | vc->vidq.gfp_flags = GFP_DMA32; |
| 1172 | vc->vidq.dev = &dev->pci_dev->dev; | ||
| 861 | 1173 | ||
| 862 | err = vb2_queue_init(&vc->vidq); | 1174 | err = vb2_queue_init(&vc->vidq); |
| 863 | if (err) { | 1175 | if (err) { |
| @@ -915,10 +1227,9 @@ int tw686x_video_init(struct tw686x_dev *dev) · 51 unmodified lines | |||
| 915 | vc->num = vdev->num; | 1227 | vc->num = vdev->num; |
| 916 | } | 1228 | } |
| 917 | 1229 | ||
| 918 | /* Set DMA frame mode on all channels. Only supported mode for now. */ | ||
| 919 | val = TW686X_DEF_PHASE_REF; | 1230 | val = TW686X_DEF_PHASE_REF; |
| 920 | for (ch = 0; ch < max_channels(dev); ch++) | 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 | reg_write(dev, PHASE_REF, val); | 1233 | reg_write(dev, PHASE_REF, val); |
| 923 | 1234 | ||
| 924 | reg_write(dev, MISC2[0], 0xe7); | 1235 | reg_write(dev, MISC2[0], 0xe7); |
| @@ -27,16 +27,14 @@ · 26 unmodified lines | |||
| 27 | #define TYPE_SECOND_GEN 0x10 | 27 | #define TYPE_SECOND_GEN 0x10 |
| 28 | #define TW686X_DEF_PHASE_REF 0x1518 | 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 | #define TW686X_AUDIO_PAGE_MAX 16 | 30 | #define TW686X_AUDIO_PAGE_MAX 16 |
| 37 | #define TW686X_AUDIO_PERIODS_MIN 2 | 31 | #define TW686X_AUDIO_PERIODS_MIN 2 |
| 38 | #define TW686X_AUDIO_PERIODS_MAX TW686X_AUDIO_PAGE_MAX | 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 | struct tw686x_format { | 38 | struct tw686x_format { |
| 41 | char *name; | 39 | char *name; |
| 42 | unsigned int fourcc; | 40 | unsigned int fourcc; |
| @@ -50,6 +48,12 @@ struct tw686x_dma_desc { · 7 unmodified lines | |||
| 50 | unsigned int size; | 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 | struct tw686x_audio_buf { | 57 | struct tw686x_audio_buf { |
| 54 | dma_addr_t dma; | 58 | dma_addr_t dma; |
| 55 | void *virt; | 59 | void *virt; |
| @@ -82,6 +86,7 @@ struct tw686x_video_channel { · 26 unmodified lines | |||
| 82 | struct video_device *device; | 86 | struct video_device *device; |
| 83 | struct tw686x_v4l2_buf *curr_bufs[2]; | 87 | struct tw686x_v4l2_buf *curr_bufs[2]; |
| 84 | struct tw686x_dma_desc dma_descs[2]; | 88 | struct tw686x_dma_desc dma_descs[2]; |
| 89 | struct tw686x_sg_desc *sg_descs[2]; | ||
| 85 | 90 | ||
| 86 | struct v4l2_ctrl_handler ctrl_handler; | 91 | struct v4l2_ctrl_handler ctrl_handler; |
| 87 | const struct tw686x_format *format; | 92 | const struct tw686x_format *format; |
| @@ -99,6 +104,16 @@ struct tw686x_video_channel { · 11 unmodified lines | |||
| 99 | bool no_signal; | 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 | * struct tw686x_dev - global device status | 118 | * struct tw686x_dev - global device status |
| 104 | * @lock: spinlock controlling access to the | 119 | * @lock: spinlock controlling access to the |
| @@ -112,15 +127,18 @@ struct tw686x_dev { · 7 unmodified lines | |||
| 112 | 127 | ||
| 113 | char name[32]; | 128 | char name[32]; |
| 114 | unsigned int type; | 129 | unsigned int type; |
| 130 | unsigned int dma_mode; | ||
| 115 | struct pci_dev *pci_dev; | 131 | struct pci_dev *pci_dev; |
| 116 | __u32 __iomem *mmio; | 132 | __u32 __iomem *mmio; |
| 117 | 133 | ||
| 118 | void *alloc_ctx; | 134 | const struct tw686x_dma_ops *dma_ops; |
| 119 | |||
| 120 | struct tw686x_video_channel *video_channels; | 135 | struct tw686x_video_channel *video_channels; |
| 121 | struct tw686x_audio_channel *audio_channels; | 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 | struct timer_list dma_delay_timer; | 143 | struct timer_list dma_delay_timer; |
| 126 | u32 pending_dma_en; /* must be protected by lock */ | 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 | return dev->type & TYPE_MAX_CHANNELS; /* 4 or 8 channels */ | 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 | void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel); | 170 | void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel); |
| 147 | void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel); | 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 | //TODO// | 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 | static void | 249 | static void |
| 254 | zr36016_init (struct zr36016 *ptr) | 250 | zr36016_init (struct zr36016 *ptr) |
| 255 | { | 251 | { |
| @@ -110,6 +110,7 @@ source "drivers/media/platform/exynos4-is/Kconfig" · 109 unmodified lines | |||
| 110 | source "drivers/media/platform/s5p-tv/Kconfig" | 110 | source "drivers/media/platform/s5p-tv/Kconfig" |
| 111 | source "drivers/media/platform/am437x/Kconfig" | 111 | source "drivers/media/platform/am437x/Kconfig" |
| 112 | source "drivers/media/platform/xilinx/Kconfig" | 112 | source "drivers/media/platform/xilinx/Kconfig" |
| 113 | source "drivers/media/platform/rcar-vin/Kconfig" | ||
| 113 | 114 | ||
| 114 | config VIDEO_TI_CAL | 115 | config VIDEO_TI_CAL |
| 115 | tristate "TI CAL (Camera Adaptation Layer) driver" | 116 | tristate "TI CAL (Camera Adaptation Layer) driver" |
| @@ -152,6 +153,36 @@ config VIDEO_CODA · 36 unmodified lines | |||
| 152 | Coda is a range of video codec IPs that supports | 153 | Coda is a range of video codec IPs that supports |
| 153 | H.264, MPEG-4, and other video formats. | 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 | config VIDEO_MEM2MEM_DEINTERLACE | 186 | config VIDEO_MEM2MEM_DEINTERLACE |
| 156 | tristate "Deinterlace support" | 187 | tristate "Deinterlace support" |
| 157 | depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE | 188 | depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE |
| @@ -247,10 +278,24 @@ config VIDEO_RENESAS_JPU · 89 unmodified lines | |||
| 247 | To compile this driver as a module, choose M here: the module | 278 | To compile this driver as a module, choose M here: the module |
| 248 | will be called rcar_jpu. | 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 | config VIDEO_RENESAS_VSP1 | 294 | config VIDEO_RENESAS_VSP1 |
| 251 | tristate "Renesas VSP1 Video Processing Engine" | 295 | tristate "Renesas VSP1 Video Processing Engine" |
| 252 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA | 296 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA |
| 253 | depends on (ARCH_RENESAS && OF) || COMPILE_TEST | 297 | depends on (ARCH_RENESAS && OF) || COMPILE_TEST |
| 298 | depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP | ||
| 254 | select VIDEOBUF2_DMA_CONTIG | 299 | select VIDEOBUF2_DMA_CONTIG |
| 255 | ---help--- | 300 | ---help--- |
| 256 | This is a V4L2 driver for the Renesas VSP1 video processing engine. | 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 | obj-$(CONFIG_SOC_CAMERA) += soc_camera/ | 47 | obj-$(CONFIG_SOC_CAMERA) += soc_camera/ |
| 48 | 48 | ||
| 49 | obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o | ||
| 49 | obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o | 50 | obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o |
| 50 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ | 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 | obj-$(CONFIG_VIDEO_XILINX) += xilinx/ | 57 | obj-$(CONFIG_VIDEO_XILINX) += xilinx/ |
| 57 | 58 | ||
| 59 | obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin/ | ||
| 60 | |||
| 58 | ccflags-y += -I$(srctree)/drivers/media/i2c | 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 | * @nbuffers: ptr to number of buffers requested by application | 1901 | * @nbuffers: ptr to number of buffers requested by application |
| 1902 | * @nplanes:: contains number of distinct video planes needed to hold a frame | 1902 | * @nplanes:: contains number of distinct video planes needed to hold a frame |
| 1903 | * @sizes[]: contains the size (in bytes) of each plane. | 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 | * This callback function is called when reqbuf() is called to adjust | 1906 | * This callback function is called when reqbuf() is called to adjust |
| 1907 | * the buffer count and buffer size | 1907 | * the buffer count and buffer size |
| 1908 | */ | 1908 | */ |
| 1909 | static int vpfe_queue_setup(struct vb2_queue *vq, | 1909 | static int vpfe_queue_setup(struct vb2_queue *vq, |
| 1910 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | struct vpfe_device *vpfe = vb2_get_drv_priv(vq); | 1913 | struct vpfe_device *vpfe = vb2_get_drv_priv(vq); |
| 1914 | unsigned size = vpfe->fmt.fmt.pix.sizeimage; | 1914 | unsigned size = vpfe->fmt.fmt.pix.sizeimage; |
| 1915 | 1915 | ||
| 1916 | if (vq->num_buffers + *nbuffers < 3) | 1916 | if (vq->num_buffers + *nbuffers < 3) |
| 1917 | *nbuffers = 3 - vq->num_buffers; | 1917 | *nbuffers = 3 - vq->num_buffers; |
| 1918 | alloc_ctxs[0] = vpfe->alloc_ctx; | ||
| 1919 | 1918 | ||
| 1920 | if (*nplanes) { | 1919 | if (*nplanes) { |
| 1921 | if (sizes[0] < size) | 1920 | if (sizes[0] < size) |
| @@ -2364,13 +2363,6 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe) · 442 unmodified lines | |||
| 2364 | goto probe_out; | 2363 | goto probe_out; |
| 2365 | 2364 | ||
| 2366 | /* Initialize videobuf2 queue as per the buffer type */ | 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 | q = &vpfe->buffer_queue; | 2366 | q = &vpfe->buffer_queue; |
| 2375 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 2367 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 2376 | q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; | 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 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 2373 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 2382 | q->lock = &vpfe->lock; | 2374 | q->lock = &vpfe->lock; |
| 2383 | q->min_buffers_needed = 1; | 2375 | q->min_buffers_needed = 1; |
| 2376 | q->dev = vpfe->pdev; | ||
| 2384 | 2377 | ||
| 2385 | err = vb2_queue_init(q); | 2378 | err = vb2_queue_init(q); |
| 2386 | if (err) { | 2379 | if (err) { |
| 2387 | vpfe_err(vpfe, "vb2_queue_init() failed\n"); | 2380 | vpfe_err(vpfe, "vb2_queue_init() failed\n"); |
| 2388 | vb2_dma_contig_cleanup_ctx(vpfe->alloc_ctx); | ||
| 2389 | goto probe_out; | 2381 | goto probe_out; |
| 2390 | } | 2382 | } |
| 2391 | 2383 | ||
| @@ -264,8 +264,6 @@ struct vpfe_device { · 263 unmodified lines | |||
| 264 | struct v4l2_rect crop; | 264 | struct v4l2_rect crop; |
| 265 | /* Buffer queue used in video-buf */ | 265 | /* Buffer queue used in video-buf */ |
| 266 | struct vb2_queue buffer_queue; | 266 | struct vb2_queue buffer_queue; |
| 267 | /* Allocator-specific contexts for each plane */ | ||
| 268 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 269 | /* Queue of filled frames */ | 267 | /* Queue of filled frames */ |
| 270 | struct list_head dma_queue; | 268 | struct list_head dma_queue; |
| 271 | /* IRQ lock for DMA queue */ | 269 | /* IRQ lock for DMA queue */ |
| @@ -91,8 +91,6 @@ struct bcap_device { · 90 unmodified lines | |||
| 91 | struct bcap_buffer *cur_frm; | 91 | struct bcap_buffer *cur_frm; |
| 92 | /* buffer queue used in videobuf2 */ | 92 | /* buffer queue used in videobuf2 */ |
| 93 | struct vb2_queue buffer_queue; | 93 | struct vb2_queue buffer_queue; |
| 94 | /* allocator-specific contexts for each plane */ | ||
| 95 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 96 | /* queue of filled frames */ | 94 | /* queue of filled frames */ |
| 97 | struct list_head dma_queue; | 95 | struct list_head dma_queue; |
| 98 | /* used in videobuf2 callback */ | 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 | static int bcap_queue_setup(struct vb2_queue *vq, | 202 | static int bcap_queue_setup(struct vb2_queue *vq, |
| 205 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); | 206 | struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); |
| 209 | 207 | ||
| 210 | if (vq->num_buffers + *nbuffers < 2) | 208 | if (vq->num_buffers + *nbuffers < 2) |
| 211 | *nbuffers = 2; | 209 | *nbuffers = 2; |
| 212 | alloc_ctxs[0] = bcap_dev->alloc_ctx; | ||
| 213 | 210 | ||
| 214 | if (*nplanes) | 211 | if (*nplanes) |
| 215 | return sizes[0] < bcap_dev->fmt.sizeimage ? -EINVAL : 0; | 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 | bcap_dev->ppi->priv = bcap_dev; | 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 | vfd = &bcap_dev->video_dev; | 820 | vfd = &bcap_dev->video_dev; |
| 830 | /* initialize field of video device */ | 821 | /* initialize field of video device */ |
| 831 | vfd->release = video_device_release_empty; | 822 | vfd->release = video_device_release_empty; |
| @@ -839,7 +830,7 @@ static int bcap_probe(struct platform_device *pdev) · 7 unmodified lines | |||
| 839 | if (ret) { | 830 | if (ret) { |
| 840 | v4l2_err(pdev->dev.driver, | 831 | v4l2_err(pdev->dev.driver, |
| 841 | "Unable to register v4l2 device\n"); | 832 | "Unable to register v4l2 device\n"); |
| 842 | goto err_cleanup_ctx; | 833 | goto err_free_ppi; |
| 843 | } | 834 | } |
| 844 | v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n"); | 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 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 854 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 864 | q->lock = &bcap_dev->mutex; | 855 | q->lock = &bcap_dev->mutex; |
| 865 | q->min_buffers_needed = 1; | 856 | q->min_buffers_needed = 1; |
| 857 | q->dev = &pdev->dev; | ||
| 866 | 858 | ||
| 867 | ret = vb2_queue_init(q); | 859 | ret = vb2_queue_init(q); |
| 868 | if (ret) | 860 | if (ret) |
| @@ -967,8 +959,6 @@ err_free_handler: · 98 unmodified lines | |||
| 967 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); | 959 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); |
| 968 | err_unreg_v4l2: | 960 | err_unreg_v4l2: |
| 969 | v4l2_device_unregister(&bcap_dev->v4l2_dev); | 961 | v4l2_device_unregister(&bcap_dev->v4l2_dev); |
| 970 | err_cleanup_ctx: | ||
| 971 | vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); | ||
| 972 | err_free_ppi: | 962 | err_free_ppi: |
| 973 | ppi_delete_instance(bcap_dev->ppi); | 963 | ppi_delete_instance(bcap_dev->ppi); |
| 974 | err_free_dev: | 964 | err_free_dev: |
| @@ -986,7 +976,6 @@ static int bcap_remove(struct platform_device *pdev) · 11 unmodified lines | |||
| 986 | video_unregister_device(&bcap_dev->video_dev); | 976 | video_unregister_device(&bcap_dev->video_dev); |
| 987 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); | 977 | v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); |
| 988 | v4l2_device_unregister(v4l2_dev); | 978 | v4l2_device_unregister(v4l2_dev); |
| 989 | vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); | ||
| 990 | ppi_delete_instance(bcap_dev->ppi); | 979 | ppi_delete_instance(bcap_dev->ppi); |
| 991 | kfree(bcap_dev); | 980 | kfree(bcap_dev); |
| 992 | return 0; | 981 | return 0; |
| @@ -1139,7 +1139,7 @@ static void set_default_params(struct coda_ctx *ctx) · 1138 unmodified lines | |||
| 1139 | */ | 1139 | */ |
| 1140 | static int coda_queue_setup(struct vb2_queue *vq, | 1140 | static int coda_queue_setup(struct vb2_queue *vq, |
| 1141 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | struct coda_ctx *ctx = vb2_get_drv_priv(vq); | 1144 | struct coda_ctx *ctx = vb2_get_drv_priv(vq); |
| 1145 | struct coda_q_data *q_data; | 1145 | struct coda_q_data *q_data; |
| @@ -1151,9 +1151,6 @@ static int coda_queue_setup(struct vb2_queue *vq, · 5 unmodified lines | |||
| 1151 | *nplanes = 1; | 1151 | *nplanes = 1; |
| 1152 | sizes[0] = size; | 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 | v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, | 1154 | v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, |
| 1158 | "get %d buffer(s) of size %d each.\n", *nbuffers, size); | 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 | * that videobuf2 will keep the value of bytesused intact. | 1596 | * that videobuf2 will keep the value of bytesused intact. |
| 1600 | */ | 1597 | */ |
| 1601 | vq->allow_zero_bytesused = 1; | 1598 | vq->allow_zero_bytesused = 1; |
| 1599 | vq->dev = &ctx->dev->plat_dev->dev; | ||
| 1602 | 1600 | ||
| 1603 | return vb2_queue_init(vq); | 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 | if (ret < 0) | 2038 | if (ret < 0) |
| 2041 | goto put_pm; | 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 | dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops); | 2041 | dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops); |
| 2050 | if (IS_ERR(dev->m2m_dev)) { | 2042 | if (IS_ERR(dev->m2m_dev)) { |
| 2051 | v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); | 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 | for (i = 0; i < dev->devtype->num_vdevs; i++) { | 2047 | for (i = 0; i < dev->devtype->num_vdevs; i++) { |
| @@ -2072,8 +2064,6 @@ rel_vfd: · 16 unmodified lines | |||
| 2072 | while (--i >= 0) | 2064 | while (--i >= 0) |
| 2073 | video_unregister_device(&dev->vfd[i]); | 2065 | video_unregister_device(&dev->vfd[i]); |
| 2074 | v4l2_m2m_release(dev->m2m_dev); | 2066 | v4l2_m2m_release(dev->m2m_dev); |
| 2075 | rel_ctx: | ||
| 2076 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); | ||
| 2077 | put_pm: | 2067 | put_pm: |
| 2078 | pm_runtime_put_sync(&pdev->dev); | 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 | dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL); | 2216 | dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL); |
| 2227 | if (IS_ERR(dev->rstc)) { | 2217 | if (IS_ERR(dev->rstc)) { |
| 2228 | ret = PTR_ERR(dev->rstc); | 2218 | ret = PTR_ERR(dev->rstc); |
| 2229 | if (ret == -ENOENT || ret == -ENOSYS) { | 2219 | if (ret == -ENOENT || ret == -ENOTSUPP) { |
| 2230 | dev->rstc = NULL; | 2220 | dev->rstc = NULL; |
| 2231 | } else { | 2221 | } else { |
| 2232 | dev_err(&pdev->dev, "failed get reset control: %d\n", | 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 | if (dev->m2m_dev) | 2314 | if (dev->m2m_dev) |
| 2325 | v4l2_m2m_release(dev->m2m_dev); | 2315 | v4l2_m2m_release(dev->m2m_dev); |
| 2326 | pm_runtime_disable(&pdev->dev); | 2316 | pm_runtime_disable(&pdev->dev); |
| 2327 | if (dev->alloc_ctx) | ||
| 2328 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); | ||
| 2329 | v4l2_device_unregister(&dev->v4l2_dev); | 2317 | v4l2_device_unregister(&dev->v4l2_dev); |
| 2330 | destroy_workqueue(dev->workqueue); | 2318 | destroy_workqueue(dev->workqueue); |
| 2331 | if (dev->iram.vaddr) | 2319 | if (dev->iram.vaddr) |
| @@ -92,7 +92,6 @@ struct coda_dev { · 91 unmodified lines | |||
| 92 | struct mutex coda_mutex; | 92 | struct mutex coda_mutex; |
| 93 | struct workqueue_struct *workqueue; | 93 | struct workqueue_struct *workqueue; |
| 94 | struct v4l2_m2m_dev *m2m_dev; | 94 | struct v4l2_m2m_dev *m2m_dev; |
| 95 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 96 | struct list_head instances; | 95 | struct list_head instances; |
| 97 | unsigned long instance_mask; | 96 | unsigned long instance_mask; |
| 98 | struct dentry *debugfs_root; | 97 | struct dentry *debugfs_root; |
| @@ -80,13 +80,6 @@ struct ccdc_hw_ops { · 79 unmodified lines | |||
| 80 | /* Pointer to function to get line length */ | 80 | /* Pointer to function to get line length */ |
| 81 | unsigned int (*get_line_length) (void); | 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 | /* Pointer to function to set frame buffer address */ | 83 | /* Pointer to function to set frame buffer address */ |
| 91 | void (*setfbaddr) (unsigned long addr); | 84 | void (*setfbaddr) (unsigned long addr); |
| 92 | /* Pointer to function to get field id */ | 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 | static int | 230 | static int |
| 231 | vpbe_buffer_queue_setup(struct vb2_queue *vq, | 231 | vpbe_buffer_queue_setup(struct vb2_queue *vq, |
| 232 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | /* Get the file handle object and layer object */ | 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 | /* Store number of buffers allocated in numbuffer member */ | 242 | /* Store number of buffers allocated in numbuffer member */ |
| 243 | if (vq->num_buffers + *nbuffers < VPBE_DEFAULT_NUM_BUFS) | 243 | if (vq->num_buffers + *nbuffers < VPBE_DEFAULT_NUM_BUFS) |
| 244 | *nbuffers = VPBE_DEFAULT_NUM_BUFS - vq->num_buffers; | 244 | *nbuffers = VPBE_DEFAULT_NUM_BUFS - vq->num_buffers; |
| 245 | alloc_ctxs[0] = layer->alloc_ctx; | ||
| 246 | 245 | ||
| 247 | if (*nplanes) | 246 | if (*nplanes) |
| 248 | return sizes[0] < layer->pix_fmt.sizeimage ? -EINVAL : 0; | 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 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1450 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1452 | q->min_buffers_needed = 1; | 1451 | q->min_buffers_needed = 1; |
| 1453 | q->lock = &disp_dev->dev[i]->opslock; | 1452 | q->lock = &disp_dev->dev[i]->opslock; |
| 1453 | q->dev = disp_dev->vpbe_dev->pdev; | ||
| 1454 | err = vb2_queue_init(q); | 1454 | err = vb2_queue_init(q); |
| 1455 | if (err) { | 1455 | if (err) { |
| 1456 | v4l2_err(v4l2_dev, "vb2_queue_init() failed\n"); | 1456 | v4l2_err(v4l2_dev, "vb2_queue_init() failed\n"); |
| 1457 | goto probe_out; | 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 | INIT_LIST_HEAD(&disp_dev->dev[i]->dma_queue); | 1460 | INIT_LIST_HEAD(&disp_dev->dev[i]->dma_queue); |
| 1469 | 1461 | ||
| 1470 | if (register_device(disp_dev->dev[i], disp_dev, pdev)) { | 1462 | if (register_device(disp_dev->dev[i], disp_dev, pdev)) { |
| @@ -1482,7 +1474,6 @@ probe_out: · 11 unmodified lines | |||
| 1482 | for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { | 1474 | for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { |
| 1483 | /* Unregister video device */ | 1475 | /* Unregister video device */ |
| 1484 | if (disp_dev->dev[k] != NULL) { | 1476 | if (disp_dev->dev[k] != NULL) { |
| 1485 | vb2_dma_contig_cleanup_ctx(disp_dev->dev[k]->alloc_ctx); | ||
| 1486 | video_unregister_device(&disp_dev->dev[k]->video_dev); | 1477 | video_unregister_device(&disp_dev->dev[k]->video_dev); |
| 1487 | kfree(disp_dev->dev[k]); | 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 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { | 1501 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { |
| 1511 | /* Get the pointer to the layer object */ | 1502 | /* Get the pointer to the layer object */ |
| 1512 | vpbe_display_layer = disp_dev->dev[i]; | 1503 | vpbe_display_layer = disp_dev->dev[i]; |
| 1513 | vb2_dma_contig_cleanup_ctx(vpbe_display_layer->alloc_ctx); | ||
| 1514 | /* Unregister video device */ | 1504 | /* Unregister video device */ |
| 1515 | video_unregister_device(&vpbe_display_layer->video_dev); | 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 | * @nbuffers: ptr to number of buffers requested by application | 107 | * @nbuffers: ptr to number of buffers requested by application |
| 108 | * @nplanes:: contains number of distinct video planes needed to hold a frame | 108 | * @nplanes:: contains number of distinct video planes needed to hold a frame |
| 109 | * @sizes[]: contains the size (in bytes) of each plane. | 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 | * This callback function is called when reqbuf() is called to adjust | 112 | * This callback function is called when reqbuf() is called to adjust |
| 113 | * the buffer count and buffer size | 113 | * the buffer count and buffer size |
| 114 | */ | 114 | */ |
| 115 | static int vpif_buffer_queue_setup(struct vb2_queue *vq, | 115 | static int vpif_buffer_queue_setup(struct vb2_queue *vq, |
| 116 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | struct channel_obj *ch = vb2_get_drv_priv(vq); | 119 | struct channel_obj *ch = vb2_get_drv_priv(vq); |
| 120 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | 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 | *nplanes = 1; | 134 | *nplanes = 1; |
| 135 | sizes[0] = size; | 135 | sizes[0] = size; |
| 136 | alloc_ctxs[0] = common->alloc_ctx; | ||
| 137 | 136 | ||
| 138 | /* Calculate the offset for Y and C data in the buffer */ | 137 | /* Calculate the offset for Y and C data in the buffer */ |
| 139 | vpif_calculate_offsets(ch); | 138 | vpif_calculate_offsets(ch); |
| @@ -1371,6 +1370,7 @@ static int vpif_probe_complete(void) · 1231 unmodified lines | |||
| 1371 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1370 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1372 | q->min_buffers_needed = 1; | 1371 | q->min_buffers_needed = 1; |
| 1373 | q->lock = &common->lock; | 1372 | q->lock = &common->lock; |
| 1373 | q->dev = vpif_dev; | ||
| 1374 | 1374 | ||
| 1375 | err = vb2_queue_init(q); | 1375 | err = vb2_queue_init(q); |
| 1376 | if (err) { | 1376 | if (err) { |
| @@ -1378,13 +1378,6 @@ static int vpif_probe_complete(void) · 1 unmodified line | |||
| 1378 | goto probe_out; | 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 | INIT_LIST_HEAD(&common->dma_queue); | 1381 | INIT_LIST_HEAD(&common->dma_queue); |
| 1389 | 1382 | ||
| 1390 | /* Initialize the video_device structure */ | 1383 | /* Initialize the video_device structure */ |
| @@ -1412,7 +1405,6 @@ probe_out: · 21 unmodified lines | |||
| 1412 | /* Get the pointer to the channel object */ | 1405 | /* Get the pointer to the channel object */ |
| 1413 | ch = vpif_obj.dev[k]; | 1406 | ch = vpif_obj.dev[k]; |
| 1414 | common = &ch->common[k]; | 1407 | common = &ch->common[k]; |
| 1415 | vb2_dma_contig_cleanup_ctx(common->alloc_ctx); | ||
| 1416 | /* Unregister video device */ | 1408 | /* Unregister video device */ |
| 1417 | video_unregister_device(&ch->video_dev); | 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 | /* Get the pointer to the channel object */ | 1538 | /* Get the pointer to the channel object */ |
| 1547 | ch = vpif_obj.dev[i]; | 1539 | ch = vpif_obj.dev[i]; |
| 1548 | common = &ch->common[VPIF_VIDEO_INDEX]; | 1540 | common = &ch->common[VPIF_VIDEO_INDEX]; |
| 1549 | vb2_dma_contig_cleanup_ctx(common->alloc_ctx); | ||
| 1550 | /* Unregister video device */ | 1541 | /* Unregister video device */ |
| 1551 | video_unregister_device(&ch->video_dev); | 1542 | video_unregister_device(&ch->video_dev); |
| 1552 | kfree(vpif_obj.dev[i]); | 1543 | kfree(vpif_obj.dev[i]); |
| @@ -65,8 +65,6 @@ struct common_obj { · 64 unmodified lines | |||
| 65 | struct v4l2_format fmt; | 65 | struct v4l2_format fmt; |
| 66 | /* Buffer queue used in video-buf */ | 66 | /* Buffer queue used in video-buf */ |
| 67 | struct vb2_queue buffer_queue; | 67 | struct vb2_queue buffer_queue; |
| 68 | /* allocator-specific contexts for each plane */ | ||
| 69 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 70 | /* Queue of filled frames */ | 68 | /* Queue of filled frames */ |
| 71 | struct list_head dma_queue; | 69 | struct list_head dma_queue; |
| 72 | /* Used in video-buf */ | 70 | /* Used in video-buf */ |
| @@ -102,14 +102,14 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb) · 101 unmodified lines | |||
| 102 | * @nbuffers: ptr to number of buffers requested by application | 102 | * @nbuffers: ptr to number of buffers requested by application |
| 103 | * @nplanes:: contains number of distinct video planes needed to hold a frame | 103 | * @nplanes:: contains number of distinct video planes needed to hold a frame |
| 104 | * @sizes[]: contains the size (in bytes) of each plane. | 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 | * This callback function is called when reqbuf() is called to adjust | 107 | * This callback function is called when reqbuf() is called to adjust |
| 108 | * the buffer count and buffer size | 108 | * the buffer count and buffer size |
| 109 | */ | 109 | */ |
| 110 | static int vpif_buffer_queue_setup(struct vb2_queue *vq, | 110 | static int vpif_buffer_queue_setup(struct vb2_queue *vq, |
| 111 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | struct channel_obj *ch = vb2_get_drv_priv(vq); | 114 | struct channel_obj *ch = vb2_get_drv_priv(vq); |
| 115 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | 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 | *nplanes = 1; | 127 | *nplanes = 1; |
| 128 | sizes[0] = size; | 128 | sizes[0] = size; |
| 129 | alloc_ctxs[0] = common->alloc_ctx; | ||
| 130 | 129 | ||
| 131 | /* Calculate the offset for Y and C data in the buffer */ | 130 | /* Calculate the offset for Y and C data in the buffer */ |
| 132 | vpif_calculate_offsets(ch); | 131 | vpif_calculate_offsets(ch); |
| @@ -1191,19 +1190,13 @@ static int vpif_probe_complete(void) · 1058 unmodified lines | |||
| 1191 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1190 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1192 | q->min_buffers_needed = 1; | 1191 | q->min_buffers_needed = 1; |
| 1193 | q->lock = &common->lock; | 1192 | q->lock = &common->lock; |
| 1193 | q->dev = vpif_dev; | ||
| 1194 | err = vb2_queue_init(q); | 1194 | err = vb2_queue_init(q); |
| 1195 | if (err) { | 1195 | if (err) { |
| 1196 | vpif_err("vpif_display: vb2_queue_init() failed\n"); | 1196 | vpif_err("vpif_display: vb2_queue_init() failed\n"); |
| 1197 | goto probe_out; | 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 | INIT_LIST_HEAD(&common->dma_queue); | 1200 | INIT_LIST_HEAD(&common->dma_queue); |
| 1208 | 1201 | ||
| 1209 | /* register video device */ | 1202 | /* register video device */ |
| @@ -1233,7 +1226,6 @@ probe_out: · 23 unmodified lines | |||
| 1233 | for (k = 0; k < j; k++) { | 1226 | for (k = 0; k < j; k++) { |
| 1234 | ch = vpif_obj.dev[k]; | 1227 | ch = vpif_obj.dev[k]; |
| 1235 | common = &ch->common[k]; | 1228 | common = &ch->common[k]; |
| 1236 | vb2_dma_contig_cleanup_ctx(common->alloc_ctx); | ||
| 1237 | video_unregister_device(&ch->video_dev); | 1229 | video_unregister_device(&ch->video_dev); |
| 1238 | } | 1230 | } |
| 1239 | return err; | 1231 | return err; |
| @@ -1355,7 +1347,6 @@ static int vpif_remove(struct platform_device *device) · 115 unmodified lines | |||
| 1355 | /* Get the pointer to the channel object */ | 1347 | /* Get the pointer to the channel object */ |
| 1356 | ch = vpif_obj.dev[i]; | 1348 | ch = vpif_obj.dev[i]; |
| 1357 | common = &ch->common[VPIF_VIDEO_INDEX]; | 1349 | common = &ch->common[VPIF_VIDEO_INDEX]; |
| 1358 | vb2_dma_contig_cleanup_ctx(common->alloc_ctx); | ||
| 1359 | /* Unregister video device */ | 1350 | /* Unregister video device */ |
| 1360 | video_unregister_device(&ch->video_dev); | 1351 | video_unregister_device(&ch->video_dev); |
| 1361 | kfree(vpif_obj.dev[i]); | 1352 | kfree(vpif_obj.dev[i]); |
| @@ -74,8 +74,6 @@ struct common_obj { · 73 unmodified lines | |||
| 74 | struct v4l2_format fmt; /* Used to store the format */ | 74 | struct v4l2_format fmt; /* Used to store the format */ |
| 75 | struct vb2_queue buffer_queue; /* Buffer queue used in | 75 | struct vb2_queue buffer_queue; /* Buffer queue used in |
| 76 | * video-buf */ | 76 | * video-buf */ |
| 77 | /* allocator-specific contexts for each plane */ | ||
| 78 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 79 | 77 | ||
| 80 | struct list_head dma_queue; /* Queue of filled frames */ | 78 | struct list_head dma_queue; /* Queue of filled frames */ |
| 81 | spinlock_t irqlock; /* Used in video-buf */ | 79 | spinlock_t irqlock; /* Used in video-buf */ |
| @@ -1123,19 +1123,13 @@ static int gsc_probe(struct platform_device *pdev) · 1122 unmodified lines | |||
| 1123 | if (ret < 0) | 1123 | if (ret < 0) |
| 1124 | goto err_m2m; | 1124 | goto err_m2m; |
| 1125 | 1125 | ||
| 1126 | /* Initialize continious memory allocator */ | 1126 | vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); |
| 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 | } | ||
| 1132 | 1127 | ||
| 1133 | dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id); | 1128 | dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id); |
| 1134 | 1129 | ||
| 1135 | pm_runtime_put(dev); | 1130 | pm_runtime_put(dev); |
| 1136 | return 0; | 1131 | return 0; |
| 1137 | err_pm: | 1132 | |
| 1138 | pm_runtime_put(dev); | ||
| 1139 | err_m2m: | 1133 | err_m2m: |
| 1140 | gsc_unregister_m2m_device(gsc); | 1134 | gsc_unregister_m2m_device(gsc); |
| 1141 | err_v4l2: | 1135 | err_v4l2: |
| @@ -1152,7 +1146,7 @@ static int gsc_remove(struct platform_device *pdev) · 10 unmodified lines | |||
| 1152 | gsc_unregister_m2m_device(gsc); | 1146 | gsc_unregister_m2m_device(gsc); |
| 1153 | v4l2_device_unregister(&gsc->v4l2_dev); | 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 | pm_runtime_disable(&pdev->dev); | 1150 | pm_runtime_disable(&pdev->dev); |
| 1157 | gsc_clk_put(gsc); | 1151 | gsc_clk_put(gsc); |
| 1158 | 1152 | ||
| @@ -327,7 +327,6 @@ struct gsc_driverdata { · 326 unmodified lines | |||
| 327 | * @irq_queue: interrupt handler waitqueue | 327 | * @irq_queue: interrupt handler waitqueue |
| 328 | * @m2m: memory-to-memory V4L2 device information | 328 | * @m2m: memory-to-memory V4L2 device information |
| 329 | * @state: flags used to synchronize m2m and capture mode operation | 329 | * @state: flags used to synchronize m2m and capture mode operation |
| 330 | * @alloc_ctx: videobuf2 memory allocator context | ||
| 331 | * @vdev: video device for G-Scaler instance | 330 | * @vdev: video device for G-Scaler instance |
| 332 | */ | 331 | */ |
| 333 | struct gsc_dev { | 332 | struct gsc_dev { |
| @@ -341,7 +340,6 @@ struct gsc_dev { · 7 unmodified lines | |||
| 341 | wait_queue_head_t irq_queue; | 340 | wait_queue_head_t irq_queue; |
| 342 | struct gsc_m2m_device m2m; | 341 | struct gsc_m2m_device m2m; |
| 343 | unsigned long state; | 342 | unsigned long state; |
| 344 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 345 | struct video_device vdev; | 343 | struct video_device vdev; |
| 346 | struct v4l2_device v4l2_dev; | 344 | struct v4l2_device v4l2_dev; |
| 347 | }; | 345 | }; |
| @@ -213,7 +213,7 @@ put_device: · 212 unmodified lines | |||
| 213 | 213 | ||
| 214 | static int gsc_m2m_queue_setup(struct vb2_queue *vq, | 214 | static int gsc_m2m_queue_setup(struct vb2_queue *vq, |
| 215 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct gsc_ctx *ctx = vb2_get_drv_priv(vq); | 218 | struct gsc_ctx *ctx = vb2_get_drv_priv(vq); |
| 219 | struct gsc_frame *frame; | 219 | struct gsc_frame *frame; |
| @@ -227,10 +227,8 @@ static int gsc_m2m_queue_setup(struct vb2_queue *vq, · 7 unmodified lines | |||
| 227 | return -EINVAL; | 227 | return -EINVAL; |
| 228 | 228 | ||
| 229 | *num_planes = frame->fmt->num_planes; | 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 | sizes[i] = frame->payload[i]; | 231 | sizes[i] = frame->payload[i]; |
| 232 | allocators[i] = ctx->gsc_dev->alloc_ctx; | ||
| 233 | } | ||
| 234 | return 0; | 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 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | 589 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
| 592 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 590 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 593 | src_vq->lock = &ctx->gsc_dev->lock; | 591 | src_vq->lock = &ctx->gsc_dev->lock; |
| 592 | src_vq->dev = &ctx->gsc_dev->pdev->dev; | ||
| 594 | 593 | ||
| 595 | ret = vb2_queue_init(src_vq); | 594 | ret = vb2_queue_init(src_vq); |
| 596 | if (ret) | 595 | if (ret) |
| @@ -605,6 +604,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, · 8 unmodified lines | |||
| 605 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | 604 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
| 606 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 605 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 607 | dst_vq->lock = &ctx->gsc_dev->lock; | 606 | dst_vq->lock = &ctx->gsc_dev->lock; |
| 607 | dst_vq->dev = &ctx->gsc_dev->pdev->dev; | ||
| 608 | 608 | ||
| 609 | return vb2_queue_init(dst_vq); | 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 | static int queue_setup(struct vb2_queue *vq, | 341 | static int queue_setup(struct vb2_queue *vq, |
| 342 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct fimc_ctx *ctx = vq->drv_priv; | 345 | struct fimc_ctx *ctx = vq->drv_priv; |
| 346 | struct fimc_frame *frame = &ctx->d_frame; | 346 | struct fimc_frame *frame = &ctx->d_frame; |
| @@ -354,11 +354,9 @@ static int queue_setup(struct vb2_queue *vq, · 7 unmodified lines | |||
| 354 | if (*num_planes) { | 354 | if (*num_planes) { |
| 355 | if (*num_planes != fmt->memplanes) | 355 | if (*num_planes != fmt->memplanes) |
| 356 | return -EINVAL; | 356 | return -EINVAL; |
| 357 | for (i = 0; i < *num_planes; i++) { | 357 | for (i = 0; i < *num_planes; i++) |
| 358 | if (sizes[i] < (wh * fmt->depth[i]) / 8) | 358 | if (sizes[i] < (wh * fmt->depth[i]) / 8) |
| 359 | return -EINVAL; | 359 | return -EINVAL; |
| 360 | allocators[i] = ctx->fimc_dev->alloc_ctx; | ||
| 361 | } | ||
| 362 | return 0; | 360 | return 0; |
| 363 | } | 361 | } |
| 364 | 362 | ||
| @@ -371,8 +369,6 @@ static int queue_setup(struct vb2_queue *vq, · 6 unmodified lines | |||
| 371 | sizes[i] = frame->payload[i]; | 369 | sizes[i] = frame->payload[i]; |
| 372 | else | 370 | else |
| 373 | sizes[i] = max_t(u32, size, frame->payload[i]); | 371 | sizes[i] = max_t(u32, size, frame->payload[i]); |
| 374 | |||
| 375 | allocators[i] = ctx->fimc_dev->alloc_ctx; | ||
| 376 | } | 372 | } |
| 377 | 373 | ||
| 378 | return 0; | 374 | return 0; |
| @@ -1779,6 +1775,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, · 1400 unmodified lines | |||
| 1779 | q->buf_struct_size = sizeof(struct fimc_vid_buffer); | 1775 | q->buf_struct_size = sizeof(struct fimc_vid_buffer); |
| 1780 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1776 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1781 | q->lock = &fimc->lock; | 1777 | q->lock = &fimc->lock; |
| 1778 | q->dev = &fimc->pdev->dev; | ||
| 1782 | 1779 | ||
| 1783 | ret = vb2_queue_init(q); | 1780 | ret = vb2_queue_init(q); |
| 1784 | if (ret) | 1781 | if (ret) |
| @@ -1018,19 +1018,11 @@ static int fimc_probe(struct platform_device *pdev) · 1017 unmodified lines | |||
| 1018 | goto err_sd; | 1018 | goto err_sd; |
| 1019 | } | 1019 | } |
| 1020 | 1020 | ||
| 1021 | /* Initialize contiguous memory allocator */ | 1021 | vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); |
| 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 | } | ||
| 1027 | 1022 | ||
| 1028 | dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id); | 1023 | dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id); |
| 1029 | return 0; | 1024 | return 0; |
| 1030 | 1025 | ||
| 1031 | err_gclk: | ||
| 1032 | if (!pm_runtime_enabled(dev)) | ||
| 1033 | clk_disable(fimc->clock[CLK_GATE]); | ||
| 1034 | err_sd: | 1026 | err_sd: |
| 1035 | fimc_unregister_capture_subdev(fimc); | 1027 | fimc_unregister_capture_subdev(fimc); |
| 1036 | err_sclk: | 1028 | err_sclk: |
| @@ -1123,7 +1115,7 @@ static int fimc_remove(struct platform_device *pdev) · 86 unmodified lines | |||
| 1123 | pm_runtime_set_suspended(&pdev->dev); | 1115 | pm_runtime_set_suspended(&pdev->dev); |
| 1124 | 1116 | ||
| 1125 | fimc_unregister_capture_subdev(fimc); | 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 | clk_disable(fimc->clock[CLK_BUS]); | 1120 | clk_disable(fimc->clock[CLK_BUS]); |
| 1129 | fimc_clk_put(fimc); | 1121 | fimc_clk_put(fimc); |
| @@ -307,7 +307,6 @@ struct fimc_m2m_device { · 306 unmodified lines | |||
| 307 | */ | 307 | */ |
| 308 | struct fimc_vid_cap { | 308 | struct fimc_vid_cap { |
| 309 | struct fimc_ctx *ctx; | 309 | struct fimc_ctx *ctx; |
| 310 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 311 | struct v4l2_subdev subdev; | 310 | struct v4l2_subdev subdev; |
| 312 | struct exynos_video_entity ve; | 311 | struct exynos_video_entity ve; |
| 313 | struct media_pad vd_pad; | 312 | struct media_pad vd_pad; |
| @@ -417,7 +416,6 @@ struct fimc_ctx; · 103 unmodified lines | |||
| 417 | * @m2m: memory-to-memory V4L2 device information | 416 | * @m2m: memory-to-memory V4L2 device information |
| 418 | * @vid_cap: camera capture device information | 417 | * @vid_cap: camera capture device information |
| 419 | * @state: flags used to synchronize m2m and capture mode operation | 418 | * @state: flags used to synchronize m2m and capture mode operation |
| 420 | * @alloc_ctx: videobuf2 memory allocator context | ||
| 421 | * @pipeline: fimc video capture pipeline data structure | 419 | * @pipeline: fimc video capture pipeline data structure |
| 422 | */ | 420 | */ |
| 423 | struct fimc_dev { | 421 | struct fimc_dev { |
| @@ -436,7 +434,6 @@ struct fimc_dev { · 12 unmodified lines | |||
| 436 | struct fimc_m2m_device m2m; | 434 | struct fimc_m2m_device m2m; |
| 437 | struct fimc_vid_cap vid_cap; | 435 | struct fimc_vid_cap vid_cap; |
| 438 | unsigned long state; | 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 | if (ret < 0) | 204 | if (ret < 0) |
| 205 | return ret; | 205 | return ret; |
| 206 | 206 | ||
| 207 | /* Initialize memory allocator context for the ISP DMA. */ | ||
| 208 | is->isp.alloc_ctx = is->alloc_ctx; | ||
| 209 | |||
| 210 | for_each_compatible_node(i2c_bus, NULL, FIMC_IS_I2C_COMPATIBLE) { | 207 | for_each_compatible_node(i2c_bus, NULL, FIMC_IS_I2C_COMPATIBLE) { |
| 211 | for_each_available_child_of_node(i2c_bus, child) { | 208 | for_each_available_child_of_node(i2c_bus, child) { |
| 212 | ret = fimc_is_parse_sensor_config(is, index, child); | 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 | if (ret < 0) | 844 | if (ret < 0) |
| 848 | goto err_pm; | 845 | goto err_pm; |
| 849 | 846 | ||
| 850 | is->alloc_ctx = vb2_dma_contig_init_ctx(dev); | 847 | vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); |
| 851 | if (IS_ERR(is->alloc_ctx)) { | ||
| 852 | ret = PTR_ERR(is->alloc_ctx); | ||
| 853 | goto err_pm; | ||
| 854 | } | ||
| 855 | /* | 848 | /* |
| 856 | * Register FIMC-IS V4L2 subdevs to this driver. The video nodes | 849 | * Register FIMC-IS V4L2 subdevs to this driver. The video nodes |
| 857 | * will be created within the subdev's registered() callback. | 850 | * will be created within the subdev's registered() callback. |
| 858 | */ | 851 | */ |
| 859 | ret = fimc_is_register_subdevs(is); | 852 | ret = fimc_is_register_subdevs(is); |
| 860 | if (ret < 0) | 853 | if (ret < 0) |
| 861 | goto err_vb; | 854 | goto err_pm; |
| 862 | 855 | ||
| 863 | ret = fimc_is_debugfs_create(is); | 856 | ret = fimc_is_debugfs_create(is); |
| 864 | if (ret < 0) | 857 | if (ret < 0) |
| @@ -877,8 +870,6 @@ err_dfs: · 12 unmodified lines | |||
| 877 | fimc_is_debugfs_remove(is); | 870 | fimc_is_debugfs_remove(is); |
| 878 | err_sd: | 871 | err_sd: |
| 879 | fimc_is_unregister_subdevs(is); | 872 | fimc_is_unregister_subdevs(is); |
| 880 | err_vb: | ||
| 881 | vb2_dma_contig_cleanup_ctx(is->alloc_ctx); | ||
| 882 | err_pm: | 873 | err_pm: |
| 883 | if (!pm_runtime_enabled(dev)) | 874 | if (!pm_runtime_enabled(dev)) |
| 884 | fimc_is_runtime_suspend(dev); | 875 | fimc_is_runtime_suspend(dev); |
| @@ -939,7 +930,7 @@ static int fimc_is_remove(struct platform_device *pdev) · 54 unmodified lines | |||
| 939 | fimc_is_runtime_suspend(dev); | 930 | fimc_is_runtime_suspend(dev); |
| 940 | free_irq(is->irq, is); | 931 | free_irq(is->irq, is); |
| 941 | fimc_is_unregister_subdevs(is); | 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 | fimc_is_put_clocks(is); | 934 | fimc_is_put_clocks(is); |
| 944 | fimc_is_debugfs_remove(is); | 935 | fimc_is_debugfs_remove(is); |
| 945 | release_firmware(is->fw.f_w); | 936 | release_firmware(is->fw.f_w); |
| @@ -233,7 +233,6 @@ struct chain_config { · 232 unmodified lines | |||
| 233 | * @pdev: pointer to FIMC-IS platform device | 233 | * @pdev: pointer to FIMC-IS platform device |
| 234 | * @pctrl: pointer to pinctrl structure for this device | 234 | * @pctrl: pointer to pinctrl structure for this device |
| 235 | * @v4l2_dev: pointer to top the level v4l2_device | 235 | * @v4l2_dev: pointer to top the level v4l2_device |
| 236 | * @alloc_ctx: videobuf2 memory allocator context | ||
| 237 | * @lock: mutex serializing video device and the subdev operations | 236 | * @lock: mutex serializing video device and the subdev operations |
| 238 | * @slock: spinlock protecting this data structure and the hw registers | 237 | * @slock: spinlock protecting this data structure and the hw registers |
| 239 | * @clocks: FIMC-LITE gate clock | 238 | * @clocks: FIMC-LITE gate clock |
| @@ -256,7 +255,6 @@ struct fimc_is { · 16 unmodified lines | |||
| 256 | struct fimc_is_sensor sensor[FIMC_IS_SENSORS_NUM]; | 255 | struct fimc_is_sensor sensor[FIMC_IS_SENSORS_NUM]; |
| 257 | struct fimc_is_setfile setfile; | 256 | struct fimc_is_setfile setfile; |
| 258 | 257 | ||
| 259 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 260 | struct v4l2_ctrl_handler ctrl_handler; | 258 | struct v4l2_ctrl_handler ctrl_handler; |
| 261 | 259 | ||
| 262 | struct mutex lock; | 260 | struct mutex lock; |
| @@ -40,7 +40,7 @@ · 39 unmodified lines | |||
| 40 | 40 | ||
| 41 | static int isp_video_capture_queue_setup(struct vb2_queue *vq, | 41 | static int isp_video_capture_queue_setup(struct vb2_queue *vq, |
| 42 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct fimc_isp *isp = vb2_get_drv_priv(vq); | 45 | struct fimc_isp *isp = vb2_get_drv_priv(vq); |
| 46 | struct v4l2_pix_format_mplane *vid_fmt = &isp->video_capture.pixfmt; | 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 | if (*num_planes) { | 57 | if (*num_planes) { |
| 58 | if (*num_planes != fmt->memplanes) | 58 | if (*num_planes != fmt->memplanes) |
| 59 | return -EINVAL; | 59 | return -EINVAL; |
| 60 | for (i = 0; i < *num_planes; i++) { | 60 | for (i = 0; i < *num_planes; i++) |
| 61 | if (sizes[i] < (wh * fmt->depth[i]) / 8) | 61 | if (sizes[i] < (wh * fmt->depth[i]) / 8) |
| 62 | return -EINVAL; | 62 | return -EINVAL; |
| 63 | allocators[i] = isp->alloc_ctx; | ||
| 64 | } | ||
| 65 | return 0; | 63 | return 0; |
| 66 | } | 64 | } |
| 67 | 65 | ||
| 68 | *num_planes = fmt->memplanes; | 66 | *num_planes = fmt->memplanes; |
| 69 | 67 | ||
| 70 | for (i = 0; i < fmt->memplanes; i++) { | 68 | for (i = 0; i < fmt->memplanes; i++) |
| 71 | sizes[i] = (wh * fmt->depth[i]) / 8; | 69 | sizes[i] = (wh * fmt->depth[i]) / 8; |
| 72 | allocators[i] = isp->alloc_ctx; | ||
| 73 | } | ||
| 74 | 70 | ||
| 75 | return 0; | 71 | return 0; |
| 76 | } | 72 | } |
| @@ -597,6 +593,7 @@ int fimc_isp_video_device_register(struct fimc_isp *isp, · 520 unmodified lines | |||
| 597 | q->drv_priv = isp; | 593 | q->drv_priv = isp; |
| 598 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 594 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 599 | q->lock = &isp->video_lock; | 595 | q->lock = &isp->video_lock; |
| 596 | q->dev = &isp->pdev->dev; | ||
| 600 | 597 | ||
| 601 | ret = vb2_queue_init(q); | 598 | ret = vb2_queue_init(q); |
| 602 | if (ret < 0) | 599 | if (ret < 0) |
| @@ -148,7 +148,6 @@ struct fimc_is_video { · 147 unmodified lines | |||
| 148 | /** | 148 | /** |
| 149 | * struct fimc_isp - FIMC-IS ISP data structure | 149 | * struct fimc_isp - FIMC-IS ISP data structure |
| 150 | * @pdev: pointer to FIMC-IS platform device | 150 | * @pdev: pointer to FIMC-IS platform device |
| 151 | * @alloc_ctx: videobuf2 memory allocator context | ||
| 152 | * @subdev: ISP v4l2_subdev | 151 | * @subdev: ISP v4l2_subdev |
| 153 | * @subdev_pads: the ISP subdev media pads | 152 | * @subdev_pads: the ISP subdev media pads |
| 154 | * @test_pattern: test pattern controls | 153 | * @test_pattern: test pattern controls |
| @@ -161,7 +160,6 @@ struct fimc_is_video { · 6 unmodified lines | |||
| 161 | */ | 160 | */ |
| 162 | struct fimc_isp { | 161 | struct fimc_isp { |
| 163 | struct platform_device *pdev; | 162 | struct platform_device *pdev; |
| 164 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 165 | struct v4l2_subdev subdev; | 163 | struct v4l2_subdev subdev; |
| 166 | struct media_pad subdev_pads[FIMC_ISP_SD_PADS_NUM]; | 164 | struct media_pad subdev_pads[FIMC_ISP_SD_PADS_NUM]; |
| 167 | struct v4l2_mbus_framefmt src_fmt; | 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 | static int queue_setup(struct vb2_queue *vq, | 358 | static int queue_setup(struct vb2_queue *vq, |
| 359 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct fimc_lite *fimc = vq->drv_priv; | 362 | struct fimc_lite *fimc = vq->drv_priv; |
| 363 | struct flite_frame *frame = &fimc->out_frame; | 363 | struct flite_frame *frame = &fimc->out_frame; |
| @@ -371,20 +371,16 @@ static int queue_setup(struct vb2_queue *vq, · 7 unmodified lines | |||
| 371 | if (*num_planes) { | 371 | if (*num_planes) { |
| 372 | if (*num_planes != fmt->memplanes) | 372 | if (*num_planes != fmt->memplanes) |
| 373 | return -EINVAL; | 373 | return -EINVAL; |
| 374 | for (i = 0; i < *num_planes; i++) { | 374 | for (i = 0; i < *num_planes; i++) |
| 375 | if (sizes[i] < (wh * fmt->depth[i]) / 8) | 375 | if (sizes[i] < (wh * fmt->depth[i]) / 8) |
| 376 | return -EINVAL; | 376 | return -EINVAL; |
| 377 | allocators[i] = fimc->alloc_ctx; | ||
| 378 | } | ||
| 379 | return 0; | 377 | return 0; |
| 380 | } | 378 | } |
| 381 | 379 | ||
| 382 | *num_planes = fmt->memplanes; | 380 | *num_planes = fmt->memplanes; |
| 383 | 381 | ||
| 384 | for (i = 0; i < fmt->memplanes; i++) { | 382 | for (i = 0; i < fmt->memplanes; i++) |
| 385 | sizes[i] = (wh * fmt->depth[i]) / 8; | 383 | sizes[i] = (wh * fmt->depth[i]) / 8; |
| 386 | allocators[i] = fimc->alloc_ctx; | ||
| 387 | } | ||
| 388 | 384 | ||
| 389 | return 0; | 385 | return 0; |
| 390 | } | 386 | } |
| @@ -1300,6 +1296,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) · 909 unmodified lines | |||
| 1300 | q->drv_priv = fimc; | 1296 | q->drv_priv = fimc; |
| 1301 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1297 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1302 | q->lock = &fimc->lock; | 1298 | q->lock = &fimc->lock; |
| 1299 | q->dev = &fimc->pdev->dev; | ||
| 1303 | 1300 | ||
| 1304 | ret = vb2_queue_init(q); | 1301 | ret = vb2_queue_init(q); |
| 1305 | if (ret < 0) | 1302 | if (ret < 0) |
| @@ -1551,11 +1548,7 @@ static int fimc_lite_probe(struct platform_device *pdev) · 245 unmodified lines | |||
| 1551 | goto err_sd; | 1548 | goto err_sd; |
| 1552 | } | 1549 | } |
| 1553 | 1550 | ||
| 1554 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); | 1551 | vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); |
| 1555 | if (IS_ERR(fimc->alloc_ctx)) { | ||
| 1556 | ret = PTR_ERR(fimc->alloc_ctx); | ||
| 1557 | goto err_clk_dis; | ||
| 1558 | } | ||
| 1559 | 1552 | ||
| 1560 | fimc_lite_set_default_config(fimc); | 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 | fimc->index); | 1556 | fimc->index); |
| 1564 | return 0; | 1557 | return 0; |
| 1565 | 1558 | ||
| 1566 | err_clk_dis: | ||
| 1567 | if (!pm_runtime_enabled(dev)) | ||
| 1568 | clk_disable(fimc->clock); | ||
| 1569 | err_sd: | 1559 | err_sd: |
| 1570 | fimc_lite_unregister_capture_subdev(fimc); | 1560 | fimc_lite_unregister_capture_subdev(fimc); |
| 1571 | err_clk_put: | 1561 | err_clk_put: |
| @@ -1651,7 +1641,7 @@ static int fimc_lite_remove(struct platform_device *pdev) · 79 unmodified lines | |||
| 1651 | pm_runtime_disable(dev); | 1641 | pm_runtime_disable(dev); |
| 1652 | pm_runtime_set_suspended(dev); | 1642 | pm_runtime_set_suspended(dev); |
| 1653 | fimc_lite_unregister_capture_subdev(fimc); | 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 | fimc_lite_clk_put(fimc); | 1645 | fimc_lite_clk_put(fimc); |
| 1656 | 1646 | ||
| 1657 | dev_info(dev, "Driver unloaded\n"); | 1647 | dev_info(dev, "Driver unloaded\n"); |
| @@ -113,7 +113,6 @@ struct flite_buffer { · 112 unmodified lines | |||
| 113 | * @ve: exynos video device entity structure | 113 | * @ve: exynos video device entity structure |
| 114 | * @v4l2_dev: pointer to top the level v4l2_device | 114 | * @v4l2_dev: pointer to top the level v4l2_device |
| 115 | * @fh: v4l2 file handle | 115 | * @fh: v4l2 file handle |
| 116 | * @alloc_ctx: videobuf2 memory allocator context | ||
| 117 | * @subdev: FIMC-LITE subdev | 116 | * @subdev: FIMC-LITE subdev |
| 118 | * @vd_pad: media (sink) pad for the capture video node | 117 | * @vd_pad: media (sink) pad for the capture video node |
| 119 | * @subdev_pads: the subdev media pads | 118 | * @subdev_pads: the subdev media pads |
| @@ -148,7 +147,6 @@ struct fimc_lite { · 28 unmodified lines | |||
| 148 | struct exynos_video_entity ve; | 147 | struct exynos_video_entity ve; |
| 149 | struct v4l2_device *v4l2_dev; | 148 | struct v4l2_device *v4l2_dev; |
| 150 | struct v4l2_fh fh; | 149 | struct v4l2_fh fh; |
| 151 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 152 | struct v4l2_subdev subdev; | 150 | struct v4l2_subdev subdev; |
| 153 | struct media_pad vd_pad; | 151 | struct media_pad vd_pad; |
| 154 | struct media_pad subdev_pads[FLITE_SD_PADS_NUM]; | 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 | src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); | 50 | src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); |
| 51 | dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); | 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 | v4l2_m2m_buf_done(src_vb, vb_state); | 54 | v4l2_m2m_buf_done(src_vb, vb_state); |
| 55 | if (dst_vb) | ||
| 55 | v4l2_m2m_buf_done(dst_vb, vb_state); | 56 | v4l2_m2m_buf_done(dst_vb, vb_state); |
| 57 | if (src_vb && dst_vb) | ||
| 56 | v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev, | 58 | v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev, |
| 57 | ctx->fh.m2m_ctx); | 59 | ctx->fh.m2m_ctx); |
| 58 | } | ||
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | /* Complete the transaction which has been scheduled for execution. */ | 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 | struct fimc_dev *fimc = ctx->fimc_dev; | 65 | struct fimc_dev *fimc = ctx->fimc_dev; |
| 65 | int ret; | ||
| 66 | 66 | ||
| 67 | if (!fimc_m2m_pending(fimc)) | 67 | if (!fimc_m2m_pending(fimc)) |
| 68 | return 0; | 68 | return; |
| 69 | 69 | ||
| 70 | fimc_ctx_state_set(FIMC_CTX_SHUT, ctx); | 70 | fimc_ctx_state_set(FIMC_CTX_SHUT, ctx); |
| 71 | 71 | ||
| 72 | ret = wait_event_timeout(fimc->irq_queue, | 72 | wait_event_timeout(fimc->irq_queue, |
| 73 | !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx), | 73 | !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx), |
| 74 | FIMC_SHUTDOWN_TIMEOUT); | 74 | FIMC_SHUTDOWN_TIMEOUT); |
| 75 | |||
| 76 | return ret == 0 ? -ETIMEDOUT : ret; | ||
| 77 | } | 75 | } |
| 78 | 76 | ||
| 79 | static int start_streaming(struct vb2_queue *q, unsigned int count) | 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 | static void stop_streaming(struct vb2_queue *q) | 86 | static void stop_streaming(struct vb2_queue *q) |
| 89 | { | 87 | { |
| 90 | struct fimc_ctx *ctx = q->drv_priv; | 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 | pm_runtime_put(&ctx->fimc_dev->pdev->dev); | 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 | static int fimc_queue_setup(struct vb2_queue *vq, | 175 | static int fimc_queue_setup(struct vb2_queue *vq, |
| 180 | unsigned int *num_buffers, unsigned int *num_planes, | 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 | struct fimc_ctx *ctx = vb2_get_drv_priv(vq); | 179 | struct fimc_ctx *ctx = vb2_get_drv_priv(vq); |
| 184 | struct fimc_frame *f; | 180 | struct fimc_frame *f; |
| @@ -195,10 +191,8 @@ static int fimc_queue_setup(struct vb2_queue *vq, · 10 unmodified lines | |||
| 195 | return -EINVAL; | 191 | return -EINVAL; |
| 196 | 192 | ||
| 197 | *num_planes = f->fmt->memplanes; | 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 | sizes[i] = f->payload[i]; | 195 | sizes[i] = f->payload[i]; |
| 200 | allocators[i] = ctx->fimc_dev->alloc_ctx; | ||
| 201 | } | ||
| 202 | return 0; | 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 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | 556 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
| 563 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 557 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 564 | src_vq->lock = &ctx->fimc_dev->lock; | 558 | src_vq->lock = &ctx->fimc_dev->lock; |
| 559 | src_vq->dev = &ctx->fimc_dev->pdev->dev; | ||
| 565 | 560 | ||
| 566 | ret = vb2_queue_init(src_vq); | 561 | ret = vb2_queue_init(src_vq); |
| 567 | if (ret) | 562 | if (ret) |
| @@ -575,6 +570,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, · 7 unmodified lines | |||
| 575 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | 570 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
| 576 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 571 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 577 | dst_vq->lock = &ctx->fimc_dev->lock; | 572 | dst_vq->lock = &ctx->fimc_dev->lock; |
| 573 | dst_vq->dev = &ctx->fimc_dev->pdev->dev; | ||
| 578 | 574 | ||
| 579 | return vb2_queue_init(dst_vq); | 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 | return 0; | 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 | static struct v4l2_subdev_core_ops s5pcsis_core_ops = { | 652 | static struct v4l2_subdev_core_ops s5pcsis_core_ops = { |
| 670 | .s_power = s5pcsis_s_power, | 653 | .s_power = s5pcsis_s_power, |
| 671 | .log_status = s5pcsis_log_status, | 654 | .log_status = s5pcsis_log_status, |
| @@ -136,7 +136,6 @@ struct deinterlace_dev { · 135 unmodified lines | |||
| 136 | struct dma_chan *dma_chan; | 136 | struct dma_chan *dma_chan; |
| 137 | 137 | ||
| 138 | struct v4l2_m2m_dev *m2m_dev; | 138 | struct v4l2_m2m_dev *m2m_dev; |
| 139 | struct vb2_alloc_ctx *alloc_ctx; | ||
| 140 | }; | 139 | }; |
| 141 | 140 | ||
| 142 | struct deinterlace_ctx { | 141 | struct deinterlace_ctx { |
| @@ -799,7 +798,7 @@ struct vb2_dc_conf { · 656 unmodified lines | |||
| 799 | 798 | ||
| 800 | static int deinterlace_queue_setup(struct vb2_queue *vq, | 799 | static int deinterlace_queue_setup(struct vb2_queue *vq, |
| 801 | unsigned int *nbuffers, unsigned int *nplanes, | 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 | struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq); | 803 | struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq); |
| 805 | struct deinterlace_q_data *q_data; | 804 | struct deinterlace_q_data *q_data; |
| @@ -820,8 +819,6 @@ static int deinterlace_queue_setup(struct vb2_queue *vq, · 14 unmodified lines | |||
| 820 | *nbuffers = count; | 819 | *nbuffers = count; |
| 821 | sizes[0] = size; | 820 | sizes[0] = size; |
| 822 | 821 | ||
| 823 | alloc_ctxs[0] = ctx->dev->alloc_ctx; | ||
| 824 | |||
| 825 | dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size); | 822 | dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size); |
| 826 | 823 | ||
| 827 | return 0; | 824 | return 0; |
| @@ -874,6 +871,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, · 46 unmodified lines | |||
| 874 | src_vq->ops = &deinterlace_qops; | 871 | src_vq->ops = &deinterlace_qops; |
| 875 | src_vq->mem_ops = &vb2_dma_contig_memops; | 872 | src_vq->mem_ops = &vb2_dma_contig_memops; |
| 876 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 873 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 874 | src_vq->dev = ctx->dev->v4l2_dev.dev; | ||
| 877 | q_data[V4L2_M2M_SRC].fmt = &formats[0]; | 875 | q_data[V4L2_M2M_SRC].fmt = &formats[0]; |
| 878 | q_data[V4L2_M2M_SRC].width = 640; | 876 | q_data[V4L2_M2M_SRC].width = 640; |
| 879 | q_data[V4L2_M2M_SRC].height = 480; | 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 | dst_vq->ops = &deinterlace_qops; | 889 | dst_vq->ops = &deinterlace_qops; |
| 892 | dst_vq->mem_ops = &vb2_dma_contig_memops; | 890 | dst_vq->mem_ops = &vb2_dma_contig_memops; |
| 893 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | 891 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 892 | dst_vq->dev = ctx->dev->v4l2_dev.dev; | ||
| 894 | q_data[V4L2_M2M_DST].fmt = &formats[0]; | 893 | q_data[V4L2_M2M_DST].fmt = &formats[0]; |
| 895 | q_data[V4L2_M2M_DST].width = 640; | 894 | q_data[V4L2_M2M_DST].width = 640; |
| 896 | q_data[V4L2_M2M_DST].height = 480; | 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 | platform_set_drvdata(pdev, pcdev); | 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 | pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops); | 1048 | pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops); |
| 1057 | if (IS_ERR(pcdev->m2m_dev)) { | 1049 | if (IS_ERR(pcdev->m2m_dev)) { |
| 1058 | v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n"); | 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 | err_m2m: | 1057 | err_m2m: |
| 1066 | video_unregister_device(&pcdev->vfd); | 1058 | video_unregister_device(&pcdev->vfd); |
| 1067 | err_ctx: | ||
| 1068 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | ||
| 1069 | unreg_dev: | 1059 | unreg_dev: |
| 1070 | v4l2_device_unregister(&pcdev->v4l2_dev); | 1060 | v4l2_device_unregister(&pcdev->v4l2_dev); |
| 1071 | rel_dma: | 1061 | rel_dma: |
| @@ -1082,7 +1072,6 @@ static int deinterlace_remove(struct platform_device *pdev) · 10 unmodified lines | |||
| 1082 | v4l2_m2m_release(pcdev->m2m_dev); | 1072 | v4l2_m2m_release(pcdev->m2m_dev); |
| 1083 | video_unregister_device(&pcdev->vfd); | 1073 | video_unregister_device(&pcdev->vfd); |
| 1084 | v4l2_device_unregister(&pcdev->v4l2_dev); | 1074 | v4l2_device_unregister(&pcdev->v4l2_dev); |
| 1085 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | ||
| 1086 | dma_release_channel(pcdev->dma_chan); | 1075 | dma_release_channel(pcdev->dma_chan); |
| 1087 | 1076 | ||
| 1088 | return 0; | 1077 | return 0; |
| @@ -973,7 +973,7 @@ static int mcam_cam_set_flip(struct mcam_camera *cam) · 972 unmodified lines | |||
| 973 | memset(&ctrl, 0, sizeof(ctrl)); | 973 | memset(&ctrl, 0, sizeof(ctrl)); |
| 974 | ctrl.id = V4L2_CID_VFLIP; | 974 | ctrl.id = V4L2_CID_VFLIP; |
| 975 | ctrl.value = flip; | 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 | static int mcam_vb_queue_setup(struct vb2_queue *vq, | 1051 | static int mcam_vb_queue_setup(struct vb2_queue *vq, |
| 1052 | unsigned int *nbufs, | 1052 | unsigned int *nbufs, |
| 1053 | unsigned int *num_planes, unsigned int sizes[], | 1053 | unsigned int *num_planes, unsigned int sizes[], |
| 1054 | void *alloc_ctxs[]) | 1054 | struct device *alloc_devs[]) |
| 1055 | { | 1055 | { |
| 1056 | struct mcam_camera *cam = vb2_get_drv_priv(vq); | 1056 | struct mcam_camera *cam = vb2_get_drv_priv(vq); |
| 1057 | int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2; | 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 | if (*nbufs < minbufs) | 1060 | if (*nbufs < minbufs) |
| 1061 | *nbufs = minbufs; | 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 | if (*num_planes) | 1063 | if (*num_planes) |
| 1068 | return sizes[0] < size ? -EINVAL : 0; | 1064 | return sizes[0] < size ? -EINVAL : 0; |
| @@ -1271,6 +1267,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam) · 202 unmodified lines | |||
| 1271 | vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1267 | vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1272 | vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; | 1268 | vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; |
| 1273 | vq->buf_struct_size = sizeof(struct mcam_vb_buffer); | 1269 | vq->buf_struct_size = sizeof(struct mcam_vb_buffer); |
| 1270 | vq->dev = cam->dev; | ||
| 1274 | INIT_LIST_HEAD(&cam->buffers); | 1271 | INIT_LIST_HEAD(&cam->buffers); |
| 1275 | switch (cam->buffer_mode) { | 1272 | switch (cam->buffer_mode) { |
| 1276 | case B_DMA_contig: | 1273 | case B_DMA_contig: |
| @@ -1279,9 +1276,6 @@ static int mcam_setup_vb2(struct mcam_camera *cam) · 2 unmodified lines | |||
| 1279 | vq->mem_ops = &vb2_dma_contig_memops; | 1276 | vq->mem_ops = &vb2_dma_contig_memops; |
| 1280 | cam->dma_setup = mcam_ctlr_dma_contig; | 1277 | cam->dma_setup = mcam_ctlr_dma_contig; |
| 1281 | cam->frame_complete = mcam_dma_contig_done; | 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 | #endif | 1279 | #endif |
| 1286 | break; | 1280 | break; |
| 1287 | case B_DMA_sg: | 1281 | case B_DMA_sg: |
| @@ -1290,9 +1284,6 @@ static int mcam_setup_vb2(struct mcam_camera *cam) · 2 unmodified lines | |||
| 1290 | vq->mem_ops = &vb2_dma_sg_memops; | 1284 | vq->mem_ops = &vb2_dma_sg_memops; |
| 1291 | cam->dma_setup = mcam_ctlr_dma_sg; | 1285 | cam->dma_setup = mcam_ctlr_dma_sg; |
| 1292 | cam->frame_complete = mcam_dma_sg_done; | 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 | #endif | 1287 | #endif |
| 1297 | break; | 1288 | break; |
| 1298 | case B_vmalloc: | 1289 | case B_vmalloc: |
| @@ -1309,18 +1300,6 @@ static int mcam_setup_vb2(struct mcam_camera *cam) · 10 unmodified lines | |||
| 1309 | return vb2_queue_init(vq); | 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 | cam_warn(cam, "Removing a device with users!\n"); | 1854 | cam_warn(cam, "Removing a device with users!\n"); |
| 1876 | mcam_ctlr_power_down(cam); | 1855 | mcam_ctlr_power_down(cam); |
| 1877 | } | 1856 | } |
| 1878 | mcam_cleanup_vb2(cam); | ||
| 1879 | if (cam->buffer_mode == B_vmalloc) | 1857 | if (cam->buffer_mode == B_vmalloc) |
| 1880 | mcam_free_dma_bufs(cam); | 1858 | mcam_free_dma_bufs(cam); |
| 1881 | video_unregister_device(&cam->vdev); | 1859 | video_unregister_device(&cam->vdev); |
| @@ -176,8 +176,6 @@ struct mcam_camera { · 175 unmodified lines | |||
| 176 | 176 | ||
| 177 | /* DMA buffers - DMA modes */ | 177 | /* DMA buffers - DMA modes */ |
| 178 | struct mcam_vb_buffer *vb_bufs[MAX_DMA_BUFS]; | 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 | /* Mode-specific ops, set at open time */ | 180 | /* Mode-specific ops, set at open time */ |
| 183 | void (*dma_setup)(struct mcam_camera *cam); | 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.