All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/14] [dt-bindings] [media] Add document file and driver for Sony CXD2880 DVB-T2/T tuner + demodulator
@ 2017-08-16  4:17 ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:17 UTC (permalink / raw)
  To: akpm, linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari.Takiguchi, Masayuki.Yamamoto,
	Hideki.Nozawa, Kota.Yonezawa, Toshihiko.Matsumoto,
	Satoshi.C.Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

Hi,

This is the patch series (version 3) of Sony CXD2880 DVB-T2/T tuner + demodulator driver.
The driver supports DVB-API and interfaces through SPI.

We have tested the driver on Raspberry Pi 3 and got picture and sound from a media player.

The change history of this patch series is as below.

[Change list]
Changes in V3
(1)Total patch number was changed from 15 to 14,
   due to the all files of [PATCH v2 04/15] were removed.
       drivers/media/dvb-frontends/cxd2880/cxd2880_math.c
          -Removed
       drivers/media/dvb-frontends/cxd2880/cxd2880_math.h
          -Removed

(2)Removed another file.
       drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
          -Removed 

(3)The detail change items of each files are as below.
    [PATCH v3 01/14]
       Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
          -no change
    [PATCH v3 02/14]
       drivers/media/spi/cxd2880-spi.c
          -adjusted of indent spaces
          -removed unnecessary cast
          -changed debugging code
          -changed timeout method
          -modified coding style of if()
          -changed hexadecimal code to lower case. 
    [PATCH v3 03/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880.h
          -no change
       drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
          -changed MASKUPPER/MASKLOWER with GENMASK 
       drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
          -removed definition NULL and SONY_SLEEP
          -changed CXD2880_SLEEP to usleep_range
          -changed cxd2880_atomic_set to atomic_set
          -removed cxd2880_atomic struct and cxd2880_atomic_read
          -changed stop-watch function
          -modified return code
       drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
          -removed unnecessary cast
          -modified return code
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
          -modified return code 
       drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
          -changed CXD2880_SLEEP to usleep_range
          -changed stop-watch function
          -modified return code
       #drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
          -cxd2880_stdlib.h file was removed from V3.
    [PATCH v3 04/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
          -removed unnecessary cast
          -changed cxd2880_memcpy to memcpy
          -modified return code
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
          -modified return code
       drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
          -modified return code
       drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
          -removed unnecessary cast
          -modified return code
       drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
          -modified return code
    [PATCH v3 05/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
          -removed code relevant to ISDB-T
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
          -removed unnecessary cast
          -removed code relevant to ISDB-T
          -changed CXD2880_SLEEP to usleep_range
          -changed cxd2880_memset to memset 
          -changed cxd2880_atomic_set to atomic_set
          -modified return code
          -modified coding style of if()
          -changed to use const values at writing a lot of registers 
           with a command. 
          -changed hexadecimal code to lower case. 
          -adjusted of indent spaces
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
          -removed code relevant to ISDB-T
          -changed cxd2880_atomic struct to atomic_t
          -modified return code
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
          -updated version information
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
          -changed CXD2880_SLEEP to usleep_range
          -removed unnecessary cast
          -modified return code
          -modified coding style of if() 
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
          -modified return code
    [PATCH v3 06/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
          -changed cxd2880_atomic_read to atomic_read
          -changed cxd2880_atomic_set to atomic_set
          -modified return code
          -modified coding style of if() 
       drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
          -modified return code
    [PATCH v3 07/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
          -adjusted indent spaces
          -modified debugging code
          -removed unnecessary cast
          -modified return code
          -modified coding style of if() 
          -modified about measurement period of PER/BER.
          -changed hexadecimal code to lower case. 
    [PATCH v3 08/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
          -no change
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
          -modified return code
          -modified coding style of if() 
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
          -modified return code
    [PATCH v3 09/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
          -changed CXD2880_SLEEP to usleep_range
          -chnaged cxd2880_atomic_set to atomic_set
          -modified return code
          -modified coding style of if() 
       drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
          -modified return code
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
          -removed unnecessary cast
          -changed cxd2880_math_log to intlog10
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
          -modified return code
    [PATCH v3 10/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
          -modified return code
          -modified coding style of if() 
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
          -modified return code
    [PATCH v3 11/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
          -changed CXD2880_SLEEP to usleep_range
          -replaced cxd2880_atomic_set to atomic_set
          -modified return code
          -modified coding style of if()  
       drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
          -modified return code
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
          -removed unnecessary cast
          -changed cxd2880_math_log to intlog10
          -modified return code
          -modified coding style of if() 
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
          -modified return code
    [PATCH v3 12/14]
       drivers/media/dvb-frontends/Makefile
          -no change
       drivers/media/dvb-frontends/cxd2880/Makefile
          -removed cxd2880_math.o \ 
       drivers/media/spi/Makefile
          -no change
    [PATCH v3 13/14]
       drivers/media/dvb-frontends/Kconfig
          -no change
       drivers/media/dvb-frontends/cxd2880/Kconfig
          -no change
       drivers/media/spi/Kconfig
          -no change
    [PATCH v3 14/14]
       MAINTAINERS
          -no change

Changes in V2
(1)[PATCH 2/5], [PATCH 3/5] and [PATCH 4/5] of version 1 were divided to change order and be small size patch.
    Total patch number was changed from 5 to 15

   <Previous>
   The changed or created files of version 1 [PATCH 2/5], [PATCH 3/5] and [PATCH 4/5]:
      [PATCH 2/5]
      drivers/media/spi/Kconfig
      drivers/media/spi/Makefile
      drivers/media/spi/cxd2880-spi.c
      [PATCH 3/5]
      drivers/media/dvb-frontends/Kconfig
      drivers/media/dvb-frontends/Makefile
      drivers/media/dvb-frontends/cxd2880/Kconfig
      drivers/media/dvb-frontends/cxd2880/Makefile
      drivers/media/dvb-frontends/cxd2880/cxd2880.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_math.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_math.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
    [PATCH 4/5]
      drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h

   <New>
   The changed or created files of version 2 from [PATCH v2 02/15] to [PATCH v2 14/15]:
    [PATCH v2 02/15]
      drivers/media/spi/cxd2880-spi.c
    [PATCH v2 03/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
    [PATCH v2 04/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_math.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_math.h
    [PATCH v2 05/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
    [PATCH v2 06/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
    [PATCH v2 07/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
    [PATCH v2 08/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
    [PATCH v2 09/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
    [PATCH v2 10/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
    [PATCH v2 11/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
    [PATCH v2 12/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
    [PATCH v2 13/15]
      drivers/media/dvb-frontends/Makefile
      drivers/media/dvb-frontends/cxd2880/Makefile
      drivers/media/spi/Makefile
    [PATCH v2 14/15]
      drivers/media/dvb-frontends/Kconfig
      drivers/media/dvb-frontends/cxd2880/Kconfig
      drivers/media/spi/Kconfig

(2)Modified PID filter setting.
    drivers/media/spi/cxd2880-spi.c in [PATCH v2 02/15]

(3)Driver version up
    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h in [PATCH v2 06/15]

Thanks,
Takiguchi
---
 Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt        | 14 ++++++++++++++
 drivers/media/spi/cxd2880-spi.c                                     | 697 ++++++++++++++++++++++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880.h                       | 46 +++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_common.c                | 38 ++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_common.h                | 50 ++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c                    | 68 ++++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h                    | 62 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c        | 60 +++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c             | 146 +++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h             |  40 ++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h                   |  51 +++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c            | 130 ++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h            |  43 ++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h                   |   46 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c                | 4030 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h                |  391 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h |   29 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c            |  221 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h            |   52 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c                 | 98 ++++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h                 | 44 ++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c                   | 1879 +++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h                  |   91 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c           | 1115 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h           |   62 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c            |  198 ++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h            |   58 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c       | 1227 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h       |  106 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h                 |  402 ++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c          | 1359 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h          |   82 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c           |  312 +++
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h           |   64 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c      | 2622 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h      |  170 ++
 drivers/media/dvb-frontends/Makefile                                |  1 +
 drivers/media/dvb-frontends/cxd2880/Makefile                        | 20 ++++++++++++++++++++
 drivers/media/spi/Makefile                                          |  5 +++++
 drivers/media/dvb-frontends/Kconfig                                 |  2 ++
 drivers/media/dvb-frontends/cxd2880/Kconfig                         |  6 ++++++
 drivers/media/spi/Kconfig                                           | 14 ++++++++++++++
 MAINTAINERS                                                         | 9 +++++++++

 43 files changed, 16160 insertions(+)

 create mode 100644 Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
 create mode 100644 drivers/media/spi/cxd2880-spi.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/Makefile
 create mode 100644 drivers/media/dvb-frontends/cxd2880/Kconfig
2.11.0

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v3 00/14] [dt-bindings] [media] Add document file and driver for Sony CXD2880 DVB-T2/T tuner + demodulator
@ 2017-08-16  4:17 ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-08-16  4:17 UTC (permalink / raw)
  To: akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
	Yasunari.Takiguchi-7U/KSKJipcs, Masayuki.Yamamoto-7U/KSKJipcs,
	Hideki.Nozawa-7U/KSKJipcs, Kota.Yonezawa-7U/KSKJipcs,
	Toshihiko.Matsumoto-7U/KSKJipcs, Satoshi.C.Watanabe-7U/KSKJipcs

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

Hi,

This is the patch series (version 3) of Sony CXD2880 DVB-T2/T tuner + demodulator driver.
The driver supports DVB-API and interfaces through SPI.

We have tested the driver on Raspberry Pi 3 and got picture and sound from a media player.

The change history of this patch series is as below.

[Change list]
Changes in V3
(1)Total patch number was changed from 15 to 14,
   due to the all files of [PATCH v2 04/15] were removed.
       drivers/media/dvb-frontends/cxd2880/cxd2880_math.c
          -Removed
       drivers/media/dvb-frontends/cxd2880/cxd2880_math.h
          -Removed

(2)Removed another file.
       drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
          -Removed 

(3)The detail change items of each files are as below.
    [PATCH v3 01/14]
       Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
          -no change
    [PATCH v3 02/14]
       drivers/media/spi/cxd2880-spi.c
          -adjusted of indent spaces
          -removed unnecessary cast
          -changed debugging code
          -changed timeout method
          -modified coding style of if()
          -changed hexadecimal code to lower case. 
    [PATCH v3 03/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880.h
          -no change
       drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
          -changed MASKUPPER/MASKLOWER with GENMASK 
       drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
          -removed definition NULL and SONY_SLEEP
          -changed CXD2880_SLEEP to usleep_range
          -changed cxd2880_atomic_set to atomic_set
          -removed cxd2880_atomic struct and cxd2880_atomic_read
          -changed stop-watch function
          -modified return code
       drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
          -removed unnecessary cast
          -modified return code
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
          -modified return code 
       drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
          -changed CXD2880_SLEEP to usleep_range
          -changed stop-watch function
          -modified return code
       #drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
          -cxd2880_stdlib.h file was removed from V3.
    [PATCH v3 04/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
          -removed unnecessary cast
          -changed cxd2880_memcpy to memcpy
          -modified return code
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
          -modified return code
       drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
          -modified return code
       drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
          -removed unnecessary cast
          -modified return code
       drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
          -modified return code
    [PATCH v3 05/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
          -removed code relevant to ISDB-T
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
          -removed unnecessary cast
          -removed code relevant to ISDB-T
          -changed CXD2880_SLEEP to usleep_range
          -changed cxd2880_memset to memset 
          -changed cxd2880_atomic_set to atomic_set
          -modified return code
          -modified coding style of if()
          -changed to use const values at writing a lot of registers 
           with a command. 
          -changed hexadecimal code to lower case. 
          -adjusted of indent spaces
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
          -removed code relevant to ISDB-T
          -changed cxd2880_atomic struct to atomic_t
          -modified return code
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
          -updated version information
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
          -changed CXD2880_SLEEP to usleep_range
          -removed unnecessary cast
          -modified return code
          -modified coding style of if() 
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
          -modified return code
    [PATCH v3 06/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
          -changed cxd2880_atomic_read to atomic_read
          -changed cxd2880_atomic_set to atomic_set
          -modified return code
          -modified coding style of if() 
       drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
          -modified return code
    [PATCH v3 07/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
          -adjusted indent spaces
          -modified debugging code
          -removed unnecessary cast
          -modified return code
          -modified coding style of if() 
          -modified about measurement period of PER/BER.
          -changed hexadecimal code to lower case. 
    [PATCH v3 08/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
          -no change
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
          -modified return code
          -modified coding style of if() 
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
          -modified return code
    [PATCH v3 09/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
          -changed CXD2880_SLEEP to usleep_range
          -chnaged cxd2880_atomic_set to atomic_set
          -modified return code
          -modified coding style of if() 
       drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
          -modified return code
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
          -removed unnecessary cast
          -changed cxd2880_math_log to intlog10
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
          -modified return code
    [PATCH v3 10/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
          -modified return code
          -modified coding style of if() 
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
          -modified return code
    [PATCH v3 11/14]
       drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
          -changed CXD2880_SLEEP to usleep_range
          -replaced cxd2880_atomic_set to atomic_set
          -modified return code
          -modified coding style of if()  
       drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
          -modified return code
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
          -removed unnecessary cast
          -changed cxd2880_math_log to intlog10
          -modified return code
          -modified coding style of if() 
          -changed hexadecimal code to lower case. 
       drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
          -modified return code
    [PATCH v3 12/14]
       drivers/media/dvb-frontends/Makefile
          -no change
       drivers/media/dvb-frontends/cxd2880/Makefile
          -removed cxd2880_math.o \ 
       drivers/media/spi/Makefile
          -no change
    [PATCH v3 13/14]
       drivers/media/dvb-frontends/Kconfig
          -no change
       drivers/media/dvb-frontends/cxd2880/Kconfig
          -no change
       drivers/media/spi/Kconfig
          -no change
    [PATCH v3 14/14]
       MAINTAINERS
          -no change

Changes in V2
(1)[PATCH 2/5], [PATCH 3/5] and [PATCH 4/5] of version 1 were divided to change order and be small size patch.
    Total patch number was changed from 5 to 15

   <Previous>
   The changed or created files of version 1 [PATCH 2/5], [PATCH 3/5] and [PATCH 4/5]:
      [PATCH 2/5]
      drivers/media/spi/Kconfig
      drivers/media/spi/Makefile
      drivers/media/spi/cxd2880-spi.c
      [PATCH 3/5]
      drivers/media/dvb-frontends/Kconfig
      drivers/media/dvb-frontends/Makefile
      drivers/media/dvb-frontends/cxd2880/Kconfig
      drivers/media/dvb-frontends/cxd2880/Makefile
      drivers/media/dvb-frontends/cxd2880/cxd2880.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_math.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_math.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
    [PATCH 4/5]
      drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h

   <New>
   The changed or created files of version 2 from [PATCH v2 02/15] to [PATCH v2 14/15]:
    [PATCH v2 02/15]
      drivers/media/spi/cxd2880-spi.c
    [PATCH v2 03/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
    [PATCH v2 04/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_math.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_math.h
    [PATCH v2 05/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
    [PATCH v2 06/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
    [PATCH v2 07/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
    [PATCH v2 08/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
    [PATCH v2 09/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
    [PATCH v2 10/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
    [PATCH v2 11/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
    [PATCH v2 12/15]
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
      drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
    [PATCH v2 13/15]
      drivers/media/dvb-frontends/Makefile
      drivers/media/dvb-frontends/cxd2880/Makefile
      drivers/media/spi/Makefile
    [PATCH v2 14/15]
      drivers/media/dvb-frontends/Kconfig
      drivers/media/dvb-frontends/cxd2880/Kconfig
      drivers/media/spi/Kconfig

(2)Modified PID filter setting.
    drivers/media/spi/cxd2880-spi.c in [PATCH v2 02/15]

(3)Driver version up
    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h in [PATCH v2 06/15]

Thanks,
Takiguchi
---
 Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt        | 14 ++++++++++++++
 drivers/media/spi/cxd2880-spi.c                                     | 697 ++++++++++++++++++++++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880.h                       | 46 +++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_common.c                | 38 ++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_common.h                | 50 ++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c                    | 68 ++++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h                    | 62 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c        | 60 +++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c             | 146 +++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h             |  40 ++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h                   |  51 +++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c            | 130 ++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h            |  43 ++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h                   |   46 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c                | 4030 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h                |  391 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h |   29 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c            |  221 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h            |   52 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c                 | 98 ++++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h                 | 44 ++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c                   | 1879 +++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h                  |   91 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c           | 1115 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h           |   62 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c            |  198 ++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h            |   58 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c       | 1227 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h       |  106 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h                 |  402 ++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c          | 1359 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h          |   82 ++
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c           |  312 +++
 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h           |   64 +
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c      | 2622 ++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h      |  170 ++
 drivers/media/dvb-frontends/Makefile                                |  1 +
 drivers/media/dvb-frontends/cxd2880/Makefile                        | 20 ++++++++++++++++++++
 drivers/media/spi/Makefile                                          |  5 +++++
 drivers/media/dvb-frontends/Kconfig                                 |  2 ++
 drivers/media/dvb-frontends/cxd2880/Kconfig                         |  6 ++++++
 drivers/media/spi/Kconfig                                           | 14 ++++++++++++++
 MAINTAINERS                                                         | 9 +++++++++

 43 files changed, 16160 insertions(+)

 create mode 100644 Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
 create mode 100644 drivers/media/spi/cxd2880-spi.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/Makefile
 create mode 100644 drivers/media/dvb-frontends/cxd2880/Kconfig
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v3 01/14] [dt-bindings] [media] Add document file for CXD2880 SPI I/F
  2017-08-16  4:17 ` Yasunari.Takiguchi-7U/KSKJipcs
@ 2017-08-16  4:24   ` Yasunari.Takiguchi
  -1 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:24 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

This is the document file for Sony CXD2880 DVB-T2/T tuner + demodulator.
It contains the description of the SPI adapter binding.

No change since version 1. I should have carried the ack forward:
Acked-by: Rob Herring <robh@kernel.org>

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 .../devicetree/bindings/media/spi/sony-cxd2880.txt         | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt

diff --git a/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt b/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
new file mode 100644
index 000000000000..fc5aa263abe5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
@@ -0,0 +1,14 @@
+Sony CXD2880 DVB-T2/T tuner + demodulator driver SPI adapter
+
+Required properties:
+- compatible: Should be "sony,cxd2880".
+- reg: SPI chip select number for the device.
+- spi-max-frequency: Maximum bus speed, should be set to <55000000> (55MHz).
+
+Example:
+
+cxd2880@0 {
+	compatible = "sony,cxd2880";
+	reg = <0>; /* CE0 */
+	spi-max-frequency = <55000000>; /* 55MHz */
+};
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 01/14] [dt-bindings] [media] Add document file for CXD2880 SPI I/F
@ 2017-08-16  4:24   ` Yasunari.Takiguchi
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:24 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

This is the document file for Sony CXD2880 DVB-T2/T tuner + demodulator.
It contains the description of the SPI adapter binding.

No change since version 1. I should have carried the ack forward:
Acked-by: Rob Herring <robh@kernel.org>

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 .../devicetree/bindings/media/spi/sony-cxd2880.txt         | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt

diff --git a/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt b/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
new file mode 100644
index 000000000000..fc5aa263abe5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/spi/sony-cxd2880.txt
@@ -0,0 +1,14 @@
+Sony CXD2880 DVB-T2/T tuner + demodulator driver SPI adapter
+
+Required properties:
+- compatible: Should be "sony,cxd2880".
+- reg: SPI chip select number for the device.
+- spi-max-frequency: Maximum bus speed, should be set to <55000000> (55MHz).
+
+Example:
+
+cxd2880@0 {
+	compatible = "sony,cxd2880";
+	reg = <0>; /* CE0 */
+	spi-max-frequency = <55000000>; /* 55MHz */
+};
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 02/14] [media] cxd2880-spi: Add support for CXD2880 SPI interface
@ 2017-08-16  4:25   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:25 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

This is the SPI adapter part of the driver for the
Sony CXD2880 DVB-T2/T tuner + demodulator.

[Change list]
Changes in V3
   drivers/media/spi/cxd2880-spi.c
      -adjusted of indent spaces
      -removed unnecessary cast
      -changed debugging code
      -changed timeout method
      -modified coding style of if()
      -changed hexadecimal code to lower case. 

Changes in V2
   drivers/media/spi/cxd2880-spi.c
      -Modified PID filter setting.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 drivers/media/spi/cxd2880-spi.c | 697 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 697 insertions(+)
 create mode 100644 drivers/media/spi/cxd2880-spi.c

diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c
new file mode 100644
index 000000000000..961b94daab38
--- /dev/null
+++ b/drivers/media/spi/cxd2880-spi.c
@@ -0,0 +1,697 @@
+/*
+ * cxd2880-spi.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI adapter
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
+
+#include <linux/spi/spi.h>
+#include <linux/jiffies.h>
+
+#include "dvb_demux.h"
+#include "dmxdev.h"
+#include "dvb_frontend.h"
+#include "cxd2880.h"
+
+#define CXD2880_MAX_FILTER_SIZE 32
+#define BURST_WRITE_MAX 128
+#define MAX_TRANS_PACKET 300
+
+struct cxd2880_ts_buf_info {
+	u8 read_ready;
+	u8 almost_full;
+	u8 almost_empty;
+	u8 overflow;
+	u8 underflow;
+	u16 packet_num;
+};
+
+struct cxd2880_pid_config {
+	u8 is_enable;
+	u16 pid;
+};
+
+struct cxd2880_pid_filter_config {
+	u8 is_negative;
+	struct cxd2880_pid_config pid_config[CXD2880_MAX_FILTER_SIZE];
+};
+
+struct cxd2880_dvb_spi {
+	struct dvb_frontend dvb_fe;
+	struct dvb_adapter adapter;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend dmx_fe;
+	struct task_struct *cxd2880_ts_read_thread;
+	struct spi_device *spi;
+	struct mutex spi_mutex; /* For SPI access exclusive control */
+	int feed_count;
+	int all_pid_feed_count;
+	u8 *ts_buf;
+	struct cxd2880_pid_filter_config filter_config;
+};
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int cxd2880_write_spi(struct spi_device *spi, u8 *data, u32 size)
+{
+	struct spi_message msg;
+	struct spi_transfer tx;
+	int ret = 0;
+
+	if ((!spi) || (!data)) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	memset(&tx, 0, sizeof(tx));
+	tx.tx_buf = data;
+	tx.len = size;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&tx, &msg);
+	ret = spi_sync(spi, &msg);
+
+	return ret;
+}
+
+static int cxd2880_write_reg(struct spi_device *spi,
+			     u8 subAddress, const u8 *data, u32 size)
+{
+	u8 send_data[BURST_WRITE_MAX + 4];
+	const u8 *write_data_top = NULL;
+	int ret = 0;
+
+	if ((!spi) || (!data)) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+	if (size > BURST_WRITE_MAX) {
+		pr_err("data size > WRITE_MAX\n");
+		return -EINVAL;
+	}
+
+	if (subAddress + size > 0x100) {
+		pr_err("out of range\n");
+		return -EINVAL;
+	}
+
+	send_data[0] = 0x0e;
+	write_data_top = data;
+
+	while (size > 0) {
+		send_data[1] = subAddress;
+		if (size > 255)
+			send_data[2] = 255;
+		else
+			send_data[2] = (u8)size;
+
+		memcpy(&send_data[3], write_data_top, send_data[2]);
+
+		ret = cxd2880_write_spi(spi, send_data, send_data[2] + 3);
+		if (ret) {
+			pr_err("write spi failed %d\n", ret);
+			break;
+		}
+		subAddress += send_data[2];
+		write_data_top += send_data[2];
+		size -= send_data[2];
+	}
+
+	return ret;
+}
+
+static int cxd2880_spi_read_ts(struct spi_device *spi,
+			       u8 *read_data,
+			       u32 packet_num)
+{
+	int ret = 0;
+	u8 data[3];
+	struct spi_message message;
+	struct spi_transfer transfer[2];
+
+	if ((!spi) || (!read_data) || (!packet_num)) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+	if (packet_num > 0xffff) {
+		pr_err("packet num > 0xffff\n");
+		return -EINVAL;
+	}
+
+	data[0] = 0x10;
+	data[1] = (packet_num >> 8) & 0xff;
+	data[2] = packet_num & 0xff;
+
+	spi_message_init(&message);
+	memset(transfer, 0, sizeof(transfer));
+
+	transfer[0].len = 3;
+	transfer[0].tx_buf = data;
+	spi_message_add_tail(&transfer[0], &message);
+	transfer[1].len = packet_num * 188;
+	transfer[1].rx_buf = read_data;
+	spi_message_add_tail(&transfer[1], &message);
+
+	ret = spi_sync(spi, &message);
+	if (ret)
+		pr_err("spi_write_then_read failed\n");
+
+	return ret;
+}
+
+static int cxd2880_spi_read_ts_buffer_info(struct spi_device *spi,
+					   struct cxd2880_ts_buf_info *info)
+{
+	u8 send_data = 0x20;
+	u8 recv_data[2];
+	int ret = 0;
+
+	if ((!spi) || (!info)) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	ret = spi_write_then_read(spi, &send_data, 1,
+				  recv_data, sizeof(recv_data));
+	if (ret)
+		pr_err("spi_write_then_read failed\n");
+
+	info->read_ready = (recv_data[0] & 0x80) ? 1 : 0;
+	info->almost_full = (recv_data[0] & 0x40) ? 1 : 0;
+	info->almost_empty = (recv_data[0] & 0x20) ? 1 : 0;
+	info->overflow = (recv_data[0] & 0x10) ? 1 : 0;
+	info->underflow = (recv_data[0] & 0x08) ? 1 : 0;
+	info->packet_num = ((recv_data[0] & 0x07) << 8) | recv_data[1];
+
+	return ret;
+}
+
+static int cxd2880_spi_clear_ts_buffer(struct spi_device *spi)
+{
+	u8 data = 0x03;
+	int ret = 0;
+
+	ret = cxd2880_write_spi(spi, &data, 1);
+
+	if (ret)
+		pr_err("write spi failed\n");
+
+	return ret;
+}
+
+static int cxd2880_set_pid_filter(struct spi_device *spi,
+				  struct cxd2880_pid_filter_config *cfg)
+{
+	u8 data[65];
+	int ret = 0;
+
+	if (!spi) {
+		pr_err("ivnalid arg\n");
+		return -EINVAL;
+	}
+
+	data[0] = 0x00;
+	ret = cxd2880_write_reg(spi, 0x00, &data[0], 1);
+	if (ret)
+		return ret;
+	if (!cfg) {
+		data[0] = 0x02;
+		ret = cxd2880_write_reg(spi, 0x50, &data[0], 1);
+		if (ret)
+			return ret;
+	} else {
+		data[0] = cfg->is_negative ? 0x01 : 0x00;
+		{
+			int i = 0;
+			u16 pid = 0;
+
+			for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
+				pid = cfg->pid_config[i].pid;
+				if (cfg->pid_config[i].is_enable) {
+					data[1 + (i * 2)] = (pid >> 8) | 0x20;
+					data[2 + (i * 2)] = pid & 0xff;
+				} else {
+					data[1 + (i * 2)] = 0x00;
+					data[2 + (i * 2)] = 0x00;
+				}
+			}
+		}
+		ret = cxd2880_write_reg(spi, 0x50, data, 65);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int cxd2880_update_pid_filter(struct cxd2880_dvb_spi *dvb_spi,
+				     struct cxd2880_pid_filter_config *cfg,
+				     bool is_all_pid_filter)
+{
+	int ret = 0;
+
+	if ((!dvb_spi) || (!cfg)) {
+		pr_err("invalid arg.\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&dvb_spi->spi_mutex);
+	if (is_all_pid_filter) {
+		struct cxd2880_pid_filter_config tmpcfg;
+
+		memset(&tmpcfg, 0, sizeof(tmpcfg));
+		tmpcfg.is_negative = 1;
+		tmpcfg.pid_config[0].is_enable = 1;
+		tmpcfg.pid_config[0].pid = 0x1fff;
+
+		ret = cxd2880_set_pid_filter(dvb_spi->spi, &tmpcfg);
+	} else {
+		ret = cxd2880_set_pid_filter(dvb_spi->spi, cfg);
+	}
+	mutex_unlock(&dvb_spi->spi_mutex);
+
+	if (ret)
+		pr_err("set_pid_filter failed\n");
+
+	return ret;
+}
+
+static int cxd2880_ts_read(void *arg)
+{
+	struct cxd2880_dvb_spi *dvb_spi = NULL;
+	struct cxd2880_ts_buf_info info;
+	unsigned int elapsed = 0;
+	unsigned long start_time = 0;
+	u32 i;
+	int ret;
+
+	dvb_spi = arg;
+	if (!dvb_spi) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	ret = cxd2880_spi_clear_ts_buffer(dvb_spi->spi);
+	if (ret) {
+		pr_err("set_clear_ts_buffer failed\n");
+		return ret;
+	}
+	start_time = jiffies;
+	while (!kthread_should_stop()) {
+		elapsed = jiffies_to_msecs(jiffies - start_time);
+		ret = cxd2880_spi_read_ts_buffer_info(dvb_spi->spi,
+						      &info);
+		if (ret) {
+			pr_err("spi_read_ts_buffer_info error\n");
+			return ret;
+		}
+
+		if (info.packet_num > MAX_TRANS_PACKET) {
+			for (i = 0; i < info.packet_num / MAX_TRANS_PACKET;
+				i++) {
+				cxd2880_spi_read_ts(dvb_spi->spi,
+						    dvb_spi->ts_buf,
+						    MAX_TRANS_PACKET);
+				dvb_dmx_swfilter(&dvb_spi->demux,
+						 dvb_spi->ts_buf,
+						 MAX_TRANS_PACKET * 188);
+			}
+			start_time = jiffies;
+		} else if ((info.packet_num > 0) && (elapsed >= 500)) {
+			cxd2880_spi_read_ts(dvb_spi->spi,
+					    dvb_spi->ts_buf,
+					    info.packet_num);
+			dvb_dmx_swfilter(&dvb_spi->demux,
+					 dvb_spi->ts_buf,
+					 info.packet_num * 188);
+			start_time = jiffies;
+		} else {
+			usleep_range(10000, 11000);
+		}
+	}
+
+	return 0;
+}
+
+static int cxd2880_start_feed(struct dvb_demux_feed *feed)
+{
+	int ret = 0;
+	int i = 0;
+	struct dvb_demux *demux = NULL;
+	struct cxd2880_dvb_spi *dvb_spi = NULL;
+
+	if (!feed) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	demux = feed->demux;
+	if (!demux) {
+		pr_err("feed->demux is NULL\n");
+		return -EINVAL;
+	}
+	dvb_spi = demux->priv;
+
+	if (dvb_spi->feed_count == CXD2880_MAX_FILTER_SIZE) {
+		pr_err("Exceeded maximum PID count (32).");
+		pr_err("Selected PID cannot be enabled.\n");
+		return -EBUSY;
+	}
+
+	if (feed->pid == 0x2000) {
+		if (dvb_spi->all_pid_feed_count == 0) {
+			ret = cxd2880_update_pid_filter(dvb_spi,
+							&dvb_spi->filter_config,
+							true);
+			if (ret) {
+				pr_err("update pid filter failed\n");
+				return ret;
+			}
+		}
+		dvb_spi->all_pid_feed_count++;
+
+		pr_debug("all PID feed (count = %d)\n",
+			 dvb_spi->all_pid_feed_count);
+	} else {
+		struct cxd2880_pid_filter_config cfgtmp;
+
+		cfgtmp = dvb_spi->filter_config;
+
+		for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
+			if (cfgtmp.pid_config[i].is_enable == 0) {
+				cfgtmp.pid_config[i].is_enable = 1;
+				cfgtmp.pid_config[i].pid = feed->pid;
+				pr_debug("store PID %d to #%d\n",
+					 feed->pid, i);
+				break;
+			}
+		}
+		if (i == CXD2880_MAX_FILTER_SIZE) {
+			pr_err("PID filter is full. Assumed bug.\n");
+			return -EBUSY;
+		}
+		if (!dvb_spi->all_pid_feed_count)
+			ret = cxd2880_update_pid_filter(dvb_spi,
+							&cfgtmp,
+							false);
+		if (ret)
+			return ret;
+
+		dvb_spi->filter_config = cfgtmp;
+	}
+
+	if (dvb_spi->feed_count == 0) {
+		dvb_spi->ts_buf =
+			kmalloc(MAX_TRANS_PACKET * 188,
+				GFP_KERNEL | GFP_DMA);
+		if (!dvb_spi->ts_buf) {
+			pr_err("ts buffer allocate failed\n");
+			memset(&dvb_spi->filter_config, 0,
+			       sizeof(dvb_spi->filter_config));
+			dvb_spi->all_pid_feed_count = 0;
+			return -ENOMEM;
+		}
+		dvb_spi->cxd2880_ts_read_thread = kthread_run(cxd2880_ts_read,
+							      dvb_spi,
+							      "cxd2880_ts_read");
+		if (IS_ERR(dvb_spi->cxd2880_ts_read_thread)) {
+			pr_err("kthread_run failed/\n");
+			kfree(dvb_spi->ts_buf);
+			dvb_spi->ts_buf = NULL;
+			memset(&dvb_spi->filter_config, 0,
+			       sizeof(dvb_spi->filter_config));
+			dvb_spi->all_pid_feed_count = 0;
+			return PTR_ERR(dvb_spi->cxd2880_ts_read_thread);
+		}
+	}
+
+	dvb_spi->feed_count++;
+
+	pr_debug("start feed (count %d)\n", dvb_spi->feed_count);
+	return 0;
+}
+
+static int cxd2880_stop_feed(struct dvb_demux_feed *feed)
+{
+	int i = 0;
+	int ret = 0;
+	struct dvb_demux *demux = NULL;
+	struct cxd2880_dvb_spi *dvb_spi = NULL;
+
+	if (!feed) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	demux = feed->demux;
+	if (!demux) {
+		pr_err("feed->demux is NULL\n");
+		return -EINVAL;
+	}
+	dvb_spi = demux->priv;
+
+	if (!dvb_spi->feed_count) {
+		pr_err("no feed is started\n");
+		return -EINVAL;
+	}
+
+	if (feed->pid == 0x2000) {
+		/*
+		 * Special PID case.
+		 * Number of 0x2000 feed request was stored
+		 * in dvb_spi->all_pid_feed_count.
+		 */
+		if (dvb_spi->all_pid_feed_count <= 0) {
+			pr_err("PID %d not found.\n", feed->pid);
+			return -EINVAL;
+		}
+		dvb_spi->all_pid_feed_count--;
+	} else {
+		struct cxd2880_pid_filter_config cfgtmp;
+
+		cfgtmp = dvb_spi->filter_config;
+
+		for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
+			if (feed->pid == cfgtmp.pid_config[i].pid &&
+			    cfgtmp.pid_config[i].is_enable != 0) {
+				cfgtmp.pid_config[i].is_enable = 0;
+				cfgtmp.pid_config[i].pid = 0;
+				pr_debug("removed PID %d from #%d\n",
+					 feed->pid, i);
+				break;
+			}
+		}
+		dvb_spi->filter_config = cfgtmp;
+
+		if (i == CXD2880_MAX_FILTER_SIZE) {
+			pr_err("PID %d not found\n", feed->pid);
+			return -EINVAL;
+		}
+	}
+
+	ret = cxd2880_update_pid_filter(dvb_spi,
+					&dvb_spi->filter_config,
+					dvb_spi->all_pid_feed_count > 0);
+	dvb_spi->feed_count--;
+
+	if (dvb_spi->feed_count == 0) {
+		int ret_stop = 0;
+
+		ret_stop = kthread_stop(dvb_spi->cxd2880_ts_read_thread);
+		if (ret_stop) {
+			pr_err("'kthread_stop failed. (%d)\n", ret_stop);
+			ret = ret_stop;
+		}
+		kfree(dvb_spi->ts_buf);
+		dvb_spi->ts_buf = NULL;
+	}
+
+	pr_debug("stop feed ok.(count %d)\n", dvb_spi->feed_count);
+
+	return ret;
+}
+
+static const struct of_device_id cxd2880_spi_of_match[] = {
+	{ .compatible = "sony,cxd2880" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, cxd2880_spi_of_match);
+
+static int
+cxd2880_spi_probe(struct spi_device *spi)
+{
+	int ret = 0;
+	struct cxd2880_dvb_spi *dvb_spi = NULL;
+	struct cxd2880_config config;
+
+	if (!spi) {
+		pr_err("invalid arg.\n");
+		return -EINVAL;
+	}
+
+	dvb_spi = kzalloc(sizeof(struct cxd2880_dvb_spi), GFP_KERNEL);
+	if (!dvb_spi)
+		return -ENOMEM;
+
+	dvb_spi->spi = spi;
+	mutex_init(&dvb_spi->spi_mutex);
+	dev_set_drvdata(&spi->dev, dvb_spi);
+	config.spi = spi;
+	config.spi_mutex = &dvb_spi->spi_mutex;
+
+	ret = dvb_register_adapter(&dvb_spi->adapter,
+				   "CXD2880",
+				   THIS_MODULE,
+				   &spi->dev,
+				   adapter_nr);
+	if (ret < 0) {
+		pr_err("dvb_register_adapter() failed\n");
+		goto fail_adapter;
+	}
+
+	if (!dvb_attach(cxd2880_attach, &dvb_spi->dvb_fe, &config)) {
+		pr_err("cxd2880_attach failed\n");
+		goto fail_attach;
+	}
+
+	ret = dvb_register_frontend(&dvb_spi->adapter,
+				    &dvb_spi->dvb_fe);
+	if (ret < 0) {
+		pr_err("dvb_register_frontend() failed\n");
+		goto fail_frontend;
+	}
+
+	dvb_spi->demux.dmx.capabilities = DMX_TS_FILTERING;
+	dvb_spi->demux.priv = dvb_spi;
+	dvb_spi->demux.filternum = CXD2880_MAX_FILTER_SIZE;
+	dvb_spi->demux.feednum = CXD2880_MAX_FILTER_SIZE;
+	dvb_spi->demux.start_feed = cxd2880_start_feed;
+	dvb_spi->demux.stop_feed = cxd2880_stop_feed;
+
+	ret = dvb_dmx_init(&dvb_spi->demux);
+	if (ret < 0) {
+		pr_err("dvb_dmx_init() failed\n");
+		goto fail_dmx;
+	}
+
+	dvb_spi->dmxdev.filternum = CXD2880_MAX_FILTER_SIZE;
+	dvb_spi->dmxdev.demux = &dvb_spi->demux.dmx;
+	dvb_spi->dmxdev.capabilities = 0;
+	ret = dvb_dmxdev_init(&dvb_spi->dmxdev,
+			      &dvb_spi->adapter);
+	if (ret < 0) {
+		pr_err("dvb_dmxdev_init() failed\n");
+		goto fail_dmxdev;
+	}
+
+	dvb_spi->dmx_fe.source = DMX_FRONTEND_0;
+	ret = dvb_spi->demux.dmx.add_frontend(&dvb_spi->demux.dmx,
+					      &dvb_spi->dmx_fe);
+	if (ret < 0) {
+		pr_err("add_frontend() failed\n");
+		goto fail_dmx_fe;
+	}
+
+	ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx,
+						  &dvb_spi->dmx_fe);
+	if (ret < 0) {
+		pr_err("dvb_register_frontend() failed\n");
+		goto fail_fe_conn;
+	}
+
+	pr_info("Sony CXD2880 has successfully attached.\n");
+
+	return 0;
+
+fail_fe_conn:
+	dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx,
+					   &dvb_spi->dmx_fe);
+fail_dmx_fe:
+	dvb_dmxdev_release(&dvb_spi->dmxdev);
+fail_dmxdev:
+	dvb_dmx_release(&dvb_spi->demux);
+fail_dmx:
+	dvb_unregister_frontend(&dvb_spi->dvb_fe);
+fail_frontend:
+	dvb_frontend_detach(&dvb_spi->dvb_fe);
+fail_attach:
+	dvb_unregister_adapter(&dvb_spi->adapter);
+fail_adapter:
+	kfree(dvb_spi);
+	return ret;
+}
+
+static int
+cxd2880_spi_remove(struct spi_device *spi)
+{
+	struct cxd2880_dvb_spi *dvb_spi;
+
+	if (!spi) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	dvb_spi = dev_get_drvdata(&spi->dev);
+
+	if (!dvb_spi) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx,
+					   &dvb_spi->dmx_fe);
+	dvb_dmxdev_release(&dvb_spi->dmxdev);
+	dvb_dmx_release(&dvb_spi->demux);
+	dvb_unregister_frontend(&dvb_spi->dvb_fe);
+	dvb_frontend_detach(&dvb_spi->dvb_fe);
+	dvb_unregister_adapter(&dvb_spi->adapter);
+
+	kfree(dvb_spi);
+	pr_info("cxd2880_spi remove ok.\n");
+
+	return 0;
+}
+
+static const struct spi_device_id cxd2880_spi_id[] = {
+	{ "cxd2880", 0 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, cxd2880_spi_id);
+
+static struct spi_driver cxd2880_spi_driver = {
+	.driver	= {
+		.name	= "cxd2880",
+		.of_match_table = cxd2880_spi_of_match,
+	},
+	.id_table = cxd2880_spi_id,
+	.probe    = cxd2880_spi_probe,
+	.remove   = cxd2880_spi_remove,
+};
+module_spi_driver(cxd2880_spi_driver);
+
+MODULE_DESCRIPTION(
+"Sony CXD2880 DVB-T2/T tuner + demodulator drvier SPI adapter");
+MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
+MODULE_LICENSE("GPL v2");
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 02/14] [media] cxd2880-spi: Add support for CXD2880 SPI interface
@ 2017-08-16  4:25   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-08-16  4:25 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

This is the SPI adapter part of the driver for the
Sony CXD2880 DVB-T2/T tuner + demodulator.

[Change list]
Changes in V3
   drivers/media/spi/cxd2880-spi.c
      -adjusted of indent spaces
      -removed unnecessary cast
      -changed debugging code
      -changed timeout method
      -modified coding style of if()
      -changed hexadecimal code to lower case. 

Changes in V2
   drivers/media/spi/cxd2880-spi.c
      -Modified PID filter setting.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 drivers/media/spi/cxd2880-spi.c | 697 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 697 insertions(+)
 create mode 100644 drivers/media/spi/cxd2880-spi.c

diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c
new file mode 100644
index 000000000000..961b94daab38
--- /dev/null
+++ b/drivers/media/spi/cxd2880-spi.c
@@ -0,0 +1,697 @@
+/*
+ * cxd2880-spi.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI adapter
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
+
+#include <linux/spi/spi.h>
+#include <linux/jiffies.h>
+
+#include "dvb_demux.h"
+#include "dmxdev.h"
+#include "dvb_frontend.h"
+#include "cxd2880.h"
+
+#define CXD2880_MAX_FILTER_SIZE 32
+#define BURST_WRITE_MAX 128
+#define MAX_TRANS_PACKET 300
+
+struct cxd2880_ts_buf_info {
+	u8 read_ready;
+	u8 almost_full;
+	u8 almost_empty;
+	u8 overflow;
+	u8 underflow;
+	u16 packet_num;
+};
+
+struct cxd2880_pid_config {
+	u8 is_enable;
+	u16 pid;
+};
+
+struct cxd2880_pid_filter_config {
+	u8 is_negative;
+	struct cxd2880_pid_config pid_config[CXD2880_MAX_FILTER_SIZE];
+};
+
+struct cxd2880_dvb_spi {
+	struct dvb_frontend dvb_fe;
+	struct dvb_adapter adapter;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend dmx_fe;
+	struct task_struct *cxd2880_ts_read_thread;
+	struct spi_device *spi;
+	struct mutex spi_mutex; /* For SPI access exclusive control */
+	int feed_count;
+	int all_pid_feed_count;
+	u8 *ts_buf;
+	struct cxd2880_pid_filter_config filter_config;
+};
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int cxd2880_write_spi(struct spi_device *spi, u8 *data, u32 size)
+{
+	struct spi_message msg;
+	struct spi_transfer tx;
+	int ret = 0;
+
+	if ((!spi) || (!data)) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	memset(&tx, 0, sizeof(tx));
+	tx.tx_buf = data;
+	tx.len = size;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&tx, &msg);
+	ret = spi_sync(spi, &msg);
+
+	return ret;
+}
+
+static int cxd2880_write_reg(struct spi_device *spi,
+			     u8 subAddress, const u8 *data, u32 size)
+{
+	u8 send_data[BURST_WRITE_MAX + 4];
+	const u8 *write_data_top = NULL;
+	int ret = 0;
+
+	if ((!spi) || (!data)) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+	if (size > BURST_WRITE_MAX) {
+		pr_err("data size > WRITE_MAX\n");
+		return -EINVAL;
+	}
+
+	if (subAddress + size > 0x100) {
+		pr_err("out of range\n");
+		return -EINVAL;
+	}
+
+	send_data[0] = 0x0e;
+	write_data_top = data;
+
+	while (size > 0) {
+		send_data[1] = subAddress;
+		if (size > 255)
+			send_data[2] = 255;
+		else
+			send_data[2] = (u8)size;
+
+		memcpy(&send_data[3], write_data_top, send_data[2]);
+
+		ret = cxd2880_write_spi(spi, send_data, send_data[2] + 3);
+		if (ret) {
+			pr_err("write spi failed %d\n", ret);
+			break;
+		}
+		subAddress += send_data[2];
+		write_data_top += send_data[2];
+		size -= send_data[2];
+	}
+
+	return ret;
+}
+
+static int cxd2880_spi_read_ts(struct spi_device *spi,
+			       u8 *read_data,
+			       u32 packet_num)
+{
+	int ret = 0;
+	u8 data[3];
+	struct spi_message message;
+	struct spi_transfer transfer[2];
+
+	if ((!spi) || (!read_data) || (!packet_num)) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+	if (packet_num > 0xffff) {
+		pr_err("packet num > 0xffff\n");
+		return -EINVAL;
+	}
+
+	data[0] = 0x10;
+	data[1] = (packet_num >> 8) & 0xff;
+	data[2] = packet_num & 0xff;
+
+	spi_message_init(&message);
+	memset(transfer, 0, sizeof(transfer));
+
+	transfer[0].len = 3;
+	transfer[0].tx_buf = data;
+	spi_message_add_tail(&transfer[0], &message);
+	transfer[1].len = packet_num * 188;
+	transfer[1].rx_buf = read_data;
+	spi_message_add_tail(&transfer[1], &message);
+
+	ret = spi_sync(spi, &message);
+	if (ret)
+		pr_err("spi_write_then_read failed\n");
+
+	return ret;
+}
+
+static int cxd2880_spi_read_ts_buffer_info(struct spi_device *spi,
+					   struct cxd2880_ts_buf_info *info)
+{
+	u8 send_data = 0x20;
+	u8 recv_data[2];
+	int ret = 0;
+
+	if ((!spi) || (!info)) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	ret = spi_write_then_read(spi, &send_data, 1,
+				  recv_data, sizeof(recv_data));
+	if (ret)
+		pr_err("spi_write_then_read failed\n");
+
+	info->read_ready = (recv_data[0] & 0x80) ? 1 : 0;
+	info->almost_full = (recv_data[0] & 0x40) ? 1 : 0;
+	info->almost_empty = (recv_data[0] & 0x20) ? 1 : 0;
+	info->overflow = (recv_data[0] & 0x10) ? 1 : 0;
+	info->underflow = (recv_data[0] & 0x08) ? 1 : 0;
+	info->packet_num = ((recv_data[0] & 0x07) << 8) | recv_data[1];
+
+	return ret;
+}
+
+static int cxd2880_spi_clear_ts_buffer(struct spi_device *spi)
+{
+	u8 data = 0x03;
+	int ret = 0;
+
+	ret = cxd2880_write_spi(spi, &data, 1);
+
+	if (ret)
+		pr_err("write spi failed\n");
+
+	return ret;
+}
+
+static int cxd2880_set_pid_filter(struct spi_device *spi,
+				  struct cxd2880_pid_filter_config *cfg)
+{
+	u8 data[65];
+	int ret = 0;
+
+	if (!spi) {
+		pr_err("ivnalid arg\n");
+		return -EINVAL;
+	}
+
+	data[0] = 0x00;
+	ret = cxd2880_write_reg(spi, 0x00, &data[0], 1);
+	if (ret)
+		return ret;
+	if (!cfg) {
+		data[0] = 0x02;
+		ret = cxd2880_write_reg(spi, 0x50, &data[0], 1);
+		if (ret)
+			return ret;
+	} else {
+		data[0] = cfg->is_negative ? 0x01 : 0x00;
+		{
+			int i = 0;
+			u16 pid = 0;
+
+			for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
+				pid = cfg->pid_config[i].pid;
+				if (cfg->pid_config[i].is_enable) {
+					data[1 + (i * 2)] = (pid >> 8) | 0x20;
+					data[2 + (i * 2)] = pid & 0xff;
+				} else {
+					data[1 + (i * 2)] = 0x00;
+					data[2 + (i * 2)] = 0x00;
+				}
+			}
+		}
+		ret = cxd2880_write_reg(spi, 0x50, data, 65);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int cxd2880_update_pid_filter(struct cxd2880_dvb_spi *dvb_spi,
+				     struct cxd2880_pid_filter_config *cfg,
+				     bool is_all_pid_filter)
+{
+	int ret = 0;
+
+	if ((!dvb_spi) || (!cfg)) {
+		pr_err("invalid arg.\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&dvb_spi->spi_mutex);
+	if (is_all_pid_filter) {
+		struct cxd2880_pid_filter_config tmpcfg;
+
+		memset(&tmpcfg, 0, sizeof(tmpcfg));
+		tmpcfg.is_negative = 1;
+		tmpcfg.pid_config[0].is_enable = 1;
+		tmpcfg.pid_config[0].pid = 0x1fff;
+
+		ret = cxd2880_set_pid_filter(dvb_spi->spi, &tmpcfg);
+	} else {
+		ret = cxd2880_set_pid_filter(dvb_spi->spi, cfg);
+	}
+	mutex_unlock(&dvb_spi->spi_mutex);
+
+	if (ret)
+		pr_err("set_pid_filter failed\n");
+
+	return ret;
+}
+
+static int cxd2880_ts_read(void *arg)
+{
+	struct cxd2880_dvb_spi *dvb_spi = NULL;
+	struct cxd2880_ts_buf_info info;
+	unsigned int elapsed = 0;
+	unsigned long start_time = 0;
+	u32 i;
+	int ret;
+
+	dvb_spi = arg;
+	if (!dvb_spi) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	ret = cxd2880_spi_clear_ts_buffer(dvb_spi->spi);
+	if (ret) {
+		pr_err("set_clear_ts_buffer failed\n");
+		return ret;
+	}
+	start_time = jiffies;
+	while (!kthread_should_stop()) {
+		elapsed = jiffies_to_msecs(jiffies - start_time);
+		ret = cxd2880_spi_read_ts_buffer_info(dvb_spi->spi,
+						      &info);
+		if (ret) {
+			pr_err("spi_read_ts_buffer_info error\n");
+			return ret;
+		}
+
+		if (info.packet_num > MAX_TRANS_PACKET) {
+			for (i = 0; i < info.packet_num / MAX_TRANS_PACKET;
+				i++) {
+				cxd2880_spi_read_ts(dvb_spi->spi,
+						    dvb_spi->ts_buf,
+						    MAX_TRANS_PACKET);
+				dvb_dmx_swfilter(&dvb_spi->demux,
+						 dvb_spi->ts_buf,
+						 MAX_TRANS_PACKET * 188);
+			}
+			start_time = jiffies;
+		} else if ((info.packet_num > 0) && (elapsed >= 500)) {
+			cxd2880_spi_read_ts(dvb_spi->spi,
+					    dvb_spi->ts_buf,
+					    info.packet_num);
+			dvb_dmx_swfilter(&dvb_spi->demux,
+					 dvb_spi->ts_buf,
+					 info.packet_num * 188);
+			start_time = jiffies;
+		} else {
+			usleep_range(10000, 11000);
+		}
+	}
+
+	return 0;
+}
+
+static int cxd2880_start_feed(struct dvb_demux_feed *feed)
+{
+	int ret = 0;
+	int i = 0;
+	struct dvb_demux *demux = NULL;
+	struct cxd2880_dvb_spi *dvb_spi = NULL;
+
+	if (!feed) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	demux = feed->demux;
+	if (!demux) {
+		pr_err("feed->demux is NULL\n");
+		return -EINVAL;
+	}
+	dvb_spi = demux->priv;
+
+	if (dvb_spi->feed_count == CXD2880_MAX_FILTER_SIZE) {
+		pr_err("Exceeded maximum PID count (32).");
+		pr_err("Selected PID cannot be enabled.\n");
+		return -EBUSY;
+	}
+
+	if (feed->pid == 0x2000) {
+		if (dvb_spi->all_pid_feed_count == 0) {
+			ret = cxd2880_update_pid_filter(dvb_spi,
+							&dvb_spi->filter_config,
+							true);
+			if (ret) {
+				pr_err("update pid filter failed\n");
+				return ret;
+			}
+		}
+		dvb_spi->all_pid_feed_count++;
+
+		pr_debug("all PID feed (count = %d)\n",
+			 dvb_spi->all_pid_feed_count);
+	} else {
+		struct cxd2880_pid_filter_config cfgtmp;
+
+		cfgtmp = dvb_spi->filter_config;
+
+		for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
+			if (cfgtmp.pid_config[i].is_enable == 0) {
+				cfgtmp.pid_config[i].is_enable = 1;
+				cfgtmp.pid_config[i].pid = feed->pid;
+				pr_debug("store PID %d to #%d\n",
+					 feed->pid, i);
+				break;
+			}
+		}
+		if (i == CXD2880_MAX_FILTER_SIZE) {
+			pr_err("PID filter is full. Assumed bug.\n");
+			return -EBUSY;
+		}
+		if (!dvb_spi->all_pid_feed_count)
+			ret = cxd2880_update_pid_filter(dvb_spi,
+							&cfgtmp,
+							false);
+		if (ret)
+			return ret;
+
+		dvb_spi->filter_config = cfgtmp;
+	}
+
+	if (dvb_spi->feed_count == 0) {
+		dvb_spi->ts_buf =
+			kmalloc(MAX_TRANS_PACKET * 188,
+				GFP_KERNEL | GFP_DMA);
+		if (!dvb_spi->ts_buf) {
+			pr_err("ts buffer allocate failed\n");
+			memset(&dvb_spi->filter_config, 0,
+			       sizeof(dvb_spi->filter_config));
+			dvb_spi->all_pid_feed_count = 0;
+			return -ENOMEM;
+		}
+		dvb_spi->cxd2880_ts_read_thread = kthread_run(cxd2880_ts_read,
+							      dvb_spi,
+							      "cxd2880_ts_read");
+		if (IS_ERR(dvb_spi->cxd2880_ts_read_thread)) {
+			pr_err("kthread_run failed/\n");
+			kfree(dvb_spi->ts_buf);
+			dvb_spi->ts_buf = NULL;
+			memset(&dvb_spi->filter_config, 0,
+			       sizeof(dvb_spi->filter_config));
+			dvb_spi->all_pid_feed_count = 0;
+			return PTR_ERR(dvb_spi->cxd2880_ts_read_thread);
+		}
+	}
+
+	dvb_spi->feed_count++;
+
+	pr_debug("start feed (count %d)\n", dvb_spi->feed_count);
+	return 0;
+}
+
+static int cxd2880_stop_feed(struct dvb_demux_feed *feed)
+{
+	int i = 0;
+	int ret = 0;
+	struct dvb_demux *demux = NULL;
+	struct cxd2880_dvb_spi *dvb_spi = NULL;
+
+	if (!feed) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	demux = feed->demux;
+	if (!demux) {
+		pr_err("feed->demux is NULL\n");
+		return -EINVAL;
+	}
+	dvb_spi = demux->priv;
+
+	if (!dvb_spi->feed_count) {
+		pr_err("no feed is started\n");
+		return -EINVAL;
+	}
+
+	if (feed->pid == 0x2000) {
+		/*
+		 * Special PID case.
+		 * Number of 0x2000 feed request was stored
+		 * in dvb_spi->all_pid_feed_count.
+		 */
+		if (dvb_spi->all_pid_feed_count <= 0) {
+			pr_err("PID %d not found.\n", feed->pid);
+			return -EINVAL;
+		}
+		dvb_spi->all_pid_feed_count--;
+	} else {
+		struct cxd2880_pid_filter_config cfgtmp;
+
+		cfgtmp = dvb_spi->filter_config;
+
+		for (i = 0; i < CXD2880_MAX_FILTER_SIZE; i++) {
+			if (feed->pid == cfgtmp.pid_config[i].pid &&
+			    cfgtmp.pid_config[i].is_enable != 0) {
+				cfgtmp.pid_config[i].is_enable = 0;
+				cfgtmp.pid_config[i].pid = 0;
+				pr_debug("removed PID %d from #%d\n",
+					 feed->pid, i);
+				break;
+			}
+		}
+		dvb_spi->filter_config = cfgtmp;
+
+		if (i == CXD2880_MAX_FILTER_SIZE) {
+			pr_err("PID %d not found\n", feed->pid);
+			return -EINVAL;
+		}
+	}
+
+	ret = cxd2880_update_pid_filter(dvb_spi,
+					&dvb_spi->filter_config,
+					dvb_spi->all_pid_feed_count > 0);
+	dvb_spi->feed_count--;
+
+	if (dvb_spi->feed_count == 0) {
+		int ret_stop = 0;
+
+		ret_stop = kthread_stop(dvb_spi->cxd2880_ts_read_thread);
+		if (ret_stop) {
+			pr_err("'kthread_stop failed. (%d)\n", ret_stop);
+			ret = ret_stop;
+		}
+		kfree(dvb_spi->ts_buf);
+		dvb_spi->ts_buf = NULL;
+	}
+
+	pr_debug("stop feed ok.(count %d)\n", dvb_spi->feed_count);
+
+	return ret;
+}
+
+static const struct of_device_id cxd2880_spi_of_match[] = {
+	{ .compatible = "sony,cxd2880" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, cxd2880_spi_of_match);
+
+static int
+cxd2880_spi_probe(struct spi_device *spi)
+{
+	int ret = 0;
+	struct cxd2880_dvb_spi *dvb_spi = NULL;
+	struct cxd2880_config config;
+
+	if (!spi) {
+		pr_err("invalid arg.\n");
+		return -EINVAL;
+	}
+
+	dvb_spi = kzalloc(sizeof(struct cxd2880_dvb_spi), GFP_KERNEL);
+	if (!dvb_spi)
+		return -ENOMEM;
+
+	dvb_spi->spi = spi;
+	mutex_init(&dvb_spi->spi_mutex);
+	dev_set_drvdata(&spi->dev, dvb_spi);
+	config.spi = spi;
+	config.spi_mutex = &dvb_spi->spi_mutex;
+
+	ret = dvb_register_adapter(&dvb_spi->adapter,
+				   "CXD2880",
+				   THIS_MODULE,
+				   &spi->dev,
+				   adapter_nr);
+	if (ret < 0) {
+		pr_err("dvb_register_adapter() failed\n");
+		goto fail_adapter;
+	}
+
+	if (!dvb_attach(cxd2880_attach, &dvb_spi->dvb_fe, &config)) {
+		pr_err("cxd2880_attach failed\n");
+		goto fail_attach;
+	}
+
+	ret = dvb_register_frontend(&dvb_spi->adapter,
+				    &dvb_spi->dvb_fe);
+	if (ret < 0) {
+		pr_err("dvb_register_frontend() failed\n");
+		goto fail_frontend;
+	}
+
+	dvb_spi->demux.dmx.capabilities = DMX_TS_FILTERING;
+	dvb_spi->demux.priv = dvb_spi;
+	dvb_spi->demux.filternum = CXD2880_MAX_FILTER_SIZE;
+	dvb_spi->demux.feednum = CXD2880_MAX_FILTER_SIZE;
+	dvb_spi->demux.start_feed = cxd2880_start_feed;
+	dvb_spi->demux.stop_feed = cxd2880_stop_feed;
+
+	ret = dvb_dmx_init(&dvb_spi->demux);
+	if (ret < 0) {
+		pr_err("dvb_dmx_init() failed\n");
+		goto fail_dmx;
+	}
+
+	dvb_spi->dmxdev.filternum = CXD2880_MAX_FILTER_SIZE;
+	dvb_spi->dmxdev.demux = &dvb_spi->demux.dmx;
+	dvb_spi->dmxdev.capabilities = 0;
+	ret = dvb_dmxdev_init(&dvb_spi->dmxdev,
+			      &dvb_spi->adapter);
+	if (ret < 0) {
+		pr_err("dvb_dmxdev_init() failed\n");
+		goto fail_dmxdev;
+	}
+
+	dvb_spi->dmx_fe.source = DMX_FRONTEND_0;
+	ret = dvb_spi->demux.dmx.add_frontend(&dvb_spi->demux.dmx,
+					      &dvb_spi->dmx_fe);
+	if (ret < 0) {
+		pr_err("add_frontend() failed\n");
+		goto fail_dmx_fe;
+	}
+
+	ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx,
+						  &dvb_spi->dmx_fe);
+	if (ret < 0) {
+		pr_err("dvb_register_frontend() failed\n");
+		goto fail_fe_conn;
+	}
+
+	pr_info("Sony CXD2880 has successfully attached.\n");
+
+	return 0;
+
+fail_fe_conn:
+	dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx,
+					   &dvb_spi->dmx_fe);
+fail_dmx_fe:
+	dvb_dmxdev_release(&dvb_spi->dmxdev);
+fail_dmxdev:
+	dvb_dmx_release(&dvb_spi->demux);
+fail_dmx:
+	dvb_unregister_frontend(&dvb_spi->dvb_fe);
+fail_frontend:
+	dvb_frontend_detach(&dvb_spi->dvb_fe);
+fail_attach:
+	dvb_unregister_adapter(&dvb_spi->adapter);
+fail_adapter:
+	kfree(dvb_spi);
+	return ret;
+}
+
+static int
+cxd2880_spi_remove(struct spi_device *spi)
+{
+	struct cxd2880_dvb_spi *dvb_spi;
+
+	if (!spi) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	dvb_spi = dev_get_drvdata(&spi->dev);
+
+	if (!dvb_spi) {
+		pr_err("failed\n");
+		return -EINVAL;
+	}
+	dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx,
+					   &dvb_spi->dmx_fe);
+	dvb_dmxdev_release(&dvb_spi->dmxdev);
+	dvb_dmx_release(&dvb_spi->demux);
+	dvb_unregister_frontend(&dvb_spi->dvb_fe);
+	dvb_frontend_detach(&dvb_spi->dvb_fe);
+	dvb_unregister_adapter(&dvb_spi->adapter);
+
+	kfree(dvb_spi);
+	pr_info("cxd2880_spi remove ok.\n");
+
+	return 0;
+}
+
+static const struct spi_device_id cxd2880_spi_id[] = {
+	{ "cxd2880", 0 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, cxd2880_spi_id);
+
+static struct spi_driver cxd2880_spi_driver = {
+	.driver	= {
+		.name	= "cxd2880",
+		.of_match_table = cxd2880_spi_of_match,
+	},
+	.id_table = cxd2880_spi_id,
+	.probe    = cxd2880_spi_probe,
+	.remove   = cxd2880_spi_remove,
+};
+module_spi_driver(cxd2880_spi_driver);
+
+MODULE_DESCRIPTION(
+"Sony CXD2880 DVB-T2/T tuner + demodulator drvier SPI adapter");
+MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
+MODULE_LICENSE("GPL v2");
-- 
2.13.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 03/14] [media] cxd2880: Add common files for the driver
  2017-08-16  4:17 ` Yasunari.Takiguchi-7U/KSKJipcs
@ 2017-08-16  4:33   ` Yasunari.Takiguchi
  -1 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:33 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

These are common files for the driver for the
Sony CXD2880 DVB-T2/T tuner + demodulator.
These contains helper functions for the driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880.h
      -no change
   drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
      -changed MASKUPPER/MASKLOWER with GENMASK 
   drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
      -removed definition NULL and SONY_SLEEP
      -changed CXD2880_SLEEP to usleep_range
      -changed cxd2880_atomic_set to atomic_set
      -removed cxd2880_atomic struct and cxd2880_atomic_read
      -changed stop-watch function
      -modified return code
   drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
      -removed unnecessary cast
      -modified return code
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
      -modified return code 
   drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
      -changed CXD2880_SLEEP to usleep_range
      -changed stop-watch function
      -modified return code
   #drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
      -cxd2880_stdlib.h file was removed from V3.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880.h      | 46 +++++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_common.c   | 38 ++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_common.h   | 50 ++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c   | 68 ++++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h   | 62 ++++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_stopwatch_port.c | 60 +++++++++++++++++++
 6 files changed, 324 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880.h b/drivers/media/dvb-frontends/cxd2880/cxd2880.h
new file mode 100644
index 000000000000..281f9a784eb5
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880.h
@@ -0,0 +1,46 @@
+/*
+ * cxd2880.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver public definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_H
+#define CXD2880_H
+
+struct cxd2880_config {
+	struct spi_device *spi;
+	struct mutex *spi_mutex; /* For SPI access exclusive control */
+};
+
+#if IS_REACHABLE(CONFIG_DVB_CXD2880)
+extern struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
+					struct cxd2880_config *cfg);
+#else
+static inline struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
+					struct cxd2880_config *cfg)
+{
+	pr_warn("%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_CXD2880 */
+
+#endif /* CXD2880_H */
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
new file mode 100644
index 000000000000..ffaa140bb8cb
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
@@ -0,0 +1,38 @@
+/*
+ * cxd2880_common.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_common.h"
+
+int cxd2880_convert2s_complement(u32 value, u32 bitlen)
+{
+	if ((bitlen == 0) || (bitlen >= 32))
+		return (int)value;
+
+	if (value & (u32)(1 << (bitlen - 1)))
+		return (int)(GENMASK(31, bitlen) | value);
+	else
+		return (int)(GENMASK(bitlen - 1, 0) & value);
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
new file mode 100644
index 000000000000..cf6b800809ee
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
@@ -0,0 +1,50 @@
+/*
+ * cxd2880_common.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver common definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_COMMON_H
+#define CXD2880_COMMON_H
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+
+#define CXD2880_ARG_UNUSED(arg) ((void)(arg))
+
+int cxd2880_convert2s_complement(u32 value, u32 bitlen);
+
+struct cxd2880_stopwatch {
+	unsigned long start_time;
+};
+
+int cxd2880_stopwatch_start(struct cxd2880_stopwatch *stopwatch);
+
+int cxd2880_stopwatch_sleep(struct cxd2880_stopwatch *stopwatch,
+			    u32 ms);
+
+int cxd2880_stopwatch_elapsed(struct cxd2880_stopwatch *stopwatch,
+			      unsigned int *elapsed);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
new file mode 100644
index 000000000000..38dd8b04a514
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
@@ -0,0 +1,68 @@
+/*
+ * cxd2880_io.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * register I/O interface functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_io.h"
+
+int cxd2880_io_common_write_one_reg(struct cxd2880_io *io,
+				    enum cxd2880_io_tgt tgt,
+				    u8 sub_address, u8 data)
+{
+	int ret = 0;
+
+	if (!io)
+		return -EINVAL;
+
+	ret = io->write_regs(io, tgt, sub_address, &data, 1);
+
+	return ret;
+}
+
+int cxd2880_io_set_reg_bits(struct cxd2880_io *io,
+			    enum cxd2880_io_tgt tgt,
+			    u8 sub_address, u8 data, u8 mask)
+{
+	int ret = 0;
+
+	if (!io)
+		return -EINVAL;
+
+	if (mask == 0x00)
+		return 0;
+
+	if (mask != 0xff) {
+		u8 rdata = 0x00;
+
+		ret = io->read_regs(io, tgt, sub_address, &rdata, 1);
+		if (ret)
+			return ret;
+
+		data = (data & mask) | (rdata & (mask ^ 0xff));
+	}
+
+	ret = io->write_reg(io, tgt, sub_address, data);
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
new file mode 100644
index 000000000000..11a045720110
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
@@ -0,0 +1,62 @@
+/*
+ * cxd2880_io.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * register I/O interface definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_IO_H
+#define CXD2880_IO_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_io_tgt {
+	CXD2880_IO_TGT_SYS,
+	CXD2880_IO_TGT_DMD
+};
+
+struct cxd2880_io {
+	int (*read_regs)(struct cxd2880_io *io,
+			 enum cxd2880_io_tgt tgt, u8 sub_address,
+			 u8 *data, u32 size);
+	int (*write_regs)(struct cxd2880_io *io,
+			  enum cxd2880_io_tgt tgt, u8 sub_address,
+			  const u8 *data, u32 size);
+	int (*write_reg)(struct cxd2880_io *io,
+			 enum cxd2880_io_tgt tgt, u8 sub_address,
+			 u8 data);
+	void *if_object;
+	u8 i2c_address_sys;
+	u8 i2c_address_demod;
+	u8 slave_select;
+	void *user;
+};
+
+int cxd2880_io_common_write_one_reg(struct cxd2880_io *io,
+				    enum cxd2880_io_tgt tgt,
+				    u8 sub_address, u8 data);
+
+int cxd2880_io_set_reg_bits(struct cxd2880_io *io,
+			    enum cxd2880_io_tgt tgt,
+			    u8 sub_address, u8 data, u8 mask);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
new file mode 100644
index 000000000000..a4a1e29de653
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
@@ -0,0 +1,60 @@
+/*
+ * cxd2880_stopwatch_port.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * time measurement functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/jiffies.h>
+
+#include "cxd2880_common.h"
+
+int cxd2880_stopwatch_start(struct cxd2880_stopwatch *stopwatch)
+{
+	if (!stopwatch)
+		return -EINVAL;
+
+	stopwatch->start_time = jiffies;
+
+	return 0;
+}
+
+int cxd2880_stopwatch_sleep(struct cxd2880_stopwatch *stopwatch,
+			    u32 ms)
+{
+	if (!stopwatch)
+		return -EINVAL;
+	CXD2880_ARG_UNUSED(*stopwatch);
+	usleep_range(ms * 10000, ms * 10000 + 1000);
+
+	return 0;
+}
+
+int cxd2880_stopwatch_elapsed(struct cxd2880_stopwatch *stopwatch,
+			      unsigned int *elapsed)
+{
+	if (!stopwatch || !elapsed)
+		return -EINVAL;
+	*elapsed = jiffies_to_msecs(jiffies - stopwatch->start_time);
+
+	return 0;
+}
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 03/14] [media] cxd2880: Add common files for the driver
@ 2017-08-16  4:33   ` Yasunari.Takiguchi
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:33 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

These are common files for the driver for the
Sony CXD2880 DVB-T2/T tuner + demodulator.
These contains helper functions for the driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880.h
      -no change
   drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
      -changed MASKUPPER/MASKLOWER with GENMASK 
   drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
      -removed definition NULL and SONY_SLEEP
      -changed CXD2880_SLEEP to usleep_range
      -changed cxd2880_atomic_set to atomic_set
      -removed cxd2880_atomic struct and cxd2880_atomic_read
      -changed stop-watch function
      -modified return code
   drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
      -removed unnecessary cast
      -modified return code
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
      -modified return code 
   drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
      -changed CXD2880_SLEEP to usleep_range
      -changed stop-watch function
      -modified return code
   #drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h
      -cxd2880_stdlib.h file was removed from V3.

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880.h      | 46 +++++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_common.c   | 38 ++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_common.h   | 50 ++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c   | 68 ++++++++++++++++++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h   | 62 ++++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_stopwatch_port.c | 60 +++++++++++++++++++
 6 files changed, 324 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880.h b/drivers/media/dvb-frontends/cxd2880/cxd2880.h
new file mode 100644
index 000000000000..281f9a784eb5
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880.h
@@ -0,0 +1,46 @@
+/*
+ * cxd2880.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver public definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_H
+#define CXD2880_H
+
+struct cxd2880_config {
+	struct spi_device *spi;
+	struct mutex *spi_mutex; /* For SPI access exclusive control */
+};
+
+#if IS_REACHABLE(CONFIG_DVB_CXD2880)
+extern struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
+					struct cxd2880_config *cfg);
+#else
+static inline struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
+					struct cxd2880_config *cfg)
+{
+	pr_warn("%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_CXD2880 */
+
+#endif /* CXD2880_H */
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
new file mode 100644
index 000000000000..ffaa140bb8cb
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c
@@ -0,0 +1,38 @@
+/*
+ * cxd2880_common.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_common.h"
+
+int cxd2880_convert2s_complement(u32 value, u32 bitlen)
+{
+	if ((bitlen == 0) || (bitlen >= 32))
+		return (int)value;
+
+	if (value & (u32)(1 << (bitlen - 1)))
+		return (int)(GENMASK(31, bitlen) | value);
+	else
+		return (int)(GENMASK(bitlen - 1, 0) & value);
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
new file mode 100644
index 000000000000..cf6b800809ee
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h
@@ -0,0 +1,50 @@
+/*
+ * cxd2880_common.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver common definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_COMMON_H
+#define CXD2880_COMMON_H
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+
+#define CXD2880_ARG_UNUSED(arg) ((void)(arg))
+
+int cxd2880_convert2s_complement(u32 value, u32 bitlen);
+
+struct cxd2880_stopwatch {
+	unsigned long start_time;
+};
+
+int cxd2880_stopwatch_start(struct cxd2880_stopwatch *stopwatch);
+
+int cxd2880_stopwatch_sleep(struct cxd2880_stopwatch *stopwatch,
+			    u32 ms);
+
+int cxd2880_stopwatch_elapsed(struct cxd2880_stopwatch *stopwatch,
+			      unsigned int *elapsed);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
new file mode 100644
index 000000000000..38dd8b04a514
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c
@@ -0,0 +1,68 @@
+/*
+ * cxd2880_io.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * register I/O interface functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_io.h"
+
+int cxd2880_io_common_write_one_reg(struct cxd2880_io *io,
+				    enum cxd2880_io_tgt tgt,
+				    u8 sub_address, u8 data)
+{
+	int ret = 0;
+
+	if (!io)
+		return -EINVAL;
+
+	ret = io->write_regs(io, tgt, sub_address, &data, 1);
+
+	return ret;
+}
+
+int cxd2880_io_set_reg_bits(struct cxd2880_io *io,
+			    enum cxd2880_io_tgt tgt,
+			    u8 sub_address, u8 data, u8 mask)
+{
+	int ret = 0;
+
+	if (!io)
+		return -EINVAL;
+
+	if (mask == 0x00)
+		return 0;
+
+	if (mask != 0xff) {
+		u8 rdata = 0x00;
+
+		ret = io->read_regs(io, tgt, sub_address, &rdata, 1);
+		if (ret)
+			return ret;
+
+		data = (data & mask) | (rdata & (mask ^ 0xff));
+	}
+
+	ret = io->write_reg(io, tgt, sub_address, data);
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
new file mode 100644
index 000000000000..11a045720110
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.h
@@ -0,0 +1,62 @@
+/*
+ * cxd2880_io.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * register I/O interface definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_IO_H
+#define CXD2880_IO_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_io_tgt {
+	CXD2880_IO_TGT_SYS,
+	CXD2880_IO_TGT_DMD
+};
+
+struct cxd2880_io {
+	int (*read_regs)(struct cxd2880_io *io,
+			 enum cxd2880_io_tgt tgt, u8 sub_address,
+			 u8 *data, u32 size);
+	int (*write_regs)(struct cxd2880_io *io,
+			  enum cxd2880_io_tgt tgt, u8 sub_address,
+			  const u8 *data, u32 size);
+	int (*write_reg)(struct cxd2880_io *io,
+			 enum cxd2880_io_tgt tgt, u8 sub_address,
+			 u8 data);
+	void *if_object;
+	u8 i2c_address_sys;
+	u8 i2c_address_demod;
+	u8 slave_select;
+	void *user;
+};
+
+int cxd2880_io_common_write_one_reg(struct cxd2880_io *io,
+				    enum cxd2880_io_tgt tgt,
+				    u8 sub_address, u8 data);
+
+int cxd2880_io_set_reg_bits(struct cxd2880_io *io,
+			    enum cxd2880_io_tgt tgt,
+			    u8 sub_address, u8 data, u8 mask);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
new file mode 100644
index 000000000000..a4a1e29de653
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c
@@ -0,0 +1,60 @@
+/*
+ * cxd2880_stopwatch_port.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * time measurement functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/jiffies.h>
+
+#include "cxd2880_common.h"
+
+int cxd2880_stopwatch_start(struct cxd2880_stopwatch *stopwatch)
+{
+	if (!stopwatch)
+		return -EINVAL;
+
+	stopwatch->start_time = jiffies;
+
+	return 0;
+}
+
+int cxd2880_stopwatch_sleep(struct cxd2880_stopwatch *stopwatch,
+			    u32 ms)
+{
+	if (!stopwatch)
+		return -EINVAL;
+	CXD2880_ARG_UNUSED(*stopwatch);
+	usleep_range(ms * 10000, ms * 10000 + 1000);
+
+	return 0;
+}
+
+int cxd2880_stopwatch_elapsed(struct cxd2880_stopwatch *stopwatch,
+			      unsigned int *elapsed)
+{
+	if (!stopwatch || !elapsed)
+		return -EINVAL;
+	*elapsed = jiffies_to_msecs(jiffies - stopwatch->start_time);
+
+	return 0;
+}
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 04/14] [media] cxd2880: Add spi device IO routines
@ 2017-08-16  4:35   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:35 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

Add functions for initializing, reading and writing to the SPI
device for the Sony CXD2880 DVB-T2/T tuner + demodulator.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
      -removed unnecessary cast
      -changed cxd2880_memcpy to memcpy
      -modified return code
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
      -modified return code
   drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
      -modified return code
   drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
      -removed unnecessary cast
      -modified return code
   drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
      -modified return code

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 .../dvb-frontends/cxd2880/cxd2880_devio_spi.c      | 146 +++++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_devio_spi.h      |  40 ++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h  |  51 +++++++
 .../dvb-frontends/cxd2880/cxd2880_spi_device.c     | 130 ++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_spi_device.h     |  43 ++++++
 5 files changed, 410 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
new file mode 100644
index 000000000000..2cf4fb0e4610
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
@@ -0,0 +1,146 @@
+/*
+ * cxd2880_devio_spi.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * I/O interface via SPI
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_devio_spi.h"
+
+#define BURST_WRITE_MAX 128
+
+static int cxd2880_io_spi_read_reg(struct cxd2880_io *io,
+				   enum cxd2880_io_tgt tgt,
+				   u8 sub_address, u8 *data,
+				   u32 size)
+{
+	int ret = 0;
+	struct cxd2880_spi *spi = NULL;
+	u8 send_data[6];
+	u8 *read_data_top = data;
+
+	if ((!io) || (!io->if_object) || (!data))
+		return -EINVAL;
+
+	if (sub_address + size > 0x100)
+		return -ERANGE;
+
+	spi = io->if_object;
+
+	if (tgt == CXD2880_IO_TGT_SYS)
+		send_data[0] = 0x0b;
+	else
+		send_data[0] = 0x0a;
+
+	send_data[3] = 0;
+	send_data[4] = 0;
+	send_data[5] = 0;
+
+	while (size > 0) {
+		send_data[1] = sub_address;
+		if (size > 255)
+			send_data[2] = 255;
+		else
+			send_data[2] = size;
+
+		ret =
+		    spi->write_read(spi, send_data, sizeof(send_data),
+				    read_data_top, send_data[2]);
+		if (ret)
+			return ret;
+
+		sub_address += send_data[2];
+		read_data_top += send_data[2];
+		size -= send_data[2];
+	}
+
+	return ret;
+}
+
+static int cxd2880_io_spi_write_reg(struct cxd2880_io *io,
+				    enum cxd2880_io_tgt tgt,
+				    u8 sub_address,
+				    const u8 *data, u32 size)
+{
+	int ret = 0;
+	struct cxd2880_spi *spi = NULL;
+	u8 send_data[BURST_WRITE_MAX + 4];
+	const u8 *write_data_top = data;
+
+	if ((!io) || (!io->if_object) || (!data))
+		return -EINVAL;
+
+	if (size > BURST_WRITE_MAX)
+		return -EOVERFLOW;
+
+	if (sub_address + size > 0x100)
+		return -ERANGE;
+
+	spi = io->if_object;
+
+	if (tgt == CXD2880_IO_TGT_SYS)
+		send_data[0] = 0x0f;
+	else
+		send_data[0] = 0x0e;
+
+	while (size > 0) {
+		send_data[1] = sub_address;
+		if (size > 255)
+			send_data[2] = 255;
+		else
+			send_data[2] = size;
+
+		memcpy(&send_data[3], write_data_top, send_data[2]);
+
+		if (tgt == CXD2880_IO_TGT_SYS) {
+			send_data[3 + send_data[2]] = 0x00;
+			ret = spi->write(spi, send_data, send_data[2] + 4);
+		} else {
+			ret = spi->write(spi, send_data, send_data[2] + 3);
+		}
+		if (ret)
+			return ret;
+
+		sub_address += send_data[2];
+		write_data_top += send_data[2];
+		size -= send_data[2];
+	}
+
+	return ret;
+}
+
+int cxd2880_io_spi_create(struct cxd2880_io *io,
+			  struct cxd2880_spi *spi, u8 slave_select)
+{
+	if ((!io) || (!spi))
+		return -EINVAL;
+
+	io->read_regs = cxd2880_io_spi_read_reg;
+	io->write_regs = cxd2880_io_spi_write_reg;
+	io->write_reg = cxd2880_io_common_write_one_reg;
+	io->if_object = spi;
+	io->i2c_address_sys = 0;
+	io->i2c_address_demod = 0;
+	io->slave_select = slave_select;
+
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
new file mode 100644
index 000000000000..41a86f0f558e
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
@@ -0,0 +1,40 @@
+/*
+ * cxd2880_devio_spi.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * I/O interface via SPI
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_DEVIO_SPI_H
+#define CXD2880_DEVIO_SPI_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_io.h"
+#include "cxd2880_spi.h"
+
+#include "cxd2880_tnrdmd.h"
+
+int cxd2880_io_spi_create(struct cxd2880_io *io,
+			  struct cxd2880_spi *spi,
+			  u8 slave_select);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
new file mode 100644
index 000000000000..f9e28daa6a2c
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
@@ -0,0 +1,51 @@
+/*
+ * cxd2880_spi.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI access definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_SPI_H
+#define CXD2880_SPI_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_spi_mode {
+	CXD2880_SPI_MODE_0,
+	CXD2880_SPI_MODE_1,
+	CXD2880_SPI_MODE_2,
+	CXD2880_SPI_MODE_3
+};
+
+struct cxd2880_spi {
+	int (*read)(struct cxd2880_spi *spi, u8 *data,
+		    u32 size);
+	int (*write)(struct cxd2880_spi *spi, const u8 *data,
+		     u32 size);
+	int (*write_read)(struct cxd2880_spi *spi,
+			  const u8 *tx_data, u32 tx_size,
+			  u8 *rx_data, u32 rx_size);
+	u32 flags;
+	void *user;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
new file mode 100644
index 000000000000..60b14e4a4098
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
@@ -0,0 +1,130 @@
+/*
+ * cxd2880_spi_device.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI access functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/spi/spi.h>
+
+#include "cxd2880_spi_device.h"
+
+static int cxd2880_spi_device_write(struct cxd2880_spi *spi,
+				    const u8 *data, u32 size)
+{
+	struct cxd2880_spi_device *spi_device = NULL;
+	struct spi_message msg;
+	struct spi_transfer tx;
+	int result = 0;
+
+	if ((!spi) || (!spi->user) || (!data) || (size == 0))
+		return -EINVAL;
+
+	spi_device = spi->user;
+
+	memset(&tx, 0, sizeof(tx));
+	tx.tx_buf = data;
+	tx.len = size;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&tx, &msg);
+	result = spi_sync(spi_device->spi, &msg);
+
+	if (result < 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int cxd2880_spi_device_write_read(struct cxd2880_spi *spi,
+					 const u8 *tx_data,
+					 u32 tx_size,
+					 u8 *rx_data,
+					 u32 rx_size)
+{
+	struct cxd2880_spi_device *spi_device = NULL;
+	int result = 0;
+
+	if ((!spi) || (!spi->user) || (!tx_data) ||
+		 (tx_size == 0) || (!rx_data) || (rx_size == 0))
+		return -EINVAL;
+
+	spi_device = spi->user;
+
+	result = spi_write_then_read(spi_device->spi, tx_data,
+				     tx_size, rx_data, rx_size);
+	if (result < 0)
+		return -EIO;
+
+	return 0;
+}
+
+int
+cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
+			      enum cxd2880_spi_mode mode,
+			      u32 speed_hz)
+{
+	int result = 0;
+	struct spi_device *spi = spi_device->spi;
+
+	switch (mode) {
+	case CXD2880_SPI_MODE_0:
+		spi->mode = SPI_MODE_0;
+		break;
+	case CXD2880_SPI_MODE_1:
+		spi->mode = SPI_MODE_1;
+		break;
+	case CXD2880_SPI_MODE_2:
+		spi->mode = SPI_MODE_2;
+		break;
+	case CXD2880_SPI_MODE_3:
+		spi->mode = SPI_MODE_3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	spi->max_speed_hz = speed_hz;
+	spi->bits_per_word = 8;
+	result = spi_setup(spi);
+	if (result != 0) {
+		pr_err("spi_setup failed %d\n", result);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
+				  struct cxd2880_spi_device *spi_device)
+{
+	if ((!spi) || (!spi_device))
+		return -EINVAL;
+
+	spi->read = NULL;
+	spi->write = cxd2880_spi_device_write;
+	spi->write_read = cxd2880_spi_device_write_read;
+	spi->flags = 0;
+	spi->user = spi_device;
+
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
new file mode 100644
index 000000000000..63f658e29343
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
@@ -0,0 +1,43 @@
+/*
+ * cxd2880_spi_device.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI access interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_SPI_DEVICE_H
+#define CXD2880_SPI_DEVICE_H
+
+#include "cxd2880_spi.h"
+
+struct cxd2880_spi_device {
+	struct spi_device *spi;
+};
+
+int cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
+				  enum cxd2880_spi_mode mode,
+				  u32 speedHz);
+
+int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
+				  struct cxd2880_spi_device *spi_device);
+
+#endif /* CXD2880_SPI_DEVICE_H */
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 04/14] [media] cxd2880: Add spi device IO routines
@ 2017-08-16  4:35   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-08-16  4:35 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

Add functions for initializing, reading and writing to the SPI
device for the Sony CXD2880 DVB-T2/T tuner + demodulator.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
      -removed unnecessary cast
      -changed cxd2880_memcpy to memcpy
      -modified return code
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
      -modified return code
   drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
      -modified return code
   drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
      -removed unnecessary cast
      -modified return code
   drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
      -modified return code

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 .../dvb-frontends/cxd2880/cxd2880_devio_spi.c      | 146 +++++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_devio_spi.h      |  40 ++++++
 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h  |  51 +++++++
 .../dvb-frontends/cxd2880/cxd2880_spi_device.c     | 130 ++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_spi_device.h     |  43 ++++++
 5 files changed, 410 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
new file mode 100644
index 000000000000..2cf4fb0e4610
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c
@@ -0,0 +1,146 @@
+/*
+ * cxd2880_devio_spi.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * I/O interface via SPI
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_devio_spi.h"
+
+#define BURST_WRITE_MAX 128
+
+static int cxd2880_io_spi_read_reg(struct cxd2880_io *io,
+				   enum cxd2880_io_tgt tgt,
+				   u8 sub_address, u8 *data,
+				   u32 size)
+{
+	int ret = 0;
+	struct cxd2880_spi *spi = NULL;
+	u8 send_data[6];
+	u8 *read_data_top = data;
+
+	if ((!io) || (!io->if_object) || (!data))
+		return -EINVAL;
+
+	if (sub_address + size > 0x100)
+		return -ERANGE;
+
+	spi = io->if_object;
+
+	if (tgt == CXD2880_IO_TGT_SYS)
+		send_data[0] = 0x0b;
+	else
+		send_data[0] = 0x0a;
+
+	send_data[3] = 0;
+	send_data[4] = 0;
+	send_data[5] = 0;
+
+	while (size > 0) {
+		send_data[1] = sub_address;
+		if (size > 255)
+			send_data[2] = 255;
+		else
+			send_data[2] = size;
+
+		ret =
+		    spi->write_read(spi, send_data, sizeof(send_data),
+				    read_data_top, send_data[2]);
+		if (ret)
+			return ret;
+
+		sub_address += send_data[2];
+		read_data_top += send_data[2];
+		size -= send_data[2];
+	}
+
+	return ret;
+}
+
+static int cxd2880_io_spi_write_reg(struct cxd2880_io *io,
+				    enum cxd2880_io_tgt tgt,
+				    u8 sub_address,
+				    const u8 *data, u32 size)
+{
+	int ret = 0;
+	struct cxd2880_spi *spi = NULL;
+	u8 send_data[BURST_WRITE_MAX + 4];
+	const u8 *write_data_top = data;
+
+	if ((!io) || (!io->if_object) || (!data))
+		return -EINVAL;
+
+	if (size > BURST_WRITE_MAX)
+		return -EOVERFLOW;
+
+	if (sub_address + size > 0x100)
+		return -ERANGE;
+
+	spi = io->if_object;
+
+	if (tgt == CXD2880_IO_TGT_SYS)
+		send_data[0] = 0x0f;
+	else
+		send_data[0] = 0x0e;
+
+	while (size > 0) {
+		send_data[1] = sub_address;
+		if (size > 255)
+			send_data[2] = 255;
+		else
+			send_data[2] = size;
+
+		memcpy(&send_data[3], write_data_top, send_data[2]);
+
+		if (tgt == CXD2880_IO_TGT_SYS) {
+			send_data[3 + send_data[2]] = 0x00;
+			ret = spi->write(spi, send_data, send_data[2] + 4);
+		} else {
+			ret = spi->write(spi, send_data, send_data[2] + 3);
+		}
+		if (ret)
+			return ret;
+
+		sub_address += send_data[2];
+		write_data_top += send_data[2];
+		size -= send_data[2];
+	}
+
+	return ret;
+}
+
+int cxd2880_io_spi_create(struct cxd2880_io *io,
+			  struct cxd2880_spi *spi, u8 slave_select)
+{
+	if ((!io) || (!spi))
+		return -EINVAL;
+
+	io->read_regs = cxd2880_io_spi_read_reg;
+	io->write_regs = cxd2880_io_spi_write_reg;
+	io->write_reg = cxd2880_io_common_write_one_reg;
+	io->if_object = spi;
+	io->i2c_address_sys = 0;
+	io->i2c_address_demod = 0;
+	io->slave_select = slave_select;
+
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
new file mode 100644
index 000000000000..41a86f0f558e
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h
@@ -0,0 +1,40 @@
+/*
+ * cxd2880_devio_spi.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * I/O interface via SPI
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_DEVIO_SPI_H
+#define CXD2880_DEVIO_SPI_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_io.h"
+#include "cxd2880_spi.h"
+
+#include "cxd2880_tnrdmd.h"
+
+int cxd2880_io_spi_create(struct cxd2880_io *io,
+			  struct cxd2880_spi *spi,
+			  u8 slave_select);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
new file mode 100644
index 000000000000..f9e28daa6a2c
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi.h
@@ -0,0 +1,51 @@
+/*
+ * cxd2880_spi.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI access definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_SPI_H
+#define CXD2880_SPI_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_spi_mode {
+	CXD2880_SPI_MODE_0,
+	CXD2880_SPI_MODE_1,
+	CXD2880_SPI_MODE_2,
+	CXD2880_SPI_MODE_3
+};
+
+struct cxd2880_spi {
+	int (*read)(struct cxd2880_spi *spi, u8 *data,
+		    u32 size);
+	int (*write)(struct cxd2880_spi *spi, const u8 *data,
+		     u32 size);
+	int (*write_read)(struct cxd2880_spi *spi,
+			  const u8 *tx_data, u32 tx_size,
+			  u8 *rx_data, u32 rx_size);
+	u32 flags;
+	void *user;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
new file mode 100644
index 000000000000..60b14e4a4098
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.c
@@ -0,0 +1,130 @@
+/*
+ * cxd2880_spi_device.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI access functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/spi/spi.h>
+
+#include "cxd2880_spi_device.h"
+
+static int cxd2880_spi_device_write(struct cxd2880_spi *spi,
+				    const u8 *data, u32 size)
+{
+	struct cxd2880_spi_device *spi_device = NULL;
+	struct spi_message msg;
+	struct spi_transfer tx;
+	int result = 0;
+
+	if ((!spi) || (!spi->user) || (!data) || (size == 0))
+		return -EINVAL;
+
+	spi_device = spi->user;
+
+	memset(&tx, 0, sizeof(tx));
+	tx.tx_buf = data;
+	tx.len = size;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&tx, &msg);
+	result = spi_sync(spi_device->spi, &msg);
+
+	if (result < 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int cxd2880_spi_device_write_read(struct cxd2880_spi *spi,
+					 const u8 *tx_data,
+					 u32 tx_size,
+					 u8 *rx_data,
+					 u32 rx_size)
+{
+	struct cxd2880_spi_device *spi_device = NULL;
+	int result = 0;
+
+	if ((!spi) || (!spi->user) || (!tx_data) ||
+		 (tx_size == 0) || (!rx_data) || (rx_size == 0))
+		return -EINVAL;
+
+	spi_device = spi->user;
+
+	result = spi_write_then_read(spi_device->spi, tx_data,
+				     tx_size, rx_data, rx_size);
+	if (result < 0)
+		return -EIO;
+
+	return 0;
+}
+
+int
+cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
+			      enum cxd2880_spi_mode mode,
+			      u32 speed_hz)
+{
+	int result = 0;
+	struct spi_device *spi = spi_device->spi;
+
+	switch (mode) {
+	case CXD2880_SPI_MODE_0:
+		spi->mode = SPI_MODE_0;
+		break;
+	case CXD2880_SPI_MODE_1:
+		spi->mode = SPI_MODE_1;
+		break;
+	case CXD2880_SPI_MODE_2:
+		spi->mode = SPI_MODE_2;
+		break;
+	case CXD2880_SPI_MODE_3:
+		spi->mode = SPI_MODE_3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	spi->max_speed_hz = speed_hz;
+	spi->bits_per_word = 8;
+	result = spi_setup(spi);
+	if (result != 0) {
+		pr_err("spi_setup failed %d\n", result);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
+				  struct cxd2880_spi_device *spi_device)
+{
+	if ((!spi) || (!spi_device))
+		return -EINVAL;
+
+	spi->read = NULL;
+	spi->write = cxd2880_spi_device_write;
+	spi->write_read = cxd2880_spi_device_write_read;
+	spi->flags = 0;
+	spi->user = spi_device;
+
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
new file mode 100644
index 000000000000..63f658e29343
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h
@@ -0,0 +1,43 @@
+/*
+ * cxd2880_spi_device.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * SPI access interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_SPI_DEVICE_H
+#define CXD2880_SPI_DEVICE_H
+
+#include "cxd2880_spi.h"
+
+struct cxd2880_spi_device {
+	struct spi_device *spi;
+};
+
+int cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device,
+				  enum cxd2880_spi_mode mode,
+				  u32 speedHz);
+
+int cxd2880_spi_device_create_spi(struct cxd2880_spi *spi,
+				  struct cxd2880_spi_device *spi_device);
+
+#endif /* CXD2880_SPI_DEVICE_H */
-- 
2.13.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 05/14] [media] cxd2880: Add tuner part of the driver
  2017-08-16  4:17 ` Yasunari.Takiguchi-7U/KSKJipcs
@ 2017-08-16  4:37   ` Yasunari.Takiguchi
  -1 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:37 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

This part of the driver has the main routines to handle
the tuner and demodulator functionality.  The tnrdmd_mon.* files
have monitor functions for the driver.
This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
      -removed code relevant to ISDB-T
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
      -removed unnecessary cast
      -removed code relevant to ISDB-T
      -changed CXD2880_SLEEP to usleep_range
      -changed cxd2880_memset to memset 
      -changed cxd2880_atomic_set to atomic_set
      -modified return code
      -modified coding style of if()
      -changed to use const values at writing a lot of registers 
       with a command. 
      -changed hexadecimal code to lower case. 
      -adjusted of indent spaces
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
      -removed code relevant to ISDB-T
      -changed cxd2880_atomic struct to atomic_t
      -modified return code
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
      -updated version information
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
      -changed CXD2880_SLEEP to usleep_range
      -removed unnecessary cast
      -modified return code
      -modified coding style of if() 
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
      -modified return code

Changes in V2
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
      -updated version information

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h  |   46 +
 .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c   | 4030 ++++++++++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h   |  391 ++
 .../cxd2880/cxd2880_tnrdmd_driver_version.h        |   29 +
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c     |  221 ++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h     |   52 +
 6 files changed, 4769 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
new file mode 100644
index 000000000000..2d35d3990060
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
@@ -0,0 +1,46 @@
+/*
+ * cxd2880_dtv.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DTV related definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_DTV_H
+#define CXD2880_DTV_H
+
+enum cxd2880_dtv_sys {
+	CXD2880_DTV_SYS_UNKNOWN,
+	CXD2880_DTV_SYS_DVBT,
+	CXD2880_DTV_SYS_DVBT2,
+	CXD2880_DTV_SYS_ANY
+};
+
+enum cxd2880_dtv_bandwidth {
+	CXD2880_DTV_BW_UNKNOWN = 0,
+	CXD2880_DTV_BW_1_7_MHZ = 1,
+	CXD2880_DTV_BW_5_MHZ = 5,
+	CXD2880_DTV_BW_6_MHZ = 6,
+	CXD2880_DTV_BW_7_MHZ = 7,
+	CXD2880_DTV_BW_8_MHZ = 8
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
new file mode 100644
index 000000000000..044dc26d2ff3
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
@@ -0,0 +1,4030 @@
+/*
+ * cxd2880_tnrdmd.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common control functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_tnrdmd_dvbt2.h"
+
+static int p_init1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data = 0;
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) ||
+	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)) {
+		switch (tnr_dmd->create_param.ts_output_if) {
+		case CXD2880_TNRDMD_TSOUT_IF_TS:
+			data = 0x00;
+			break;
+		case CXD2880_TNRDMD_TSOUT_IF_SPI:
+			data = 0x01;
+			break;
+		case CXD2880_TNRDMD_TSOUT_IF_SDIO:
+			data = 0x02;
+			break;
+		default:
+			return -EINVAL;
+		}
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x10, data);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x11, 0x16);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	switch (tnr_dmd->chip_id) {
+	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X:
+		data = 0x1a;
+		break;
+	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11:
+		data = 0x16;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x10, data);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->create_param.en_internal_ldo)
+		data = 0x01;
+	else
+		data = 0x00;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x11, data);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x13, data);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x12, data);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	switch (tnr_dmd->chip_id) {
+	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X:
+		data = 0x01;
+		break;
+	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11:
+		data = 0x00;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x69, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int p_init2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[6] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	data[0] = tnr_dmd->create_param.xosc_cap;
+	data[1] = tnr_dmd->create_param.xosc_i;
+	switch (tnr_dmd->create_param.xtal_share_type) {
+	case CXD2880_TNRDMD_XTAL_SHARE_NONE:
+		data[2] = 0x01;
+		data[3] = 0x00;
+		break;
+	case CXD2880_TNRDMD_XTAL_SHARE_EXTREF:
+		data[2] = 0x00;
+		data[3] = 0x00;
+		break;
+	case CXD2880_TNRDMD_XTAL_SHARE_MASTER:
+		data[2] = 0x01;
+		data[3] = 0x01;
+		break;
+	case CXD2880_TNRDMD_XTAL_SHARE_SLAVE:
+		data[2] = 0x00;
+		data[3] = 0x01;
+		break;
+	default:
+		return -EINVAL;
+	}
+	data[4] = 0x06;
+	data[5] = 0x00;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x13,
+				      data,
+				      6);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int p_init3(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[2] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	switch (tnr_dmd->diver_mode) {
+	case CXD2880_TNRDMD_DIVERMODE_SINGLE:
+		data[0] = 0x00;
+		break;
+	case CXD2880_TNRDMD_DIVERMODE_MAIN:
+		data[0] = 0x03;
+		break;
+	case CXD2880_TNRDMD_DIVERMODE_SUB:
+		data[0] = 0x02;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	data[1] = 0x01;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x1f, data, 2);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rf_init1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[8] = { 0 };
+	u8 addr = 0;
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	data[0] = 0x01;
+	data[1] = 0x00;
+	data[2] = 0x01;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x21, data, 3);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	data[0] = 0x01;
+	data[1] = 0x01;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x17, data, 2);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->create_param.stationary_use) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x1a, 0x06);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x4f, 0x18);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x61, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x71, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x9d, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x7d, 0x02);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x8f, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x8b, 0xc6);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x9a, 0x03);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x1c, 0x00);
+	if (ret)
+		return ret;
+	data[0] = 0x00;
+	if ((tnr_dmd->create_param.is_cxd2881gg) &&
+	    (tnr_dmd->create_param.xtal_share_type ==
+		CXD2880_TNRDMD_XTAL_SHARE_SLAVE))
+		data[1] = 0x00;
+	else
+		data[1] = 0x1f;
+	data[2] = 0x0a;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xb5, data, 3);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xb9, 0x07);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x33, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xc1, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xc4, 0x1e);
+	if (ret)
+		return ret;
+	if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) {
+		data[0] = 0x34;
+		data[1] = 0x2c;
+	} else {
+		data[0] = 0x2f;
+		data[1] = 0x25;
+	}
+	data[2] = 0x15;
+	data[3] = 0x19;
+	data[4] = 0x1b;
+	data[5] = 0x15;
+	data[6] = 0x19;
+	data[7] = 0x1b;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xd9, data, 8);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x11);
+	if (ret)
+		return ret;
+	data[0] = 0x6c;
+	data[1] = 0x10;
+	data[2] = 0xa6;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x44, data, 3);
+	if (ret)
+		return ret;
+	data[0] = 0x16;
+	data[1] = 0xa8;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x50, data, 2);
+	if (ret)
+		return ret;
+	data[0] = 0x00;
+	data[1] = 0x22;
+	data[2] = 0x00;
+	data[3] = 0x88;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x62, data, 4);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x74, 0x75);
+	if (ret)
+		return ret;
+	{
+		const u8 cdata[] = {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+				    0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03,
+				    0x03, 0x04, 0x04, 0x05, 0x05, 0x05, 0x02,
+				    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+				    0x02, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02,
+				    0x02, 0x03, 0x04, 0x04, 0x04};
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x7f, cdata, 40);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x16);
+	if (ret)
+		return ret;
+	data[0] = 0x00;
+	data[1] = 0x71;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x10, data, 2);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x23, 0x89);
+	if (ret)
+		return ret;
+
+	{
+		const u8 cdata[] = {0xff, 0x00, 0x00, 0x00, 0x00};
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x27, cdata, 5);
+		if (ret)
+			return ret;
+	}
+
+	{
+		const u8 cdata[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+				    0x01, 0x00, 0x02, 0x00, 0x63, 0x00, 0x00,
+				    0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00,
+				    0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x09,
+				    0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0d, 0x00,
+				    0x0d, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f,
+				    0x00, 0x10, 0x00, 0x79, 0x00, 0x00, 0x00,
+				    0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01,
+				    0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
+				    0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05,
+				    0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00,
+				    0x0a, 0x03, 0xe0};
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x3a, cdata, 80);
+		if (ret)
+			return ret;
+	}
+
+	data[0] = 0x03;
+	data[1] = 0xe0;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xbc, data, 2);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x51, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xc5, 0x07);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x11);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x70, 0xe9);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x76, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x78, 0x32);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x7a, 0x46);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x7c, 0x86);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x7e, 0xa4);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xe1, 0x01);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->create_param.stationary_use) {
+		data[0] = 0x06;
+		data[1] = 0x07;
+		data[2] = 0x1a;
+	} else {
+		data[0] = 0x00;
+		data[1] = 0x08;
+		data[2] = 0x19;
+	}
+	data[3] = 0x0e;
+	data[4] = 0x09;
+	data[5] = 0x0e;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x12);
+	if (ret)
+		return ret;
+	for (addr = 0x10; addr < 0x9f; addr += 6) {
+		if (tnr_dmd->lna_thrs_tbl_air) {
+			u8 idx = 0;
+
+			idx = (addr - 0x10) / 6;
+			data[0] =
+			    tnr_dmd->lna_thrs_tbl_air->thrs[idx].off_on;
+			data[1] =
+			    tnr_dmd->lna_thrs_tbl_air->thrs[idx].on_off;
+		}
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      addr, data, 6);
+		if (ret)
+			return ret;
+	}
+
+	data[0] = 0x00;
+	data[1] = 0x08;
+	if (tnr_dmd->create_param.stationary_use)
+		data[2] = 0x1a;
+	else
+		data[2] = 0x19;
+	data[3] = 0x0e;
+	data[4] = 0x09;
+	data[5] = 0x0e;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x13);
+	if (ret)
+		return ret;
+	for (addr = 0x10; addr < 0xcf; addr += 6) {
+		if (tnr_dmd->lna_thrs_tbl_cable) {
+			u8 idx = 0;
+
+			idx = (addr - 0x10) / 6;
+			data[0] =
+			    tnr_dmd->lna_thrs_tbl_cable->thrs[idx].off_on;
+			data[1] =
+			    tnr_dmd->lna_thrs_tbl_cable->thrs[idx].on_off;
+		}
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      addr, data, 6);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x11);
+	if (ret)
+		return ret;
+	data[0] = 0x08;
+	data[1] = 0x09;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xbd, data, 2);
+	if (ret)
+		return ret;
+	data[0] = 0x08;
+	data[1] = 0x09;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xc4, data, 2);
+	if (ret)
+		return ret;
+
+	{
+		const u8 cdata[] = {0x20, 0x20, 0x30, 0x41, 0x50, 0x5f,
+				    0x6f, 0x80};
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0xc9, cdata, 8);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x14);
+	if (ret)
+		return ret;
+	data[0] = 0x15;
+	data[1] = 0x18;
+	data[2] = 0x00;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x10, data, 3);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x15, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x16);
+	if (ret)
+		return ret;
+
+	{
+		const u8 cdata[] = {0x00, 0x09, 0x00, 0x08, 0x00, 0x07, 0x00,
+				    0x06, 0x00, 0x05, 0x00, 0x03, 0x00, 0x02,
+				    0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
+				    0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c,
+				    0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0f, 0x00,
+				    0x0e, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f,
+				    0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f, 0x00,
+				    0x0e};
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x12, cdata, 50);
+		if (ret)
+			return ret;
+	}
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x10, data, 1);
+	if (ret)
+		return ret;
+	if ((data[0] & 0x01) == 0x00)
+		return -EBUSY;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x25, 0x00);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x11, data, 1);
+	if (ret)
+		return ret;
+	if ((data[0] & 0x01) == 0x00)
+		return -EBUSY;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x02, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0xe1);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x8f, 0x16);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x67, 0x60);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x6a, 0x0f);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x6c, 0x17);
+	if (ret)
+		return ret;
+	data[0] = 0x00;
+	data[1] = 0xfe;
+	data[2] = 0xee;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_DMD,
+				      0x6e, data, 3);
+	if (ret)
+		return ret;
+	data[0] = 0xa1;
+	data[1] = 0x8b;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_DMD,
+				      0x8d, data, 2);
+	if (ret)
+		return ret;
+	data[0] = 0x08;
+	data[1] = 0x09;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_DMD,
+				      0x77, data, 2);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->create_param.stationary_use) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x80, 0xaa);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0xe2);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x41, 0xa0);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x4b, 0x68);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x25, 0x01);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x1a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x10, data, 1);
+	if (ret)
+		return ret;
+	if ((data[0] & 0x01) == 0x00)
+		return -EBUSY;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x14, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x26, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rf_init2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[5] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	data[0] = 0x40;
+	data[1] = 0x40;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xea, data, 2);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	data[0] = 0x00;
+	if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X)
+		data[1] = 0x00;
+	else
+		data[1] = 0x01;
+	data[2] = 0x01;
+	data[3] = 0x03;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x30, data, 4);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x14);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x1b, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0xe1);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xd3, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+		   enum cxd2880_dtv_sys sys, u32 freq_khz,
+		   enum cxd2880_dtv_bandwidth bandwidth,
+		   u8 is_cable, int shift_frequency_khz)
+{
+	u8 data[11] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	data[0] = 0x00;
+	data[1] = 0x00;
+	data[2] = 0x0e;
+	data[3] = 0x00;
+	data[4] = 0x03;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xe7, data, 5);
+	if (ret)
+		return ret;
+
+	data[0] = 0x1f;
+	data[1] = 0x80;
+	data[2] = 0x18;
+	data[3] = 0x00;
+	data[4] = 0x07;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xe7, data, 5);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	data[0] = 0x72;
+	data[1] = 0x81;
+	data[3] = 0x1d;
+	data[4] = 0x6f;
+	data[5] = 0x7e;
+	data[7] = 0x1c;
+	switch (sys) {
+	case CXD2880_DTV_SYS_DVBT:
+		data[2] = 0x94;
+		data[6] = 0x91;
+		break;
+	case CXD2880_DTV_SYS_DVBT2:
+		data[2] = 0x96;
+		data[6] = 0x93;
+		break;
+	default:
+		return -EINVAL;
+	}
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x44, data, 8);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x62, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x15);
+	if (ret)
+		return ret;
+	data[0] = 0x03;
+	data[1] = 0xe2;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x1e, data, 2);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	data[0] = is_cable ? 0x01 : 0x00;
+	data[1] = 0x00;
+	data[2] = 0x6b;
+	data[3] = 0x4d;
+
+	switch (bandwidth) {
+	case CXD2880_DTV_BW_1_7_MHZ:
+		data[4] = 0x03;
+		break;
+	case CXD2880_DTV_BW_5_MHZ:
+	case CXD2880_DTV_BW_6_MHZ:
+		data[4] = 0x00;
+		break;
+	case CXD2880_DTV_BW_7_MHZ:
+		data[4] = 0x01;
+		break;
+	case CXD2880_DTV_BW_8_MHZ:
+		data[4] = 0x02;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	data[5] = 0x00;
+
+	freq_khz += shift_frequency_khz;
+
+	data[6] = (freq_khz >> 16) & 0x0f;
+	data[7] = (freq_khz >> 8) & 0xff;
+	data[8] = freq_khz & 0xff;
+	data[9] = 0xff;
+	data[10] = 0xfe;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x52, data, 11);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+		   enum cxd2880_dtv_bandwidth bandwidth,
+		   enum cxd2880_tnrdmd_clockmode clk_mode,
+		   int shift_frequency_khz)
+{
+	u8 data[3] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x11);
+	if (ret)
+		return ret;
+
+	data[0] = 0x01;
+	data[1] = 0x0e;
+	data[2] = 0x01;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x2d, data, 3);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x1a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x29, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x2c, data, 1);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x60, data[0]);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x62, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x11);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x2d, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x2f, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x01);
+	if (ret)
+		return ret;
+
+	if (shift_frequency_khz != 0) {
+		int shift_freq = 0;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0xe1);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x60, data, 2);
+		if (ret)
+			return ret;
+
+		shift_freq = shift_frequency_khz * 1000;
+
+		switch (clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+		default:
+			if (shift_freq >= 0)
+				shift_freq = (shift_freq + 183 / 2) / 183;
+			else
+				shift_freq = (shift_freq - 183 / 2) / 183;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			if (shift_freq >= 0)
+				shift_freq = (shift_freq + 178 / 2) / 178;
+			else
+				shift_freq = (shift_freq - 178 / 2) / 178;
+			break;
+		}
+
+		shift_freq +=
+		    cxd2880_convert2s_complement((data[0] << 8) | data[1], 16);
+
+		if (shift_freq > 32767)
+			shift_freq = 32767;
+		else if (shift_freq < -32768)
+			shift_freq = -32768;
+
+		data[0] = (shift_freq >> 8) & 0xff;
+		data[1] = shift_freq & 0xff;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x60, data, 2);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x69, data, 1);
+		if (ret)
+			return ret;
+
+		shift_freq = -shift_frequency_khz;
+
+		if (bandwidth == CXD2880_DTV_BW_1_7_MHZ) {
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+			default:
+				if (shift_freq >= 0)
+					shift_freq =
+					    (shift_freq * 1000 +
+					     17578 / 2) / 17578;
+				else
+					shift_freq =
+					    (shift_freq * 1000 -
+					     17578 / 2) / 17578;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				if (shift_freq >= 0)
+					shift_freq =
+					    (shift_freq * 1000 +
+					     17090 / 2) / 17090;
+				else
+					shift_freq =
+					    (shift_freq * 1000 -
+					     17090 / 2) / 17090;
+				break;
+			}
+		} else {
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+			default:
+				if (shift_freq >= 0)
+					shift_freq =
+					    (shift_freq * 1000 +
+					     35156 / 2) / 35156;
+				else
+					shift_freq =
+					    (shift_freq * 1000 -
+					     35156 / 2) / 35156;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				if (shift_freq >= 0)
+					shift_freq =
+					    (shift_freq * 1000 +
+					     34180 / 2) / 34180;
+				else
+					shift_freq =
+					    (shift_freq * 1000 -
+					     34180 / 2) / 34180;
+				break;
+			}
+		}
+
+		shift_freq += cxd2880_convert2s_complement(data[0], 8);
+
+		if (shift_freq > 127)
+			shift_freq = 127;
+		else if (shift_freq < -128)
+			shift_freq = -128;
+
+		data[0] = shift_freq & 0xff;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x69, data[0]);
+		if (ret)
+			return ret;
+	}
+
+	if (tnr_dmd->create_param.stationary_use) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0xe1);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x8a, 0x87);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_tune3(struct cxd2880_tnrdmd *tnr_dmd,
+		   enum cxd2880_dtv_sys sys,
+		   u8 en_fef_intmtnt_ctrl)
+{
+	u8 data[6] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0xe2);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x41, 0xa0);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xfe, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl) {
+		data[0] = 0x01;
+		data[1] = 0x01;
+		data[2] = 0x01;
+		data[3] = 0x01;
+		data[4] = 0x01;
+		data[5] = 0x01;
+	} else {
+		data[0] = 0x00;
+		data[1] = 0x00;
+		data[2] = 0x00;
+		data[3] = 0x00;
+		data[4] = 0x00;
+		data[5] = 0x00;
+	}
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xef, data, 6);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x2d);
+	if (ret)
+		return ret;
+	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
+		data[0] = 0x00;
+	else
+		data[0] = 0x01;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xb1, data[0]);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_tune4(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[2] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	{
+		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+							CXD2880_IO_TGT_SYS,
+							0x00, 0x00);
+		if (ret)
+			return ret;
+		data[0] = 0x14;
+		data[1] = 0x00;
+		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+							CXD2880_IO_TGT_SYS,
+							0x55, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	{
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00, 0x00);
+		if (ret)
+			return ret;
+		data[0] = 0x0b;
+		data[1] = 0xff;
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x53, data, 2);
+		if (ret)
+			return ret;
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x57, 0x01);
+		if (ret)
+			return ret;
+		data[0] = 0x0b;
+		data[1] = 0xff;
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x55, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	{
+		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+							CXD2880_IO_TGT_SYS,
+							0x00, 0x00);
+		if (ret)
+			return ret;
+		data[0] = 0x14;
+		data[1] = 0x00;
+		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+							 CXD2880_IO_TGT_SYS,
+							 0x53, data, 2);
+		if (ret)
+			return ret;
+		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+							CXD2880_IO_TGT_SYS,
+							0x57, 0x02);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xfe, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+						CXD2880_IO_TGT_DMD,
+						0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+						CXD2880_IO_TGT_DMD,
+						0xfe, 0x01);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_sleep1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[3] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	{
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00, 0x00);
+		if (ret)
+			return ret;
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x57, 0x03);
+		if (ret)
+			return ret;
+		data[0] = 0x00;
+		data[1] = 0x00;
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x53, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	{
+		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+							CXD2880_IO_TGT_SYS,
+							0x00, 0x00);
+		if (ret)
+			return ret;
+		data[0] = 0x1f;
+		data[1] = 0xff;
+		data[2] = 0x03;
+		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+							 CXD2880_IO_TGT_SYS,
+							 0x55, data, 3);
+		if (ret)
+			return ret;
+		data[0] = 0x00;
+		data[1] = 0x00;
+		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+							 CXD2880_IO_TGT_SYS,
+							 0x53, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	{
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00, 0x00);
+		if (ret)
+			return ret;
+		data[0] = 0x1f;
+		data[1] = 0xff;
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x55, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int x_sleep2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data = 0;
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x2d);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xb1, 0x01);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xb2, &data, 1);
+	if (ret)
+		return ret;
+	if ((data & 0x01) == 0x00)
+		return -EBUSY;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xf4, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xf3, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xf2, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xf1, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xf0, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xef, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_sleep3(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xfd, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_sleep4(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0xe2);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x41, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int spll_reset(struct cxd2880_tnrdmd *tnr_dmd,
+		      enum cxd2880_tnrdmd_clockmode clockmode)
+{
+	u8 data[4] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x29, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x28, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x27, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x26, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x27, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x22, 0x01);
+	if (ret)
+		return ret;
+	switch (clockmode) {
+	case CXD2880_TNRDMD_CLOCKMODE_A:
+		data[0] = 0x00;
+		break;
+
+	case CXD2880_TNRDMD_CLOCKMODE_B:
+		data[0] = 0x01;
+		break;
+
+	case CXD2880_TNRDMD_CLOCKMODE_C:
+		data[0] = 0x02;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x30, data[0]);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x22, 0x00);
+	if (ret)
+		return ret;
+
+	usleep_range(2000, 3000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x10, data, 1);
+	if (ret)
+		return ret;
+	if ((data[0] & 0x01) == 0x00)
+		return -EBUSY;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x27, 0x01);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	data[0] = 0x00;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	data[3] = 0x00;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x26, data, 4);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int t_power_x(struct cxd2880_tnrdmd *tnr_dmd, u8 on)
+{
+	u8 data[3] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x29, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x28, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x27, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x27, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x25, 0x01);
+	if (ret)
+		return ret;
+
+	if (on) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x2b, 0x01);
+		if (ret)
+			return ret;
+
+		usleep_range(1000, 2000);
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00, 0x0a);
+		if (ret)
+			return ret;
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x12, data, 1);
+		if (ret)
+			return ret;
+		if ((data[0] & 0x01) == 0)
+			return -EBUSY;
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00, 0x00);
+		if (ret)
+			return ret;
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x2a, 0x00);
+		if (ret)
+			return ret;
+	} else {
+		data[0] = 0x03;
+		data[1] = 0x00;
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x2a, data, 2);
+		if (ret)
+			return ret;
+
+		usleep_range(1000, 2000);
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00, 0x0a);
+		if (ret)
+			return ret;
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x13, data, 1);
+		if (ret)
+			return ret;
+		if ((data[0] & 0x01) == 0)
+			return -EBUSY;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x25, 0x00);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x11, data, 1);
+	if (ret)
+		return ret;
+	if ((data[0] & 0x01) == 0)
+		return -EBUSY;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x27, 0x01);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	data[0] = 0x00;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x27, data, 3);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct cxd2880_tnrdmd_ts_clk_cfg {
+	u8 srl_clk_mode;
+	u8 srl_duty_mode;
+	u8 ts_clk_period;
+};
+
+static int set_ts_clk_mode_and_freq(struct cxd2880_tnrdmd *tnr_dmd,
+				    enum cxd2880_dtv_sys sys)
+{
+	int ret = 0;
+	u8 backwards_compatible = 0;
+	struct cxd2880_tnrdmd_ts_clk_cfg ts_clk_cfg;
+
+	const struct cxd2880_tnrdmd_ts_clk_cfg srl_ts_clk_stgs[2][2] = {
+	{
+		{3, 1, 8,},
+		{0, 2, 16,}
+	},
+	{
+		{1, 1, 8,},
+		{2, 2, 16,}
+	}
+	};
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	{
+		u8 ts_rate_ctrl_off = 0;
+		u8 ts_in_off = 0;
+		u8 ts_clk_manaul_on = 0;
+
+		if (tnr_dmd->is_ts_backwards_compatible_mode) {
+			backwards_compatible = 1;
+			ts_rate_ctrl_off = 1;
+			ts_in_off = 1;
+		} else {
+			backwards_compatible = 0;
+			ts_rate_ctrl_off = 0;
+			ts_in_off = 0;
+		}
+
+		if (tnr_dmd->ts_byte_clk_manual_setting) {
+			ts_clk_manaul_on = 1;
+			ts_rate_ctrl_off = 0;
+		}
+
+		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xd3, ts_rate_ctrl_off, 0x01);
+		if (ret)
+			return ret;
+
+		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xde, ts_in_off, 0x01);
+		if (ret)
+			return ret;
+
+		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xda, ts_clk_manaul_on, 0x01);
+		if (ret)
+			return ret;
+	}
+
+	ts_clk_cfg = srl_ts_clk_stgs[tnr_dmd->srl_ts_clk_mod_cnts]
+				    [tnr_dmd->srl_ts_clk_frq];
+
+	if (tnr_dmd->ts_byte_clk_manual_setting)
+		ts_clk_cfg.ts_clk_period = tnr_dmd->ts_byte_clk_manual_setting;
+
+	ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+				      CXD2880_IO_TGT_DMD,
+				      0xc4, ts_clk_cfg.srl_clk_mode, 0x03);
+	if (ret)
+		return ret;
+
+	ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+				      CXD2880_IO_TGT_DMD,
+				      0xd1, ts_clk_cfg.srl_duty_mode, 0x03);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD, 0xd9,
+				     ts_clk_cfg.ts_clk_period);
+	if (ret)
+		return ret;
+
+	{
+		u8 data = backwards_compatible ? 0x00 : 0x01;
+
+		if (sys == CXD2880_DTV_SYS_DVBT) {
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x00, 0x10);
+			if (ret)
+				return ret;
+
+			ret =
+			    cxd2880_io_set_reg_bits(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD,
+						    0x66, data, 0x01);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int pid_ftr_setting(struct cxd2880_tnrdmd *tnr_dmd,
+			   struct cxd2880_tnrdmd_pid_ftr_cfg
+			   *pid_ftr_cfg)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	if (!pid_ftr_cfg) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x50, 0x02);
+		if (ret)
+			return ret;
+	} else {
+		u8 data[65];
+
+		data[0] = pid_ftr_cfg->is_negative ? 0x01 : 0x00;
+		{
+			int i = 0;
+
+			for (i = 0; i < 32; i++) {
+				if (pid_ftr_cfg->pid_cfg[i].is_en) {
+					data[1 + (i * 2)] =
+					    (pid_ftr_cfg->pid_cfg[i].pid
+					     >> 8) | 0x20;
+					data[2 + (i * 2)] =
+					    pid_ftr_cfg->pid_cfg[i].pid
+					    & 0xff;
+				} else {
+					data[1 + (i * 2)] = 0x00;
+					data[2 + (i * 2)] = 0x00;
+				}
+			}
+		}
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x50, data, 65);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+	u8 i;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     tnr_dmd->cfg_mem[i].tgt,
+					     0x00, tnr_dmd->cfg_mem[i].bank);
+		if (ret)
+			return ret;
+
+		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+					      tnr_dmd->cfg_mem[i].tgt,
+					      tnr_dmd->cfg_mem[i].address,
+					      tnr_dmd->cfg_mem[i].value,
+					      tnr_dmd->cfg_mem[i].bit_mask);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int set_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd,
+		       enum cxd2880_io_tgt tgt,
+		       u8 bank, u8 address, u8 value, u8 bit_mask)
+{
+	u8 i;
+	u8 value_stored = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) {
+		if ((value_stored == 0) &&
+		    (tnr_dmd->cfg_mem[i].tgt == tgt) &&
+		    (tnr_dmd->cfg_mem[i].bank == bank) &&
+		    (tnr_dmd->cfg_mem[i].address == address)) {
+			tnr_dmd->cfg_mem[i].value &= ~bit_mask;
+			tnr_dmd->cfg_mem[i].value |= (value & bit_mask);
+
+			tnr_dmd->cfg_mem[i].bit_mask |= bit_mask;
+
+			value_stored = 1;
+		}
+	}
+
+	if (value_stored == 0) {
+		if (tnr_dmd->cfg_mem_last_entry <
+		    CXD2880_TNRDMD_MAX_CFG_MEM_COUNT) {
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].tgt = tgt;
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bank =
+			    bank;
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].address =
+			    address;
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].value =
+			    (value & bit_mask);
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bit_mask =
+			    bit_mask;
+			tnr_dmd->cfg_mem_last_entry++;
+		} else {
+			return -EOVERFLOW;
+		}
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
+			  struct cxd2880_io *io,
+			  struct cxd2880_tnrdmd_create_param
+			  *create_param)
+{
+	if ((!tnr_dmd) || (!io) || (!create_param))
+		return -EINVAL;
+
+	memset(tnr_dmd, 0, sizeof(struct cxd2880_tnrdmd));
+
+	tnr_dmd->io = io;
+	tnr_dmd->create_param = *create_param;
+
+	tnr_dmd->diver_mode = CXD2880_TNRDMD_DIVERMODE_SINGLE;
+	tnr_dmd->diver_sub = NULL;
+
+	tnr_dmd->srl_ts_clk_mod_cnts = 1;
+	tnr_dmd->en_fef_intmtnt_base = 1;
+	tnr_dmd->en_fef_intmtnt_lite = 1;
+	tnr_dmd->rf_lvl_cmpstn = NULL;
+	tnr_dmd->lna_thrs_tbl_air = NULL;
+	tnr_dmd->lna_thrs_tbl_cable = NULL;
+	atomic_set(&tnr_dmd->cancel, 0);
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
+				*tnr_dmd_main,
+				struct cxd2880_io *io_main,
+				struct cxd2880_tnrdmd *tnr_dmd_sub,
+				struct cxd2880_io *io_sub,
+				struct
+				cxd2880_tnrdmd_diver_create_param
+				*create_param)
+{
+	if ((!tnr_dmd_main) || (!io_main) || (!tnr_dmd_sub) || (!io_sub) ||
+	    (!create_param))
+		return -EINVAL;
+
+	memset(tnr_dmd_main, 0, sizeof(struct cxd2880_tnrdmd));
+	memset(tnr_dmd_sub, 0, sizeof(struct cxd2880_tnrdmd));
+
+	tnr_dmd_main->io = io_main;
+	tnr_dmd_main->diver_mode = CXD2880_TNRDMD_DIVERMODE_MAIN;
+	tnr_dmd_main->diver_sub = tnr_dmd_sub;
+	tnr_dmd_main->create_param.en_internal_ldo =
+	    create_param->en_internal_ldo;
+	tnr_dmd_main->create_param.ts_output_if = create_param->ts_output_if;
+	tnr_dmd_main->create_param.xtal_share_type =
+	    CXD2880_TNRDMD_XTAL_SHARE_MASTER;
+	tnr_dmd_main->create_param.xosc_cap = create_param->xosc_cap_main;
+	tnr_dmd_main->create_param.xosc_i = create_param->xosc_i_main;
+	tnr_dmd_main->create_param.is_cxd2881gg = create_param->is_cxd2881gg;
+	tnr_dmd_main->create_param.stationary_use =
+	    create_param->stationary_use;
+
+	tnr_dmd_sub->io = io_sub;
+	tnr_dmd_sub->diver_mode = CXD2880_TNRDMD_DIVERMODE_SUB;
+	tnr_dmd_sub->diver_sub = NULL;
+	tnr_dmd_sub->create_param.en_internal_ldo =
+	    create_param->en_internal_ldo;
+	tnr_dmd_sub->create_param.ts_output_if = create_param->ts_output_if;
+	tnr_dmd_sub->create_param.xtal_share_type =
+	    CXD2880_TNRDMD_XTAL_SHARE_SLAVE;
+	tnr_dmd_sub->create_param.xosc_cap = 0;
+	tnr_dmd_sub->create_param.xosc_i = create_param->xosc_i_sub;
+	tnr_dmd_sub->create_param.is_cxd2881gg = create_param->is_cxd2881gg;
+	tnr_dmd_sub->create_param.stationary_use = create_param->stationary_use;
+
+	tnr_dmd_main->srl_ts_clk_mod_cnts = 1;
+	tnr_dmd_main->en_fef_intmtnt_base = 1;
+	tnr_dmd_main->en_fef_intmtnt_lite = 1;
+	tnr_dmd_main->rf_lvl_cmpstn = NULL;
+	tnr_dmd_main->lna_thrs_tbl_air = NULL;
+	tnr_dmd_main->lna_thrs_tbl_cable = NULL;
+
+	tnr_dmd_sub->srl_ts_clk_mod_cnts = 1;
+	tnr_dmd_sub->en_fef_intmtnt_base = 1;
+	tnr_dmd_sub->en_fef_intmtnt_lite = 1;
+	tnr_dmd_sub->rf_lvl_cmpstn = NULL;
+	tnr_dmd_sub->lna_thrs_tbl_air = NULL;
+	tnr_dmd_sub->lna_thrs_tbl_cable = NULL;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB))
+		return -EINVAL;
+
+	tnr_dmd->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
+	tnr_dmd->state = CXD2880_TNRDMD_STATE_UNKNOWN;
+	tnr_dmd->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN;
+	tnr_dmd->frequency_khz = 0;
+	tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN;
+	tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+	tnr_dmd->scan_mode = 0;
+	atomic_set(&tnr_dmd->cancel, 0);
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		tnr_dmd->diver_sub->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
+		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_UNKNOWN;
+		tnr_dmd->diver_sub->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN;
+		tnr_dmd->diver_sub->frequency_khz = 0;
+		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN;
+		tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+		tnr_dmd->diver_sub->scan_mode = 0;
+		atomic_set(&tnr_dmd->diver_sub->cancel, 0);
+	}
+
+	ret = cxd2880_tnrdmd_chip_id(tnr_dmd, &tnr_dmd->chip_id);
+	if (ret)
+		return ret;
+
+	if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->chip_id))
+		return -EOPNOTSUPP;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret =
+		    cxd2880_tnrdmd_chip_id(tnr_dmd->diver_sub,
+					   &tnr_dmd->diver_sub->chip_id);
+		if (ret)
+			return ret;
+
+		if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->diver_sub->chip_id))
+			return -EOPNOTSUPP;
+	}
+
+	ret = p_init1(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = p_init1(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	usleep_range(1000, 2000);
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = p_init2(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	ret = p_init2(tnr_dmd);
+	if (ret)
+		return ret;
+
+	usleep_range(5000, 6000);
+
+	ret = p_init3(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = p_init3(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	ret = rf_init1(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = rf_init1(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	{
+		u8 cpu_task_completed = 0;
+
+		ret =
+		    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
+						     &cpu_task_completed);
+		if (ret)
+			return ret;
+
+		if (!cpu_task_completed)
+			return -EBUSY;
+	}
+
+	ret = rf_init2(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = rf_init2(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	ret = load_cfg_mem(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = load_cfg_mem(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
+					     *tnr_dmd,
+					     u8 *task_completed)
+{
+	u16 cpu_status = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!task_completed))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd, &cpu_status);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (cpu_status == 0)
+			*task_completed = 1;
+		else
+			*task_completed = 0;
+
+		return ret;
+	}
+	if (cpu_status != 0) {
+		*task_completed = 0;
+		return ret;
+	}
+
+	ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status);
+	if (ret)
+		return ret;
+
+	if (cpu_status == 0)
+		*task_completed = 1;
+	else
+		*task_completed = 0;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd *tnr_dmd,
+					enum cxd2880_dtv_sys sys,
+					u32 frequency_khz,
+					enum cxd2880_dtv_bandwidth
+					bandwidth, u8 one_seg_opt,
+					u8 one_seg_opt_shft_dir)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	if (frequency_khz < 4000)
+		return -ERANGE;
+
+	ret = cxd2880_tnrdmd_sleep(tnr_dmd);
+	if (ret)
+		return ret;
+
+	{
+		u8 data = 0;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00,
+					     0x00);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x2b,
+					     &data,
+					     1);
+		if (ret)
+			return ret;
+
+		switch (sys) {
+		case CXD2880_DTV_SYS_DVBT:
+			if (data == 0x00) {
+				ret = t_power_x(tnr_dmd, 1);
+				if (ret)
+					return ret;
+
+				if (tnr_dmd->diver_mode ==
+				    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+					ret = t_power_x(tnr_dmd->diver_sub, 1);
+					if (ret)
+						return ret;
+				}
+			}
+			break;
+
+		case CXD2880_DTV_SYS_DVBT2:
+			if (data == 0x01) {
+				ret = t_power_x(tnr_dmd, 0);
+				if (ret)
+					return ret;
+
+				if (tnr_dmd->diver_mode ==
+				    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+					ret = t_power_x(tnr_dmd->diver_sub, 0);
+					if (ret)
+						return ret;
+				}
+			}
+			break;
+
+		default:
+			return -EINVAL;
+		}
+	}
+
+	{
+		enum cxd2880_tnrdmd_clockmode new_clk_mode =
+		    CXD2880_TNRDMD_CLOCKMODE_A;
+
+		ret = spll_reset(tnr_dmd, new_clk_mode);
+		if (ret)
+			return ret;
+
+		tnr_dmd->clk_mode = new_clk_mode;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = spll_reset(tnr_dmd->diver_sub, new_clk_mode);
+			if (ret)
+				return ret;
+
+			tnr_dmd->diver_sub->clk_mode = new_clk_mode;
+		}
+
+		ret = load_cfg_mem(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = load_cfg_mem(tnr_dmd->diver_sub);
+			if (ret)
+				return ret;
+		}
+	}
+
+	{
+		int shift_frequency_khz = 0;
+
+		if (one_seg_opt) {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				shift_frequency_khz = 350;
+			} else {
+				if (one_seg_opt_shft_dir)
+					shift_frequency_khz = 350;
+				else
+					shift_frequency_khz = -350;
+
+				if (tnr_dmd->create_param.xtal_share_type ==
+				    CXD2880_TNRDMD_XTAL_SHARE_SLAVE)
+					shift_frequency_khz *= -1;
+			}
+		} else {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				shift_frequency_khz = 150;
+			} else {
+				switch (tnr_dmd->create_param.xtal_share_type) {
+				case CXD2880_TNRDMD_XTAL_SHARE_NONE:
+				case CXD2880_TNRDMD_XTAL_SHARE_EXTREF:
+				default:
+					shift_frequency_khz = 0;
+					break;
+				case CXD2880_TNRDMD_XTAL_SHARE_MASTER:
+					shift_frequency_khz = 150;
+					break;
+				case CXD2880_TNRDMD_XTAL_SHARE_SLAVE:
+					shift_frequency_khz = -150;
+					break;
+				}
+			}
+		}
+
+		ret =
+		    x_tune1(tnr_dmd, sys, frequency_khz, bandwidth,
+			    tnr_dmd->is_cable_input, shift_frequency_khz);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret =
+			    x_tune1(tnr_dmd->diver_sub, sys, frequency_khz,
+				    bandwidth, tnr_dmd->is_cable_input,
+				    -shift_frequency_khz);
+			if (ret)
+				return ret;
+		}
+
+		usleep_range(10000, 11000);
+
+		{
+			u8 cpu_task_completed = 0;
+
+			ret =
+			    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
+						     &cpu_task_completed);
+			if (ret)
+				return ret;
+
+			if (!cpu_task_completed)
+				return -EBUSY;
+		}
+
+		ret =
+		    x_tune2(tnr_dmd, bandwidth, tnr_dmd->clk_mode,
+			    shift_frequency_khz);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret =
+			    x_tune2(tnr_dmd->diver_sub, bandwidth,
+				    tnr_dmd->diver_sub->clk_mode,
+				    -shift_frequency_khz);
+			if (ret)
+				return ret;
+		}
+	}
+
+	if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) {
+		ret = set_ts_clk_mode_and_freq(tnr_dmd, sys);
+		if (ret)
+			return ret;
+	} else {
+		struct cxd2880_tnrdmd_pid_ftr_cfg *pid_ftr_cfg;
+
+		if (tnr_dmd->pid_ftr_cfg_en)
+			pid_ftr_cfg = &tnr_dmd->pid_ftr_cfg;
+		else
+			pid_ftr_cfg = NULL;
+
+		ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
+					*tnr_dmd,
+					enum cxd2880_dtv_sys sys,
+					u8 en_fef_intmtnt_ctrl)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = x_tune3(tnr_dmd, sys, en_fef_intmtnt_ctrl);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = x_tune3(tnr_dmd->diver_sub, sys, en_fef_intmtnt_ctrl);
+		if (ret)
+			return ret;
+	}
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = x_tune4(tnr_dmd);
+		if (ret)
+			return ret;
+	}
+
+	ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 1);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state == CXD2880_TNRDMD_STATE_SLEEP) {
+	} else if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) {
+		ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 0);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = x_sleep1(tnr_dmd);
+			if (ret)
+				return ret;
+		}
+
+		ret = x_sleep2(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = x_sleep2(tnr_dmd->diver_sub);
+			if (ret)
+				return ret;
+		}
+
+		switch (tnr_dmd->sys) {
+		case CXD2880_DTV_SYS_DVBT:
+			ret = cxd2880_tnrdmd_dvbt_sleep_setting(tnr_dmd);
+			if (ret)
+				return ret;
+			break;
+
+		case CXD2880_DTV_SYS_DVBT2:
+			ret = cxd2880_tnrdmd_dvbt2_sleep_setting(tnr_dmd);
+			if (ret)
+				return ret;
+			break;
+
+		default:
+			return -EPERM;
+		}
+
+		ret = x_sleep3(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = x_sleep3(tnr_dmd->diver_sub);
+			if (ret)
+				return ret;
+		}
+
+		ret = x_sleep4(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = x_sleep4(tnr_dmd->diver_sub);
+			if (ret)
+				return ret;
+		}
+
+		tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP;
+		tnr_dmd->frequency_khz = 0;
+		tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN;
+		tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP;
+			tnr_dmd->diver_sub->frequency_khz = 0;
+			tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN;
+			tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+		}
+	} else {
+		return -EPERM;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+			   enum cxd2880_tnrdmd_cfg_id id,
+			   int value)
+{
+	int ret = 0;
+	u8 data[2] = { 0 };
+	u8 need_sub_setting = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	switch (id) {
+	case CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc4,
+							 value ? 0x00 : 0x10,
+							 0x10);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc5,
+							 value ? 0x00 : 0x02,
+							 0x02);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc5,
+							 value ? 0x00 : 0x04,
+							 0x04);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xcb,
+							 value ? 0x00 : 0x01,
+							 0x01);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc5,
+							 value ? 0x01 : 0x00,
+							 0x01);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSCLK_CONT:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		tnr_dmd->srl_ts_clk_mod_cnts = value ? 0x01 : 0x00;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSCLK_MASK:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		if ((value < 0) || (value > 0x1f))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc6, value,
+							 0x1f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSVALID_MASK:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		if ((value < 0) || (value > 0x1f))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc8, value,
+							 0x1f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSERR_MASK:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		if ((value < 0) || (value > 0x1f))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc9, value,
+							 0x1f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSERR_VALID_DIS:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x91,
+							 value ? 0x01 : 0x00,
+							 0x01);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSPIN_CURRENT:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x51, value,
+							 0x3f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x50,
+							 value ? 0x80 : 0x00,
+							 0x80);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSPIN_PULLUP:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x50, value,
+							 0x3f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSCLK_FREQ:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		if ((value < 0) || (value > 1))
+			return -ERANGE;
+
+		tnr_dmd->srl_ts_clk_frq =
+		    (enum cxd2880_tnrdmd_serial_ts_clk)value;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		if ((value < 0) || (value > 0xff))
+			return -ERANGE;
+
+		tnr_dmd->ts_byte_clk_manual_setting = value;
+
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_PACKET_GAP:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		if ((value < 0) || (value > 7))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xd6, value,
+							 0x07);
+		if (ret)
+			return ret;
+
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		tnr_dmd->is_ts_backwards_compatible_mode = value ? 1 : 0;
+
+		break;
+
+	case CXD2880_TNRDMD_CFG_PWM_VALUE:
+		if ((value < 0) || (value > 0x1000))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x22,
+							 value ? 0x01 : 0x00,
+							 0x01);
+		if (ret)
+			return ret;
+
+		{
+			u8 data[2];
+
+			data[0] = (value >> 8) & 0x1f;
+			data[1] = value & 0xff;
+
+			ret =
+			    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x23,
+							 data[0], 0x1f);
+			if (ret)
+				return ret;
+
+			ret =
+			    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x24,
+							 data[1], 0xff);
+			if (ret)
+				return ret;
+		}
+
+		break;
+
+	case CXD2880_TNRDMD_CFG_INTERRUPT:
+		data[0] = (value >> 8) & 0xff;
+		data[1] = value & 0xff;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x48, data[0],
+							 0xff);
+		if (ret)
+			return ret;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x49, data[1],
+							 0xff);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL:
+		data[0] = value & 0x07;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x4a, data[0],
+							 0x07);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL:
+		data[0] = (value & 0x07) << 3;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x4a, data[0],
+							 0x38);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE:
+		if ((value < CXD2880_TNRDMD_CLOCKMODE_UNKNOWN) ||
+		    (value > CXD2880_TNRDMD_CLOCKMODE_C))
+			return -ERANGE;
+		tnr_dmd->fixed_clk_mode = (enum cxd2880_tnrdmd_clockmode)value;
+		break;
+
+	case CXD2880_TNRDMD_CFG_CABLE_INPUT:
+		tnr_dmd->is_cable_input = value ? 1 : 0;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE:
+		tnr_dmd->en_fef_intmtnt_base = value ? 1 : 0;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE:
+		tnr_dmd->en_fef_intmtnt_lite = value ? 1 : 0;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS:
+		data[0] = (value >> 8) & 0x07;
+		data[1] = value & 0xff;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x99, data[0],
+							 0x07);
+		if (ret)
+			return ret;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9a, data[1],
+							 0xff);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS:
+		data[0] = (value >> 8) & 0x07;
+		data[1] = value & 0xff;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9b, data[0],
+							 0x07);
+		if (ret)
+			return ret;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9c, data[1],
+							 0xff);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS:
+		data[0] = (value >> 8) & 0x07;
+		data[1] = value & 0xff;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9d, data[0],
+							 0x07);
+		if (ret)
+			return ret;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9e, data[1],
+							 0xff);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST:
+		tnr_dmd->blind_tune_dvbt2_first = value ? 1 : 0;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD:
+		if ((value < 0) || (value > 31))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x10, 0x60,
+							 value & 0x1f, 0x1f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD:
+		if ((value < 0) || (value > 7))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x10, 0x6f,
+							 value & 0x07, 0x07);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_BBER_MES:
+		if ((value < 0) || (value > 15))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x20, 0x72,
+							 value & 0x0f, 0x0f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_LBER_MES:
+		if ((value < 0) || (value > 15))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x20, 0x6f,
+							 value & 0x0f, 0x0f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT_PER_MES:
+		if ((value < 0) || (value > 15))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x10, 0x5c,
+							 value & 0x0f, 0x0f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_PER_MES:
+		if ((value < 0) || (value > 15))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x24, 0xdc,
+							 value & 0x0f, 0x0f);
+		if (ret)
+			return ret;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (need_sub_setting &&
+	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)) {
+		ret = cxd2880_tnrdmd_set_cfg(tnr_dmd->diver_sub, id, value);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+				u8 id,
+				u8 en,
+				enum cxd2880_tnrdmd_gpio_mode mode,
+				u8 open_drain, u8 invert)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (id > 2)
+		return -EINVAL;
+
+	if (mode > CXD2880_TNRDMD_GPIO_MODE_EEW)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x40 + id, mode,
+						 0x0f);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x43,
+						 open_drain ? (1 << id) : 0,
+						 1 << id);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x44,
+						 invert ? (1 << id) : 0,
+						 1 << id);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x45,
+						 en ? 0 : (1 << id),
+						 1 << id);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				    u8 id,
+				    u8 en,
+				    enum cxd2880_tnrdmd_gpio_mode
+				    mode, u8 open_drain, u8 invert)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_gpio_set_cfg(tnr_dmd->diver_sub, id, en, mode,
+					open_drain, invert);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
+			     u8 id, u8 *value)
+{
+	u8 data = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!value))
+		return -EINVAL;
+
+	if (id > 2)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x20, &data, 1);
+	if (ret)
+		return ret;
+
+	*value = (data >> id) & 0x01;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				 u8 id, u8 *value)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_gpio_read(tnr_dmd->diver_sub, id, value);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
+			      u8 id, u8 value)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (id > 2)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+						   CXD2880_IO_TGT_SYS,
+						   0x00, 0x46,
+						   value ? (1 << id) : 0,
+						   1 << id);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				  u8 id, u8 value)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_gpio_write(tnr_dmd->diver_sub, id, value);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
+				  u16 *value)
+{
+	int ret = 0;
+	u8 data[2] = { 0 };
+
+	if ((!tnr_dmd) || (!value))
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x15, data, 2);
+	if (ret)
+		return ret;
+
+	*value = (data[0] << 8) | data[1];
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
+				   u16 value)
+{
+	int ret = 0;
+	u8 data[2] = { 0 };
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	data[0] = (value >> 8) & 0xff;
+	data[1] = value & 0xff;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x3c, data, 2);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
+				u8 clear_overflow_flag,
+				u8 clear_underflow_flag,
+				u8 clear_buf)
+{
+	int ret = 0;
+	u8 data[2] = { 0 };
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	data[0] = clear_overflow_flag ? 0x02 : 0x00;
+	data[0] |= clear_underflow_flag ? 0x01 : 0x00;
+	data[1] = clear_buf ? 0x01 : 0x00;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_DMD,
+				      0x9f, data, 2);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
+			   enum cxd2880_tnrdmd_chip_id *chip_id)
+{
+	int ret = 0;
+	u8 data = 0;
+
+	if ((!tnr_dmd) || (!chip_id))
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xfd, &data, 1);
+	if (ret)
+		return ret;
+
+	*chip_id = (enum cxd2880_tnrdmd_chip_id)data;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
+					 *tnr_dmd,
+					 enum cxd2880_io_tgt tgt,
+					 u8 bank, u8 address,
+					 u8 value, u8 bit_mask)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io, tgt, 0x00, bank);
+	if (ret)
+		return ret;
+
+	ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+				      tgt, address, value, bit_mask);
+	if (ret)
+		return ret;
+
+	ret = set_cfg_mem(tnr_dmd, tgt, bank, address, value, bit_mask);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
+				 enum cxd2880_dtv_sys sys,
+				 u8 scan_mode_end)
+{
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	CXD2880_ARG_UNUSED(sys);
+
+	tnr_dmd->scan_mode = scan_mode_end;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		int ret = 0;
+
+		ret =
+		    cxd2880_tnrdmd_set_scan_mode(tnr_dmd->diver_sub, sys,
+						 scan_mode_end);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
+			       struct cxd2880_tnrdmd_pid_ftr_cfg
+			       *pid_ftr_cfg)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS)
+		return -EOPNOTSUPP;
+
+	if (pid_ftr_cfg) {
+		tnr_dmd->pid_ftr_cfg = *pid_ftr_cfg;
+		tnr_dmd->pid_ftr_cfg_en = 1;
+	} else {
+		tnr_dmd->pid_ftr_cfg_en = 0;
+	}
+
+	if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) {
+		ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     int (*rf_lvl_cmpstn)
+				     (struct cxd2880_tnrdmd *,
+				     int *))
+{
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	tnr_dmd->rf_lvl_cmpstn = rf_lvl_cmpstn;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd
+					 *tnr_dmd,
+					 int (*rf_lvl_cmpstn)
+					 (struct cxd2880_tnrdmd *,
+					 int *))
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_set_rf_lvl_cmpstn(tnr_dmd->diver_sub,
+					       rf_lvl_cmpstn);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
+				struct cxd2880_tnrdmd_lna_thrs_tbl_air
+				*tbl_air,
+				struct cxd2880_tnrdmd_lna_thrs_tbl_cable
+				*tbl_cable)
+{
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	tnr_dmd->lna_thrs_tbl_air = tbl_air;
+	tnr_dmd->lna_thrs_tbl_cable = tbl_cable;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				    struct
+				    cxd2880_tnrdmd_lna_thrs_tbl_air
+				    *tbl_air,
+				    struct cxd2880_tnrdmd_lna_thrs_tbl_cable
+				    *tbl_cable)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_set_lna_thrs(tnr_dmd->diver_sub,
+					  tbl_air, tbl_cable);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 en, u8 value)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+		return -EPERM;
+
+	if (tnr_dmd->create_param.ts_output_if != CXD2880_TNRDMD_TSOUT_IF_TS)
+		return -EOPNOTSUPP;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	if (en) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x50, ((value & 0x1f) | 0x80));
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x52, (value & 0x1f));
+		if (ret)
+			return ret;
+	} else {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x50, 0x3f);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x52, 0x1f);
+		if (ret)
+			return ret;
+
+		ret = load_cfg_mem(tnr_dmd);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
+				 u8 en)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	switch (tnr_dmd->create_param.ts_output_if) {
+	case CXD2880_TNRDMD_TSOUT_IF_TS:
+		if (en) {
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_SYS,
+						     0x00, 0x00);
+			if (ret)
+				return ret;
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_SYS,
+						     0x52, 0x00);
+			if (ret)
+				return ret;
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x00, 0x00);
+			if (ret)
+				return ret;
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0xc3, 0x00);
+			if (ret)
+				return ret;
+		} else {
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x00, 0x00);
+			if (ret)
+				return ret;
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0xc3, 0x01);
+			if (ret)
+				return ret;
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_SYS,
+						     0x00, 0x00);
+			if (ret)
+				return ret;
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_SYS,
+						     0x52, 0x1f);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_TNRDMD_TSOUT_IF_SPI:
+		break;
+
+	case CXD2880_TNRDMD_TSOUT_IF_SDIO:
+		break;
+
+	default:
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	switch (tnr_dmd->create_param.ts_output_if) {
+	case CXD2880_TNRDMD_TSOUT_IF_SPI:
+	case CXD2880_TNRDMD_TSOUT_IF_SDIO:
+		{
+			u8 data = 0;
+
+			ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x00, &data, 1);
+			if (ret)
+				return ret;
+		}
+		break;
+	case CXD2880_TNRDMD_TSOUT_IF_TS:
+	default:
+		break;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x01, 0x01);
+	if (ret)
+		return ret;
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
new file mode 100644
index 000000000000..c168c9f27dad
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
@@ -0,0 +1,391 @@
+/*
+ * cxd2880_tnrdmd.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common control interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_H
+#define CXD2880_TNRDMD_H
+
+#include <linux/atomic.h>
+
+#include "cxd2880_common.h"
+#include "cxd2880_io.h"
+#include "cxd2880_dtv.h"
+#include "cxd2880_dvbt.h"
+#include "cxd2880_dvbt2.h"
+
+#define CXD2880_TNRDMD_MAX_CFG_MEM_COUNT 100
+
+#define slvt_unfreeze_reg(tnr_dmd) ((void)((tnr_dmd)->io->write_reg\
+((tnr_dmd)->io, CXD2880_IO_TGT_DMD, 0x01, 0x00)))
+
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_UNDERFLOW     0x0001
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_OVERFLOW      0x0002
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_EMPTY  0x0004
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_FULL   0x0008
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_RRDY	  0x0010
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_COMMAND      0x0020
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_ACCESS       0x0040
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_CPU_ERROR	    0x0100
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_LOCK		 0x0200
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_INV_LOCK	     0x0400
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_NOOFDM	       0x0800
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_EWS		  0x1000
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_EEW		  0x2000
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_FEC_FAIL	     0x4000
+
+#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_L1POST_OK	0x01
+#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_DMD_LOCK	 0x02
+#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_TS_LOCK	  0x04
+
+enum cxd2880_tnrdmd_chip_id {
+	CXD2880_TNRDMD_CHIP_ID_UNKNOWN = 0x00,
+	CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X = 0x62,
+	CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11 = 0x6a
+};
+
+#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) (((chip_id) == \
+CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \
+((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11))
+
+enum cxd2880_tnrdmd_state {
+	CXD2880_TNRDMD_STATE_UNKNOWN,
+	CXD2880_TNRDMD_STATE_SLEEP,
+	CXD2880_TNRDMD_STATE_ACTIVE,
+	CXD2880_TNRDMD_STATE_INVALID
+};
+
+enum cxd2880_tnrdmd_divermode {
+	CXD2880_TNRDMD_DIVERMODE_SINGLE,
+	CXD2880_TNRDMD_DIVERMODE_MAIN,
+	CXD2880_TNRDMD_DIVERMODE_SUB
+};
+
+enum cxd2880_tnrdmd_clockmode {
+	CXD2880_TNRDMD_CLOCKMODE_UNKNOWN,
+	CXD2880_TNRDMD_CLOCKMODE_A,
+	CXD2880_TNRDMD_CLOCKMODE_B,
+	CXD2880_TNRDMD_CLOCKMODE_C
+};
+
+enum cxd2880_tnrdmd_tsout_if {
+	CXD2880_TNRDMD_TSOUT_IF_TS,
+	CXD2880_TNRDMD_TSOUT_IF_SPI,
+	CXD2880_TNRDMD_TSOUT_IF_SDIO
+};
+
+enum cxd2880_tnrdmd_xtal_share {
+	CXD2880_TNRDMD_XTAL_SHARE_NONE,
+	CXD2880_TNRDMD_XTAL_SHARE_EXTREF,
+	CXD2880_TNRDMD_XTAL_SHARE_MASTER,
+	CXD2880_TNRDMD_XTAL_SHARE_SLAVE
+};
+
+enum cxd2880_tnrdmd_spectrum_sense {
+	CXD2880_TNRDMD_SPECTRUM_NORMAL,
+	CXD2880_TNRDMD_SPECTRUM_INV
+};
+
+enum cxd2880_tnrdmd_cfg_id {
+	CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB,
+	CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI,
+	CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI,
+	CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI,
+	CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE,
+	CXD2880_TNRDMD_CFG_TSCLK_CONT,
+	CXD2880_TNRDMD_CFG_TSCLK_MASK,
+	CXD2880_TNRDMD_CFG_TSVALID_MASK,
+	CXD2880_TNRDMD_CFG_TSERR_MASK,
+	CXD2880_TNRDMD_CFG_TSERR_VALID_DIS,
+	CXD2880_TNRDMD_CFG_TSPIN_CURRENT,
+	CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL,
+	CXD2880_TNRDMD_CFG_TSPIN_PULLUP,
+	CXD2880_TNRDMD_CFG_TSCLK_FREQ,
+	CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL,
+	CXD2880_TNRDMD_CFG_TS_PACKET_GAP,
+	CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE,
+	CXD2880_TNRDMD_CFG_PWM_VALUE,
+	CXD2880_TNRDMD_CFG_INTERRUPT,
+	CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL,
+	CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL,
+	CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS,
+	CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS,
+	CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS,
+	CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE,
+	CXD2880_TNRDMD_CFG_CABLE_INPUT,
+	CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE,
+	CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE,
+	CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST,
+	CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
+	CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
+	CXD2880_TNRDMD_CFG_DVBT_PER_MES,
+	CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
+	CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
+	CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
+};
+
+enum cxd2880_tnrdmd_lock_result {
+	CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT,
+	CXD2880_TNRDMD_LOCK_RESULT_LOCKED,
+	CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED
+};
+
+enum cxd2880_tnrdmd_gpio_mode {
+	CXD2880_TNRDMD_GPIO_MODE_OUTPUT = 0x00,
+	CXD2880_TNRDMD_GPIO_MODE_INPUT = 0x01,
+	CXD2880_TNRDMD_GPIO_MODE_INT = 0x02,
+	CXD2880_TNRDMD_GPIO_MODE_FEC_FAIL = 0x03,
+	CXD2880_TNRDMD_GPIO_MODE_PWM = 0x04,
+	CXD2880_TNRDMD_GPIO_MODE_EWS = 0x05,
+	CXD2880_TNRDMD_GPIO_MODE_EEW = 0x06
+};
+
+enum cxd2880_tnrdmd_serial_ts_clk {
+	CXD2880_TNRDMD_SERIAL_TS_CLK_FULL,
+	CXD2880_TNRDMD_SERIAL_TS_CLK_HALF
+};
+
+struct cxd2880_tnrdmd_cfg_mem {
+	enum cxd2880_io_tgt tgt;
+	u8 bank;
+	u8 address;
+	u8 value;
+	u8 bit_mask;
+};
+
+struct cxd2880_tnrdmd_pid_cfg {
+	u8 is_en;
+	u16 pid;
+};
+
+struct cxd2880_tnrdmd_pid_ftr_cfg {
+	u8 is_negative;
+	struct cxd2880_tnrdmd_pid_cfg pid_cfg[32];
+};
+
+struct cxd2880_tnrdmd_ts_buf_info {
+	u8 read_ready;
+	u8 almost_full;
+	u8 almost_empty;
+	u8 overflow;
+	u8 underflow;
+	u16 packet_num;
+};
+
+struct cxd2880_tnrdmd_lna_thrs {
+	u8 off_on;
+	u8 on_off;
+};
+
+struct cxd2880_tnrdmd_lna_thrs_tbl_air {
+	struct cxd2880_tnrdmd_lna_thrs thrs[24];
+};
+
+struct cxd2880_tnrdmd_lna_thrs_tbl_cable {
+	struct cxd2880_tnrdmd_lna_thrs thrs[32];
+};
+
+struct cxd2880_tnrdmd_create_param {
+	enum cxd2880_tnrdmd_tsout_if ts_output_if;
+	u8 en_internal_ldo;
+	enum cxd2880_tnrdmd_xtal_share xtal_share_type;
+	u8 xosc_cap;
+	u8 xosc_i;
+	u8 is_cxd2881gg;
+	u8 stationary_use;
+};
+
+struct cxd2880_tnrdmd_diver_create_param {
+	enum cxd2880_tnrdmd_tsout_if ts_output_if;
+	u8 en_internal_ldo;
+	u8 xosc_cap_main;
+	u8 xosc_i_main;
+	u8 xosc_i_sub;
+	u8 is_cxd2881gg;
+	u8 stationary_use;
+};
+
+struct cxd2880_tnrdmd {
+	struct cxd2880_tnrdmd *diver_sub;
+	struct cxd2880_io *io;
+	struct cxd2880_tnrdmd_create_param create_param;
+	enum cxd2880_tnrdmd_divermode diver_mode;
+	enum cxd2880_tnrdmd_clockmode fixed_clk_mode;
+	u8 is_cable_input;
+	u8 en_fef_intmtnt_base;
+	u8 en_fef_intmtnt_lite;
+	u8 blind_tune_dvbt2_first;
+	int (*rf_lvl_cmpstn)(struct cxd2880_tnrdmd *tnr_dmd,
+			     int *rf_lvl_db);
+	struct cxd2880_tnrdmd_lna_thrs_tbl_air *lna_thrs_tbl_air;
+	struct cxd2880_tnrdmd_lna_thrs_tbl_cable *lna_thrs_tbl_cable;
+	u8 srl_ts_clk_mod_cnts;
+	enum cxd2880_tnrdmd_serial_ts_clk srl_ts_clk_frq;
+	u8 ts_byte_clk_manual_setting;
+	u8 is_ts_backwards_compatible_mode;
+	struct cxd2880_tnrdmd_cfg_mem cfg_mem[CXD2880_TNRDMD_MAX_CFG_MEM_COUNT];
+	u8 cfg_mem_last_entry;
+	struct cxd2880_tnrdmd_pid_ftr_cfg pid_ftr_cfg;
+	u8 pid_ftr_cfg_en;
+	void *user;
+	enum cxd2880_tnrdmd_chip_id chip_id;
+	enum cxd2880_tnrdmd_state state;
+	enum cxd2880_tnrdmd_clockmode clk_mode;
+	u32 frequency_khz;
+	enum cxd2880_dtv_sys sys;
+	enum cxd2880_dtv_bandwidth bandwidth;
+	u8 scan_mode;
+	atomic_t cancel;
+};
+
+int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
+			  struct cxd2880_io *io,
+			  struct cxd2880_tnrdmd_create_param
+			  *create_param);
+
+int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
+				*tnr_dmd_main,
+				struct cxd2880_io *io_main,
+				struct cxd2880_tnrdmd *tnr_dmd_sub,
+				struct cxd2880_io *io_sub,
+				struct
+				cxd2880_tnrdmd_diver_create_param
+				*create_param);
+
+int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
+					     *tnr_dmd,
+					     u8 *task_completed);
+
+int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd
+					*tnr_dmd,
+					enum cxd2880_dtv_sys sys,
+					u32 frequency_khz,
+					enum cxd2880_dtv_bandwidth
+					bandwidth, u8 one_seg_opt,
+					u8 one_seg_opt_shft_dir);
+
+int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
+					*tnr_dmd,
+					enum cxd2880_dtv_sys sys,
+					u8 en_fef_intmtnt_ctrl);
+
+int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+			   enum cxd2880_tnrdmd_cfg_id id,
+			   int value);
+
+int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+				u8 id,
+				u8 en,
+				enum cxd2880_tnrdmd_gpio_mode mode,
+				u8 open_drain, u8 invert);
+
+int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				    u8 id,
+				    u8 en,
+				    enum cxd2880_tnrdmd_gpio_mode
+				    mode, u8 open_drain,
+				    u8 invert);
+
+int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
+			     u8 id, u8 *value);
+
+int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				 u8 id, u8 *value);
+
+int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
+			      u8 id, u8 value);
+
+int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				  u8 id, u8 value);
+
+int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
+				  u16 *value);
+
+int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
+				   u16 value);
+
+int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
+				u8 clear_overflow_flag,
+				u8 clear_underflow_flag,
+				u8 clear_buf);
+
+int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
+			   enum cxd2880_tnrdmd_chip_id *chip_id);
+
+int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
+					 *tnr_dmd,
+					 enum cxd2880_io_tgt tgt,
+					 u8 bank, u8 address,
+					 u8 value, u8 bit_mask);
+
+int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
+				 enum cxd2880_dtv_sys sys,
+				 u8 scan_mode_end);
+
+int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
+			       struct cxd2880_tnrdmd_pid_ftr_cfg
+			       *pid_ftr_cfg);
+
+int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     int (*rf_lvl_cmpstn)
+				     (struct cxd2880_tnrdmd *,
+				     int *));
+
+int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd *tnr_dmd,
+					 int (*rf_lvl_cmpstn)
+					 (struct cxd2880_tnrdmd *,
+					 int *));
+
+int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
+				struct
+				cxd2880_tnrdmd_lna_thrs_tbl_air
+				*tbl_air,
+				struct
+				cxd2880_tnrdmd_lna_thrs_tbl_cable
+				*tbl_cable);
+
+int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				    struct
+				    cxd2880_tnrdmd_lna_thrs_tbl_air
+				    *tbl_air,
+				    struct
+				    cxd2880_tnrdmd_lna_thrs_tbl_cable
+				    *tbl_cable);
+
+int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 en, u8 value);
+
+int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
+				 u8 en);
+
+int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
new file mode 100644
index 000000000000..bb0f6b295ed3
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
@@ -0,0 +1,29 @@
+/*
+ * cxd2880_tnrdmd_driver_version.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * version information
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.2"
+
+#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2017-08-07"
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
new file mode 100644
index 000000000000..1ed415af3727
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
@@ -0,0 +1,221 @@
+/*
+ * cxd2880_tnrdmd_mon.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common monitor functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd_mon.h"
+
+int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
+			      int *rf_lvl_db)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!rf_lvl_db))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	{
+		u8 data[2] = { 0x80, 0x00 };
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x5b, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	usleep_range(2000, 3000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x1a);
+	if (ret)
+		return ret;
+
+	{
+		u8 data[2];
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x15, data, 2);
+		if (ret)
+			return ret;
+
+		if ((data[0] != 0) || (data[1] != 0))
+			return -EPERM;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x11, data, 2);
+		if (ret)
+			return ret;
+
+		*rf_lvl_db =
+		    cxd2880_convert2s_complement((data[0] << 3) |
+						 ((data[1] & 0xe0) >> 5), 11);
+	}
+
+	*rf_lvl_db *= 125;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x00);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->rf_lvl_cmpstn) {
+		ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				  int *rf_lvl_db)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!rf_lvl_db))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
+					   *tnr_dmd, u16 *status)
+{
+	u8 data[2] = { 0 };
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!status))
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x1a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x15, data, 2);
+	if (ret)
+		return ret;
+
+	*status = (data[0] << 8) | data[1];
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
+					       cxd2880_tnrdmd
+					       *tnr_dmd,
+					       u16 *status)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!status))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub, status);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd,
+				   struct
+				   cxd2880_tnrdmd_ts_buf_info
+				   *info)
+{
+	u8 data[3] = { 0 };
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!info))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x50, data, 3);
+	if (ret)
+		return ret;
+
+	info->read_ready = (data[0] & 0x10) ? 0x01 : 0x00;
+	info->almost_full = (data[0] & 0x08) ? 0x01 : 0x00;
+	info->almost_empty = (data[0] & 0x04) ? 0x01 : 0x00;
+	info->overflow = (data[0] & 0x02) ? 0x01 : 0x00;
+	info->underflow = (data[0] & 0x01) ? 0x01 : 0x00;
+
+	info->packet_num = ((data[1] & 0x07) << 8) | data[2];
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
new file mode 100644
index 000000000000..a4c34f56a7a1
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
@@ -0,0 +1,52 @@
+/*
+ * cxd2880_tnrdmd_mon.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common monitor interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_MON_H
+#define CXD2880_TNRDMD_MON_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+
+int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
+			      int *rf_lvl_db);
+
+int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				  int *rf_lvl_db);
+
+int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
+					   *tnr_dmd, u16 *status);
+
+int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
+					       cxd2880_tnrdmd
+					       *tnr_dmd,
+					       u16 *status);
+
+int cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd,
+				   struct
+				   cxd2880_tnrdmd_ts_buf_info
+				   *info);
+
+#endif
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 05/14] [media] cxd2880: Add tuner part of the driver
@ 2017-08-16  4:37   ` Yasunari.Takiguchi
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:37 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

This part of the driver has the main routines to handle
the tuner and demodulator functionality.  The tnrdmd_mon.* files
have monitor functions for the driver.
This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
      -removed code relevant to ISDB-T
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
      -removed unnecessary cast
      -removed code relevant to ISDB-T
      -changed CXD2880_SLEEP to usleep_range
      -changed cxd2880_memset to memset 
      -changed cxd2880_atomic_set to atomic_set
      -modified return code
      -modified coding style of if()
      -changed to use const values at writing a lot of registers 
       with a command. 
      -changed hexadecimal code to lower case. 
      -adjusted of indent spaces
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
      -removed code relevant to ISDB-T
      -changed cxd2880_atomic struct to atomic_t
      -modified return code
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
      -updated version information
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
      -changed CXD2880_SLEEP to usleep_range
      -removed unnecessary cast
      -modified return code
      -modified coding style of if() 
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
      -modified return code

Changes in V2
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
      -updated version information

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h  |   46 +
 .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c   | 4030 ++++++++++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h   |  391 ++
 .../cxd2880/cxd2880_tnrdmd_driver_version.h        |   29 +
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c     |  221 ++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h     |   52 +
 6 files changed, 4769 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
new file mode 100644
index 000000000000..2d35d3990060
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
@@ -0,0 +1,46 @@
+/*
+ * cxd2880_dtv.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DTV related definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_DTV_H
+#define CXD2880_DTV_H
+
+enum cxd2880_dtv_sys {
+	CXD2880_DTV_SYS_UNKNOWN,
+	CXD2880_DTV_SYS_DVBT,
+	CXD2880_DTV_SYS_DVBT2,
+	CXD2880_DTV_SYS_ANY
+};
+
+enum cxd2880_dtv_bandwidth {
+	CXD2880_DTV_BW_UNKNOWN = 0,
+	CXD2880_DTV_BW_1_7_MHZ = 1,
+	CXD2880_DTV_BW_5_MHZ = 5,
+	CXD2880_DTV_BW_6_MHZ = 6,
+	CXD2880_DTV_BW_7_MHZ = 7,
+	CXD2880_DTV_BW_8_MHZ = 8
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
new file mode 100644
index 000000000000..044dc26d2ff3
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
@@ -0,0 +1,4030 @@
+/*
+ * cxd2880_tnrdmd.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common control functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_tnrdmd_dvbt2.h"
+
+static int p_init1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data = 0;
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) ||
+	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)) {
+		switch (tnr_dmd->create_param.ts_output_if) {
+		case CXD2880_TNRDMD_TSOUT_IF_TS:
+			data = 0x00;
+			break;
+		case CXD2880_TNRDMD_TSOUT_IF_SPI:
+			data = 0x01;
+			break;
+		case CXD2880_TNRDMD_TSOUT_IF_SDIO:
+			data = 0x02;
+			break;
+		default:
+			return -EINVAL;
+		}
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x10, data);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x11, 0x16);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	switch (tnr_dmd->chip_id) {
+	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X:
+		data = 0x1a;
+		break;
+	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11:
+		data = 0x16;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x10, data);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->create_param.en_internal_ldo)
+		data = 0x01;
+	else
+		data = 0x00;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x11, data);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x13, data);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x12, data);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	switch (tnr_dmd->chip_id) {
+	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X:
+		data = 0x01;
+		break;
+	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11:
+		data = 0x00;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x69, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int p_init2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[6] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	data[0] = tnr_dmd->create_param.xosc_cap;
+	data[1] = tnr_dmd->create_param.xosc_i;
+	switch (tnr_dmd->create_param.xtal_share_type) {
+	case CXD2880_TNRDMD_XTAL_SHARE_NONE:
+		data[2] = 0x01;
+		data[3] = 0x00;
+		break;
+	case CXD2880_TNRDMD_XTAL_SHARE_EXTREF:
+		data[2] = 0x00;
+		data[3] = 0x00;
+		break;
+	case CXD2880_TNRDMD_XTAL_SHARE_MASTER:
+		data[2] = 0x01;
+		data[3] = 0x01;
+		break;
+	case CXD2880_TNRDMD_XTAL_SHARE_SLAVE:
+		data[2] = 0x00;
+		data[3] = 0x01;
+		break;
+	default:
+		return -EINVAL;
+	}
+	data[4] = 0x06;
+	data[5] = 0x00;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x13,
+				      data,
+				      6);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int p_init3(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[2] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	switch (tnr_dmd->diver_mode) {
+	case CXD2880_TNRDMD_DIVERMODE_SINGLE:
+		data[0] = 0x00;
+		break;
+	case CXD2880_TNRDMD_DIVERMODE_MAIN:
+		data[0] = 0x03;
+		break;
+	case CXD2880_TNRDMD_DIVERMODE_SUB:
+		data[0] = 0x02;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	data[1] = 0x01;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x1f, data, 2);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rf_init1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[8] = { 0 };
+	u8 addr = 0;
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	data[0] = 0x01;
+	data[1] = 0x00;
+	data[2] = 0x01;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x21, data, 3);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	data[0] = 0x01;
+	data[1] = 0x01;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x17, data, 2);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->create_param.stationary_use) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x1a, 0x06);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x4f, 0x18);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x61, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x71, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x9d, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x7d, 0x02);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x8f, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x8b, 0xc6);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x9a, 0x03);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x1c, 0x00);
+	if (ret)
+		return ret;
+	data[0] = 0x00;
+	if ((tnr_dmd->create_param.is_cxd2881gg) &&
+	    (tnr_dmd->create_param.xtal_share_type ==
+		CXD2880_TNRDMD_XTAL_SHARE_SLAVE))
+		data[1] = 0x00;
+	else
+		data[1] = 0x1f;
+	data[2] = 0x0a;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xb5, data, 3);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xb9, 0x07);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x33, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xc1, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xc4, 0x1e);
+	if (ret)
+		return ret;
+	if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) {
+		data[0] = 0x34;
+		data[1] = 0x2c;
+	} else {
+		data[0] = 0x2f;
+		data[1] = 0x25;
+	}
+	data[2] = 0x15;
+	data[3] = 0x19;
+	data[4] = 0x1b;
+	data[5] = 0x15;
+	data[6] = 0x19;
+	data[7] = 0x1b;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xd9, data, 8);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x11);
+	if (ret)
+		return ret;
+	data[0] = 0x6c;
+	data[1] = 0x10;
+	data[2] = 0xa6;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x44, data, 3);
+	if (ret)
+		return ret;
+	data[0] = 0x16;
+	data[1] = 0xa8;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x50, data, 2);
+	if (ret)
+		return ret;
+	data[0] = 0x00;
+	data[1] = 0x22;
+	data[2] = 0x00;
+	data[3] = 0x88;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x62, data, 4);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x74, 0x75);
+	if (ret)
+		return ret;
+	{
+		const u8 cdata[] = {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+				    0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03,
+				    0x03, 0x04, 0x04, 0x05, 0x05, 0x05, 0x02,
+				    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+				    0x02, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02,
+				    0x02, 0x03, 0x04, 0x04, 0x04};
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x7f, cdata, 40);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x16);
+	if (ret)
+		return ret;
+	data[0] = 0x00;
+	data[1] = 0x71;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x10, data, 2);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x23, 0x89);
+	if (ret)
+		return ret;
+
+	{
+		const u8 cdata[] = {0xff, 0x00, 0x00, 0x00, 0x00};
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x27, cdata, 5);
+		if (ret)
+			return ret;
+	}
+
+	{
+		const u8 cdata[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+				    0x01, 0x00, 0x02, 0x00, 0x63, 0x00, 0x00,
+				    0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00,
+				    0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x09,
+				    0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0d, 0x00,
+				    0x0d, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f,
+				    0x00, 0x10, 0x00, 0x79, 0x00, 0x00, 0x00,
+				    0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01,
+				    0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
+				    0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05,
+				    0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00,
+				    0x0a, 0x03, 0xe0};
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x3a, cdata, 80);
+		if (ret)
+			return ret;
+	}
+
+	data[0] = 0x03;
+	data[1] = 0xe0;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xbc, data, 2);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x51, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xc5, 0x07);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x11);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x70, 0xe9);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x76, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x78, 0x32);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x7a, 0x46);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x7c, 0x86);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x7e, 0xa4);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xe1, 0x01);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->create_param.stationary_use) {
+		data[0] = 0x06;
+		data[1] = 0x07;
+		data[2] = 0x1a;
+	} else {
+		data[0] = 0x00;
+		data[1] = 0x08;
+		data[2] = 0x19;
+	}
+	data[3] = 0x0e;
+	data[4] = 0x09;
+	data[5] = 0x0e;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x12);
+	if (ret)
+		return ret;
+	for (addr = 0x10; addr < 0x9f; addr += 6) {
+		if (tnr_dmd->lna_thrs_tbl_air) {
+			u8 idx = 0;
+
+			idx = (addr - 0x10) / 6;
+			data[0] =
+			    tnr_dmd->lna_thrs_tbl_air->thrs[idx].off_on;
+			data[1] =
+			    tnr_dmd->lna_thrs_tbl_air->thrs[idx].on_off;
+		}
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      addr, data, 6);
+		if (ret)
+			return ret;
+	}
+
+	data[0] = 0x00;
+	data[1] = 0x08;
+	if (tnr_dmd->create_param.stationary_use)
+		data[2] = 0x1a;
+	else
+		data[2] = 0x19;
+	data[3] = 0x0e;
+	data[4] = 0x09;
+	data[5] = 0x0e;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x13);
+	if (ret)
+		return ret;
+	for (addr = 0x10; addr < 0xcf; addr += 6) {
+		if (tnr_dmd->lna_thrs_tbl_cable) {
+			u8 idx = 0;
+
+			idx = (addr - 0x10) / 6;
+			data[0] =
+			    tnr_dmd->lna_thrs_tbl_cable->thrs[idx].off_on;
+			data[1] =
+			    tnr_dmd->lna_thrs_tbl_cable->thrs[idx].on_off;
+		}
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      addr, data, 6);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x11);
+	if (ret)
+		return ret;
+	data[0] = 0x08;
+	data[1] = 0x09;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xbd, data, 2);
+	if (ret)
+		return ret;
+	data[0] = 0x08;
+	data[1] = 0x09;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xc4, data, 2);
+	if (ret)
+		return ret;
+
+	{
+		const u8 cdata[] = {0x20, 0x20, 0x30, 0x41, 0x50, 0x5f,
+				    0x6f, 0x80};
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0xc9, cdata, 8);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x14);
+	if (ret)
+		return ret;
+	data[0] = 0x15;
+	data[1] = 0x18;
+	data[2] = 0x00;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x10, data, 3);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x15, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x16);
+	if (ret)
+		return ret;
+
+	{
+		const u8 cdata[] = {0x00, 0x09, 0x00, 0x08, 0x00, 0x07, 0x00,
+				    0x06, 0x00, 0x05, 0x00, 0x03, 0x00, 0x02,
+				    0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
+				    0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c,
+				    0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0f, 0x00,
+				    0x0e, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f,
+				    0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f, 0x00,
+				    0x0e};
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x12, cdata, 50);
+		if (ret)
+			return ret;
+	}
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x10, data, 1);
+	if (ret)
+		return ret;
+	if ((data[0] & 0x01) == 0x00)
+		return -EBUSY;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x25, 0x00);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x11, data, 1);
+	if (ret)
+		return ret;
+	if ((data[0] & 0x01) == 0x00)
+		return -EBUSY;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x02, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0xe1);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x8f, 0x16);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x67, 0x60);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x6a, 0x0f);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x6c, 0x17);
+	if (ret)
+		return ret;
+	data[0] = 0x00;
+	data[1] = 0xfe;
+	data[2] = 0xee;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_DMD,
+				      0x6e, data, 3);
+	if (ret)
+		return ret;
+	data[0] = 0xa1;
+	data[1] = 0x8b;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_DMD,
+				      0x8d, data, 2);
+	if (ret)
+		return ret;
+	data[0] = 0x08;
+	data[1] = 0x09;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_DMD,
+				      0x77, data, 2);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->create_param.stationary_use) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x80, 0xaa);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0xe2);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x41, 0xa0);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x4b, 0x68);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x25, 0x01);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x1a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x10, data, 1);
+	if (ret)
+		return ret;
+	if ((data[0] & 0x01) == 0x00)
+		return -EBUSY;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x14, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x26, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rf_init2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[5] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	data[0] = 0x40;
+	data[1] = 0x40;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xea, data, 2);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	data[0] = 0x00;
+	if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X)
+		data[1] = 0x00;
+	else
+		data[1] = 0x01;
+	data[2] = 0x01;
+	data[3] = 0x03;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x30, data, 4);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x14);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x1b, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0xe1);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xd3, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+		   enum cxd2880_dtv_sys sys, u32 freq_khz,
+		   enum cxd2880_dtv_bandwidth bandwidth,
+		   u8 is_cable, int shift_frequency_khz)
+{
+	u8 data[11] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	data[0] = 0x00;
+	data[1] = 0x00;
+	data[2] = 0x0e;
+	data[3] = 0x00;
+	data[4] = 0x03;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xe7, data, 5);
+	if (ret)
+		return ret;
+
+	data[0] = 0x1f;
+	data[1] = 0x80;
+	data[2] = 0x18;
+	data[3] = 0x00;
+	data[4] = 0x07;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xe7, data, 5);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	data[0] = 0x72;
+	data[1] = 0x81;
+	data[3] = 0x1d;
+	data[4] = 0x6f;
+	data[5] = 0x7e;
+	data[7] = 0x1c;
+	switch (sys) {
+	case CXD2880_DTV_SYS_DVBT:
+		data[2] = 0x94;
+		data[6] = 0x91;
+		break;
+	case CXD2880_DTV_SYS_DVBT2:
+		data[2] = 0x96;
+		data[6] = 0x93;
+		break;
+	default:
+		return -EINVAL;
+	}
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x44, data, 8);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x62, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x15);
+	if (ret)
+		return ret;
+	data[0] = 0x03;
+	data[1] = 0xe2;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x1e, data, 2);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	data[0] = is_cable ? 0x01 : 0x00;
+	data[1] = 0x00;
+	data[2] = 0x6b;
+	data[3] = 0x4d;
+
+	switch (bandwidth) {
+	case CXD2880_DTV_BW_1_7_MHZ:
+		data[4] = 0x03;
+		break;
+	case CXD2880_DTV_BW_5_MHZ:
+	case CXD2880_DTV_BW_6_MHZ:
+		data[4] = 0x00;
+		break;
+	case CXD2880_DTV_BW_7_MHZ:
+		data[4] = 0x01;
+		break;
+	case CXD2880_DTV_BW_8_MHZ:
+		data[4] = 0x02;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	data[5] = 0x00;
+
+	freq_khz += shift_frequency_khz;
+
+	data[6] = (freq_khz >> 16) & 0x0f;
+	data[7] = (freq_khz >> 8) & 0xff;
+	data[8] = freq_khz & 0xff;
+	data[9] = 0xff;
+	data[10] = 0xfe;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x52, data, 11);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+		   enum cxd2880_dtv_bandwidth bandwidth,
+		   enum cxd2880_tnrdmd_clockmode clk_mode,
+		   int shift_frequency_khz)
+{
+	u8 data[3] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x11);
+	if (ret)
+		return ret;
+
+	data[0] = 0x01;
+	data[1] = 0x0e;
+	data[2] = 0x01;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x2d, data, 3);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x1a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x29, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x2c, data, 1);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x60, data[0]);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x62, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x11);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x2d, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x2f, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x01);
+	if (ret)
+		return ret;
+
+	if (shift_frequency_khz != 0) {
+		int shift_freq = 0;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0xe1);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x60, data, 2);
+		if (ret)
+			return ret;
+
+		shift_freq = shift_frequency_khz * 1000;
+
+		switch (clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+		default:
+			if (shift_freq >= 0)
+				shift_freq = (shift_freq + 183 / 2) / 183;
+			else
+				shift_freq = (shift_freq - 183 / 2) / 183;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			if (shift_freq >= 0)
+				shift_freq = (shift_freq + 178 / 2) / 178;
+			else
+				shift_freq = (shift_freq - 178 / 2) / 178;
+			break;
+		}
+
+		shift_freq +=
+		    cxd2880_convert2s_complement((data[0] << 8) | data[1], 16);
+
+		if (shift_freq > 32767)
+			shift_freq = 32767;
+		else if (shift_freq < -32768)
+			shift_freq = -32768;
+
+		data[0] = (shift_freq >> 8) & 0xff;
+		data[1] = shift_freq & 0xff;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x60, data, 2);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x69, data, 1);
+		if (ret)
+			return ret;
+
+		shift_freq = -shift_frequency_khz;
+
+		if (bandwidth == CXD2880_DTV_BW_1_7_MHZ) {
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+			default:
+				if (shift_freq >= 0)
+					shift_freq =
+					    (shift_freq * 1000 +
+					     17578 / 2) / 17578;
+				else
+					shift_freq =
+					    (shift_freq * 1000 -
+					     17578 / 2) / 17578;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				if (shift_freq >= 0)
+					shift_freq =
+					    (shift_freq * 1000 +
+					     17090 / 2) / 17090;
+				else
+					shift_freq =
+					    (shift_freq * 1000 -
+					     17090 / 2) / 17090;
+				break;
+			}
+		} else {
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+			default:
+				if (shift_freq >= 0)
+					shift_freq =
+					    (shift_freq * 1000 +
+					     35156 / 2) / 35156;
+				else
+					shift_freq =
+					    (shift_freq * 1000 -
+					     35156 / 2) / 35156;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				if (shift_freq >= 0)
+					shift_freq =
+					    (shift_freq * 1000 +
+					     34180 / 2) / 34180;
+				else
+					shift_freq =
+					    (shift_freq * 1000 -
+					     34180 / 2) / 34180;
+				break;
+			}
+		}
+
+		shift_freq += cxd2880_convert2s_complement(data[0], 8);
+
+		if (shift_freq > 127)
+			shift_freq = 127;
+		else if (shift_freq < -128)
+			shift_freq = -128;
+
+		data[0] = shift_freq & 0xff;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x69, data[0]);
+		if (ret)
+			return ret;
+	}
+
+	if (tnr_dmd->create_param.stationary_use) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0xe1);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x8a, 0x87);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_tune3(struct cxd2880_tnrdmd *tnr_dmd,
+		   enum cxd2880_dtv_sys sys,
+		   u8 en_fef_intmtnt_ctrl)
+{
+	u8 data[6] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0xe2);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x41, 0xa0);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xfe, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl) {
+		data[0] = 0x01;
+		data[1] = 0x01;
+		data[2] = 0x01;
+		data[3] = 0x01;
+		data[4] = 0x01;
+		data[5] = 0x01;
+	} else {
+		data[0] = 0x00;
+		data[1] = 0x00;
+		data[2] = 0x00;
+		data[3] = 0x00;
+		data[4] = 0x00;
+		data[5] = 0x00;
+	}
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0xef, data, 6);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x2d);
+	if (ret)
+		return ret;
+	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
+		data[0] = 0x00;
+	else
+		data[0] = 0x01;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xb1, data[0]);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_tune4(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[2] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	{
+		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+							CXD2880_IO_TGT_SYS,
+							0x00, 0x00);
+		if (ret)
+			return ret;
+		data[0] = 0x14;
+		data[1] = 0x00;
+		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+							CXD2880_IO_TGT_SYS,
+							0x55, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	{
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00, 0x00);
+		if (ret)
+			return ret;
+		data[0] = 0x0b;
+		data[1] = 0xff;
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x53, data, 2);
+		if (ret)
+			return ret;
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x57, 0x01);
+		if (ret)
+			return ret;
+		data[0] = 0x0b;
+		data[1] = 0xff;
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x55, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	{
+		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+							CXD2880_IO_TGT_SYS,
+							0x00, 0x00);
+		if (ret)
+			return ret;
+		data[0] = 0x14;
+		data[1] = 0x00;
+		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+							 CXD2880_IO_TGT_SYS,
+							 0x53, data, 2);
+		if (ret)
+			return ret;
+		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+							CXD2880_IO_TGT_SYS,
+							0x57, 0x02);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xfe, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+						CXD2880_IO_TGT_DMD,
+						0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+						CXD2880_IO_TGT_DMD,
+						0xfe, 0x01);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_sleep1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data[3] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	{
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00, 0x00);
+		if (ret)
+			return ret;
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x57, 0x03);
+		if (ret)
+			return ret;
+		data[0] = 0x00;
+		data[1] = 0x00;
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x53, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	{
+		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
+							CXD2880_IO_TGT_SYS,
+							0x00, 0x00);
+		if (ret)
+			return ret;
+		data[0] = 0x1f;
+		data[1] = 0xff;
+		data[2] = 0x03;
+		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+							 CXD2880_IO_TGT_SYS,
+							 0x55, data, 3);
+		if (ret)
+			return ret;
+		data[0] = 0x00;
+		data[1] = 0x00;
+		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
+							 CXD2880_IO_TGT_SYS,
+							 0x53, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	{
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00, 0x00);
+		if (ret)
+			return ret;
+		data[0] = 0x1f;
+		data[1] = 0xff;
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x55, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int x_sleep2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 data = 0;
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x2d);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xb1, 0x01);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xb2, &data, 1);
+	if (ret)
+		return ret;
+	if ((data & 0x01) == 0x00)
+		return -EBUSY;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xf4, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xf3, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xf2, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xf1, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xf0, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xef, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_sleep3(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xfd, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_sleep4(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0xe2);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x41, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x21, 0x00);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int spll_reset(struct cxd2880_tnrdmd *tnr_dmd,
+		      enum cxd2880_tnrdmd_clockmode clockmode)
+{
+	u8 data[4] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x29, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x28, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x27, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x26, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x27, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x22, 0x01);
+	if (ret)
+		return ret;
+	switch (clockmode) {
+	case CXD2880_TNRDMD_CLOCKMODE_A:
+		data[0] = 0x00;
+		break;
+
+	case CXD2880_TNRDMD_CLOCKMODE_B:
+		data[0] = 0x01;
+		break;
+
+	case CXD2880_TNRDMD_CLOCKMODE_C:
+		data[0] = 0x02;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x30, data[0]);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x22, 0x00);
+	if (ret)
+		return ret;
+
+	usleep_range(2000, 3000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x10, data, 1);
+	if (ret)
+		return ret;
+	if ((data[0] & 0x01) == 0x00)
+		return -EBUSY;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x27, 0x01);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	data[0] = 0x00;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	data[3] = 0x00;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x26, data, 4);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int t_power_x(struct cxd2880_tnrdmd *tnr_dmd, u8 on)
+{
+	u8 data[3] = { 0 };
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x29, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x28, 0x01);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x27, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x27, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x25, 0x01);
+	if (ret)
+		return ret;
+
+	if (on) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x2b, 0x01);
+		if (ret)
+			return ret;
+
+		usleep_range(1000, 2000);
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00, 0x0a);
+		if (ret)
+			return ret;
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x12, data, 1);
+		if (ret)
+			return ret;
+		if ((data[0] & 0x01) == 0)
+			return -EBUSY;
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00, 0x00);
+		if (ret)
+			return ret;
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x2a, 0x00);
+		if (ret)
+			return ret;
+	} else {
+		data[0] = 0x03;
+		data[1] = 0x00;
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x2a, data, 2);
+		if (ret)
+			return ret;
+
+		usleep_range(1000, 2000);
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00, 0x0a);
+		if (ret)
+			return ret;
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x13, data, 1);
+		if (ret)
+			return ret;
+		if ((data[0] & 0x01) == 0)
+			return -EBUSY;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x25, 0x00);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x11, data, 1);
+	if (ret)
+		return ret;
+	if ((data[0] & 0x01) == 0)
+		return -EBUSY;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x27, 0x01);
+	if (ret)
+		return ret;
+
+	usleep_range(1000, 2000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+	data[0] = 0x00;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x27, data, 3);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+struct cxd2880_tnrdmd_ts_clk_cfg {
+	u8 srl_clk_mode;
+	u8 srl_duty_mode;
+	u8 ts_clk_period;
+};
+
+static int set_ts_clk_mode_and_freq(struct cxd2880_tnrdmd *tnr_dmd,
+				    enum cxd2880_dtv_sys sys)
+{
+	int ret = 0;
+	u8 backwards_compatible = 0;
+	struct cxd2880_tnrdmd_ts_clk_cfg ts_clk_cfg;
+
+	const struct cxd2880_tnrdmd_ts_clk_cfg srl_ts_clk_stgs[2][2] = {
+	{
+		{3, 1, 8,},
+		{0, 2, 16,}
+	},
+	{
+		{1, 1, 8,},
+		{2, 2, 16,}
+	}
+	};
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	{
+		u8 ts_rate_ctrl_off = 0;
+		u8 ts_in_off = 0;
+		u8 ts_clk_manaul_on = 0;
+
+		if (tnr_dmd->is_ts_backwards_compatible_mode) {
+			backwards_compatible = 1;
+			ts_rate_ctrl_off = 1;
+			ts_in_off = 1;
+		} else {
+			backwards_compatible = 0;
+			ts_rate_ctrl_off = 0;
+			ts_in_off = 0;
+		}
+
+		if (tnr_dmd->ts_byte_clk_manual_setting) {
+			ts_clk_manaul_on = 1;
+			ts_rate_ctrl_off = 0;
+		}
+
+		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xd3, ts_rate_ctrl_off, 0x01);
+		if (ret)
+			return ret;
+
+		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xde, ts_in_off, 0x01);
+		if (ret)
+			return ret;
+
+		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xda, ts_clk_manaul_on, 0x01);
+		if (ret)
+			return ret;
+	}
+
+	ts_clk_cfg = srl_ts_clk_stgs[tnr_dmd->srl_ts_clk_mod_cnts]
+				    [tnr_dmd->srl_ts_clk_frq];
+
+	if (tnr_dmd->ts_byte_clk_manual_setting)
+		ts_clk_cfg.ts_clk_period = tnr_dmd->ts_byte_clk_manual_setting;
+
+	ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+				      CXD2880_IO_TGT_DMD,
+				      0xc4, ts_clk_cfg.srl_clk_mode, 0x03);
+	if (ret)
+		return ret;
+
+	ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+				      CXD2880_IO_TGT_DMD,
+				      0xd1, ts_clk_cfg.srl_duty_mode, 0x03);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD, 0xd9,
+				     ts_clk_cfg.ts_clk_period);
+	if (ret)
+		return ret;
+
+	{
+		u8 data = backwards_compatible ? 0x00 : 0x01;
+
+		if (sys == CXD2880_DTV_SYS_DVBT) {
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x00, 0x10);
+			if (ret)
+				return ret;
+
+			ret =
+			    cxd2880_io_set_reg_bits(tnr_dmd->io,
+						    CXD2880_IO_TGT_DMD,
+						    0x66, data, 0x01);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int pid_ftr_setting(struct cxd2880_tnrdmd *tnr_dmd,
+			   struct cxd2880_tnrdmd_pid_ftr_cfg
+			   *pid_ftr_cfg)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	if (!pid_ftr_cfg) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x50, 0x02);
+		if (ret)
+			return ret;
+	} else {
+		u8 data[65];
+
+		data[0] = pid_ftr_cfg->is_negative ? 0x01 : 0x00;
+		{
+			int i = 0;
+
+			for (i = 0; i < 32; i++) {
+				if (pid_ftr_cfg->pid_cfg[i].is_en) {
+					data[1 + (i * 2)] =
+					    (pid_ftr_cfg->pid_cfg[i].pid
+					     >> 8) | 0x20;
+					data[2 + (i * 2)] =
+					    pid_ftr_cfg->pid_cfg[i].pid
+					    & 0xff;
+				} else {
+					data[1 + (i * 2)] = 0x00;
+					data[2 + (i * 2)] = 0x00;
+				}
+			}
+		}
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x50, data, 65);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+	u8 i;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     tnr_dmd->cfg_mem[i].tgt,
+					     0x00, tnr_dmd->cfg_mem[i].bank);
+		if (ret)
+			return ret;
+
+		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+					      tnr_dmd->cfg_mem[i].tgt,
+					      tnr_dmd->cfg_mem[i].address,
+					      tnr_dmd->cfg_mem[i].value,
+					      tnr_dmd->cfg_mem[i].bit_mask);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int set_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd,
+		       enum cxd2880_io_tgt tgt,
+		       u8 bank, u8 address, u8 value, u8 bit_mask)
+{
+	u8 i;
+	u8 value_stored = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) {
+		if ((value_stored == 0) &&
+		    (tnr_dmd->cfg_mem[i].tgt == tgt) &&
+		    (tnr_dmd->cfg_mem[i].bank == bank) &&
+		    (tnr_dmd->cfg_mem[i].address == address)) {
+			tnr_dmd->cfg_mem[i].value &= ~bit_mask;
+			tnr_dmd->cfg_mem[i].value |= (value & bit_mask);
+
+			tnr_dmd->cfg_mem[i].bit_mask |= bit_mask;
+
+			value_stored = 1;
+		}
+	}
+
+	if (value_stored == 0) {
+		if (tnr_dmd->cfg_mem_last_entry <
+		    CXD2880_TNRDMD_MAX_CFG_MEM_COUNT) {
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].tgt = tgt;
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bank =
+			    bank;
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].address =
+			    address;
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].value =
+			    (value & bit_mask);
+			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bit_mask =
+			    bit_mask;
+			tnr_dmd->cfg_mem_last_entry++;
+		} else {
+			return -EOVERFLOW;
+		}
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
+			  struct cxd2880_io *io,
+			  struct cxd2880_tnrdmd_create_param
+			  *create_param)
+{
+	if ((!tnr_dmd) || (!io) || (!create_param))
+		return -EINVAL;
+
+	memset(tnr_dmd, 0, sizeof(struct cxd2880_tnrdmd));
+
+	tnr_dmd->io = io;
+	tnr_dmd->create_param = *create_param;
+
+	tnr_dmd->diver_mode = CXD2880_TNRDMD_DIVERMODE_SINGLE;
+	tnr_dmd->diver_sub = NULL;
+
+	tnr_dmd->srl_ts_clk_mod_cnts = 1;
+	tnr_dmd->en_fef_intmtnt_base = 1;
+	tnr_dmd->en_fef_intmtnt_lite = 1;
+	tnr_dmd->rf_lvl_cmpstn = NULL;
+	tnr_dmd->lna_thrs_tbl_air = NULL;
+	tnr_dmd->lna_thrs_tbl_cable = NULL;
+	atomic_set(&tnr_dmd->cancel, 0);
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
+				*tnr_dmd_main,
+				struct cxd2880_io *io_main,
+				struct cxd2880_tnrdmd *tnr_dmd_sub,
+				struct cxd2880_io *io_sub,
+				struct
+				cxd2880_tnrdmd_diver_create_param
+				*create_param)
+{
+	if ((!tnr_dmd_main) || (!io_main) || (!tnr_dmd_sub) || (!io_sub) ||
+	    (!create_param))
+		return -EINVAL;
+
+	memset(tnr_dmd_main, 0, sizeof(struct cxd2880_tnrdmd));
+	memset(tnr_dmd_sub, 0, sizeof(struct cxd2880_tnrdmd));
+
+	tnr_dmd_main->io = io_main;
+	tnr_dmd_main->diver_mode = CXD2880_TNRDMD_DIVERMODE_MAIN;
+	tnr_dmd_main->diver_sub = tnr_dmd_sub;
+	tnr_dmd_main->create_param.en_internal_ldo =
+	    create_param->en_internal_ldo;
+	tnr_dmd_main->create_param.ts_output_if = create_param->ts_output_if;
+	tnr_dmd_main->create_param.xtal_share_type =
+	    CXD2880_TNRDMD_XTAL_SHARE_MASTER;
+	tnr_dmd_main->create_param.xosc_cap = create_param->xosc_cap_main;
+	tnr_dmd_main->create_param.xosc_i = create_param->xosc_i_main;
+	tnr_dmd_main->create_param.is_cxd2881gg = create_param->is_cxd2881gg;
+	tnr_dmd_main->create_param.stationary_use =
+	    create_param->stationary_use;
+
+	tnr_dmd_sub->io = io_sub;
+	tnr_dmd_sub->diver_mode = CXD2880_TNRDMD_DIVERMODE_SUB;
+	tnr_dmd_sub->diver_sub = NULL;
+	tnr_dmd_sub->create_param.en_internal_ldo =
+	    create_param->en_internal_ldo;
+	tnr_dmd_sub->create_param.ts_output_if = create_param->ts_output_if;
+	tnr_dmd_sub->create_param.xtal_share_type =
+	    CXD2880_TNRDMD_XTAL_SHARE_SLAVE;
+	tnr_dmd_sub->create_param.xosc_cap = 0;
+	tnr_dmd_sub->create_param.xosc_i = create_param->xosc_i_sub;
+	tnr_dmd_sub->create_param.is_cxd2881gg = create_param->is_cxd2881gg;
+	tnr_dmd_sub->create_param.stationary_use = create_param->stationary_use;
+
+	tnr_dmd_main->srl_ts_clk_mod_cnts = 1;
+	tnr_dmd_main->en_fef_intmtnt_base = 1;
+	tnr_dmd_main->en_fef_intmtnt_lite = 1;
+	tnr_dmd_main->rf_lvl_cmpstn = NULL;
+	tnr_dmd_main->lna_thrs_tbl_air = NULL;
+	tnr_dmd_main->lna_thrs_tbl_cable = NULL;
+
+	tnr_dmd_sub->srl_ts_clk_mod_cnts = 1;
+	tnr_dmd_sub->en_fef_intmtnt_base = 1;
+	tnr_dmd_sub->en_fef_intmtnt_lite = 1;
+	tnr_dmd_sub->rf_lvl_cmpstn = NULL;
+	tnr_dmd_sub->lna_thrs_tbl_air = NULL;
+	tnr_dmd_sub->lna_thrs_tbl_cable = NULL;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB))
+		return -EINVAL;
+
+	tnr_dmd->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
+	tnr_dmd->state = CXD2880_TNRDMD_STATE_UNKNOWN;
+	tnr_dmd->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN;
+	tnr_dmd->frequency_khz = 0;
+	tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN;
+	tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+	tnr_dmd->scan_mode = 0;
+	atomic_set(&tnr_dmd->cancel, 0);
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		tnr_dmd->diver_sub->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
+		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_UNKNOWN;
+		tnr_dmd->diver_sub->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN;
+		tnr_dmd->diver_sub->frequency_khz = 0;
+		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN;
+		tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+		tnr_dmd->diver_sub->scan_mode = 0;
+		atomic_set(&tnr_dmd->diver_sub->cancel, 0);
+	}
+
+	ret = cxd2880_tnrdmd_chip_id(tnr_dmd, &tnr_dmd->chip_id);
+	if (ret)
+		return ret;
+
+	if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->chip_id))
+		return -EOPNOTSUPP;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret =
+		    cxd2880_tnrdmd_chip_id(tnr_dmd->diver_sub,
+					   &tnr_dmd->diver_sub->chip_id);
+		if (ret)
+			return ret;
+
+		if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->diver_sub->chip_id))
+			return -EOPNOTSUPP;
+	}
+
+	ret = p_init1(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = p_init1(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	usleep_range(1000, 2000);
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = p_init2(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	ret = p_init2(tnr_dmd);
+	if (ret)
+		return ret;
+
+	usleep_range(5000, 6000);
+
+	ret = p_init3(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = p_init3(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	ret = rf_init1(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = rf_init1(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	{
+		u8 cpu_task_completed = 0;
+
+		ret =
+		    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
+						     &cpu_task_completed);
+		if (ret)
+			return ret;
+
+		if (!cpu_task_completed)
+			return -EBUSY;
+	}
+
+	ret = rf_init2(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = rf_init2(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	ret = load_cfg_mem(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = load_cfg_mem(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
+					     *tnr_dmd,
+					     u8 *task_completed)
+{
+	u16 cpu_status = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!task_completed))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd, &cpu_status);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (cpu_status == 0)
+			*task_completed = 1;
+		else
+			*task_completed = 0;
+
+		return ret;
+	}
+	if (cpu_status != 0) {
+		*task_completed = 0;
+		return ret;
+	}
+
+	ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status);
+	if (ret)
+		return ret;
+
+	if (cpu_status == 0)
+		*task_completed = 1;
+	else
+		*task_completed = 0;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd *tnr_dmd,
+					enum cxd2880_dtv_sys sys,
+					u32 frequency_khz,
+					enum cxd2880_dtv_bandwidth
+					bandwidth, u8 one_seg_opt,
+					u8 one_seg_opt_shft_dir)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	if (frequency_khz < 4000)
+		return -ERANGE;
+
+	ret = cxd2880_tnrdmd_sleep(tnr_dmd);
+	if (ret)
+		return ret;
+
+	{
+		u8 data = 0;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x00,
+					     0x00);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x2b,
+					     &data,
+					     1);
+		if (ret)
+			return ret;
+
+		switch (sys) {
+		case CXD2880_DTV_SYS_DVBT:
+			if (data == 0x00) {
+				ret = t_power_x(tnr_dmd, 1);
+				if (ret)
+					return ret;
+
+				if (tnr_dmd->diver_mode ==
+				    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+					ret = t_power_x(tnr_dmd->diver_sub, 1);
+					if (ret)
+						return ret;
+				}
+			}
+			break;
+
+		case CXD2880_DTV_SYS_DVBT2:
+			if (data == 0x01) {
+				ret = t_power_x(tnr_dmd, 0);
+				if (ret)
+					return ret;
+
+				if (tnr_dmd->diver_mode ==
+				    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+					ret = t_power_x(tnr_dmd->diver_sub, 0);
+					if (ret)
+						return ret;
+				}
+			}
+			break;
+
+		default:
+			return -EINVAL;
+		}
+	}
+
+	{
+		enum cxd2880_tnrdmd_clockmode new_clk_mode =
+		    CXD2880_TNRDMD_CLOCKMODE_A;
+
+		ret = spll_reset(tnr_dmd, new_clk_mode);
+		if (ret)
+			return ret;
+
+		tnr_dmd->clk_mode = new_clk_mode;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = spll_reset(tnr_dmd->diver_sub, new_clk_mode);
+			if (ret)
+				return ret;
+
+			tnr_dmd->diver_sub->clk_mode = new_clk_mode;
+		}
+
+		ret = load_cfg_mem(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = load_cfg_mem(tnr_dmd->diver_sub);
+			if (ret)
+				return ret;
+		}
+	}
+
+	{
+		int shift_frequency_khz = 0;
+
+		if (one_seg_opt) {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				shift_frequency_khz = 350;
+			} else {
+				if (one_seg_opt_shft_dir)
+					shift_frequency_khz = 350;
+				else
+					shift_frequency_khz = -350;
+
+				if (tnr_dmd->create_param.xtal_share_type ==
+				    CXD2880_TNRDMD_XTAL_SHARE_SLAVE)
+					shift_frequency_khz *= -1;
+			}
+		} else {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				shift_frequency_khz = 150;
+			} else {
+				switch (tnr_dmd->create_param.xtal_share_type) {
+				case CXD2880_TNRDMD_XTAL_SHARE_NONE:
+				case CXD2880_TNRDMD_XTAL_SHARE_EXTREF:
+				default:
+					shift_frequency_khz = 0;
+					break;
+				case CXD2880_TNRDMD_XTAL_SHARE_MASTER:
+					shift_frequency_khz = 150;
+					break;
+				case CXD2880_TNRDMD_XTAL_SHARE_SLAVE:
+					shift_frequency_khz = -150;
+					break;
+				}
+			}
+		}
+
+		ret =
+		    x_tune1(tnr_dmd, sys, frequency_khz, bandwidth,
+			    tnr_dmd->is_cable_input, shift_frequency_khz);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret =
+			    x_tune1(tnr_dmd->diver_sub, sys, frequency_khz,
+				    bandwidth, tnr_dmd->is_cable_input,
+				    -shift_frequency_khz);
+			if (ret)
+				return ret;
+		}
+
+		usleep_range(10000, 11000);
+
+		{
+			u8 cpu_task_completed = 0;
+
+			ret =
+			    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
+						     &cpu_task_completed);
+			if (ret)
+				return ret;
+
+			if (!cpu_task_completed)
+				return -EBUSY;
+		}
+
+		ret =
+		    x_tune2(tnr_dmd, bandwidth, tnr_dmd->clk_mode,
+			    shift_frequency_khz);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret =
+			    x_tune2(tnr_dmd->diver_sub, bandwidth,
+				    tnr_dmd->diver_sub->clk_mode,
+				    -shift_frequency_khz);
+			if (ret)
+				return ret;
+		}
+	}
+
+	if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) {
+		ret = set_ts_clk_mode_and_freq(tnr_dmd, sys);
+		if (ret)
+			return ret;
+	} else {
+		struct cxd2880_tnrdmd_pid_ftr_cfg *pid_ftr_cfg;
+
+		if (tnr_dmd->pid_ftr_cfg_en)
+			pid_ftr_cfg = &tnr_dmd->pid_ftr_cfg;
+		else
+			pid_ftr_cfg = NULL;
+
+		ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
+					*tnr_dmd,
+					enum cxd2880_dtv_sys sys,
+					u8 en_fef_intmtnt_ctrl)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = x_tune3(tnr_dmd, sys, en_fef_intmtnt_ctrl);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = x_tune3(tnr_dmd->diver_sub, sys, en_fef_intmtnt_ctrl);
+		if (ret)
+			return ret;
+	}
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = x_tune4(tnr_dmd);
+		if (ret)
+			return ret;
+	}
+
+	ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 1);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state == CXD2880_TNRDMD_STATE_SLEEP) {
+	} else if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) {
+		ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 0);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = x_sleep1(tnr_dmd);
+			if (ret)
+				return ret;
+		}
+
+		ret = x_sleep2(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = x_sleep2(tnr_dmd->diver_sub);
+			if (ret)
+				return ret;
+		}
+
+		switch (tnr_dmd->sys) {
+		case CXD2880_DTV_SYS_DVBT:
+			ret = cxd2880_tnrdmd_dvbt_sleep_setting(tnr_dmd);
+			if (ret)
+				return ret;
+			break;
+
+		case CXD2880_DTV_SYS_DVBT2:
+			ret = cxd2880_tnrdmd_dvbt2_sleep_setting(tnr_dmd);
+			if (ret)
+				return ret;
+			break;
+
+		default:
+			return -EPERM;
+		}
+
+		ret = x_sleep3(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = x_sleep3(tnr_dmd->diver_sub);
+			if (ret)
+				return ret;
+		}
+
+		ret = x_sleep4(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			ret = x_sleep4(tnr_dmd->diver_sub);
+			if (ret)
+				return ret;
+		}
+
+		tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP;
+		tnr_dmd->frequency_khz = 0;
+		tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN;
+		tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP;
+			tnr_dmd->diver_sub->frequency_khz = 0;
+			tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN;
+			tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN;
+		}
+	} else {
+		return -EPERM;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+			   enum cxd2880_tnrdmd_cfg_id id,
+			   int value)
+{
+	int ret = 0;
+	u8 data[2] = { 0 };
+	u8 need_sub_setting = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	switch (id) {
+	case CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc4,
+							 value ? 0x00 : 0x10,
+							 0x10);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc5,
+							 value ? 0x00 : 0x02,
+							 0x02);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc5,
+							 value ? 0x00 : 0x04,
+							 0x04);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xcb,
+							 value ? 0x00 : 0x01,
+							 0x01);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc5,
+							 value ? 0x01 : 0x00,
+							 0x01);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSCLK_CONT:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		tnr_dmd->srl_ts_clk_mod_cnts = value ? 0x01 : 0x00;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSCLK_MASK:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		if ((value < 0) || (value > 0x1f))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc6, value,
+							 0x1f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSVALID_MASK:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		if ((value < 0) || (value > 0x1f))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc8, value,
+							 0x1f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSERR_MASK:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		if ((value < 0) || (value > 0x1f))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xc9, value,
+							 0x1f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSERR_VALID_DIS:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x91,
+							 value ? 0x01 : 0x00,
+							 0x01);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSPIN_CURRENT:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x51, value,
+							 0x3f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x50,
+							 value ? 0x80 : 0x00,
+							 0x80);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSPIN_PULLUP:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x50, value,
+							 0x3f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSCLK_FREQ:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		if ((value < 0) || (value > 1))
+			return -ERANGE;
+
+		tnr_dmd->srl_ts_clk_frq =
+		    (enum cxd2880_tnrdmd_serial_ts_clk)value;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		if ((value < 0) || (value > 0xff))
+			return -ERANGE;
+
+		tnr_dmd->ts_byte_clk_manual_setting = value;
+
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_PACKET_GAP:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		if ((value < 0) || (value > 7))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0xd6, value,
+							 0x07);
+		if (ret)
+			return ret;
+
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE:
+		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+			return -EPERM;
+
+		tnr_dmd->is_ts_backwards_compatible_mode = value ? 1 : 0;
+
+		break;
+
+	case CXD2880_TNRDMD_CFG_PWM_VALUE:
+		if ((value < 0) || (value > 0x1000))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x22,
+							 value ? 0x01 : 0x00,
+							 0x01);
+		if (ret)
+			return ret;
+
+		{
+			u8 data[2];
+
+			data[0] = (value >> 8) & 0x1f;
+			data[1] = value & 0xff;
+
+			ret =
+			    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x23,
+							 data[0], 0x1f);
+			if (ret)
+				return ret;
+
+			ret =
+			    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x24,
+							 data[1], 0xff);
+			if (ret)
+				return ret;
+		}
+
+		break;
+
+	case CXD2880_TNRDMD_CFG_INTERRUPT:
+		data[0] = (value >> 8) & 0xff;
+		data[1] = value & 0xff;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x48, data[0],
+							 0xff);
+		if (ret)
+			return ret;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x49, data[1],
+							 0xff);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL:
+		data[0] = value & 0x07;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x4a, data[0],
+							 0x07);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL:
+		data[0] = (value & 0x07) << 3;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_SYS,
+							 0x00, 0x4a, data[0],
+							 0x38);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE:
+		if ((value < CXD2880_TNRDMD_CLOCKMODE_UNKNOWN) ||
+		    (value > CXD2880_TNRDMD_CLOCKMODE_C))
+			return -ERANGE;
+		tnr_dmd->fixed_clk_mode = (enum cxd2880_tnrdmd_clockmode)value;
+		break;
+
+	case CXD2880_TNRDMD_CFG_CABLE_INPUT:
+		tnr_dmd->is_cable_input = value ? 1 : 0;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE:
+		tnr_dmd->en_fef_intmtnt_base = value ? 1 : 0;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE:
+		tnr_dmd->en_fef_intmtnt_lite = value ? 1 : 0;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS:
+		data[0] = (value >> 8) & 0x07;
+		data[1] = value & 0xff;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x99, data[0],
+							 0x07);
+		if (ret)
+			return ret;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9a, data[1],
+							 0xff);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS:
+		data[0] = (value >> 8) & 0x07;
+		data[1] = value & 0xff;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9b, data[0],
+							 0x07);
+		if (ret)
+			return ret;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9c, data[1],
+							 0xff);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS:
+		data[0] = (value >> 8) & 0x07;
+		data[1] = value & 0xff;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9d, data[0],
+							 0x07);
+		if (ret)
+			return ret;
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x00, 0x9e, data[1],
+							 0xff);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST:
+		tnr_dmd->blind_tune_dvbt2_first = value ? 1 : 0;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD:
+		if ((value < 0) || (value > 31))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x10, 0x60,
+							 value & 0x1f, 0x1f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD:
+		if ((value < 0) || (value > 7))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x10, 0x6f,
+							 value & 0x07, 0x07);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_BBER_MES:
+		if ((value < 0) || (value > 15))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x20, 0x72,
+							 value & 0x0f, 0x0f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_LBER_MES:
+		if ((value < 0) || (value > 15))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x20, 0x6f,
+							 value & 0x0f, 0x0f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT_PER_MES:
+		if ((value < 0) || (value > 15))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x10, 0x5c,
+							 value & 0x0f, 0x0f);
+		if (ret)
+			return ret;
+		break;
+
+	case CXD2880_TNRDMD_CFG_DVBT2_PER_MES:
+		if ((value < 0) || (value > 15))
+			return -ERANGE;
+
+		ret =
+		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+							 CXD2880_IO_TGT_DMD,
+							 0x24, 0xdc,
+							 value & 0x0f, 0x0f);
+		if (ret)
+			return ret;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (need_sub_setting &&
+	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)) {
+		ret = cxd2880_tnrdmd_set_cfg(tnr_dmd->diver_sub, id, value);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+				u8 id,
+				u8 en,
+				enum cxd2880_tnrdmd_gpio_mode mode,
+				u8 open_drain, u8 invert)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (id > 2)
+		return -EINVAL;
+
+	if (mode > CXD2880_TNRDMD_GPIO_MODE_EEW)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x40 + id, mode,
+						 0x0f);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x43,
+						 open_drain ? (1 << id) : 0,
+						 1 << id);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x44,
+						 invert ? (1 << id) : 0,
+						 1 << id);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
+						 0x00, 0x45,
+						 en ? 0 : (1 << id),
+						 1 << id);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				    u8 id,
+				    u8 en,
+				    enum cxd2880_tnrdmd_gpio_mode
+				    mode, u8 open_drain, u8 invert)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_gpio_set_cfg(tnr_dmd->diver_sub, id, en, mode,
+					open_drain, invert);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
+			     u8 id, u8 *value)
+{
+	u8 data = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!value))
+		return -EINVAL;
+
+	if (id > 2)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x20, &data, 1);
+	if (ret)
+		return ret;
+
+	*value = (data >> id) & 0x01;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				 u8 id, u8 *value)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_gpio_read(tnr_dmd->diver_sub, id, value);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
+			      u8 id, u8 value)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (id > 2)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
+						   CXD2880_IO_TGT_SYS,
+						   0x00, 0x46,
+						   value ? (1 << id) : 0,
+						   1 << id);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				  u8 id, u8 value)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_gpio_write(tnr_dmd->diver_sub, id, value);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
+				  u16 *value)
+{
+	int ret = 0;
+	u8 data[2] = { 0 };
+
+	if ((!tnr_dmd) || (!value))
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x15, data, 2);
+	if (ret)
+		return ret;
+
+	*value = (data[0] << 8) | data[1];
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
+				   u16 value)
+{
+	int ret = 0;
+	u8 data[2] = { 0 };
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	data[0] = (value >> 8) & 0xff;
+	data[1] = value & 0xff;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_SYS,
+				      0x3c, data, 2);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
+				u8 clear_overflow_flag,
+				u8 clear_underflow_flag,
+				u8 clear_buf)
+{
+	int ret = 0;
+	u8 data[2] = { 0 };
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	data[0] = clear_overflow_flag ? 0x02 : 0x00;
+	data[0] |= clear_underflow_flag ? 0x01 : 0x00;
+	data[1] = clear_buf ? 0x01 : 0x00;
+	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+				      CXD2880_IO_TGT_DMD,
+				      0x9f, data, 2);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
+			   enum cxd2880_tnrdmd_chip_id *chip_id)
+{
+	int ret = 0;
+	u8 data = 0;
+
+	if ((!tnr_dmd) || (!chip_id))
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0xfd, &data, 1);
+	if (ret)
+		return ret;
+
+	*chip_id = (enum cxd2880_tnrdmd_chip_id)data;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
+					 *tnr_dmd,
+					 enum cxd2880_io_tgt tgt,
+					 u8 bank, u8 address,
+					 u8 value, u8 bit_mask)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io, tgt, 0x00, bank);
+	if (ret)
+		return ret;
+
+	ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
+				      tgt, address, value, bit_mask);
+	if (ret)
+		return ret;
+
+	ret = set_cfg_mem(tnr_dmd, tgt, bank, address, value, bit_mask);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
+				 enum cxd2880_dtv_sys sys,
+				 u8 scan_mode_end)
+{
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	CXD2880_ARG_UNUSED(sys);
+
+	tnr_dmd->scan_mode = scan_mode_end;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		int ret = 0;
+
+		ret =
+		    cxd2880_tnrdmd_set_scan_mode(tnr_dmd->diver_sub, sys,
+						 scan_mode_end);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
+			       struct cxd2880_tnrdmd_pid_ftr_cfg
+			       *pid_ftr_cfg)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS)
+		return -EOPNOTSUPP;
+
+	if (pid_ftr_cfg) {
+		tnr_dmd->pid_ftr_cfg = *pid_ftr_cfg;
+		tnr_dmd->pid_ftr_cfg_en = 1;
+	} else {
+		tnr_dmd->pid_ftr_cfg_en = 0;
+	}
+
+	if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) {
+		ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     int (*rf_lvl_cmpstn)
+				     (struct cxd2880_tnrdmd *,
+				     int *))
+{
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	tnr_dmd->rf_lvl_cmpstn = rf_lvl_cmpstn;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd
+					 *tnr_dmd,
+					 int (*rf_lvl_cmpstn)
+					 (struct cxd2880_tnrdmd *,
+					 int *))
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_set_rf_lvl_cmpstn(tnr_dmd->diver_sub,
+					       rf_lvl_cmpstn);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
+				struct cxd2880_tnrdmd_lna_thrs_tbl_air
+				*tbl_air,
+				struct cxd2880_tnrdmd_lna_thrs_tbl_cable
+				*tbl_cable)
+{
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	tnr_dmd->lna_thrs_tbl_air = tbl_air;
+	tnr_dmd->lna_thrs_tbl_cable = tbl_cable;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				    struct
+				    cxd2880_tnrdmd_lna_thrs_tbl_air
+				    *tbl_air,
+				    struct cxd2880_tnrdmd_lna_thrs_tbl_cable
+				    *tbl_cable)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_set_lna_thrs(tnr_dmd->diver_sub,
+					  tbl_air, tbl_cable);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 en, u8 value)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
+		return -EPERM;
+
+	if (tnr_dmd->create_param.ts_output_if != CXD2880_TNRDMD_TSOUT_IF_TS)
+		return -EOPNOTSUPP;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	if (en) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x50, ((value & 0x1f) | 0x80));
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x52, (value & 0x1f));
+		if (ret)
+			return ret;
+	} else {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x50, 0x3f);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x52, 0x1f);
+		if (ret)
+			return ret;
+
+		ret = load_cfg_mem(tnr_dmd);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
+				 u8 en)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	switch (tnr_dmd->create_param.ts_output_if) {
+	case CXD2880_TNRDMD_TSOUT_IF_TS:
+		if (en) {
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_SYS,
+						     0x00, 0x00);
+			if (ret)
+				return ret;
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_SYS,
+						     0x52, 0x00);
+			if (ret)
+				return ret;
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x00, 0x00);
+			if (ret)
+				return ret;
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0xc3, 0x00);
+			if (ret)
+				return ret;
+		} else {
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x00, 0x00);
+			if (ret)
+				return ret;
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0xc3, 0x01);
+			if (ret)
+				return ret;
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_SYS,
+						     0x00, 0x00);
+			if (ret)
+				return ret;
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_SYS,
+						     0x52, 0x1f);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_TNRDMD_TSOUT_IF_SPI:
+		break;
+
+	case CXD2880_TNRDMD_TSOUT_IF_SDIO:
+		break;
+
+	default:
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	switch (tnr_dmd->create_param.ts_output_if) {
+	case CXD2880_TNRDMD_TSOUT_IF_SPI:
+	case CXD2880_TNRDMD_TSOUT_IF_SDIO:
+		{
+			u8 data = 0;
+
+			ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x00, &data, 1);
+			if (ret)
+				return ret;
+		}
+		break;
+	case CXD2880_TNRDMD_TSOUT_IF_TS:
+	default:
+		break;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x01, 0x01);
+	if (ret)
+		return ret;
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
new file mode 100644
index 000000000000..c168c9f27dad
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
@@ -0,0 +1,391 @@
+/*
+ * cxd2880_tnrdmd.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common control interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_H
+#define CXD2880_TNRDMD_H
+
+#include <linux/atomic.h>
+
+#include "cxd2880_common.h"
+#include "cxd2880_io.h"
+#include "cxd2880_dtv.h"
+#include "cxd2880_dvbt.h"
+#include "cxd2880_dvbt2.h"
+
+#define CXD2880_TNRDMD_MAX_CFG_MEM_COUNT 100
+
+#define slvt_unfreeze_reg(tnr_dmd) ((void)((tnr_dmd)->io->write_reg\
+((tnr_dmd)->io, CXD2880_IO_TGT_DMD, 0x01, 0x00)))
+
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_UNDERFLOW     0x0001
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_OVERFLOW      0x0002
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_EMPTY  0x0004
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_FULL   0x0008
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_RRDY	  0x0010
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_COMMAND      0x0020
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_ACCESS       0x0040
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_CPU_ERROR	    0x0100
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_LOCK		 0x0200
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_INV_LOCK	     0x0400
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_NOOFDM	       0x0800
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_EWS		  0x1000
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_EEW		  0x2000
+#define CXD2880_TNRDMD_INTERRUPT_TYPE_FEC_FAIL	     0x4000
+
+#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_L1POST_OK	0x01
+#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_DMD_LOCK	 0x02
+#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_TS_LOCK	  0x04
+
+enum cxd2880_tnrdmd_chip_id {
+	CXD2880_TNRDMD_CHIP_ID_UNKNOWN = 0x00,
+	CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X = 0x62,
+	CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11 = 0x6a
+};
+
+#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) (((chip_id) == \
+CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \
+((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11))
+
+enum cxd2880_tnrdmd_state {
+	CXD2880_TNRDMD_STATE_UNKNOWN,
+	CXD2880_TNRDMD_STATE_SLEEP,
+	CXD2880_TNRDMD_STATE_ACTIVE,
+	CXD2880_TNRDMD_STATE_INVALID
+};
+
+enum cxd2880_tnrdmd_divermode {
+	CXD2880_TNRDMD_DIVERMODE_SINGLE,
+	CXD2880_TNRDMD_DIVERMODE_MAIN,
+	CXD2880_TNRDMD_DIVERMODE_SUB
+};
+
+enum cxd2880_tnrdmd_clockmode {
+	CXD2880_TNRDMD_CLOCKMODE_UNKNOWN,
+	CXD2880_TNRDMD_CLOCKMODE_A,
+	CXD2880_TNRDMD_CLOCKMODE_B,
+	CXD2880_TNRDMD_CLOCKMODE_C
+};
+
+enum cxd2880_tnrdmd_tsout_if {
+	CXD2880_TNRDMD_TSOUT_IF_TS,
+	CXD2880_TNRDMD_TSOUT_IF_SPI,
+	CXD2880_TNRDMD_TSOUT_IF_SDIO
+};
+
+enum cxd2880_tnrdmd_xtal_share {
+	CXD2880_TNRDMD_XTAL_SHARE_NONE,
+	CXD2880_TNRDMD_XTAL_SHARE_EXTREF,
+	CXD2880_TNRDMD_XTAL_SHARE_MASTER,
+	CXD2880_TNRDMD_XTAL_SHARE_SLAVE
+};
+
+enum cxd2880_tnrdmd_spectrum_sense {
+	CXD2880_TNRDMD_SPECTRUM_NORMAL,
+	CXD2880_TNRDMD_SPECTRUM_INV
+};
+
+enum cxd2880_tnrdmd_cfg_id {
+	CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB,
+	CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI,
+	CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI,
+	CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI,
+	CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE,
+	CXD2880_TNRDMD_CFG_TSCLK_CONT,
+	CXD2880_TNRDMD_CFG_TSCLK_MASK,
+	CXD2880_TNRDMD_CFG_TSVALID_MASK,
+	CXD2880_TNRDMD_CFG_TSERR_MASK,
+	CXD2880_TNRDMD_CFG_TSERR_VALID_DIS,
+	CXD2880_TNRDMD_CFG_TSPIN_CURRENT,
+	CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL,
+	CXD2880_TNRDMD_CFG_TSPIN_PULLUP,
+	CXD2880_TNRDMD_CFG_TSCLK_FREQ,
+	CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL,
+	CXD2880_TNRDMD_CFG_TS_PACKET_GAP,
+	CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE,
+	CXD2880_TNRDMD_CFG_PWM_VALUE,
+	CXD2880_TNRDMD_CFG_INTERRUPT,
+	CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL,
+	CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL,
+	CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS,
+	CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS,
+	CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS,
+	CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE,
+	CXD2880_TNRDMD_CFG_CABLE_INPUT,
+	CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE,
+	CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE,
+	CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST,
+	CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
+	CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
+	CXD2880_TNRDMD_CFG_DVBT_PER_MES,
+	CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
+	CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
+	CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
+};
+
+enum cxd2880_tnrdmd_lock_result {
+	CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT,
+	CXD2880_TNRDMD_LOCK_RESULT_LOCKED,
+	CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED
+};
+
+enum cxd2880_tnrdmd_gpio_mode {
+	CXD2880_TNRDMD_GPIO_MODE_OUTPUT = 0x00,
+	CXD2880_TNRDMD_GPIO_MODE_INPUT = 0x01,
+	CXD2880_TNRDMD_GPIO_MODE_INT = 0x02,
+	CXD2880_TNRDMD_GPIO_MODE_FEC_FAIL = 0x03,
+	CXD2880_TNRDMD_GPIO_MODE_PWM = 0x04,
+	CXD2880_TNRDMD_GPIO_MODE_EWS = 0x05,
+	CXD2880_TNRDMD_GPIO_MODE_EEW = 0x06
+};
+
+enum cxd2880_tnrdmd_serial_ts_clk {
+	CXD2880_TNRDMD_SERIAL_TS_CLK_FULL,
+	CXD2880_TNRDMD_SERIAL_TS_CLK_HALF
+};
+
+struct cxd2880_tnrdmd_cfg_mem {
+	enum cxd2880_io_tgt tgt;
+	u8 bank;
+	u8 address;
+	u8 value;
+	u8 bit_mask;
+};
+
+struct cxd2880_tnrdmd_pid_cfg {
+	u8 is_en;
+	u16 pid;
+};
+
+struct cxd2880_tnrdmd_pid_ftr_cfg {
+	u8 is_negative;
+	struct cxd2880_tnrdmd_pid_cfg pid_cfg[32];
+};
+
+struct cxd2880_tnrdmd_ts_buf_info {
+	u8 read_ready;
+	u8 almost_full;
+	u8 almost_empty;
+	u8 overflow;
+	u8 underflow;
+	u16 packet_num;
+};
+
+struct cxd2880_tnrdmd_lna_thrs {
+	u8 off_on;
+	u8 on_off;
+};
+
+struct cxd2880_tnrdmd_lna_thrs_tbl_air {
+	struct cxd2880_tnrdmd_lna_thrs thrs[24];
+};
+
+struct cxd2880_tnrdmd_lna_thrs_tbl_cable {
+	struct cxd2880_tnrdmd_lna_thrs thrs[32];
+};
+
+struct cxd2880_tnrdmd_create_param {
+	enum cxd2880_tnrdmd_tsout_if ts_output_if;
+	u8 en_internal_ldo;
+	enum cxd2880_tnrdmd_xtal_share xtal_share_type;
+	u8 xosc_cap;
+	u8 xosc_i;
+	u8 is_cxd2881gg;
+	u8 stationary_use;
+};
+
+struct cxd2880_tnrdmd_diver_create_param {
+	enum cxd2880_tnrdmd_tsout_if ts_output_if;
+	u8 en_internal_ldo;
+	u8 xosc_cap_main;
+	u8 xosc_i_main;
+	u8 xosc_i_sub;
+	u8 is_cxd2881gg;
+	u8 stationary_use;
+};
+
+struct cxd2880_tnrdmd {
+	struct cxd2880_tnrdmd *diver_sub;
+	struct cxd2880_io *io;
+	struct cxd2880_tnrdmd_create_param create_param;
+	enum cxd2880_tnrdmd_divermode diver_mode;
+	enum cxd2880_tnrdmd_clockmode fixed_clk_mode;
+	u8 is_cable_input;
+	u8 en_fef_intmtnt_base;
+	u8 en_fef_intmtnt_lite;
+	u8 blind_tune_dvbt2_first;
+	int (*rf_lvl_cmpstn)(struct cxd2880_tnrdmd *tnr_dmd,
+			     int *rf_lvl_db);
+	struct cxd2880_tnrdmd_lna_thrs_tbl_air *lna_thrs_tbl_air;
+	struct cxd2880_tnrdmd_lna_thrs_tbl_cable *lna_thrs_tbl_cable;
+	u8 srl_ts_clk_mod_cnts;
+	enum cxd2880_tnrdmd_serial_ts_clk srl_ts_clk_frq;
+	u8 ts_byte_clk_manual_setting;
+	u8 is_ts_backwards_compatible_mode;
+	struct cxd2880_tnrdmd_cfg_mem cfg_mem[CXD2880_TNRDMD_MAX_CFG_MEM_COUNT];
+	u8 cfg_mem_last_entry;
+	struct cxd2880_tnrdmd_pid_ftr_cfg pid_ftr_cfg;
+	u8 pid_ftr_cfg_en;
+	void *user;
+	enum cxd2880_tnrdmd_chip_id chip_id;
+	enum cxd2880_tnrdmd_state state;
+	enum cxd2880_tnrdmd_clockmode clk_mode;
+	u32 frequency_khz;
+	enum cxd2880_dtv_sys sys;
+	enum cxd2880_dtv_bandwidth bandwidth;
+	u8 scan_mode;
+	atomic_t cancel;
+};
+
+int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
+			  struct cxd2880_io *io,
+			  struct cxd2880_tnrdmd_create_param
+			  *create_param);
+
+int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
+				*tnr_dmd_main,
+				struct cxd2880_io *io_main,
+				struct cxd2880_tnrdmd *tnr_dmd_sub,
+				struct cxd2880_io *io_sub,
+				struct
+				cxd2880_tnrdmd_diver_create_param
+				*create_param);
+
+int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
+					     *tnr_dmd,
+					     u8 *task_completed);
+
+int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd
+					*tnr_dmd,
+					enum cxd2880_dtv_sys sys,
+					u32 frequency_khz,
+					enum cxd2880_dtv_bandwidth
+					bandwidth, u8 one_seg_opt,
+					u8 one_seg_opt_shft_dir);
+
+int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
+					*tnr_dmd,
+					enum cxd2880_dtv_sys sys,
+					u8 en_fef_intmtnt_ctrl);
+
+int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+			   enum cxd2880_tnrdmd_cfg_id id,
+			   int value);
+
+int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
+				u8 id,
+				u8 en,
+				enum cxd2880_tnrdmd_gpio_mode mode,
+				u8 open_drain, u8 invert);
+
+int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				    u8 id,
+				    u8 en,
+				    enum cxd2880_tnrdmd_gpio_mode
+				    mode, u8 open_drain,
+				    u8 invert);
+
+int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
+			     u8 id, u8 *value);
+
+int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				 u8 id, u8 *value);
+
+int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
+			      u8 id, u8 value);
+
+int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				  u8 id, u8 value);
+
+int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
+				  u16 *value);
+
+int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
+				   u16 value);
+
+int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
+				u8 clear_overflow_flag,
+				u8 clear_underflow_flag,
+				u8 clear_buf);
+
+int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
+			   enum cxd2880_tnrdmd_chip_id *chip_id);
+
+int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
+					 *tnr_dmd,
+					 enum cxd2880_io_tgt tgt,
+					 u8 bank, u8 address,
+					 u8 value, u8 bit_mask);
+
+int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
+				 enum cxd2880_dtv_sys sys,
+				 u8 scan_mode_end);
+
+int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
+			       struct cxd2880_tnrdmd_pid_ftr_cfg
+			       *pid_ftr_cfg);
+
+int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     int (*rf_lvl_cmpstn)
+				     (struct cxd2880_tnrdmd *,
+				     int *));
+
+int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd *tnr_dmd,
+					 int (*rf_lvl_cmpstn)
+					 (struct cxd2880_tnrdmd *,
+					 int *));
+
+int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
+				struct
+				cxd2880_tnrdmd_lna_thrs_tbl_air
+				*tbl_air,
+				struct
+				cxd2880_tnrdmd_lna_thrs_tbl_cable
+				*tbl_cable);
+
+int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				    struct
+				    cxd2880_tnrdmd_lna_thrs_tbl_air
+				    *tbl_air,
+				    struct
+				    cxd2880_tnrdmd_lna_thrs_tbl_cable
+				    *tbl_cable);
+
+int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 en, u8 value);
+
+int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
+				 u8 en);
+
+int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
new file mode 100644
index 000000000000..bb0f6b295ed3
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
@@ -0,0 +1,29 @@
+/*
+ * cxd2880_tnrdmd_driver_version.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * version information
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.2"
+
+#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2017-08-07"
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
new file mode 100644
index 000000000000..1ed415af3727
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
@@ -0,0 +1,221 @@
+/*
+ * cxd2880_tnrdmd_mon.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common monitor functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd_mon.h"
+
+int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
+			      int *rf_lvl_db)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!rf_lvl_db))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x01);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	{
+		u8 data[2] = { 0x80, 0x00 };
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_SYS,
+					      0x5b, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	usleep_range(2000, 3000);
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x1a);
+	if (ret)
+		return ret;
+
+	{
+		u8 data[2];
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x15, data, 2);
+		if (ret)
+			return ret;
+
+		if ((data[0] != 0) || (data[1] != 0))
+			return -EPERM;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_SYS,
+					     0x11, data, 2);
+		if (ret)
+			return ret;
+
+		*rf_lvl_db =
+		    cxd2880_convert2s_complement((data[0] << 3) |
+						 ((data[1] & 0xe0) >> 5), 11);
+	}
+
+	*rf_lvl_db *= 125;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, 0x00);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->rf_lvl_cmpstn) {
+		ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				  int *rf_lvl_db)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!rf_lvl_db))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
+					   *tnr_dmd, u16 *status)
+{
+	u8 data[2] = { 0 };
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!status))
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x1a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x15, data, 2);
+	if (ret)
+		return ret;
+
+	*status = (data[0] << 8) | data[1];
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
+					       cxd2880_tnrdmd
+					       *tnr_dmd,
+					       u16 *status)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!status))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub, status);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd,
+				   struct
+				   cxd2880_tnrdmd_ts_buf_info
+				   *info)
+{
+	u8 data[3] = { 0 };
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!info))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0a);
+	if (ret)
+		return ret;
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x50, data, 3);
+	if (ret)
+		return ret;
+
+	info->read_ready = (data[0] & 0x10) ? 0x01 : 0x00;
+	info->almost_full = (data[0] & 0x08) ? 0x01 : 0x00;
+	info->almost_empty = (data[0] & 0x04) ? 0x01 : 0x00;
+	info->overflow = (data[0] & 0x02) ? 0x01 : 0x00;
+	info->underflow = (data[0] & 0x01) ? 0x01 : 0x00;
+
+	info->packet_num = ((data[1] & 0x07) << 8) | data[2];
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
new file mode 100644
index 000000000000..a4c34f56a7a1
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
@@ -0,0 +1,52 @@
+/*
+ * cxd2880_tnrdmd_mon.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * common monitor interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_MON_H
+#define CXD2880_TNRDMD_MON_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+
+int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
+			      int *rf_lvl_db);
+
+int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				  int *rf_lvl_db);
+
+int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
+					   *tnr_dmd, u16 *status);
+
+int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
+					       cxd2880_tnrdmd
+					       *tnr_dmd,
+					       u16 *status);
+
+int cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd,
+				   struct
+				   cxd2880_tnrdmd_ts_buf_info
+				   *info);
+
+#endif
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 06/14] [media] cxd2880: Add integration layer for the driver
  2017-08-16  4:17 ` Yasunari.Takiguchi-7U/KSKJipcs
@ 2017-08-16  4:38   ` Yasunari.Takiguchi
  -1 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:38 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

These functions monitor the driver and watch for task completion.
This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
      -changed cxd2880_atomic_read to atomic_read
      -changed cxd2880_atomic_set to atomic_set
      -modified return code
      -modified coding style of if() 
   drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
      -modified return code

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 .../media/dvb-frontends/cxd2880/cxd2880_integ.c    | 98 ++++++++++++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_integ.h    | 44 ++++++++++
 2 files changed, 142 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
new file mode 100644
index 000000000000..d4516df49210
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
@@ -0,0 +1,98 @@
+/*
+ * cxd2880_integ.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer common functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_integ.h"
+
+int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+	struct cxd2880_stopwatch timer;
+	unsigned int elapsed_time = 0;
+	u8 cpu_task_completed = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_init1(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret)
+		return ret;
+
+	while (1) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed_time);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
+						     &cpu_task_completed);
+		if (ret)
+			return ret;
+
+		if (cpu_task_completed)
+			break;
+
+		if (elapsed_time > CXD2880_TNRDMD_WAIT_INIT_TIMEOUT)
+			return -ETIME;
+		ret =
+		    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_TNRDMD_WAIT_INIT_INTVL);
+		if (ret)
+			return ret;
+	}
+
+	ret = cxd2880_tnrdmd_init2(tnr_dmd);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	atomic_set(&tnr_dmd->cancel, 1);
+
+	return 0;
+}
+
+int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (atomic_read(&tnr_dmd->cancel) != 0)
+		return -ECANCELED;
+
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
new file mode 100644
index 000000000000..2b4fe5c3743b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
@@ -0,0 +1,44 @@
+/*
+ * cxd2880_integ.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer common interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_INTEG_H
+#define CXD2880_INTEG_H
+
+#include "cxd2880_tnrdmd.h"
+
+#define CXD2880_TNRDMD_WAIT_INIT_TIMEOUT	500
+#define CXD2880_TNRDMD_WAIT_INIT_INTVL	10
+
+#define CXD2880_TNRDMD_WAIT_AGC_STABLE		100
+
+int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd
+				     *tnr_dmd);
+
+#endif
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 06/14] [media] cxd2880: Add integration layer for the driver
@ 2017-08-16  4:38   ` Yasunari.Takiguchi
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:38 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

These functions monitor the driver and watch for task completion.
This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
      -changed cxd2880_atomic_read to atomic_read
      -changed cxd2880_atomic_set to atomic_set
      -modified return code
      -modified coding style of if() 
   drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
      -modified return code

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 .../media/dvb-frontends/cxd2880/cxd2880_integ.c    | 98 ++++++++++++++++++++++
 .../media/dvb-frontends/cxd2880/cxd2880_integ.h    | 44 ++++++++++
 2 files changed, 142 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
new file mode 100644
index 000000000000..d4516df49210
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c
@@ -0,0 +1,98 @@
+/*
+ * cxd2880_integ.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer common functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_integ.h"
+
+int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+	struct cxd2880_stopwatch timer;
+	unsigned int elapsed_time = 0;
+	u8 cpu_task_completed = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_init1(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret)
+		return ret;
+
+	while (1) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed_time);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
+						     &cpu_task_completed);
+		if (ret)
+			return ret;
+
+		if (cpu_task_completed)
+			break;
+
+		if (elapsed_time > CXD2880_TNRDMD_WAIT_INIT_TIMEOUT)
+			return -ETIME;
+		ret =
+		    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_TNRDMD_WAIT_INIT_INTVL);
+		if (ret)
+			return ret;
+	}
+
+	ret = cxd2880_tnrdmd_init2(tnr_dmd);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	atomic_set(&tnr_dmd->cancel, 1);
+
+	return 0;
+}
+
+int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (atomic_read(&tnr_dmd->cancel) != 0)
+		return -ECANCELED;
+
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
new file mode 100644
index 000000000000..2b4fe5c3743b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.h
@@ -0,0 +1,44 @@
+/*
+ * cxd2880_integ.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer common interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_INTEG_H
+#define CXD2880_INTEG_H
+
+#include "cxd2880_tnrdmd.h"
+
+#define CXD2880_TNRDMD_WAIT_INIT_TIMEOUT	500
+#define CXD2880_TNRDMD_WAIT_INIT_INTVL	10
+
+#define CXD2880_TNRDMD_WAIT_AGC_STABLE		100
+
+int cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd
+				     *tnr_dmd);
+
+#endif
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 07/14] [media] cxd2880: Add top level of the driver
  2017-08-16  4:17 ` Yasunari.Takiguchi-7U/KSKJipcs
@ 2017-08-16  4:39   ` Yasunari.Takiguchi
  -1 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:39 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

This provides the main dvb frontend operation functions
for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
      -adjusted indent spaces
      -modified debugging code
      -removed unnecessary cast
      -modified return code
      -modified coding style of if() 
      -modified about measurement period of PER/BER.
      -changed hexadecimal code to lower case. 

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c | 1879 +++++++++++++++++++++
 1 file changed, 1879 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
new file mode 100644
index 000000000000..306966dd186b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
@@ -0,0 +1,1879 @@
+/*
+ * cxd2880_top.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
+
+#include <linux/spi/spi.h>
+
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+
+#include "cxd2880.h"
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+#include "cxd2880_tnrdmd_dvbt_mon.h"
+#include "cxd2880_integ_dvbt2.h"
+#include "cxd2880_integ_dvbt.h"
+#include "cxd2880_devio_spi.h"
+#include "cxd2880_spi_device.h"
+#include "cxd2880_tnrdmd_driver_version.h"
+
+struct cxd2880_priv {
+	struct cxd2880_tnrdmd tnrdmd;
+	struct spi_device *spi;
+	struct cxd2880_io regio;
+	struct cxd2880_spi_device spi_device;
+	struct cxd2880_spi cxd2880_spi;
+	struct cxd2880_dvbt_tune_param dvbt_tune_param;
+	struct cxd2880_dvbt2_tune_param dvbt2_tune_param;
+	struct mutex *spi_mutex; /* For SPI access exclusive control */
+	unsigned long pre_ber_update;
+	unsigned long pre_ber_interval;
+	unsigned long post_ber_update;
+	unsigned long post_ber_interval;
+	unsigned long ucblock_update;
+	unsigned long ucblock_interval;
+};
+
+static int cxd2880_pre_bit_err_t(
+		struct cxd2880_tnrdmd *tnrdmd, u32 *pre_bit_err,
+		u32 *pre_bit_count)
+{
+	u8 rdata[2];
+	int ret = 0;
+
+	if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count))
+		return -EINVAL;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnrdmd);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x10);
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x39, rdata, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	if ((rdata[0] & 0x01) == 0) {
+		slvt_unfreeze_reg(tnrdmd);
+		return -EBUSY;
+	}
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x22, rdata, 2);
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	*pre_bit_err = (rdata[0] << 8) | rdata[1];
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x6f, rdata, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnrdmd);
+
+	*pre_bit_count = ((rdata[0] & 0x07) == 0) ?
+			 256 : (0x1000 << (rdata[0] & 0x07));
+
+	return 0;
+}
+
+static int cxd2880_pre_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
+				  u32 *pre_bit_err,
+				  u32 *pre_bit_count)
+{
+	u32 period_exp = 0;
+	u32 n_ldpc = 0;
+	u8 data[5];
+	int ret = 0;
+
+	if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count))
+		return -EINVAL;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnrdmd);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x0b);
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x3c, data, sizeof(data));
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	if (!(data[0] & 0x01)) {
+		slvt_unfreeze_reg(tnrdmd);
+		return -EBUSY;
+	}
+	*pre_bit_err =
+	((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0xa0, data, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) ==
+	    CXD2880_DVBT2_FEC_LDPC_16K)
+		n_ldpc = 16200;
+	else
+		n_ldpc = 64800;
+	slvt_unfreeze_reg(tnrdmd);
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x20);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x6f, data, 1);
+	if (ret)
+		return ret;
+
+	period_exp = data[0] & 0x0f;
+
+	*pre_bit_count = (1U << period_exp) * n_ldpc;
+
+	return 0;
+}
+
+static int cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd,
+				  u32 *post_bit_err,
+				  u32 *post_bit_count)
+{
+	u8 rdata[3];
+	u32 bit_error = 0;
+	u32 period_exp = 0;
+	int ret = 0;
+
+	if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count))
+		return -EINVAL;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x0d);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x15, rdata, 3);
+	if (ret)
+		return ret;
+
+	if ((rdata[0] & 0x40) == 0)
+		return -EBUSY;
+
+	*post_bit_err = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2];
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x60, rdata, 1);
+	if (ret)
+		return ret;
+
+	period_exp = (rdata[0] & 0x1f);
+
+	if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8))
+		return -EBUSY;
+
+	if (period_exp == 11)
+		*post_bit_count = 3342336;
+	else
+		*post_bit_count = (1U << period_exp) * 204 * 81;
+
+	return 0;
+}
+
+static int cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
+				   u32 *post_bit_err,
+				   u32 *post_bit_count)
+{
+	u32 period_exp = 0;
+	u32 n_bch = 0;
+
+	if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count))
+		return -EINVAL;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[3];
+		enum cxd2880_dvbt2_plp_fec plp_fec_type =
+			CXD2880_DVBT2_FEC_LDPC_16K;
+		enum cxd2880_dvbt2_plp_code_rate plp_code_rate =
+			CXD2880_DVBT2_R1_2;
+
+		static const u16 n_bch_bits_lookup[2][8] = {
+			{7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480},
+			{32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920}
+		};
+		int ret = 0;
+
+		ret = slvt_freeze_reg(tnrdmd);
+		if (ret)
+			return ret;
+
+		ret = tnrdmd->io->write_reg(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnrdmd);
+			return ret;
+		}
+
+		ret = tnrdmd->io->read_regs(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x15, data, 3);
+		if (ret) {
+			slvt_unfreeze_reg(tnrdmd);
+			return ret;
+		}
+
+		if (!(data[0] & 0x40)) {
+			slvt_unfreeze_reg(tnrdmd);
+			return -EBUSY;
+		}
+
+		*post_bit_err =
+			((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2];
+
+		ret = tnrdmd->io->read_regs(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x9d, data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnrdmd);
+			return ret;
+		}
+
+		plp_code_rate =
+		(enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07);
+
+		ret = tnrdmd->io->read_regs(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0xa0, data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnrdmd);
+			return ret;
+		}
+
+		plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03);
+
+		slvt_unfreeze_reg(tnrdmd);
+
+		ret = tnrdmd->io->write_reg(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x00, 0x20);
+		if (ret)
+			return ret;
+
+		ret = tnrdmd->io->read_regs(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x72, data, 1);
+		if (ret)
+			return ret;
+
+		period_exp = data[0] & 0x0f;
+
+		if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) ||
+		    (plp_code_rate > CXD2880_DVBT2_R2_5))
+			return -EBUSY;
+
+		n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate];
+	}
+
+	if (*post_bit_err > ((1U << period_exp) * n_bch))
+		return -EBUSY;
+
+	*post_bit_count = (1U << period_exp) * n_bch;
+
+	return 0;
+}
+
+static int cxd2880_read_block_err_t(struct cxd2880_tnrdmd *tnrdmd,
+				    u32 *block_err,
+				    u32 *block_count)
+{
+	u8 rdata[3];
+	int ret = 0;
+
+	if ((!tnrdmd) || (!block_err) || (!block_count))
+		return -EINVAL;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x0d);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x18, rdata, 3);
+	if (ret)
+		return ret;
+
+	if ((rdata[0] & 0x01) == 0)
+		return -EBUSY;
+
+	*block_err = (rdata[1] << 8) | rdata[2];
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x5c, rdata, 1);
+	if (ret)
+		return ret;
+
+	*block_count = 1U << (rdata[0] & 0x0f);
+
+	if ((*block_count == 0) || (*block_err > *block_count))
+		return -EBUSY;
+
+	return 0;
+}
+
+static int cxd2880_read_block_err_t2(struct cxd2880_tnrdmd *tnrdmd,
+				     u32 *block_err,
+				     u32 *block_count)
+{
+	if ((!tnrdmd) || (!block_err) || (!block_count))
+		return -EINVAL;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 rdata[3];
+		int ret = 0;
+
+		ret = tnrdmd->io->write_reg(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x00, 0x0b);
+		if (ret)
+			return ret;
+
+		ret = tnrdmd->io->read_regs(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x18, rdata, 3);
+		if (ret)
+			return ret;
+
+		if ((rdata[0] & 0x01) == 0)
+			return -EBUSY;
+
+		*block_err = (rdata[1] << 8) | rdata[2];
+
+		ret = tnrdmd->io->write_reg(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x00, 0x24);
+		if (ret)
+			return ret;
+
+		ret = tnrdmd->io->read_regs(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0xdc, rdata, 1);
+		if (ret)
+			return ret;
+
+		*block_count = 1U << (rdata[0] & 0x0f);
+	}
+
+	if ((*block_count == 0) || (*block_err > *block_count))
+		return -EBUSY;
+
+	return 0;
+}
+
+static void cxd2880_release(struct dvb_frontend *fe)
+{
+	struct cxd2880_priv *priv = NULL;
+
+	if (!fe) {
+		pr_err("invalid arg.\n");
+		return;
+	}
+	priv = fe->demodulator_priv;
+	kfree(priv);
+}
+
+static int cxd2880_init(struct dvb_frontend *fe)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct cxd2880_tnrdmd_create_param create_param;
+
+	if (!fe) {
+		pr_err("invalid arg.\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+
+	create_param.ts_output_if = CXD2880_TNRDMD_TSOUT_IF_SPI;
+	create_param.xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_NONE;
+	create_param.en_internal_ldo = 1;
+	create_param.xosc_cap = 18;
+	create_param.xosc_i = 8;
+	create_param.stationary_use = 1;
+
+	mutex_lock(priv->spi_mutex);
+	if (priv->tnrdmd.io != &priv->regio) {
+		ret = cxd2880_tnrdmd_create(&priv->tnrdmd,
+					    &priv->regio, &create_param);
+		if (ret) {
+			mutex_unlock(priv->spi_mutex);
+			pr_info("cxd2880 tnrdmd create failed %d\n", ret);
+			return ret;
+		}
+	}
+	ret = cxd2880_integ_init(&priv->tnrdmd);
+	if (ret) {
+		mutex_unlock(priv->spi_mutex);
+		pr_err("cxd2880 integ init failed %d\n", ret);
+		return ret;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	pr_debug("OK.\n");
+
+	return ret;
+}
+
+static int cxd2880_sleep(struct dvb_frontend *fe)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+
+	if (!fe) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd);
+	mutex_unlock(priv->spi_mutex);
+
+	pr_debug("tnrdmd_sleep ret %d\n", ret);
+
+	return ret;
+}
+
+static int cxd2880_read_signal_strength(struct dvb_frontend *fe,
+					u16 *strength)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+	int level = 0;
+
+	if ((!fe) || (!strength)) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	mutex_lock(priv->spi_mutex);
+	if ((c->delivery_system == SYS_DVBT) ||
+	    (c->delivery_system == SYS_DVBT2)) {
+		ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &level);
+	} else {
+		pr_debug("invalid system\n");
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	level /= 125;
+	/* -105dBm - -30dBm (-105000/125 = -840, -30000/125 = -240 */
+	level = clamp(level, -840, -240);
+	/* scale value to 0x0000-0xffff */
+	*strength = (u16)(((level + 840) * 0xffff) / (-240 + 840));
+
+	if (ret)
+		pr_debug("ret = %d\n", ret);
+
+	return ret;
+}
+
+static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	int ret = 0;
+	int snrvalue = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+
+	if ((!fe) || (!snr)) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	mutex_lock(priv->spi_mutex);
+	if (c->delivery_system == SYS_DVBT) {
+		ret = cxd2880_tnrdmd_dvbt_mon_snr(&priv->tnrdmd,
+						  &snrvalue);
+	} else if (c->delivery_system == SYS_DVBT2) {
+		ret = cxd2880_tnrdmd_dvbt2_mon_snr(&priv->tnrdmd,
+						   &snrvalue);
+	} else {
+		pr_err("invalid system\n");
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	if (snrvalue < 0)
+		snrvalue = 0;
+	*snr = (u16)snrvalue;
+
+	if (ret)
+		pr_debug("ret = %d\n", ret);
+
+	return ret;
+}
+
+static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+
+	if ((!fe) || (!ucblocks)) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	mutex_lock(priv->spi_mutex);
+	if (c->delivery_system == SYS_DVBT) {
+		ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number(
+								&priv->tnrdmd,
+								ucblocks);
+	} else if (c->delivery_system == SYS_DVBT2) {
+		ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number(
+								&priv->tnrdmd,
+								ucblocks);
+	} else {
+		pr_err("invlaid system\n");
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	if (ret)
+		pr_debug("ret = %d\n", ret);
+
+	return ret;
+}
+
+static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+
+	if ((!fe) || (!ber)) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	mutex_lock(priv->spi_mutex);
+	if (c->delivery_system == SYS_DVBT) {
+		ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(&priv->tnrdmd,
+							ber);
+		/* x100 to change unit.(10^7 -> 10^9 */
+		*ber *= 100;
+	} else if (c->delivery_system == SYS_DVBT2) {
+		ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(&priv->tnrdmd,
+							  ber);
+	} else {
+		pr_err("invlaid system\n");
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	if (ret)
+		pr_debug("ret = %d\n", ret);
+
+	return ret;
+}
+
+static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe)
+{
+	int ret = 0;
+	struct dtv_frontend_properties *c;
+	struct cxd2880_priv *priv;
+	int cr_table[5] = {31500, 42000, 47250, 52500, 55125};
+	int denominator_tbl[4] = {125664, 129472, 137088, 152320};
+	struct cxd2880_dvbt_tpsinfo info;
+	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
+	u32 pre_ber_rate = 0;
+	u32 post_ber_rate = 0;
+	u32 ucblock_rate = 0;
+	u32 mes_exp = 0;
+
+	if (!fe) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+	bw = priv->dvbt_tune_param.bandwidth;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd,
+					       &info);
+	if (ret) {
+		pr_err("tps monitor error ret = %d\n", ret);
+		info.hierarchy = CXD2880_DVBT_HIERARCHY_NON;
+		info.constellation = CXD2880_DVBT_CONSTELLATION_QPSK;
+		info.guard = CXD2880_DVBT_GUARD_1_4;
+		info.rate_hp = CXD2880_DVBT_CODERATE_1_2;
+		info.rate_lp = CXD2880_DVBT_CODERATE_1_2;
+	}
+
+	if (info.hierarchy == CXD2880_DVBT_HIERARCHY_NON) {
+		pre_ber_rate = 63000000 * bw * (info.constellation * 2 + 2) /
+			       denominator_tbl[info.guard];
+
+		post_ber_rate =	1000 * cr_table[info.rate_hp] * bw *
+				(info.constellation * 2 + 2) /
+				denominator_tbl[info.guard];
+
+		ucblock_rate = 875 * cr_table[info.rate_hp] * bw *
+			       (info.constellation * 2 + 2) /
+			       denominator_tbl[info.guard];
+	} else {
+		u8 data = 0;
+		struct cxd2880_tnrdmd *tnrdmd = &priv->tnrdmd;
+
+		ret = tnrdmd->io->write_reg(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x00, 0x10);
+		if (!ret) {
+			ret = tnrdmd->io->read_regs(tnrdmd->io,
+						    CXD2880_IO_TGT_DMD,
+						    0x67, &data, 1);
+			if (ret)
+				data = 0x00;
+		} else {
+			data = 0x00;
+		}
+
+		if (data & 0x01) { /* Low priority */
+			pre_ber_rate =
+				63000000 * bw * (info.constellation * 2 + 2) /
+				denominator_tbl[info.guard];
+
+			post_ber_rate = 1000 * cr_table[info.rate_lp] * bw *
+					(info.constellation * 2 + 2) /
+					denominator_tbl[info.guard];
+
+			ucblock_rate = (1000 * 7 / 8) *	cr_table[info.rate_lp] *
+				       bw * (info.constellation * 2 + 2) /
+				       denominator_tbl[info.guard];
+		} else { /* High priority */
+			pre_ber_rate =
+				63000000 * bw * 2 / denominator_tbl[info.guard];
+
+			post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * 2 /
+					denominator_tbl[info.guard];
+
+			ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_hp] *
+					bw * 2 / denominator_tbl[info.guard];
+		}
+	}
+
+	mes_exp = pre_ber_rate < 8192 ? 8 : intlog2(pre_ber_rate) >> 24;
+	priv->pre_ber_interval =
+		((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) /
+		pre_ber_rate;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
+			       mes_exp == 8 ? 0 : mes_exp - 12);
+
+	mes_exp = intlog2(post_ber_rate) >> 24;
+	priv->post_ber_interval =
+		((1U << mes_exp) * 1000 + (post_ber_rate / 2)) /
+		post_ber_rate;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
+			       mes_exp);
+
+	mes_exp = intlog2(ucblock_rate) >> 24;
+	priv->ucblock_interval =
+		((1U << mes_exp) * 1000 + (ucblock_rate / 2)) /
+		ucblock_rate;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT_PER_MES,
+			       mes_exp);
+
+	return 0;
+}
+
+static int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe)
+{
+	int ret = 0;
+	struct dtv_frontend_properties *c;
+	struct cxd2880_priv *priv;
+	struct cxd2880_dvbt2_l1pre l1pre;
+	struct cxd2880_dvbt2_l1post l1post;
+	struct cxd2880_dvbt2_plp plp;
+	struct cxd2880_dvbt2_bbheader bbheader;
+	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
+	u32 pre_ber_rate = 0;
+	u32 post_ber_rate = 0;
+	u32 ucblock_rate = 0;
+	u32 mes_exp = 0;
+	u32 term_a = 0;
+	u32 term_b = 0;
+	u32 gi_tbl[7] = {32, 64, 128, 256, 8, 152, 76};
+	u8  n_tbl[6] = {8, 2, 4, 16, 1, 1};
+	u8  mode_tbl[6] = {2, 8, 4, 1, 16, 32};
+	u32 kbch_tbl[2][8] = {
+			{6952, 9472, 10552, 11632, 12352, 13072, 5152, 6232},
+			{32128, 38608, 42960, 48328, 51568, 53760, 0, 0} };
+	u32 denominator = 0;
+
+	if (!fe) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+	bw = priv->dvbt2_tune_param.bandwidth;
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
+	if (ret) {
+		pr_info("l1 pre error\n");
+		goto error_ber_setting;
+	}
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_active_plp(&priv->tnrdmd,
+						  CXD2880_DVBT2_PLP_DATA, &plp);
+	if (ret) {
+		pr_info("plp info error\n");
+		goto error_ber_setting;
+	}
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_l1_post(&priv->tnrdmd, &l1post);
+	if (ret) {
+		pr_info("l1 post error\n");
+		goto error_ber_setting;
+	}
+
+	term_a =
+		(mode_tbl[l1pre.fft_mode] * (1024 + gi_tbl[l1pre.gi])) *
+		(l1pre.num_symbols + n_tbl[l1pre.fft_mode]) + 2048;
+
+	if (l1pre.mixed && l1post.fef_intvl) {
+		term_b = (l1post.fef_length + (l1post.fef_intvl / 2)) /
+			 l1post.fef_intvl;
+	} else {
+		term_b = 0;
+	}
+
+	switch (bw) {
+	case CXD2880_DTV_BW_1_7_MHZ:
+		denominator = ((term_a + term_b) * 71 + (131 / 2)) / 131;
+		break;
+	case CXD2880_DTV_BW_5_MHZ:
+		denominator = ((term_a + term_b) * 7 + 20) / 40;
+		break;
+	case CXD2880_DTV_BW_6_MHZ:
+		denominator = ((term_a + term_b) * 7 + 24) / 48;
+		break;
+	case CXD2880_DTV_BW_7_MHZ:
+		denominator = ((term_a + term_b) + 4) / 8;
+		break;
+	case CXD2880_DTV_BW_8_MHZ:
+	default:
+		denominator = ((term_a + term_b) * 7 + 32) / 64;
+		break;
+	}
+
+	if (plp.til_type && plp.til_len) {
+		pre_ber_rate =
+			(plp.num_blocks_max * 1000000 + (denominator / 2)) /
+			denominator;
+		pre_ber_rate = (pre_ber_rate + (plp.til_len / 2)) /
+			       plp.til_len;
+	} else {
+		pre_ber_rate =
+			(plp.num_blocks_max * 1000000 + (denominator / 2)) /
+			denominator;
+	}
+
+	post_ber_rate = pre_ber_rate;
+
+	mes_exp = intlog2(pre_ber_rate) >> 24;
+	priv->pre_ber_interval =
+		((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) /
+		pre_ber_rate;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
+			       mes_exp);
+
+	mes_exp = intlog2(post_ber_rate) >> 24;
+	priv->post_ber_interval =
+		((1U << mes_exp) * 1000 + (post_ber_rate / 2)) /
+		post_ber_rate;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
+			       mes_exp);
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_bbheader(&priv->tnrdmd,
+						CXD2880_DVBT2_PLP_DATA,
+						&bbheader);
+	if (ret) {
+		pr_info("bb header error\n");
+		goto error_ucblock_setting;
+	}
+
+	if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
+		if (!bbheader.issy_indicator) {
+			ucblock_rate =
+				(pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] +
+				752) / 1504;
+		} else {
+			ucblock_rate =
+				(pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] +
+				764) / 1528;
+		}
+	} else if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_HEM) {
+		ucblock_rate =
+			(pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 748) /
+			1496;
+	} else {
+		pr_info("plp mode is not Normal or HEM\n");
+		goto error_ucblock_setting;
+	}
+
+	mes_exp = intlog2(ucblock_rate) >> 24;
+	priv->ucblock_interval =
+		((1U << mes_exp) * 1000 + (ucblock_rate / 2)) /
+		ucblock_rate;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
+			       mes_exp);
+
+	return 0;
+
+error_ber_setting:
+	priv->pre_ber_interval = 1000;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+				     CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, 0);
+
+	priv->post_ber_interval = 1000;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, 0);
+
+error_ucblock_setting:
+	priv->ucblock_interval = 1000;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT2_PER_MES, 8);
+
+	return 0;
+}
+
+static int cxd2880_set_frontend(struct dvb_frontend *fe)
+{
+	int ret = 0;
+	int ret_val = 0;
+	struct dtv_frontend_properties *c;
+	struct cxd2880_priv *priv;
+	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
+
+	if (!fe) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->pre_bit_error.stat[0].uvalue = 0;
+	c->pre_bit_error.len = 1;
+	c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->pre_bit_count.stat[0].uvalue = 0;
+	c->pre_bit_count.len = 1;
+	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_error.stat[0].uvalue = 0;
+	c->post_bit_error.len = 1;
+	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_count.stat[0].uvalue = 0;
+	c->post_bit_count.len = 1;
+	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->block_error.stat[0].uvalue = 0;
+	c->block_error.len = 1;
+	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->block_count.stat[0].uvalue = 0;
+	c->block_count.len = 1;
+
+	switch (c->bandwidth_hz) {
+	case 1712000:
+		bw = CXD2880_DTV_BW_1_7_MHZ;
+		break;
+	case 5000000:
+		bw = CXD2880_DTV_BW_5_MHZ;
+		break;
+	case 6000000:
+		bw = CXD2880_DTV_BW_6_MHZ;
+		break;
+	case 7000000:
+		bw = CXD2880_DTV_BW_7_MHZ;
+		break;
+	case 8000000:
+		bw = CXD2880_DTV_BW_8_MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	pr_info("sys:%d freq:%d bw:%d\n",
+		c->delivery_system, c->frequency, bw);
+	mutex_lock(priv->spi_mutex);
+	if (c->delivery_system == SYS_DVBT) {
+		priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT;
+		priv->dvbt_tune_param.center_freq_khz = c->frequency / 1000;
+		priv->dvbt_tune_param.bandwidth = bw;
+		priv->dvbt_tune_param.profile = CXD2880_DVBT_PROFILE_HP;
+		ret = cxd2880_integ_dvbt_tune(&priv->tnrdmd,
+					      &priv->dvbt_tune_param);
+		ret_val = cxd2880_set_ber_per_period_t(fe);
+	} else if (c->delivery_system == SYS_DVBT2) {
+		priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT2;
+		priv->dvbt2_tune_param.center_freq_khz = c->frequency / 1000;
+		priv->dvbt2_tune_param.bandwidth = bw;
+		priv->dvbt2_tune_param.data_plp_id = (u16)c->stream_id;
+		priv->dvbt2_tune_param.profile = CXD2880_DVBT2_PROFILE_BASE;
+		ret = cxd2880_integ_dvbt2_tune(&priv->tnrdmd,
+					       &priv->dvbt2_tune_param);
+		ret_val = cxd2880_set_ber_per_period_t2(fe);
+	} else {
+		pr_err("invalid system\n");
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	pr_info("tune result %d set ber/per result %d\n", ret, ret_val);
+
+	return ret;
+}
+
+static int cxd2880_get_stats(struct dvb_frontend *fe,
+			     enum fe_status status)
+{
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+	u32 pre_bit_err = 0, pre_bit_count = 0;
+	u32 post_bit_err = 0, post_bit_count = 0;
+	u32 block_err = 0, block_count = 0;
+	int ret = 0;
+
+	if (!fe) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	if (!(status & FE_HAS_LOCK)) {
+		c->pre_bit_error.len = 1;
+		c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->pre_bit_count.len = 1;
+		c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->post_bit_error.len = 1;
+		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->post_bit_count.len = 1;
+		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->block_error.len = 1;
+		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->block_count.len = 1;
+		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+		return 0;
+	}
+
+	if (time_after(jiffies, priv->pre_ber_update)) {
+		priv->pre_ber_update =
+			 jiffies + msecs_to_jiffies(priv->pre_ber_interval);
+		if (c->delivery_system == SYS_DVBT) {
+			mutex_lock(priv->spi_mutex);
+			ret = cxd2880_pre_bit_err_t(&priv->tnrdmd,
+						    &pre_bit_err,
+						    &pre_bit_count);
+			mutex_unlock(priv->spi_mutex);
+		} else if (c->delivery_system == SYS_DVBT2) {
+			mutex_lock(priv->spi_mutex);
+			ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd,
+						     &pre_bit_err,
+						     &pre_bit_count);
+			mutex_unlock(priv->spi_mutex);
+		} else {
+			return -EINVAL;
+		}
+
+		if (!ret) {
+			c->pre_bit_error.len = 1;
+			c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+			c->pre_bit_error.stat[0].uvalue += pre_bit_err;
+			c->pre_bit_count.len = 1;
+			c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+			c->pre_bit_count.stat[0].uvalue += pre_bit_count;
+		} else {
+			c->pre_bit_error.len = 1;
+			c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+			c->pre_bit_count.len = 1;
+			c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+			pr_debug("pre_bit_error_t failed %d\n", ret);
+		}
+	}
+
+	if (time_after(jiffies, priv->post_ber_update)) {
+		priv->post_ber_update =
+			jiffies + msecs_to_jiffies(priv->post_ber_interval);
+		if (c->delivery_system == SYS_DVBT) {
+			mutex_lock(priv->spi_mutex);
+			ret = cxd2880_post_bit_err_t(&priv->tnrdmd,
+						     &post_bit_err,
+						     &post_bit_count);
+			mutex_unlock(priv->spi_mutex);
+		} else if (c->delivery_system == SYS_DVBT2) {
+			mutex_lock(priv->spi_mutex);
+			ret = cxd2880_post_bit_err_t2(&priv->tnrdmd,
+						      &post_bit_err,
+						      &post_bit_count);
+			mutex_unlock(priv->spi_mutex);
+		} else {
+			pr_err();
+			return -EINVAL;
+		}
+
+		if (!ret) {
+			c->post_bit_error.len = 1;
+			c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+			c->post_bit_error.stat[0].uvalue += post_bit_err;
+			c->post_bit_count.len = 1;
+			c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+			c->post_bit_count.stat[0].uvalue += post_bit_count;
+		} else {
+			c->post_bit_error.len = 1;
+			c->post_bit_error.stat[0].scale =
+							FE_SCALE_NOT_AVAILABLE;
+			c->post_bit_count.len = 1;
+			c->post_bit_count.stat[0].scale =
+							FE_SCALE_NOT_AVAILABLE;
+			pr_debug("post_bit_err_t %d\n", ret);
+		}
+	}
+
+	if (time_after(jiffies, priv->ucblock_update)) {
+		priv->ucblock_update =
+			jiffies + msecs_to_jiffies(priv->ucblock_interval);
+		if (c->delivery_system == SYS_DVBT) {
+			mutex_lock(priv->spi_mutex);
+			ret = cxd2880_read_block_err_t(&priv->tnrdmd,
+						       &block_err,
+						       &block_count);
+			mutex_unlock(priv->spi_mutex);
+		} else if (c->delivery_system == SYS_DVBT2) {
+			mutex_lock(priv->spi_mutex);
+			ret = cxd2880_read_block_err_t2(&priv->tnrdmd,
+							&block_err,
+							&block_count);
+			mutex_unlock(priv->spi_mutex);
+		} else {
+			pr_err();
+			return -EINVAL;
+		}
+		if (!ret) {
+			c->block_error.len = 1;
+			c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+			c->block_error.stat[0].uvalue += block_err;
+			c->block_count.len = 1;
+			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+			c->block_count.stat[0].uvalue += block_count;
+		} else {
+			c->block_error.len = 1;
+			c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+			c->block_count.len = 1;
+			c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+			pr_debug("read_block_err_t  %d\n", ret);
+		}
+	}
+
+	return 0;
+}
+
+static int cxd2880_read_status(struct dvb_frontend *fe,
+			       enum fe_status *status)
+{
+	int ret = 0;
+	u8 sync = 0;
+	u8 lock = 0;
+	u8 unlock = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+
+	if ((!fe) || (!status)) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+	*status = 0;
+
+	if (priv->tnrdmd.state == CXD2880_TNRDMD_STATE_ACTIVE) {
+		mutex_lock(priv->spi_mutex);
+		if (c->delivery_system == SYS_DVBT) {
+			ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(
+							&priv->tnrdmd,
+							&sync,
+							&lock,
+							&unlock);
+		} else if (c->delivery_system == SYS_DVBT2) {
+			ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(
+							&priv->tnrdmd,
+							&sync,
+							&lock,
+							&unlock);
+		} else {
+			pr_err("invlaid system");
+			mutex_unlock(priv->spi_mutex);
+			return -EINVAL;
+		}
+
+		mutex_unlock(priv->spi_mutex);
+		if (ret) {
+			pr_err("failed. sys = %d\n", priv->tnrdmd.sys);
+			return  ret;
+		}
+
+		if (sync == 6) {
+			*status = FE_HAS_SIGNAL |
+				  FE_HAS_CARRIER;
+		}
+		if (lock)
+			*status |= FE_HAS_VITERBI |
+				   FE_HAS_SYNC |
+				   FE_HAS_LOCK;
+	}
+
+	pr_debug("status %d result %d\n", *status, ret);
+
+	cxd2880_get_stats(fe, *status);
+	return  0;
+}
+
+static int cxd2880_tune(struct dvb_frontend *fe,
+			bool retune,
+			unsigned int mode_flags,
+			unsigned int *delay,
+			enum fe_status *status)
+{
+	int ret = 0;
+
+	if ((!fe) || (!delay) || (!status)) {
+		pr_err("invalid arg.");
+		return -EINVAL;
+	}
+
+	if (retune) {
+		ret = cxd2880_set_frontend(fe);
+		if (ret) {
+			pr_err("cxd2880_set_frontend failed %d\n", ret);
+			return ret;
+		}
+	}
+
+	*delay = HZ / 5;
+
+	return cxd2880_read_status(fe, status);
+}
+
+static int cxd2880_get_frontend_t(struct dvb_frontend *fe,
+				  struct dtv_frontend_properties *c)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+	enum cxd2880_dvbt_mode mode = CXD2880_DVBT_MODE_2K;
+	enum cxd2880_dvbt_guard guard = CXD2880_DVBT_GUARD_1_32;
+	struct cxd2880_dvbt_tpsinfo tps;
+	enum cxd2880_tnrdmd_spectrum_sense sense;
+	u16 snr = 0;
+	int strength = 0;
+
+	if ((!fe) || (!c)) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt_mon_mode_guard(&priv->tnrdmd,
+						 &mode, &guard);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (mode) {
+		case CXD2880_DVBT_MODE_2K:
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			break;
+		case CXD2880_DVBT_MODE_8K:
+			c->transmission_mode = TRANSMISSION_MODE_8K;
+			break;
+		default:
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			pr_err("get invalid mode %d\n", mode);
+			break;
+		}
+		switch (guard) {
+		case CXD2880_DVBT_GUARD_1_32:
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case CXD2880_DVBT_GUARD_1_16:
+			c->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case CXD2880_DVBT_GUARD_1_8:
+			c->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case CXD2880_DVBT_GUARD_1_4:
+			c->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		default:
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			pr_err("get invalid guard %d\n", guard);
+			break;
+		}
+	} else {
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		pr_debug("ModeGuard err %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (tps.hierarchy) {
+		case CXD2880_DVBT_HIERARCHY_NON:
+			c->hierarchy = HIERARCHY_NONE;
+			break;
+		case CXD2880_DVBT_HIERARCHY_1:
+			c->hierarchy = HIERARCHY_1;
+			break;
+		case CXD2880_DVBT_HIERARCHY_2:
+			c->hierarchy = HIERARCHY_2;
+			break;
+		case CXD2880_DVBT_HIERARCHY_4:
+			c->hierarchy = HIERARCHY_4;
+			break;
+		default:
+			c->hierarchy = HIERARCHY_NONE;
+			pr_err("TPSInfo hierarchy invalid %d\n",
+			       tps.hierarchy);
+			break;
+		}
+
+		switch (tps.rate_hp) {
+		case CXD2880_DVBT_CODERATE_1_2:
+			c->code_rate_HP = FEC_1_2;
+			break;
+		case CXD2880_DVBT_CODERATE_2_3:
+			c->code_rate_HP = FEC_2_3;
+			break;
+		case CXD2880_DVBT_CODERATE_3_4:
+			c->code_rate_HP = FEC_3_4;
+			break;
+		case CXD2880_DVBT_CODERATE_5_6:
+			c->code_rate_HP = FEC_5_6;
+			break;
+		case CXD2880_DVBT_CODERATE_7_8:
+			c->code_rate_HP = FEC_7_8;
+			break;
+		default:
+			c->code_rate_HP = FEC_NONE;
+			pr_err("TPSInfo rateHP invalid %d\n",
+			       tps.rate_hp);
+			break;
+		}
+		switch (tps.rate_lp) {
+		case CXD2880_DVBT_CODERATE_1_2:
+			c->code_rate_LP = FEC_1_2;
+			break;
+		case CXD2880_DVBT_CODERATE_2_3:
+			c->code_rate_LP = FEC_2_3;
+			break;
+		case CXD2880_DVBT_CODERATE_3_4:
+			c->code_rate_LP = FEC_3_4;
+			break;
+		case CXD2880_DVBT_CODERATE_5_6:
+			c->code_rate_LP = FEC_5_6;
+			break;
+		case CXD2880_DVBT_CODERATE_7_8:
+			c->code_rate_LP = FEC_7_8;
+			break;
+		default:
+			c->code_rate_LP = FEC_NONE;
+			pr_err("TPSInfo rateLP invalid %d\n",
+			       tps.rate_lp);
+			break;
+		}
+		switch (tps.constellation) {
+		case CXD2880_DVBT_CONSTELLATION_QPSK:
+			c->modulation = QPSK;
+			break;
+		case CXD2880_DVBT_CONSTELLATION_16QAM:
+			c->modulation = QAM_16;
+			break;
+		case CXD2880_DVBT_CONSTELLATION_64QAM:
+			c->modulation = QAM_64;
+			break;
+		default:
+			c->modulation = QPSK;
+			pr_err("TPSInfo constellation invalid %d\n",
+			       tps.constellation);
+			break;
+		}
+	} else {
+		c->hierarchy = HIERARCHY_NONE;
+		c->code_rate_HP = FEC_NONE;
+		c->code_rate_LP = FEC_NONE;
+		c->modulation = QPSK;
+		pr_debug("TPS info err %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (sense) {
+		case CXD2880_TNRDMD_SPECTRUM_NORMAL:
+			c->inversion = INVERSION_OFF;
+			break;
+		case CXD2880_TNRDMD_SPECTRUM_INV:
+			c->inversion = INVERSION_ON;
+			break;
+		default:
+			c->inversion = INVERSION_OFF;
+			pr_err("spectrum sense invalid %d\n", sense);
+			break;
+		}
+	} else {
+		c->inversion = INVERSION_OFF;
+		pr_debug("spectrum_sense %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+		c->strength.stat[0].svalue = strength;
+	} else {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		pr_debug("mon_rf_lvl %d\n", ret);
+	}
+
+	ret = cxd2880_read_snr(fe, &snr);
+	if (!ret) {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		c->cnr.stat[0].svalue = snr;
+	} else {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		pr_debug("read_snr %d\n", ret);
+	}
+
+	return 0;
+}
+
+static int cxd2880_get_frontend_t2(struct dvb_frontend *fe,
+				   struct dtv_frontend_properties *c)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct cxd2880_dvbt2_l1pre l1pre;
+	enum cxd2880_dvbt2_plp_code_rate coderate;
+	enum cxd2880_dvbt2_plp_constell qam;
+	enum cxd2880_tnrdmd_spectrum_sense sense;
+	u16 snr = 0;
+	int strength = 0;
+
+	if ((!fe) || (!c)) {
+		pr_err("invalid arg.\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (l1pre.fft_mode) {
+		case CXD2880_DVBT2_M2K:
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			break;
+		case CXD2880_DVBT2_M8K:
+			c->transmission_mode = TRANSMISSION_MODE_8K;
+			break;
+		case CXD2880_DVBT2_M4K:
+			c->transmission_mode = TRANSMISSION_MODE_4K;
+			break;
+		case CXD2880_DVBT2_M1K:
+			c->transmission_mode = TRANSMISSION_MODE_1K;
+			break;
+		case CXD2880_DVBT2_M16K:
+			c->transmission_mode = TRANSMISSION_MODE_16K;
+			break;
+		case CXD2880_DVBT2_M32K:
+			c->transmission_mode = TRANSMISSION_MODE_32K;
+			break;
+		default:
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			pr_err("L1Pre fft_mode invalid %d\n",
+			       l1pre.fft_mode);
+			break;
+		}
+		switch (l1pre.gi) {
+		case CXD2880_DVBT2_G1_32:
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case CXD2880_DVBT2_G1_16:
+			c->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case CXD2880_DVBT2_G1_8:
+			c->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case CXD2880_DVBT2_G1_4:
+			c->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		case CXD2880_DVBT2_G1_128:
+			c->guard_interval = GUARD_INTERVAL_1_128;
+			break;
+		case CXD2880_DVBT2_G19_128:
+			c->guard_interval = GUARD_INTERVAL_19_128;
+			break;
+		case CXD2880_DVBT2_G19_256:
+			c->guard_interval = GUARD_INTERVAL_19_256;
+			break;
+		default:
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			pr_err("L1Pre gi invalid %d\n", l1pre.gi);
+			break;
+		}
+	} else {
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		pr_debug("L1Pre err %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(&priv->tnrdmd,
+						 CXD2880_DVBT2_PLP_DATA,
+						 &coderate);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (coderate) {
+		case CXD2880_DVBT2_R1_2:
+			c->fec_inner = FEC_1_2;
+			break;
+		case CXD2880_DVBT2_R3_5:
+			c->fec_inner = FEC_3_5;
+			break;
+		case CXD2880_DVBT2_R2_3:
+			c->fec_inner = FEC_2_3;
+			break;
+		case CXD2880_DVBT2_R3_4:
+			c->fec_inner = FEC_3_4;
+			break;
+		case CXD2880_DVBT2_R4_5:
+			c->fec_inner = FEC_4_5;
+			break;
+		case CXD2880_DVBT2_R5_6:
+			c->fec_inner = FEC_5_6;
+			break;
+		default:
+			c->fec_inner = FEC_NONE;
+			pr_err("CodeRate invalid %d\n", coderate);
+			break;
+		}
+	} else {
+		c->fec_inner = FEC_NONE;
+		pr_debug("CodeRate %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt2_mon_qam(&priv->tnrdmd,
+					   CXD2880_DVBT2_PLP_DATA,
+					   &qam);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (qam) {
+		case CXD2880_DVBT2_QPSK:
+			c->modulation = QPSK;
+			break;
+		case CXD2880_DVBT2_QAM16:
+			c->modulation = QAM_16;
+			break;
+		case CXD2880_DVBT2_QAM64:
+			c->modulation = QAM_64;
+			break;
+		case CXD2880_DVBT2_QAM256:
+			c->modulation = QAM_256;
+			break;
+		default:
+			c->modulation = QPSK;
+			pr_err("QAM invalid %d\n", qam);
+			break;
+		}
+	} else {
+		c->modulation = QPSK;
+		pr_debug("QAM %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (sense) {
+		case CXD2880_TNRDMD_SPECTRUM_NORMAL:
+			c->inversion = INVERSION_OFF;
+			break;
+		case CXD2880_TNRDMD_SPECTRUM_INV:
+			c->inversion = INVERSION_ON;
+			break;
+		default:
+			c->inversion = INVERSION_OFF;
+			pr_err("spectrum sense invalid %d\n", sense);
+			break;
+		}
+	} else {
+		c->inversion = INVERSION_OFF;
+		pr_debug("SpectrumSense %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+		c->strength.stat[0].svalue = strength;
+	} else {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		pr_debug("mon_rf_lvl %d\n", ret);
+	}
+
+	ret = cxd2880_read_snr(fe, &snr);
+	if (!ret) {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		c->cnr.stat[0].svalue = snr;
+	} else {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		pr_debug("read_snr %d\n", ret);
+	}
+
+	return 0;
+}
+
+static int cxd2880_get_frontend(struct dvb_frontend *fe,
+				struct dtv_frontend_properties *props)
+{
+	struct cxd2880_priv *priv = NULL;
+	int ret = 0;
+
+	if ((!fe) || (!props)) {
+		pr_err("invalid arg.");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+
+	pr_debug("system=%d\n", fe->dtv_property_cache.delivery_system);
+	switch (fe->dtv_property_cache.delivery_system) {
+	case SYS_DVBT:
+		ret = cxd2880_get_frontend_t(fe, props);
+		break;
+	case SYS_DVBT2:
+		ret = cxd2880_get_frontend_t2(fe, props);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_HW;
+}
+
+static struct dvb_frontend_ops cxd2880_dvbt_t2_ops;
+
+struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
+				    struct cxd2880_config *cfg)
+{
+	int ret = 0;
+	enum cxd2880_tnrdmd_chip_id chipid =
+					CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
+	static struct cxd2880_priv *priv;
+	u8 data = 0;
+
+	if (!fe) {
+		pr_err("invalid arg.\n");
+		return NULL;
+	}
+
+	priv = kzalloc(sizeof(struct cxd2880_priv), GFP_KERNEL);
+	if (!priv)
+		return NULL;
+
+	priv->spi = cfg->spi;
+	priv->spi_mutex = cfg->spi_mutex;
+	priv->spi_device.spi = cfg->spi;
+
+	memcpy(&fe->ops, &cxd2880_dvbt_t2_ops,
+	       sizeof(struct dvb_frontend_ops));
+
+	ret = cxd2880_spi_device_initialize(&priv->spi_device,
+					    CXD2880_SPI_MODE_0,
+					    55000000);
+	if (ret) {
+		pr_err("spi_device_initialize failed. %d\n", ret);
+		kfree(priv);
+		return NULL;
+	}
+
+	ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi,
+					    &priv->spi_device);
+	if (ret) {
+		pr_err("spi_device_create_spi failed. %d\n", ret);
+		kfree(priv);
+		return NULL;
+	}
+
+	ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0);
+	if (ret) {
+		pr_err("io_spi_create failed. %d\n", ret);
+		kfree(priv);
+		return NULL;
+	}
+	ret = priv->regio.write_reg(&priv->regio,
+				    CXD2880_IO_TGT_SYS, 0x00, 0x00);
+	if (ret) {
+		pr_err("set bank to 0x00 failed.\n");
+		kfree(priv);
+		return NULL;
+	}
+	ret = priv->regio.read_regs(&priv->regio,
+				    CXD2880_IO_TGT_SYS, 0xfd, &data, 1);
+	if (ret) {
+		pr_err("read chip id failed.\n");
+		kfree(priv);
+		return NULL;
+	}
+
+	chipid = (enum cxd2880_tnrdmd_chip_id)data;
+	if ((chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) &&
+	    (chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11)) {
+		pr_err("chip id invalid.\n");
+		kfree(priv);
+		return NULL;
+	}
+
+	fe->demodulator_priv = priv;
+	pr_info("CXD2880 driver version: Ver %s\n",
+		CXD2880_TNRDMD_DRIVER_VERSION);
+
+	return fe;
+}
+EXPORT_SYMBOL(cxd2880_attach);
+
+static struct dvb_frontend_ops cxd2880_dvbt_t2_ops = {
+	.info = {
+		.name = "Sony CXD2880",
+		.frequency_min =  174000000,
+		.frequency_max = 862000000,
+		.frequency_stepsize = 1000,
+		.caps = FE_CAN_INVERSION_AUTO |
+				FE_CAN_FEC_1_2 |
+				FE_CAN_FEC_2_3 |
+				FE_CAN_FEC_3_4 |
+				FE_CAN_FEC_4_5 |
+				FE_CAN_FEC_5_6	|
+				FE_CAN_FEC_7_8	|
+				FE_CAN_FEC_AUTO |
+				FE_CAN_QPSK |
+				FE_CAN_QAM_16 |
+				FE_CAN_QAM_32 |
+				FE_CAN_QAM_64 |
+				FE_CAN_QAM_128 |
+				FE_CAN_QAM_256 |
+				FE_CAN_QAM_AUTO |
+				FE_CAN_TRANSMISSION_MODE_AUTO |
+				FE_CAN_GUARD_INTERVAL_AUTO |
+				FE_CAN_2G_MODULATION |
+				FE_CAN_RECOVER |
+				FE_CAN_MUTE_TS,
+	},
+	.delsys = { SYS_DVBT, SYS_DVBT2 },
+
+	.release = cxd2880_release,
+	.init = cxd2880_init,
+	.sleep = cxd2880_sleep,
+	.tune = cxd2880_tune,
+	.set_frontend = cxd2880_set_frontend,
+	.get_frontend = cxd2880_get_frontend,
+	.read_status = cxd2880_read_status,
+	.read_ber = cxd2880_read_ber,
+	.read_signal_strength = cxd2880_read_signal_strength,
+	.read_snr = cxd2880_read_snr,
+	.read_ucblocks = cxd2880_read_ucblocks,
+	.get_frontend_algo = cxd2880_get_frontend_algo,
+};
+
+MODULE_DESCRIPTION(
+"Sony CXD2880 DVB-T2/T tuner + demodulator drvier");
+MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
+MODULE_LICENSE("GPL v2");
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 07/14] [media] cxd2880: Add top level of the driver
@ 2017-08-16  4:39   ` Yasunari.Takiguchi
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:39 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

This provides the main dvb frontend operation functions
for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
      -adjusted indent spaces
      -modified debugging code
      -removed unnecessary cast
      -modified return code
      -modified coding style of if() 
      -modified about measurement period of PER/BER.
      -changed hexadecimal code to lower case. 

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c | 1879 +++++++++++++++++++++
 1 file changed, 1879 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
new file mode 100644
index 000000000000..306966dd186b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
@@ -0,0 +1,1879 @@
+/*
+ * cxd2880_top.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
+
+#include <linux/spi/spi.h>
+
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+
+#include "cxd2880.h"
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+#include "cxd2880_tnrdmd_dvbt_mon.h"
+#include "cxd2880_integ_dvbt2.h"
+#include "cxd2880_integ_dvbt.h"
+#include "cxd2880_devio_spi.h"
+#include "cxd2880_spi_device.h"
+#include "cxd2880_tnrdmd_driver_version.h"
+
+struct cxd2880_priv {
+	struct cxd2880_tnrdmd tnrdmd;
+	struct spi_device *spi;
+	struct cxd2880_io regio;
+	struct cxd2880_spi_device spi_device;
+	struct cxd2880_spi cxd2880_spi;
+	struct cxd2880_dvbt_tune_param dvbt_tune_param;
+	struct cxd2880_dvbt2_tune_param dvbt2_tune_param;
+	struct mutex *spi_mutex; /* For SPI access exclusive control */
+	unsigned long pre_ber_update;
+	unsigned long pre_ber_interval;
+	unsigned long post_ber_update;
+	unsigned long post_ber_interval;
+	unsigned long ucblock_update;
+	unsigned long ucblock_interval;
+};
+
+static int cxd2880_pre_bit_err_t(
+		struct cxd2880_tnrdmd *tnrdmd, u32 *pre_bit_err,
+		u32 *pre_bit_count)
+{
+	u8 rdata[2];
+	int ret = 0;
+
+	if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count))
+		return -EINVAL;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnrdmd);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x10);
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x39, rdata, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	if ((rdata[0] & 0x01) == 0) {
+		slvt_unfreeze_reg(tnrdmd);
+		return -EBUSY;
+	}
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x22, rdata, 2);
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	*pre_bit_err = (rdata[0] << 8) | rdata[1];
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x6f, rdata, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnrdmd);
+
+	*pre_bit_count = ((rdata[0] & 0x07) == 0) ?
+			 256 : (0x1000 << (rdata[0] & 0x07));
+
+	return 0;
+}
+
+static int cxd2880_pre_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
+				  u32 *pre_bit_err,
+				  u32 *pre_bit_count)
+{
+	u32 period_exp = 0;
+	u32 n_ldpc = 0;
+	u8 data[5];
+	int ret = 0;
+
+	if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count))
+		return -EINVAL;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnrdmd);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x0b);
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x3c, data, sizeof(data));
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	if (!(data[0] & 0x01)) {
+		slvt_unfreeze_reg(tnrdmd);
+		return -EBUSY;
+	}
+	*pre_bit_err =
+	((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0xa0, data, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnrdmd);
+		return ret;
+	}
+
+	if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) ==
+	    CXD2880_DVBT2_FEC_LDPC_16K)
+		n_ldpc = 16200;
+	else
+		n_ldpc = 64800;
+	slvt_unfreeze_reg(tnrdmd);
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x20);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x6f, data, 1);
+	if (ret)
+		return ret;
+
+	period_exp = data[0] & 0x0f;
+
+	*pre_bit_count = (1U << period_exp) * n_ldpc;
+
+	return 0;
+}
+
+static int cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd,
+				  u32 *post_bit_err,
+				  u32 *post_bit_count)
+{
+	u8 rdata[3];
+	u32 bit_error = 0;
+	u32 period_exp = 0;
+	int ret = 0;
+
+	if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count))
+		return -EINVAL;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x0d);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x15, rdata, 3);
+	if (ret)
+		return ret;
+
+	if ((rdata[0] & 0x40) == 0)
+		return -EBUSY;
+
+	*post_bit_err = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2];
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x60, rdata, 1);
+	if (ret)
+		return ret;
+
+	period_exp = (rdata[0] & 0x1f);
+
+	if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8))
+		return -EBUSY;
+
+	if (period_exp == 11)
+		*post_bit_count = 3342336;
+	else
+		*post_bit_count = (1U << period_exp) * 204 * 81;
+
+	return 0;
+}
+
+static int cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
+				   u32 *post_bit_err,
+				   u32 *post_bit_count)
+{
+	u32 period_exp = 0;
+	u32 n_bch = 0;
+
+	if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count))
+		return -EINVAL;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[3];
+		enum cxd2880_dvbt2_plp_fec plp_fec_type =
+			CXD2880_DVBT2_FEC_LDPC_16K;
+		enum cxd2880_dvbt2_plp_code_rate plp_code_rate =
+			CXD2880_DVBT2_R1_2;
+
+		static const u16 n_bch_bits_lookup[2][8] = {
+			{7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480},
+			{32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920}
+		};
+		int ret = 0;
+
+		ret = slvt_freeze_reg(tnrdmd);
+		if (ret)
+			return ret;
+
+		ret = tnrdmd->io->write_reg(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnrdmd);
+			return ret;
+		}
+
+		ret = tnrdmd->io->read_regs(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x15, data, 3);
+		if (ret) {
+			slvt_unfreeze_reg(tnrdmd);
+			return ret;
+		}
+
+		if (!(data[0] & 0x40)) {
+			slvt_unfreeze_reg(tnrdmd);
+			return -EBUSY;
+		}
+
+		*post_bit_err =
+			((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2];
+
+		ret = tnrdmd->io->read_regs(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x9d, data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnrdmd);
+			return ret;
+		}
+
+		plp_code_rate =
+		(enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07);
+
+		ret = tnrdmd->io->read_regs(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0xa0, data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnrdmd);
+			return ret;
+		}
+
+		plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03);
+
+		slvt_unfreeze_reg(tnrdmd);
+
+		ret = tnrdmd->io->write_reg(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x00, 0x20);
+		if (ret)
+			return ret;
+
+		ret = tnrdmd->io->read_regs(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x72, data, 1);
+		if (ret)
+			return ret;
+
+		period_exp = data[0] & 0x0f;
+
+		if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) ||
+		    (plp_code_rate > CXD2880_DVBT2_R2_5))
+			return -EBUSY;
+
+		n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate];
+	}
+
+	if (*post_bit_err > ((1U << period_exp) * n_bch))
+		return -EBUSY;
+
+	*post_bit_count = (1U << period_exp) * n_bch;
+
+	return 0;
+}
+
+static int cxd2880_read_block_err_t(struct cxd2880_tnrdmd *tnrdmd,
+				    u32 *block_err,
+				    u32 *block_count)
+{
+	u8 rdata[3];
+	int ret = 0;
+
+	if ((!tnrdmd) || (!block_err) || (!block_count))
+		return -EINVAL;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x0d);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x18, rdata, 3);
+	if (ret)
+		return ret;
+
+	if ((rdata[0] & 0x01) == 0)
+		return -EBUSY;
+
+	*block_err = (rdata[1] << 8) | rdata[2];
+
+	ret = tnrdmd->io->write_reg(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnrdmd->io->read_regs(tnrdmd->io,
+				    CXD2880_IO_TGT_DMD,
+				    0x5c, rdata, 1);
+	if (ret)
+		return ret;
+
+	*block_count = 1U << (rdata[0] & 0x0f);
+
+	if ((*block_count == 0) || (*block_err > *block_count))
+		return -EBUSY;
+
+	return 0;
+}
+
+static int cxd2880_read_block_err_t2(struct cxd2880_tnrdmd *tnrdmd,
+				     u32 *block_err,
+				     u32 *block_count)
+{
+	if ((!tnrdmd) || (!block_err) || (!block_count))
+		return -EINVAL;
+
+	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 rdata[3];
+		int ret = 0;
+
+		ret = tnrdmd->io->write_reg(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x00, 0x0b);
+		if (ret)
+			return ret;
+
+		ret = tnrdmd->io->read_regs(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x18, rdata, 3);
+		if (ret)
+			return ret;
+
+		if ((rdata[0] & 0x01) == 0)
+			return -EBUSY;
+
+		*block_err = (rdata[1] << 8) | rdata[2];
+
+		ret = tnrdmd->io->write_reg(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x00, 0x24);
+		if (ret)
+			return ret;
+
+		ret = tnrdmd->io->read_regs(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0xdc, rdata, 1);
+		if (ret)
+			return ret;
+
+		*block_count = 1U << (rdata[0] & 0x0f);
+	}
+
+	if ((*block_count == 0) || (*block_err > *block_count))
+		return -EBUSY;
+
+	return 0;
+}
+
+static void cxd2880_release(struct dvb_frontend *fe)
+{
+	struct cxd2880_priv *priv = NULL;
+
+	if (!fe) {
+		pr_err("invalid arg.\n");
+		return;
+	}
+	priv = fe->demodulator_priv;
+	kfree(priv);
+}
+
+static int cxd2880_init(struct dvb_frontend *fe)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct cxd2880_tnrdmd_create_param create_param;
+
+	if (!fe) {
+		pr_err("invalid arg.\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+
+	create_param.ts_output_if = CXD2880_TNRDMD_TSOUT_IF_SPI;
+	create_param.xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_NONE;
+	create_param.en_internal_ldo = 1;
+	create_param.xosc_cap = 18;
+	create_param.xosc_i = 8;
+	create_param.stationary_use = 1;
+
+	mutex_lock(priv->spi_mutex);
+	if (priv->tnrdmd.io != &priv->regio) {
+		ret = cxd2880_tnrdmd_create(&priv->tnrdmd,
+					    &priv->regio, &create_param);
+		if (ret) {
+			mutex_unlock(priv->spi_mutex);
+			pr_info("cxd2880 tnrdmd create failed %d\n", ret);
+			return ret;
+		}
+	}
+	ret = cxd2880_integ_init(&priv->tnrdmd);
+	if (ret) {
+		mutex_unlock(priv->spi_mutex);
+		pr_err("cxd2880 integ init failed %d\n", ret);
+		return ret;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	pr_debug("OK.\n");
+
+	return ret;
+}
+
+static int cxd2880_sleep(struct dvb_frontend *fe)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+
+	if (!fe) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd);
+	mutex_unlock(priv->spi_mutex);
+
+	pr_debug("tnrdmd_sleep ret %d\n", ret);
+
+	return ret;
+}
+
+static int cxd2880_read_signal_strength(struct dvb_frontend *fe,
+					u16 *strength)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+	int level = 0;
+
+	if ((!fe) || (!strength)) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	mutex_lock(priv->spi_mutex);
+	if ((c->delivery_system == SYS_DVBT) ||
+	    (c->delivery_system == SYS_DVBT2)) {
+		ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &level);
+	} else {
+		pr_debug("invalid system\n");
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	level /= 125;
+	/* -105dBm - -30dBm (-105000/125 = -840, -30000/125 = -240 */
+	level = clamp(level, -840, -240);
+	/* scale value to 0x0000-0xffff */
+	*strength = (u16)(((level + 840) * 0xffff) / (-240 + 840));
+
+	if (ret)
+		pr_debug("ret = %d\n", ret);
+
+	return ret;
+}
+
+static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	int ret = 0;
+	int snrvalue = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+
+	if ((!fe) || (!snr)) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	mutex_lock(priv->spi_mutex);
+	if (c->delivery_system == SYS_DVBT) {
+		ret = cxd2880_tnrdmd_dvbt_mon_snr(&priv->tnrdmd,
+						  &snrvalue);
+	} else if (c->delivery_system == SYS_DVBT2) {
+		ret = cxd2880_tnrdmd_dvbt2_mon_snr(&priv->tnrdmd,
+						   &snrvalue);
+	} else {
+		pr_err("invalid system\n");
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	if (snrvalue < 0)
+		snrvalue = 0;
+	*snr = (u16)snrvalue;
+
+	if (ret)
+		pr_debug("ret = %d\n", ret);
+
+	return ret;
+}
+
+static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+
+	if ((!fe) || (!ucblocks)) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	mutex_lock(priv->spi_mutex);
+	if (c->delivery_system == SYS_DVBT) {
+		ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number(
+								&priv->tnrdmd,
+								ucblocks);
+	} else if (c->delivery_system == SYS_DVBT2) {
+		ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number(
+								&priv->tnrdmd,
+								ucblocks);
+	} else {
+		pr_err("invlaid system\n");
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	if (ret)
+		pr_debug("ret = %d\n", ret);
+
+	return ret;
+}
+
+static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+
+	if ((!fe) || (!ber)) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	mutex_lock(priv->spi_mutex);
+	if (c->delivery_system == SYS_DVBT) {
+		ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(&priv->tnrdmd,
+							ber);
+		/* x100 to change unit.(10^7 -> 10^9 */
+		*ber *= 100;
+	} else if (c->delivery_system == SYS_DVBT2) {
+		ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(&priv->tnrdmd,
+							  ber);
+	} else {
+		pr_err("invlaid system\n");
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	if (ret)
+		pr_debug("ret = %d\n", ret);
+
+	return ret;
+}
+
+static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe)
+{
+	int ret = 0;
+	struct dtv_frontend_properties *c;
+	struct cxd2880_priv *priv;
+	int cr_table[5] = {31500, 42000, 47250, 52500, 55125};
+	int denominator_tbl[4] = {125664, 129472, 137088, 152320};
+	struct cxd2880_dvbt_tpsinfo info;
+	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
+	u32 pre_ber_rate = 0;
+	u32 post_ber_rate = 0;
+	u32 ucblock_rate = 0;
+	u32 mes_exp = 0;
+
+	if (!fe) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+	bw = priv->dvbt_tune_param.bandwidth;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd,
+					       &info);
+	if (ret) {
+		pr_err("tps monitor error ret = %d\n", ret);
+		info.hierarchy = CXD2880_DVBT_HIERARCHY_NON;
+		info.constellation = CXD2880_DVBT_CONSTELLATION_QPSK;
+		info.guard = CXD2880_DVBT_GUARD_1_4;
+		info.rate_hp = CXD2880_DVBT_CODERATE_1_2;
+		info.rate_lp = CXD2880_DVBT_CODERATE_1_2;
+	}
+
+	if (info.hierarchy == CXD2880_DVBT_HIERARCHY_NON) {
+		pre_ber_rate = 63000000 * bw * (info.constellation * 2 + 2) /
+			       denominator_tbl[info.guard];
+
+		post_ber_rate =	1000 * cr_table[info.rate_hp] * bw *
+				(info.constellation * 2 + 2) /
+				denominator_tbl[info.guard];
+
+		ucblock_rate = 875 * cr_table[info.rate_hp] * bw *
+			       (info.constellation * 2 + 2) /
+			       denominator_tbl[info.guard];
+	} else {
+		u8 data = 0;
+		struct cxd2880_tnrdmd *tnrdmd = &priv->tnrdmd;
+
+		ret = tnrdmd->io->write_reg(tnrdmd->io,
+					    CXD2880_IO_TGT_DMD,
+					    0x00, 0x10);
+		if (!ret) {
+			ret = tnrdmd->io->read_regs(tnrdmd->io,
+						    CXD2880_IO_TGT_DMD,
+						    0x67, &data, 1);
+			if (ret)
+				data = 0x00;
+		} else {
+			data = 0x00;
+		}
+
+		if (data & 0x01) { /* Low priority */
+			pre_ber_rate =
+				63000000 * bw * (info.constellation * 2 + 2) /
+				denominator_tbl[info.guard];
+
+			post_ber_rate = 1000 * cr_table[info.rate_lp] * bw *
+					(info.constellation * 2 + 2) /
+					denominator_tbl[info.guard];
+
+			ucblock_rate = (1000 * 7 / 8) *	cr_table[info.rate_lp] *
+				       bw * (info.constellation * 2 + 2) /
+				       denominator_tbl[info.guard];
+		} else { /* High priority */
+			pre_ber_rate =
+				63000000 * bw * 2 / denominator_tbl[info.guard];
+
+			post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * 2 /
+					denominator_tbl[info.guard];
+
+			ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_hp] *
+					bw * 2 / denominator_tbl[info.guard];
+		}
+	}
+
+	mes_exp = pre_ber_rate < 8192 ? 8 : intlog2(pre_ber_rate) >> 24;
+	priv->pre_ber_interval =
+		((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) /
+		pre_ber_rate;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
+			       mes_exp == 8 ? 0 : mes_exp - 12);
+
+	mes_exp = intlog2(post_ber_rate) >> 24;
+	priv->post_ber_interval =
+		((1U << mes_exp) * 1000 + (post_ber_rate / 2)) /
+		post_ber_rate;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
+			       mes_exp);
+
+	mes_exp = intlog2(ucblock_rate) >> 24;
+	priv->ucblock_interval =
+		((1U << mes_exp) * 1000 + (ucblock_rate / 2)) /
+		ucblock_rate;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT_PER_MES,
+			       mes_exp);
+
+	return 0;
+}
+
+static int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe)
+{
+	int ret = 0;
+	struct dtv_frontend_properties *c;
+	struct cxd2880_priv *priv;
+	struct cxd2880_dvbt2_l1pre l1pre;
+	struct cxd2880_dvbt2_l1post l1post;
+	struct cxd2880_dvbt2_plp plp;
+	struct cxd2880_dvbt2_bbheader bbheader;
+	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
+	u32 pre_ber_rate = 0;
+	u32 post_ber_rate = 0;
+	u32 ucblock_rate = 0;
+	u32 mes_exp = 0;
+	u32 term_a = 0;
+	u32 term_b = 0;
+	u32 gi_tbl[7] = {32, 64, 128, 256, 8, 152, 76};
+	u8  n_tbl[6] = {8, 2, 4, 16, 1, 1};
+	u8  mode_tbl[6] = {2, 8, 4, 1, 16, 32};
+	u32 kbch_tbl[2][8] = {
+			{6952, 9472, 10552, 11632, 12352, 13072, 5152, 6232},
+			{32128, 38608, 42960, 48328, 51568, 53760, 0, 0} };
+	u32 denominator = 0;
+
+	if (!fe) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+	bw = priv->dvbt2_tune_param.bandwidth;
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
+	if (ret) {
+		pr_info("l1 pre error\n");
+		goto error_ber_setting;
+	}
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_active_plp(&priv->tnrdmd,
+						  CXD2880_DVBT2_PLP_DATA, &plp);
+	if (ret) {
+		pr_info("plp info error\n");
+		goto error_ber_setting;
+	}
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_l1_post(&priv->tnrdmd, &l1post);
+	if (ret) {
+		pr_info("l1 post error\n");
+		goto error_ber_setting;
+	}
+
+	term_a =
+		(mode_tbl[l1pre.fft_mode] * (1024 + gi_tbl[l1pre.gi])) *
+		(l1pre.num_symbols + n_tbl[l1pre.fft_mode]) + 2048;
+
+	if (l1pre.mixed && l1post.fef_intvl) {
+		term_b = (l1post.fef_length + (l1post.fef_intvl / 2)) /
+			 l1post.fef_intvl;
+	} else {
+		term_b = 0;
+	}
+
+	switch (bw) {
+	case CXD2880_DTV_BW_1_7_MHZ:
+		denominator = ((term_a + term_b) * 71 + (131 / 2)) / 131;
+		break;
+	case CXD2880_DTV_BW_5_MHZ:
+		denominator = ((term_a + term_b) * 7 + 20) / 40;
+		break;
+	case CXD2880_DTV_BW_6_MHZ:
+		denominator = ((term_a + term_b) * 7 + 24) / 48;
+		break;
+	case CXD2880_DTV_BW_7_MHZ:
+		denominator = ((term_a + term_b) + 4) / 8;
+		break;
+	case CXD2880_DTV_BW_8_MHZ:
+	default:
+		denominator = ((term_a + term_b) * 7 + 32) / 64;
+		break;
+	}
+
+	if (plp.til_type && plp.til_len) {
+		pre_ber_rate =
+			(plp.num_blocks_max * 1000000 + (denominator / 2)) /
+			denominator;
+		pre_ber_rate = (pre_ber_rate + (plp.til_len / 2)) /
+			       plp.til_len;
+	} else {
+		pre_ber_rate =
+			(plp.num_blocks_max * 1000000 + (denominator / 2)) /
+			denominator;
+	}
+
+	post_ber_rate = pre_ber_rate;
+
+	mes_exp = intlog2(pre_ber_rate) >> 24;
+	priv->pre_ber_interval =
+		((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) /
+		pre_ber_rate;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
+			       mes_exp);
+
+	mes_exp = intlog2(post_ber_rate) >> 24;
+	priv->post_ber_interval =
+		((1U << mes_exp) * 1000 + (post_ber_rate / 2)) /
+		post_ber_rate;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
+			       mes_exp);
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_bbheader(&priv->tnrdmd,
+						CXD2880_DVBT2_PLP_DATA,
+						&bbheader);
+	if (ret) {
+		pr_info("bb header error\n");
+		goto error_ucblock_setting;
+	}
+
+	if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
+		if (!bbheader.issy_indicator) {
+			ucblock_rate =
+				(pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] +
+				752) / 1504;
+		} else {
+			ucblock_rate =
+				(pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] +
+				764) / 1528;
+		}
+	} else if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_HEM) {
+		ucblock_rate =
+			(pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 748) /
+			1496;
+	} else {
+		pr_info("plp mode is not Normal or HEM\n");
+		goto error_ucblock_setting;
+	}
+
+	mes_exp = intlog2(ucblock_rate) >> 24;
+	priv->ucblock_interval =
+		((1U << mes_exp) * 1000 + (ucblock_rate / 2)) /
+		ucblock_rate;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
+			       mes_exp);
+
+	return 0;
+
+error_ber_setting:
+	priv->pre_ber_interval = 1000;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+				     CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, 0);
+
+	priv->post_ber_interval = 1000;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, 0);
+
+error_ucblock_setting:
+	priv->ucblock_interval = 1000;
+	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
+			       CXD2880_TNRDMD_CFG_DVBT2_PER_MES, 8);
+
+	return 0;
+}
+
+static int cxd2880_set_frontend(struct dvb_frontend *fe)
+{
+	int ret = 0;
+	int ret_val = 0;
+	struct dtv_frontend_properties *c;
+	struct cxd2880_priv *priv;
+	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
+
+	if (!fe) {
+		pr_err("inavlid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->pre_bit_error.stat[0].uvalue = 0;
+	c->pre_bit_error.len = 1;
+	c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->pre_bit_count.stat[0].uvalue = 0;
+	c->pre_bit_count.len = 1;
+	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_error.stat[0].uvalue = 0;
+	c->post_bit_error.len = 1;
+	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_count.stat[0].uvalue = 0;
+	c->post_bit_count.len = 1;
+	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->block_error.stat[0].uvalue = 0;
+	c->block_error.len = 1;
+	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->block_count.stat[0].uvalue = 0;
+	c->block_count.len = 1;
+
+	switch (c->bandwidth_hz) {
+	case 1712000:
+		bw = CXD2880_DTV_BW_1_7_MHZ;
+		break;
+	case 5000000:
+		bw = CXD2880_DTV_BW_5_MHZ;
+		break;
+	case 6000000:
+		bw = CXD2880_DTV_BW_6_MHZ;
+		break;
+	case 7000000:
+		bw = CXD2880_DTV_BW_7_MHZ;
+		break;
+	case 8000000:
+		bw = CXD2880_DTV_BW_8_MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	pr_info("sys:%d freq:%d bw:%d\n",
+		c->delivery_system, c->frequency, bw);
+	mutex_lock(priv->spi_mutex);
+	if (c->delivery_system == SYS_DVBT) {
+		priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT;
+		priv->dvbt_tune_param.center_freq_khz = c->frequency / 1000;
+		priv->dvbt_tune_param.bandwidth = bw;
+		priv->dvbt_tune_param.profile = CXD2880_DVBT_PROFILE_HP;
+		ret = cxd2880_integ_dvbt_tune(&priv->tnrdmd,
+					      &priv->dvbt_tune_param);
+		ret_val = cxd2880_set_ber_per_period_t(fe);
+	} else if (c->delivery_system == SYS_DVBT2) {
+		priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT2;
+		priv->dvbt2_tune_param.center_freq_khz = c->frequency / 1000;
+		priv->dvbt2_tune_param.bandwidth = bw;
+		priv->dvbt2_tune_param.data_plp_id = (u16)c->stream_id;
+		priv->dvbt2_tune_param.profile = CXD2880_DVBT2_PROFILE_BASE;
+		ret = cxd2880_integ_dvbt2_tune(&priv->tnrdmd,
+					       &priv->dvbt2_tune_param);
+		ret_val = cxd2880_set_ber_per_period_t2(fe);
+	} else {
+		pr_err("invalid system\n");
+		mutex_unlock(priv->spi_mutex);
+		return -EINVAL;
+	}
+	mutex_unlock(priv->spi_mutex);
+
+	pr_info("tune result %d set ber/per result %d\n", ret, ret_val);
+
+	return ret;
+}
+
+static int cxd2880_get_stats(struct dvb_frontend *fe,
+			     enum fe_status status)
+{
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+	u32 pre_bit_err = 0, pre_bit_count = 0;
+	u32 post_bit_err = 0, post_bit_count = 0;
+	u32 block_err = 0, block_count = 0;
+	int ret = 0;
+
+	if (!fe) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+
+	if (!(status & FE_HAS_LOCK)) {
+		c->pre_bit_error.len = 1;
+		c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->pre_bit_count.len = 1;
+		c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->post_bit_error.len = 1;
+		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->post_bit_count.len = 1;
+		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->block_error.len = 1;
+		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		c->block_count.len = 1;
+		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+		return 0;
+	}
+
+	if (time_after(jiffies, priv->pre_ber_update)) {
+		priv->pre_ber_update =
+			 jiffies + msecs_to_jiffies(priv->pre_ber_interval);
+		if (c->delivery_system == SYS_DVBT) {
+			mutex_lock(priv->spi_mutex);
+			ret = cxd2880_pre_bit_err_t(&priv->tnrdmd,
+						    &pre_bit_err,
+						    &pre_bit_count);
+			mutex_unlock(priv->spi_mutex);
+		} else if (c->delivery_system == SYS_DVBT2) {
+			mutex_lock(priv->spi_mutex);
+			ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd,
+						     &pre_bit_err,
+						     &pre_bit_count);
+			mutex_unlock(priv->spi_mutex);
+		} else {
+			return -EINVAL;
+		}
+
+		if (!ret) {
+			c->pre_bit_error.len = 1;
+			c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+			c->pre_bit_error.stat[0].uvalue += pre_bit_err;
+			c->pre_bit_count.len = 1;
+			c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+			c->pre_bit_count.stat[0].uvalue += pre_bit_count;
+		} else {
+			c->pre_bit_error.len = 1;
+			c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+			c->pre_bit_count.len = 1;
+			c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+			pr_debug("pre_bit_error_t failed %d\n", ret);
+		}
+	}
+
+	if (time_after(jiffies, priv->post_ber_update)) {
+		priv->post_ber_update =
+			jiffies + msecs_to_jiffies(priv->post_ber_interval);
+		if (c->delivery_system == SYS_DVBT) {
+			mutex_lock(priv->spi_mutex);
+			ret = cxd2880_post_bit_err_t(&priv->tnrdmd,
+						     &post_bit_err,
+						     &post_bit_count);
+			mutex_unlock(priv->spi_mutex);
+		} else if (c->delivery_system == SYS_DVBT2) {
+			mutex_lock(priv->spi_mutex);
+			ret = cxd2880_post_bit_err_t2(&priv->tnrdmd,
+						      &post_bit_err,
+						      &post_bit_count);
+			mutex_unlock(priv->spi_mutex);
+		} else {
+			pr_err();
+			return -EINVAL;
+		}
+
+		if (!ret) {
+			c->post_bit_error.len = 1;
+			c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+			c->post_bit_error.stat[0].uvalue += post_bit_err;
+			c->post_bit_count.len = 1;
+			c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+			c->post_bit_count.stat[0].uvalue += post_bit_count;
+		} else {
+			c->post_bit_error.len = 1;
+			c->post_bit_error.stat[0].scale =
+							FE_SCALE_NOT_AVAILABLE;
+			c->post_bit_count.len = 1;
+			c->post_bit_count.stat[0].scale =
+							FE_SCALE_NOT_AVAILABLE;
+			pr_debug("post_bit_err_t %d\n", ret);
+		}
+	}
+
+	if (time_after(jiffies, priv->ucblock_update)) {
+		priv->ucblock_update =
+			jiffies + msecs_to_jiffies(priv->ucblock_interval);
+		if (c->delivery_system == SYS_DVBT) {
+			mutex_lock(priv->spi_mutex);
+			ret = cxd2880_read_block_err_t(&priv->tnrdmd,
+						       &block_err,
+						       &block_count);
+			mutex_unlock(priv->spi_mutex);
+		} else if (c->delivery_system == SYS_DVBT2) {
+			mutex_lock(priv->spi_mutex);
+			ret = cxd2880_read_block_err_t2(&priv->tnrdmd,
+							&block_err,
+							&block_count);
+			mutex_unlock(priv->spi_mutex);
+		} else {
+			pr_err();
+			return -EINVAL;
+		}
+		if (!ret) {
+			c->block_error.len = 1;
+			c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+			c->block_error.stat[0].uvalue += block_err;
+			c->block_count.len = 1;
+			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+			c->block_count.stat[0].uvalue += block_count;
+		} else {
+			c->block_error.len = 1;
+			c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+			c->block_count.len = 1;
+			c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+			pr_debug("read_block_err_t  %d\n", ret);
+		}
+	}
+
+	return 0;
+}
+
+static int cxd2880_read_status(struct dvb_frontend *fe,
+			       enum fe_status *status)
+{
+	int ret = 0;
+	u8 sync = 0;
+	u8 lock = 0;
+	u8 unlock = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct dtv_frontend_properties *c = NULL;
+
+	if ((!fe) || (!status)) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+	c = &fe->dtv_property_cache;
+	*status = 0;
+
+	if (priv->tnrdmd.state == CXD2880_TNRDMD_STATE_ACTIVE) {
+		mutex_lock(priv->spi_mutex);
+		if (c->delivery_system == SYS_DVBT) {
+			ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(
+							&priv->tnrdmd,
+							&sync,
+							&lock,
+							&unlock);
+		} else if (c->delivery_system == SYS_DVBT2) {
+			ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(
+							&priv->tnrdmd,
+							&sync,
+							&lock,
+							&unlock);
+		} else {
+			pr_err("invlaid system");
+			mutex_unlock(priv->spi_mutex);
+			return -EINVAL;
+		}
+
+		mutex_unlock(priv->spi_mutex);
+		if (ret) {
+			pr_err("failed. sys = %d\n", priv->tnrdmd.sys);
+			return  ret;
+		}
+
+		if (sync == 6) {
+			*status = FE_HAS_SIGNAL |
+				  FE_HAS_CARRIER;
+		}
+		if (lock)
+			*status |= FE_HAS_VITERBI |
+				   FE_HAS_SYNC |
+				   FE_HAS_LOCK;
+	}
+
+	pr_debug("status %d result %d\n", *status, ret);
+
+	cxd2880_get_stats(fe, *status);
+	return  0;
+}
+
+static int cxd2880_tune(struct dvb_frontend *fe,
+			bool retune,
+			unsigned int mode_flags,
+			unsigned int *delay,
+			enum fe_status *status)
+{
+	int ret = 0;
+
+	if ((!fe) || (!delay) || (!status)) {
+		pr_err("invalid arg.");
+		return -EINVAL;
+	}
+
+	if (retune) {
+		ret = cxd2880_set_frontend(fe);
+		if (ret) {
+			pr_err("cxd2880_set_frontend failed %d\n", ret);
+			return ret;
+		}
+	}
+
+	*delay = HZ / 5;
+
+	return cxd2880_read_status(fe, status);
+}
+
+static int cxd2880_get_frontend_t(struct dvb_frontend *fe,
+				  struct dtv_frontend_properties *c)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+	enum cxd2880_dvbt_mode mode = CXD2880_DVBT_MODE_2K;
+	enum cxd2880_dvbt_guard guard = CXD2880_DVBT_GUARD_1_32;
+	struct cxd2880_dvbt_tpsinfo tps;
+	enum cxd2880_tnrdmd_spectrum_sense sense;
+	u16 snr = 0;
+	int strength = 0;
+
+	if ((!fe) || (!c)) {
+		pr_err("invalid arg\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt_mon_mode_guard(&priv->tnrdmd,
+						 &mode, &guard);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (mode) {
+		case CXD2880_DVBT_MODE_2K:
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			break;
+		case CXD2880_DVBT_MODE_8K:
+			c->transmission_mode = TRANSMISSION_MODE_8K;
+			break;
+		default:
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			pr_err("get invalid mode %d\n", mode);
+			break;
+		}
+		switch (guard) {
+		case CXD2880_DVBT_GUARD_1_32:
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case CXD2880_DVBT_GUARD_1_16:
+			c->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case CXD2880_DVBT_GUARD_1_8:
+			c->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case CXD2880_DVBT_GUARD_1_4:
+			c->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		default:
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			pr_err("get invalid guard %d\n", guard);
+			break;
+		}
+	} else {
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		pr_debug("ModeGuard err %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (tps.hierarchy) {
+		case CXD2880_DVBT_HIERARCHY_NON:
+			c->hierarchy = HIERARCHY_NONE;
+			break;
+		case CXD2880_DVBT_HIERARCHY_1:
+			c->hierarchy = HIERARCHY_1;
+			break;
+		case CXD2880_DVBT_HIERARCHY_2:
+			c->hierarchy = HIERARCHY_2;
+			break;
+		case CXD2880_DVBT_HIERARCHY_4:
+			c->hierarchy = HIERARCHY_4;
+			break;
+		default:
+			c->hierarchy = HIERARCHY_NONE;
+			pr_err("TPSInfo hierarchy invalid %d\n",
+			       tps.hierarchy);
+			break;
+		}
+
+		switch (tps.rate_hp) {
+		case CXD2880_DVBT_CODERATE_1_2:
+			c->code_rate_HP = FEC_1_2;
+			break;
+		case CXD2880_DVBT_CODERATE_2_3:
+			c->code_rate_HP = FEC_2_3;
+			break;
+		case CXD2880_DVBT_CODERATE_3_4:
+			c->code_rate_HP = FEC_3_4;
+			break;
+		case CXD2880_DVBT_CODERATE_5_6:
+			c->code_rate_HP = FEC_5_6;
+			break;
+		case CXD2880_DVBT_CODERATE_7_8:
+			c->code_rate_HP = FEC_7_8;
+			break;
+		default:
+			c->code_rate_HP = FEC_NONE;
+			pr_err("TPSInfo rateHP invalid %d\n",
+			       tps.rate_hp);
+			break;
+		}
+		switch (tps.rate_lp) {
+		case CXD2880_DVBT_CODERATE_1_2:
+			c->code_rate_LP = FEC_1_2;
+			break;
+		case CXD2880_DVBT_CODERATE_2_3:
+			c->code_rate_LP = FEC_2_3;
+			break;
+		case CXD2880_DVBT_CODERATE_3_4:
+			c->code_rate_LP = FEC_3_4;
+			break;
+		case CXD2880_DVBT_CODERATE_5_6:
+			c->code_rate_LP = FEC_5_6;
+			break;
+		case CXD2880_DVBT_CODERATE_7_8:
+			c->code_rate_LP = FEC_7_8;
+			break;
+		default:
+			c->code_rate_LP = FEC_NONE;
+			pr_err("TPSInfo rateLP invalid %d\n",
+			       tps.rate_lp);
+			break;
+		}
+		switch (tps.constellation) {
+		case CXD2880_DVBT_CONSTELLATION_QPSK:
+			c->modulation = QPSK;
+			break;
+		case CXD2880_DVBT_CONSTELLATION_16QAM:
+			c->modulation = QAM_16;
+			break;
+		case CXD2880_DVBT_CONSTELLATION_64QAM:
+			c->modulation = QAM_64;
+			break;
+		default:
+			c->modulation = QPSK;
+			pr_err("TPSInfo constellation invalid %d\n",
+			       tps.constellation);
+			break;
+		}
+	} else {
+		c->hierarchy = HIERARCHY_NONE;
+		c->code_rate_HP = FEC_NONE;
+		c->code_rate_LP = FEC_NONE;
+		c->modulation = QPSK;
+		pr_debug("TPS info err %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (sense) {
+		case CXD2880_TNRDMD_SPECTRUM_NORMAL:
+			c->inversion = INVERSION_OFF;
+			break;
+		case CXD2880_TNRDMD_SPECTRUM_INV:
+			c->inversion = INVERSION_ON;
+			break;
+		default:
+			c->inversion = INVERSION_OFF;
+			pr_err("spectrum sense invalid %d\n", sense);
+			break;
+		}
+	} else {
+		c->inversion = INVERSION_OFF;
+		pr_debug("spectrum_sense %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+		c->strength.stat[0].svalue = strength;
+	} else {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		pr_debug("mon_rf_lvl %d\n", ret);
+	}
+
+	ret = cxd2880_read_snr(fe, &snr);
+	if (!ret) {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		c->cnr.stat[0].svalue = snr;
+	} else {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		pr_debug("read_snr %d\n", ret);
+	}
+
+	return 0;
+}
+
+static int cxd2880_get_frontend_t2(struct dvb_frontend *fe,
+				   struct dtv_frontend_properties *c)
+{
+	int ret = 0;
+	struct cxd2880_priv *priv = NULL;
+	struct cxd2880_dvbt2_l1pre l1pre;
+	enum cxd2880_dvbt2_plp_code_rate coderate;
+	enum cxd2880_dvbt2_plp_constell qam;
+	enum cxd2880_tnrdmd_spectrum_sense sense;
+	u16 snr = 0;
+	int strength = 0;
+
+	if ((!fe) || (!c)) {
+		pr_err("invalid arg.\n");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (l1pre.fft_mode) {
+		case CXD2880_DVBT2_M2K:
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			break;
+		case CXD2880_DVBT2_M8K:
+			c->transmission_mode = TRANSMISSION_MODE_8K;
+			break;
+		case CXD2880_DVBT2_M4K:
+			c->transmission_mode = TRANSMISSION_MODE_4K;
+			break;
+		case CXD2880_DVBT2_M1K:
+			c->transmission_mode = TRANSMISSION_MODE_1K;
+			break;
+		case CXD2880_DVBT2_M16K:
+			c->transmission_mode = TRANSMISSION_MODE_16K;
+			break;
+		case CXD2880_DVBT2_M32K:
+			c->transmission_mode = TRANSMISSION_MODE_32K;
+			break;
+		default:
+			c->transmission_mode = TRANSMISSION_MODE_2K;
+			pr_err("L1Pre fft_mode invalid %d\n",
+			       l1pre.fft_mode);
+			break;
+		}
+		switch (l1pre.gi) {
+		case CXD2880_DVBT2_G1_32:
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			break;
+		case CXD2880_DVBT2_G1_16:
+			c->guard_interval = GUARD_INTERVAL_1_16;
+			break;
+		case CXD2880_DVBT2_G1_8:
+			c->guard_interval = GUARD_INTERVAL_1_8;
+			break;
+		case CXD2880_DVBT2_G1_4:
+			c->guard_interval = GUARD_INTERVAL_1_4;
+			break;
+		case CXD2880_DVBT2_G1_128:
+			c->guard_interval = GUARD_INTERVAL_1_128;
+			break;
+		case CXD2880_DVBT2_G19_128:
+			c->guard_interval = GUARD_INTERVAL_19_128;
+			break;
+		case CXD2880_DVBT2_G19_256:
+			c->guard_interval = GUARD_INTERVAL_19_256;
+			break;
+		default:
+			c->guard_interval = GUARD_INTERVAL_1_32;
+			pr_err("L1Pre gi invalid %d\n", l1pre.gi);
+			break;
+		}
+	} else {
+		c->transmission_mode = TRANSMISSION_MODE_2K;
+		c->guard_interval = GUARD_INTERVAL_1_32;
+		pr_debug("L1Pre err %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(&priv->tnrdmd,
+						 CXD2880_DVBT2_PLP_DATA,
+						 &coderate);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (coderate) {
+		case CXD2880_DVBT2_R1_2:
+			c->fec_inner = FEC_1_2;
+			break;
+		case CXD2880_DVBT2_R3_5:
+			c->fec_inner = FEC_3_5;
+			break;
+		case CXD2880_DVBT2_R2_3:
+			c->fec_inner = FEC_2_3;
+			break;
+		case CXD2880_DVBT2_R3_4:
+			c->fec_inner = FEC_3_4;
+			break;
+		case CXD2880_DVBT2_R4_5:
+			c->fec_inner = FEC_4_5;
+			break;
+		case CXD2880_DVBT2_R5_6:
+			c->fec_inner = FEC_5_6;
+			break;
+		default:
+			c->fec_inner = FEC_NONE;
+			pr_err("CodeRate invalid %d\n", coderate);
+			break;
+		}
+	} else {
+		c->fec_inner = FEC_NONE;
+		pr_debug("CodeRate %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt2_mon_qam(&priv->tnrdmd,
+					   CXD2880_DVBT2_PLP_DATA,
+					   &qam);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (qam) {
+		case CXD2880_DVBT2_QPSK:
+			c->modulation = QPSK;
+			break;
+		case CXD2880_DVBT2_QAM16:
+			c->modulation = QAM_16;
+			break;
+		case CXD2880_DVBT2_QAM64:
+			c->modulation = QAM_64;
+			break;
+		case CXD2880_DVBT2_QAM256:
+			c->modulation = QAM_256;
+			break;
+		default:
+			c->modulation = QPSK;
+			pr_err("QAM invalid %d\n", qam);
+			break;
+		}
+	} else {
+		c->modulation = QPSK;
+		pr_debug("QAM %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		switch (sense) {
+		case CXD2880_TNRDMD_SPECTRUM_NORMAL:
+			c->inversion = INVERSION_OFF;
+			break;
+		case CXD2880_TNRDMD_SPECTRUM_INV:
+			c->inversion = INVERSION_ON;
+			break;
+		default:
+			c->inversion = INVERSION_OFF;
+			pr_err("spectrum sense invalid %d\n", sense);
+			break;
+		}
+	} else {
+		c->inversion = INVERSION_OFF;
+		pr_debug("SpectrumSense %d\n", ret);
+	}
+
+	mutex_lock(priv->spi_mutex);
+	ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
+	mutex_unlock(priv->spi_mutex);
+	if (!ret) {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+		c->strength.stat[0].svalue = strength;
+	} else {
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		pr_debug("mon_rf_lvl %d\n", ret);
+	}
+
+	ret = cxd2880_read_snr(fe, &snr);
+	if (!ret) {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		c->cnr.stat[0].svalue = snr;
+	} else {
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		pr_debug("read_snr %d\n", ret);
+	}
+
+	return 0;
+}
+
+static int cxd2880_get_frontend(struct dvb_frontend *fe,
+				struct dtv_frontend_properties *props)
+{
+	struct cxd2880_priv *priv = NULL;
+	int ret = 0;
+
+	if ((!fe) || (!props)) {
+		pr_err("invalid arg.");
+		return -EINVAL;
+	}
+
+	priv = fe->demodulator_priv;
+
+	pr_debug("system=%d\n", fe->dtv_property_cache.delivery_system);
+	switch (fe->dtv_property_cache.delivery_system) {
+	case SYS_DVBT:
+		ret = cxd2880_get_frontend_t(fe, props);
+		break;
+	case SYS_DVBT2:
+		ret = cxd2880_get_frontend_t2(fe, props);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_HW;
+}
+
+static struct dvb_frontend_ops cxd2880_dvbt_t2_ops;
+
+struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
+				    struct cxd2880_config *cfg)
+{
+	int ret = 0;
+	enum cxd2880_tnrdmd_chip_id chipid =
+					CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
+	static struct cxd2880_priv *priv;
+	u8 data = 0;
+
+	if (!fe) {
+		pr_err("invalid arg.\n");
+		return NULL;
+	}
+
+	priv = kzalloc(sizeof(struct cxd2880_priv), GFP_KERNEL);
+	if (!priv)
+		return NULL;
+
+	priv->spi = cfg->spi;
+	priv->spi_mutex = cfg->spi_mutex;
+	priv->spi_device.spi = cfg->spi;
+
+	memcpy(&fe->ops, &cxd2880_dvbt_t2_ops,
+	       sizeof(struct dvb_frontend_ops));
+
+	ret = cxd2880_spi_device_initialize(&priv->spi_device,
+					    CXD2880_SPI_MODE_0,
+					    55000000);
+	if (ret) {
+		pr_err("spi_device_initialize failed. %d\n", ret);
+		kfree(priv);
+		return NULL;
+	}
+
+	ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi,
+					    &priv->spi_device);
+	if (ret) {
+		pr_err("spi_device_create_spi failed. %d\n", ret);
+		kfree(priv);
+		return NULL;
+	}
+
+	ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0);
+	if (ret) {
+		pr_err("io_spi_create failed. %d\n", ret);
+		kfree(priv);
+		return NULL;
+	}
+	ret = priv->regio.write_reg(&priv->regio,
+				    CXD2880_IO_TGT_SYS, 0x00, 0x00);
+	if (ret) {
+		pr_err("set bank to 0x00 failed.\n");
+		kfree(priv);
+		return NULL;
+	}
+	ret = priv->regio.read_regs(&priv->regio,
+				    CXD2880_IO_TGT_SYS, 0xfd, &data, 1);
+	if (ret) {
+		pr_err("read chip id failed.\n");
+		kfree(priv);
+		return NULL;
+	}
+
+	chipid = (enum cxd2880_tnrdmd_chip_id)data;
+	if ((chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) &&
+	    (chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11)) {
+		pr_err("chip id invalid.\n");
+		kfree(priv);
+		return NULL;
+	}
+
+	fe->demodulator_priv = priv;
+	pr_info("CXD2880 driver version: Ver %s\n",
+		CXD2880_TNRDMD_DRIVER_VERSION);
+
+	return fe;
+}
+EXPORT_SYMBOL(cxd2880_attach);
+
+static struct dvb_frontend_ops cxd2880_dvbt_t2_ops = {
+	.info = {
+		.name = "Sony CXD2880",
+		.frequency_min =  174000000,
+		.frequency_max = 862000000,
+		.frequency_stepsize = 1000,
+		.caps = FE_CAN_INVERSION_AUTO |
+				FE_CAN_FEC_1_2 |
+				FE_CAN_FEC_2_3 |
+				FE_CAN_FEC_3_4 |
+				FE_CAN_FEC_4_5 |
+				FE_CAN_FEC_5_6	|
+				FE_CAN_FEC_7_8	|
+				FE_CAN_FEC_AUTO |
+				FE_CAN_QPSK |
+				FE_CAN_QAM_16 |
+				FE_CAN_QAM_32 |
+				FE_CAN_QAM_64 |
+				FE_CAN_QAM_128 |
+				FE_CAN_QAM_256 |
+				FE_CAN_QAM_AUTO |
+				FE_CAN_TRANSMISSION_MODE_AUTO |
+				FE_CAN_GUARD_INTERVAL_AUTO |
+				FE_CAN_2G_MODULATION |
+				FE_CAN_RECOVER |
+				FE_CAN_MUTE_TS,
+	},
+	.delsys = { SYS_DVBT, SYS_DVBT2 },
+
+	.release = cxd2880_release,
+	.init = cxd2880_init,
+	.sleep = cxd2880_sleep,
+	.tune = cxd2880_tune,
+	.set_frontend = cxd2880_set_frontend,
+	.get_frontend = cxd2880_get_frontend,
+	.read_status = cxd2880_read_status,
+	.read_ber = cxd2880_read_ber,
+	.read_signal_strength = cxd2880_read_signal_strength,
+	.read_snr = cxd2880_read_snr,
+	.read_ucblocks = cxd2880_read_ucblocks,
+	.get_frontend_algo = cxd2880_get_frontend_algo,
+};
+
+MODULE_DESCRIPTION(
+"Sony CXD2880 DVB-T2/T tuner + demodulator drvier");
+MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
+MODULE_LICENSE("GPL v2");
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 08/14] [media] cxd2880: Add DVB-T control functions the driver
@ 2017-08-16  4:40   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:40 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

Provide definitions, interfaces and functions needed for DVB-T
of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
      -no change
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
      -modified return code
      -modified coding style of if() 
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
      -modified return code

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h |   91 ++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c    | 1115 ++++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h    |   62 ++
 3 files changed, 1268 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
new file mode 100644
index 000000000000..345c094760d2
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
@@ -0,0 +1,91 @@
+/*
+ * cxd2880_dvbt.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T related definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_DVBT_H
+#define CXD2880_DVBT_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_dvbt_constellation {
+	CXD2880_DVBT_CONSTELLATION_QPSK,
+	CXD2880_DVBT_CONSTELLATION_16QAM,
+	CXD2880_DVBT_CONSTELLATION_64QAM,
+	CXD2880_DVBT_CONSTELLATION_RESERVED_3
+};
+
+enum cxd2880_dvbt_hierarchy {
+	CXD2880_DVBT_HIERARCHY_NON,
+	CXD2880_DVBT_HIERARCHY_1,
+	CXD2880_DVBT_HIERARCHY_2,
+	CXD2880_DVBT_HIERARCHY_4
+};
+
+enum cxd2880_dvbt_coderate {
+	CXD2880_DVBT_CODERATE_1_2,
+	CXD2880_DVBT_CODERATE_2_3,
+	CXD2880_DVBT_CODERATE_3_4,
+	CXD2880_DVBT_CODERATE_5_6,
+	CXD2880_DVBT_CODERATE_7_8,
+	CXD2880_DVBT_CODERATE_RESERVED_5,
+	CXD2880_DVBT_CODERATE_RESERVED_6,
+	CXD2880_DVBT_CODERATE_RESERVED_7
+};
+
+enum cxd2880_dvbt_guard {
+	CXD2880_DVBT_GUARD_1_32,
+	CXD2880_DVBT_GUARD_1_16,
+	CXD2880_DVBT_GUARD_1_8,
+	CXD2880_DVBT_GUARD_1_4
+};
+
+enum cxd2880_dvbt_mode {
+	CXD2880_DVBT_MODE_2K,
+	CXD2880_DVBT_MODE_8K,
+	CXD2880_DVBT_MODE_RESERVED_2,
+	CXD2880_DVBT_MODE_RESERVED_3
+};
+
+enum cxd2880_dvbt_profile {
+	CXD2880_DVBT_PROFILE_HP = 0,
+	CXD2880_DVBT_PROFILE_LP
+};
+
+struct cxd2880_dvbt_tpsinfo {
+	enum cxd2880_dvbt_constellation constellation;
+	enum cxd2880_dvbt_hierarchy hierarchy;
+	enum cxd2880_dvbt_coderate rate_hp;
+	enum cxd2880_dvbt_coderate rate_lp;
+	enum cxd2880_dvbt_guard guard;
+	enum cxd2880_dvbt_mode mode;
+	u8 fnum;
+	u8 length_indicator;
+	u16 cell_id;
+	u8 cell_id_ok;
+	u8 reserved_even;
+	u8 reserved_odd;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
new file mode 100644
index 000000000000..8a16cb359171
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
@@ -0,0 +1,1115 @@
+/*
+ * cxd2880_tnrdmd_dvbt.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control functions for DVB-T
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_tnrdmd_dvbt_mon.h"
+
+static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dtv_bandwidth
+				     bandwidth,
+				     enum cxd2880_tnrdmd_clockmode
+				     clk_mode)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x31, 0x01);
+	if (ret)
+		return ret;
+
+	{
+		u8 data_a[2] = { 0x52, 0x49 };
+		u8 data_b[2] = { 0x5d, 0x55 };
+		u8 data_c[2] = { 0x60, 0x00 };
+		u8 *data = NULL;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x04);
+		if (ret)
+			return ret;
+
+		switch (clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			data = data_a;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			data = data_b;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			data = data_c;
+			break;
+		default:
+			return -EPERM;
+		}
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x65, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x5d, 0x07);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+		u8 data[2] = { 0x01, 0x01 };
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x00);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xce, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x04);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x5c, 0xfb);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xa4, 0x03);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x14);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xb0, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x25);
+	if (ret)
+		return ret;
+
+	{
+		u8 data[2] = { 0x01, 0xf0 };
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xf0, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) ||
+	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x12);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x44, 0x00);
+		if (ret)
+			return ret;
+	}
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x11);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x87, 0xd2);
+		if (ret)
+			return ret;
+	}
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+		u8 data_a[3] = { 0x73, 0xca, 0x49 };
+		u8 data_b[3] = { 0xc8, 0x13, 0xaa };
+		u8 data_c[3] = { 0xdc, 0x6c, 0x00 };
+		u8 *data = NULL;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x04);
+		if (ret)
+			return ret;
+
+		switch (clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			data = data_a;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			data = data_b;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			data = data_c;
+			break;
+		default:
+			return -EPERM;
+		}
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x68, data, 3);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x04);
+	if (ret)
+		return ret;
+
+	switch (bandwidth) {
+	case CXD2880_DTV_BW_8_MHZ:
+
+		{
+			u8 data_ac[5] = { 0x15, 0x00, 0x00, 0x00,
+				0x00
+			};
+			u8 data_b[5] = { 0x14, 0x6a, 0xaa, 0xaa,
+				0xaa
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x60, data, 5);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x00);
+		if (ret)
+			return ret;
+
+		{
+			u8 data_a[2] = { 0x01, 0x28 };
+			u8 data_b[2] = { 0x11, 0x44 };
+			u8 data_c[2] = { 0x15, 0x28 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x7d, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data = 0;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = 0x35;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = 0x34;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x71, data);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[5] = { 0x30, 0x00, 0x00, 0x90,
+				0x00
+			};
+			u8 data_b[5] = { 0x36, 0x71, 0x00, 0xa3,
+				0x55
+			};
+			u8 data_c[5] = { 0x38, 0x00, 0x00, 0xa8,
+				0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x51, &data[2], 3);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data[4] = { 0xb3, 0x00, 0x01, 0x02 };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x72, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x6b, &data[2], 2);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_7_MHZ:
+
+		{
+			u8 data_ac[5] = { 0x18, 0x00, 0x00, 0x00,
+				0x00
+			};
+			u8 data_b[5] = { 0x17, 0x55, 0x55, 0x55,
+				0x55
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x60, data, 5);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x02);
+		if (ret)
+			return ret;
+
+		{
+			u8 data_a[2] = { 0x12, 0x4c };
+			u8 data_b[2] = { 0x1f, 0x15 };
+			u8 data_c[2] = { 0x1f, 0xf8 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x7d, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data = 0;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = 0x2f;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = 0x2e;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x71, data);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[5] = { 0x36, 0xdb, 0x00, 0xa4,
+				0x92
+			};
+			u8 data_b[5] = { 0x3e, 0x38, 0x00, 0xba,
+				0xaa
+			};
+			u8 data_c[5] = { 0x40, 0x00, 0x00, 0xc0,
+				0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x51, &data[2], 3);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data[4] = { 0xb8, 0x00, 0x00, 0x03 };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x72, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x6b, &data[2], 2);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_6_MHZ:
+
+		{
+			u8 data_ac[5] = { 0x1c, 0x00, 0x00, 0x00,
+				0x00
+			};
+			u8 data_b[5] = { 0x1b, 0x38, 0xe3, 0x8e,
+				0x38
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x60, data, 5);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x04);
+		if (ret)
+			return ret;
+
+		{
+			u8 data_a[2] = { 0x1f, 0xf8 };
+			u8 data_b[2] = { 0x24, 0x43 };
+			u8 data_c[2] = { 0x25, 0x4c };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x7d, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data = 0;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = 0x29;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = 0x2a;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x71, data);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[5] = { 0x40, 0x00, 0x00, 0xc0,
+				0x00
+			};
+			u8 data_b[5] = { 0x48, 0x97, 0x00, 0xd9,
+				0xc7
+			};
+			u8 data_c[5] = { 0x4a, 0xaa, 0x00, 0xdf,
+				0xff
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x51, &data[2], 3);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data[4] = { 0xbe, 0xab, 0x00, 0x03 };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x72, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x6b, &data[2], 2);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_5_MHZ:
+
+		{
+			u8 data_ac[5] = { 0x21, 0x99, 0x99, 0x99,
+				0x99
+			};
+			u8 data_b[5] = { 0x20, 0xaa, 0xaa, 0xaa,
+				0xaa
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x60, data, 5);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x06);
+		if (ret)
+			return ret;
+
+		{
+			u8 data_a[2] = { 0x26, 0x5d };
+			u8 data_b[2] = { 0x2b, 0x84 };
+			u8 data_c[2] = { 0x2c, 0xc2 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x7d, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data = 0;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = 0x24;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = 0x23;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x71, data);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[5] = { 0x4c, 0xcc, 0x00, 0xe6,
+				0x66
+			};
+			u8 data_b[5] = { 0x57, 0x1c, 0x01, 0x05,
+				0x55
+			};
+			u8 data_c[5] = { 0x59, 0x99, 0x01, 0x0c,
+				0xcc
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x51, &data[2], 3);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data[4] = { 0xc8, 0x01, 0x00, 0x03 };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x72, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x6b, &data[2], 2);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	default:
+		return -EPERM;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xfd, 0x01);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd
+						   *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x04);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x5c, 0xd8);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xa4, 0x00);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x11);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x87, 0x04);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
+			    enum cxd2880_dvbt_profile profile)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x67,
+				     (profile == CXD2880_DVBT_PROFILE_HP)
+				     ? 0x00 : 0x01);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+			      struct cxd2880_dvbt_tune_param
+			      *tune_param)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT,
+						tune_param->center_freq_khz,
+						tune_param->bandwidth, 0, 0);
+	if (ret)
+		return ret;
+
+	ret =
+	    x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth,
+				      tnr_dmd->clk_mode);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret =
+		    x_tune_dvbt_demod_setting(tnr_dmd->diver_sub,
+					      tune_param->bandwidth,
+					      tnr_dmd->diver_sub->clk_mode);
+		if (ret)
+			return ret;
+	}
+
+	ret = dvbt_set_profile(tnr_dmd, tune_param->profile);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+			      struct cxd2880_dvbt_tune_param
+			      *tune_param)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT,
+						0);
+	if (ret)
+		return ret;
+
+	tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
+	tnr_dmd->frequency_khz = tune_param->center_freq_khz;
+	tnr_dmd->sys = CXD2880_DTV_SYS_DVBT;
+	tnr_dmd->bandwidth = tune_param->bandwidth;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
+		tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
+		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT;
+		tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = x_sleep_dvbt_demod_setting(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
+					 *tnr_dmd,
+					 enum
+					 cxd2880_tnrdmd_lock_result
+					 *lock)
+{
+	int ret = 0;
+
+	u8 sync_stat = 0;
+	u8 ts_lock = 0;
+	u8 unlock_detected = 0;
+	u8 unlock_detected_sub = 0;
+
+	if ((!tnr_dmd) || (!lock))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+					      &unlock_detected);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (sync_stat == 6)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		else if (unlock_detected)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+		else
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+		return ret;
+	}
+
+	if (sync_stat == 6) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		return ret;
+	}
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+						  &unlock_detected_sub);
+	if (ret)
+		return ret;
+
+	if (sync_stat == 6)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+	else if (unlock_detected && unlock_detected_sub)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+	else
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
+				      *tnr_dmd,
+				      enum
+				      cxd2880_tnrdmd_lock_result
+				      *lock)
+{
+	int ret = 0;
+
+	u8 sync_stat = 0;
+	u8 ts_lock = 0;
+	u8 unlock_detected = 0;
+	u8 unlock_detected_sub = 0;
+
+	if ((!tnr_dmd) || (!lock))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+					      &unlock_detected);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (ts_lock)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		else if (unlock_detected)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+		else
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+		return ret;
+	}
+
+	if (ts_lock) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		return ret;
+	} else if (!unlock_detected) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+		return ret;
+	}
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+						  &unlock_detected_sub);
+	if (ret)
+		return ret;
+
+	if (unlock_detected && unlock_detected_sub)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+	else
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
new file mode 100644
index 000000000000..f0a36040da3b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
@@ -0,0 +1,62 @@
+/*
+ * cxd2880_tnrdmd_dvbt.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control interface for DVB-T
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT_H
+#define CXD2880_TNRDMD_DVBT_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+
+struct cxd2880_dvbt_tune_param {
+	u32 center_freq_khz;
+	enum cxd2880_dtv_bandwidth bandwidth;
+	enum cxd2880_dvbt_profile profile;
+};
+
+int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+			      struct cxd2880_dvbt_tune_param
+			      *tune_param);
+
+int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+			      struct cxd2880_dvbt_tune_param
+			      *tune_param);
+
+int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd
+				      *tnr_dmd);
+
+int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
+					 *tnr_dmd,
+					 enum
+					 cxd2880_tnrdmd_lock_result
+					 *lock);
+
+int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
+				      *tnr_dmd,
+				      enum
+				      cxd2880_tnrdmd_lock_result
+				      *lock);
+
+#endif
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 08/14] [media] cxd2880: Add DVB-T control functions the driver
@ 2017-08-16  4:40   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-08-16  4:40 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

Provide definitions, interfaces and functions needed for DVB-T
of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
      -no change
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
      -modified return code
      -modified coding style of if() 
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
      -modified return code

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h |   91 ++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c    | 1115 ++++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h    |   62 ++
 3 files changed, 1268 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
new file mode 100644
index 000000000000..345c094760d2
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
@@ -0,0 +1,91 @@
+/*
+ * cxd2880_dvbt.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T related definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_DVBT_H
+#define CXD2880_DVBT_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_dvbt_constellation {
+	CXD2880_DVBT_CONSTELLATION_QPSK,
+	CXD2880_DVBT_CONSTELLATION_16QAM,
+	CXD2880_DVBT_CONSTELLATION_64QAM,
+	CXD2880_DVBT_CONSTELLATION_RESERVED_3
+};
+
+enum cxd2880_dvbt_hierarchy {
+	CXD2880_DVBT_HIERARCHY_NON,
+	CXD2880_DVBT_HIERARCHY_1,
+	CXD2880_DVBT_HIERARCHY_2,
+	CXD2880_DVBT_HIERARCHY_4
+};
+
+enum cxd2880_dvbt_coderate {
+	CXD2880_DVBT_CODERATE_1_2,
+	CXD2880_DVBT_CODERATE_2_3,
+	CXD2880_DVBT_CODERATE_3_4,
+	CXD2880_DVBT_CODERATE_5_6,
+	CXD2880_DVBT_CODERATE_7_8,
+	CXD2880_DVBT_CODERATE_RESERVED_5,
+	CXD2880_DVBT_CODERATE_RESERVED_6,
+	CXD2880_DVBT_CODERATE_RESERVED_7
+};
+
+enum cxd2880_dvbt_guard {
+	CXD2880_DVBT_GUARD_1_32,
+	CXD2880_DVBT_GUARD_1_16,
+	CXD2880_DVBT_GUARD_1_8,
+	CXD2880_DVBT_GUARD_1_4
+};
+
+enum cxd2880_dvbt_mode {
+	CXD2880_DVBT_MODE_2K,
+	CXD2880_DVBT_MODE_8K,
+	CXD2880_DVBT_MODE_RESERVED_2,
+	CXD2880_DVBT_MODE_RESERVED_3
+};
+
+enum cxd2880_dvbt_profile {
+	CXD2880_DVBT_PROFILE_HP = 0,
+	CXD2880_DVBT_PROFILE_LP
+};
+
+struct cxd2880_dvbt_tpsinfo {
+	enum cxd2880_dvbt_constellation constellation;
+	enum cxd2880_dvbt_hierarchy hierarchy;
+	enum cxd2880_dvbt_coderate rate_hp;
+	enum cxd2880_dvbt_coderate rate_lp;
+	enum cxd2880_dvbt_guard guard;
+	enum cxd2880_dvbt_mode mode;
+	u8 fnum;
+	u8 length_indicator;
+	u16 cell_id;
+	u8 cell_id_ok;
+	u8 reserved_even;
+	u8 reserved_odd;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
new file mode 100644
index 000000000000..8a16cb359171
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
@@ -0,0 +1,1115 @@
+/*
+ * cxd2880_tnrdmd_dvbt.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control functions for DVB-T
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_tnrdmd_dvbt_mon.h"
+
+static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dtv_bandwidth
+				     bandwidth,
+				     enum cxd2880_tnrdmd_clockmode
+				     clk_mode)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x31, 0x01);
+	if (ret)
+		return ret;
+
+	{
+		u8 data_a[2] = { 0x52, 0x49 };
+		u8 data_b[2] = { 0x5d, 0x55 };
+		u8 data_c[2] = { 0x60, 0x00 };
+		u8 *data = NULL;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x04);
+		if (ret)
+			return ret;
+
+		switch (clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			data = data_a;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			data = data_b;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			data = data_c;
+			break;
+		default:
+			return -EPERM;
+		}
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x65, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x5d, 0x07);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+		u8 data[2] = { 0x01, 0x01 };
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x00);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xce, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x04);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x5c, 0xfb);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xa4, 0x03);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x14);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xb0, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x25);
+	if (ret)
+		return ret;
+
+	{
+		u8 data[2] = { 0x01, 0xf0 };
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xf0, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) ||
+	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x12);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x44, 0x00);
+		if (ret)
+			return ret;
+	}
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x11);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x87, 0xd2);
+		if (ret)
+			return ret;
+	}
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+		u8 data_a[3] = { 0x73, 0xca, 0x49 };
+		u8 data_b[3] = { 0xc8, 0x13, 0xaa };
+		u8 data_c[3] = { 0xdc, 0x6c, 0x00 };
+		u8 *data = NULL;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x04);
+		if (ret)
+			return ret;
+
+		switch (clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			data = data_a;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			data = data_b;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			data = data_c;
+			break;
+		default:
+			return -EPERM;
+		}
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x68, data, 3);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x04);
+	if (ret)
+		return ret;
+
+	switch (bandwidth) {
+	case CXD2880_DTV_BW_8_MHZ:
+
+		{
+			u8 data_ac[5] = { 0x15, 0x00, 0x00, 0x00,
+				0x00
+			};
+			u8 data_b[5] = { 0x14, 0x6a, 0xaa, 0xaa,
+				0xaa
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x60, data, 5);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x00);
+		if (ret)
+			return ret;
+
+		{
+			u8 data_a[2] = { 0x01, 0x28 };
+			u8 data_b[2] = { 0x11, 0x44 };
+			u8 data_c[2] = { 0x15, 0x28 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x7d, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data = 0;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = 0x35;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = 0x34;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x71, data);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[5] = { 0x30, 0x00, 0x00, 0x90,
+				0x00
+			};
+			u8 data_b[5] = { 0x36, 0x71, 0x00, 0xa3,
+				0x55
+			};
+			u8 data_c[5] = { 0x38, 0x00, 0x00, 0xa8,
+				0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x51, &data[2], 3);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data[4] = { 0xb3, 0x00, 0x01, 0x02 };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x72, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x6b, &data[2], 2);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_7_MHZ:
+
+		{
+			u8 data_ac[5] = { 0x18, 0x00, 0x00, 0x00,
+				0x00
+			};
+			u8 data_b[5] = { 0x17, 0x55, 0x55, 0x55,
+				0x55
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x60, data, 5);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x02);
+		if (ret)
+			return ret;
+
+		{
+			u8 data_a[2] = { 0x12, 0x4c };
+			u8 data_b[2] = { 0x1f, 0x15 };
+			u8 data_c[2] = { 0x1f, 0xf8 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x7d, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data = 0;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = 0x2f;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = 0x2e;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x71, data);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[5] = { 0x36, 0xdb, 0x00, 0xa4,
+				0x92
+			};
+			u8 data_b[5] = { 0x3e, 0x38, 0x00, 0xba,
+				0xaa
+			};
+			u8 data_c[5] = { 0x40, 0x00, 0x00, 0xc0,
+				0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x51, &data[2], 3);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data[4] = { 0xb8, 0x00, 0x00, 0x03 };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x72, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x6b, &data[2], 2);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_6_MHZ:
+
+		{
+			u8 data_ac[5] = { 0x1c, 0x00, 0x00, 0x00,
+				0x00
+			};
+			u8 data_b[5] = { 0x1b, 0x38, 0xe3, 0x8e,
+				0x38
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x60, data, 5);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x04);
+		if (ret)
+			return ret;
+
+		{
+			u8 data_a[2] = { 0x1f, 0xf8 };
+			u8 data_b[2] = { 0x24, 0x43 };
+			u8 data_c[2] = { 0x25, 0x4c };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x7d, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data = 0;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = 0x29;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = 0x2a;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x71, data);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[5] = { 0x40, 0x00, 0x00, 0xc0,
+				0x00
+			};
+			u8 data_b[5] = { 0x48, 0x97, 0x00, 0xd9,
+				0xc7
+			};
+			u8 data_c[5] = { 0x4a, 0xaa, 0x00, 0xdf,
+				0xff
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x51, &data[2], 3);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data[4] = { 0xbe, 0xab, 0x00, 0x03 };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x72, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x6b, &data[2], 2);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_5_MHZ:
+
+		{
+			u8 data_ac[5] = { 0x21, 0x99, 0x99, 0x99,
+				0x99
+			};
+			u8 data_b[5] = { 0x20, 0xaa, 0xaa, 0xaa,
+				0xaa
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x60, data, 5);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x06);
+		if (ret)
+			return ret;
+
+		{
+			u8 data_a[2] = { 0x26, 0x5d };
+			u8 data_b[2] = { 0x2b, 0x84 };
+			u8 data_c[2] = { 0x2c, 0xc2 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x7d, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data = 0;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = 0x24;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = 0x23;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x71, data);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[5] = { 0x4c, 0xcc, 0x00, 0xe6,
+				0x66
+			};
+			u8 data_b[5] = { 0x57, 0x1c, 0x01, 0x05,
+				0x55
+			};
+			u8 data_c[5] = { 0x59, 0x99, 0x01, 0x0c,
+				0xcc
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x51, &data[2], 3);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data[4] = { 0xc8, 0x01, 0x00, 0x03 };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x72, &data[0], 2);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x6b, &data[2], 2);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	default:
+		return -EPERM;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xfd, 0x01);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd
+						   *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x04);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x5c, 0xd8);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xa4, 0x00);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x11);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x87, 0x04);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
+			    enum cxd2880_dvbt_profile profile)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x67,
+				     (profile == CXD2880_DVBT_PROFILE_HP)
+				     ? 0x00 : 0x01);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+			      struct cxd2880_dvbt_tune_param
+			      *tune_param)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT,
+						tune_param->center_freq_khz,
+						tune_param->bandwidth, 0, 0);
+	if (ret)
+		return ret;
+
+	ret =
+	    x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth,
+				      tnr_dmd->clk_mode);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret =
+		    x_tune_dvbt_demod_setting(tnr_dmd->diver_sub,
+					      tune_param->bandwidth,
+					      tnr_dmd->diver_sub->clk_mode);
+		if (ret)
+			return ret;
+	}
+
+	ret = dvbt_set_profile(tnr_dmd, tune_param->profile);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+			      struct cxd2880_dvbt_tune_param
+			      *tune_param)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT,
+						0);
+	if (ret)
+		return ret;
+
+	tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
+	tnr_dmd->frequency_khz = tune_param->center_freq_khz;
+	tnr_dmd->sys = CXD2880_DTV_SYS_DVBT;
+	tnr_dmd->bandwidth = tune_param->bandwidth;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
+		tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
+		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT;
+		tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = x_sleep_dvbt_demod_setting(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
+					 *tnr_dmd,
+					 enum
+					 cxd2880_tnrdmd_lock_result
+					 *lock)
+{
+	int ret = 0;
+
+	u8 sync_stat = 0;
+	u8 ts_lock = 0;
+	u8 unlock_detected = 0;
+	u8 unlock_detected_sub = 0;
+
+	if ((!tnr_dmd) || (!lock))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+					      &unlock_detected);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (sync_stat == 6)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		else if (unlock_detected)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+		else
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+		return ret;
+	}
+
+	if (sync_stat == 6) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		return ret;
+	}
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+						  &unlock_detected_sub);
+	if (ret)
+		return ret;
+
+	if (sync_stat == 6)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+	else if (unlock_detected && unlock_detected_sub)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+	else
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
+				      *tnr_dmd,
+				      enum
+				      cxd2880_tnrdmd_lock_result
+				      *lock)
+{
+	int ret = 0;
+
+	u8 sync_stat = 0;
+	u8 ts_lock = 0;
+	u8 unlock_detected = 0;
+	u8 unlock_detected_sub = 0;
+
+	if ((!tnr_dmd) || (!lock))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+					      &unlock_detected);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (ts_lock)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		else if (unlock_detected)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+		else
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+		return ret;
+	}
+
+	if (ts_lock) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		return ret;
+	} else if (!unlock_detected) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+		return ret;
+	}
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+						  &unlock_detected_sub);
+	if (ret)
+		return ret;
+
+	if (unlock_detected && unlock_detected_sub)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+	else
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
new file mode 100644
index 000000000000..f0a36040da3b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
@@ -0,0 +1,62 @@
+/*
+ * cxd2880_tnrdmd_dvbt.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control interface for DVB-T
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT_H
+#define CXD2880_TNRDMD_DVBT_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+
+struct cxd2880_dvbt_tune_param {
+	u32 center_freq_khz;
+	enum cxd2880_dtv_bandwidth bandwidth;
+	enum cxd2880_dvbt_profile profile;
+};
+
+int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+			      struct cxd2880_dvbt_tune_param
+			      *tune_param);
+
+int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+			      struct cxd2880_dvbt_tune_param
+			      *tune_param);
+
+int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd
+				      *tnr_dmd);
+
+int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
+					 *tnr_dmd,
+					 enum
+					 cxd2880_tnrdmd_lock_result
+					 *lock);
+
+int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
+				      *tnr_dmd,
+				      enum
+				      cxd2880_tnrdmd_lock_result
+				      *lock);
+
+#endif
-- 
2.13.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 09/14] [media] cxd2880: Add DVB-T monitor and integration layer functions
@ 2017-08-16  4:41   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:41 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

Provide monitor and integration layer functions (DVB-T)
for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
      -changed CXD2880_SLEEP to usleep_range
      -chnaged cxd2880_atomic_set to atomic_set
      -modified return code
      -modified coding style of if() 
   drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
      -modified return code
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
      -removed unnecessary cast
      -changed cxd2880_math_log to intlog10
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
      -modified return code

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.c     |  198 ++++
 .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.h     |   58 +
 .../cxd2880/cxd2880_tnrdmd_dvbt_mon.c              | 1227 ++++++++++++++++++++
 .../cxd2880/cxd2880_tnrdmd_dvbt_mon.h              |  106 ++
 4 files changed, 1589 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
new file mode 100644
index 000000000000..729cb0939203
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
@@ -0,0 +1,198 @@
+/*
+ * cxd2880_integ_dvbt.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer functions for DVB-T
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_integ_dvbt.h"
+
+static int dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd,
+			    struct cxd2880_dvbt_tune_param
+			    *tune_param)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	atomic_set(&tnr_dmd->cancel, 0);
+
+	if ((tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ)) {
+		return -EOPNOTSUPP;
+	}
+
+	ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param);
+	if (ret)
+		return ret;
+
+	usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000,
+		     CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000);
+
+	ret = cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param);
+	if (ret)
+		return ret;
+
+	ret = dvbt_wait_demod_lock(tnr_dmd);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+	enum cxd2880_tnrdmd_lock_result lock =
+	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	unsigned int elapsed = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret)
+		return ret;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret)
+			return ret;
+
+		if (elapsed >= CXD2880_DVBT_WAIT_TS_LOCK)
+			continue_wait = 0;
+
+		ret = cxd2880_tnrdmd_dvbt_check_ts_lock(tnr_dmd, &lock);
+		if (ret)
+			return ret;
+
+		switch (lock) {
+		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
+			return 0;
+
+		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
+			return -EAGAIN;
+
+		default:
+			break;
+		}
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT_WAIT_LOCK_INTVL);
+			if (ret)
+				return ret;
+		} else {
+			ret = -ETIME;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+	enum cxd2880_tnrdmd_lock_result lock =
+	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	unsigned int elapsed = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret)
+		return ret;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret)
+			return ret;
+
+		if (elapsed >= CXD2880_DVBT_WAIT_DMD_LOCK)
+			continue_wait = 0;
+
+		ret = cxd2880_tnrdmd_dvbt_check_demod_lock(tnr_dmd, &lock);
+		if (ret)
+			return ret;
+
+		switch (lock) {
+		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
+			return 0;
+
+		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
+			return -EAGAIN;
+
+		default:
+			break;
+		}
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT_WAIT_LOCK_INTVL);
+			if (ret)
+				return ret;
+		} else {
+			ret = -ETIME;
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
new file mode 100644
index 000000000000..07f9b71a3006
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
@@ -0,0 +1,58 @@
+/*
+ * cxd2880_integ_dvbt.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer interface for DVB-T
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_INTEG_DVBT_H
+#define CXD2880_INTEG_DVBT_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_integ.h"
+
+#define CXD2880_DVBT_WAIT_DMD_LOCK	1000
+#define CXD2880_DVBT_WAIT_TS_LOCK	1000
+#define CXD2880_DVBT_WAIT_LOCK_INTVL	10
+
+struct cxd2880_integ_dvbt_scan_param {
+	u32 start_frequency_khz;
+	u32 end_frequency_khz;
+	u32 step_frequency_khz;
+	enum cxd2880_dtv_bandwidth bandwidth;
+};
+
+struct cxd2880_integ_dvbt_scan_result {
+	u32 center_freq_khz;
+	int tune_result;
+	struct cxd2880_dvbt_tune_param dvbt_tune_param;
+};
+
+int cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd,
+			    struct cxd2880_dvbt_tune_param
+			    *tune_param);
+
+int cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd
+				    *tnr_dmd);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
new file mode 100644
index 000000000000..37396a071727
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
@@ -0,0 +1,1227 @@
+/*
+ * cxd2880_tnrdmd_dvbt_mon.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T monitor functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_tnrdmd_dvbt_mon.h"
+
+#include "dvb_math.h"
+
+static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
+				      *tnr_dmd, u8 *sync_stat,
+				      u8 *ts_lock_stat,
+				      u8 *unlock_detected)
+{
+	u8 rdata = 0x00;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, &rdata, 1);
+	if (ret)
+		return ret;
+
+	*unlock_detected = (rdata & 0x10) ? 1 : 0;
+	*sync_stat = rdata & 0x07;
+	*ts_lock_stat = (rdata & 0x20) ? 1 : 0;
+
+	if (*sync_stat == 0x07)
+		return -EBUSY;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
+					  *tnr_dmd, u8 *sync_stat,
+					  u8 *unlock_detected)
+{
+	u8 ts_lock_stat = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub, sync_stat,
+					      &ts_lock_stat, unlock_detected);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
+				       *tnr_dmd,
+				       enum cxd2880_dvbt_mode
+				       *mode,
+				       enum cxd2880_dvbt_guard
+				       *guard)
+{
+	u8 rdata = 0x00;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!mode) || (!guard))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+			ret =
+			    cxd2880_tnrdmd_dvbt_mon_mode_guard(
+					tnr_dmd->diver_sub, mode, guard);
+
+		return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x1b, &rdata, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03);
+	*guard = (enum cxd2880_dvbt_guard)(rdata & 0x03);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
+					   *tnr_dmd, int *offset)
+{
+	u8 rdata[4];
+	u32 ctl_val = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!offset))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x1d, rdata, 4);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	ctl_val =
+	    ((rdata[0] & 0x1f) << 24) | (rdata[1] << 16) | (rdata[2] << 8) |
+	    (rdata[3]);
+	*offset = cxd2880_convert2s_complement(ctl_val, 29);
+	*offset = -1 * ((*offset) * tnr_dmd->bandwidth / 235);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
+					       cxd2880_tnrdmd
+					       *tnr_dmd,
+					       int *offset)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!offset))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub, offset);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd
+					   *tnr_dmd, u32 *ber)
+{
+	u8 rdata[2];
+	u32 bit_error = 0;
+	u32 period = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ber))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x10);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x39, rdata, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if ((rdata[0] & 0x01) == 0) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return -EBUSY;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x22, rdata, 2);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	bit_error = (rdata[0] << 8) | rdata[1];
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x6f, rdata, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	period = ((rdata[0] & 0x07) == 0) ? 256 : (0x1000 << (rdata[0] & 0x07));
+
+	if ((period == 0) || (bit_error > period))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		div = period / 128;
+
+		Q = (bit_error * 3125) / div;
+		R = (bit_error * 3125) % div;
+
+		R *= 25;
+		Q = Q * 25 + R / div;
+		R = R % div;
+
+		if (div / 2 <= R)
+			*ber = Q + 1;
+		else
+			*ber = Q;
+	}
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd
+				      *tnr_dmd, u32 *ber)
+{
+	u8 rdata[3];
+	u32 bit_error = 0;
+	u32 period_exp = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ber))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x15, rdata, 3);
+	if (ret)
+		return ret;
+
+	if ((rdata[0] & 0x40) == 0)
+		return -EBUSY;
+
+	bit_error = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2];
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x60, rdata, 1);
+	if (ret)
+		return ret;
+
+	period_exp = (rdata[0] & 0x1f);
+
+	if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		if (period_exp <= 8)
+			div = (1U << period_exp) * 51;
+		else
+			div = (1U << 8) * 51;
+
+		Q = (bit_error * 250) / div;
+		R = (bit_error * 250) % div;
+
+		R *= 1250;
+		Q = Q * 1250 + R / div;
+		R = R % div;
+
+		if (period_exp > 8) {
+			*ber =
+			    (Q + (1 << (period_exp - 9))) >> (period_exp - 8);
+		} else {
+			if (div / 2 <= R)
+				*ber = Q + 1;
+			else
+				*ber = Q;
+		}
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     struct cxd2880_dvbt_tpsinfo
+				     *info)
+{
+	u8 rdata[7];
+	u8 cell_id_ok = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!info))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+			ret =
+			    cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd->diver_sub,
+							     info);
+
+		return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x29, rdata, 7);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x11);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xd5, &cell_id_ok, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	info->constellation =
+	    (enum cxd2880_dvbt_constellation)((rdata[0] >> 6) & 0x03);
+	info->hierarchy = (enum cxd2880_dvbt_hierarchy)((rdata[0] >> 3) & 0x07);
+	info->rate_hp = (enum cxd2880_dvbt_coderate)(rdata[0] & 0x07);
+	info->rate_lp = (enum cxd2880_dvbt_coderate)((rdata[1] >> 5) & 0x07);
+	info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03);
+	info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03);
+	info->fnum = (rdata[2] >> 6) & 0x03;
+	info->length_indicator = rdata[2] & 0x3f;
+	info->cell_id = (rdata[3] << 8) | rdata[4];
+	info->reserved_even = rdata[5] & 0x3f;
+	info->reserved_odd = rdata[6] & 0x3f;
+
+	info->cell_id_ok = cell_id_ok & 0x01;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
+						cxd2880_tnrdmd
+						*tnr_dmd,
+						u32 *pen)
+{
+	u8 rdata[3];
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!pen))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x26, rdata, 3);
+	if (ret)
+		return ret;
+
+	if (!(rdata[0] & 0x01))
+		return -EBUSY;
+
+	*pen = (rdata[1] << 8) | rdata[2];
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
+					   *tnr_dmd,
+					    enum
+					    cxd2880_tnrdmd_spectrum_sense
+					    *sense)
+{
+	u8 data = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!sense))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+			ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(
+					tnr_dmd->diver_sub, sense);
+
+		return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x1c, &data, sizeof(data));
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*sense =
+	    (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
+	    CXD2880_TNRDMD_SPECTRUM_NORMAL;
+
+	return ret;
+}
+
+static int dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
+			     u16 *reg_value)
+{
+	u8 rdata[2];
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!reg_value))
+		return -EINVAL;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x13, rdata, 2);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*reg_value = (rdata[0] << 8) | rdata[1];
+
+	return ret;
+}
+
+static int dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
+			 u32 reg_value, int *snr)
+{
+	if ((!tnr_dmd) || (!snr))
+		return -EINVAL;
+
+	if (reg_value == 0)
+		return -EBUSY;
+
+	if (reg_value > 4996)
+		reg_value = 4996;
+
+	*snr = intlog10(reg_value) - intlog10(5350 - reg_value);
+	*snr = (*snr + 839) / 1678 + 28500;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+				int *snr)
+{
+	u16 reg_value = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!snr))
+		return -EINVAL;
+
+	*snr = -1000 * 1000;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
+		if (ret)
+			return ret;
+
+		ret = dvbt_calc_snr(tnr_dmd, reg_value, snr);
+		if (ret)
+			return ret;
+	} else {
+		int snr_main = 0;
+		int snr_sub = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main,
+						      &snr_sub);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
+				      *tnr_dmd, int *snr,
+				      int *snr_main, int *snr_sub)
+{
+	u16 reg_value = 0;
+	u32 reg_value_sum = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub))
+		return -EINVAL;
+
+	*snr = -1000 * 1000;
+	*snr_main = -1000 * 1000;
+	*snr_sub = -1000 * 1000;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
+	if (!ret) {
+		ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main);
+		if (ret)
+			reg_value = 0;
+	} else if (ret == -EBUSY) {
+		reg_value = 0;
+	} else {
+		return ret;
+	}
+
+	reg_value_sum += reg_value;
+
+	ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
+	if (!ret) {
+		ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
+		if (ret)
+			reg_value = 0;
+	} else if (ret == -EBUSY) {
+		reg_value = 0;
+	} else {
+		return ret;
+	}
+
+	reg_value_sum += reg_value;
+
+	ret = dvbt_calc_snr(tnr_dmd, reg_value_sum, snr);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
+					    *tnr_dmd, int *ppm)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ppm))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	{
+		u8 ctl_val_reg[5];
+		u8 nominal_rate_reg[5];
+		u32 trl_ctl_val = 0;
+		u32 trcg_nominal_rate = 0;
+		int num;
+		int den;
+		s8 diff_upper = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret = is_tps_locked(tnr_dmd);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0d);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x21, ctl_val_reg,
+					     sizeof(ctl_val_reg));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x04);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x60, nominal_rate_reg,
+					     sizeof(nominal_rate_reg));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		diff_upper =
+		    (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
+
+		if ((diff_upper < -1) || (diff_upper > 1))
+			return -EBUSY;
+
+		trl_ctl_val = ctl_val_reg[1] << 24;
+		trl_ctl_val |= ctl_val_reg[2] << 16;
+		trl_ctl_val |= ctl_val_reg[3] << 8;
+		trl_ctl_val |= ctl_val_reg[4];
+
+		trcg_nominal_rate = nominal_rate_reg[1] << 24;
+		trcg_nominal_rate |= nominal_rate_reg[2] << 16;
+		trcg_nominal_rate |= nominal_rate_reg[3] << 8;
+		trcg_nominal_rate |= nominal_rate_reg[4];
+
+		trl_ctl_val >>= 1;
+		trcg_nominal_rate >>= 1;
+
+		if (diff_upper == 1)
+			num =
+			    (int)((trl_ctl_val + 0x80000000u) -
+				  trcg_nominal_rate);
+		else if (diff_upper == -1)
+			num =
+			    -(int)((trcg_nominal_rate + 0x80000000u) -
+				   trl_ctl_val);
+		else
+			num = (int)(trl_ctl_val - trcg_nominal_rate);
+
+		den = (nominal_rate_reg[0] & 0x7f) << 24;
+		den |= nominal_rate_reg[1] << 16;
+		den |= nominal_rate_reg[2] << 8;
+		den |= nominal_rate_reg[3];
+		den = (den + (390625 / 2)) / 390625;
+
+		den >>= 1;
+
+		if (num >= 0)
+			*ppm = (num + (den / 2)) / den;
+		else
+			*ppm = (num - (den / 2)) / den;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
+						cxd2880_tnrdmd
+						*tnr_dmd, int *ppm)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ppm))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd,
+				    u8 *quality)
+{
+	struct cxd2880_dvbt_tpsinfo tps;
+	enum cxd2880_dvbt_profile profile = CXD2880_DVBT_PROFILE_HP;
+	u32 ber = 0;
+	int sn = 0;
+	int sn_rel = 0;
+	int ber_sqi = 0;
+
+	static const int nordig_non_hdvbt_db_1000[3][5] = {
+		{5100, 6900, 7900, 8900, 9700},
+		{10800, 13100, 14600, 15600, 16000},
+		{16500, 18700, 20200, 21600, 22500}
+	};
+
+	static const int nordig_hier_hp_dvbt_db_1000[3][2][5] = {
+		{
+		 {9100, 12000, 13600, 15000, 16600},
+		 {10900, 14100, 15700, 19400, 20600}
+		 },
+		{
+		 {6800, 9100, 10400, 11900, 12700},
+		 {8500, 11000, 12800, 15000, 16000}
+		 },
+		{
+		 {5800, 7900, 9100, 10300, 12100},
+		 {8000, 9300, 11600, 13000, 12900}
+		}
+	};
+
+	static const int nordig_hier_lp_dvbt_db_1000[3][2][5] = {
+		{
+		 {12500, 14300, 15300, 16300, 16900},
+		 {16700, 19100, 20900, 22500, 23700}
+		 },
+		{
+		 {15000, 17200, 18400, 19100, 20100},
+		 {18500, 21200, 23600, 24700, 25900}
+		 },
+		{
+		 {19500, 21400, 22500, 23700, 24700},
+		 {21900, 24200, 25600, 26900, 27800}
+		}
+	};
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!quality))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
+	if (ret)
+		return ret;
+
+	if (tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) {
+		u8 data = 0;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x10);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x67, &data, 1);
+		if (ret)
+			return ret;
+
+		profile =
+		    ((data & 0x01) ==
+		     0x01) ? CXD2880_DVBT_PROFILE_LP : CXD2880_DVBT_PROFILE_HP;
+	}
+
+	ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(tnr_dmd, &ber);
+	if (ret)
+		return ret;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_snr(tnr_dmd, &sn);
+	if (ret)
+		return ret;
+
+	if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) ||
+	    (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5) ||
+	    (tps.rate_lp >= CXD2880_DVBT_CODERATE_RESERVED_5) ||
+	    (tps.hierarchy > CXD2880_DVBT_HIERARCHY_4)) {
+		return -EPERM;
+	}
+
+	if ((tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) &&
+	    (tps.constellation == CXD2880_DVBT_CONSTELLATION_QPSK))
+		return -EPERM;
+
+	if (tps.hierarchy == CXD2880_DVBT_HIERARCHY_NON)
+		sn_rel =
+		    sn -
+		    nordig_non_hdvbt_db_1000[tps.constellation][tps.rate_hp];
+	else if (profile == CXD2880_DVBT_PROFILE_LP)
+		sn_rel =
+		    sn - nordig_hier_lp_dvbt_db_1000[tps.hierarchy - 1]
+						    [tps.constellation - 1]
+						    [tps.rate_lp];
+	else
+		sn_rel =
+		    sn - nordig_hier_hp_dvbt_db_1000[tps.hierarchy - 1]
+						    [tps.constellation - 1]
+						    [tps.rate_hp];
+
+	if (ber > 10000) {
+		ber_sqi = 0;
+	} else if (ber > 1) {
+		ber_sqi = (int)((intlog10(ber) + 8388) / 16777);
+		ber_sqi = 20 * (7 * 1000 - (ber_sqi)) - 40 * 1000;
+	} else {
+		ber_sqi = 100 * 1000;
+	}
+
+	if (sn_rel < -7 * 1000) {
+		*quality = 0;
+	} else if (sn_rel < 3 * 1000) {
+		int tmp_sqi = (((sn_rel - (3 * 1000)) / 10) + 1000);
+		*quality =
+		    (u8)(((tmp_sqi * ber_sqi) +
+			   (1000000 / 2)) / (1000000)) & 0xff;
+	} else {
+		*quality = (u8)((ber_sqi + 500) / 1000);
+	}
+
+	if (*quality > 100)
+		*quality = 100;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
+				u32 *per)
+{
+	u32 packet_error = 0;
+	u32 period = 0;
+	u8 rdata[3];
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!per))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x18, rdata, 3);
+	if (ret)
+		return ret;
+
+	if ((rdata[0] & 0x01) == 0)
+		return -EBUSY;
+
+	packet_error = (rdata[1] << 8) | rdata[2];
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x5c, rdata, 1);
+	if (ret)
+		return ret;
+
+	period = 1U << (rdata[0] & 0x0f);
+
+	if ((period == 0) || (packet_error > period))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		div = period;
+
+		Q = (packet_error * 1000) / div;
+		R = (packet_error * 1000) % div;
+
+		R *= 1000;
+		Q = Q * 1000 + R / div;
+		R = R % div;
+
+		if ((div != 1) && (div / 2 <= R))
+			*per = Q + 1;
+		else
+			*per = Q;
+	}
+
+	return ret;
+}
+
+static int dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+			 int rf_lvl, u8 *ssi)
+{
+	struct cxd2880_dvbt_tpsinfo tps;
+	int prel;
+	int temp_ssi = 0;
+	int ret = 0;
+
+	static const int ref_dbm_1000[3][5] = {
+		{-93000, -91000, -90000, -89000, -88000},
+		{-87000, -85000, -84000, -83000, -82000},
+		{-82000, -80000, -78000, -77000, -76000},
+	};
+
+	if ((!tnr_dmd) || (!ssi))
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
+	if (ret)
+		return ret;
+
+	if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) ||
+	    (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5))
+		return -EPERM;
+
+	prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp];
+
+	if (prel < -15000)
+		temp_ssi = 0;
+	else if (prel < 0)
+		temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
+	else if (prel < 20000)
+		temp_ssi = (((4 * prel) + 500) / 1000) + 10;
+	else if (prel < 35000)
+		temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
+	else
+		temp_ssi = 100;
+
+	*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+				u8 *ssi)
+{
+	int rf_lvl = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ssi))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
+	if (ret)
+		return ret;
+
+	ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				    u8 *ssi)
+{
+	int rf_lvl = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ssi))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
+	if (ret)
+		return ret;
+
+	ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 sync = 0;
+	u8 tslock = 0;
+	u8 early_unlock = 0;
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock,
+					      &early_unlock);
+	if (ret)
+		return ret;
+
+	if (sync != 6)
+		return -EBUSY;
+
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
new file mode 100644
index 000000000000..ce966270c69b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
@@ -0,0 +1,106 @@
+/*
+ * cxd2880_tnrdmd_dvbt_mon.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T monitor interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT_MON_H
+#define CXD2880_TNRDMD_DVBT_MON_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_dvbt.h"
+
+int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
+				      *tnr_dmd, u8 *sync_stat,
+				      u8 *ts_lock_stat,
+				      u8 *unlock_detected);
+
+int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
+					  *tnr_dmd, u8 *sync_stat,
+					  u8 *unlock_detected);
+
+int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
+				       *tnr_dmd,
+				       enum cxd2880_dvbt_mode
+				       *mode,
+				       enum cxd2880_dvbt_guard
+				       *guard);
+
+int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
+					   *tnr_dmd, int *offset);
+
+int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
+					       cxd2880_tnrdmd
+					       *tnr_dmd,
+					       int *offset);
+
+int cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd
+					   *tnr_dmd, u32 *ber);
+
+int cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd
+				      *tnr_dmd, u32 *ber);
+
+int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     struct cxd2880_dvbt_tpsinfo
+				     *info);
+
+int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
+						cxd2880_tnrdmd
+						*tnr_dmd,
+						u32 *pen);
+
+int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
+					   *tnr_dmd,
+					   enum
+					   cxd2880_tnrdmd_spectrum_sense
+					   *sense);
+
+int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+				int *snr);
+
+int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
+				      *tnr_dmd, int *snr,
+				      int *snr_main, int *snr_sub);
+
+int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
+					    *tnr_dmd, int *ppm);
+
+int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
+						cxd2880_tnrdmd
+						*tnr_dmd,
+						int *ppm);
+
+int cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd,
+				    u8 *quality);
+
+int cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
+				u32 *per);
+
+int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+				u8 *ssi);
+
+int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				    u8 *ssi);
+
+#endif
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 09/14] [media] cxd2880: Add DVB-T monitor and integration layer functions
@ 2017-08-16  4:41   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-08-16  4:41 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

Provide monitor and integration layer functions (DVB-T)
for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
      -changed CXD2880_SLEEP to usleep_range
      -chnaged cxd2880_atomic_set to atomic_set
      -modified return code
      -modified coding style of if() 
   drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
      -modified return code
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
      -removed unnecessary cast
      -changed cxd2880_math_log to intlog10
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
      -modified return code

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.c     |  198 ++++
 .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.h     |   58 +
 .../cxd2880/cxd2880_tnrdmd_dvbt_mon.c              | 1227 ++++++++++++++++++++
 .../cxd2880/cxd2880_tnrdmd_dvbt_mon.h              |  106 ++
 4 files changed, 1589 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
new file mode 100644
index 000000000000..729cb0939203
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
@@ -0,0 +1,198 @@
+/*
+ * cxd2880_integ_dvbt.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer functions for DVB-T
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_integ_dvbt.h"
+
+static int dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd,
+			    struct cxd2880_dvbt_tune_param
+			    *tune_param)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	atomic_set(&tnr_dmd->cancel, 0);
+
+	if ((tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ)) {
+		return -EOPNOTSUPP;
+	}
+
+	ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param);
+	if (ret)
+		return ret;
+
+	usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000,
+		     CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000);
+
+	ret = cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param);
+	if (ret)
+		return ret;
+
+	ret = dvbt_wait_demod_lock(tnr_dmd);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+	enum cxd2880_tnrdmd_lock_result lock =
+	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	unsigned int elapsed = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret)
+		return ret;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret)
+			return ret;
+
+		if (elapsed >= CXD2880_DVBT_WAIT_TS_LOCK)
+			continue_wait = 0;
+
+		ret = cxd2880_tnrdmd_dvbt_check_ts_lock(tnr_dmd, &lock);
+		if (ret)
+			return ret;
+
+		switch (lock) {
+		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
+			return 0;
+
+		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
+			return -EAGAIN;
+
+		default:
+			break;
+		}
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT_WAIT_LOCK_INTVL);
+			if (ret)
+				return ret;
+		} else {
+			ret = -ETIME;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+	enum cxd2880_tnrdmd_lock_result lock =
+	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	unsigned int elapsed = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret)
+		return ret;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret)
+			return ret;
+
+		if (elapsed >= CXD2880_DVBT_WAIT_DMD_LOCK)
+			continue_wait = 0;
+
+		ret = cxd2880_tnrdmd_dvbt_check_demod_lock(tnr_dmd, &lock);
+		if (ret)
+			return ret;
+
+		switch (lock) {
+		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
+			return 0;
+
+		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
+			return -EAGAIN;
+
+		default:
+			break;
+		}
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT_WAIT_LOCK_INTVL);
+			if (ret)
+				return ret;
+		} else {
+			ret = -ETIME;
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
new file mode 100644
index 000000000000..07f9b71a3006
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
@@ -0,0 +1,58 @@
+/*
+ * cxd2880_integ_dvbt.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer interface for DVB-T
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_INTEG_DVBT_H
+#define CXD2880_INTEG_DVBT_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_integ.h"
+
+#define CXD2880_DVBT_WAIT_DMD_LOCK	1000
+#define CXD2880_DVBT_WAIT_TS_LOCK	1000
+#define CXD2880_DVBT_WAIT_LOCK_INTVL	10
+
+struct cxd2880_integ_dvbt_scan_param {
+	u32 start_frequency_khz;
+	u32 end_frequency_khz;
+	u32 step_frequency_khz;
+	enum cxd2880_dtv_bandwidth bandwidth;
+};
+
+struct cxd2880_integ_dvbt_scan_result {
+	u32 center_freq_khz;
+	int tune_result;
+	struct cxd2880_dvbt_tune_param dvbt_tune_param;
+};
+
+int cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd,
+			    struct cxd2880_dvbt_tune_param
+			    *tune_param);
+
+int cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd
+				    *tnr_dmd);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
new file mode 100644
index 000000000000..37396a071727
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
@@ -0,0 +1,1227 @@
+/*
+ * cxd2880_tnrdmd_dvbt_mon.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T monitor functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt.h"
+#include "cxd2880_tnrdmd_dvbt_mon.h"
+
+#include "dvb_math.h"
+
+static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
+				      *tnr_dmd, u8 *sync_stat,
+				      u8 *ts_lock_stat,
+				      u8 *unlock_detected)
+{
+	u8 rdata = 0x00;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, &rdata, 1);
+	if (ret)
+		return ret;
+
+	*unlock_detected = (rdata & 0x10) ? 1 : 0;
+	*sync_stat = rdata & 0x07;
+	*ts_lock_stat = (rdata & 0x20) ? 1 : 0;
+
+	if (*sync_stat == 0x07)
+		return -EBUSY;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
+					  *tnr_dmd, u8 *sync_stat,
+					  u8 *unlock_detected)
+{
+	u8 ts_lock_stat = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub, sync_stat,
+					      &ts_lock_stat, unlock_detected);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
+				       *tnr_dmd,
+				       enum cxd2880_dvbt_mode
+				       *mode,
+				       enum cxd2880_dvbt_guard
+				       *guard)
+{
+	u8 rdata = 0x00;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!mode) || (!guard))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+			ret =
+			    cxd2880_tnrdmd_dvbt_mon_mode_guard(
+					tnr_dmd->diver_sub, mode, guard);
+
+		return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x1b, &rdata, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03);
+	*guard = (enum cxd2880_dvbt_guard)(rdata & 0x03);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
+					   *tnr_dmd, int *offset)
+{
+	u8 rdata[4];
+	u32 ctl_val = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!offset))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x1d, rdata, 4);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	ctl_val =
+	    ((rdata[0] & 0x1f) << 24) | (rdata[1] << 16) | (rdata[2] << 8) |
+	    (rdata[3]);
+	*offset = cxd2880_convert2s_complement(ctl_val, 29);
+	*offset = -1 * ((*offset) * tnr_dmd->bandwidth / 235);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
+					       cxd2880_tnrdmd
+					       *tnr_dmd,
+					       int *offset)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!offset))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub, offset);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd
+					   *tnr_dmd, u32 *ber)
+{
+	u8 rdata[2];
+	u32 bit_error = 0;
+	u32 period = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ber))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x10);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x39, rdata, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if ((rdata[0] & 0x01) == 0) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return -EBUSY;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x22, rdata, 2);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	bit_error = (rdata[0] << 8) | rdata[1];
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x6f, rdata, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	period = ((rdata[0] & 0x07) == 0) ? 256 : (0x1000 << (rdata[0] & 0x07));
+
+	if ((period == 0) || (bit_error > period))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		div = period / 128;
+
+		Q = (bit_error * 3125) / div;
+		R = (bit_error * 3125) % div;
+
+		R *= 25;
+		Q = Q * 25 + R / div;
+		R = R % div;
+
+		if (div / 2 <= R)
+			*ber = Q + 1;
+		else
+			*ber = Q;
+	}
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd
+				      *tnr_dmd, u32 *ber)
+{
+	u8 rdata[3];
+	u32 bit_error = 0;
+	u32 period_exp = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ber))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x15, rdata, 3);
+	if (ret)
+		return ret;
+
+	if ((rdata[0] & 0x40) == 0)
+		return -EBUSY;
+
+	bit_error = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2];
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x60, rdata, 1);
+	if (ret)
+		return ret;
+
+	period_exp = (rdata[0] & 0x1f);
+
+	if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		if (period_exp <= 8)
+			div = (1U << period_exp) * 51;
+		else
+			div = (1U << 8) * 51;
+
+		Q = (bit_error * 250) / div;
+		R = (bit_error * 250) % div;
+
+		R *= 1250;
+		Q = Q * 1250 + R / div;
+		R = R % div;
+
+		if (period_exp > 8) {
+			*ber =
+			    (Q + (1 << (period_exp - 9))) >> (period_exp - 8);
+		} else {
+			if (div / 2 <= R)
+				*ber = Q + 1;
+			else
+				*ber = Q;
+		}
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     struct cxd2880_dvbt_tpsinfo
+				     *info)
+{
+	u8 rdata[7];
+	u8 cell_id_ok = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!info))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+			ret =
+			    cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd->diver_sub,
+							     info);
+
+		return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x29, rdata, 7);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x11);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xd5, &cell_id_ok, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	info->constellation =
+	    (enum cxd2880_dvbt_constellation)((rdata[0] >> 6) & 0x03);
+	info->hierarchy = (enum cxd2880_dvbt_hierarchy)((rdata[0] >> 3) & 0x07);
+	info->rate_hp = (enum cxd2880_dvbt_coderate)(rdata[0] & 0x07);
+	info->rate_lp = (enum cxd2880_dvbt_coderate)((rdata[1] >> 5) & 0x07);
+	info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03);
+	info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03);
+	info->fnum = (rdata[2] >> 6) & 0x03;
+	info->length_indicator = rdata[2] & 0x3f;
+	info->cell_id = (rdata[3] << 8) | rdata[4];
+	info->reserved_even = rdata[5] & 0x3f;
+	info->reserved_odd = rdata[6] & 0x3f;
+
+	info->cell_id_ok = cell_id_ok & 0x01;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
+						cxd2880_tnrdmd
+						*tnr_dmd,
+						u32 *pen)
+{
+	u8 rdata[3];
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!pen))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x26, rdata, 3);
+	if (ret)
+		return ret;
+
+	if (!(rdata[0] & 0x01))
+		return -EBUSY;
+
+	*pen = (rdata[1] << 8) | rdata[2];
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
+					   *tnr_dmd,
+					    enum
+					    cxd2880_tnrdmd_spectrum_sense
+					    *sense)
+{
+	u8 data = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!sense))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+			ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(
+					tnr_dmd->diver_sub, sense);
+
+		return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x1c, &data, sizeof(data));
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*sense =
+	    (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
+	    CXD2880_TNRDMD_SPECTRUM_NORMAL;
+
+	return ret;
+}
+
+static int dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
+			     u16 *reg_value)
+{
+	u8 rdata[2];
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!reg_value))
+		return -EINVAL;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = is_tps_locked(tnr_dmd);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x13, rdata, 2);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*reg_value = (rdata[0] << 8) | rdata[1];
+
+	return ret;
+}
+
+static int dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
+			 u32 reg_value, int *snr)
+{
+	if ((!tnr_dmd) || (!snr))
+		return -EINVAL;
+
+	if (reg_value == 0)
+		return -EBUSY;
+
+	if (reg_value > 4996)
+		reg_value = 4996;
+
+	*snr = intlog10(reg_value) - intlog10(5350 - reg_value);
+	*snr = (*snr + 839) / 1678 + 28500;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+				int *snr)
+{
+	u16 reg_value = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!snr))
+		return -EINVAL;
+
+	*snr = -1000 * 1000;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
+		if (ret)
+			return ret;
+
+		ret = dvbt_calc_snr(tnr_dmd, reg_value, snr);
+		if (ret)
+			return ret;
+	} else {
+		int snr_main = 0;
+		int snr_sub = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main,
+						      &snr_sub);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
+				      *tnr_dmd, int *snr,
+				      int *snr_main, int *snr_sub)
+{
+	u16 reg_value = 0;
+	u32 reg_value_sum = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub))
+		return -EINVAL;
+
+	*snr = -1000 * 1000;
+	*snr_main = -1000 * 1000;
+	*snr_sub = -1000 * 1000;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
+	if (!ret) {
+		ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main);
+		if (ret)
+			reg_value = 0;
+	} else if (ret == -EBUSY) {
+		reg_value = 0;
+	} else {
+		return ret;
+	}
+
+	reg_value_sum += reg_value;
+
+	ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
+	if (!ret) {
+		ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
+		if (ret)
+			reg_value = 0;
+	} else if (ret == -EBUSY) {
+		reg_value = 0;
+	} else {
+		return ret;
+	}
+
+	reg_value_sum += reg_value;
+
+	ret = dvbt_calc_snr(tnr_dmd, reg_value_sum, snr);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
+					    *tnr_dmd, int *ppm)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ppm))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	{
+		u8 ctl_val_reg[5];
+		u8 nominal_rate_reg[5];
+		u32 trl_ctl_val = 0;
+		u32 trcg_nominal_rate = 0;
+		int num;
+		int den;
+		s8 diff_upper = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret = is_tps_locked(tnr_dmd);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0d);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x21, ctl_val_reg,
+					     sizeof(ctl_val_reg));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x04);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x60, nominal_rate_reg,
+					     sizeof(nominal_rate_reg));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		diff_upper =
+		    (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
+
+		if ((diff_upper < -1) || (diff_upper > 1))
+			return -EBUSY;
+
+		trl_ctl_val = ctl_val_reg[1] << 24;
+		trl_ctl_val |= ctl_val_reg[2] << 16;
+		trl_ctl_val |= ctl_val_reg[3] << 8;
+		trl_ctl_val |= ctl_val_reg[4];
+
+		trcg_nominal_rate = nominal_rate_reg[1] << 24;
+		trcg_nominal_rate |= nominal_rate_reg[2] << 16;
+		trcg_nominal_rate |= nominal_rate_reg[3] << 8;
+		trcg_nominal_rate |= nominal_rate_reg[4];
+
+		trl_ctl_val >>= 1;
+		trcg_nominal_rate >>= 1;
+
+		if (diff_upper == 1)
+			num =
+			    (int)((trl_ctl_val + 0x80000000u) -
+				  trcg_nominal_rate);
+		else if (diff_upper == -1)
+			num =
+			    -(int)((trcg_nominal_rate + 0x80000000u) -
+				   trl_ctl_val);
+		else
+			num = (int)(trl_ctl_val - trcg_nominal_rate);
+
+		den = (nominal_rate_reg[0] & 0x7f) << 24;
+		den |= nominal_rate_reg[1] << 16;
+		den |= nominal_rate_reg[2] << 8;
+		den |= nominal_rate_reg[3];
+		den = (den + (390625 / 2)) / 390625;
+
+		den >>= 1;
+
+		if (num >= 0)
+			*ppm = (num + (den / 2)) / den;
+		else
+			*ppm = (num - (den / 2)) / den;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
+						cxd2880_tnrdmd
+						*tnr_dmd, int *ppm)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ppm))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd,
+				    u8 *quality)
+{
+	struct cxd2880_dvbt_tpsinfo tps;
+	enum cxd2880_dvbt_profile profile = CXD2880_DVBT_PROFILE_HP;
+	u32 ber = 0;
+	int sn = 0;
+	int sn_rel = 0;
+	int ber_sqi = 0;
+
+	static const int nordig_non_hdvbt_db_1000[3][5] = {
+		{5100, 6900, 7900, 8900, 9700},
+		{10800, 13100, 14600, 15600, 16000},
+		{16500, 18700, 20200, 21600, 22500}
+	};
+
+	static const int nordig_hier_hp_dvbt_db_1000[3][2][5] = {
+		{
+		 {9100, 12000, 13600, 15000, 16600},
+		 {10900, 14100, 15700, 19400, 20600}
+		 },
+		{
+		 {6800, 9100, 10400, 11900, 12700},
+		 {8500, 11000, 12800, 15000, 16000}
+		 },
+		{
+		 {5800, 7900, 9100, 10300, 12100},
+		 {8000, 9300, 11600, 13000, 12900}
+		}
+	};
+
+	static const int nordig_hier_lp_dvbt_db_1000[3][2][5] = {
+		{
+		 {12500, 14300, 15300, 16300, 16900},
+		 {16700, 19100, 20900, 22500, 23700}
+		 },
+		{
+		 {15000, 17200, 18400, 19100, 20100},
+		 {18500, 21200, 23600, 24700, 25900}
+		 },
+		{
+		 {19500, 21400, 22500, 23700, 24700},
+		 {21900, 24200, 25600, 26900, 27800}
+		}
+	};
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!quality))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
+	if (ret)
+		return ret;
+
+	if (tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) {
+		u8 data = 0;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x10);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x67, &data, 1);
+		if (ret)
+			return ret;
+
+		profile =
+		    ((data & 0x01) ==
+		     0x01) ? CXD2880_DVBT_PROFILE_LP : CXD2880_DVBT_PROFILE_HP;
+	}
+
+	ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(tnr_dmd, &ber);
+	if (ret)
+		return ret;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_snr(tnr_dmd, &sn);
+	if (ret)
+		return ret;
+
+	if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) ||
+	    (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5) ||
+	    (tps.rate_lp >= CXD2880_DVBT_CODERATE_RESERVED_5) ||
+	    (tps.hierarchy > CXD2880_DVBT_HIERARCHY_4)) {
+		return -EPERM;
+	}
+
+	if ((tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) &&
+	    (tps.constellation == CXD2880_DVBT_CONSTELLATION_QPSK))
+		return -EPERM;
+
+	if (tps.hierarchy == CXD2880_DVBT_HIERARCHY_NON)
+		sn_rel =
+		    sn -
+		    nordig_non_hdvbt_db_1000[tps.constellation][tps.rate_hp];
+	else if (profile == CXD2880_DVBT_PROFILE_LP)
+		sn_rel =
+		    sn - nordig_hier_lp_dvbt_db_1000[tps.hierarchy - 1]
+						    [tps.constellation - 1]
+						    [tps.rate_lp];
+	else
+		sn_rel =
+		    sn - nordig_hier_hp_dvbt_db_1000[tps.hierarchy - 1]
+						    [tps.constellation - 1]
+						    [tps.rate_hp];
+
+	if (ber > 10000) {
+		ber_sqi = 0;
+	} else if (ber > 1) {
+		ber_sqi = (int)((intlog10(ber) + 8388) / 16777);
+		ber_sqi = 20 * (7 * 1000 - (ber_sqi)) - 40 * 1000;
+	} else {
+		ber_sqi = 100 * 1000;
+	}
+
+	if (sn_rel < -7 * 1000) {
+		*quality = 0;
+	} else if (sn_rel < 3 * 1000) {
+		int tmp_sqi = (((sn_rel - (3 * 1000)) / 10) + 1000);
+		*quality =
+		    (u8)(((tmp_sqi * ber_sqi) +
+			   (1000000 / 2)) / (1000000)) & 0xff;
+	} else {
+		*quality = (u8)((ber_sqi + 500) / 1000);
+	}
+
+	if (*quality > 100)
+		*quality = 100;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
+				u32 *per)
+{
+	u32 packet_error = 0;
+	u32 period = 0;
+	u8 rdata[3];
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!per))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0d);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x18, rdata, 3);
+	if (ret)
+		return ret;
+
+	if ((rdata[0] & 0x01) == 0)
+		return -EBUSY;
+
+	packet_error = (rdata[1] << 8) | rdata[2];
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x10);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x5c, rdata, 1);
+	if (ret)
+		return ret;
+
+	period = 1U << (rdata[0] & 0x0f);
+
+	if ((period == 0) || (packet_error > period))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		div = period;
+
+		Q = (packet_error * 1000) / div;
+		R = (packet_error * 1000) % div;
+
+		R *= 1000;
+		Q = Q * 1000 + R / div;
+		R = R % div;
+
+		if ((div != 1) && (div / 2 <= R))
+			*per = Q + 1;
+		else
+			*per = Q;
+	}
+
+	return ret;
+}
+
+static int dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+			 int rf_lvl, u8 *ssi)
+{
+	struct cxd2880_dvbt_tpsinfo tps;
+	int prel;
+	int temp_ssi = 0;
+	int ret = 0;
+
+	static const int ref_dbm_1000[3][5] = {
+		{-93000, -91000, -90000, -89000, -88000},
+		{-87000, -85000, -84000, -83000, -82000},
+		{-82000, -80000, -78000, -77000, -76000},
+	};
+
+	if ((!tnr_dmd) || (!ssi))
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
+	if (ret)
+		return ret;
+
+	if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) ||
+	    (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5))
+		return -EPERM;
+
+	prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp];
+
+	if (prel < -15000)
+		temp_ssi = 0;
+	else if (prel < 0)
+		temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
+	else if (prel < 20000)
+		temp_ssi = (((4 * prel) + 500) / 1000) + 10;
+	else if (prel < 35000)
+		temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
+	else
+		temp_ssi = 100;
+
+	*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+				u8 *ssi)
+{
+	int rf_lvl = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ssi))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
+	if (ret)
+		return ret;
+
+	ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				    u8 *ssi)
+{
+	int rf_lvl = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ssi))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
+	if (ret)
+		return ret;
+
+	ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	u8 sync = 0;
+	u8 tslock = 0;
+	u8 early_unlock = 0;
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock,
+					      &early_unlock);
+	if (ret)
+		return ret;
+
+	if (sync != 6)
+		return -EBUSY;
+
+	return 0;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
new file mode 100644
index 000000000000..ce966270c69b
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
@@ -0,0 +1,106 @@
+/*
+ * cxd2880_tnrdmd_dvbt_mon.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T monitor interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT_MON_H
+#define CXD2880_TNRDMD_DVBT_MON_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_dvbt.h"
+
+int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
+				      *tnr_dmd, u8 *sync_stat,
+				      u8 *ts_lock_stat,
+				      u8 *unlock_detected);
+
+int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
+					  *tnr_dmd, u8 *sync_stat,
+					  u8 *unlock_detected);
+
+int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
+				       *tnr_dmd,
+				       enum cxd2880_dvbt_mode
+				       *mode,
+				       enum cxd2880_dvbt_guard
+				       *guard);
+
+int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
+					   *tnr_dmd, int *offset);
+
+int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
+					       cxd2880_tnrdmd
+					       *tnr_dmd,
+					       int *offset);
+
+int cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd
+					   *tnr_dmd, u32 *ber);
+
+int cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd
+				      *tnr_dmd, u32 *ber);
+
+int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     struct cxd2880_dvbt_tpsinfo
+				     *info);
+
+int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
+						cxd2880_tnrdmd
+						*tnr_dmd,
+						u32 *pen);
+
+int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
+					   *tnr_dmd,
+					   enum
+					   cxd2880_tnrdmd_spectrum_sense
+					   *sense);
+
+int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+				int *snr);
+
+int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
+				      *tnr_dmd, int *snr,
+				      int *snr_main, int *snr_sub);
+
+int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
+					    *tnr_dmd, int *ppm);
+
+int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
+						cxd2880_tnrdmd
+						*tnr_dmd,
+						int *ppm);
+
+int cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd,
+				    u8 *quality);
+
+int cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
+				u32 *per);
+
+int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+				u8 *ssi);
+
+int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
+				    u8 *ssi);
+
+#endif
-- 
2.13.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 10/14] [media] cxd2880: Add DVB-T2 control functions for the driver
@ 2017-08-16  4:42   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:42 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

Provide definitions, interfaces and functions needed for DVB-T2
of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
      -modified return code
      -modified coding style of if() 
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
      -modified return code

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 .../media/dvb-frontends/cxd2880/cxd2880_dvbt2.h    |  402 ++++++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c   | 1359 ++++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h   |   82 ++
 3 files changed, 1843 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
new file mode 100644
index 000000000000..674ed17deef5
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
@@ -0,0 +1,402 @@
+/*
+ * cxd2880_dvbt2.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T2 related definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_DVBT2_H
+#define CXD2880_DVBT2_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_dvbt2_profile {
+	CXD2880_DVBT2_PROFILE_BASE,
+	CXD2880_DVBT2_PROFILE_LITE,
+	CXD2880_DVBT2_PROFILE_ANY
+};
+
+enum cxd2880_dvbt2_version {
+	CXD2880_DVBT2_V111,
+	CXD2880_DVBT2_V121,
+	CXD2880_DVBT2_V131
+};
+
+enum cxd2880_dvbt2_s1 {
+	CXD2880_DVBT2_S1_BASE_SISO = 0x00,
+	CXD2880_DVBT2_S1_BASE_MISO = 0x01,
+	CXD2880_DVBT2_S1_NON_DVBT2 = 0x02,
+	CXD2880_DVBT2_S1_LITE_SISO = 0x03,
+	CXD2880_DVBT2_S1_LITE_MISO = 0x04,
+	CXD2880_DVBT2_S1_RSVD3 = 0x05,
+	CXD2880_DVBT2_S1_RSVD4 = 0x06,
+	CXD2880_DVBT2_S1_RSVD5 = 0x07,
+	CXD2880_DVBT2_S1_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_base_s2 {
+	CXD2880_DVBT2_BASE_S2_M2K_G_ANY = 0x00,
+	CXD2880_DVBT2_BASE_S2_M8K_G_DVBT = 0x01,
+	CXD2880_DVBT2_BASE_S2_M4K_G_ANY = 0x02,
+	CXD2880_DVBT2_BASE_S2_M1K_G_ANY = 0x03,
+	CXD2880_DVBT2_BASE_S2_M16K_G_ANY = 0x04,
+	CXD2880_DVBT2_BASE_S2_M32K_G_DVBT = 0x05,
+	CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2 = 0x06,
+	CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2 = 0x07,
+	CXD2880_DVBT2_BASE_S2_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_lite_s2 {
+	CXD2880_DVBT2_LITE_S2_M2K_G_ANY = 0x00,
+	CXD2880_DVBT2_LITE_S2_M8K_G_DVBT = 0x01,
+	CXD2880_DVBT2_LITE_S2_M4K_G_ANY = 0x02,
+	CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2 = 0x03,
+	CXD2880_DVBT2_LITE_S2_M16K_G_DVBT = 0x04,
+	CXD2880_DVBT2_LITE_S2_RSVD1 = 0x05,
+	CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2 = 0x06,
+	CXD2880_DVBT2_LITE_S2_RSVD2 = 0x07,
+	CXD2880_DVBT2_LITE_S2_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_guard {
+	CXD2880_DVBT2_G1_32 = 0x00,
+	CXD2880_DVBT2_G1_16 = 0x01,
+	CXD2880_DVBT2_G1_8 = 0x02,
+	CXD2880_DVBT2_G1_4 = 0x03,
+	CXD2880_DVBT2_G1_128 = 0x04,
+	CXD2880_DVBT2_G19_128 = 0x05,
+	CXD2880_DVBT2_G19_256 = 0x06,
+	CXD2880_DVBT2_G_RSVD1 = 0x07,
+	CXD2880_DVBT2_G_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_mode {
+	CXD2880_DVBT2_M2K = 0x00,
+	CXD2880_DVBT2_M8K = 0x01,
+	CXD2880_DVBT2_M4K = 0x02,
+	CXD2880_DVBT2_M1K = 0x03,
+	CXD2880_DVBT2_M16K = 0x04,
+	CXD2880_DVBT2_M32K = 0x05,
+	CXD2880_DVBT2_M_RSVD1 = 0x06,
+	CXD2880_DVBT2_M_RSVD2 = 0x07
+};
+
+enum cxd2880_dvbt2_bw {
+	CXD2880_DVBT2_BW_8 = 0x00,
+	CXD2880_DVBT2_BW_7 = 0x01,
+	CXD2880_DVBT2_BW_6 = 0x02,
+	CXD2880_DVBT2_BW_5 = 0x03,
+	CXD2880_DVBT2_BW_10 = 0x04,
+	CXD2880_DVBT2_BW_1_7 = 0x05,
+	CXD2880_DVBT2_BW_RSVD1 = 0x06,
+	CXD2880_DVBT2_BW_RSVD2 = 0x07,
+	CXD2880_DVBT2_BW_RSVD3 = 0x08,
+	CXD2880_DVBT2_BW_RSVD4 = 0x09,
+	CXD2880_DVBT2_BW_RSVD5 = 0x0a,
+	CXD2880_DVBT2_BW_RSVD6 = 0x0b,
+	CXD2880_DVBT2_BW_RSVD7 = 0x0c,
+	CXD2880_DVBT2_BW_RSVD8 = 0x0d,
+	CXD2880_DVBT2_BW_RSVD9 = 0x0e,
+	CXD2880_DVBT2_BW_RSVD10 = 0x0f,
+	CXD2880_DVBT2_BW_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_l1pre_type {
+	CXD2880_DVBT2_L1PRE_TYPE_TS = 0x00,
+	CXD2880_DVBT2_L1PRE_TYPE_GS = 0x01,
+	CXD2880_DVBT2_L1PRE_TYPE_TS_GS = 0x02,
+	CXD2880_DVBT2_L1PRE_TYPE_RESERVED = 0x03,
+	CXD2880_DVBT2_L1PRE_TYPE_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_papr {
+	CXD2880_DVBT2_PAPR_0 = 0x00,
+	CXD2880_DVBT2_PAPR_1 = 0x01,
+	CXD2880_DVBT2_PAPR_2 = 0x02,
+	CXD2880_DVBT2_PAPR_3 = 0x03,
+	CXD2880_DVBT2_PAPR_RSVD1 = 0x04,
+	CXD2880_DVBT2_PAPR_RSVD2 = 0x05,
+	CXD2880_DVBT2_PAPR_RSVD3 = 0x06,
+	CXD2880_DVBT2_PAPR_RSVD4 = 0x07,
+	CXD2880_DVBT2_PAPR_RSVD5 = 0x08,
+	CXD2880_DVBT2_PAPR_RSVD6 = 0x09,
+	CXD2880_DVBT2_PAPR_RSVD7 = 0x0a,
+	CXD2880_DVBT2_PAPR_RSVD8 = 0x0b,
+	CXD2880_DVBT2_PAPR_RSVD9 = 0x0c,
+	CXD2880_DVBT2_PAPR_RSVD10 = 0x0d,
+	CXD2880_DVBT2_PAPR_RSVD11 = 0x0e,
+	CXD2880_DVBT2_PAPR_RSVD12 = 0x0f,
+	CXD2880_DVBT2_PAPR_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_l1post_constell {
+	CXD2880_DVBT2_L1POST_BPSK = 0x00,
+	CXD2880_DVBT2_L1POST_QPSK = 0x01,
+	CXD2880_DVBT2_L1POST_QAM16 = 0x02,
+	CXD2880_DVBT2_L1POST_QAM64 = 0x03,
+	CXD2880_DVBT2_L1POST_C_RSVD1 = 0x04,
+	CXD2880_DVBT2_L1POST_C_RSVD2 = 0x05,
+	CXD2880_DVBT2_L1POST_C_RSVD3 = 0x06,
+	CXD2880_DVBT2_L1POST_C_RSVD4 = 0x07,
+	CXD2880_DVBT2_L1POST_C_RSVD5 = 0x08,
+	CXD2880_DVBT2_L1POST_C_RSVD6 = 0x09,
+	CXD2880_DVBT2_L1POST_C_RSVD7 = 0x0a,
+	CXD2880_DVBT2_L1POST_C_RSVD8 = 0x0b,
+	CXD2880_DVBT2_L1POST_C_RSVD9 = 0x0c,
+	CXD2880_DVBT2_L1POST_C_RSVD10 = 0x0d,
+	CXD2880_DVBT2_L1POST_C_RSVD11 = 0x0e,
+	CXD2880_DVBT2_L1POST_C_RSVD12 = 0x0f,
+	CXD2880_DVBT2_L1POST_CONSTELL_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_l1post_cr {
+	CXD2880_DVBT2_L1POST_R1_2 = 0x00,
+	CXD2880_DVBT2_L1POST_R_RSVD1 = 0x01,
+	CXD2880_DVBT2_L1POST_R_RSVD2 = 0x02,
+	CXD2880_DVBT2_L1POST_R_RSVD3 = 0x03,
+	CXD2880_DVBT2_L1POST_R_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_l1post_fec_type {
+	CXD2880_DVBT2_L1POST_FEC_LDPC16K = 0x00,
+	CXD2880_DVBT2_L1POST_FEC_RSVD1 = 0x01,
+	CXD2880_DVBT2_L1POST_FEC_RSVD2 = 0x02,
+	CXD2880_DVBT2_L1POST_FEC_RSVD3 = 0x03,
+	CXD2880_DVBT2_L1POST_FEC_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_pp {
+	CXD2880_DVBT2_PP1 = 0x00,
+	CXD2880_DVBT2_PP2 = 0x01,
+	CXD2880_DVBT2_PP3 = 0x02,
+	CXD2880_DVBT2_PP4 = 0x03,
+	CXD2880_DVBT2_PP5 = 0x04,
+	CXD2880_DVBT2_PP6 = 0x05,
+	CXD2880_DVBT2_PP7 = 0x06,
+	CXD2880_DVBT2_PP8 = 0x07,
+	CXD2880_DVBT2_PP_RSVD1 = 0x08,
+	CXD2880_DVBT2_PP_RSVD2 = 0x09,
+	CXD2880_DVBT2_PP_RSVD3 = 0x0a,
+	CXD2880_DVBT2_PP_RSVD4 = 0x0b,
+	CXD2880_DVBT2_PP_RSVD5 = 0x0c,
+	CXD2880_DVBT2_PP_RSVD6 = 0x0d,
+	CXD2880_DVBT2_PP_RSVD7 = 0x0e,
+	CXD2880_DVBT2_PP_RSVD8 = 0x0f,
+	CXD2880_DVBT2_PP_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_code_rate {
+	CXD2880_DVBT2_R1_2 = 0x00,
+	CXD2880_DVBT2_R3_5 = 0x01,
+	CXD2880_DVBT2_R2_3 = 0x02,
+	CXD2880_DVBT2_R3_4 = 0x03,
+	CXD2880_DVBT2_R4_5 = 0x04,
+	CXD2880_DVBT2_R5_6 = 0x05,
+	CXD2880_DVBT2_R1_3 = 0x06,
+	CXD2880_DVBT2_R2_5 = 0x07,
+	CXD2880_DVBT2_PLP_CR_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_constell {
+	CXD2880_DVBT2_QPSK = 0x00,
+	CXD2880_DVBT2_QAM16 = 0x01,
+	CXD2880_DVBT2_QAM64 = 0x02,
+	CXD2880_DVBT2_QAM256 = 0x03,
+	CXD2880_DVBT2_CON_RSVD1 = 0x04,
+	CXD2880_DVBT2_CON_RSVD2 = 0x05,
+	CXD2880_DVBT2_CON_RSVD3 = 0x06,
+	CXD2880_DVBT2_CON_RSVD4 = 0x07,
+	CXD2880_DVBT2_CONSTELL_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_type {
+	CXD2880_DVBT2_PLP_TYPE_COMMON = 0x00,
+	CXD2880_DVBT2_PLP_TYPE_DATA1 = 0x01,
+	CXD2880_DVBT2_PLP_TYPE_DATA2 = 0x02,
+	CXD2880_DVBT2_PLP_TYPE_RSVD1 = 0x03,
+	CXD2880_DVBT2_PLP_TYPE_RSVD2 = 0x04,
+	CXD2880_DVBT2_PLP_TYPE_RSVD3 = 0x05,
+	CXD2880_DVBT2_PLP_TYPE_RSVD4 = 0x06,
+	CXD2880_DVBT2_PLP_TYPE_RSVD5 = 0x07,
+	CXD2880_DVBT2_PLP_TYPE_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_payload {
+	CXD2880_DVBT2_PLP_PAYLOAD_GFPS = 0x00,
+	CXD2880_DVBT2_PLP_PAYLOAD_GCS = 0x01,
+	CXD2880_DVBT2_PLP_PAYLOAD_GSE = 0x02,
+	CXD2880_DVBT2_PLP_PAYLOAD_TS = 0x03,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD1 = 0x04,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD2 = 0x05,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD3 = 0x06,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD4 = 0x07,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD5 = 0x08,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD6 = 0x09,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD7 = 0x0a,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD8 = 0x0b,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD9 = 0x0c,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD10 = 0x0d,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD11 = 0x0e,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD12 = 0x0f,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD13 = 0x10,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD14 = 0x11,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD15 = 0x12,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD16 = 0x13,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD17 = 0x14,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD18 = 0x15,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD19 = 0x16,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD20 = 0x17,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD21 = 0x18,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD22 = 0x19,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD23 = 0x1a,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD24 = 0x1b,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD25 = 0x1c,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD26 = 0x1d,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD27 = 0x1e,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD28 = 0x1f,
+	CXD2880_DVBT2_PLP_PAYLOAD_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_fec {
+	CXD2880_DVBT2_FEC_LDPC_16K = 0x00,
+	CXD2880_DVBT2_FEC_LDPC_64K = 0x01,
+	CXD2880_DVBT2_FEC_RSVD1 = 0x02,
+	CXD2880_DVBT2_FEC_RSVD2 = 0x03,
+	CXD2880_DVBT2_FEC_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_mode {
+	CXD2880_DVBT2_PLP_MODE_NOTSPECIFIED = 0x00,
+	CXD2880_DVBT2_PLP_MODE_NM = 0x01,
+	CXD2880_DVBT2_PLP_MODE_HEM = 0x02,
+	CXD2880_DVBT2_PLP_MODE_RESERVED = 0x03,
+	CXD2880_DVBT2_PLP_MODE_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_btype {
+	CXD2880_DVBT2_PLP_COMMON,
+	CXD2880_DVBT2_PLP_DATA
+};
+
+enum cxd2880_dvbt2_stream {
+	CXD2880_DVBT2_STREAM_GENERIC_PACKETIZED = 0x00,
+	CXD2880_DVBT2_STREAM_GENERIC_CONTINUOUS = 0x01,
+	CXD2880_DVBT2_STREAM_GENERIC_ENCAPSULATED = 0x02,
+	CXD2880_DVBT2_STREAM_TRANSPORT = 0x03,
+	CXD2880_DVBT2_STREAM_UNKNOWN = 0xff
+};
+
+struct cxd2880_dvbt2_l1pre {
+	enum cxd2880_dvbt2_l1pre_type type;
+	u8 bw_ext;
+	enum cxd2880_dvbt2_s1 s1;
+	u8 s2;
+	u8 mixed;
+	enum cxd2880_dvbt2_mode fft_mode;
+	u8 l1_rep;
+	enum cxd2880_dvbt2_guard gi;
+	enum cxd2880_dvbt2_papr papr;
+	enum cxd2880_dvbt2_l1post_constell mod;
+	enum cxd2880_dvbt2_l1post_cr cr;
+	enum cxd2880_dvbt2_l1post_fec_type fec;
+	u32 l1_post_size;
+	u32 l1_post_info_size;
+	enum cxd2880_dvbt2_pp pp;
+	u8 tx_id_availability;
+	u16 cell_id;
+	u16 network_id;
+	u16 sys_id;
+	u8 num_frames;
+	u16 num_symbols;
+	u8 regen;
+	u8 post_ext;
+	u8 num_rf_freqs;
+	u8 rf_idx;
+	enum cxd2880_dvbt2_version t2_version;
+	u8 l1_post_scrambled;
+	u8 t2_base_lite;
+	u32 crc32;
+};
+
+struct cxd2880_dvbt2_plp {
+	u8 id;
+	enum cxd2880_dvbt2_plp_type type;
+	enum cxd2880_dvbt2_plp_payload payload;
+	u8 ff;
+	u8 first_rf_idx;
+	u8 first_frm_idx;
+	u8 group_id;
+	enum cxd2880_dvbt2_plp_constell constell;
+	enum cxd2880_dvbt2_plp_code_rate plp_cr;
+	u8 rot;
+	enum cxd2880_dvbt2_plp_fec fec;
+	u16 num_blocks_max;
+	u8 frm_int;
+	u8 til_len;
+	u8 til_type;
+	u8 in_band_a_flag;
+	u8 in_band_b_flag;
+	u16 rsvd;
+	enum cxd2880_dvbt2_plp_mode plp_mode;
+	u8 static_flag;
+	u8 static_padding_flag;
+};
+
+struct cxd2880_dvbt2_l1post {
+	u16 sub_slices_per_frame;
+	u8 num_plps;
+	u8 num_aux;
+	u8 aux_cfg_rfu;
+	u8 rf_idx;
+	u32 freq;
+	u8 fef_type;
+	u32 fef_length;
+	u8 fef_intvl;
+};
+
+struct cxd2880_dvbt2_ofdm {
+	u8 mixed;
+	u8 is_miso;
+	enum cxd2880_dvbt2_mode mode;
+	enum cxd2880_dvbt2_guard gi;
+	enum cxd2880_dvbt2_pp pp;
+	u8 bw_ext;
+	enum cxd2880_dvbt2_papr papr;
+	u16 num_symbols;
+};
+
+struct cxd2880_dvbt2_bbheader {
+	enum cxd2880_dvbt2_stream stream_input;
+	u8 is_single_input_stream;
+	u8 is_constant_coding_modulation;
+	u8 issy_indicator;
+	u8 null_packet_deletion;
+	u8 ext;
+	u8 input_stream_identifier;
+	u16 user_packet_length;
+	u16 data_field_length;
+	u8 sync_byte;
+	u32 issy;
+	enum cxd2880_dvbt2_plp_mode plp_mode;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
new file mode 100644
index 000000000000..3df0648598a1
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
@@ -0,0 +1,1359 @@
+/*
+ * cxd2880_tnrdmd_dvbt2.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control functions for DVB-T2
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+
+static int x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd
+				      *tnr_dmd,
+				      enum cxd2880_dtv_bandwidth
+				      bandwidth,
+				      enum cxd2880_tnrdmd_clockmode
+				      clk_mode)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x31, 0x02);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x04);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x5d, 0x0b);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+		u8 data[2] = { 0x01, 0x01 };
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x00);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xce, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	{
+		u8 data[14] = { 0x07, 0x06, 0x01, 0xf0,
+			0x00, 0x00, 0x04, 0xb0, 0x00, 0x00, 0x09, 0x9c, 0x0e,
+			    0x4c
+		};
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x20);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x8a, data[0]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x90, data[1]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x25);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xf0, &data[2], 2);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x2a);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xdc, data[4]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xde, data[5]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x2d);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x73, &data[6], 4);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x8f, &data[10], 4);
+		if (ret)
+			return ret;
+	}
+
+	{
+		u8 data_a_1[9] = { 0x52, 0x49, 0x2c, 0x51,
+			0x51, 0x3d, 0x15, 0x29, 0x0c
+		};
+		u8 data_b_1[9] = { 0x5d, 0x55, 0x32, 0x5c,
+			0x5c, 0x45, 0x17, 0x2e, 0x0d
+		};
+		u8 data_c_1[9] = { 0x60, 0x00, 0x34, 0x5e,
+			0x5e, 0x47, 0x18, 0x2f, 0x0e
+		};
+
+		u8 data_a_2[13] = { 0x04, 0xe7, 0x94, 0x92,
+			0x09, 0xcf, 0x7e, 0xd0, 0x49, 0xcd, 0xcd, 0x1f, 0x5b
+		};
+		u8 data_b_2[13] = { 0x05, 0x90, 0x27, 0x55,
+			0x0b, 0x20, 0x8f, 0xd6, 0xea, 0xc8, 0xc8, 0x23, 0x91
+		};
+		u8 data_c_2[13] = { 0x05, 0xb8, 0xd8, 0x00,
+			0x0b, 0x72, 0x93, 0xf3, 0x00, 0xcd, 0xcd, 0x24, 0x95
+		};
+
+		u8 data_a_3[5] = { 0x0b, 0x6a, 0xc9, 0x03,
+			0x33
+		};
+		u8 data_b_3[5] = { 0x01, 0x02, 0xe4, 0x03,
+			0x39
+		};
+		u8 data_c_3[5] = { 0x01, 0x02, 0xeb, 0x03,
+			0x3b
+		};
+
+		u8 *data_1 = NULL;
+		u8 *data_2 = NULL;
+		u8 *data_3 = NULL;
+
+		switch (clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			data_1 = data_a_1;
+			data_2 = data_a_2;
+			data_3 = data_a_3;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			data_1 = data_b_1;
+			data_2 = data_b_2;
+			data_3 = data_b_3;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			data_1 = data_c_1;
+			data_2 = data_c_2;
+			data_3 = data_c_3;
+			break;
+		default:
+			return -EPERM;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x04);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x1d, &data_1[0], 3);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x22, data_1[3]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x24, data_1[4]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x26, data_1[5]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x29, &data_1[6], 2);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x2d, data_1[8]);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x2e, &data_2[0], 6);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x35, &data_2[6], 7);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x3c, &data_3[0], 2);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x56, &data_3[2], 3);
+		if (ret)
+			return ret;
+	}
+
+	switch (bandwidth) {
+	case CXD2880_DTV_BW_8_MHZ:
+
+		{
+			u8 data_ac[6] = { 0x15, 0x00, 0x00, 0x00,
+				0x00, 0x00
+			};
+			u8 data_b[6] = { 0x14, 0x6a, 0xaa, 0xaa,
+				0xab, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x10, data, 6);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x00);
+		if (ret)
+			return ret;
+
+		{
+			u8 data_a[2] = { 0x19, 0xd2 };
+			u8 data_bc[2] = { 0x3f, 0xff };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_bc;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x19, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x2a };
+			u8 data_b[2] = { 0x06, 0x29 };
+			u8 data_c[2] = { 0x06, 0x28 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x1b, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x28, 0x00, 0x50, 0x00,
+				0x60, 0x00, 0x00, 0x90, 0x00
+			};
+			u8 data_b[9] = { 0x2d, 0x5e, 0x5a, 0xbd,
+				0x6c, 0xe3, 0x00, 0xa3, 0x55
+			};
+			u8 data_c[9] = { 0x2e, 0xaa, 0x5d, 0x55,
+				0x70, 0x00, 0x00, 0xa8, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, data, 9);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_7_MHZ:
+
+		{
+			u8 data_ac[6] = { 0x18, 0x00, 0x00, 0x00,
+				0x00, 0x00
+			};
+			u8 data_b[6] = { 0x17, 0x55, 0x55, 0x55,
+				0x55, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x10, data, 6);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x02);
+		if (ret)
+			return ret;
+
+		{
+			u8 data[2] = { 0x3f, 0xff };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x19, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x23 };
+			u8 data_b[2] = { 0x06, 0x22 };
+			u8 data_c[2] = { 0x06, 0x21 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x1b, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x2d, 0xb6, 0x5b, 0x6d,
+				0x6d, 0xb6, 0x00, 0xa4, 0x92
+			};
+			u8 data_b[9] = { 0x33, 0xda, 0x67, 0xb4,
+				0x7c, 0x71, 0x00, 0xba, 0xaa
+			};
+			u8 data_c[9] = { 0x35, 0x55, 0x6a, 0xaa,
+				0x80, 0x00, 0x00, 0xc0, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, data, 9);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_6_MHZ:
+
+		{
+			u8 data_ac[6] = { 0x1c, 0x00, 0x00, 0x00,
+				0x00, 0x00
+			};
+			u8 data_b[6] = { 0x1b, 0x38, 0xe3, 0x8e,
+				0x39, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x10, data, 6);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x04);
+		if (ret)
+			return ret;
+
+		{
+			u8 data[2] = { 0x3f, 0xff };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x19, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x1c };
+			u8 data_b[2] = { 0x06, 0x1b };
+			u8 data_c[2] = { 0x06, 0x1a };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x1b, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x35, 0x55, 0x6a, 0xaa,
+				0x80, 0x00, 0x00, 0xc0, 0x00
+			};
+			u8 data_b[9] = { 0x3c, 0x7e, 0x78, 0xfc,
+				0x91, 0x2f, 0x00, 0xd9, 0xc7
+			};
+			u8 data_c[9] = { 0x3e, 0x38, 0x7c, 0x71,
+				0x95, 0x55, 0x00, 0xdf, 0xff
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, data, 9);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_5_MHZ:
+
+		{
+			u8 data_ac[6] = { 0x21, 0x99, 0x99, 0x99,
+				0x9a, 0x00
+			};
+			u8 data_b[6] = { 0x20, 0xaa, 0xaa, 0xaa,
+				0xab, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x10, data, 6);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x06);
+		if (ret)
+			return ret;
+
+		{
+			u8 data[2] = { 0x3f, 0xff };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x19, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x15 };
+			u8 data_b[2] = { 0x06, 0x15 };
+			u8 data_c[2] = { 0x06, 0x14 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x1b, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x40, 0x00, 0x6a, 0xaa,
+				0x80, 0x00, 0x00, 0xe6, 0x66
+			};
+			u8 data_b[9] = { 0x48, 0x97, 0x78, 0xfc,
+				0x91, 0x2f, 0x01, 0x05, 0x55
+			};
+			u8 data_c[9] = { 0x4a, 0xaa, 0x7c, 0x71,
+				0x95, 0x55, 0x01, 0x0c, 0xcc
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, data, 9);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_1_7_MHZ:
+
+		{
+			u8 data_a[6] = { 0x68, 0x0f, 0xa2, 0x32,
+				0xcf, 0x03
+			};
+			u8 data_c[6] = { 0x68, 0x0f, 0xa2, 0x32,
+				0xcf, 0x03
+			};
+			u8 data_b[6] = { 0x65, 0x2b, 0xa4, 0xcd,
+				0xd8, 0x03
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x10, data, 6);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x03);
+		if (ret)
+			return ret;
+
+		{
+			u8 data[2] = { 0x3f, 0xff };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x19, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x0c };
+			u8 data_b[2] = { 0x06, 0x0c };
+			u8 data_c[2] = { 0x06, 0x0b };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x1b, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x40, 0x00, 0x6a, 0xaa,
+				0x80, 0x00, 0x02, 0xc9, 0x8f
+			};
+			u8 data_b[9] = { 0x48, 0x97, 0x78, 0xfc,
+				0x91, 0x2f, 0x03, 0x29, 0x5d
+			};
+			u8 data_c[9] = { 0x4a, 0xaa, 0x7c, 0x71,
+				0x95, 0x55, 0x03, 0x40, 0x7d
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, data, 9);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	default:
+		return -EPERM;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xfd, 0x01);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd
+				       *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		u8 data[] = { 0, 1, 0, 2,
+			0, 4, 0, 8, 0, 16, 0, 32
+		};
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x1d);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x47, data, 12);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
+			     enum cxd2880_dvbt2_profile profile)
+{
+	u8 t2_mode_tune_mode = 0;
+	u8 seq_not2_dtime = 0;
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	{
+		u8 dtime1 = 0;
+		u8 dtime2 = 0;
+
+		switch (tnr_dmd->clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			dtime1 = 0x27;
+			dtime2 = 0x0c;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			dtime1 = 0x2c;
+			dtime2 = 0x0d;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			dtime1 = 0x2e;
+			dtime2 = 0x0e;
+			break;
+		default:
+			return -EPERM;
+		}
+
+		switch (profile) {
+		case CXD2880_DVBT2_PROFILE_BASE:
+			t2_mode_tune_mode = 0x01;
+			seq_not2_dtime = dtime2;
+			break;
+
+		case CXD2880_DVBT2_PROFILE_LITE:
+			t2_mode_tune_mode = 0x05;
+			seq_not2_dtime = dtime1;
+			break;
+
+		case CXD2880_DVBT2_PROFILE_ANY:
+			t2_mode_tune_mode = 0x00;
+			seq_not2_dtime = dtime1;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x2e);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, t2_mode_tune_mode);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x04);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x2c, seq_not2_dtime);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+			       struct cxd2880_dvbt2_tune_param
+			       *tune_param)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) &&
+	    (tune_param->profile == CXD2880_DVBT2_PROFILE_ANY))
+		return -EOPNOTSUPP;
+
+	ret =
+	    cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2,
+						tune_param->center_freq_khz,
+						tune_param->bandwidth, 0, 0);
+	if (ret)
+		return ret;
+
+	ret =
+	    x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth,
+				       tnr_dmd->clk_mode);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret =
+		    x_tune_dvbt2_demod_setting(tnr_dmd->diver_sub,
+					       tune_param->bandwidth,
+					       tnr_dmd->diver_sub->clk_mode);
+		if (ret)
+			return ret;
+	}
+
+	ret = dvbt2_set_profile(tnr_dmd, tune_param->profile);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret =
+		    dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile);
+		if (ret)
+			return ret;
+	}
+
+	if (tune_param->data_plp_id == CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO) {
+		ret = cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 1, 0);
+		if (ret)
+			return ret;
+	} else {
+		ret =
+		    cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0,
+					     (u8)(tune_param->data_plp_id));
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+			       struct cxd2880_dvbt2_tune_param
+			       *tune_param)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	{
+		u8 en_fef_intmtnt_ctrl = 1;
+
+		switch (tune_param->profile) {
+		case CXD2880_DVBT2_PROFILE_BASE:
+			en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_base;
+			break;
+		case CXD2880_DVBT2_PROFILE_LITE:
+			en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_lite;
+			break;
+		case CXD2880_DVBT2_PROFILE_ANY:
+			if (tnr_dmd->en_fef_intmtnt_base &&
+			    tnr_dmd->en_fef_intmtnt_lite)
+				en_fef_intmtnt_ctrl = 1;
+			else
+				en_fef_intmtnt_ctrl = 0;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		ret =
+		    cxd2880_tnrdmd_common_tune_setting2(tnr_dmd,
+							CXD2880_DTV_SYS_DVBT2,
+							en_fef_intmtnt_ctrl);
+		if (ret)
+			return ret;
+	}
+
+	tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
+	tnr_dmd->frequency_khz = tune_param->center_freq_khz;
+	tnr_dmd->sys = CXD2880_DTV_SYS_DVBT2;
+	tnr_dmd->bandwidth = tune_param->bandwidth;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
+		tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
+		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT2;
+		tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
+				       *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = x_sleep_dvbt2_demod_setting(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
+					  *tnr_dmd,
+					  enum
+					  cxd2880_tnrdmd_lock_result
+					  *lock)
+{
+	int ret = 0;
+
+	u8 sync_stat = 0;
+	u8 ts_lock = 0;
+	u8 unlock_detected = 0;
+	u8 unlock_detected_sub = 0;
+
+	if ((!tnr_dmd) || (!lock))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+					       &unlock_detected);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (sync_stat == 6)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		else if (unlock_detected)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+		else
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+		return ret;
+	}
+
+	if (sync_stat == 6) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		return ret;
+	}
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+						   &unlock_detected_sub);
+	if (ret)
+		return ret;
+
+	if (sync_stat == 6)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+	else if (unlock_detected && unlock_detected_sub)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+	else
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
+				       *tnr_dmd,
+				       enum
+				       cxd2880_tnrdmd_lock_result
+				       *lock)
+{
+	int ret = 0;
+
+	u8 sync_stat = 0;
+	u8 ts_lock = 0;
+	u8 unlock_detected = 0;
+	u8 unlock_detected_sub = 0;
+
+	if ((!tnr_dmd) || (!lock))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+					       &unlock_detected);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (ts_lock)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		else if (unlock_detected)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+		else
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+		return ret;
+	}
+
+	if (ts_lock) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		return ret;
+	} else if (!unlock_detected) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+		return ret;
+	}
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+						   &unlock_detected_sub);
+	if (ret)
+		return ret;
+
+	if (unlock_detected && unlock_detected_sub)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+	else
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
+				     *tnr_dmd, u8 auto_plp,
+				     u8 plp_id)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x23);
+	if (ret)
+		return ret;
+
+	if (!auto_plp) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xaf, plp_id);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xad, auto_plp ? 0x00 : 0x01);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
+					   *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE)
+		return 0;
+
+	{
+		struct cxd2880_dvbt2_ofdm ofdm;
+
+		ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm);
+		if (ret)
+			return ret;
+
+		if (!ofdm.mixed)
+			return 0;
+	}
+
+	{
+		u8 data[] = { 0, 8, 0, 16,
+			0, 32, 0, 64, 0, 128, 1, 0
+		};
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x1d);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x47, data, 12);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
+					    *tnr_dmd,
+					    u8 *l1_post_valid)
+{
+	int ret = 0;
+
+	u8 data;
+
+	if ((!tnr_dmd) || (!l1_post_valid))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x86, &data, 1);
+	if (ret)
+		return ret;
+
+	*l1_post_valid = data & 0x01;
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
new file mode 100644
index 000000000000..409685425b53
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
@@ -0,0 +1,82 @@
+/*
+ * cxd2880_tnrdmd_dvbt2.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control interface for DVB-T2
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT2_H
+#define CXD2880_TNRDMD_DVBT2_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+
+enum cxd2880_tnrdmd_dvbt2_tune_info {
+	CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK,
+	CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID
+};
+
+struct cxd2880_dvbt2_tune_param {
+	u32 center_freq_khz;
+	enum cxd2880_dtv_bandwidth bandwidth;
+	u16 data_plp_id;
+	enum cxd2880_dvbt2_profile profile;
+	enum cxd2880_tnrdmd_dvbt2_tune_info tune_info;
+};
+
+#define CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO  0xffff
+
+int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+			       struct cxd2880_dvbt2_tune_param
+			       *tune_param);
+
+int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+			       struct cxd2880_dvbt2_tune_param
+			       *tune_param);
+
+int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
+				       *tnr_dmd);
+
+int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
+					  *tnr_dmd,
+					  enum
+					  cxd2880_tnrdmd_lock_result
+					  *lock);
+
+int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
+				       *tnr_dmd,
+				       enum
+				       cxd2880_tnrdmd_lock_result
+				       *lock);
+
+int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
+				     *tnr_dmd, u8 auto_plp,
+				     u8 plp_id);
+
+int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
+					   *tnr_dmd);
+
+int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
+					    *tnr_dmd,
+					    u8 *l1_post_valid);
+
+#endif
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 10/14] [media] cxd2880: Add DVB-T2 control functions for the driver
@ 2017-08-16  4:42   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-08-16  4:42 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

Provide definitions, interfaces and functions needed for DVB-T2
of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
      -modified return code
      -modified coding style of if() 
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
      -modified return code

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 .../media/dvb-frontends/cxd2880/cxd2880_dvbt2.h    |  402 ++++++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c   | 1359 ++++++++++++++++++++
 .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h   |   82 ++
 3 files changed, 1843 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
new file mode 100644
index 000000000000..674ed17deef5
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
@@ -0,0 +1,402 @@
+/*
+ * cxd2880_dvbt2.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T2 related definitions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_DVBT2_H
+#define CXD2880_DVBT2_H
+
+#include "cxd2880_common.h"
+
+enum cxd2880_dvbt2_profile {
+	CXD2880_DVBT2_PROFILE_BASE,
+	CXD2880_DVBT2_PROFILE_LITE,
+	CXD2880_DVBT2_PROFILE_ANY
+};
+
+enum cxd2880_dvbt2_version {
+	CXD2880_DVBT2_V111,
+	CXD2880_DVBT2_V121,
+	CXD2880_DVBT2_V131
+};
+
+enum cxd2880_dvbt2_s1 {
+	CXD2880_DVBT2_S1_BASE_SISO = 0x00,
+	CXD2880_DVBT2_S1_BASE_MISO = 0x01,
+	CXD2880_DVBT2_S1_NON_DVBT2 = 0x02,
+	CXD2880_DVBT2_S1_LITE_SISO = 0x03,
+	CXD2880_DVBT2_S1_LITE_MISO = 0x04,
+	CXD2880_DVBT2_S1_RSVD3 = 0x05,
+	CXD2880_DVBT2_S1_RSVD4 = 0x06,
+	CXD2880_DVBT2_S1_RSVD5 = 0x07,
+	CXD2880_DVBT2_S1_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_base_s2 {
+	CXD2880_DVBT2_BASE_S2_M2K_G_ANY = 0x00,
+	CXD2880_DVBT2_BASE_S2_M8K_G_DVBT = 0x01,
+	CXD2880_DVBT2_BASE_S2_M4K_G_ANY = 0x02,
+	CXD2880_DVBT2_BASE_S2_M1K_G_ANY = 0x03,
+	CXD2880_DVBT2_BASE_S2_M16K_G_ANY = 0x04,
+	CXD2880_DVBT2_BASE_S2_M32K_G_DVBT = 0x05,
+	CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2 = 0x06,
+	CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2 = 0x07,
+	CXD2880_DVBT2_BASE_S2_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_lite_s2 {
+	CXD2880_DVBT2_LITE_S2_M2K_G_ANY = 0x00,
+	CXD2880_DVBT2_LITE_S2_M8K_G_DVBT = 0x01,
+	CXD2880_DVBT2_LITE_S2_M4K_G_ANY = 0x02,
+	CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2 = 0x03,
+	CXD2880_DVBT2_LITE_S2_M16K_G_DVBT = 0x04,
+	CXD2880_DVBT2_LITE_S2_RSVD1 = 0x05,
+	CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2 = 0x06,
+	CXD2880_DVBT2_LITE_S2_RSVD2 = 0x07,
+	CXD2880_DVBT2_LITE_S2_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_guard {
+	CXD2880_DVBT2_G1_32 = 0x00,
+	CXD2880_DVBT2_G1_16 = 0x01,
+	CXD2880_DVBT2_G1_8 = 0x02,
+	CXD2880_DVBT2_G1_4 = 0x03,
+	CXD2880_DVBT2_G1_128 = 0x04,
+	CXD2880_DVBT2_G19_128 = 0x05,
+	CXD2880_DVBT2_G19_256 = 0x06,
+	CXD2880_DVBT2_G_RSVD1 = 0x07,
+	CXD2880_DVBT2_G_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_mode {
+	CXD2880_DVBT2_M2K = 0x00,
+	CXD2880_DVBT2_M8K = 0x01,
+	CXD2880_DVBT2_M4K = 0x02,
+	CXD2880_DVBT2_M1K = 0x03,
+	CXD2880_DVBT2_M16K = 0x04,
+	CXD2880_DVBT2_M32K = 0x05,
+	CXD2880_DVBT2_M_RSVD1 = 0x06,
+	CXD2880_DVBT2_M_RSVD2 = 0x07
+};
+
+enum cxd2880_dvbt2_bw {
+	CXD2880_DVBT2_BW_8 = 0x00,
+	CXD2880_DVBT2_BW_7 = 0x01,
+	CXD2880_DVBT2_BW_6 = 0x02,
+	CXD2880_DVBT2_BW_5 = 0x03,
+	CXD2880_DVBT2_BW_10 = 0x04,
+	CXD2880_DVBT2_BW_1_7 = 0x05,
+	CXD2880_DVBT2_BW_RSVD1 = 0x06,
+	CXD2880_DVBT2_BW_RSVD2 = 0x07,
+	CXD2880_DVBT2_BW_RSVD3 = 0x08,
+	CXD2880_DVBT2_BW_RSVD4 = 0x09,
+	CXD2880_DVBT2_BW_RSVD5 = 0x0a,
+	CXD2880_DVBT2_BW_RSVD6 = 0x0b,
+	CXD2880_DVBT2_BW_RSVD7 = 0x0c,
+	CXD2880_DVBT2_BW_RSVD8 = 0x0d,
+	CXD2880_DVBT2_BW_RSVD9 = 0x0e,
+	CXD2880_DVBT2_BW_RSVD10 = 0x0f,
+	CXD2880_DVBT2_BW_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_l1pre_type {
+	CXD2880_DVBT2_L1PRE_TYPE_TS = 0x00,
+	CXD2880_DVBT2_L1PRE_TYPE_GS = 0x01,
+	CXD2880_DVBT2_L1PRE_TYPE_TS_GS = 0x02,
+	CXD2880_DVBT2_L1PRE_TYPE_RESERVED = 0x03,
+	CXD2880_DVBT2_L1PRE_TYPE_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_papr {
+	CXD2880_DVBT2_PAPR_0 = 0x00,
+	CXD2880_DVBT2_PAPR_1 = 0x01,
+	CXD2880_DVBT2_PAPR_2 = 0x02,
+	CXD2880_DVBT2_PAPR_3 = 0x03,
+	CXD2880_DVBT2_PAPR_RSVD1 = 0x04,
+	CXD2880_DVBT2_PAPR_RSVD2 = 0x05,
+	CXD2880_DVBT2_PAPR_RSVD3 = 0x06,
+	CXD2880_DVBT2_PAPR_RSVD4 = 0x07,
+	CXD2880_DVBT2_PAPR_RSVD5 = 0x08,
+	CXD2880_DVBT2_PAPR_RSVD6 = 0x09,
+	CXD2880_DVBT2_PAPR_RSVD7 = 0x0a,
+	CXD2880_DVBT2_PAPR_RSVD8 = 0x0b,
+	CXD2880_DVBT2_PAPR_RSVD9 = 0x0c,
+	CXD2880_DVBT2_PAPR_RSVD10 = 0x0d,
+	CXD2880_DVBT2_PAPR_RSVD11 = 0x0e,
+	CXD2880_DVBT2_PAPR_RSVD12 = 0x0f,
+	CXD2880_DVBT2_PAPR_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_l1post_constell {
+	CXD2880_DVBT2_L1POST_BPSK = 0x00,
+	CXD2880_DVBT2_L1POST_QPSK = 0x01,
+	CXD2880_DVBT2_L1POST_QAM16 = 0x02,
+	CXD2880_DVBT2_L1POST_QAM64 = 0x03,
+	CXD2880_DVBT2_L1POST_C_RSVD1 = 0x04,
+	CXD2880_DVBT2_L1POST_C_RSVD2 = 0x05,
+	CXD2880_DVBT2_L1POST_C_RSVD3 = 0x06,
+	CXD2880_DVBT2_L1POST_C_RSVD4 = 0x07,
+	CXD2880_DVBT2_L1POST_C_RSVD5 = 0x08,
+	CXD2880_DVBT2_L1POST_C_RSVD6 = 0x09,
+	CXD2880_DVBT2_L1POST_C_RSVD7 = 0x0a,
+	CXD2880_DVBT2_L1POST_C_RSVD8 = 0x0b,
+	CXD2880_DVBT2_L1POST_C_RSVD9 = 0x0c,
+	CXD2880_DVBT2_L1POST_C_RSVD10 = 0x0d,
+	CXD2880_DVBT2_L1POST_C_RSVD11 = 0x0e,
+	CXD2880_DVBT2_L1POST_C_RSVD12 = 0x0f,
+	CXD2880_DVBT2_L1POST_CONSTELL_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_l1post_cr {
+	CXD2880_DVBT2_L1POST_R1_2 = 0x00,
+	CXD2880_DVBT2_L1POST_R_RSVD1 = 0x01,
+	CXD2880_DVBT2_L1POST_R_RSVD2 = 0x02,
+	CXD2880_DVBT2_L1POST_R_RSVD3 = 0x03,
+	CXD2880_DVBT2_L1POST_R_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_l1post_fec_type {
+	CXD2880_DVBT2_L1POST_FEC_LDPC16K = 0x00,
+	CXD2880_DVBT2_L1POST_FEC_RSVD1 = 0x01,
+	CXD2880_DVBT2_L1POST_FEC_RSVD2 = 0x02,
+	CXD2880_DVBT2_L1POST_FEC_RSVD3 = 0x03,
+	CXD2880_DVBT2_L1POST_FEC_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_pp {
+	CXD2880_DVBT2_PP1 = 0x00,
+	CXD2880_DVBT2_PP2 = 0x01,
+	CXD2880_DVBT2_PP3 = 0x02,
+	CXD2880_DVBT2_PP4 = 0x03,
+	CXD2880_DVBT2_PP5 = 0x04,
+	CXD2880_DVBT2_PP6 = 0x05,
+	CXD2880_DVBT2_PP7 = 0x06,
+	CXD2880_DVBT2_PP8 = 0x07,
+	CXD2880_DVBT2_PP_RSVD1 = 0x08,
+	CXD2880_DVBT2_PP_RSVD2 = 0x09,
+	CXD2880_DVBT2_PP_RSVD3 = 0x0a,
+	CXD2880_DVBT2_PP_RSVD4 = 0x0b,
+	CXD2880_DVBT2_PP_RSVD5 = 0x0c,
+	CXD2880_DVBT2_PP_RSVD6 = 0x0d,
+	CXD2880_DVBT2_PP_RSVD7 = 0x0e,
+	CXD2880_DVBT2_PP_RSVD8 = 0x0f,
+	CXD2880_DVBT2_PP_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_code_rate {
+	CXD2880_DVBT2_R1_2 = 0x00,
+	CXD2880_DVBT2_R3_5 = 0x01,
+	CXD2880_DVBT2_R2_3 = 0x02,
+	CXD2880_DVBT2_R3_4 = 0x03,
+	CXD2880_DVBT2_R4_5 = 0x04,
+	CXD2880_DVBT2_R5_6 = 0x05,
+	CXD2880_DVBT2_R1_3 = 0x06,
+	CXD2880_DVBT2_R2_5 = 0x07,
+	CXD2880_DVBT2_PLP_CR_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_constell {
+	CXD2880_DVBT2_QPSK = 0x00,
+	CXD2880_DVBT2_QAM16 = 0x01,
+	CXD2880_DVBT2_QAM64 = 0x02,
+	CXD2880_DVBT2_QAM256 = 0x03,
+	CXD2880_DVBT2_CON_RSVD1 = 0x04,
+	CXD2880_DVBT2_CON_RSVD2 = 0x05,
+	CXD2880_DVBT2_CON_RSVD3 = 0x06,
+	CXD2880_DVBT2_CON_RSVD4 = 0x07,
+	CXD2880_DVBT2_CONSTELL_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_type {
+	CXD2880_DVBT2_PLP_TYPE_COMMON = 0x00,
+	CXD2880_DVBT2_PLP_TYPE_DATA1 = 0x01,
+	CXD2880_DVBT2_PLP_TYPE_DATA2 = 0x02,
+	CXD2880_DVBT2_PLP_TYPE_RSVD1 = 0x03,
+	CXD2880_DVBT2_PLP_TYPE_RSVD2 = 0x04,
+	CXD2880_DVBT2_PLP_TYPE_RSVD3 = 0x05,
+	CXD2880_DVBT2_PLP_TYPE_RSVD4 = 0x06,
+	CXD2880_DVBT2_PLP_TYPE_RSVD5 = 0x07,
+	CXD2880_DVBT2_PLP_TYPE_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_payload {
+	CXD2880_DVBT2_PLP_PAYLOAD_GFPS = 0x00,
+	CXD2880_DVBT2_PLP_PAYLOAD_GCS = 0x01,
+	CXD2880_DVBT2_PLP_PAYLOAD_GSE = 0x02,
+	CXD2880_DVBT2_PLP_PAYLOAD_TS = 0x03,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD1 = 0x04,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD2 = 0x05,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD3 = 0x06,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD4 = 0x07,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD5 = 0x08,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD6 = 0x09,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD7 = 0x0a,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD8 = 0x0b,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD9 = 0x0c,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD10 = 0x0d,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD11 = 0x0e,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD12 = 0x0f,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD13 = 0x10,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD14 = 0x11,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD15 = 0x12,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD16 = 0x13,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD17 = 0x14,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD18 = 0x15,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD19 = 0x16,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD20 = 0x17,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD21 = 0x18,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD22 = 0x19,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD23 = 0x1a,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD24 = 0x1b,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD25 = 0x1c,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD26 = 0x1d,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD27 = 0x1e,
+	CXD2880_DVBT2_PLP_PAYLOAD_RSVD28 = 0x1f,
+	CXD2880_DVBT2_PLP_PAYLOAD_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_fec {
+	CXD2880_DVBT2_FEC_LDPC_16K = 0x00,
+	CXD2880_DVBT2_FEC_LDPC_64K = 0x01,
+	CXD2880_DVBT2_FEC_RSVD1 = 0x02,
+	CXD2880_DVBT2_FEC_RSVD2 = 0x03,
+	CXD2880_DVBT2_FEC_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_mode {
+	CXD2880_DVBT2_PLP_MODE_NOTSPECIFIED = 0x00,
+	CXD2880_DVBT2_PLP_MODE_NM = 0x01,
+	CXD2880_DVBT2_PLP_MODE_HEM = 0x02,
+	CXD2880_DVBT2_PLP_MODE_RESERVED = 0x03,
+	CXD2880_DVBT2_PLP_MODE_UNKNOWN = 0xff
+};
+
+enum cxd2880_dvbt2_plp_btype {
+	CXD2880_DVBT2_PLP_COMMON,
+	CXD2880_DVBT2_PLP_DATA
+};
+
+enum cxd2880_dvbt2_stream {
+	CXD2880_DVBT2_STREAM_GENERIC_PACKETIZED = 0x00,
+	CXD2880_DVBT2_STREAM_GENERIC_CONTINUOUS = 0x01,
+	CXD2880_DVBT2_STREAM_GENERIC_ENCAPSULATED = 0x02,
+	CXD2880_DVBT2_STREAM_TRANSPORT = 0x03,
+	CXD2880_DVBT2_STREAM_UNKNOWN = 0xff
+};
+
+struct cxd2880_dvbt2_l1pre {
+	enum cxd2880_dvbt2_l1pre_type type;
+	u8 bw_ext;
+	enum cxd2880_dvbt2_s1 s1;
+	u8 s2;
+	u8 mixed;
+	enum cxd2880_dvbt2_mode fft_mode;
+	u8 l1_rep;
+	enum cxd2880_dvbt2_guard gi;
+	enum cxd2880_dvbt2_papr papr;
+	enum cxd2880_dvbt2_l1post_constell mod;
+	enum cxd2880_dvbt2_l1post_cr cr;
+	enum cxd2880_dvbt2_l1post_fec_type fec;
+	u32 l1_post_size;
+	u32 l1_post_info_size;
+	enum cxd2880_dvbt2_pp pp;
+	u8 tx_id_availability;
+	u16 cell_id;
+	u16 network_id;
+	u16 sys_id;
+	u8 num_frames;
+	u16 num_symbols;
+	u8 regen;
+	u8 post_ext;
+	u8 num_rf_freqs;
+	u8 rf_idx;
+	enum cxd2880_dvbt2_version t2_version;
+	u8 l1_post_scrambled;
+	u8 t2_base_lite;
+	u32 crc32;
+};
+
+struct cxd2880_dvbt2_plp {
+	u8 id;
+	enum cxd2880_dvbt2_plp_type type;
+	enum cxd2880_dvbt2_plp_payload payload;
+	u8 ff;
+	u8 first_rf_idx;
+	u8 first_frm_idx;
+	u8 group_id;
+	enum cxd2880_dvbt2_plp_constell constell;
+	enum cxd2880_dvbt2_plp_code_rate plp_cr;
+	u8 rot;
+	enum cxd2880_dvbt2_plp_fec fec;
+	u16 num_blocks_max;
+	u8 frm_int;
+	u8 til_len;
+	u8 til_type;
+	u8 in_band_a_flag;
+	u8 in_band_b_flag;
+	u16 rsvd;
+	enum cxd2880_dvbt2_plp_mode plp_mode;
+	u8 static_flag;
+	u8 static_padding_flag;
+};
+
+struct cxd2880_dvbt2_l1post {
+	u16 sub_slices_per_frame;
+	u8 num_plps;
+	u8 num_aux;
+	u8 aux_cfg_rfu;
+	u8 rf_idx;
+	u32 freq;
+	u8 fef_type;
+	u32 fef_length;
+	u8 fef_intvl;
+};
+
+struct cxd2880_dvbt2_ofdm {
+	u8 mixed;
+	u8 is_miso;
+	enum cxd2880_dvbt2_mode mode;
+	enum cxd2880_dvbt2_guard gi;
+	enum cxd2880_dvbt2_pp pp;
+	u8 bw_ext;
+	enum cxd2880_dvbt2_papr papr;
+	u16 num_symbols;
+};
+
+struct cxd2880_dvbt2_bbheader {
+	enum cxd2880_dvbt2_stream stream_input;
+	u8 is_single_input_stream;
+	u8 is_constant_coding_modulation;
+	u8 issy_indicator;
+	u8 null_packet_deletion;
+	u8 ext;
+	u8 input_stream_identifier;
+	u16 user_packet_length;
+	u16 data_field_length;
+	u8 sync_byte;
+	u32 issy;
+	enum cxd2880_dvbt2_plp_mode plp_mode;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
new file mode 100644
index 000000000000..3df0648598a1
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
@@ -0,0 +1,1359 @@
+/*
+ * cxd2880_tnrdmd_dvbt2.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control functions for DVB-T2
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+
+static int x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd
+				      *tnr_dmd,
+				      enum cxd2880_dtv_bandwidth
+				      bandwidth,
+				      enum cxd2880_tnrdmd_clockmode
+				      clk_mode)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_SYS,
+				     0x31, 0x02);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x04);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x5d, 0x0b);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+		u8 data[2] = { 0x01, 0x01 };
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x00);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xce, data, 2);
+		if (ret)
+			return ret;
+	}
+
+	{
+		u8 data[14] = { 0x07, 0x06, 0x01, 0xf0,
+			0x00, 0x00, 0x04, 0xb0, 0x00, 0x00, 0x09, 0x9c, 0x0e,
+			    0x4c
+		};
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x20);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x8a, data[0]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x90, data[1]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x25);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0xf0, &data[2], 2);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x2a);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xdc, data[4]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xde, data[5]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x2d);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x73, &data[6], 4);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x8f, &data[10], 4);
+		if (ret)
+			return ret;
+	}
+
+	{
+		u8 data_a_1[9] = { 0x52, 0x49, 0x2c, 0x51,
+			0x51, 0x3d, 0x15, 0x29, 0x0c
+		};
+		u8 data_b_1[9] = { 0x5d, 0x55, 0x32, 0x5c,
+			0x5c, 0x45, 0x17, 0x2e, 0x0d
+		};
+		u8 data_c_1[9] = { 0x60, 0x00, 0x34, 0x5e,
+			0x5e, 0x47, 0x18, 0x2f, 0x0e
+		};
+
+		u8 data_a_2[13] = { 0x04, 0xe7, 0x94, 0x92,
+			0x09, 0xcf, 0x7e, 0xd0, 0x49, 0xcd, 0xcd, 0x1f, 0x5b
+		};
+		u8 data_b_2[13] = { 0x05, 0x90, 0x27, 0x55,
+			0x0b, 0x20, 0x8f, 0xd6, 0xea, 0xc8, 0xc8, 0x23, 0x91
+		};
+		u8 data_c_2[13] = { 0x05, 0xb8, 0xd8, 0x00,
+			0x0b, 0x72, 0x93, 0xf3, 0x00, 0xcd, 0xcd, 0x24, 0x95
+		};
+
+		u8 data_a_3[5] = { 0x0b, 0x6a, 0xc9, 0x03,
+			0x33
+		};
+		u8 data_b_3[5] = { 0x01, 0x02, 0xe4, 0x03,
+			0x39
+		};
+		u8 data_c_3[5] = { 0x01, 0x02, 0xeb, 0x03,
+			0x3b
+		};
+
+		u8 *data_1 = NULL;
+		u8 *data_2 = NULL;
+		u8 *data_3 = NULL;
+
+		switch (clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			data_1 = data_a_1;
+			data_2 = data_a_2;
+			data_3 = data_a_3;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			data_1 = data_b_1;
+			data_2 = data_b_2;
+			data_3 = data_b_3;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			data_1 = data_c_1;
+			data_2 = data_c_2;
+			data_3 = data_c_3;
+			break;
+		default:
+			return -EPERM;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x04);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x1d, &data_1[0], 3);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x22, data_1[3]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x24, data_1[4]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x26, data_1[5]);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x29, &data_1[6], 2);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x2d, data_1[8]);
+		if (ret)
+			return ret;
+
+		if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x2e, &data_2[0], 6);
+			if (ret)
+				return ret;
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x35, &data_2[6], 7);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x3c, &data_3[0], 2);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x56, &data_3[2], 3);
+		if (ret)
+			return ret;
+	}
+
+	switch (bandwidth) {
+	case CXD2880_DTV_BW_8_MHZ:
+
+		{
+			u8 data_ac[6] = { 0x15, 0x00, 0x00, 0x00,
+				0x00, 0x00
+			};
+			u8 data_b[6] = { 0x14, 0x6a, 0xaa, 0xaa,
+				0xab, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x10, data, 6);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x00);
+		if (ret)
+			return ret;
+
+		{
+			u8 data_a[2] = { 0x19, 0xd2 };
+			u8 data_bc[2] = { 0x3f, 0xff };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_bc;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x19, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x2a };
+			u8 data_b[2] = { 0x06, 0x29 };
+			u8 data_c[2] = { 0x06, 0x28 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x1b, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x28, 0x00, 0x50, 0x00,
+				0x60, 0x00, 0x00, 0x90, 0x00
+			};
+			u8 data_b[9] = { 0x2d, 0x5e, 0x5a, 0xbd,
+				0x6c, 0xe3, 0x00, 0xa3, 0x55
+			};
+			u8 data_c[9] = { 0x2e, 0xaa, 0x5d, 0x55,
+				0x70, 0x00, 0x00, 0xa8, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, data, 9);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_7_MHZ:
+
+		{
+			u8 data_ac[6] = { 0x18, 0x00, 0x00, 0x00,
+				0x00, 0x00
+			};
+			u8 data_b[6] = { 0x17, 0x55, 0x55, 0x55,
+				0x55, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x10, data, 6);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x02);
+		if (ret)
+			return ret;
+
+		{
+			u8 data[2] = { 0x3f, 0xff };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x19, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x23 };
+			u8 data_b[2] = { 0x06, 0x22 };
+			u8 data_c[2] = { 0x06, 0x21 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x1b, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x2d, 0xb6, 0x5b, 0x6d,
+				0x6d, 0xb6, 0x00, 0xa4, 0x92
+			};
+			u8 data_b[9] = { 0x33, 0xda, 0x67, 0xb4,
+				0x7c, 0x71, 0x00, 0xba, 0xaa
+			};
+			u8 data_c[9] = { 0x35, 0x55, 0x6a, 0xaa,
+				0x80, 0x00, 0x00, 0xc0, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, data, 9);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_6_MHZ:
+
+		{
+			u8 data_ac[6] = { 0x1c, 0x00, 0x00, 0x00,
+				0x00, 0x00
+			};
+			u8 data_b[6] = { 0x1b, 0x38, 0xe3, 0x8e,
+				0x39, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x10, data, 6);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x04);
+		if (ret)
+			return ret;
+
+		{
+			u8 data[2] = { 0x3f, 0xff };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x19, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x1c };
+			u8 data_b[2] = { 0x06, 0x1b };
+			u8 data_c[2] = { 0x06, 0x1a };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x1b, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x35, 0x55, 0x6a, 0xaa,
+				0x80, 0x00, 0x00, 0xc0, 0x00
+			};
+			u8 data_b[9] = { 0x3c, 0x7e, 0x78, 0xfc,
+				0x91, 0x2f, 0x00, 0xd9, 0xc7
+			};
+			u8 data_c[9] = { 0x3e, 0x38, 0x7c, 0x71,
+				0x95, 0x55, 0x00, 0xdf, 0xff
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, data, 9);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_5_MHZ:
+
+		{
+			u8 data_ac[6] = { 0x21, 0x99, 0x99, 0x99,
+				0x9a, 0x00
+			};
+			u8 data_b[6] = { 0x20, 0xaa, 0xaa, 0xaa,
+				0xab, 0x00
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_ac;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x10, data, 6);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x06);
+		if (ret)
+			return ret;
+
+		{
+			u8 data[2] = { 0x3f, 0xff };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x19, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x15 };
+			u8 data_b[2] = { 0x06, 0x15 };
+			u8 data_c[2] = { 0x06, 0x14 };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x1b, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x40, 0x00, 0x6a, 0xaa,
+				0x80, 0x00, 0x00, 0xe6, 0x66
+			};
+			u8 data_b[9] = { 0x48, 0x97, 0x78, 0xfc,
+				0x91, 0x2f, 0x01, 0x05, 0x55
+			};
+			u8 data_c[9] = { 0x4a, 0xaa, 0x7c, 0x71,
+				0x95, 0x55, 0x01, 0x0c, 0xcc
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, data, 9);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	case CXD2880_DTV_BW_1_7_MHZ:
+
+		{
+			u8 data_a[6] = { 0x68, 0x0f, 0xa2, 0x32,
+				0xcf, 0x03
+			};
+			u8 data_c[6] = { 0x68, 0x0f, 0xa2, 0x32,
+				0xcf, 0x03
+			};
+			u8 data_b[6] = { 0x65, 0x2b, 0xa4, 0xcd,
+				0xd8, 0x03
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x10, data, 6);
+			if (ret)
+				return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x4a, 0x03);
+		if (ret)
+			return ret;
+
+		{
+			u8 data[2] = { 0x3f, 0xff };
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x19, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		{
+			u8 data_a[2] = { 0x06, 0x0c };
+			u8 data_b[2] = { 0x06, 0x0c };
+			u8 data_c[2] = { 0x06, 0x0b };
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x1b, data, 2);
+			if (ret)
+				return ret;
+		}
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+			u8 data_a[9] = { 0x40, 0x00, 0x6a, 0xaa,
+				0x80, 0x00, 0x02, 0xc9, 0x8f
+			};
+			u8 data_b[9] = { 0x48, 0x97, 0x78, 0xfc,
+				0x91, 0x2f, 0x03, 0x29, 0x5d
+			};
+			u8 data_c[9] = { 0x4a, 0xaa, 0x7c, 0x71,
+				0x95, 0x55, 0x03, 0x40, 0x7d
+			};
+			u8 *data = NULL;
+
+			switch (clk_mode) {
+			case CXD2880_TNRDMD_CLOCKMODE_A:
+				data = data_a;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_B:
+				data = data_b;
+				break;
+			case CXD2880_TNRDMD_CLOCKMODE_C:
+				data = data_c;
+				break;
+			default:
+				return -EPERM;
+			}
+
+			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+						      CXD2880_IO_TGT_DMD,
+						      0x4b, data, 9);
+			if (ret)
+				return ret;
+		}
+		break;
+
+	default:
+		return -EPERM;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x00);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xfd, 0x01);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd
+				       *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		u8 data[] = { 0, 1, 0, 2,
+			0, 4, 0, 8, 0, 16, 0, 32
+		};
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x1d);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x47, data, 12);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
+			     enum cxd2880_dvbt2_profile profile)
+{
+	u8 t2_mode_tune_mode = 0;
+	u8 seq_not2_dtime = 0;
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	{
+		u8 dtime1 = 0;
+		u8 dtime2 = 0;
+
+		switch (tnr_dmd->clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			dtime1 = 0x27;
+			dtime2 = 0x0c;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			dtime1 = 0x2c;
+			dtime2 = 0x0d;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			dtime1 = 0x2e;
+			dtime2 = 0x0e;
+			break;
+		default:
+			return -EPERM;
+		}
+
+		switch (profile) {
+		case CXD2880_DVBT2_PROFILE_BASE:
+			t2_mode_tune_mode = 0x01;
+			seq_not2_dtime = dtime2;
+			break;
+
+		case CXD2880_DVBT2_PROFILE_LITE:
+			t2_mode_tune_mode = 0x05;
+			seq_not2_dtime = dtime1;
+			break;
+
+		case CXD2880_DVBT2_PROFILE_ANY:
+			t2_mode_tune_mode = 0x00;
+			seq_not2_dtime = dtime1;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x2e);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x10, t2_mode_tune_mode);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x04);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x2c, seq_not2_dtime);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+			       struct cxd2880_dvbt2_tune_param
+			       *tune_param)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) &&
+	    (tune_param->profile == CXD2880_DVBT2_PROFILE_ANY))
+		return -EOPNOTSUPP;
+
+	ret =
+	    cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2,
+						tune_param->center_freq_khz,
+						tune_param->bandwidth, 0, 0);
+	if (ret)
+		return ret;
+
+	ret =
+	    x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth,
+				       tnr_dmd->clk_mode);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret =
+		    x_tune_dvbt2_demod_setting(tnr_dmd->diver_sub,
+					       tune_param->bandwidth,
+					       tnr_dmd->diver_sub->clk_mode);
+		if (ret)
+			return ret;
+	}
+
+	ret = dvbt2_set_profile(tnr_dmd, tune_param->profile);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret =
+		    dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile);
+		if (ret)
+			return ret;
+	}
+
+	if (tune_param->data_plp_id == CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO) {
+		ret = cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 1, 0);
+		if (ret)
+			return ret;
+	} else {
+		ret =
+		    cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0,
+					     (u8)(tune_param->data_plp_id));
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+			       struct cxd2880_dvbt2_tune_param
+			       *tune_param)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	{
+		u8 en_fef_intmtnt_ctrl = 1;
+
+		switch (tune_param->profile) {
+		case CXD2880_DVBT2_PROFILE_BASE:
+			en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_base;
+			break;
+		case CXD2880_DVBT2_PROFILE_LITE:
+			en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_lite;
+			break;
+		case CXD2880_DVBT2_PROFILE_ANY:
+			if (tnr_dmd->en_fef_intmtnt_base &&
+			    tnr_dmd->en_fef_intmtnt_lite)
+				en_fef_intmtnt_ctrl = 1;
+			else
+				en_fef_intmtnt_ctrl = 0;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		ret =
+		    cxd2880_tnrdmd_common_tune_setting2(tnr_dmd,
+							CXD2880_DTV_SYS_DVBT2,
+							en_fef_intmtnt_ctrl);
+		if (ret)
+			return ret;
+	}
+
+	tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
+	tnr_dmd->frequency_khz = tune_param->center_freq_khz;
+	tnr_dmd->sys = CXD2880_DTV_SYS_DVBT2;
+	tnr_dmd->bandwidth = tune_param->bandwidth;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
+		tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
+		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT2;
+		tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
+				       *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = x_sleep_dvbt2_demod_setting(tnr_dmd);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
+		ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
+					  *tnr_dmd,
+					  enum
+					  cxd2880_tnrdmd_lock_result
+					  *lock)
+{
+	int ret = 0;
+
+	u8 sync_stat = 0;
+	u8 ts_lock = 0;
+	u8 unlock_detected = 0;
+	u8 unlock_detected_sub = 0;
+
+	if ((!tnr_dmd) || (!lock))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+					       &unlock_detected);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (sync_stat == 6)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		else if (unlock_detected)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+		else
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+		return ret;
+	}
+
+	if (sync_stat == 6) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		return ret;
+	}
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+						   &unlock_detected_sub);
+	if (ret)
+		return ret;
+
+	if (sync_stat == 6)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+	else if (unlock_detected && unlock_detected_sub)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+	else
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
+				       *tnr_dmd,
+				       enum
+				       cxd2880_tnrdmd_lock_result
+				       *lock)
+{
+	int ret = 0;
+
+	u8 sync_stat = 0;
+	u8 ts_lock = 0;
+	u8 unlock_detected = 0;
+	u8 unlock_detected_sub = 0;
+
+	if ((!tnr_dmd) || (!lock))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
+					       &unlock_detected);
+	if (ret)
+		return ret;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		if (ts_lock)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		else if (unlock_detected)
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+		else
+			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+		return ret;
+	}
+
+	if (ts_lock) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
+		return ret;
+	} else if (!unlock_detected) {
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+		return ret;
+	}
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
+						   &unlock_detected_sub);
+	if (ret)
+		return ret;
+
+	if (unlock_detected && unlock_detected_sub)
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
+	else
+		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
+				     *tnr_dmd, u8 auto_plp,
+				     u8 plp_id)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x23);
+	if (ret)
+		return ret;
+
+	if (!auto_plp) {
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xaf, plp_id);
+		if (ret)
+			return ret;
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0xad, auto_plp ? 0x00 : 0x01);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
+					   *tnr_dmd)
+{
+	int ret = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE)
+		return 0;
+
+	{
+		struct cxd2880_dvbt2_ofdm ofdm;
+
+		ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm);
+		if (ret)
+			return ret;
+
+		if (!ofdm.mixed)
+			return 0;
+	}
+
+	{
+		u8 data[] = { 0, 8, 0, 16,
+			0, 32, 0, 64, 0, 128, 1, 0
+		};
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x1d);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
+					      CXD2880_IO_TGT_DMD,
+					      0x47, data, 12);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
+					    *tnr_dmd,
+					    u8 *l1_post_valid)
+{
+	int ret = 0;
+
+	u8 data;
+
+	if ((!tnr_dmd) || (!l1_post_valid))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x86, &data, 1);
+	if (ret)
+		return ret;
+
+	*l1_post_valid = data & 0x01;
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
new file mode 100644
index 000000000000..409685425b53
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
@@ -0,0 +1,82 @@
+/*
+ * cxd2880_tnrdmd_dvbt2.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * control interface for DVB-T2
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT2_H
+#define CXD2880_TNRDMD_DVBT2_H
+
+#include "cxd2880_common.h"
+#include "cxd2880_tnrdmd.h"
+
+enum cxd2880_tnrdmd_dvbt2_tune_info {
+	CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK,
+	CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID
+};
+
+struct cxd2880_dvbt2_tune_param {
+	u32 center_freq_khz;
+	enum cxd2880_dtv_bandwidth bandwidth;
+	u16 data_plp_id;
+	enum cxd2880_dvbt2_profile profile;
+	enum cxd2880_tnrdmd_dvbt2_tune_info tune_info;
+};
+
+#define CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO  0xffff
+
+int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
+			       struct cxd2880_dvbt2_tune_param
+			       *tune_param);
+
+int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
+			       struct cxd2880_dvbt2_tune_param
+			       *tune_param);
+
+int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
+				       *tnr_dmd);
+
+int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
+					  *tnr_dmd,
+					  enum
+					  cxd2880_tnrdmd_lock_result
+					  *lock);
+
+int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
+				       *tnr_dmd,
+				       enum
+				       cxd2880_tnrdmd_lock_result
+				       *lock);
+
+int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
+				     *tnr_dmd, u8 auto_plp,
+				     u8 plp_id);
+
+int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
+					   *tnr_dmd);
+
+int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
+					    *tnr_dmd,
+					    u8 *l1_post_valid);
+
+#endif
-- 
2.13.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 11/14] [media] cxd2880: Add DVB-T2 monitor and integration layer functions
@ 2017-08-16  4:43   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:43 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

Provide monitor and integration layer functions (DVB-T2)
for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
      -changed CXD2880_SLEEP to usleep_range
      -replaced cxd2880_atomic_set to atomic_set
      -modified return code
      -modified coding style of if()  
   drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
      -modified return code
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
      -removed unnecessary cast
      -changed cxd2880_math_log to intlog10
      -modified return code
      -modified coding style of if() 
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
      -modified return code

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c    |  312 +++
 .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h    |   64 +
 .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.c             | 2622 ++++++++++++++++++++
 .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.h             |  170 ++
 4 files changed, 3168 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
new file mode 100644
index 000000000000..ac049820d797
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
@@ -0,0 +1,312 @@
+/*
+ * cxd2880_integ_dvbt2.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer functions for DVB-T2
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+#include "cxd2880_integ_dvbt2.h"
+
+static int dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd,
+				 enum cxd2880_dvbt2_profile
+				 profile);
+
+static int dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd,
+			     struct cxd2880_dvbt2_tune_param
+			     *tune_param)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	atomic_set(&tnr_dmd->cancel, 0);
+
+	if ((tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ)) {
+		return -EOPNOTSUPP;
+	}
+
+	if ((tune_param->profile != CXD2880_DVBT2_PROFILE_BASE) &&
+	    (tune_param->profile != CXD2880_DVBT2_PROFILE_LITE))
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param);
+	if (ret)
+		return ret;
+
+	usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000,
+		     CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000);
+
+	ret = cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param);
+	if (ret)
+		return ret;
+
+	ret = dvbt2_wait_demod_lock(tnr_dmd, tune_param->profile);
+	if (ret)
+		return ret;
+
+	ret = cxd2880_tnrdmd_dvbt2_diver_fef_setting(tnr_dmd);
+	if (ret == -EBUSY)
+		return -EAGAIN;
+	else if (ret)
+		return ret;
+
+	ret = dvbt2_wait_l1_post_lock(tnr_dmd);
+	if (ret)
+		return ret;
+
+	{
+		u8 plp_not_found;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_data_plp_error(tnr_dmd,
+							    &plp_not_found);
+		if (ret == -EBUSY)
+			return -EAGAIN;
+		else if (ret)
+			return ret;
+
+		if (plp_not_found) {
+			ret = -0;
+			tune_param->tune_info =
+			    CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID;
+		} else {
+			tune_param->tune_info =
+			    CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK;
+		}
+	}
+
+	return ret;
+}
+
+int cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dvbt2_profile
+				     profile)
+{
+	int ret = 0;
+	enum cxd2880_tnrdmd_lock_result lock =
+	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+	u16 timeout = 0;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	unsigned int elapsed = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret)
+		return ret;
+
+	if (profile == CXD2880_DVBT2_PROFILE_BASE)
+		timeout = CXD2880_DVBT2_BASE_WAIT_TS_LOCK;
+	else if (profile == CXD2880_DVBT2_PROFILE_LITE)
+		timeout = CXD2880_DVBT2_LITE_WAIT_TS_LOCK;
+	else
+		return -EINVAL;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret)
+			return ret;
+
+		if (elapsed >= timeout)
+			continue_wait = 0;
+
+		ret = cxd2880_tnrdmd_dvbt2_check_ts_lock(tnr_dmd, &lock);
+		if (ret)
+			return ret;
+
+		switch (lock) {
+		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
+			return 0;
+
+		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
+			return -EAGAIN;
+
+		default:
+			break;
+		}
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
+			if (ret)
+				return ret;
+		} else {
+			ret = -ETIME;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd,
+				 enum cxd2880_dvbt2_profile
+				 profile)
+{
+	int ret = 0;
+	enum cxd2880_tnrdmd_lock_result lock =
+	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+	u16 timeout = 0;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	unsigned int elapsed = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret)
+		return ret;
+
+	if (profile == CXD2880_DVBT2_PROFILE_BASE)
+		timeout = CXD2880_DVBT2_BASE_WAIT_DMD_LOCK;
+	else if ((profile == CXD2880_DVBT2_PROFILE_LITE) ||
+		 (profile == CXD2880_DVBT2_PROFILE_ANY))
+		timeout = CXD2880_DVBT2_LITE_WAIT_DMD_LOCK;
+	else
+		return -EPERM;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret)
+			return ret;
+
+		if (elapsed >= timeout)
+			continue_wait = 0;
+
+		ret = cxd2880_tnrdmd_dvbt2_check_demod_lock(tnr_dmd, &lock);
+		if (ret)
+			return ret;
+
+		switch (lock) {
+		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
+			return 0;
+
+		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
+			return -EAGAIN;
+
+		default:
+			break;
+		}
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
+			if (ret)
+				return ret;
+		} else {
+			ret = -ETIME;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	unsigned int elapsed = 0;
+	u8 l1_post_valid;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret)
+		return ret;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret)
+			return ret;
+
+		if (elapsed >= CXD2880_DVBT2_L1POST_TIMEOUT)
+			continue_wait = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_check_l1post_valid(tnr_dmd,
+							    &l1_post_valid);
+		if (ret)
+			return ret;
+
+		if (l1_post_valid)
+			return 0;
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
+			if (ret)
+				return ret;
+		} else {
+			ret = -ETIME;
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
new file mode 100644
index 000000000000..c7b1df6306df
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
@@ -0,0 +1,64 @@
+/*
+ * cxd2880_integ_dvbt2.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer interface for DVB-T2
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_INTEG_DVBT2_H
+#define CXD2880_INTEG_DVBT2_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_integ.h"
+
+#define CXD2880_DVBT2_BASE_WAIT_DMD_LOCK     3500
+#define CXD2880_DVBT2_BASE_WAIT_TS_LOCK	1500
+#define CXD2880_DVBT2_LITE_WAIT_DMD_LOCK     5000
+#define CXD2880_DVBT2_LITE_WAIT_TS_LOCK	2300
+#define CXD2880_DVBT2_WAIT_LOCK_INTVL       10
+#define CXD2880_DVBT2_L1POST_TIMEOUT	   500
+
+struct cxd2880_integ_dvbt2_scan_param {
+	u32 start_frequency_khz;
+	u32 end_frequency_khz;
+	u32 step_frequency_khz;
+	enum cxd2880_dtv_bandwidth bandwidth;
+	enum cxd2880_dvbt2_profile t2_profile;
+};
+
+struct cxd2880_integ_dvbt2_scan_result {
+	u32 center_freq_khz;
+	int tune_result;
+	struct cxd2880_dvbt2_tune_param dvbt2_tune_param;
+};
+
+int cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd,
+			     struct cxd2880_dvbt2_tune_param
+			     *tune_param);
+
+int cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dvbt2_profile
+				     profile);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
new file mode 100644
index 000000000000..62ee5d540dff
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
@@ -0,0 +1,2622 @@
+/*
+ * cxd2880_tnrdmd_dvbt2_mon.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T2 monitor functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+
+#include "dvb_math.h"
+
+int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 *sync_stat,
+				       u8 *ts_lock_stat,
+				       u8 *unlock_detected)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret)
+		return ret;
+
+	{
+		u8 data;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x10, &data, sizeof(data));
+		if (ret)
+			return ret;
+
+		*sync_stat = data & 0x07;
+		*ts_lock_stat = ((data & 0x20) ? 1 : 0);
+		*unlock_detected = ((data & 0x10) ? 1 : 0);
+	}
+
+	if (*sync_stat == 0x07)
+		return -EBUSY;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
+					   *tnr_dmd,
+					   u8 *sync_stat,
+					   u8 *unlock_detected)
+{
+	u8 ts_lock_stat = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub, sync_stat,
+					       &ts_lock_stat, unlock_detected);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
+					    *tnr_dmd, int *offset)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!offset))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[4];
+		u32 ctl_val = 0;
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state != 6) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x30, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ctl_val =
+		    ((data[0] & 0x0f) << 24) | (data[1] << 16) | (data[2] << 8)
+		    | (data[3]);
+		*offset = cxd2880_convert2s_complement(ctl_val, 28);
+
+		switch (tnr_dmd->bandwidth) {
+		case CXD2880_DTV_BW_1_7_MHZ:
+			*offset = -1 * ((*offset) / 582);
+			break;
+		case CXD2880_DTV_BW_5_MHZ:
+		case CXD2880_DTV_BW_6_MHZ:
+		case CXD2880_DTV_BW_7_MHZ:
+		case CXD2880_DTV_BW_8_MHZ:
+			*offset =
+			    -1 * ((*offset) * tnr_dmd->bandwidth / 940);
+			break;
+		default:
+			return -EPERM;
+		}
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
+						cxd2880_tnrdmd
+						*tnr_dmd,
+						int *offset)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!offset))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub, offset);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
+				    struct cxd2880_dvbt2_l1pre
+				    *l1_pre)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!l1_pre))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[37];
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		u8 version = 0;
+		enum cxd2880_dvbt2_profile profile;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state < 5) {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
+				    (tnr_dmd, &sync_state, &unlock_detected);
+				if (ret) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return ret;
+				}
+
+				if (sync_state < 5) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return -EBUSY;
+				}
+			} else {
+				slvt_unfreeze_reg(tnr_dmd);
+				return -EBUSY;
+			}
+		}
+
+		ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x61, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+		slvt_unfreeze_reg(tnr_dmd);
+
+		l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0];
+		l1_pre->bw_ext = data[1] & 0x01;
+		l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07);
+		l1_pre->s2 = data[3] & 0x0f;
+		l1_pre->l1_rep = data[4] & 0x01;
+		l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07);
+		l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0f);
+		l1_pre->mod =
+		    (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0f);
+		l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03);
+		l1_pre->fec =
+		    (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03);
+		l1_pre->l1_post_size = (data[10] & 0x03) << 16;
+		l1_pre->l1_post_size |= (data[11]) << 8;
+		l1_pre->l1_post_size |= (data[12]);
+		l1_pre->l1_post_info_size = (data[13] & 0x03) << 16;
+		l1_pre->l1_post_info_size |= (data[14]) << 8;
+		l1_pre->l1_post_info_size |= (data[15]);
+		l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0f);
+		l1_pre->tx_id_availability = data[17];
+		l1_pre->cell_id = (data[18] << 8);
+		l1_pre->cell_id |= (data[19]);
+		l1_pre->network_id = (data[20] << 8);
+		l1_pre->network_id |= (data[21]);
+		l1_pre->sys_id = (data[22] << 8);
+		l1_pre->sys_id |= (data[23]);
+		l1_pre->num_frames = data[24];
+		l1_pre->num_symbols = (data[25] & 0x0f) << 8;
+		l1_pre->num_symbols |= data[26];
+		l1_pre->regen = data[27] & 0x07;
+		l1_pre->post_ext = data[28] & 0x01;
+		l1_pre->num_rf_freqs = data[29] & 0x07;
+		l1_pre->rf_idx = data[30] & 0x07;
+		version = (data[31] & 0x03) << 2;
+		version |= (data[32] & 0xc0) >> 6;
+		l1_pre->t2_version = (enum cxd2880_dvbt2_version)version;
+		l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5;
+		l1_pre->t2_base_lite = (data[32] & 0x10) >> 4;
+		l1_pre->crc32 = (data[33] << 24);
+		l1_pre->crc32 |= (data[34] << 16);
+		l1_pre->crc32 |= (data[35] << 8);
+		l1_pre->crc32 |= data[36];
+
+		if (profile == CXD2880_DVBT2_PROFILE_BASE) {
+			switch ((l1_pre->s2 >> 1)) {
+			case CXD2880_DVBT2_BASE_S2_M1K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M1K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M2K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M2K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M4K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M4K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT:
+			case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2:
+				l1_pre->fft_mode = CXD2880_DVBT2_M8K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M16K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M16K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT:
+			case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2:
+				l1_pre->fft_mode = CXD2880_DVBT2_M32K;
+				break;
+			default:
+				return -EBUSY;
+			}
+		} else if (profile == CXD2880_DVBT2_PROFILE_LITE) {
+			switch ((l1_pre->s2 >> 1)) {
+			case CXD2880_DVBT2_LITE_S2_M2K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M2K;
+				break;
+			case CXD2880_DVBT2_LITE_S2_M4K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M4K;
+				break;
+			case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT:
+			case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2:
+				l1_pre->fft_mode = CXD2880_DVBT2_M8K;
+				break;
+			case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT:
+			case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2:
+				l1_pre->fft_mode = CXD2880_DVBT2_M16K;
+				break;
+			default:
+				return -EBUSY;
+			}
+		} else {
+			return -EBUSY;
+		}
+
+		l1_pre->mixed = l1_pre->s2 & 0x01;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dvbt2_version
+				     *ver)
+{
+	int ret = 0;
+	u8 version = 0;
+
+	if ((!tnr_dmd) || (!ver))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[2];
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state < 5) {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
+				    (tnr_dmd, &sync_state, &unlock_detected);
+				if (ret) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return ret;
+				}
+
+				if (sync_state < 5) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return -EBUSY;
+				}
+			} else {
+				slvt_unfreeze_reg(tnr_dmd);
+				return -EBUSY;
+			}
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x80, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		version = ((data[0] & 0x03) << 2);
+		version |= ((data[1] & 0xc0) >> 6);
+		*ver = (enum cxd2880_dvbt2_version)version;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
+				  struct cxd2880_dvbt2_ofdm *ofdm)
+{
+	if ((!tnr_dmd) || (!ofdm))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[5];
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		int ret = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state != 6) {
+			slvt_unfreeze_reg(tnr_dmd);
+
+			ret = -EBUSY;
+
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN)
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_ofdm(
+					tnr_dmd->diver_sub, ofdm);
+
+			return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x1d, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ofdm->mixed = ((data[0] & 0x20) ? 1 : 0);
+		ofdm->is_miso = ((data[0] & 0x10) >> 4);
+		ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07);
+		ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4);
+		ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07);
+		ofdm->bw_ext = (data[2] & 0x10) >> 4;
+		ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0f);
+		ofdm->num_symbols = (data[3] << 8) | data[4];
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 *plp_ids,
+				       u8 *num_plps)
+{
+	if ((!tnr_dmd) || (!num_plps))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 l1_post_ok = 0;
+		int ret = 0;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret)
+			return ret;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x86, &l1_post_ok, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!(l1_post_ok & 0x01)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xc1, num_plps, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (*num_plps == 0) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EPERM;
+		}
+
+		if (!plp_ids) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return 0;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xc2,
+					     plp_ids,
+					     ((*num_plps > 62) ?
+					     62 : *num_plps));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (*num_plps > 62) {
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x00, 0x0c);
+			if (ret) {
+				slvt_unfreeze_reg(tnr_dmd);
+				return ret;
+			}
+
+			ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x10, plp_ids + 62,
+						     *num_plps - 62);
+			if (ret) {
+				slvt_unfreeze_reg(tnr_dmd);
+				return ret;
+			}
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+	}
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
+					*tnr_dmd,
+					enum
+					cxd2880_dvbt2_plp_btype
+					type,
+					struct cxd2880_dvbt2_plp
+					*plp_info)
+{
+	if ((!tnr_dmd) || (!plp_info))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[20];
+		u8 addr = 0;
+		u8 index = 0;
+		u8 l1_post_ok = 0;
+		int ret = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x86, &l1_post_ok, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!l1_post_ok) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		if (type == CXD2880_DVBT2_PLP_COMMON)
+			addr = 0xa9;
+		else
+			addr = 0x96;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     addr, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if ((type == CXD2880_DVBT2_PLP_COMMON) && (data[13] == 0))
+			return -EBUSY;
+
+		plp_info->id = data[index++];
+		plp_info->type =
+		    (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07);
+		plp_info->payload =
+		    (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1f);
+		plp_info->ff = data[index++] & 0x01;
+		plp_info->first_rf_idx = data[index++] & 0x07;
+		plp_info->first_frm_idx = data[index++];
+		plp_info->group_id = data[index++];
+		plp_info->plp_cr =
+		    (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07);
+		plp_info->constell =
+		    (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07);
+		plp_info->rot = data[index++] & 0x01;
+		plp_info->fec =
+		    (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03);
+		plp_info->num_blocks_max = (data[index++] & 0x03) << 8;
+		plp_info->num_blocks_max |= data[index++];
+		plp_info->frm_int = data[index++];
+		plp_info->til_len = data[index++];
+		plp_info->til_type = data[index++] & 0x01;
+
+		plp_info->in_band_a_flag = data[index++] & 0x01;
+		plp_info->rsvd = data[index++] << 8;
+		plp_info->rsvd |= data[index++];
+
+		plp_info->in_band_b_flag =
+		    (plp_info->rsvd & 0x8000) >> 15;
+		plp_info->plp_mode =
+		    (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000c) >>
+						  2);
+		plp_info->static_flag = (plp_info->rsvd & 0x0002) >> 1;
+		plp_info->static_padding_flag = plp_info->rsvd & 0x0001;
+		plp_info->rsvd = (plp_info->rsvd & 0x7ff0) >> 4;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
+					    *tnr_dmd,
+					    u8 *plp_error)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!plp_error))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	{
+		u8 data;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x86, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if ((data & 0x01) == 0x00) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xc0, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		*plp_error = data & 0x01;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 *l1_change)
+{
+	if ((!tnr_dmd) || (!l1_change))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data;
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		int ret = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state < 5) {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
+				    (tnr_dmd, &sync_state, &unlock_detected);
+				if (ret) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return ret;
+				}
+
+				if (sync_state < 5) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return -EBUSY;
+				}
+			} else {
+				slvt_unfreeze_reg(tnr_dmd);
+				return -EBUSY;
+			}
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x5f, &data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		*l1_change = data & 0x01;
+		if (*l1_change) {
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x00, 0x22);
+			if (ret) {
+				slvt_unfreeze_reg(tnr_dmd);
+				return ret;
+			}
+
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x16, 0x01);
+			if (ret) {
+				slvt_unfreeze_reg(tnr_dmd);
+				return ret;
+			}
+		}
+		slvt_unfreeze_reg(tnr_dmd);
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     struct cxd2880_dvbt2_l1post
+				     *l1_post)
+{
+	if ((!tnr_dmd) || (!l1_post))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[16];
+		int ret = 0;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x86, data, sizeof(data));
+		if (ret)
+			return ret;
+
+		if (!(data[0] & 0x01))
+			return -EBUSY;
+
+		l1_post->sub_slices_per_frame = (data[1] & 0x7f) << 8;
+		l1_post->sub_slices_per_frame |= data[2];
+		l1_post->num_plps = data[3];
+		l1_post->num_aux = data[4] & 0x0f;
+		l1_post->aux_cfg_rfu = data[5];
+		l1_post->rf_idx = data[6] & 0x07;
+		l1_post->freq = data[7] << 24;
+		l1_post->freq |= data[8] << 16;
+		l1_post->freq |= data[9] << 8;
+		l1_post->freq |= data[10];
+		l1_post->fef_type = data[11] & 0x0f;
+		l1_post->fef_length = data[12] << 16;
+		l1_post->fef_length |= data[13] << 8;
+		l1_post->fef_length |= data[14];
+		l1_post->fef_intvl = data[15];
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
+				      *tnr_dmd,
+				      enum cxd2880_dvbt2_plp_btype
+				      type,
+				      struct cxd2880_dvbt2_bbheader
+				      *bbheader)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!bbheader))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	{
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!ts_lock) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if (type == CXD2880_DVBT2_PLP_COMMON) {
+		u8 l1_post_ok;
+		u8 data;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x86, &l1_post_ok, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!(l1_post_ok & 0x01)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xb6, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (data == 0) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+	}
+
+	{
+		u8 data[14];
+		u8 addr = 0;
+
+		if (type == CXD2880_DVBT2_PLP_COMMON)
+			addr = 0x51;
+		else
+			addr = 0x42;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     addr, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		bbheader->stream_input =
+		    (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03);
+		bbheader->is_single_input_stream = (data[0] >> 5) & 0x01;
+		bbheader->is_constant_coding_modulation =
+		    (data[0] >> 4) & 0x01;
+		bbheader->issy_indicator = (data[0] >> 3) & 0x01;
+		bbheader->null_packet_deletion = (data[0] >> 2) & 0x01;
+		bbheader->ext = data[0] & 0x03;
+
+		bbheader->input_stream_identifier = data[1];
+		bbheader->plp_mode =
+		    (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM :
+		    CXD2880_DVBT2_PLP_MODE_NM;
+		bbheader->data_field_length = (data[4] << 8) | data[5];
+
+		if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
+			bbheader->user_packet_length =
+			    (data[6] << 8) | data[7];
+			bbheader->sync_byte = data[8];
+			bbheader->issy = 0;
+		} else {
+			bbheader->user_packet_length = 0;
+			bbheader->sync_byte = 0;
+			bbheader->issy =
+			    (data[11] << 16) | (data[12] << 8) | data[13];
+		}
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
+					      *tnr_dmd,
+					      enum
+					      cxd2880_dvbt2_plp_btype
+					      type,
+					      u32 *ts_rate_bps)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ts_rate_bps))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	{
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!ts_lock) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	{
+		u8 l1_post_ok = 0;
+		u8 addr = 0;
+		u8 data = 0;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x86, &l1_post_ok, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!(l1_post_ok & 0x01)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		if (type == CXD2880_DVBT2_PLP_COMMON)
+			addr = 0xba;
+		else
+			addr = 0xa7;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     addr, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if ((data & 0x80) == 0x00) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x25);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	{
+		u8 data[4];
+		u8 addr = 0;
+
+		if (type == CXD2880_DVBT2_PLP_COMMON)
+			addr = 0xa6;
+		else
+			addr = 0xaa;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     addr, &data[0], 4);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		*ts_rate_bps = ((data[0] & 0x07) << 24) | (data[1] << 16) |
+			       (data[2] << 8) | data[3];
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
+					    *tnr_dmd,
+					    enum
+					    cxd2880_tnrdmd_spectrum_sense
+					    *sense)
+{
+	int ret = 0;
+	u8 sync_state = 0;
+	u8 ts_lock = 0;
+	u8 early_unlock = 0;
+
+	if ((!tnr_dmd) || (!sense))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock,
+					       &early_unlock);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if (sync_state != 6) {
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ret = -EBUSY;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+			ret =
+			    cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(
+				tnr_dmd->diver_sub, sense);
+
+		return ret;
+	}
+
+	{
+		u8 data = 0;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x2f, &data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		*sense =
+		    (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
+		    CXD2880_TNRDMD_SPECTRUM_NORMAL;
+	}
+
+	return 0;
+}
+
+static int dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
+			      u16 *reg_value)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!reg_value))
+		return -EINVAL;
+
+	{
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		u8 data[2];
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state != 6) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x13, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		*reg_value = (data[0] << 8) | data[1];
+	}
+
+	return ret;
+}
+
+static int dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
+			  u32 reg_value, int *snr)
+{
+	if ((!tnr_dmd) || (!snr))
+		return -EINVAL;
+
+	if (reg_value == 0)
+		return -EBUSY;
+
+	if (reg_value > 10876)
+		reg_value = 10876;
+
+	*snr = intlog10(reg_value) - intlog10(12600 - reg_value);
+	*snr = (*snr + 839) / 1678 + 32000;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+				 int *snr)
+{
+	u16 reg_value = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!snr))
+		return -EINVAL;
+
+	*snr = -1000 * 1000;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
+		if (ret)
+			return ret;
+
+		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr);
+		if (ret)
+			return ret;
+	} else {
+		int snr_main = 0;
+		int snr_sub = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main,
+						       &snr_sub);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
+				       *tnr_dmd, int *snr,
+				       int *snr_main, int *snr_sub)
+{
+	u16 reg_value = 0;
+	u32 reg_value_sum = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub))
+		return -EINVAL;
+
+	*snr = -1000 * 1000;
+	*snr_main = -1000 * 1000;
+	*snr_sub = -1000 * 1000;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
+	if (!ret) {
+		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main);
+		if (ret)
+			reg_value = 0;
+	} else if (ret == -EBUSY) {
+		reg_value = 0;
+	} else {
+		return ret;
+	}
+
+	reg_value_sum += reg_value;
+
+	ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
+	if (!ret) {
+		ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
+		if (ret)
+			reg_value = 0;
+	} else if (ret == -EBUSY) {
+		reg_value = 0;
+	} else {
+		return ret;
+	}
+
+	reg_value_sum += reg_value;
+
+	ret = dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd
+					 *tnr_dmd, u32 *ber)
+{
+	int ret = 0;
+	u32 bit_error = 0;
+	u32 period_exp = 0;
+	u32 n_ldpc = 0;
+
+	if ((!tnr_dmd) || (!ber))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	{
+		u8 data[5];
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x3c, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!(data[0] & 0x01)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		bit_error =
+		    ((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8)
+		    | data[4];
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xa0, data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) ==
+		    CXD2880_DVBT2_FEC_LDPC_16K)
+			n_ldpc = 16200;
+		else
+			n_ldpc = 64800;
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x20);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x6f, data, 1);
+		if (ret)
+			return ret;
+
+		period_exp = data[0] & 0x0f;
+	}
+
+	if (bit_error > ((1U << period_exp) * n_ldpc))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		if (period_exp >= 4) {
+			div = (1U << (period_exp - 4)) * (n_ldpc / 200);
+
+			Q = (bit_error * 5) / div;
+			R = (bit_error * 5) % div;
+
+			R *= 625;
+			Q = Q * 625 + R / div;
+			R = R % div;
+		} else {
+			div = (1U << period_exp) * (n_ldpc / 200);
+
+			Q = (bit_error * 10) / div;
+			R = (bit_error * 10) % div;
+
+			R *= 5000;
+			Q = Q * 5000 + R / div;
+			R = R % div;
+		}
+
+		if (div / 2 <= R)
+			*ber = Q + 1;
+		else
+			*ber = Q;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd
+					 *tnr_dmd, u32 *fer)
+{
+	int ret = 0;
+	u32 fec_error = 0;
+	u32 period = 0;
+
+	if ((!tnr_dmd) || (!fer))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret)
+		return ret;
+
+	{
+		u8 data[2];
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x1b, data, 2);
+		if (ret)
+			return ret;
+
+		if (!(data[0] & 0x80))
+			return -EBUSY;
+
+		fec_error = ((data[0] & 0x7f) << 8) | (data[1]);
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x20);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x72, data, 1);
+		if (ret)
+			return ret;
+
+		period = (1 << (data[0] & 0x0f));
+	}
+
+	if ((period == 0) || (fec_error > period))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		div = period;
+
+		Q = (fec_error * 1000) / div;
+		R = (fec_error * 1000) % div;
+
+		R *= 1000;
+		Q = Q * 1000 + R / div;
+		R = R % div;
+
+		if ((div != 1) && (div / 2 <= R))
+			*fer = Q + 1;
+		else
+			*fer = Q;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd
+					*tnr_dmd, u32 *ber)
+{
+	int ret = 0;
+	u32 bit_error = 0;
+	u32 period_exp = 0;
+	u32 n_bch = 0;
+
+	if ((!tnr_dmd) || (!ber))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[3];
+		enum cxd2880_dvbt2_plp_fec plp_fec_type =
+		    CXD2880_DVBT2_FEC_LDPC_16K;
+		enum cxd2880_dvbt2_plp_code_rate plp_cr = CXD2880_DVBT2_R1_2;
+
+		static const u16 n_bch_bits_lookup[2][8] = {
+			{7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480},
+			{32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920}
+		};
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x15, data, 3);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!(data[0] & 0x40)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		bit_error = ((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2];
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x9d, data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		plp_cr = (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07);
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xa0, data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03);
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x20);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x72, data, 1);
+		if (ret)
+			return ret;
+
+		period_exp = data[0] & 0x0f;
+
+		if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) ||
+		    (plp_cr > CXD2880_DVBT2_R2_5))
+			return -EBUSY;
+
+		n_bch = n_bch_bits_lookup[plp_fec_type][plp_cr];
+	}
+
+	if (bit_error > ((1U << period_exp) * n_bch))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		if (period_exp >= 6) {
+			div = (1U << (period_exp - 6)) * (n_bch / 40);
+
+			Q = (bit_error * 625) / div;
+			R = (bit_error * 625) % div;
+
+			R *= 625;
+			Q = Q * 625 + R / div;
+			R = R % div;
+		} else {
+			div = (1U << period_exp) * (n_bch / 40);
+
+			Q = (bit_error * 1000) / div;
+			R = (bit_error * 1000) % div;
+
+			R *= 25000;
+			Q = Q * 25000 + R / div;
+			R = R % div;
+		}
+
+		if (div / 2 <= R)
+			*ber = Q + 1;
+		else
+			*ber = Q;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
+						 cxd2880_tnrdmd
+						 *tnr_dmd,
+						 u32 *pen)
+{
+	int ret = 0;
+
+	u8 data[3];
+
+	if ((!tnr_dmd) || (!pen))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x39, data, sizeof(data));
+	if (ret)
+		return ret;
+
+	if (!(data[0] & 0x01))
+		return -EBUSY;
+
+	*pen = ((data[1] << 8) | data[2]);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
+					     *tnr_dmd, int *ppm)
+{
+	if ((!tnr_dmd) || (!ppm))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 ctl_val_reg[5];
+		u8 nominal_rate_reg[5];
+		u32 trl_ctl_val = 0;
+		u32 trcg_nominal_rate = 0;
+		int num;
+		int den;
+		int ret = 0;
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		s8 diff_upper = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state != 6) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x34, ctl_val_reg,
+					     sizeof(ctl_val_reg));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x04);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x10, nominal_rate_reg,
+					     sizeof(nominal_rate_reg));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		diff_upper =
+		    (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
+
+		if ((diff_upper < -1) || (diff_upper > 1))
+			return -EBUSY;
+
+		trl_ctl_val = ctl_val_reg[1] << 24;
+		trl_ctl_val |= ctl_val_reg[2] << 16;
+		trl_ctl_val |= ctl_val_reg[3] << 8;
+		trl_ctl_val |= ctl_val_reg[4];
+
+		trcg_nominal_rate = nominal_rate_reg[1] << 24;
+		trcg_nominal_rate |= nominal_rate_reg[2] << 16;
+		trcg_nominal_rate |= nominal_rate_reg[3] << 8;
+		trcg_nominal_rate |= nominal_rate_reg[4];
+
+		trl_ctl_val >>= 1;
+		trcg_nominal_rate >>= 1;
+
+		if (diff_upper == 1)
+			num =
+			    (int)((trl_ctl_val + 0x80000000u) -
+				  trcg_nominal_rate);
+		else if (diff_upper == -1)
+			num =
+			    -(int)((trcg_nominal_rate + 0x80000000u) -
+				   trl_ctl_val);
+		else
+			num = (int)(trl_ctl_val - trcg_nominal_rate);
+
+		den = (nominal_rate_reg[0] & 0x7f) << 24;
+		den |= nominal_rate_reg[1] << 16;
+		den |= nominal_rate_reg[2] << 8;
+		den |= nominal_rate_reg[3];
+		den = (den + (390625 / 2)) / 390625;
+
+		den >>= 1;
+
+		if (num >= 0)
+			*ppm = (num + (den / 2)) / den;
+		else
+			*ppm = (num - (den / 2)) / den;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
+						 cxd2880_tnrdmd
+						 *tnr_dmd,
+						 int *ppm)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ppm))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd
+				     *tnr_dmd, u8 *quality)
+{
+	int ret = 0;
+	int snr = 0;
+	int snr_rel = 0;
+	u32 ber = 0;
+	u32 ber_sqi = 0;
+	enum cxd2880_dvbt2_plp_constell qam;
+	enum cxd2880_dvbt2_plp_code_rate code_rate;
+
+	static const int snr_nordig_p1_db_1000[4][8] = {
+		{3500, 4700, 5600, 6600, 7200, 7700, 1300, 2200},
+		{8700, 10100, 11400, 12500, 13300, 13800, 6000, 7200},
+		{13000, 14800, 16200, 17700, 18700, 19400, 9800, 11100},
+		{17000, 19400, 20800, 22900, 24300, 25100, 13200, 14800},
+	};
+
+	if ((!tnr_dmd) || (!quality))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(tnr_dmd, &ber);
+	if (ret)
+		return ret;
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_snr(tnr_dmd, &snr);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
+					       &code_rate);
+	if (ret)
+		return ret;
+
+	if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256))
+		return -EPERM;
+
+	if (ber > 100000)
+		ber_sqi = 0;
+	else if (ber >= 100)
+		ber_sqi = 6667;
+	else
+		ber_sqi = 16667;
+
+	snr_rel = snr - snr_nordig_p1_db_1000[qam][code_rate];
+
+	if (snr_rel < -3000) {
+		*quality = 0;
+	} else if (snr_rel <= 3000) {
+		u32 temp_sqi =
+		    (((snr_rel + 3000) * ber_sqi) + 500000) / 1000000;
+		*quality = (temp_sqi > 100) ? 100 : (u8)temp_sqi;
+	} else {
+		*quality = 100;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd
+				     *tnr_dmd, u32 *ts_rate_kbps)
+{
+	int ret = 0;
+	u32 rd_smooth_dp = 0;
+	u32 ep_ck_nume = 0;
+	u32 ep_ck_deno = 0;
+	u8 issy_on_data = 0;
+
+	if ((!tnr_dmd) || (!ts_rate_kbps))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[12];
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!ts_lock) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x23, data, 12);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		rd_smooth_dp = (data[0] & 0x1f) << 24;
+		rd_smooth_dp |= data[1] << 16;
+		rd_smooth_dp |= data[2] << 8;
+		rd_smooth_dp |= data[3];
+
+		if (rd_smooth_dp < 214958) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ep_ck_nume = (data[4] & 0x3f) << 24;
+		ep_ck_nume |= data[5] << 16;
+		ep_ck_nume |= data[6] << 8;
+		ep_ck_nume |= data[7];
+
+		ep_ck_deno = (data[8] & 0x3f) << 24;
+		ep_ck_deno |= data[9] << 16;
+		ep_ck_deno |= data[10] << 8;
+		ep_ck_deno |= data[11];
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x41, data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		issy_on_data = data[0] & 0x01;
+
+		slvt_unfreeze_reg(tnr_dmd);
+	}
+
+	if (issy_on_data) {
+		if ((ep_ck_deno == 0) || (ep_ck_nume == 0) ||
+		    (ep_ck_deno >= ep_ck_nume))
+			return -EBUSY;
+	}
+
+	{
+		u32 ick_x100;
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		switch (tnr_dmd->clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			ick_x100 = 8228;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			ick_x100 = 9330;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			ick_x100 = 9600;
+			break;
+		default:
+			return -EPERM;
+		}
+
+		div = rd_smooth_dp;
+
+		Q = ick_x100 * 262144U / div;
+		R = ick_x100 * 262144U % div;
+
+		R *= 5U;
+		Q = Q * 5 + R / div;
+		R = R % div;
+
+		R *= 2U;
+		Q = Q * 2 + R / div;
+		R = R % div;
+
+		if (div / 2 <= R)
+			*ts_rate_kbps = Q + 1;
+		else
+			*ts_rate_kbps = Q;
+	}
+
+	if (issy_on_data) {
+		u32 diff = ep_ck_nume - ep_ck_deno;
+
+		while (diff > 0x7fff) {
+			diff >>= 1;
+			ep_ck_nume >>= 1;
+		}
+
+		*ts_rate_kbps -=
+		    (*ts_rate_kbps * diff + ep_ck_nume / 2) / ep_ck_nume;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
+				 u32 *per)
+{
+	int ret = 0;
+	u32 packet_error = 0;
+	u32 period = 0;
+
+	if (!tnr_dmd || !per)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 rdata[3];
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x18, rdata, 3);
+		if (ret)
+			return ret;
+
+		if ((rdata[0] & 0x01) == 0)
+			return -EBUSY;
+
+		packet_error = (rdata[1] << 8) | rdata[2];
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x24);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xdc, rdata, 1);
+		if (ret)
+			return ret;
+
+		period = 1U << (rdata[0] & 0x0f);
+	}
+
+	if ((period == 0) || (packet_error > period))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		div = period;
+
+		Q = (packet_error * 1000) / div;
+		R = (packet_error * 1000) % div;
+
+		R *= 1000;
+		Q = Q * 1000 + R / div;
+		R = R % div;
+
+		if ((div != 1) && (div / 2 <= R))
+			*per = Q + 1;
+		else
+			*per = Q;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
+				 enum cxd2880_dvbt2_plp_btype type,
+				 enum cxd2880_dvbt2_plp_constell *qam)
+{
+	u8 data;
+	u8 l1_post_ok = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!qam))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x86, &l1_post_ok, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if (!(l1_post_ok & 0x01)) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return -EBUSY;
+	}
+
+	if (type == CXD2880_DVBT2_PLP_COMMON) {
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xb6, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (data == 0) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xb1, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+	} else {
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x9e, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
+				       *tnr_dmd,
+				       enum cxd2880_dvbt2_plp_btype
+				       type,
+				       enum
+				       cxd2880_dvbt2_plp_code_rate
+				       *code_rate)
+{
+	u8 data;
+	u8 l1_post_ok = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!code_rate))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x86, &l1_post_ok, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if (!(l1_post_ok & 0x01)) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return -EBUSY;
+	}
+
+	if (type == CXD2880_DVBT2_PLP_COMMON) {
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xb6, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (data == 0) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xb0, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+	} else {
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x9d, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dvbt2_profile
+				     *profile)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!profile))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret)
+		return ret;
+
+	{
+		u8 data;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x22, &data, sizeof(data));
+		if (ret)
+			return ret;
+
+		if (data & 0x02) {
+			if (data & 0x01)
+				*profile = CXD2880_DVBT2_PROFILE_LITE;
+			else
+				*profile = CXD2880_DVBT2_PROFILE_BASE;
+		} else {
+			ret = -EBUSY;
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN)
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_profile(
+					tnr_dmd->diver_sub, profile);
+
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int dvbt2_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+			  int rf_lvl, u8 *ssi)
+{
+	enum cxd2880_dvbt2_plp_constell qam;
+	enum cxd2880_dvbt2_plp_code_rate code_rate;
+	int prel;
+	int temp_ssi = 0;
+	int ret = 0;
+
+	static const int ref_dbm_1000[4][8] = {
+		{-96000, -95000, -94000, -93000, -92000, -92000, -98000,
+		 -97000},
+		{-91000, -89000, -88000, -87000, -86000, -86000, -93000,
+		 -92000},
+		{-86000, -85000, -83000, -82000, -81000, -80000, -89000,
+		 -88000},
+		{-82000, -80000, -78000, -76000, -75000, -74000, -86000,
+		 -84000},
+	};
+
+	if ((!tnr_dmd) || (!ssi))
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
+					       &code_rate);
+	if (ret)
+		return ret;
+
+	if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256))
+		return -EPERM;
+
+	prel = rf_lvl - ref_dbm_1000[qam][code_rate];
+
+	if (prel < -15000)
+		temp_ssi = 0;
+	else if (prel < 0)
+		temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
+	else if (prel < 20000)
+		temp_ssi = (((4 * prel) + 500) / 1000) + 10;
+	else if (prel < 35000)
+		temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
+	else
+		temp_ssi = 100;
+
+	*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+				 u8 *ssi)
+{
+	int rf_lvl = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ssi))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
+	if (ret)
+		return ret;
+
+	ret = dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
+				     *tnr_dmd, u8 *ssi)
+{
+	int rf_lvl = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ssi))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
+	if (ret)
+		return ret;
+
+	ret = dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
+	if (ret)
+		return ret;
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
new file mode 100644
index 000000000000..f7b2f618e80f
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
@@ -0,0 +1,170 @@
+/*
+ * cxd2880_tnrdmd_dvbt2_mon.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T2 monitor interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT2_MON_H
+#define CXD2880_TNRDMD_DVBT2_MON_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_dvbt2.h"
+
+int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 *sync_stat,
+				       u8 *ts_lock_stat,
+				       u8 *unlock_detected);
+
+int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
+					   *tnr_dmd,
+					   u8 *sync_stat,
+					   u8 *unlock_detected);
+
+int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
+					    *tnr_dmd, int *offset);
+
+int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
+						cxd2880_tnrdmd
+						*tnr_dmd,
+						int *offset);
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
+				    struct cxd2880_dvbt2_l1pre
+				    *l1_pre);
+
+int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dvbt2_version
+				     *ver);
+
+int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
+				  struct cxd2880_dvbt2_ofdm *ofdm);
+
+int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 *plp_ids,
+				       u8 *num_plps);
+
+int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
+					*tnr_dmd,
+					enum
+					cxd2880_dvbt2_plp_btype
+					type,
+					struct cxd2880_dvbt2_plp
+					*plp_info);
+
+int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
+					    *tnr_dmd,
+					    u8 *plp_error);
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 *l1_change);
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     struct cxd2880_dvbt2_l1post
+				     *l1_post);
+
+int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
+				      *tnr_dmd,
+				      enum cxd2880_dvbt2_plp_btype
+				      type,
+				      struct cxd2880_dvbt2_bbheader
+				      *bbheader);
+
+int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
+					      *tnr_dmd,
+					      enum
+					      cxd2880_dvbt2_plp_btype
+					      type,
+					      u32 *ts_rate_bps);
+
+int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
+					    *tnr_dmd,
+					    enum
+					    cxd2880_tnrdmd_spectrum_sense
+					    *sense);
+
+int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+				 int *snr);
+
+int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
+				       *tnr_dmd, int *snr,
+				       int *snr_main,
+				       int *snr_sub);
+
+int cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd
+					 *tnr_dmd, u32 *ber);
+
+int cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd
+					 *tnr_dmd, u32 *fer);
+
+int cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd
+					*tnr_dmd, u32 *ber);
+
+int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
+						 cxd2880_tnrdmd
+						 *tnr_dmd,
+						 u32 *pen);
+
+int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
+					     *tnr_dmd, int *ppm);
+
+int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
+						 cxd2880_tnrdmd
+						 *tnr_dmd,
+						 int *ppm);
+
+int cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd
+				     *tnr_dmd, u32 *ts_rate_kbps);
+
+int cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd
+				     *tnr_dmd, u8 *quality);
+
+int cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
+				 u32 *per);
+
+int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
+				 enum cxd2880_dvbt2_plp_btype type,
+				 enum cxd2880_dvbt2_plp_constell
+				 *qam);
+
+int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
+				       *tnr_dmd,
+				       enum cxd2880_dvbt2_plp_btype
+				       type,
+				       enum
+				       cxd2880_dvbt2_plp_code_rate
+				       *code_rate);
+
+int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dvbt2_profile
+				     *profile);
+
+int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+				 u8 *ssi);
+
+int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
+				     *tnr_dmd, u8 *ssi);
+
+#endif
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 11/14] [media] cxd2880: Add DVB-T2 monitor and integration layer functions
@ 2017-08-16  4:43   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-08-16  4:43 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

Provide monitor and integration layer functions (DVB-T2)
for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
      -changed CXD2880_SLEEP to usleep_range
      -replaced cxd2880_atomic_set to atomic_set
      -modified return code
      -modified coding style of if()  
   drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
      -modified return code
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
      -removed unnecessary cast
      -changed cxd2880_math_log to intlog10
      -modified return code
      -modified coding style of if() 
      -changed hexadecimal code to lower case. 
   drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
      -modified return code

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c    |  312 +++
 .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h    |   64 +
 .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.c             | 2622 ++++++++++++++++++++
 .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.h             |  170 ++
 4 files changed, 3168 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
 create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h

diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
new file mode 100644
index 000000000000..ac049820d797
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
@@ -0,0 +1,312 @@
+/*
+ * cxd2880_integ_dvbt2.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer functions for DVB-T2
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+#include "cxd2880_integ_dvbt2.h"
+
+static int dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd,
+				 enum cxd2880_dvbt2_profile
+				 profile);
+
+static int dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd);
+
+int cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd,
+			     struct cxd2880_dvbt2_tune_param
+			     *tune_param)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!tune_param))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
+	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
+		return -EPERM;
+
+	atomic_set(&tnr_dmd->cancel, 0);
+
+	if ((tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ) &&
+	    (tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ)) {
+		return -EOPNOTSUPP;
+	}
+
+	if ((tune_param->profile != CXD2880_DVBT2_PROFILE_BASE) &&
+	    (tune_param->profile != CXD2880_DVBT2_PROFILE_LITE))
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param);
+	if (ret)
+		return ret;
+
+	usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000,
+		     CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000);
+
+	ret = cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param);
+	if (ret)
+		return ret;
+
+	ret = dvbt2_wait_demod_lock(tnr_dmd, tune_param->profile);
+	if (ret)
+		return ret;
+
+	ret = cxd2880_tnrdmd_dvbt2_diver_fef_setting(tnr_dmd);
+	if (ret == -EBUSY)
+		return -EAGAIN;
+	else if (ret)
+		return ret;
+
+	ret = dvbt2_wait_l1_post_lock(tnr_dmd);
+	if (ret)
+		return ret;
+
+	{
+		u8 plp_not_found;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_data_plp_error(tnr_dmd,
+							    &plp_not_found);
+		if (ret == -EBUSY)
+			return -EAGAIN;
+		else if (ret)
+			return ret;
+
+		if (plp_not_found) {
+			ret = -0;
+			tune_param->tune_info =
+			    CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID;
+		} else {
+			tune_param->tune_info =
+			    CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK;
+		}
+	}
+
+	return ret;
+}
+
+int cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dvbt2_profile
+				     profile)
+{
+	int ret = 0;
+	enum cxd2880_tnrdmd_lock_result lock =
+	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+	u16 timeout = 0;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	unsigned int elapsed = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret)
+		return ret;
+
+	if (profile == CXD2880_DVBT2_PROFILE_BASE)
+		timeout = CXD2880_DVBT2_BASE_WAIT_TS_LOCK;
+	else if (profile == CXD2880_DVBT2_PROFILE_LITE)
+		timeout = CXD2880_DVBT2_LITE_WAIT_TS_LOCK;
+	else
+		return -EINVAL;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret)
+			return ret;
+
+		if (elapsed >= timeout)
+			continue_wait = 0;
+
+		ret = cxd2880_tnrdmd_dvbt2_check_ts_lock(tnr_dmd, &lock);
+		if (ret)
+			return ret;
+
+		switch (lock) {
+		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
+			return 0;
+
+		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
+			return -EAGAIN;
+
+		default:
+			break;
+		}
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
+			if (ret)
+				return ret;
+		} else {
+			ret = -ETIME;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd,
+				 enum cxd2880_dvbt2_profile
+				 profile)
+{
+	int ret = 0;
+	enum cxd2880_tnrdmd_lock_result lock =
+	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
+	u16 timeout = 0;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	unsigned int elapsed = 0;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret)
+		return ret;
+
+	if (profile == CXD2880_DVBT2_PROFILE_BASE)
+		timeout = CXD2880_DVBT2_BASE_WAIT_DMD_LOCK;
+	else if ((profile == CXD2880_DVBT2_PROFILE_LITE) ||
+		 (profile == CXD2880_DVBT2_PROFILE_ANY))
+		timeout = CXD2880_DVBT2_LITE_WAIT_DMD_LOCK;
+	else
+		return -EPERM;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret)
+			return ret;
+
+		if (elapsed >= timeout)
+			continue_wait = 0;
+
+		ret = cxd2880_tnrdmd_dvbt2_check_demod_lock(tnr_dmd, &lock);
+		if (ret)
+			return ret;
+
+		switch (lock) {
+		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
+			return 0;
+
+		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
+			return -EAGAIN;
+
+		default:
+			break;
+		}
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
+			if (ret)
+				return ret;
+		} else {
+			ret = -ETIME;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd)
+{
+	int ret = 0;
+	struct cxd2880_stopwatch timer;
+	u8 continue_wait = 1;
+	unsigned int elapsed = 0;
+	u8 l1_post_valid;
+
+	if (!tnr_dmd)
+		return -EINVAL;
+
+	ret = cxd2880_stopwatch_start(&timer);
+	if (ret)
+		return ret;
+
+	for (;;) {
+		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
+		if (ret)
+			return ret;
+
+		if (elapsed >= CXD2880_DVBT2_L1POST_TIMEOUT)
+			continue_wait = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_check_l1post_valid(tnr_dmd,
+							    &l1_post_valid);
+		if (ret)
+			return ret;
+
+		if (l1_post_valid)
+			return 0;
+
+		ret = cxd2880_integ_check_cancellation(tnr_dmd);
+		if (ret)
+			return ret;
+
+		if (continue_wait) {
+			ret =
+			    cxd2880_stopwatch_sleep(&timer,
+					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
+			if (ret)
+				return ret;
+		} else {
+			ret = -ETIME;
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
new file mode 100644
index 000000000000..c7b1df6306df
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
@@ -0,0 +1,64 @@
+/*
+ * cxd2880_integ_dvbt2.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * integration layer interface for DVB-T2
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_INTEG_DVBT2_H
+#define CXD2880_INTEG_DVBT2_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_integ.h"
+
+#define CXD2880_DVBT2_BASE_WAIT_DMD_LOCK     3500
+#define CXD2880_DVBT2_BASE_WAIT_TS_LOCK	1500
+#define CXD2880_DVBT2_LITE_WAIT_DMD_LOCK     5000
+#define CXD2880_DVBT2_LITE_WAIT_TS_LOCK	2300
+#define CXD2880_DVBT2_WAIT_LOCK_INTVL       10
+#define CXD2880_DVBT2_L1POST_TIMEOUT	   500
+
+struct cxd2880_integ_dvbt2_scan_param {
+	u32 start_frequency_khz;
+	u32 end_frequency_khz;
+	u32 step_frequency_khz;
+	enum cxd2880_dtv_bandwidth bandwidth;
+	enum cxd2880_dvbt2_profile t2_profile;
+};
+
+struct cxd2880_integ_dvbt2_scan_result {
+	u32 center_freq_khz;
+	int tune_result;
+	struct cxd2880_dvbt2_tune_param dvbt2_tune_param;
+};
+
+int cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd,
+			     struct cxd2880_dvbt2_tune_param
+			     *tune_param);
+
+int cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dvbt2_profile
+				     profile);
+
+#endif
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
new file mode 100644
index 000000000000..62ee5d540dff
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
@@ -0,0 +1,2622 @@
+/*
+ * cxd2880_tnrdmd_dvbt2_mon.c
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T2 monitor functions
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cxd2880_tnrdmd_mon.h"
+#include "cxd2880_tnrdmd_dvbt2.h"
+#include "cxd2880_tnrdmd_dvbt2_mon.h"
+
+#include "dvb_math.h"
+
+int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 *sync_stat,
+				       u8 *ts_lock_stat,
+				       u8 *unlock_detected)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret)
+		return ret;
+
+	{
+		u8 data;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x10, &data, sizeof(data));
+		if (ret)
+			return ret;
+
+		*sync_stat = data & 0x07;
+		*ts_lock_stat = ((data & 0x20) ? 1 : 0);
+		*unlock_detected = ((data & 0x10) ? 1 : 0);
+	}
+
+	if (*sync_stat == 0x07)
+		return -EBUSY;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
+					   *tnr_dmd,
+					   u8 *sync_stat,
+					   u8 *unlock_detected)
+{
+	u8 ts_lock_stat = 0;
+
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub, sync_stat,
+					       &ts_lock_stat, unlock_detected);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
+					    *tnr_dmd, int *offset)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!offset))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[4];
+		u32 ctl_val = 0;
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state != 6) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x30, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ctl_val =
+		    ((data[0] & 0x0f) << 24) | (data[1] << 16) | (data[2] << 8)
+		    | (data[3]);
+		*offset = cxd2880_convert2s_complement(ctl_val, 28);
+
+		switch (tnr_dmd->bandwidth) {
+		case CXD2880_DTV_BW_1_7_MHZ:
+			*offset = -1 * ((*offset) / 582);
+			break;
+		case CXD2880_DTV_BW_5_MHZ:
+		case CXD2880_DTV_BW_6_MHZ:
+		case CXD2880_DTV_BW_7_MHZ:
+		case CXD2880_DTV_BW_8_MHZ:
+			*offset =
+			    -1 * ((*offset) * tnr_dmd->bandwidth / 940);
+			break;
+		default:
+			return -EPERM;
+		}
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
+						cxd2880_tnrdmd
+						*tnr_dmd,
+						int *offset)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!offset))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub, offset);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
+				    struct cxd2880_dvbt2_l1pre
+				    *l1_pre)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!l1_pre))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[37];
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		u8 version = 0;
+		enum cxd2880_dvbt2_profile profile;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state < 5) {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
+				    (tnr_dmd, &sync_state, &unlock_detected);
+				if (ret) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return ret;
+				}
+
+				if (sync_state < 5) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return -EBUSY;
+				}
+			} else {
+				slvt_unfreeze_reg(tnr_dmd);
+				return -EBUSY;
+			}
+		}
+
+		ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x61, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+		slvt_unfreeze_reg(tnr_dmd);
+
+		l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0];
+		l1_pre->bw_ext = data[1] & 0x01;
+		l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07);
+		l1_pre->s2 = data[3] & 0x0f;
+		l1_pre->l1_rep = data[4] & 0x01;
+		l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07);
+		l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0f);
+		l1_pre->mod =
+		    (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0f);
+		l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03);
+		l1_pre->fec =
+		    (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03);
+		l1_pre->l1_post_size = (data[10] & 0x03) << 16;
+		l1_pre->l1_post_size |= (data[11]) << 8;
+		l1_pre->l1_post_size |= (data[12]);
+		l1_pre->l1_post_info_size = (data[13] & 0x03) << 16;
+		l1_pre->l1_post_info_size |= (data[14]) << 8;
+		l1_pre->l1_post_info_size |= (data[15]);
+		l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0f);
+		l1_pre->tx_id_availability = data[17];
+		l1_pre->cell_id = (data[18] << 8);
+		l1_pre->cell_id |= (data[19]);
+		l1_pre->network_id = (data[20] << 8);
+		l1_pre->network_id |= (data[21]);
+		l1_pre->sys_id = (data[22] << 8);
+		l1_pre->sys_id |= (data[23]);
+		l1_pre->num_frames = data[24];
+		l1_pre->num_symbols = (data[25] & 0x0f) << 8;
+		l1_pre->num_symbols |= data[26];
+		l1_pre->regen = data[27] & 0x07;
+		l1_pre->post_ext = data[28] & 0x01;
+		l1_pre->num_rf_freqs = data[29] & 0x07;
+		l1_pre->rf_idx = data[30] & 0x07;
+		version = (data[31] & 0x03) << 2;
+		version |= (data[32] & 0xc0) >> 6;
+		l1_pre->t2_version = (enum cxd2880_dvbt2_version)version;
+		l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5;
+		l1_pre->t2_base_lite = (data[32] & 0x10) >> 4;
+		l1_pre->crc32 = (data[33] << 24);
+		l1_pre->crc32 |= (data[34] << 16);
+		l1_pre->crc32 |= (data[35] << 8);
+		l1_pre->crc32 |= data[36];
+
+		if (profile == CXD2880_DVBT2_PROFILE_BASE) {
+			switch ((l1_pre->s2 >> 1)) {
+			case CXD2880_DVBT2_BASE_S2_M1K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M1K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M2K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M2K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M4K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M4K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT:
+			case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2:
+				l1_pre->fft_mode = CXD2880_DVBT2_M8K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M16K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M16K;
+				break;
+			case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT:
+			case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2:
+				l1_pre->fft_mode = CXD2880_DVBT2_M32K;
+				break;
+			default:
+				return -EBUSY;
+			}
+		} else if (profile == CXD2880_DVBT2_PROFILE_LITE) {
+			switch ((l1_pre->s2 >> 1)) {
+			case CXD2880_DVBT2_LITE_S2_M2K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M2K;
+				break;
+			case CXD2880_DVBT2_LITE_S2_M4K_G_ANY:
+				l1_pre->fft_mode = CXD2880_DVBT2_M4K;
+				break;
+			case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT:
+			case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2:
+				l1_pre->fft_mode = CXD2880_DVBT2_M8K;
+				break;
+			case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT:
+			case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2:
+				l1_pre->fft_mode = CXD2880_DVBT2_M16K;
+				break;
+			default:
+				return -EBUSY;
+			}
+		} else {
+			return -EBUSY;
+		}
+
+		l1_pre->mixed = l1_pre->s2 & 0x01;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dvbt2_version
+				     *ver)
+{
+	int ret = 0;
+	u8 version = 0;
+
+	if ((!tnr_dmd) || (!ver))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[2];
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state < 5) {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
+				    (tnr_dmd, &sync_state, &unlock_detected);
+				if (ret) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return ret;
+				}
+
+				if (sync_state < 5) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return -EBUSY;
+				}
+			} else {
+				slvt_unfreeze_reg(tnr_dmd);
+				return -EBUSY;
+			}
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x80, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		version = ((data[0] & 0x03) << 2);
+		version |= ((data[1] & 0xc0) >> 6);
+		*ver = (enum cxd2880_dvbt2_version)version;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
+				  struct cxd2880_dvbt2_ofdm *ofdm)
+{
+	if ((!tnr_dmd) || (!ofdm))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[5];
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		int ret = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state != 6) {
+			slvt_unfreeze_reg(tnr_dmd);
+
+			ret = -EBUSY;
+
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN)
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_ofdm(
+					tnr_dmd->diver_sub, ofdm);
+
+			return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x1d, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ofdm->mixed = ((data[0] & 0x20) ? 1 : 0);
+		ofdm->is_miso = ((data[0] & 0x10) >> 4);
+		ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07);
+		ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4);
+		ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07);
+		ofdm->bw_ext = (data[2] & 0x10) >> 4;
+		ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0f);
+		ofdm->num_symbols = (data[3] << 8) | data[4];
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 *plp_ids,
+				       u8 *num_plps)
+{
+	if ((!tnr_dmd) || (!num_plps))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 l1_post_ok = 0;
+		int ret = 0;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret)
+			return ret;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x86, &l1_post_ok, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!(l1_post_ok & 0x01)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xc1, num_plps, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (*num_plps == 0) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EPERM;
+		}
+
+		if (!plp_ids) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return 0;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xc2,
+					     plp_ids,
+					     ((*num_plps > 62) ?
+					     62 : *num_plps));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (*num_plps > 62) {
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x00, 0x0c);
+			if (ret) {
+				slvt_unfreeze_reg(tnr_dmd);
+				return ret;
+			}
+
+			ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x10, plp_ids + 62,
+						     *num_plps - 62);
+			if (ret) {
+				slvt_unfreeze_reg(tnr_dmd);
+				return ret;
+			}
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+	}
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
+					*tnr_dmd,
+					enum
+					cxd2880_dvbt2_plp_btype
+					type,
+					struct cxd2880_dvbt2_plp
+					*plp_info)
+{
+	if ((!tnr_dmd) || (!plp_info))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[20];
+		u8 addr = 0;
+		u8 index = 0;
+		u8 l1_post_ok = 0;
+		int ret = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x86, &l1_post_ok, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!l1_post_ok) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		if (type == CXD2880_DVBT2_PLP_COMMON)
+			addr = 0xa9;
+		else
+			addr = 0x96;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     addr, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		if ((type == CXD2880_DVBT2_PLP_COMMON) && (data[13] == 0))
+			return -EBUSY;
+
+		plp_info->id = data[index++];
+		plp_info->type =
+		    (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07);
+		plp_info->payload =
+		    (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1f);
+		plp_info->ff = data[index++] & 0x01;
+		plp_info->first_rf_idx = data[index++] & 0x07;
+		plp_info->first_frm_idx = data[index++];
+		plp_info->group_id = data[index++];
+		plp_info->plp_cr =
+		    (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07);
+		plp_info->constell =
+		    (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07);
+		plp_info->rot = data[index++] & 0x01;
+		plp_info->fec =
+		    (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03);
+		plp_info->num_blocks_max = (data[index++] & 0x03) << 8;
+		plp_info->num_blocks_max |= data[index++];
+		plp_info->frm_int = data[index++];
+		plp_info->til_len = data[index++];
+		plp_info->til_type = data[index++] & 0x01;
+
+		plp_info->in_band_a_flag = data[index++] & 0x01;
+		plp_info->rsvd = data[index++] << 8;
+		plp_info->rsvd |= data[index++];
+
+		plp_info->in_band_b_flag =
+		    (plp_info->rsvd & 0x8000) >> 15;
+		plp_info->plp_mode =
+		    (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000c) >>
+						  2);
+		plp_info->static_flag = (plp_info->rsvd & 0x0002) >> 1;
+		plp_info->static_padding_flag = plp_info->rsvd & 0x0001;
+		plp_info->rsvd = (plp_info->rsvd & 0x7ff0) >> 4;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
+					    *tnr_dmd,
+					    u8 *plp_error)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!plp_error))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	{
+		u8 data;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x86, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if ((data & 0x01) == 0x00) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xc0, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		*plp_error = data & 0x01;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 *l1_change)
+{
+	if ((!tnr_dmd) || (!l1_change))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data;
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		int ret = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state < 5) {
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
+				    (tnr_dmd, &sync_state, &unlock_detected);
+				if (ret) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return ret;
+				}
+
+				if (sync_state < 5) {
+					slvt_unfreeze_reg(tnr_dmd);
+					return -EBUSY;
+				}
+			} else {
+				slvt_unfreeze_reg(tnr_dmd);
+				return -EBUSY;
+			}
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x5f, &data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		*l1_change = data & 0x01;
+		if (*l1_change) {
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x00, 0x22);
+			if (ret) {
+				slvt_unfreeze_reg(tnr_dmd);
+				return ret;
+			}
+
+			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+						     CXD2880_IO_TGT_DMD,
+						     0x16, 0x01);
+			if (ret) {
+				slvt_unfreeze_reg(tnr_dmd);
+				return ret;
+			}
+		}
+		slvt_unfreeze_reg(tnr_dmd);
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     struct cxd2880_dvbt2_l1post
+				     *l1_post)
+{
+	if ((!tnr_dmd) || (!l1_post))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[16];
+		int ret = 0;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x86, data, sizeof(data));
+		if (ret)
+			return ret;
+
+		if (!(data[0] & 0x01))
+			return -EBUSY;
+
+		l1_post->sub_slices_per_frame = (data[1] & 0x7f) << 8;
+		l1_post->sub_slices_per_frame |= data[2];
+		l1_post->num_plps = data[3];
+		l1_post->num_aux = data[4] & 0x0f;
+		l1_post->aux_cfg_rfu = data[5];
+		l1_post->rf_idx = data[6] & 0x07;
+		l1_post->freq = data[7] << 24;
+		l1_post->freq |= data[8] << 16;
+		l1_post->freq |= data[9] << 8;
+		l1_post->freq |= data[10];
+		l1_post->fef_type = data[11] & 0x0f;
+		l1_post->fef_length = data[12] << 16;
+		l1_post->fef_length |= data[13] << 8;
+		l1_post->fef_length |= data[14];
+		l1_post->fef_intvl = data[15];
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
+				      *tnr_dmd,
+				      enum cxd2880_dvbt2_plp_btype
+				      type,
+				      struct cxd2880_dvbt2_bbheader
+				      *bbheader)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!bbheader))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	{
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!ts_lock) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if (type == CXD2880_DVBT2_PLP_COMMON) {
+		u8 l1_post_ok;
+		u8 data;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x86, &l1_post_ok, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!(l1_post_ok & 0x01)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xb6, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (data == 0) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+	}
+
+	{
+		u8 data[14];
+		u8 addr = 0;
+
+		if (type == CXD2880_DVBT2_PLP_COMMON)
+			addr = 0x51;
+		else
+			addr = 0x42;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     addr, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		bbheader->stream_input =
+		    (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03);
+		bbheader->is_single_input_stream = (data[0] >> 5) & 0x01;
+		bbheader->is_constant_coding_modulation =
+		    (data[0] >> 4) & 0x01;
+		bbheader->issy_indicator = (data[0] >> 3) & 0x01;
+		bbheader->null_packet_deletion = (data[0] >> 2) & 0x01;
+		bbheader->ext = data[0] & 0x03;
+
+		bbheader->input_stream_identifier = data[1];
+		bbheader->plp_mode =
+		    (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM :
+		    CXD2880_DVBT2_PLP_MODE_NM;
+		bbheader->data_field_length = (data[4] << 8) | data[5];
+
+		if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
+			bbheader->user_packet_length =
+			    (data[6] << 8) | data[7];
+			bbheader->sync_byte = data[8];
+			bbheader->issy = 0;
+		} else {
+			bbheader->user_packet_length = 0;
+			bbheader->sync_byte = 0;
+			bbheader->issy =
+			    (data[11] << 16) | (data[12] << 8) | data[13];
+		}
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
+					      *tnr_dmd,
+					      enum
+					      cxd2880_dvbt2_plp_btype
+					      type,
+					      u32 *ts_rate_bps)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ts_rate_bps))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	{
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!ts_lock) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	{
+		u8 l1_post_ok = 0;
+		u8 addr = 0;
+		u8 data = 0;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x86, &l1_post_ok, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!(l1_post_ok & 0x01)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		if (type == CXD2880_DVBT2_PLP_COMMON)
+			addr = 0xba;
+		else
+			addr = 0xa7;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     addr, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if ((data & 0x80) == 0x00) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+	}
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x25);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	{
+		u8 data[4];
+		u8 addr = 0;
+
+		if (type == CXD2880_DVBT2_PLP_COMMON)
+			addr = 0xa6;
+		else
+			addr = 0xaa;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     addr, &data[0], 4);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		*ts_rate_bps = ((data[0] & 0x07) << 24) | (data[1] << 16) |
+			       (data[2] << 8) | data[3];
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
+					    *tnr_dmd,
+					    enum
+					    cxd2880_tnrdmd_spectrum_sense
+					    *sense)
+{
+	int ret = 0;
+	u8 sync_state = 0;
+	u8 ts_lock = 0;
+	u8 early_unlock = 0;
+
+	if ((!tnr_dmd) || (!sense))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock,
+					       &early_unlock);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if (sync_state != 6) {
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ret = -EBUSY;
+
+		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
+			ret =
+			    cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(
+				tnr_dmd->diver_sub, sense);
+
+		return ret;
+	}
+
+	{
+		u8 data = 0;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x2f, &data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		*sense =
+		    (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
+		    CXD2880_TNRDMD_SPECTRUM_NORMAL;
+	}
+
+	return 0;
+}
+
+static int dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
+			      u16 *reg_value)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!reg_value))
+		return -EINVAL;
+
+	{
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		u8 data[2];
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state != 6) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x13, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		*reg_value = (data[0] << 8) | data[1];
+	}
+
+	return ret;
+}
+
+static int dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
+			  u32 reg_value, int *snr)
+{
+	if ((!tnr_dmd) || (!snr))
+		return -EINVAL;
+
+	if (reg_value == 0)
+		return -EBUSY;
+
+	if (reg_value > 10876)
+		reg_value = 10876;
+
+	*snr = intlog10(reg_value) - intlog10(12600 - reg_value);
+	*snr = (*snr + 839) / 1678 + 32000;
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+				 int *snr)
+{
+	u16 reg_value = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!snr))
+		return -EINVAL;
+
+	*snr = -1000 * 1000;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
+		ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
+		if (ret)
+			return ret;
+
+		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr);
+		if (ret)
+			return ret;
+	} else {
+		int snr_main = 0;
+		int snr_sub = 0;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main,
+						       &snr_sub);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
+				       *tnr_dmd, int *snr,
+				       int *snr_main, int *snr_sub)
+{
+	u16 reg_value = 0;
+	u32 reg_value_sum = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub))
+		return -EINVAL;
+
+	*snr = -1000 * 1000;
+	*snr_main = -1000 * 1000;
+	*snr_sub = -1000 * 1000;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
+	if (!ret) {
+		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main);
+		if (ret)
+			reg_value = 0;
+	} else if (ret == -EBUSY) {
+		reg_value = 0;
+	} else {
+		return ret;
+	}
+
+	reg_value_sum += reg_value;
+
+	ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
+	if (!ret) {
+		ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
+		if (ret)
+			reg_value = 0;
+	} else if (ret == -EBUSY) {
+		reg_value = 0;
+	} else {
+		return ret;
+	}
+
+	reg_value_sum += reg_value;
+
+	ret = dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd
+					 *tnr_dmd, u32 *ber)
+{
+	int ret = 0;
+	u32 bit_error = 0;
+	u32 period_exp = 0;
+	u32 n_ldpc = 0;
+
+	if ((!tnr_dmd) || (!ber))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	{
+		u8 data[5];
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x3c, data, sizeof(data));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!(data[0] & 0x01)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		bit_error =
+		    ((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8)
+		    | data[4];
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xa0, data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) ==
+		    CXD2880_DVBT2_FEC_LDPC_16K)
+			n_ldpc = 16200;
+		else
+			n_ldpc = 64800;
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x20);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x6f, data, 1);
+		if (ret)
+			return ret;
+
+		period_exp = data[0] & 0x0f;
+	}
+
+	if (bit_error > ((1U << period_exp) * n_ldpc))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		if (period_exp >= 4) {
+			div = (1U << (period_exp - 4)) * (n_ldpc / 200);
+
+			Q = (bit_error * 5) / div;
+			R = (bit_error * 5) % div;
+
+			R *= 625;
+			Q = Q * 625 + R / div;
+			R = R % div;
+		} else {
+			div = (1U << period_exp) * (n_ldpc / 200);
+
+			Q = (bit_error * 10) / div;
+			R = (bit_error * 10) % div;
+
+			R *= 5000;
+			Q = Q * 5000 + R / div;
+			R = R % div;
+		}
+
+		if (div / 2 <= R)
+			*ber = Q + 1;
+		else
+			*ber = Q;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd
+					 *tnr_dmd, u32 *fer)
+{
+	int ret = 0;
+	u32 fec_error = 0;
+	u32 period = 0;
+
+	if ((!tnr_dmd) || (!fer))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret)
+		return ret;
+
+	{
+		u8 data[2];
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x1b, data, 2);
+		if (ret)
+			return ret;
+
+		if (!(data[0] & 0x80))
+			return -EBUSY;
+
+		fec_error = ((data[0] & 0x7f) << 8) | (data[1]);
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x20);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x72, data, 1);
+		if (ret)
+			return ret;
+
+		period = (1 << (data[0] & 0x0f));
+	}
+
+	if ((period == 0) || (fec_error > period))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		div = period;
+
+		Q = (fec_error * 1000) / div;
+		R = (fec_error * 1000) % div;
+
+		R *= 1000;
+		Q = Q * 1000 + R / div;
+		R = R % div;
+
+		if ((div != 1) && (div / 2 <= R))
+			*fer = Q + 1;
+		else
+			*fer = Q;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd
+					*tnr_dmd, u32 *ber)
+{
+	int ret = 0;
+	u32 bit_error = 0;
+	u32 period_exp = 0;
+	u32 n_bch = 0;
+
+	if ((!tnr_dmd) || (!ber))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[3];
+		enum cxd2880_dvbt2_plp_fec plp_fec_type =
+		    CXD2880_DVBT2_FEC_LDPC_16K;
+		enum cxd2880_dvbt2_plp_code_rate plp_cr = CXD2880_DVBT2_R1_2;
+
+		static const u16 n_bch_bits_lookup[2][8] = {
+			{7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480},
+			{32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920}
+		};
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x15, data, 3);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!(data[0] & 0x40)) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		bit_error = ((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2];
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x9d, data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		plp_cr = (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07);
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xa0, data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03);
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x20);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x72, data, 1);
+		if (ret)
+			return ret;
+
+		period_exp = data[0] & 0x0f;
+
+		if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) ||
+		    (plp_cr > CXD2880_DVBT2_R2_5))
+			return -EBUSY;
+
+		n_bch = n_bch_bits_lookup[plp_fec_type][plp_cr];
+	}
+
+	if (bit_error > ((1U << period_exp) * n_bch))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		if (period_exp >= 6) {
+			div = (1U << (period_exp - 6)) * (n_bch / 40);
+
+			Q = (bit_error * 625) / div;
+			R = (bit_error * 625) % div;
+
+			R *= 625;
+			Q = Q * 625 + R / div;
+			R = R % div;
+		} else {
+			div = (1U << period_exp) * (n_bch / 40);
+
+			Q = (bit_error * 1000) / div;
+			R = (bit_error * 1000) % div;
+
+			R *= 25000;
+			Q = Q * 25000 + R / div;
+			R = R % div;
+		}
+
+		if (div / 2 <= R)
+			*ber = Q + 1;
+		else
+			*ber = Q;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
+						 cxd2880_tnrdmd
+						 *tnr_dmd,
+						 u32 *pen)
+{
+	int ret = 0;
+
+	u8 data[3];
+
+	if ((!tnr_dmd) || (!pen))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x39, data, sizeof(data));
+	if (ret)
+		return ret;
+
+	if (!(data[0] & 0x01))
+		return -EBUSY;
+
+	*pen = ((data[1] << 8) | data[2]);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
+					     *tnr_dmd, int *ppm)
+{
+	if ((!tnr_dmd) || (!ppm))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 ctl_val_reg[5];
+		u8 nominal_rate_reg[5];
+		u32 trl_ctl_val = 0;
+		u32 trcg_nominal_rate = 0;
+		int num;
+		int den;
+		int ret = 0;
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+		s8 diff_upper = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (sync_state != 6) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x34, ctl_val_reg,
+					     sizeof(ctl_val_reg));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x04);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x10, nominal_rate_reg,
+					     sizeof(nominal_rate_reg));
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		slvt_unfreeze_reg(tnr_dmd);
+
+		diff_upper =
+		    (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
+
+		if ((diff_upper < -1) || (diff_upper > 1))
+			return -EBUSY;
+
+		trl_ctl_val = ctl_val_reg[1] << 24;
+		trl_ctl_val |= ctl_val_reg[2] << 16;
+		trl_ctl_val |= ctl_val_reg[3] << 8;
+		trl_ctl_val |= ctl_val_reg[4];
+
+		trcg_nominal_rate = nominal_rate_reg[1] << 24;
+		trcg_nominal_rate |= nominal_rate_reg[2] << 16;
+		trcg_nominal_rate |= nominal_rate_reg[3] << 8;
+		trcg_nominal_rate |= nominal_rate_reg[4];
+
+		trl_ctl_val >>= 1;
+		trcg_nominal_rate >>= 1;
+
+		if (diff_upper == 1)
+			num =
+			    (int)((trl_ctl_val + 0x80000000u) -
+				  trcg_nominal_rate);
+		else if (diff_upper == -1)
+			num =
+			    -(int)((trcg_nominal_rate + 0x80000000u) -
+				   trl_ctl_val);
+		else
+			num = (int)(trl_ctl_val - trcg_nominal_rate);
+
+		den = (nominal_rate_reg[0] & 0x7f) << 24;
+		den |= nominal_rate_reg[1] << 16;
+		den |= nominal_rate_reg[2] << 8;
+		den |= nominal_rate_reg[3];
+		den = (den + (390625 / 2)) / 390625;
+
+		den >>= 1;
+
+		if (num >= 0)
+			*ppm = (num + (den / 2)) / den;
+		else
+			*ppm = (num - (den / 2)) / den;
+	}
+
+	return 0;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
+						 cxd2880_tnrdmd
+						 *tnr_dmd,
+						 int *ppm)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ppm))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd
+				     *tnr_dmd, u8 *quality)
+{
+	int ret = 0;
+	int snr = 0;
+	int snr_rel = 0;
+	u32 ber = 0;
+	u32 ber_sqi = 0;
+	enum cxd2880_dvbt2_plp_constell qam;
+	enum cxd2880_dvbt2_plp_code_rate code_rate;
+
+	static const int snr_nordig_p1_db_1000[4][8] = {
+		{3500, 4700, 5600, 6600, 7200, 7700, 1300, 2200},
+		{8700, 10100, 11400, 12500, 13300, 13800, 6000, 7200},
+		{13000, 14800, 16200, 17700, 18700, 19400, 9800, 11100},
+		{17000, 19400, 20800, 22900, 24300, 25100, 13200, 14800},
+	};
+
+	if ((!tnr_dmd) || (!quality))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(tnr_dmd, &ber);
+	if (ret)
+		return ret;
+
+	ret = cxd2880_tnrdmd_dvbt2_mon_snr(tnr_dmd, &snr);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
+					       &code_rate);
+	if (ret)
+		return ret;
+
+	if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256))
+		return -EPERM;
+
+	if (ber > 100000)
+		ber_sqi = 0;
+	else if (ber >= 100)
+		ber_sqi = 6667;
+	else
+		ber_sqi = 16667;
+
+	snr_rel = snr - snr_nordig_p1_db_1000[qam][code_rate];
+
+	if (snr_rel < -3000) {
+		*quality = 0;
+	} else if (snr_rel <= 3000) {
+		u32 temp_sqi =
+		    (((snr_rel + 3000) * ber_sqi) + 500000) / 1000000;
+		*quality = (temp_sqi > 100) ? 100 : (u8)temp_sqi;
+	} else {
+		*quality = 100;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd
+				     *tnr_dmd, u32 *ts_rate_kbps)
+{
+	int ret = 0;
+	u32 rd_smooth_dp = 0;
+	u32 ep_ck_nume = 0;
+	u32 ep_ck_deno = 0;
+	u8 issy_on_data = 0;
+
+	if ((!tnr_dmd) || (!ts_rate_kbps))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 data[12];
+		u8 sync_state = 0;
+		u8 ts_lock = 0;
+		u8 unlock_detected = 0;
+
+		ret = slvt_freeze_reg(tnr_dmd);
+		if (ret)
+			return ret;
+
+		ret =
+		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
+						       &ts_lock,
+						       &unlock_detected);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (!ts_lock) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x23, data, 12);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		rd_smooth_dp = (data[0] & 0x1f) << 24;
+		rd_smooth_dp |= data[1] << 16;
+		rd_smooth_dp |= data[2] << 8;
+		rd_smooth_dp |= data[3];
+
+		if (rd_smooth_dp < 214958) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ep_ck_nume = (data[4] & 0x3f) << 24;
+		ep_ck_nume |= data[5] << 16;
+		ep_ck_nume |= data[6] << 8;
+		ep_ck_nume |= data[7];
+
+		ep_ck_deno = (data[8] & 0x3f) << 24;
+		ep_ck_deno |= data[9] << 16;
+		ep_ck_deno |= data[10] << 8;
+		ep_ck_deno |= data[11];
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x41, data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		issy_on_data = data[0] & 0x01;
+
+		slvt_unfreeze_reg(tnr_dmd);
+	}
+
+	if (issy_on_data) {
+		if ((ep_ck_deno == 0) || (ep_ck_nume == 0) ||
+		    (ep_ck_deno >= ep_ck_nume))
+			return -EBUSY;
+	}
+
+	{
+		u32 ick_x100;
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		switch (tnr_dmd->clk_mode) {
+		case CXD2880_TNRDMD_CLOCKMODE_A:
+			ick_x100 = 8228;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_B:
+			ick_x100 = 9330;
+			break;
+		case CXD2880_TNRDMD_CLOCKMODE_C:
+			ick_x100 = 9600;
+			break;
+		default:
+			return -EPERM;
+		}
+
+		div = rd_smooth_dp;
+
+		Q = ick_x100 * 262144U / div;
+		R = ick_x100 * 262144U % div;
+
+		R *= 5U;
+		Q = Q * 5 + R / div;
+		R = R % div;
+
+		R *= 2U;
+		Q = Q * 2 + R / div;
+		R = R % div;
+
+		if (div / 2 <= R)
+			*ts_rate_kbps = Q + 1;
+		else
+			*ts_rate_kbps = Q;
+	}
+
+	if (issy_on_data) {
+		u32 diff = ep_ck_nume - ep_ck_deno;
+
+		while (diff > 0x7fff) {
+			diff >>= 1;
+			ep_ck_nume >>= 1;
+		}
+
+		*ts_rate_kbps -=
+		    (*ts_rate_kbps * diff + ep_ck_nume / 2) / ep_ck_nume;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
+				 u32 *per)
+{
+	int ret = 0;
+	u32 packet_error = 0;
+	u32 period = 0;
+
+	if (!tnr_dmd || !per)
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	{
+		u8 rdata[3];
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x0b);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x18, rdata, 3);
+		if (ret)
+			return ret;
+
+		if ((rdata[0] & 0x01) == 0)
+			return -EBUSY;
+
+		packet_error = (rdata[1] << 8) | rdata[2];
+
+		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x00, 0x24);
+		if (ret)
+			return ret;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xdc, rdata, 1);
+		if (ret)
+			return ret;
+
+		period = 1U << (rdata[0] & 0x0f);
+	}
+
+	if ((period == 0) || (packet_error > period))
+		return -EBUSY;
+
+	{
+		u32 div = 0;
+		u32 Q = 0;
+		u32 R = 0;
+
+		div = period;
+
+		Q = (packet_error * 1000) / div;
+		R = (packet_error * 1000) % div;
+
+		R *= 1000;
+		Q = Q * 1000 + R / div;
+		R = R % div;
+
+		if ((div != 1) && (div / 2 <= R))
+			*per = Q + 1;
+		else
+			*per = Q;
+	}
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
+				 enum cxd2880_dvbt2_plp_btype type,
+				 enum cxd2880_dvbt2_plp_constell *qam)
+{
+	u8 data;
+	u8 l1_post_ok = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!qam))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x86, &l1_post_ok, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if (!(l1_post_ok & 0x01)) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return -EBUSY;
+	}
+
+	if (type == CXD2880_DVBT2_PLP_COMMON) {
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xb6, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (data == 0) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xb1, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+	} else {
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x9e, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
+				       *tnr_dmd,
+				       enum cxd2880_dvbt2_plp_btype
+				       type,
+				       enum
+				       cxd2880_dvbt2_plp_code_rate
+				       *code_rate)
+{
+	u8 data;
+	u8 l1_post_ok = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!code_rate))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = slvt_freeze_reg(tnr_dmd);
+	if (ret)
+		return ret;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x86, &l1_post_ok, 1);
+	if (ret) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return ret;
+	}
+
+	if (!(l1_post_ok & 0x01)) {
+		slvt_unfreeze_reg(tnr_dmd);
+		return -EBUSY;
+	}
+
+	if (type == CXD2880_DVBT2_PLP_COMMON) {
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xb6, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+
+		if (data == 0) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return -EBUSY;
+		}
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0xb0, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+	} else {
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x9d, &data, 1);
+		if (ret) {
+			slvt_unfreeze_reg(tnr_dmd);
+			return ret;
+		}
+	}
+
+	slvt_unfreeze_reg(tnr_dmd);
+
+	*code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07);
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dvbt2_profile
+				     *profile)
+{
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!profile))
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
+				     CXD2880_IO_TGT_DMD,
+				     0x00, 0x0b);
+	if (ret)
+		return ret;
+
+	{
+		u8 data;
+
+		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
+					     CXD2880_IO_TGT_DMD,
+					     0x22, &data, sizeof(data));
+		if (ret)
+			return ret;
+
+		if (data & 0x02) {
+			if (data & 0x01)
+				*profile = CXD2880_DVBT2_PROFILE_LITE;
+			else
+				*profile = CXD2880_DVBT2_PROFILE_BASE;
+		} else {
+			ret = -EBUSY;
+			if (tnr_dmd->diver_mode ==
+			    CXD2880_TNRDMD_DIVERMODE_MAIN)
+				ret =
+				    cxd2880_tnrdmd_dvbt2_mon_profile(
+					tnr_dmd->diver_sub, profile);
+
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int dvbt2_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+			  int rf_lvl, u8 *ssi)
+{
+	enum cxd2880_dvbt2_plp_constell qam;
+	enum cxd2880_dvbt2_plp_code_rate code_rate;
+	int prel;
+	int temp_ssi = 0;
+	int ret = 0;
+
+	static const int ref_dbm_1000[4][8] = {
+		{-96000, -95000, -94000, -93000, -92000, -92000, -98000,
+		 -97000},
+		{-91000, -89000, -88000, -87000, -86000, -86000, -93000,
+		 -92000},
+		{-86000, -85000, -83000, -82000, -81000, -80000, -89000,
+		 -88000},
+		{-82000, -80000, -78000, -76000, -75000, -74000, -86000,
+		 -84000},
+	};
+
+	if ((!tnr_dmd) || (!ssi))
+		return -EINVAL;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
+	if (ret)
+		return ret;
+
+	ret =
+	    cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
+					       &code_rate);
+	if (ret)
+		return ret;
+
+	if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256))
+		return -EPERM;
+
+	prel = rf_lvl - ref_dbm_1000[qam][code_rate];
+
+	if (prel < -15000)
+		temp_ssi = 0;
+	else if (prel < 0)
+		temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
+	else if (prel < 20000)
+		temp_ssi = (((4 * prel) + 500) / 1000) + 10;
+	else if (prel < 35000)
+		temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
+	else
+		temp_ssi = 100;
+
+	*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+				 u8 *ssi)
+{
+	int rf_lvl = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ssi))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
+	if (ret)
+		return ret;
+
+	ret = dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
+				     *tnr_dmd, u8 *ssi)
+{
+	int rf_lvl = 0;
+	int ret = 0;
+
+	if ((!tnr_dmd) || (!ssi))
+		return -EINVAL;
+
+	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
+		return -EINVAL;
+
+	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
+		return -EPERM;
+
+	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
+		return -EPERM;
+
+	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
+	if (ret)
+		return ret;
+
+	ret = dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
+	if (ret)
+		return ret;
+
+	return ret;
+}
diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
new file mode 100644
index 000000000000..f7b2f618e80f
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
@@ -0,0 +1,170 @@
+/*
+ * cxd2880_tnrdmd_dvbt2_mon.h
+ * Sony CXD2880 DVB-T2/T tuner + demodulator driver
+ * DVB-T2 monitor interface
+ *
+ * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CXD2880_TNRDMD_DVBT2_MON_H
+#define CXD2880_TNRDMD_DVBT2_MON_H
+
+#include "cxd2880_tnrdmd.h"
+#include "cxd2880_dvbt2.h"
+
+int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 *sync_stat,
+				       u8 *ts_lock_stat,
+				       u8 *unlock_detected);
+
+int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
+					   *tnr_dmd,
+					   u8 *sync_stat,
+					   u8 *unlock_detected);
+
+int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
+					    *tnr_dmd, int *offset);
+
+int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
+						cxd2880_tnrdmd
+						*tnr_dmd,
+						int *offset);
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
+				    struct cxd2880_dvbt2_l1pre
+				    *l1_pre);
+
+int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dvbt2_version
+				     *ver);
+
+int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
+				  struct cxd2880_dvbt2_ofdm *ofdm);
+
+int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 *plp_ids,
+				       u8 *num_plps);
+
+int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
+					*tnr_dmd,
+					enum
+					cxd2880_dvbt2_plp_btype
+					type,
+					struct cxd2880_dvbt2_plp
+					*plp_info);
+
+int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
+					    *tnr_dmd,
+					    u8 *plp_error);
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
+				       *tnr_dmd, u8 *l1_change);
+
+int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     struct cxd2880_dvbt2_l1post
+				     *l1_post);
+
+int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
+				      *tnr_dmd,
+				      enum cxd2880_dvbt2_plp_btype
+				      type,
+				      struct cxd2880_dvbt2_bbheader
+				      *bbheader);
+
+int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
+					      *tnr_dmd,
+					      enum
+					      cxd2880_dvbt2_plp_btype
+					      type,
+					      u32 *ts_rate_bps);
+
+int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
+					    *tnr_dmd,
+					    enum
+					    cxd2880_tnrdmd_spectrum_sense
+					    *sense);
+
+int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
+				 int *snr);
+
+int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
+				       *tnr_dmd, int *snr,
+				       int *snr_main,
+				       int *snr_sub);
+
+int cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd
+					 *tnr_dmd, u32 *ber);
+
+int cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd
+					 *tnr_dmd, u32 *fer);
+
+int cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd
+					*tnr_dmd, u32 *ber);
+
+int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
+						 cxd2880_tnrdmd
+						 *tnr_dmd,
+						 u32 *pen);
+
+int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
+					     *tnr_dmd, int *ppm);
+
+int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
+						 cxd2880_tnrdmd
+						 *tnr_dmd,
+						 int *ppm);
+
+int cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd
+				     *tnr_dmd, u32 *ts_rate_kbps);
+
+int cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd
+				     *tnr_dmd, u8 *quality);
+
+int cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
+				 u32 *per);
+
+int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
+				 enum cxd2880_dvbt2_plp_btype type,
+				 enum cxd2880_dvbt2_plp_constell
+				 *qam);
+
+int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
+				       *tnr_dmd,
+				       enum cxd2880_dvbt2_plp_btype
+				       type,
+				       enum
+				       cxd2880_dvbt2_plp_code_rate
+				       *code_rate);
+
+int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
+				     *tnr_dmd,
+				     enum cxd2880_dvbt2_profile
+				     *profile);
+
+int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
+				 u8 *ssi);
+
+int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
+				     *tnr_dmd, u8 *ssi);
+
+#endif
-- 
2.13.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 12/14]  [media] cxd2880: Add all Makefile files for the driver
@ 2017-08-16  4:44   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:44 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

This is the Makefile files of driver
for the Sony CXD2880 DVB-T2/T tuner + demodulator.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/Makefile
      -no change
   drivers/media/dvb-frontends/cxd2880/Makefile
      -removed cxd2880_math.o \ 
   drivers/media/spi/Makefile
      -no change

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 drivers/media/dvb-frontends/Makefile         |  1 +
 drivers/media/dvb-frontends/cxd2880/Makefile | 20 ++++++++++++++++++++
 drivers/media/spi/Makefile                   |  5 +++++
 3 files changed, 26 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/Makefile

diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 3fccaf34ef52..d298c7954699 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -126,3 +126,4 @@ obj-$(CONFIG_DVB_HORUS3A) += horus3a.o
 obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o
 obj-$(CONFIG_DVB_HELENE) += helene.o
 obj-$(CONFIG_DVB_ZD1301_DEMOD) += zd1301_demod.o
+obj-$(CONFIG_DVB_CXD2880) += cxd2880/
diff --git a/drivers/media/dvb-frontends/cxd2880/Makefile b/drivers/media/dvb-frontends/cxd2880/Makefile
new file mode 100644
index 000000000000..ee7758b28a05
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/Makefile
@@ -0,0 +1,20 @@
+cxd2880-objs := cxd2880_common.o \
+		cxd2880_devio_spi.o \
+		cxd2880_integ.o \
+		cxd2880_integ_dvbt2.o \
+		cxd2880_integ_dvbt.o \
+		cxd2880_io.o \
+		cxd2880_spi_device.o \
+		cxd2880_stopwatch_port.o \
+		cxd2880_tnrdmd.o \
+		cxd2880_tnrdmd_dvbt2.o \
+		cxd2880_tnrdmd_dvbt2_mon.o \
+		cxd2880_tnrdmd_dvbt.o \
+		cxd2880_tnrdmd_dvbt_mon.o\
+		cxd2880_tnrdmd_mon.o\
+		cxd2880_top.o
+
+obj-$(CONFIG_DVB_CXD2880) += cxd2880.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/spi/Makefile b/drivers/media/spi/Makefile
index ea64013d16cc..40e0f88d9f6c 100644
--- a/drivers/media/spi/Makefile
+++ b/drivers/media/spi/Makefile
@@ -1 +1,6 @@
 obj-$(CONFIG_VIDEO_GS1662) += gs1662.o
+obj-$(CONFIG_CXD2880_SPI_DRV) += cxd2880-spi.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/dvb-frontends/cxd2880
\ No newline at end of file
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 12/14]  [media] cxd2880: Add all Makefile files for the driver
@ 2017-08-16  4:44   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-08-16  4:44 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

This is the Makefile files of driver
for the Sony CXD2880 DVB-T2/T tuner + demodulator.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/Makefile
      -no change
   drivers/media/dvb-frontends/cxd2880/Makefile
      -removed cxd2880_math.o \ 
   drivers/media/spi/Makefile
      -no change

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 drivers/media/dvb-frontends/Makefile         |  1 +
 drivers/media/dvb-frontends/cxd2880/Makefile | 20 ++++++++++++++++++++
 drivers/media/spi/Makefile                   |  5 +++++
 3 files changed, 26 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/Makefile

diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 3fccaf34ef52..d298c7954699 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -126,3 +126,4 @@ obj-$(CONFIG_DVB_HORUS3A) += horus3a.o
 obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o
 obj-$(CONFIG_DVB_HELENE) += helene.o
 obj-$(CONFIG_DVB_ZD1301_DEMOD) += zd1301_demod.o
+obj-$(CONFIG_DVB_CXD2880) += cxd2880/
diff --git a/drivers/media/dvb-frontends/cxd2880/Makefile b/drivers/media/dvb-frontends/cxd2880/Makefile
new file mode 100644
index 000000000000..ee7758b28a05
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/Makefile
@@ -0,0 +1,20 @@
+cxd2880-objs := cxd2880_common.o \
+		cxd2880_devio_spi.o \
+		cxd2880_integ.o \
+		cxd2880_integ_dvbt2.o \
+		cxd2880_integ_dvbt.o \
+		cxd2880_io.o \
+		cxd2880_spi_device.o \
+		cxd2880_stopwatch_port.o \
+		cxd2880_tnrdmd.o \
+		cxd2880_tnrdmd_dvbt2.o \
+		cxd2880_tnrdmd_dvbt2_mon.o \
+		cxd2880_tnrdmd_dvbt.o \
+		cxd2880_tnrdmd_dvbt_mon.o\
+		cxd2880_tnrdmd_mon.o\
+		cxd2880_top.o
+
+obj-$(CONFIG_DVB_CXD2880) += cxd2880.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/spi/Makefile b/drivers/media/spi/Makefile
index ea64013d16cc..40e0f88d9f6c 100644
--- a/drivers/media/spi/Makefile
+++ b/drivers/media/spi/Makefile
@@ -1 +1,6 @@
 obj-$(CONFIG_VIDEO_GS1662) += gs1662.o
+obj-$(CONFIG_CXD2880_SPI_DRV) += cxd2880-spi.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/dvb-frontends/cxd2880
\ No newline at end of file
-- 
2.13.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 13/14] [media] cxd2880: Add all Kconfig files for the driver
@ 2017-08-16  4:45   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:45 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

This is the Kconfig files of driver for
the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/Kconfig
      -no change
   drivers/media/dvb-frontends/cxd2880/Kconfig
      -no change
   drivers/media/spi/Kconfig
      -no change

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 drivers/media/dvb-frontends/Kconfig         |  2 ++
 drivers/media/dvb-frontends/cxd2880/Kconfig |  6 ++++++
 drivers/media/spi/Kconfig                   | 14 ++++++++++++++
 3 files changed, 22 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/Kconfig

diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 3a260b82b3e8..6831f4a49c18 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -519,6 +519,8 @@ config DVB_GP8PSK_FE
 	depends on DVB_CORE
 	default DVB_USB_GP8PSK
 
+source "drivers/media/dvb-frontends/cxd2880/Kconfig"
+
 comment "DVB-C (cable) frontends"
 	depends on DVB_CORE
 
diff --git a/drivers/media/dvb-frontends/cxd2880/Kconfig b/drivers/media/dvb-frontends/cxd2880/Kconfig
new file mode 100644
index 000000000000..36b8b6f7c4f7
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/Kconfig
@@ -0,0 +1,6 @@
+config DVB_CXD2880
+	tristate "Sony CXD2880 DVB-T2/T tuner + demodulator"
+	depends on DVB_CORE && SPI
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  Say Y when you want to support this frontend.
\ No newline at end of file
diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig
index a21f5a39a440..b07ac86fc53c 100644
--- a/drivers/media/spi/Kconfig
+++ b/drivers/media/spi/Kconfig
@@ -12,3 +12,17 @@ config VIDEO_GS1662
 endmenu
 
 endif
+
+if SPI
+menu "Media SPI Adapters"
+
+config CXD2880_SPI_DRV
+	tristate "Sony CXD2880 SPI support"
+	depends on DVB_CORE && SPI
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  Choose if you would like to have SPI interface support for Sony CXD2880.
+
+endmenu
+
+endif
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 13/14] [media] cxd2880: Add all Kconfig files for the driver
@ 2017-08-16  4:45   ` Yasunari.Takiguchi-7U/KSKJipcs
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi-7U/KSKJipcs @ 2017-08-16  4:45 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Yasunari Takiguchi,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>

This is the Kconfig files of driver for
the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

[Change list]
Changes in V3
   drivers/media/dvb-frontends/Kconfig
      -no change
   drivers/media/dvb-frontends/cxd2880/Kconfig
      -no change
   drivers/media/spi/Kconfig
      -no change

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
---
 drivers/media/dvb-frontends/Kconfig         |  2 ++
 drivers/media/dvb-frontends/cxd2880/Kconfig |  6 ++++++
 drivers/media/spi/Kconfig                   | 14 ++++++++++++++
 3 files changed, 22 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/cxd2880/Kconfig

diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 3a260b82b3e8..6831f4a49c18 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -519,6 +519,8 @@ config DVB_GP8PSK_FE
 	depends on DVB_CORE
 	default DVB_USB_GP8PSK
 
+source "drivers/media/dvb-frontends/cxd2880/Kconfig"
+
 comment "DVB-C (cable) frontends"
 	depends on DVB_CORE
 
diff --git a/drivers/media/dvb-frontends/cxd2880/Kconfig b/drivers/media/dvb-frontends/cxd2880/Kconfig
new file mode 100644
index 000000000000..36b8b6f7c4f7
--- /dev/null
+++ b/drivers/media/dvb-frontends/cxd2880/Kconfig
@@ -0,0 +1,6 @@
+config DVB_CXD2880
+	tristate "Sony CXD2880 DVB-T2/T tuner + demodulator"
+	depends on DVB_CORE && SPI
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  Say Y when you want to support this frontend.
\ No newline at end of file
diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig
index a21f5a39a440..b07ac86fc53c 100644
--- a/drivers/media/spi/Kconfig
+++ b/drivers/media/spi/Kconfig
@@ -12,3 +12,17 @@ config VIDEO_GS1662
 endmenu
 
 endif
+
+if SPI
+menu "Media SPI Adapters"
+
+config CXD2880_SPI_DRV
+	tristate "Sony CXD2880 SPI support"
+	depends on DVB_CORE && SPI
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  Choose if you would like to have SPI interface support for Sony CXD2880.
+
+endmenu
+
+endif
-- 
2.13.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 14/14] [media] cxd2880 : Update MAINTAINERS file for CXD2880 driver
  2017-08-16  4:17 ` Yasunari.Takiguchi-7U/KSKJipcs
@ 2017-08-16  4:47   ` Yasunari.Takiguchi
  -1 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:47 UTC (permalink / raw)
  To: mchehab, linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

This is MAINTAINERS file update about the driver for
the Sony CXD2880 DVB-T2/T tuner + demodulator.

[Change list]
Changes in V3
   MAINTAINERS
      -no change

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6f7721d1634c..12a80c33c194 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8302,6 +8302,15 @@ T:	git git://linuxtv.org/media_tree.git
 S:	Supported
 F:	drivers/media/dvb-frontends/cxd2841er*
 
+MEDIA DRIVERS FOR CXD2880
+M:	Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org/
+T:	git git://linuxtv.org/media_tree.git
+S:	Supported
+F:	drivers/media/dvb-frontends/cxd2880/*
+F:	drivers/media/spi/cxd2880*
+
 MEDIA DRIVERS FOR FREESCALE IMX
 M:	Steve Longerbeam <slongerbeam@gmail.com>
 M:	Philipp Zabel <p.zabel@pengutronix.de>
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [PATCH v3 14/14] [media] cxd2880 : Update MAINTAINERS file for CXD2880 driver
@ 2017-08-16  4:47   ` Yasunari.Takiguchi
  0 siblings, 0 replies; 51+ messages in thread
From: Yasunari.Takiguchi @ 2017-08-16  4:47 UTC (permalink / raw)
  To: mchehab, linux-kernel, devicetree, linux-media
  Cc: tbird20d, frowand.list, Yasunari Takiguchi, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

This is MAINTAINERS file update about the driver for
the Sony CXD2880 DVB-T2/T tuner + demodulator.

[Change list]
Changes in V3
   MAINTAINERS
      -no change

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6f7721d1634c..12a80c33c194 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8302,6 +8302,15 @@ T:	git git://linuxtv.org/media_tree.git
 S:	Supported
 F:	drivers/media/dvb-frontends/cxd2841er*
 
+MEDIA DRIVERS FOR CXD2880
+M:	Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org/
+T:	git git://linuxtv.org/media_tree.git
+S:	Supported
+F:	drivers/media/dvb-frontends/cxd2880/*
+F:	drivers/media/spi/cxd2880*
+
 MEDIA DRIVERS FOR FREESCALE IMX
 M:	Steve Longerbeam <slongerbeam@gmail.com>
 M:	Philipp Zabel <p.zabel@pengutronix.de>
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 14/14] [media] cxd2880 : Update MAINTAINERS file for CXD2880 driver
  2017-08-16  4:47   ` Yasunari.Takiguchi
@ 2017-08-16  8:02     ` Takiguchi, Yasunari
  -1 siblings, 0 replies; 51+ messages in thread
From: Takiguchi, Yasunari @ 2017-08-16  8:02 UTC (permalink / raw)
  To: mchehab, linux-kernel, devicetree, linux-media, akpm
  Cc: tbird20d, frowand.list, Masayuki Yamamoto, Hideki Nozawa,
	Kota Yonezawa, Toshihiko Matsumoto, Satoshi Watanabe,
	yasunari.takiguchi

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

I add an e-mail address and re-send this mail again.

This is MAINTAINERS file update about the driver for
the Sony CXD2880 DVB-T2/T tuner + demodulator.

[Change list]
Changes in V3
   MAINTAINERS
      -no change

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6f7721d1634c..12a80c33c194 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8302,6 +8302,15 @@ T:	git git://linuxtv.org/media_tree.git
 S:	Supported
 F:	drivers/media/dvb-frontends/cxd2841er*
 
+MEDIA DRIVERS FOR CXD2880
+M:	Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org/
+T:	git git://linuxtv.org/media_tree.git
+S:	Supported
+F:	drivers/media/dvb-frontends/cxd2880/*
+F:	drivers/media/spi/cxd2880*
+
 MEDIA DRIVERS FOR FREESCALE IMX
 M:	Steve Longerbeam <slongerbeam@gmail.com>
 M:	Philipp Zabel <p.zabel@pengutronix.de>
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 14/14] [media] cxd2880 : Update MAINTAINERS file for CXD2880 driver
@ 2017-08-16  8:02     ` Takiguchi, Yasunari
  0 siblings, 0 replies; 51+ messages in thread
From: Takiguchi, Yasunari @ 2017-08-16  8:02 UTC (permalink / raw)
  To: mchehab, linux-kernel, devicetree, linux-media, akpm
  Cc: tbird20d, frowand.list, Masayuki Yamamoto, Hideki Nozawa,
	Kota Yonezawa, Toshihiko Matsumoto, Satoshi Watanabe,
	yasunari.takiguchi

From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

I add an e-mail address and re-send this mail again.

This is MAINTAINERS file update about the driver for
the Sony CXD2880 DVB-T2/T tuner + demodulator.

[Change list]
Changes in V3
   MAINTAINERS
      -no change

Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6f7721d1634c..12a80c33c194 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8302,6 +8302,15 @@ T:	git git://linuxtv.org/media_tree.git
 S:	Supported
 F:	drivers/media/dvb-frontends/cxd2841er*
 
+MEDIA DRIVERS FOR CXD2880
+M:	Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
+L:	linux-media@vger.kernel.org
+W:	http://linuxtv.org/
+T:	git git://linuxtv.org/media_tree.git
+S:	Supported
+F:	drivers/media/dvb-frontends/cxd2880/*
+F:	drivers/media/spi/cxd2880*
+
 MEDIA DRIVERS FOR FREESCALE IMX
 M:	Steve Longerbeam <slongerbeam@gmail.com>
 M:	Philipp Zabel <p.zabel@pengutronix.de>
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 05/14] [media] cxd2880: Add tuner part of the driver
@ 2017-08-27 14:45     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 14:45 UTC (permalink / raw)
  To: Yasunari.Takiguchi
  Cc: linux-kernel, devicetree, linux-media, tbird20d, frowand.list,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

Em Wed, 16 Aug 2017 13:37:14 +0900
<Yasunari.Takiguchi@sony.com> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> 
> This part of the driver has the main routines to handle
> the tuner and demodulator functionality.  The tnrdmd_mon.* files
> have monitor functions for the driver.
> This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

This series is on a much better state. Thanks!

Patches 1-4 sound ok to me.

Still, there are a few issues on this patch. See below.

> 
> [Change list]
> Changes in V3
>    drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
>       -removed code relevant to ISDB-T

Just curiosity here: why is it removed?

>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
>       -removed unnecessary cast
>       -removed code relevant to ISDB-T
>       -changed CXD2880_SLEEP to usleep_range
>       -changed cxd2880_memset to memset 
>       -changed cxd2880_atomic_set to atomic_set
>       -modified return code
>       -modified coding style of if()
>       -changed to use const values at writing a lot of registers 
>        with a command. 
>       -changed hexadecimal code to lower case. 
>       -adjusted of indent spaces
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
>       -removed code relevant to ISDB-T
>       -changed cxd2880_atomic struct to atomic_t
>       -modified return code
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
>       -updated version information
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
>       -changed CXD2880_SLEEP to usleep_range
>       -removed unnecessary cast
>       -modified return code
>       -modified coding style of if() 
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
>       -modified return code
> 
> Changes in V2
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
>       -updated version information
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
> ---
>  drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h  |   46 +
>  .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c   | 4030 ++++++++++++++++++++
>  .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h   |  391 ++
>  .../cxd2880/cxd2880_tnrdmd_driver_version.h        |   29 +
>  .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c     |  221 ++
>  .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h     |   52 +
>  6 files changed, 4769 insertions(+)
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
> 
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
> new file mode 100644
> index 000000000000..2d35d3990060
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
> @@ -0,0 +1,46 @@
> +/*
> + * cxd2880_dtv.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DTV related definitions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_DTV_H
> +#define CXD2880_DTV_H
> +
> +enum cxd2880_dtv_sys {
> +	CXD2880_DTV_SYS_UNKNOWN,
> +	CXD2880_DTV_SYS_DVBT,
> +	CXD2880_DTV_SYS_DVBT2,
> +	CXD2880_DTV_SYS_ANY
> +};
> +
> +enum cxd2880_dtv_bandwidth {
> +	CXD2880_DTV_BW_UNKNOWN = 0,
> +	CXD2880_DTV_BW_1_7_MHZ = 1,
> +	CXD2880_DTV_BW_5_MHZ = 5,
> +	CXD2880_DTV_BW_6_MHZ = 6,
> +	CXD2880_DTV_BW_7_MHZ = 7,
> +	CXD2880_DTV_BW_8_MHZ = 8
> +};
> +
> +#endif
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
> new file mode 100644
> index 000000000000..044dc26d2ff3
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
> @@ -0,0 +1,4030 @@
> +/*
> + * cxd2880_tnrdmd.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * common control functions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_common.h"
> +#include "cxd2880_tnrdmd.h"
> +#include "cxd2880_tnrdmd_mon.h"
> +#include "cxd2880_tnrdmd_dvbt.h"
> +#include "cxd2880_tnrdmd_dvbt2.h"
> +
> +static int p_init1(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data = 0;
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) ||
> +	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)) {
> +		switch (tnr_dmd->create_param.ts_output_if) {
> +		case CXD2880_TNRDMD_TSOUT_IF_TS:
> +			data = 0x00;
> +			break;
> +		case CXD2880_TNRDMD_TSOUT_IF_SPI:
> +			data = 0x01;
> +			break;
> +		case CXD2880_TNRDMD_TSOUT_IF_SDIO:
> +			data = 0x02;
> +			break;
> +		default:
> +			return -EINVAL;
> +		}
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x10, data);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x11, 0x16);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	switch (tnr_dmd->chip_id) {
> +	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X:
> +		data = 0x1a;
> +		break;
> +	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11:
> +		data = 0x16;
> +		break;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x10, data);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->create_param.en_internal_ldo)
> +		data = 0x01;
> +	else
> +		data = 0x00;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x11, data);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x13, data);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x12, data);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	switch (tnr_dmd->chip_id) {
> +	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X:
> +		data = 0x01;
> +		break;
> +	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11:
> +		data = 0x00;
> +		break;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x69, data);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int p_init2(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data[6] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	data[0] = tnr_dmd->create_param.xosc_cap;
> +	data[1] = tnr_dmd->create_param.xosc_i;
> +	switch (tnr_dmd->create_param.xtal_share_type) {
> +	case CXD2880_TNRDMD_XTAL_SHARE_NONE:
> +		data[2] = 0x01;
> +		data[3] = 0x00;
> +		break;
> +	case CXD2880_TNRDMD_XTAL_SHARE_EXTREF:
> +		data[2] = 0x00;
> +		data[3] = 0x00;
> +		break;
> +	case CXD2880_TNRDMD_XTAL_SHARE_MASTER:
> +		data[2] = 0x01;
> +		data[3] = 0x01;
> +		break;
> +	case CXD2880_TNRDMD_XTAL_SHARE_SLAVE:
> +		data[2] = 0x00;
> +		data[3] = 0x01;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	data[4] = 0x06;
> +	data[5] = 0x00;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x13,
> +				      data,
> +				      6);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int p_init3(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data[2] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	switch (tnr_dmd->diver_mode) {
> +	case CXD2880_TNRDMD_DIVERMODE_SINGLE:
> +		data[0] = 0x00;
> +		break;
> +	case CXD2880_TNRDMD_DIVERMODE_MAIN:
> +		data[0] = 0x03;
> +		break;
> +	case CXD2880_TNRDMD_DIVERMODE_SUB:
> +		data[0] = 0x02;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	data[1] = 0x01;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x1f, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int rf_init1(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data[8] = { 0 };
> +	u8 addr = 0;
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x01;
> +	data[1] = 0x00;
> +	data[2] = 0x01;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x21, data, 3);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x01;
> +	data[1] = 0x01;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x17, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->create_param.stationary_use) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x1a, 0x06);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x4f, 0x18);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x61, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x71, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x9d, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x7d, 0x02);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x8f, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x8b, 0xc6);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x9a, 0x03);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x1c, 0x00);

You have here (and on other parts of the driver, large sequences of
data to be written. IMHO, the best would be to store those data
on some static const arrays, and have a "write_regs" function that
would flush it altogether, e. g. something like:

	struct {
		u8 reg, value;
	} cxd2880_reg_value;

	static const cxd2880_reg_value rf_init_sequence[] = {
		{0x4f, 0x18},
		{0x61, 0x00},
		{0x71, 0x00},
		...
	};

	static int rf_init1(struct cxd2880_tnrdmd *tnr_dmd)
	{
	...
		ret = tuner_write_multi_regs(tnr_dmd->io,
				             CXD2880_IO_TGT_SYS,
				             rf_init_sequence,
				             ARRAY_SIZE(rf_init_sequence));
		if (ret)
			return ret;
	...
	}

That makes both the source code and the object code smaller and
easier to understand.


> +	if (ret)
> +		return ret;
> +	data[0] = 0x00;
> +	if ((tnr_dmd->create_param.is_cxd2881gg) &&
> +	    (tnr_dmd->create_param.xtal_share_type ==
> +		CXD2880_TNRDMD_XTAL_SHARE_SLAVE))
> +		data[1] = 0x00;
> +	else
> +		data[1] = 0x1f;
> +	data[2] = 0x0a;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xb5, data, 3);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xb9, 0x07);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x33, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xc1, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xc4, 0x1e);
> +	if (ret)
> +		return ret;
> +	if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) {
> +		data[0] = 0x34;
> +		data[1] = 0x2c;
> +	} else {
> +		data[0] = 0x2f;
> +		data[1] = 0x25;
> +	}
> +	data[2] = 0x15;
> +	data[3] = 0x19;
> +	data[4] = 0x1b;
> +	data[5] = 0x15;
> +	data[6] = 0x19;
> +	data[7] = 0x1b;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xd9, data, 8);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x11);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x6c;
> +	data[1] = 0x10;
> +	data[2] = 0xa6;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x44, data, 3);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x16;
> +	data[1] = 0xa8;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x50, data, 2);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x00;
> +	data[1] = 0x22;
> +	data[2] = 0x00;
> +	data[3] = 0x88;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x62, data, 4);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x74, 0x75);
> +	if (ret)
> +		return ret;
> +	{
> +		const u8 cdata[] = {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
> +				    0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03,
> +				    0x03, 0x04, 0x04, 0x05, 0x05, 0x05, 0x02,
> +				    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
> +				    0x02, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02,
> +				    0x02, 0x03, 0x04, 0x04, 0x04};

Please don't indent without a real need. Instead, just move "cdata" to
an static const data before the function, as it increases the code
readability.

> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x7f, cdata, 40);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x16);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x00;
> +	data[1] = 0x71;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x10, data, 2);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x23, 0x89);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		const u8 cdata[] = {0xff, 0x00, 0x00, 0x00, 0x00};

Same here.

> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x27, cdata, 5);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		const u8 cdata[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
> +				    0x01, 0x00, 0x02, 0x00, 0x63, 0x00, 0x00,
> +				    0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00,
> +				    0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x09,
> +				    0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0d, 0x00,
> +				    0x0d, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f,
> +				    0x00, 0x10, 0x00, 0x79, 0x00, 0x00, 0x00,
> +				    0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01,
> +				    0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
> +				    0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05,
> +				    0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00,
> +				    0x0a, 0x03, 0xe0};

And here.

> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x3a, cdata, 80);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	data[0] = 0x03;
> +	data[1] = 0xe0;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xbc, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x51, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xc5, 0x07);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x11);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x70, 0xe9);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x76, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x78, 0x32);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x7a, 0x46);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x7c, 0x86);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x7e, 0xa4);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xe1, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->create_param.stationary_use) {
> +		data[0] = 0x06;
> +		data[1] = 0x07;
> +		data[2] = 0x1a;
> +	} else {
> +		data[0] = 0x00;
> +		data[1] = 0x08;
> +		data[2] = 0x19;
> +	}
> +	data[3] = 0x0e;
> +	data[4] = 0x09;
> +	data[5] = 0x0e;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x12);
> +	if (ret)
> +		return ret;
> +	for (addr = 0x10; addr < 0x9f; addr += 6) {
> +		if (tnr_dmd->lna_thrs_tbl_air) {
> +			u8 idx = 0;
> +
> +			idx = (addr - 0x10) / 6;
> +			data[0] =
> +			    tnr_dmd->lna_thrs_tbl_air->thrs[idx].off_on;
> +			data[1] =
> +			    tnr_dmd->lna_thrs_tbl_air->thrs[idx].on_off;
> +		}
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      addr, data, 6);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	data[0] = 0x00;
> +	data[1] = 0x08;
> +	if (tnr_dmd->create_param.stationary_use)
> +		data[2] = 0x1a;
> +	else
> +		data[2] = 0x19;
> +	data[3] = 0x0e;
> +	data[4] = 0x09;
> +	data[5] = 0x0e;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x13);
> +	if (ret)
> +		return ret;
> +	for (addr = 0x10; addr < 0xcf; addr += 6) {
> +		if (tnr_dmd->lna_thrs_tbl_cable) {
> +			u8 idx = 0;
> +
> +			idx = (addr - 0x10) / 6;
> +			data[0] =
> +			    tnr_dmd->lna_thrs_tbl_cable->thrs[idx].off_on;
> +			data[1] =
> +			    tnr_dmd->lna_thrs_tbl_cable->thrs[idx].on_off;
> +		}
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      addr, data, 6);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x11);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x08;
> +	data[1] = 0x09;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xbd, data, 2);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x08;
> +	data[1] = 0x09;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xc4, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		const u8 cdata[] = {0x20, 0x20, 0x30, 0x41, 0x50, 0x5f,
> +				    0x6f, 0x80};

And here (and on other places below).

> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0xc9, cdata, 8);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x14);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x15;
> +	data[1] = 0x18;
> +	data[2] = 0x00;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x10, data, 3);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x15, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x16);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		const u8 cdata[] = {0x00, 0x09, 0x00, 0x08, 0x00, 0x07, 0x00,
> +				    0x06, 0x00, 0x05, 0x00, 0x03, 0x00, 0x02,
> +				    0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
> +				    0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c,
> +				    0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0f, 0x00,
> +				    0x0e, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f,
> +				    0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f, 0x00,
> +				    0x0e};
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x12, cdata, 50);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x10, data, 1);
> +	if (ret)
> +		return ret;
> +	if ((data[0] & 0x01) == 0x00)
> +		return -EBUSY;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x25, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x11, data, 1);
> +	if (ret)
> +		return ret;
> +	if ((data[0] & 0x01) == 0x00)
> +		return -EBUSY;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x02, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0xe1);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x8f, 0x16);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x67, 0x60);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x6a, 0x0f);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x6c, 0x17);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x00;
> +	data[1] = 0xfe;
> +	data[2] = 0xee;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_DMD,
> +				      0x6e, data, 3);
> +	if (ret)
> +		return ret;
> +	data[0] = 0xa1;
> +	data[1] = 0x8b;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_DMD,
> +				      0x8d, data, 2);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x08;
> +	data[1] = 0x09;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_DMD,
> +				      0x77, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->create_param.stationary_use) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x80, 0xaa);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0xe2);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x41, 0xa0);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x4b, 0x68);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x25, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x1a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x10, data, 1);
> +	if (ret)
> +		return ret;
> +	if ((data[0] & 0x01) == 0x00)
> +		return -EBUSY;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x14, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x26, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int rf_init2(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data[5] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x40;
> +	data[1] = 0x40;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xea, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	data[0] = 0x00;
> +	if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X)
> +		data[1] = 0x00;
> +	else
> +		data[1] = 0x01;
> +	data[2] = 0x01;
> +	data[3] = 0x03;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x30, data, 4);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x14);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x1b, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0xe1);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xd3, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_tune1(struct cxd2880_tnrdmd *tnr_dmd,
> +		   enum cxd2880_dtv_sys sys, u32 freq_khz,
> +		   enum cxd2880_dtv_bandwidth bandwidth,
> +		   u8 is_cable, int shift_frequency_khz)
> +{
> +	u8 data[11] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	data[0] = 0x00;
> +	data[1] = 0x00;
> +	data[2] = 0x0e;
> +	data[3] = 0x00;
> +	data[4] = 0x03;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xe7, data, 5);
> +	if (ret)
> +		return ret;
> +
> +	data[0] = 0x1f;
> +	data[1] = 0x80;
> +	data[2] = 0x18;
> +	data[3] = 0x00;
> +	data[4] = 0x07;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xe7, data, 5);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	data[0] = 0x72;
> +	data[1] = 0x81;
> +	data[3] = 0x1d;
> +	data[4] = 0x6f;
> +	data[5] = 0x7e;
> +	data[7] = 0x1c;
> +	switch (sys) {
> +	case CXD2880_DTV_SYS_DVBT:
> +		data[2] = 0x94;
> +		data[6] = 0x91;
> +		break;
> +	case CXD2880_DTV_SYS_DVBT2:
> +		data[2] = 0x96;
> +		data[6] = 0x93;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x44, data, 8);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x62, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x15);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x03;
> +	data[1] = 0xe2;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x1e, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	data[0] = is_cable ? 0x01 : 0x00;
> +	data[1] = 0x00;
> +	data[2] = 0x6b;
> +	data[3] = 0x4d;
> +
> +	switch (bandwidth) {
> +	case CXD2880_DTV_BW_1_7_MHZ:
> +		data[4] = 0x03;
> +		break;
> +	case CXD2880_DTV_BW_5_MHZ:
> +	case CXD2880_DTV_BW_6_MHZ:
> +		data[4] = 0x00;
> +		break;
> +	case CXD2880_DTV_BW_7_MHZ:
> +		data[4] = 0x01;
> +		break;
> +	case CXD2880_DTV_BW_8_MHZ:
> +		data[4] = 0x02;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	data[5] = 0x00;
> +
> +	freq_khz += shift_frequency_khz;
> +
> +	data[6] = (freq_khz >> 16) & 0x0f;
> +	data[7] = (freq_khz >> 8) & 0xff;
> +	data[8] = freq_khz & 0xff;
> +	data[9] = 0xff;
> +	data[10] = 0xfe;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x52, data, 11);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_tune2(struct cxd2880_tnrdmd *tnr_dmd,
> +		   enum cxd2880_dtv_bandwidth bandwidth,
> +		   enum cxd2880_tnrdmd_clockmode clk_mode,
> +		   int shift_frequency_khz)
> +{
> +	u8 data[3] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x11);
> +	if (ret)
> +		return ret;
> +
> +	data[0] = 0x01;
> +	data[1] = 0x0e;
> +	data[2] = 0x01;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x2d, data, 3);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x1a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x29, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x2c, data, 1);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x60, data[0]);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x62, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x11);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x2d, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x2f, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	if (shift_frequency_khz != 0) {
> +		int shift_freq = 0;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0xe1);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x60, data, 2);
> +		if (ret)
> +			return ret;
> +
> +		shift_freq = shift_frequency_khz * 1000;
> +
> +		switch (clk_mode) {
> +		case CXD2880_TNRDMD_CLOCKMODE_A:
> +		case CXD2880_TNRDMD_CLOCKMODE_C:
> +		default:
> +			if (shift_freq >= 0)
> +				shift_freq = (shift_freq + 183 / 2) / 183;
> +			else
> +				shift_freq = (shift_freq - 183 / 2) / 183;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_B:
> +			if (shift_freq >= 0)
> +				shift_freq = (shift_freq + 178 / 2) / 178;
> +			else
> +				shift_freq = (shift_freq - 178 / 2) / 178;
> +			break;
> +		}
> +
> +		shift_freq +=
> +		    cxd2880_convert2s_complement((data[0] << 8) | data[1], 16);
> +
> +		if (shift_freq > 32767)
> +			shift_freq = 32767;
> +		else if (shift_freq < -32768)
> +			shift_freq = -32768;
> +
> +		data[0] = (shift_freq >> 8) & 0xff;
> +		data[1] = shift_freq & 0xff;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x60, data, 2);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x69, data, 1);
> +		if (ret)
> +			return ret;
> +
> +		shift_freq = -shift_frequency_khz;
> +
> +		if (bandwidth == CXD2880_DTV_BW_1_7_MHZ) {
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +			default:
> +				if (shift_freq >= 0)
> +					shift_freq =
> +					    (shift_freq * 1000 +
> +					     17578 / 2) / 17578;
> +				else
> +					shift_freq =
> +					    (shift_freq * 1000 -
> +					     17578 / 2) / 17578;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				if (shift_freq >= 0)
> +					shift_freq =
> +					    (shift_freq * 1000 +
> +					     17090 / 2) / 17090;
> +				else
> +					shift_freq =
> +					    (shift_freq * 1000 -
> +					     17090 / 2) / 17090;
> +				break;
> +			}
> +		} else {
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +			default:
> +				if (shift_freq >= 0)
> +					shift_freq =
> +					    (shift_freq * 1000 +
> +					     35156 / 2) / 35156;
> +				else
> +					shift_freq =
> +					    (shift_freq * 1000 -
> +					     35156 / 2) / 35156;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				if (shift_freq >= 0)
> +					shift_freq =
> +					    (shift_freq * 1000 +
> +					     34180 / 2) / 34180;
> +				else
> +					shift_freq =
> +					    (shift_freq * 1000 -
> +					     34180 / 2) / 34180;
> +				break;
> +			}
> +		}
> +
> +		shift_freq += cxd2880_convert2s_complement(data[0], 8);
> +
> +		if (shift_freq > 127)
> +			shift_freq = 127;
> +		else if (shift_freq < -128)
> +			shift_freq = -128;
> +
> +		data[0] = shift_freq & 0xff;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x69, data[0]);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (tnr_dmd->create_param.stationary_use) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0xe1);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x8a, 0x87);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_tune3(struct cxd2880_tnrdmd *tnr_dmd,
> +		   enum cxd2880_dtv_sys sys,
> +		   u8 en_fef_intmtnt_ctrl)
> +{
> +	u8 data[6] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0xe2);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x41, 0xa0);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xfe, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl) {
> +		data[0] = 0x01;
> +		data[1] = 0x01;
> +		data[2] = 0x01;
> +		data[3] = 0x01;
> +		data[4] = 0x01;
> +		data[5] = 0x01;
> +	} else {
> +		data[0] = 0x00;
> +		data[1] = 0x00;
> +		data[2] = 0x00;
> +		data[3] = 0x00;
> +		data[4] = 0x00;
> +		data[5] = 0x00;
> +	}

Instead, just do:

	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
		memset(data, 0x01, sizeof(data));
	else
		memset(data, 0x00, sizeof(data));

> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xef, data, 6);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x2d);
> +	if (ret)
> +		return ret;

> +	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
> +		data[0] = 0x00;
> +	else
> +		data[0] = 0x01;

Not actually needed, as the previous logic already set data[0]
accordingly.

> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xb1, data[0]);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_tune4(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data[2] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	{

On this function, you have lots of '{}' sequences that serves for
absolutely no purpose. Just remove them, as it makes the code
easier to read.

> +		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
> +							CXD2880_IO_TGT_SYS,
> +							0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x14;
> +		data[1] = 0x00;
> +		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
> +							CXD2880_IO_TGT_SYS,
> +							0x55, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x0b;
> +		data[1] = 0xff;
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x53, data, 2);
> +		if (ret)
> +			return ret;
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x57, 0x01);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x0b;
> +		data[1] = 0xff;
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x55, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
> +							CXD2880_IO_TGT_SYS,
> +							0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x14;
> +		data[1] = 0x00;
> +		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x53, data, 2);
> +		if (ret)
> +			return ret;
> +		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
> +							CXD2880_IO_TGT_SYS,
> +							0x57, 0x02);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xfe, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
> +						CXD2880_IO_TGT_DMD,
> +						0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
> +						CXD2880_IO_TGT_DMD,
> +						0xfe, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_sleep1(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data[3] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	{

Same happens on this function.

> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x57, 0x03);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x00;
> +		data[1] = 0x00;
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x53, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
> +							CXD2880_IO_TGT_SYS,
> +							0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x1f;
> +		data[1] = 0xff;
> +		data[2] = 0x03;
> +		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x55, data, 3);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x00;
> +		data[1] = 0x00;
> +		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x53, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x1f;
> +		data[1] = 0xff;
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x55, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int x_sleep2(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data = 0;
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x2d);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xb1, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xb2, &data, 1);
> +	if (ret)
> +		return ret;
> +	if ((data & 0x01) == 0x00)
> +		return -EBUSY;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xf4, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xf3, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xf2, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xf1, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xf0, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xef, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_sleep3(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xfd, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_sleep4(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0xe2);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x41, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int spll_reset(struct cxd2880_tnrdmd *tnr_dmd,
> +		      enum cxd2880_tnrdmd_clockmode clockmode)
> +{
> +	u8 data[4] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x29, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x28, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x27, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x26, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x27, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x22, 0x01);
> +	if (ret)
> +		return ret;
> +	switch (clockmode) {
> +	case CXD2880_TNRDMD_CLOCKMODE_A:
> +		data[0] = 0x00;
> +		break;
> +
> +	case CXD2880_TNRDMD_CLOCKMODE_B:
> +		data[0] = 0x01;
> +		break;
> +
> +	case CXD2880_TNRDMD_CLOCKMODE_C:
> +		data[0] = 0x02;
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x30, data[0]);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x22, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(2000, 3000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x10, data, 1);
> +	if (ret)
> +		return ret;
> +	if ((data[0] & 0x01) == 0x00)
> +		return -EBUSY;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x27, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x00;
> +	data[1] = 0x00;
> +	data[2] = 0x00;
> +	data[3] = 0x00;

use memset().

> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x26, data, 4);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int t_power_x(struct cxd2880_tnrdmd *tnr_dmd, u8 on)
> +{
> +	u8 data[3] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x29, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x28, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x27, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x27, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x25, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	if (on) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x2b, 0x01);
> +		if (ret)
> +			return ret;
> +
> +		usleep_range(1000, 2000);
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00, 0x0a);
> +		if (ret)
> +			return ret;
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x12, data, 1);
> +		if (ret)
> +			return ret;
> +		if ((data[0] & 0x01) == 0)
> +			return -EBUSY;
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x2a, 0x00);
> +		if (ret)
> +			return ret;
> +	} else {
> +		data[0] = 0x03;
> +		data[1] = 0x00;
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x2a, data, 2);
> +		if (ret)
> +			return ret;
> +
> +		usleep_range(1000, 2000);
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00, 0x0a);
> +		if (ret)
> +			return ret;
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x13, data, 1);
> +		if (ret)
> +			return ret;
> +		if ((data[0] & 0x01) == 0)
> +			return -EBUSY;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x25, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x11, data, 1);
> +	if (ret)
> +		return ret;
> +	if ((data[0] & 0x01) == 0)
> +		return -EBUSY;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x27, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x00;
> +	data[1] = 0x00;
> +	data[2] = 0x00;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x27, data, 3);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +struct cxd2880_tnrdmd_ts_clk_cfg {
> +	u8 srl_clk_mode;
> +	u8 srl_duty_mode;
> +	u8 ts_clk_period;
> +};
> +
> +static int set_ts_clk_mode_and_freq(struct cxd2880_tnrdmd *tnr_dmd,
> +				    enum cxd2880_dtv_sys sys)
> +{
> +	int ret = 0;
> +	u8 backwards_compatible = 0;
> +	struct cxd2880_tnrdmd_ts_clk_cfg ts_clk_cfg;
> +
> +	const struct cxd2880_tnrdmd_ts_clk_cfg srl_ts_clk_stgs[2][2] = {
> +	{
> +		{3, 1, 8,},
> +		{0, 2, 16,}
> +	},
> +	{
> +		{1, 1, 8,},
> +		{2, 2, 16,}
> +	}
> +	};

Indentation is wrong here. Also, please prefer placing the constants
with longer initialization data out of the function, as it improves
code readability. I would declare it as:


static const struct cxd2880_tnrdmd_ts_clk_cfg srl_ts_clk_stgs[2][2] = {
	{
		{3, 1, 8,},
		{0, 2, 16,}
	}, {			/* We generally close and open braces at the same line */
		{1, 1, 8,},
		{2, 2, 16,}
	}
};

> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 ts_rate_ctrl_off = 0;
> +		u8 ts_in_off = 0;
> +		u8 ts_clk_manaul_on = 0;

We don't use this "c++" style of declaring data inside the code,
except when we really need a braces block - like on if () and
while() for example. So, please move the above to the beginning of
the function.

> +
> +		if (tnr_dmd->is_ts_backwards_compatible_mode) {
> +			backwards_compatible = 1;
> +			ts_rate_ctrl_off = 1;
> +			ts_in_off = 1;
> +		} else {
> +			backwards_compatible = 0;
> +			ts_rate_ctrl_off = 0;
> +			ts_in_off = 0;
> +		}
> +
> +		if (tnr_dmd->ts_byte_clk_manual_setting) {
> +			ts_clk_manaul_on = 1;
> +			ts_rate_ctrl_off = 0;
> +		}
> +
> +		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xd3, ts_rate_ctrl_off, 0x01);
> +		if (ret)
> +			return ret;
> +
> +		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xde, ts_in_off, 0x01);
> +		if (ret)
> +			return ret;
> +
> +		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xda, ts_clk_manaul_on, 0x01);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ts_clk_cfg = srl_ts_clk_stgs[tnr_dmd->srl_ts_clk_mod_cnts]
> +				    [tnr_dmd->srl_ts_clk_frq];
> +
> +	if (tnr_dmd->ts_byte_clk_manual_setting)
> +		ts_clk_cfg.ts_clk_period = tnr_dmd->ts_byte_clk_manual_setting;
> +
> +	ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +				      CXD2880_IO_TGT_DMD,
> +				      0xc4, ts_clk_cfg.srl_clk_mode, 0x03);
> +	if (ret)
> +		return ret;
> +
> +	ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +				      CXD2880_IO_TGT_DMD,
> +				      0xd1, ts_clk_cfg.srl_duty_mode, 0x03);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD, 0xd9,
> +				     ts_clk_cfg.ts_clk_period);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data = backwards_compatible ? 0x00 : 0x01;

Same here.

> +
> +		if (sys == CXD2880_DTV_SYS_DVBT) {
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x00, 0x10);
> +			if (ret)
> +				return ret;
> +
> +			ret =
> +			    cxd2880_io_set_reg_bits(tnr_dmd->io,
> +						    CXD2880_IO_TGT_DMD,
> +						    0x66, data, 0x01);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int pid_ftr_setting(struct cxd2880_tnrdmd *tnr_dmd,
> +			   struct cxd2880_tnrdmd_pid_ftr_cfg
> +			   *pid_ftr_cfg)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	if (!pid_ftr_cfg) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x50, 0x02);
> +		if (ret)
> +			return ret;
> +	} else {
> +		u8 data[65];
> +
> +		data[0] = pid_ftr_cfg->is_negative ? 0x01 : 0x00;

As you needed an IF here, the above contruction is OK...


> +		{
> +			int i = 0;

But this should be moved to be just after "u8 data[65]" and the
extra braces/indentation should be removed.

> +
> +			for (i = 0; i < 32; i++) {
> +				if (pid_ftr_cfg->pid_cfg[i].is_en) {
> +					data[1 + (i * 2)] =
> +					    (pid_ftr_cfg->pid_cfg[i].pid
> +					     >> 8) | 0x20;
> +					data[2 + (i * 2)] =
> +					    pid_ftr_cfg->pid_cfg[i].pid
> +					    & 0xff;

For the above, the better is to violate the 80-columns limit, as,
in this specific case, it makes harder to read what's there.

> +				} else {
> +					data[1 + (i * 2)] = 0x00;
> +					data[2 + (i * 2)] = 0x00;
> +				}
> +			}
> +		}
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x50, data, 65);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +	u8 i;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     tnr_dmd->cfg_mem[i].tgt,
> +					     0x00, tnr_dmd->cfg_mem[i].bank);
> +		if (ret)
> +			return ret;
> +
> +		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +					      tnr_dmd->cfg_mem[i].tgt,
> +					      tnr_dmd->cfg_mem[i].address,
> +					      tnr_dmd->cfg_mem[i].value,
> +					      tnr_dmd->cfg_mem[i].bit_mask);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static int set_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd,
> +		       enum cxd2880_io_tgt tgt,
> +		       u8 bank, u8 address, u8 value, u8 bit_mask)
> +{
> +	u8 i;
> +	u8 value_stored = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) {
> +		if ((value_stored == 0) &&
> +		    (tnr_dmd->cfg_mem[i].tgt == tgt) &&
> +		    (tnr_dmd->cfg_mem[i].bank == bank) &&
> +		    (tnr_dmd->cfg_mem[i].address == address)) {
> +			tnr_dmd->cfg_mem[i].value &= ~bit_mask;
> +			tnr_dmd->cfg_mem[i].value |= (value & bit_mask);
> +
> +			tnr_dmd->cfg_mem[i].bit_mask |= bit_mask;
> +
> +			value_stored = 1;
> +		}
> +	}
> +
> +	if (value_stored == 0) {
> +		if (tnr_dmd->cfg_mem_last_entry <
> +		    CXD2880_TNRDMD_MAX_CFG_MEM_COUNT) {
> +			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].tgt = tgt;
> +			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bank =
> +			    bank;
> +			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].address =
> +			    address;
> +			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].value =
> +			    (value & bit_mask);
> +			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bit_mask =
> +			    bit_mask;

Same on above: better to just violate the 80 cols limit.

> +			tnr_dmd->cfg_mem_last_entry++;
> +		} else {
> +			return -EOVERFLOW;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
> +			  struct cxd2880_io *io,
> +			  struct cxd2880_tnrdmd_create_param
> +			  *create_param)
> +{
> +	if ((!tnr_dmd) || (!io) || (!create_param))
> +		return -EINVAL;
> +
> +	memset(tnr_dmd, 0, sizeof(struct cxd2880_tnrdmd));
> +
> +	tnr_dmd->io = io;
> +	tnr_dmd->create_param = *create_param;
> +
> +	tnr_dmd->diver_mode = CXD2880_TNRDMD_DIVERMODE_SINGLE;
> +	tnr_dmd->diver_sub = NULL;
> +
> +	tnr_dmd->srl_ts_clk_mod_cnts = 1;
> +	tnr_dmd->en_fef_intmtnt_base = 1;
> +	tnr_dmd->en_fef_intmtnt_lite = 1;
> +	tnr_dmd->rf_lvl_cmpstn = NULL;
> +	tnr_dmd->lna_thrs_tbl_air = NULL;
> +	tnr_dmd->lna_thrs_tbl_cable = NULL;
> +	atomic_set(&tnr_dmd->cancel, 0);
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
> +				*tnr_dmd_main,
> +				struct cxd2880_io *io_main,
> +				struct cxd2880_tnrdmd *tnr_dmd_sub,
> +				struct cxd2880_io *io_sub,
> +				struct
> +				cxd2880_tnrdmd_diver_create_param
> +				*create_param)
> +{
> +	if ((!tnr_dmd_main) || (!io_main) || (!tnr_dmd_sub) || (!io_sub) ||
> +	    (!create_param))
> +		return -EINVAL;
> +
> +	memset(tnr_dmd_main, 0, sizeof(struct cxd2880_tnrdmd));
> +	memset(tnr_dmd_sub, 0, sizeof(struct cxd2880_tnrdmd));
> +
> +	tnr_dmd_main->io = io_main;
> +	tnr_dmd_main->diver_mode = CXD2880_TNRDMD_DIVERMODE_MAIN;
> +	tnr_dmd_main->diver_sub = tnr_dmd_sub;
> +	tnr_dmd_main->create_param.en_internal_ldo =
> +	    create_param->en_internal_ldo;
> +	tnr_dmd_main->create_param.ts_output_if = create_param->ts_output_if;
> +	tnr_dmd_main->create_param.xtal_share_type =
> +	    CXD2880_TNRDMD_XTAL_SHARE_MASTER;
> +	tnr_dmd_main->create_param.xosc_cap = create_param->xosc_cap_main;
> +	tnr_dmd_main->create_param.xosc_i = create_param->xosc_i_main;
> +	tnr_dmd_main->create_param.is_cxd2881gg = create_param->is_cxd2881gg;
> +	tnr_dmd_main->create_param.stationary_use =
> +	    create_param->stationary_use;
> +
> +	tnr_dmd_sub->io = io_sub;
> +	tnr_dmd_sub->diver_mode = CXD2880_TNRDMD_DIVERMODE_SUB;
> +	tnr_dmd_sub->diver_sub = NULL;
> +	tnr_dmd_sub->create_param.en_internal_ldo =
> +	    create_param->en_internal_ldo;
> +	tnr_dmd_sub->create_param.ts_output_if = create_param->ts_output_if;
> +	tnr_dmd_sub->create_param.xtal_share_type =
> +	    CXD2880_TNRDMD_XTAL_SHARE_SLAVE;
> +	tnr_dmd_sub->create_param.xosc_cap = 0;
> +	tnr_dmd_sub->create_param.xosc_i = create_param->xosc_i_sub;
> +	tnr_dmd_sub->create_param.is_cxd2881gg = create_param->is_cxd2881gg;
> +	tnr_dmd_sub->create_param.stationary_use = create_param->stationary_use;

Same here: just violate 80 columns limit where needed.

Yet, you could consider, instead, to use memcpy(), just overriding
the fields that would be different, e. g. something like:

      memcpy(tnr_dmd_sub->create_param, create_param,
	     sizeof(*create_param));
      tnr_dmd_sub->create_param.xosc_cap = 0;

Or, alternatively, do something like:

	struct cxd2880_tnrdmd_diver_create_param *sub_param;

	sub_param = &tnr_dmd_sub->create_param;

	sub_param->en_internal_ldo = create_param->en_internal_ldo;
	sub_param->ts_output_if = create_param->ts_output_if;

> +
> +	tnr_dmd_main->srl_ts_clk_mod_cnts = 1;
> +	tnr_dmd_main->en_fef_intmtnt_base = 1;
> +	tnr_dmd_main->en_fef_intmtnt_lite = 1;
> +	tnr_dmd_main->rf_lvl_cmpstn = NULL;
> +	tnr_dmd_main->lna_thrs_tbl_air = NULL;
> +	tnr_dmd_main->lna_thrs_tbl_cable = NULL;
> +
> +	tnr_dmd_sub->srl_ts_clk_mod_cnts = 1;
> +	tnr_dmd_sub->en_fef_intmtnt_base = 1;
> +	tnr_dmd_sub->en_fef_intmtnt_lite = 1;
> +	tnr_dmd_sub->rf_lvl_cmpstn = NULL;
> +	tnr_dmd_sub->lna_thrs_tbl_air = NULL;
> +	tnr_dmd_sub->lna_thrs_tbl_cable = NULL;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB))
> +		return -EINVAL;
> +
> +	tnr_dmd->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
> +	tnr_dmd->state = CXD2880_TNRDMD_STATE_UNKNOWN;
> +	tnr_dmd->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN;
> +	tnr_dmd->frequency_khz = 0;
> +	tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN;
> +	tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN;
> +	tnr_dmd->scan_mode = 0;

if all those *_UNKNOWN are equal to zero, the best would be 
to do, instead:

	memset(tnr_dmd, 0, sizeof(tnr_dmd);

or, if this is allocated with kmalloc(), to use kzalloc() instead.

> +	atomic_set(&tnr_dmd->cancel, 0);
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		tnr_dmd->diver_sub->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
> +		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_UNKNOWN;
> +		tnr_dmd->diver_sub->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN;
> +		tnr_dmd->diver_sub->frequency_khz = 0;
> +		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN;
> +		tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN;
> +		tnr_dmd->diver_sub->scan_mode = 0;

Same here.

> +		atomic_set(&tnr_dmd->diver_sub->cancel, 0);
> +	}
> +
> +	ret = cxd2880_tnrdmd_chip_id(tnr_dmd, &tnr_dmd->chip_id);
> +	if (ret)
> +		return ret;
> +
> +	if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->chip_id))
> +		return -EOPNOTSUPP;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret =
> +		    cxd2880_tnrdmd_chip_id(tnr_dmd->diver_sub,
> +					   &tnr_dmd->diver_sub->chip_id);
> +		if (ret)
> +			return ret;
> +
> +		if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->diver_sub->chip_id))
> +			return -EOPNOTSUPP;
> +	}
> +
> +	ret = p_init1(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = p_init1(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	usleep_range(1000, 2000);
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = p_init2(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = p_init2(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(5000, 6000);
> +
> +	ret = p_init3(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = p_init3(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = rf_init1(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = rf_init1(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	{
> +		u8 cpu_task_completed = 0;

Another indent that needs to be fixed. Won't comment it anymore. You
got the idea ;-)

> +
> +		ret =
> +		    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
> +						     &cpu_task_completed);
> +		if (ret)
> +			return ret;
> +
> +		if (!cpu_task_completed)
> +			return -EBUSY;
> +	}
> +
> +	ret = rf_init2(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = rf_init2(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = load_cfg_mem(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = load_cfg_mem(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
> +					     *tnr_dmd,
> +					     u8 *task_completed)
> +{
> +	u16 cpu_status = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!task_completed))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd, &cpu_status);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		if (cpu_status == 0)
> +			*task_completed = 1;
> +		else
> +			*task_completed = 0;
> +
> +		return ret;
> +	}
> +	if (cpu_status != 0) {
> +		*task_completed = 0;
> +		return ret;
> +	}
> +
> +	ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status);
> +	if (ret)
> +		return ret;
> +
> +	if (cpu_status == 0)
> +		*task_completed = 1;
> +	else
> +		*task_completed = 0;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd *tnr_dmd,
> +					enum cxd2880_dtv_sys sys,
> +					u32 frequency_khz,
> +					enum cxd2880_dtv_bandwidth
> +					bandwidth, u8 one_seg_opt,
> +					u8 one_seg_opt_shft_dir)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	if (frequency_khz < 4000)
> +		return -ERANGE;
> +
> +	ret = cxd2880_tnrdmd_sleep(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data = 0;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00,
> +					     0x00);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x2b,
> +					     &data,
> +					     1);
> +		if (ret)
> +			return ret;
> +
> +		switch (sys) {
> +		case CXD2880_DTV_SYS_DVBT:
> +			if (data == 0x00) {
> +				ret = t_power_x(tnr_dmd, 1);
> +				if (ret)
> +					return ret;
> +
> +				if (tnr_dmd->diver_mode ==
> +				    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +					ret = t_power_x(tnr_dmd->diver_sub, 1);
> +					if (ret)
> +						return ret;
> +				}
> +			}
> +			break;
> +
> +		case CXD2880_DTV_SYS_DVBT2:
> +			if (data == 0x01) {
> +				ret = t_power_x(tnr_dmd, 0);
> +				if (ret)
> +					return ret;
> +
> +				if (tnr_dmd->diver_mode ==
> +				    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +					ret = t_power_x(tnr_dmd->diver_sub, 0);
> +					if (ret)
> +						return ret;
> +				}
> +			}
> +			break;
> +
> +		default:
> +			return -EINVAL;
> +		}
> +	}
> +
> +	{
> +		enum cxd2880_tnrdmd_clockmode new_clk_mode =
> +		    CXD2880_TNRDMD_CLOCKMODE_A;
> +
> +		ret = spll_reset(tnr_dmd, new_clk_mode);
> +		if (ret)
> +			return ret;
> +
> +		tnr_dmd->clk_mode = new_clk_mode;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret = spll_reset(tnr_dmd->diver_sub, new_clk_mode);
> +			if (ret)
> +				return ret;
> +
> +			tnr_dmd->diver_sub->clk_mode = new_clk_mode;
> +		}
> +
> +		ret = load_cfg_mem(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret = load_cfg_mem(tnr_dmd->diver_sub);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	{
> +		int shift_frequency_khz = 0;
> +
> +		if (one_seg_opt) {
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +				shift_frequency_khz = 350;
> +			} else {
> +				if (one_seg_opt_shft_dir)
> +					shift_frequency_khz = 350;
> +				else
> +					shift_frequency_khz = -350;
> +
> +				if (tnr_dmd->create_param.xtal_share_type ==
> +				    CXD2880_TNRDMD_XTAL_SHARE_SLAVE)
> +					shift_frequency_khz *= -1;
> +			}
> +		} else {
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +				shift_frequency_khz = 150;
> +			} else {
> +				switch (tnr_dmd->create_param.xtal_share_type) {
> +				case CXD2880_TNRDMD_XTAL_SHARE_NONE:
> +				case CXD2880_TNRDMD_XTAL_SHARE_EXTREF:
> +				default:
> +					shift_frequency_khz = 0;
> +					break;
> +				case CXD2880_TNRDMD_XTAL_SHARE_MASTER:
> +					shift_frequency_khz = 150;
> +					break;
> +				case CXD2880_TNRDMD_XTAL_SHARE_SLAVE:
> +					shift_frequency_khz = -150;
> +					break;
> +				}
> +			}
> +		}
> +
> +		ret =
> +		    x_tune1(tnr_dmd, sys, frequency_khz, bandwidth,
> +			    tnr_dmd->is_cable_input, shift_frequency_khz);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret =
> +			    x_tune1(tnr_dmd->diver_sub, sys, frequency_khz,
> +				    bandwidth, tnr_dmd->is_cable_input,
> +				    -shift_frequency_khz);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		usleep_range(10000, 11000);
> +
> +		{
> +			u8 cpu_task_completed = 0;
> +
> +			ret =
> +			    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
> +						     &cpu_task_completed);
> +			if (ret)
> +				return ret;
> +
> +			if (!cpu_task_completed)
> +				return -EBUSY;
> +		}
> +
> +		ret =
> +		    x_tune2(tnr_dmd, bandwidth, tnr_dmd->clk_mode,
> +			    shift_frequency_khz);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret =
> +			    x_tune2(tnr_dmd->diver_sub, bandwidth,
> +				    tnr_dmd->diver_sub->clk_mode,
> +				    -shift_frequency_khz);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) {
> +		ret = set_ts_clk_mode_and_freq(tnr_dmd, sys);
> +		if (ret)
> +			return ret;
> +	} else {
> +		struct cxd2880_tnrdmd_pid_ftr_cfg *pid_ftr_cfg;
> +
> +		if (tnr_dmd->pid_ftr_cfg_en)
> +			pid_ftr_cfg = &tnr_dmd->pid_ftr_cfg;
> +		else
> +			pid_ftr_cfg = NULL;
> +
> +		ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
> +					*tnr_dmd,
> +					enum cxd2880_dtv_sys sys,
> +					u8 en_fef_intmtnt_ctrl)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = x_tune3(tnr_dmd, sys, en_fef_intmtnt_ctrl);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = x_tune3(tnr_dmd->diver_sub, sys, en_fef_intmtnt_ctrl);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = x_tune4(tnr_dmd);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 1);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state == CXD2880_TNRDMD_STATE_SLEEP) {
> +	} else if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) {

Please don't add things like 
	if(foo) {
		// do nothing
	} else {


In this specific case, by looking on what actually happens, I guess the
best would be to write this as:

	if (tnr_dmd->state == CXD2880_TNRDMD_STATE_SLEEP)
		return 0;

	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
		return -EPERM.

And then remove the indent for all the code below. On such case,
you can also change the line that declared ret to just:

	int ret;

As it won't be needed to be initialized anymore.

> +		ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 0);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret = x_sleep1(tnr_dmd);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = x_sleep2(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret = x_sleep2(tnr_dmd->diver_sub);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		switch (tnr_dmd->sys) {
> +		case CXD2880_DTV_SYS_DVBT:
> +			ret = cxd2880_tnrdmd_dvbt_sleep_setting(tnr_dmd);
> +			if (ret)
> +				return ret;
> +			break;
> +
> +		case CXD2880_DTV_SYS_DVBT2:
> +			ret = cxd2880_tnrdmd_dvbt2_sleep_setting(tnr_dmd);
> +			if (ret)
> +				return ret;
> +			break;
> +
> +		default:
> +			return -EPERM;
> +		}
> +
> +		ret = x_sleep3(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret = x_sleep3(tnr_dmd->diver_sub);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = x_sleep4(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret = x_sleep4(tnr_dmd->diver_sub);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP;
> +		tnr_dmd->frequency_khz = 0;
> +		tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN;
> +		tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP;
> +			tnr_dmd->diver_sub->frequency_khz = 0;
> +			tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN;
> +			tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN;
> +		}
> +	} else {
> +		return -EPERM;
> +	}
> +
> +	return ret;

Return will always be zero here. So, better to just do:

	return 0;

> +}
> +
> +int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
> +			   enum cxd2880_tnrdmd_cfg_id id,
> +			   int value)
> +{
> +	int ret = 0;

I didn't mentioned on other places, but we only initialize stuff that
requires it. In the case of ret, before using it, you're doing:

	ret = cxd2880_tnrdmd_set_and_save_reg_bits()...

So, it will always be initialized before usage. So, you can declare
it as just:

	int ret;


> +	u8 data[2] = { 0 };
> +	u8 need_sub_setting = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	switch (id) {
> +	case CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc4,
> +							 value ? 0x00 : 0x10,
> +							 0x10);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc5,
> +							 value ? 0x00 : 0x02,
> +							 0x02);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc5,
> +							 value ? 0x00 : 0x04,
> +							 0x04);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xcb,
> +							 value ? 0x00 : 0x01,
> +							 0x01);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc5,
> +							 value ? 0x01 : 0x00,
> +							 0x01);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSCLK_CONT:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		tnr_dmd->srl_ts_clk_mod_cnts = value ? 0x01 : 0x00;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSCLK_MASK:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		if ((value < 0) || (value > 0x1f))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc6, value,
> +							 0x1f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSVALID_MASK:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		if ((value < 0) || (value > 0x1f))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc8, value,
> +							 0x1f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSERR_MASK:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		if ((value < 0) || (value > 0x1f))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc9, value,
> +							 0x1f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSERR_VALID_DIS:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x91,
> +							 value ? 0x01 : 0x00,
> +							 0x01);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSPIN_CURRENT:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x51, value,
> +							 0x3f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x50,
> +							 value ? 0x80 : 0x00,
> +							 0x80);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSPIN_PULLUP:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x50, value,
> +							 0x3f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSCLK_FREQ:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		if ((value < 0) || (value > 1))
> +			return -ERANGE;
> +
> +		tnr_dmd->srl_ts_clk_frq =
> +		    (enum cxd2880_tnrdmd_serial_ts_clk)value;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		if ((value < 0) || (value > 0xff))
> +			return -ERANGE;
> +
> +		tnr_dmd->ts_byte_clk_manual_setting = value;
> +
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TS_PACKET_GAP:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		if ((value < 0) || (value > 7))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xd6, value,
> +							 0x07);
> +		if (ret)
> +			return ret;
> +
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		tnr_dmd->is_ts_backwards_compatible_mode = value ? 1 : 0;
> +
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_PWM_VALUE:
> +		if ((value < 0) || (value > 0x1000))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x22,
> +							 value ? 0x01 : 0x00,
> +							 0x01);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data[2];
> +
> +			data[0] = (value >> 8) & 0x1f;
> +			data[1] = value & 0xff;
> +
> +			ret =
> +			    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x23,
> +							 data[0], 0x1f);
> +			if (ret)
> +				return ret;
> +
> +			ret =
> +			    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x24,
> +							 data[1], 0xff);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_INTERRUPT:
> +		data[0] = (value >> 8) & 0xff;
> +		data[1] = value & 0xff;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x48, data[0],
> +							 0xff);
> +		if (ret)
> +			return ret;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x49, data[1],
> +							 0xff);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL:
> +		data[0] = value & 0x07;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x4a, data[0],
> +							 0x07);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL:
> +		data[0] = (value & 0x07) << 3;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x4a, data[0],
> +							 0x38);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE:
> +		if ((value < CXD2880_TNRDMD_CLOCKMODE_UNKNOWN) ||
> +		    (value > CXD2880_TNRDMD_CLOCKMODE_C))
> +			return -ERANGE;
> +		tnr_dmd->fixed_clk_mode = (enum cxd2880_tnrdmd_clockmode)value;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_CABLE_INPUT:
> +		tnr_dmd->is_cable_input = value ? 1 : 0;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE:
> +		tnr_dmd->en_fef_intmtnt_base = value ? 1 : 0;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE:
> +		tnr_dmd->en_fef_intmtnt_lite = value ? 1 : 0;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS:
> +		data[0] = (value >> 8) & 0x07;
> +		data[1] = value & 0xff;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x99, data[0],
> +							 0x07);
> +		if (ret)
> +			return ret;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x9a, data[1],
> +							 0xff);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS:
> +		data[0] = (value >> 8) & 0x07;
> +		data[1] = value & 0xff;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x9b, data[0],
> +							 0x07);
> +		if (ret)
> +			return ret;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x9c, data[1],
> +							 0xff);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS:
> +		data[0] = (value >> 8) & 0x07;
> +		data[1] = value & 0xff;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x9d, data[0],
> +							 0x07);
> +		if (ret)
> +			return ret;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x9e, data[1],
> +							 0xff);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST:
> +		tnr_dmd->blind_tune_dvbt2_first = value ? 1 : 0;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD:
> +		if ((value < 0) || (value > 31))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x10, 0x60,
> +							 value & 0x1f, 0x1f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD:
> +		if ((value < 0) || (value > 7))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x10, 0x6f,
> +							 value & 0x07, 0x07);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT2_BBER_MES:
> +		if ((value < 0) || (value > 15))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x20, 0x72,
> +							 value & 0x0f, 0x0f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT2_LBER_MES:
> +		if ((value < 0) || (value > 15))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x20, 0x6f,
> +							 value & 0x0f, 0x0f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT_PER_MES:
> +		if ((value < 0) || (value > 15))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x10, 0x5c,
> +							 value & 0x0f, 0x0f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT2_PER_MES:
> +		if ((value < 0) || (value > 15))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x24, 0xdc,
> +							 value & 0x0f, 0x0f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	if (need_sub_setting &&
> +	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)) {
> +		ret = cxd2880_tnrdmd_set_cfg(tnr_dmd->diver_sub, id, value);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
> +				u8 id,
> +				u8 en,
> +				enum cxd2880_tnrdmd_gpio_mode mode,
> +				u8 open_drain, u8 invert)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (id > 2)
> +		return -EINVAL;
> +
> +	if (mode > CXD2880_TNRDMD_GPIO_MODE_EEW)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
> +						 0x00, 0x40 + id, mode,
> +						 0x0f);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
> +						 0x00, 0x43,
> +						 open_drain ? (1 << id) : 0,
> +						 1 << id);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
> +						 0x00, 0x44,
> +						 invert ? (1 << id) : 0,
> +						 1 << id);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
> +						 0x00, 0x45,
> +						 en ? 0 : (1 << id),
> +						 1 << id);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				    u8 id,
> +				    u8 en,
> +				    enum cxd2880_tnrdmd_gpio_mode
> +				    mode, u8 open_drain, u8 invert)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_gpio_set_cfg(tnr_dmd->diver_sub, id, en, mode,
> +					open_drain, invert);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
> +			     u8 id, u8 *value)
> +{
> +	u8 data = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!value))
> +		return -EINVAL;
> +
> +	if (id > 2)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x20, &data, 1);
> +	if (ret)
> +		return ret;
> +
> +	*value = (data >> id) & 0x01;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u8 id, u8 *value)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_gpio_read(tnr_dmd->diver_sub, id, value);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
> +			      u8 id, u8 value)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (id > 2)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +						   CXD2880_IO_TGT_SYS,
> +						   0x00, 0x46,
> +						   value ? (1 << id) : 0,
> +						   1 << id);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				  u8 id, u8 value)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_gpio_write(tnr_dmd->diver_sub, id, value);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
> +				  u16 *value)
> +{
> +	int ret = 0;
> +	u8 data[2] = { 0 };
> +
> +	if ((!tnr_dmd) || (!value))
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x15, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	*value = (data[0] << 8) | data[1];
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
> +				   u16 value)
> +{
> +	int ret = 0;
> +	u8 data[2] = { 0 };
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	data[0] = (value >> 8) & 0xff;
> +	data[1] = value & 0xff;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x3c, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
> +				u8 clear_overflow_flag,
> +				u8 clear_underflow_flag,
> +				u8 clear_buf)
> +{
> +	int ret = 0;
> +	u8 data[2] = { 0 };
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	data[0] = clear_overflow_flag ? 0x02 : 0x00;
> +	data[0] |= clear_underflow_flag ? 0x01 : 0x00;
> +	data[1] = clear_buf ? 0x01 : 0x00;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_DMD,
> +				      0x9f, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
> +			   enum cxd2880_tnrdmd_chip_id *chip_id)
> +{
> +	int ret = 0;
> +	u8 data = 0;
> +
> +	if ((!tnr_dmd) || (!chip_id))
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xfd, &data, 1);
> +	if (ret)
> +		return ret;
> +
> +	*chip_id = (enum cxd2880_tnrdmd_chip_id)data;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
> +					 *tnr_dmd,
> +					 enum cxd2880_io_tgt tgt,
> +					 u8 bank, u8 address,
> +					 u8 value, u8 bit_mask)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io, tgt, 0x00, bank);
> +	if (ret)
> +		return ret;
> +
> +	ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +				      tgt, address, value, bit_mask);
> +	if (ret)
> +		return ret;
> +
> +	ret = set_cfg_mem(tnr_dmd, tgt, bank, address, value, bit_mask);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
> +				 enum cxd2880_dtv_sys sys,
> +				 u8 scan_mode_end)
> +{
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	CXD2880_ARG_UNUSED(sys);
> +
> +	tnr_dmd->scan_mode = scan_mode_end;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		int ret = 0;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_scan_mode(tnr_dmd->diver_sub, sys,
> +						 scan_mode_end);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
> +			       struct cxd2880_tnrdmd_pid_ftr_cfg
> +			       *pid_ftr_cfg)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS)
> +		return -EOPNOTSUPP;
> +
> +	if (pid_ftr_cfg) {
> +		tnr_dmd->pid_ftr_cfg = *pid_ftr_cfg;
> +		tnr_dmd->pid_ftr_cfg_en = 1;
> +	} else {
> +		tnr_dmd->pid_ftr_cfg_en = 0;
> +	}
> +
> +	if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) {
> +		ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     int (*rf_lvl_cmpstn)
> +				     (struct cxd2880_tnrdmd *,
> +				     int *))
> +{
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	tnr_dmd->rf_lvl_cmpstn = rf_lvl_cmpstn;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd
> +					 *tnr_dmd,
> +					 int (*rf_lvl_cmpstn)
> +					 (struct cxd2880_tnrdmd *,
> +					 int *))
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_set_rf_lvl_cmpstn(tnr_dmd->diver_sub,
> +					       rf_lvl_cmpstn);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
> +				struct cxd2880_tnrdmd_lna_thrs_tbl_air
> +				*tbl_air,
> +				struct cxd2880_tnrdmd_lna_thrs_tbl_cable
> +				*tbl_cable)
> +{
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	tnr_dmd->lna_thrs_tbl_air = tbl_air;
> +	tnr_dmd->lna_thrs_tbl_cable = tbl_cable;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				    struct
> +				    cxd2880_tnrdmd_lna_thrs_tbl_air
> +				    *tbl_air,
> +				    struct cxd2880_tnrdmd_lna_thrs_tbl_cable
> +				    *tbl_cable)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_set_lna_thrs(tnr_dmd->diver_sub,
> +					  tbl_air, tbl_cable);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 en, u8 value)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +		return -EPERM;
> +
> +	if (tnr_dmd->create_param.ts_output_if != CXD2880_TNRDMD_TSOUT_IF_TS)
> +		return -EOPNOTSUPP;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	if (en) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x50, ((value & 0x1f) | 0x80));
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x52, (value & 0x1f));
> +		if (ret)
> +			return ret;
> +	} else {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x50, 0x3f);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x52, 0x1f);
> +		if (ret)
> +			return ret;
> +
> +		ret = load_cfg_mem(tnr_dmd);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u8 en)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	switch (tnr_dmd->create_param.ts_output_if) {
> +	case CXD2880_TNRDMD_TSOUT_IF_TS:
> +		if (en) {
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_SYS,
> +						     0x00, 0x00);
> +			if (ret)
> +				return ret;
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_SYS,
> +						     0x52, 0x00);
> +			if (ret)
> +				return ret;
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x00, 0x00);
> +			if (ret)
> +				return ret;
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0xc3, 0x00);
> +			if (ret)
> +				return ret;
> +		} else {
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x00, 0x00);
> +			if (ret)
> +				return ret;
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0xc3, 0x01);
> +			if (ret)
> +				return ret;
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_SYS,
> +						     0x00, 0x00);
> +			if (ret)
> +				return ret;
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_SYS,
> +						     0x52, 0x1f);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_TNRDMD_TSOUT_IF_SPI:
> +		break;
> +
> +	case CXD2880_TNRDMD_TSOUT_IF_SDIO:
> +		break;
> +
> +	default:
> +		return -EPERM;
> +	}
> +
> +	return 0;
> +}
> +
> +int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	switch (tnr_dmd->create_param.ts_output_if) {
> +	case CXD2880_TNRDMD_TSOUT_IF_SPI:
> +	case CXD2880_TNRDMD_TSOUT_IF_SDIO:
> +		{
> +			u8 data = 0;
> +
> +			ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x00, &data, 1);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +	case CXD2880_TNRDMD_TSOUT_IF_TS:
> +	default:
> +		break;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x01, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
> new file mode 100644
> index 000000000000..c168c9f27dad
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
> @@ -0,0 +1,391 @@
> +/*
> + * cxd2880_tnrdmd.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * common control interface
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_TNRDMD_H
> +#define CXD2880_TNRDMD_H
> +
> +#include <linux/atomic.h>
> +
> +#include "cxd2880_common.h"
> +#include "cxd2880_io.h"
> +#include "cxd2880_dtv.h"
> +#include "cxd2880_dvbt.h"
> +#include "cxd2880_dvbt2.h"
> +
> +#define CXD2880_TNRDMD_MAX_CFG_MEM_COUNT 100
> +
> +#define slvt_unfreeze_reg(tnr_dmd) ((void)((tnr_dmd)->io->write_reg\
> +((tnr_dmd)->io, CXD2880_IO_TGT_DMD, 0x01, 0x00)))
> +
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_UNDERFLOW     0x0001
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_OVERFLOW      0x0002
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_EMPTY  0x0004
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_FULL   0x0008
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_RRDY	  0x0010
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_COMMAND      0x0020
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_ACCESS       0x0040
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_CPU_ERROR	    0x0100
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_LOCK		 0x0200
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_INV_LOCK	     0x0400
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_NOOFDM	       0x0800
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_EWS		  0x1000
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_EEW		  0x2000
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_FEC_FAIL	     0x4000
> +
> +#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_L1POST_OK	0x01
> +#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_DMD_LOCK	 0x02
> +#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_TS_LOCK	  0x04
> +
> +enum cxd2880_tnrdmd_chip_id {
> +	CXD2880_TNRDMD_CHIP_ID_UNKNOWN = 0x00,
> +	CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X = 0x62,
> +	CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11 = 0x6a
> +};
> +
> +#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) (((chip_id) == \
> +CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \
> +((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11))

The line breaks here make it harder to read. Better to declare it as:

#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) \
	(((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \
	 ((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11))


> +
> +enum cxd2880_tnrdmd_state {
> +	CXD2880_TNRDMD_STATE_UNKNOWN,
> +	CXD2880_TNRDMD_STATE_SLEEP,
> +	CXD2880_TNRDMD_STATE_ACTIVE,
> +	CXD2880_TNRDMD_STATE_INVALID
> +};
> +
> +enum cxd2880_tnrdmd_divermode {
> +	CXD2880_TNRDMD_DIVERMODE_SINGLE,
> +	CXD2880_TNRDMD_DIVERMODE_MAIN,
> +	CXD2880_TNRDMD_DIVERMODE_SUB
> +};
> +
> +enum cxd2880_tnrdmd_clockmode {
> +	CXD2880_TNRDMD_CLOCKMODE_UNKNOWN,
> +	CXD2880_TNRDMD_CLOCKMODE_A,
> +	CXD2880_TNRDMD_CLOCKMODE_B,
> +	CXD2880_TNRDMD_CLOCKMODE_C
> +};
> +
> +enum cxd2880_tnrdmd_tsout_if {
> +	CXD2880_TNRDMD_TSOUT_IF_TS,
> +	CXD2880_TNRDMD_TSOUT_IF_SPI,
> +	CXD2880_TNRDMD_TSOUT_IF_SDIO
> +};
> +
> +enum cxd2880_tnrdmd_xtal_share {
> +	CXD2880_TNRDMD_XTAL_SHARE_NONE,
> +	CXD2880_TNRDMD_XTAL_SHARE_EXTREF,
> +	CXD2880_TNRDMD_XTAL_SHARE_MASTER,
> +	CXD2880_TNRDMD_XTAL_SHARE_SLAVE
> +};
> +
> +enum cxd2880_tnrdmd_spectrum_sense {
> +	CXD2880_TNRDMD_SPECTRUM_NORMAL,
> +	CXD2880_TNRDMD_SPECTRUM_INV
> +};
> +
> +enum cxd2880_tnrdmd_cfg_id {
> +	CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB,
> +	CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI,
> +	CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI,
> +	CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI,
> +	CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE,
> +	CXD2880_TNRDMD_CFG_TSCLK_CONT,
> +	CXD2880_TNRDMD_CFG_TSCLK_MASK,
> +	CXD2880_TNRDMD_CFG_TSVALID_MASK,
> +	CXD2880_TNRDMD_CFG_TSERR_MASK,
> +	CXD2880_TNRDMD_CFG_TSERR_VALID_DIS,
> +	CXD2880_TNRDMD_CFG_TSPIN_CURRENT,
> +	CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL,
> +	CXD2880_TNRDMD_CFG_TSPIN_PULLUP,
> +	CXD2880_TNRDMD_CFG_TSCLK_FREQ,
> +	CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL,
> +	CXD2880_TNRDMD_CFG_TS_PACKET_GAP,
> +	CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE,
> +	CXD2880_TNRDMD_CFG_PWM_VALUE,
> +	CXD2880_TNRDMD_CFG_INTERRUPT,
> +	CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL,
> +	CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL,
> +	CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS,
> +	CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS,
> +	CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS,
> +	CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE,
> +	CXD2880_TNRDMD_CFG_CABLE_INPUT,
> +	CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE,
> +	CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE,
> +	CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST,
> +	CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
> +	CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
> +	CXD2880_TNRDMD_CFG_DVBT_PER_MES,
> +	CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
> +	CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
> +	CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
> +};
> +
> +enum cxd2880_tnrdmd_lock_result {
> +	CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT,
> +	CXD2880_TNRDMD_LOCK_RESULT_LOCKED,
> +	CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED
> +};
> +
> +enum cxd2880_tnrdmd_gpio_mode {
> +	CXD2880_TNRDMD_GPIO_MODE_OUTPUT = 0x00,
> +	CXD2880_TNRDMD_GPIO_MODE_INPUT = 0x01,
> +	CXD2880_TNRDMD_GPIO_MODE_INT = 0x02,
> +	CXD2880_TNRDMD_GPIO_MODE_FEC_FAIL = 0x03,
> +	CXD2880_TNRDMD_GPIO_MODE_PWM = 0x04,
> +	CXD2880_TNRDMD_GPIO_MODE_EWS = 0x05,
> +	CXD2880_TNRDMD_GPIO_MODE_EEW = 0x06
> +};
> +
> +enum cxd2880_tnrdmd_serial_ts_clk {
> +	CXD2880_TNRDMD_SERIAL_TS_CLK_FULL,
> +	CXD2880_TNRDMD_SERIAL_TS_CLK_HALF
> +};
> +
> +struct cxd2880_tnrdmd_cfg_mem {
> +	enum cxd2880_io_tgt tgt;
> +	u8 bank;
> +	u8 address;
> +	u8 value;
> +	u8 bit_mask;
> +};
> +
> +struct cxd2880_tnrdmd_pid_cfg {
> +	u8 is_en;
> +	u16 pid;
> +};
> +
> +struct cxd2880_tnrdmd_pid_ftr_cfg {
> +	u8 is_negative;
> +	struct cxd2880_tnrdmd_pid_cfg pid_cfg[32];
> +};
> +
> +struct cxd2880_tnrdmd_ts_buf_info {
> +	u8 read_ready;
> +	u8 almost_full;
> +	u8 almost_empty;
> +	u8 overflow;
> +	u8 underflow;
> +	u16 packet_num;
> +};
> +
> +struct cxd2880_tnrdmd_lna_thrs {
> +	u8 off_on;
> +	u8 on_off;
> +};
> +
> +struct cxd2880_tnrdmd_lna_thrs_tbl_air {
> +	struct cxd2880_tnrdmd_lna_thrs thrs[24];
> +};
> +
> +struct cxd2880_tnrdmd_lna_thrs_tbl_cable {
> +	struct cxd2880_tnrdmd_lna_thrs thrs[32];
> +};
> +
> +struct cxd2880_tnrdmd_create_param {
> +	enum cxd2880_tnrdmd_tsout_if ts_output_if;
> +	u8 en_internal_ldo;
> +	enum cxd2880_tnrdmd_xtal_share xtal_share_type;
> +	u8 xosc_cap;
> +	u8 xosc_i;
> +	u8 is_cxd2881gg;
> +	u8 stationary_use;
> +};
> +
> +struct cxd2880_tnrdmd_diver_create_param {
> +	enum cxd2880_tnrdmd_tsout_if ts_output_if;
> +	u8 en_internal_ldo;
> +	u8 xosc_cap_main;
> +	u8 xosc_i_main;
> +	u8 xosc_i_sub;
> +	u8 is_cxd2881gg;
> +	u8 stationary_use;
> +};
> +
> +struct cxd2880_tnrdmd {
> +	struct cxd2880_tnrdmd *diver_sub;
> +	struct cxd2880_io *io;
> +	struct cxd2880_tnrdmd_create_param create_param;
> +	enum cxd2880_tnrdmd_divermode diver_mode;
> +	enum cxd2880_tnrdmd_clockmode fixed_clk_mode;
> +	u8 is_cable_input;
> +	u8 en_fef_intmtnt_base;
> +	u8 en_fef_intmtnt_lite;
> +	u8 blind_tune_dvbt2_first;
> +	int (*rf_lvl_cmpstn)(struct cxd2880_tnrdmd *tnr_dmd,
> +			     int *rf_lvl_db);
> +	struct cxd2880_tnrdmd_lna_thrs_tbl_air *lna_thrs_tbl_air;
> +	struct cxd2880_tnrdmd_lna_thrs_tbl_cable *lna_thrs_tbl_cable;
> +	u8 srl_ts_clk_mod_cnts;
> +	enum cxd2880_tnrdmd_serial_ts_clk srl_ts_clk_frq;
> +	u8 ts_byte_clk_manual_setting;
> +	u8 is_ts_backwards_compatible_mode;
> +	struct cxd2880_tnrdmd_cfg_mem cfg_mem[CXD2880_TNRDMD_MAX_CFG_MEM_COUNT];
> +	u8 cfg_mem_last_entry;
> +	struct cxd2880_tnrdmd_pid_ftr_cfg pid_ftr_cfg;
> +	u8 pid_ftr_cfg_en;
> +	void *user;
> +	enum cxd2880_tnrdmd_chip_id chip_id;
> +	enum cxd2880_tnrdmd_state state;
> +	enum cxd2880_tnrdmd_clockmode clk_mode;
> +	u32 frequency_khz;
> +	enum cxd2880_dtv_sys sys;
> +	enum cxd2880_dtv_bandwidth bandwidth;
> +	u8 scan_mode;
> +	atomic_t cancel;
> +};
> +
> +int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
> +			  struct cxd2880_io *io,
> +			  struct cxd2880_tnrdmd_create_param
> +			  *create_param);
> +
> +int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
> +				*tnr_dmd_main,
> +				struct cxd2880_io *io_main,
> +				struct cxd2880_tnrdmd *tnr_dmd_sub,
> +				struct cxd2880_io *io_sub,
> +				struct
> +				cxd2880_tnrdmd_diver_create_param
> +				*create_param);
> +
> +int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
> +					     *tnr_dmd,
> +					     u8 *task_completed);
> +
> +int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd
> +					*tnr_dmd,
> +					enum cxd2880_dtv_sys sys,
> +					u32 frequency_khz,
> +					enum cxd2880_dtv_bandwidth
> +					bandwidth, u8 one_seg_opt,
> +					u8 one_seg_opt_shft_dir);
> +
> +int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
> +					*tnr_dmd,
> +					enum cxd2880_dtv_sys sys,
> +					u8 en_fef_intmtnt_ctrl);
> +
> +int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
> +			   enum cxd2880_tnrdmd_cfg_id id,
> +			   int value);
> +
> +int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
> +				u8 id,
> +				u8 en,
> +				enum cxd2880_tnrdmd_gpio_mode mode,
> +				u8 open_drain, u8 invert);
> +
> +int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				    u8 id,
> +				    u8 en,
> +				    enum cxd2880_tnrdmd_gpio_mode
> +				    mode, u8 open_drain,
> +				    u8 invert);
> +
> +int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
> +			     u8 id, u8 *value);
> +
> +int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u8 id, u8 *value);
> +
> +int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
> +			      u8 id, u8 value);
> +
> +int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				  u8 id, u8 value);
> +
> +int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
> +				  u16 *value);
> +
> +int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
> +				   u16 value);
> +
> +int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
> +				u8 clear_overflow_flag,
> +				u8 clear_underflow_flag,
> +				u8 clear_buf);
> +
> +int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
> +			   enum cxd2880_tnrdmd_chip_id *chip_id);
> +
> +int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
> +					 *tnr_dmd,
> +					 enum cxd2880_io_tgt tgt,
> +					 u8 bank, u8 address,
> +					 u8 value, u8 bit_mask);
> +
> +int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
> +				 enum cxd2880_dtv_sys sys,
> +				 u8 scan_mode_end);
> +
> +int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
> +			       struct cxd2880_tnrdmd_pid_ftr_cfg
> +			       *pid_ftr_cfg);
> +
> +int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     int (*rf_lvl_cmpstn)
> +				     (struct cxd2880_tnrdmd *,
> +				     int *));
> +
> +int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +					 int (*rf_lvl_cmpstn)
> +					 (struct cxd2880_tnrdmd *,
> +					 int *));
> +
> +int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
> +				struct
> +				cxd2880_tnrdmd_lna_thrs_tbl_air
> +				*tbl_air,
> +				struct
> +				cxd2880_tnrdmd_lna_thrs_tbl_cable
> +				*tbl_cable);
> +
> +int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				    struct
> +				    cxd2880_tnrdmd_lna_thrs_tbl_air
> +				    *tbl_air,
> +				    struct
> +				    cxd2880_tnrdmd_lna_thrs_tbl_cable
> +				    *tbl_cable);
> +
> +int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 en, u8 value);
> +
> +int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u8 en);
> +
> +int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +#endif
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
> new file mode 100644
> index 000000000000..bb0f6b295ed3
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
> @@ -0,0 +1,29 @@
> +/*
> + * cxd2880_tnrdmd_driver_version.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * version information
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.2"
> +
> +#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2017-08-07"
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
> new file mode 100644
> index 000000000000..1ed415af3727
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
> @@ -0,0 +1,221 @@
> +/*
> + * cxd2880_tnrdmd_mon.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * common monitor functions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_common.h"
> +#include "cxd2880_tnrdmd_mon.h"
> +
> +int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
> +			      int *rf_lvl_db)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!rf_lvl_db))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data[2] = { 0x80, 0x00 };
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x5b, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	usleep_range(2000, 3000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x1a);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data[2];
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x15, data, 2);
> +		if (ret)
> +			return ret;
> +
> +		if ((data[0] != 0) || (data[1] != 0))
> +			return -EPERM;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x11, data, 2);
> +		if (ret)
> +			return ret;
> +
> +		*rf_lvl_db =
> +		    cxd2880_convert2s_complement((data[0] << 3) |
> +						 ((data[1] & 0xe0) >> 5), 11);
> +	}
> +
> +	*rf_lvl_db *= 125;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->rf_lvl_cmpstn) {
> +		ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				  int *rf_lvl_db)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!rf_lvl_db))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
> +					   *tnr_dmd, u16 *status)
> +{
> +	u8 data[2] = { 0 };
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!status))
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x1a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x15, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	*status = (data[0] << 8) | data[1];
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
> +					       cxd2880_tnrdmd
> +					       *tnr_dmd,
> +					       u16 *status)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!status))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub, status);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd,
> +				   struct
> +				   cxd2880_tnrdmd_ts_buf_info
> +				   *info)
> +{
> +	u8 data[3] = { 0 };
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!info))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x50, data, 3);
> +	if (ret)
> +		return ret;
> +
> +	info->read_ready = (data[0] & 0x10) ? 0x01 : 0x00;
> +	info->almost_full = (data[0] & 0x08) ? 0x01 : 0x00;
> +	info->almost_empty = (data[0] & 0x04) ? 0x01 : 0x00;
> +	info->overflow = (data[0] & 0x02) ? 0x01 : 0x00;
> +	info->underflow = (data[0] & 0x01) ? 0x01 : 0x00;
> +
> +	info->packet_num = ((data[1] & 0x07) << 8) | data[2];
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
> new file mode 100644
> index 000000000000..a4c34f56a7a1
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
> @@ -0,0 +1,52 @@
> +/*
> + * cxd2880_tnrdmd_mon.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * common monitor interface
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_TNRDMD_MON_H
> +#define CXD2880_TNRDMD_MON_H
> +
> +#include "cxd2880_common.h"
> +#include "cxd2880_tnrdmd.h"
> +
> +int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
> +			      int *rf_lvl_db);
> +
> +int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				  int *rf_lvl_db);
> +
> +int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
> +					   *tnr_dmd, u16 *status);
> +
> +int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
> +					       cxd2880_tnrdmd
> +					       *tnr_dmd,
> +					       u16 *status);
> +
> +int cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd,
> +				   struct
> +				   cxd2880_tnrdmd_ts_buf_info
> +				   *info);
> +
> +#endif



Thanks,
Mauro

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 05/14] [media] cxd2880: Add tuner part of the driver
@ 2017-08-27 14:45     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 14:45 UTC (permalink / raw)
  To: Yasunari.Takiguchi-7U/KSKJipcs
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

Em Wed, 16 Aug 2017 13:37:14 +0900
<Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
> 
> This part of the driver has the main routines to handle
> the tuner and demodulator functionality.  The tnrdmd_mon.* files
> have monitor functions for the driver.
> This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

This series is on a much better state. Thanks!

Patches 1-4 sound ok to me.

Still, there are a few issues on this patch. See below.

> 
> [Change list]
> Changes in V3
>    drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
>       -removed code relevant to ISDB-T

Just curiosity here: why is it removed?

>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
>       -removed unnecessary cast
>       -removed code relevant to ISDB-T
>       -changed CXD2880_SLEEP to usleep_range
>       -changed cxd2880_memset to memset 
>       -changed cxd2880_atomic_set to atomic_set
>       -modified return code
>       -modified coding style of if()
>       -changed to use const values at writing a lot of registers 
>        with a command. 
>       -changed hexadecimal code to lower case. 
>       -adjusted of indent spaces
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
>       -removed code relevant to ISDB-T
>       -changed cxd2880_atomic struct to atomic_t
>       -modified return code
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
>       -updated version information
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
>       -changed CXD2880_SLEEP to usleep_range
>       -removed unnecessary cast
>       -modified return code
>       -modified coding style of if() 
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
>       -modified return code
> 
> Changes in V2
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
>       -updated version information
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
> ---
>  drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h  |   46 +
>  .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c   | 4030 ++++++++++++++++++++
>  .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h   |  391 ++
>  .../cxd2880/cxd2880_tnrdmd_driver_version.h        |   29 +
>  .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c     |  221 ++
>  .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h     |   52 +
>  6 files changed, 4769 insertions(+)
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
> 
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
> new file mode 100644
> index 000000000000..2d35d3990060
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
> @@ -0,0 +1,46 @@
> +/*
> + * cxd2880_dtv.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DTV related definitions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_DTV_H
> +#define CXD2880_DTV_H
> +
> +enum cxd2880_dtv_sys {
> +	CXD2880_DTV_SYS_UNKNOWN,
> +	CXD2880_DTV_SYS_DVBT,
> +	CXD2880_DTV_SYS_DVBT2,
> +	CXD2880_DTV_SYS_ANY
> +};
> +
> +enum cxd2880_dtv_bandwidth {
> +	CXD2880_DTV_BW_UNKNOWN = 0,
> +	CXD2880_DTV_BW_1_7_MHZ = 1,
> +	CXD2880_DTV_BW_5_MHZ = 5,
> +	CXD2880_DTV_BW_6_MHZ = 6,
> +	CXD2880_DTV_BW_7_MHZ = 7,
> +	CXD2880_DTV_BW_8_MHZ = 8
> +};
> +
> +#endif
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
> new file mode 100644
> index 000000000000..044dc26d2ff3
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c
> @@ -0,0 +1,4030 @@
> +/*
> + * cxd2880_tnrdmd.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * common control functions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_common.h"
> +#include "cxd2880_tnrdmd.h"
> +#include "cxd2880_tnrdmd_mon.h"
> +#include "cxd2880_tnrdmd_dvbt.h"
> +#include "cxd2880_tnrdmd_dvbt2.h"
> +
> +static int p_init1(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data = 0;
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) ||
> +	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)) {
> +		switch (tnr_dmd->create_param.ts_output_if) {
> +		case CXD2880_TNRDMD_TSOUT_IF_TS:
> +			data = 0x00;
> +			break;
> +		case CXD2880_TNRDMD_TSOUT_IF_SPI:
> +			data = 0x01;
> +			break;
> +		case CXD2880_TNRDMD_TSOUT_IF_SDIO:
> +			data = 0x02;
> +			break;
> +		default:
> +			return -EINVAL;
> +		}
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x10, data);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x11, 0x16);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	switch (tnr_dmd->chip_id) {
> +	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X:
> +		data = 0x1a;
> +		break;
> +	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11:
> +		data = 0x16;
> +		break;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x10, data);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->create_param.en_internal_ldo)
> +		data = 0x01;
> +	else
> +		data = 0x00;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x11, data);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x13, data);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x12, data);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	switch (tnr_dmd->chip_id) {
> +	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X:
> +		data = 0x01;
> +		break;
> +	case CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11:
> +		data = 0x00;
> +		break;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x69, data);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int p_init2(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data[6] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	data[0] = tnr_dmd->create_param.xosc_cap;
> +	data[1] = tnr_dmd->create_param.xosc_i;
> +	switch (tnr_dmd->create_param.xtal_share_type) {
> +	case CXD2880_TNRDMD_XTAL_SHARE_NONE:
> +		data[2] = 0x01;
> +		data[3] = 0x00;
> +		break;
> +	case CXD2880_TNRDMD_XTAL_SHARE_EXTREF:
> +		data[2] = 0x00;
> +		data[3] = 0x00;
> +		break;
> +	case CXD2880_TNRDMD_XTAL_SHARE_MASTER:
> +		data[2] = 0x01;
> +		data[3] = 0x01;
> +		break;
> +	case CXD2880_TNRDMD_XTAL_SHARE_SLAVE:
> +		data[2] = 0x00;
> +		data[3] = 0x01;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	data[4] = 0x06;
> +	data[5] = 0x00;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x13,
> +				      data,
> +				      6);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int p_init3(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data[2] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	switch (tnr_dmd->diver_mode) {
> +	case CXD2880_TNRDMD_DIVERMODE_SINGLE:
> +		data[0] = 0x00;
> +		break;
> +	case CXD2880_TNRDMD_DIVERMODE_MAIN:
> +		data[0] = 0x03;
> +		break;
> +	case CXD2880_TNRDMD_DIVERMODE_SUB:
> +		data[0] = 0x02;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	data[1] = 0x01;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x1f, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int rf_init1(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data[8] = { 0 };
> +	u8 addr = 0;
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x01;
> +	data[1] = 0x00;
> +	data[2] = 0x01;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x21, data, 3);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x01;
> +	data[1] = 0x01;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x17, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->create_param.stationary_use) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x1a, 0x06);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x4f, 0x18);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x61, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x71, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x9d, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x7d, 0x02);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x8f, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x8b, 0xc6);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x9a, 0x03);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x1c, 0x00);

You have here (and on other parts of the driver, large sequences of
data to be written. IMHO, the best would be to store those data
on some static const arrays, and have a "write_regs" function that
would flush it altogether, e. g. something like:

	struct {
		u8 reg, value;
	} cxd2880_reg_value;

	static const cxd2880_reg_value rf_init_sequence[] = {
		{0x4f, 0x18},
		{0x61, 0x00},
		{0x71, 0x00},
		...
	};

	static int rf_init1(struct cxd2880_tnrdmd *tnr_dmd)
	{
	...
		ret = tuner_write_multi_regs(tnr_dmd->io,
				             CXD2880_IO_TGT_SYS,
				             rf_init_sequence,
				             ARRAY_SIZE(rf_init_sequence));
		if (ret)
			return ret;
	...
	}

That makes both the source code and the object code smaller and
easier to understand.


> +	if (ret)
> +		return ret;
> +	data[0] = 0x00;
> +	if ((tnr_dmd->create_param.is_cxd2881gg) &&
> +	    (tnr_dmd->create_param.xtal_share_type ==
> +		CXD2880_TNRDMD_XTAL_SHARE_SLAVE))
> +		data[1] = 0x00;
> +	else
> +		data[1] = 0x1f;
> +	data[2] = 0x0a;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xb5, data, 3);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xb9, 0x07);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x33, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xc1, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xc4, 0x1e);
> +	if (ret)
> +		return ret;
> +	if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) {
> +		data[0] = 0x34;
> +		data[1] = 0x2c;
> +	} else {
> +		data[0] = 0x2f;
> +		data[1] = 0x25;
> +	}
> +	data[2] = 0x15;
> +	data[3] = 0x19;
> +	data[4] = 0x1b;
> +	data[5] = 0x15;
> +	data[6] = 0x19;
> +	data[7] = 0x1b;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xd9, data, 8);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x11);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x6c;
> +	data[1] = 0x10;
> +	data[2] = 0xa6;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x44, data, 3);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x16;
> +	data[1] = 0xa8;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x50, data, 2);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x00;
> +	data[1] = 0x22;
> +	data[2] = 0x00;
> +	data[3] = 0x88;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x62, data, 4);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x74, 0x75);
> +	if (ret)
> +		return ret;
> +	{
> +		const u8 cdata[] = {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
> +				    0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03,
> +				    0x03, 0x04, 0x04, 0x05, 0x05, 0x05, 0x02,
> +				    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
> +				    0x02, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02,
> +				    0x02, 0x03, 0x04, 0x04, 0x04};

Please don't indent without a real need. Instead, just move "cdata" to
an static const data before the function, as it increases the code
readability.

> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x7f, cdata, 40);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x16);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x00;
> +	data[1] = 0x71;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x10, data, 2);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x23, 0x89);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		const u8 cdata[] = {0xff, 0x00, 0x00, 0x00, 0x00};

Same here.

> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x27, cdata, 5);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		const u8 cdata[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
> +				    0x01, 0x00, 0x02, 0x00, 0x63, 0x00, 0x00,
> +				    0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00,
> +				    0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x09,
> +				    0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0d, 0x00,
> +				    0x0d, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f,
> +				    0x00, 0x10, 0x00, 0x79, 0x00, 0x00, 0x00,
> +				    0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01,
> +				    0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
> +				    0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x05,
> +				    0x00, 0x07, 0x00, 0x07, 0x00, 0x08, 0x00,
> +				    0x0a, 0x03, 0xe0};

And here.

> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x3a, cdata, 80);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	data[0] = 0x03;
> +	data[1] = 0xe0;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xbc, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x51, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xc5, 0x07);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x11);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x70, 0xe9);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x76, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x78, 0x32);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x7a, 0x46);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x7c, 0x86);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x7e, 0xa4);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xe1, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->create_param.stationary_use) {
> +		data[0] = 0x06;
> +		data[1] = 0x07;
> +		data[2] = 0x1a;
> +	} else {
> +		data[0] = 0x00;
> +		data[1] = 0x08;
> +		data[2] = 0x19;
> +	}
> +	data[3] = 0x0e;
> +	data[4] = 0x09;
> +	data[5] = 0x0e;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x12);
> +	if (ret)
> +		return ret;
> +	for (addr = 0x10; addr < 0x9f; addr += 6) {
> +		if (tnr_dmd->lna_thrs_tbl_air) {
> +			u8 idx = 0;
> +
> +			idx = (addr - 0x10) / 6;
> +			data[0] =
> +			    tnr_dmd->lna_thrs_tbl_air->thrs[idx].off_on;
> +			data[1] =
> +			    tnr_dmd->lna_thrs_tbl_air->thrs[idx].on_off;
> +		}
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      addr, data, 6);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	data[0] = 0x00;
> +	data[1] = 0x08;
> +	if (tnr_dmd->create_param.stationary_use)
> +		data[2] = 0x1a;
> +	else
> +		data[2] = 0x19;
> +	data[3] = 0x0e;
> +	data[4] = 0x09;
> +	data[5] = 0x0e;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x13);
> +	if (ret)
> +		return ret;
> +	for (addr = 0x10; addr < 0xcf; addr += 6) {
> +		if (tnr_dmd->lna_thrs_tbl_cable) {
> +			u8 idx = 0;
> +
> +			idx = (addr - 0x10) / 6;
> +			data[0] =
> +			    tnr_dmd->lna_thrs_tbl_cable->thrs[idx].off_on;
> +			data[1] =
> +			    tnr_dmd->lna_thrs_tbl_cable->thrs[idx].on_off;
> +		}
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      addr, data, 6);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x11);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x08;
> +	data[1] = 0x09;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xbd, data, 2);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x08;
> +	data[1] = 0x09;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xc4, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		const u8 cdata[] = {0x20, 0x20, 0x30, 0x41, 0x50, 0x5f,
> +				    0x6f, 0x80};

And here (and on other places below).

> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0xc9, cdata, 8);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x14);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x15;
> +	data[1] = 0x18;
> +	data[2] = 0x00;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x10, data, 3);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x15, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x16);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		const u8 cdata[] = {0x00, 0x09, 0x00, 0x08, 0x00, 0x07, 0x00,
> +				    0x06, 0x00, 0x05, 0x00, 0x03, 0x00, 0x02,
> +				    0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
> +				    0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c,
> +				    0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0f, 0x00,
> +				    0x0e, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f,
> +				    0x00, 0x0e, 0x00, 0x10, 0x00, 0x0f, 0x00,
> +				    0x0e};
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x12, cdata, 50);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x10, data, 1);
> +	if (ret)
> +		return ret;
> +	if ((data[0] & 0x01) == 0x00)
> +		return -EBUSY;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x25, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x11, data, 1);
> +	if (ret)
> +		return ret;
> +	if ((data[0] & 0x01) == 0x00)
> +		return -EBUSY;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x02, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0xe1);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x8f, 0x16);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x67, 0x60);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x6a, 0x0f);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x6c, 0x17);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x00;
> +	data[1] = 0xfe;
> +	data[2] = 0xee;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_DMD,
> +				      0x6e, data, 3);
> +	if (ret)
> +		return ret;
> +	data[0] = 0xa1;
> +	data[1] = 0x8b;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_DMD,
> +				      0x8d, data, 2);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x08;
> +	data[1] = 0x09;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_DMD,
> +				      0x77, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->create_param.stationary_use) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x80, 0xaa);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0xe2);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x41, 0xa0);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x4b, 0x68);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x25, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x1a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x10, data, 1);
> +	if (ret)
> +		return ret;
> +	if ((data[0] & 0x01) == 0x00)
> +		return -EBUSY;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x14, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x26, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int rf_init2(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data[5] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x40;
> +	data[1] = 0x40;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xea, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	data[0] = 0x00;
> +	if (tnr_dmd->chip_id == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X)
> +		data[1] = 0x00;
> +	else
> +		data[1] = 0x01;
> +	data[2] = 0x01;
> +	data[3] = 0x03;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x30, data, 4);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x14);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x1b, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0xe1);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xd3, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_tune1(struct cxd2880_tnrdmd *tnr_dmd,
> +		   enum cxd2880_dtv_sys sys, u32 freq_khz,
> +		   enum cxd2880_dtv_bandwidth bandwidth,
> +		   u8 is_cable, int shift_frequency_khz)
> +{
> +	u8 data[11] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	data[0] = 0x00;
> +	data[1] = 0x00;
> +	data[2] = 0x0e;
> +	data[3] = 0x00;
> +	data[4] = 0x03;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xe7, data, 5);
> +	if (ret)
> +		return ret;
> +
> +	data[0] = 0x1f;
> +	data[1] = 0x80;
> +	data[2] = 0x18;
> +	data[3] = 0x00;
> +	data[4] = 0x07;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xe7, data, 5);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	data[0] = 0x72;
> +	data[1] = 0x81;
> +	data[3] = 0x1d;
> +	data[4] = 0x6f;
> +	data[5] = 0x7e;
> +	data[7] = 0x1c;
> +	switch (sys) {
> +	case CXD2880_DTV_SYS_DVBT:
> +		data[2] = 0x94;
> +		data[6] = 0x91;
> +		break;
> +	case CXD2880_DTV_SYS_DVBT2:
> +		data[2] = 0x96;
> +		data[6] = 0x93;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x44, data, 8);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x62, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x15);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x03;
> +	data[1] = 0xe2;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x1e, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	data[0] = is_cable ? 0x01 : 0x00;
> +	data[1] = 0x00;
> +	data[2] = 0x6b;
> +	data[3] = 0x4d;
> +
> +	switch (bandwidth) {
> +	case CXD2880_DTV_BW_1_7_MHZ:
> +		data[4] = 0x03;
> +		break;
> +	case CXD2880_DTV_BW_5_MHZ:
> +	case CXD2880_DTV_BW_6_MHZ:
> +		data[4] = 0x00;
> +		break;
> +	case CXD2880_DTV_BW_7_MHZ:
> +		data[4] = 0x01;
> +		break;
> +	case CXD2880_DTV_BW_8_MHZ:
> +		data[4] = 0x02;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	data[5] = 0x00;
> +
> +	freq_khz += shift_frequency_khz;
> +
> +	data[6] = (freq_khz >> 16) & 0x0f;
> +	data[7] = (freq_khz >> 8) & 0xff;
> +	data[8] = freq_khz & 0xff;
> +	data[9] = 0xff;
> +	data[10] = 0xfe;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x52, data, 11);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_tune2(struct cxd2880_tnrdmd *tnr_dmd,
> +		   enum cxd2880_dtv_bandwidth bandwidth,
> +		   enum cxd2880_tnrdmd_clockmode clk_mode,
> +		   int shift_frequency_khz)
> +{
> +	u8 data[3] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x11);
> +	if (ret)
> +		return ret;
> +
> +	data[0] = 0x01;
> +	data[1] = 0x0e;
> +	data[2] = 0x01;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x2d, data, 3);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x1a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x29, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x2c, data, 1);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x60, data[0]);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x62, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x11);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x2d, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x2f, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	if (shift_frequency_khz != 0) {
> +		int shift_freq = 0;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0xe1);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x60, data, 2);
> +		if (ret)
> +			return ret;
> +
> +		shift_freq = shift_frequency_khz * 1000;
> +
> +		switch (clk_mode) {
> +		case CXD2880_TNRDMD_CLOCKMODE_A:
> +		case CXD2880_TNRDMD_CLOCKMODE_C:
> +		default:
> +			if (shift_freq >= 0)
> +				shift_freq = (shift_freq + 183 / 2) / 183;
> +			else
> +				shift_freq = (shift_freq - 183 / 2) / 183;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_B:
> +			if (shift_freq >= 0)
> +				shift_freq = (shift_freq + 178 / 2) / 178;
> +			else
> +				shift_freq = (shift_freq - 178 / 2) / 178;
> +			break;
> +		}
> +
> +		shift_freq +=
> +		    cxd2880_convert2s_complement((data[0] << 8) | data[1], 16);
> +
> +		if (shift_freq > 32767)
> +			shift_freq = 32767;
> +		else if (shift_freq < -32768)
> +			shift_freq = -32768;
> +
> +		data[0] = (shift_freq >> 8) & 0xff;
> +		data[1] = shift_freq & 0xff;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x60, data, 2);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x69, data, 1);
> +		if (ret)
> +			return ret;
> +
> +		shift_freq = -shift_frequency_khz;
> +
> +		if (bandwidth == CXD2880_DTV_BW_1_7_MHZ) {
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +			default:
> +				if (shift_freq >= 0)
> +					shift_freq =
> +					    (shift_freq * 1000 +
> +					     17578 / 2) / 17578;
> +				else
> +					shift_freq =
> +					    (shift_freq * 1000 -
> +					     17578 / 2) / 17578;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				if (shift_freq >= 0)
> +					shift_freq =
> +					    (shift_freq * 1000 +
> +					     17090 / 2) / 17090;
> +				else
> +					shift_freq =
> +					    (shift_freq * 1000 -
> +					     17090 / 2) / 17090;
> +				break;
> +			}
> +		} else {
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +			default:
> +				if (shift_freq >= 0)
> +					shift_freq =
> +					    (shift_freq * 1000 +
> +					     35156 / 2) / 35156;
> +				else
> +					shift_freq =
> +					    (shift_freq * 1000 -
> +					     35156 / 2) / 35156;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				if (shift_freq >= 0)
> +					shift_freq =
> +					    (shift_freq * 1000 +
> +					     34180 / 2) / 34180;
> +				else
> +					shift_freq =
> +					    (shift_freq * 1000 -
> +					     34180 / 2) / 34180;
> +				break;
> +			}
> +		}
> +
> +		shift_freq += cxd2880_convert2s_complement(data[0], 8);
> +
> +		if (shift_freq > 127)
> +			shift_freq = 127;
> +		else if (shift_freq < -128)
> +			shift_freq = -128;
> +
> +		data[0] = shift_freq & 0xff;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x69, data[0]);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (tnr_dmd->create_param.stationary_use) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0xe1);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x8a, 0x87);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_tune3(struct cxd2880_tnrdmd *tnr_dmd,
> +		   enum cxd2880_dtv_sys sys,
> +		   u8 en_fef_intmtnt_ctrl)
> +{
> +	u8 data[6] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0xe2);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x41, 0xa0);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xfe, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl) {
> +		data[0] = 0x01;
> +		data[1] = 0x01;
> +		data[2] = 0x01;
> +		data[3] = 0x01;
> +		data[4] = 0x01;
> +		data[5] = 0x01;
> +	} else {
> +		data[0] = 0x00;
> +		data[1] = 0x00;
> +		data[2] = 0x00;
> +		data[3] = 0x00;
> +		data[4] = 0x00;
> +		data[5] = 0x00;
> +	}

Instead, just do:

	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
		memset(data, 0x01, sizeof(data));
	else
		memset(data, 0x00, sizeof(data));

> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0xef, data, 6);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x2d);
> +	if (ret)
> +		return ret;

> +	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
> +		data[0] = 0x00;
> +	else
> +		data[0] = 0x01;

Not actually needed, as the previous logic already set data[0]
accordingly.

> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xb1, data[0]);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_tune4(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data[2] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	{

On this function, you have lots of '{}' sequences that serves for
absolutely no purpose. Just remove them, as it makes the code
easier to read.

> +		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
> +							CXD2880_IO_TGT_SYS,
> +							0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x14;
> +		data[1] = 0x00;
> +		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
> +							CXD2880_IO_TGT_SYS,
> +							0x55, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x0b;
> +		data[1] = 0xff;
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x53, data, 2);
> +		if (ret)
> +			return ret;
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x57, 0x01);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x0b;
> +		data[1] = 0xff;
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x55, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
> +							CXD2880_IO_TGT_SYS,
> +							0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x14;
> +		data[1] = 0x00;
> +		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x53, data, 2);
> +		if (ret)
> +			return ret;
> +		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
> +							CXD2880_IO_TGT_SYS,
> +							0x57, 0x02);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xfe, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
> +						CXD2880_IO_TGT_DMD,
> +						0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
> +						CXD2880_IO_TGT_DMD,
> +						0xfe, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_sleep1(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data[3] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	{

Same happens on this function.

> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x57, 0x03);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x00;
> +		data[1] = 0x00;
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x53, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		ret = tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io,
> +							CXD2880_IO_TGT_SYS,
> +							0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x1f;
> +		data[1] = 0xff;
> +		data[2] = 0x03;
> +		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x55, data, 3);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x00;
> +		data[1] = 0x00;
> +		ret = tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x53, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		data[0] = 0x1f;
> +		data[1] = 0xff;
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x55, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int x_sleep2(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 data = 0;
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x2d);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xb1, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xb2, &data, 1);
> +	if (ret)
> +		return ret;
> +	if ((data & 0x01) == 0x00)
> +		return -EBUSY;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xf4, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xf3, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xf2, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xf1, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xf0, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xef, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_sleep3(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xfd, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_sleep4(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0xe2);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x41, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x21, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int spll_reset(struct cxd2880_tnrdmd *tnr_dmd,
> +		      enum cxd2880_tnrdmd_clockmode clockmode)
> +{
> +	u8 data[4] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x29, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x28, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x27, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x26, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x27, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x22, 0x01);
> +	if (ret)
> +		return ret;
> +	switch (clockmode) {
> +	case CXD2880_TNRDMD_CLOCKMODE_A:
> +		data[0] = 0x00;
> +		break;
> +
> +	case CXD2880_TNRDMD_CLOCKMODE_B:
> +		data[0] = 0x01;
> +		break;
> +
> +	case CXD2880_TNRDMD_CLOCKMODE_C:
> +		data[0] = 0x02;
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x30, data[0]);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x22, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(2000, 3000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x10, data, 1);
> +	if (ret)
> +		return ret;
> +	if ((data[0] & 0x01) == 0x00)
> +		return -EBUSY;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x27, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x00;
> +	data[1] = 0x00;
> +	data[2] = 0x00;
> +	data[3] = 0x00;

use memset().

> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x26, data, 4);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int t_power_x(struct cxd2880_tnrdmd *tnr_dmd, u8 on)
> +{
> +	u8 data[3] = { 0 };
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x29, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x28, 0x01);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x27, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x27, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x25, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	if (on) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x2b, 0x01);
> +		if (ret)
> +			return ret;
> +
> +		usleep_range(1000, 2000);
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00, 0x0a);
> +		if (ret)
> +			return ret;
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x12, data, 1);
> +		if (ret)
> +			return ret;
> +		if ((data[0] & 0x01) == 0)
> +			return -EBUSY;
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00, 0x00);
> +		if (ret)
> +			return ret;
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x2a, 0x00);
> +		if (ret)
> +			return ret;
> +	} else {
> +		data[0] = 0x03;
> +		data[1] = 0x00;
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x2a, data, 2);
> +		if (ret)
> +			return ret;
> +
> +		usleep_range(1000, 2000);
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00, 0x0a);
> +		if (ret)
> +			return ret;
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x13, data, 1);
> +		if (ret)
> +			return ret;
> +		if ((data[0] & 0x01) == 0)
> +			return -EBUSY;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x25, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x11, data, 1);
> +	if (ret)
> +		return ret;
> +	if ((data[0] & 0x01) == 0)
> +		return -EBUSY;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x27, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(1000, 2000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +	data[0] = 0x00;
> +	data[1] = 0x00;
> +	data[2] = 0x00;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x27, data, 3);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +struct cxd2880_tnrdmd_ts_clk_cfg {
> +	u8 srl_clk_mode;
> +	u8 srl_duty_mode;
> +	u8 ts_clk_period;
> +};
> +
> +static int set_ts_clk_mode_and_freq(struct cxd2880_tnrdmd *tnr_dmd,
> +				    enum cxd2880_dtv_sys sys)
> +{
> +	int ret = 0;
> +	u8 backwards_compatible = 0;
> +	struct cxd2880_tnrdmd_ts_clk_cfg ts_clk_cfg;
> +
> +	const struct cxd2880_tnrdmd_ts_clk_cfg srl_ts_clk_stgs[2][2] = {
> +	{
> +		{3, 1, 8,},
> +		{0, 2, 16,}
> +	},
> +	{
> +		{1, 1, 8,},
> +		{2, 2, 16,}
> +	}
> +	};

Indentation is wrong here. Also, please prefer placing the constants
with longer initialization data out of the function, as it improves
code readability. I would declare it as:


static const struct cxd2880_tnrdmd_ts_clk_cfg srl_ts_clk_stgs[2][2] = {
	{
		{3, 1, 8,},
		{0, 2, 16,}
	}, {			/* We generally close and open braces at the same line */
		{1, 1, 8,},
		{2, 2, 16,}
	}
};

> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 ts_rate_ctrl_off = 0;
> +		u8 ts_in_off = 0;
> +		u8 ts_clk_manaul_on = 0;

We don't use this "c++" style of declaring data inside the code,
except when we really need a braces block - like on if () and
while() for example. So, please move the above to the beginning of
the function.

> +
> +		if (tnr_dmd->is_ts_backwards_compatible_mode) {
> +			backwards_compatible = 1;
> +			ts_rate_ctrl_off = 1;
> +			ts_in_off = 1;
> +		} else {
> +			backwards_compatible = 0;
> +			ts_rate_ctrl_off = 0;
> +			ts_in_off = 0;
> +		}
> +
> +		if (tnr_dmd->ts_byte_clk_manual_setting) {
> +			ts_clk_manaul_on = 1;
> +			ts_rate_ctrl_off = 0;
> +		}
> +
> +		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xd3, ts_rate_ctrl_off, 0x01);
> +		if (ret)
> +			return ret;
> +
> +		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xde, ts_in_off, 0x01);
> +		if (ret)
> +			return ret;
> +
> +		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xda, ts_clk_manaul_on, 0x01);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ts_clk_cfg = srl_ts_clk_stgs[tnr_dmd->srl_ts_clk_mod_cnts]
> +				    [tnr_dmd->srl_ts_clk_frq];
> +
> +	if (tnr_dmd->ts_byte_clk_manual_setting)
> +		ts_clk_cfg.ts_clk_period = tnr_dmd->ts_byte_clk_manual_setting;
> +
> +	ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +				      CXD2880_IO_TGT_DMD,
> +				      0xc4, ts_clk_cfg.srl_clk_mode, 0x03);
> +	if (ret)
> +		return ret;
> +
> +	ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +				      CXD2880_IO_TGT_DMD,
> +				      0xd1, ts_clk_cfg.srl_duty_mode, 0x03);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD, 0xd9,
> +				     ts_clk_cfg.ts_clk_period);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data = backwards_compatible ? 0x00 : 0x01;

Same here.

> +
> +		if (sys == CXD2880_DTV_SYS_DVBT) {
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x00, 0x10);
> +			if (ret)
> +				return ret;
> +
> +			ret =
> +			    cxd2880_io_set_reg_bits(tnr_dmd->io,
> +						    CXD2880_IO_TGT_DMD,
> +						    0x66, data, 0x01);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int pid_ftr_setting(struct cxd2880_tnrdmd *tnr_dmd,
> +			   struct cxd2880_tnrdmd_pid_ftr_cfg
> +			   *pid_ftr_cfg)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	if (!pid_ftr_cfg) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x50, 0x02);
> +		if (ret)
> +			return ret;
> +	} else {
> +		u8 data[65];
> +
> +		data[0] = pid_ftr_cfg->is_negative ? 0x01 : 0x00;

As you needed an IF here, the above contruction is OK...


> +		{
> +			int i = 0;

But this should be moved to be just after "u8 data[65]" and the
extra braces/indentation should be removed.

> +
> +			for (i = 0; i < 32; i++) {
> +				if (pid_ftr_cfg->pid_cfg[i].is_en) {
> +					data[1 + (i * 2)] =
> +					    (pid_ftr_cfg->pid_cfg[i].pid
> +					     >> 8) | 0x20;
> +					data[2 + (i * 2)] =
> +					    pid_ftr_cfg->pid_cfg[i].pid
> +					    & 0xff;

For the above, the better is to violate the 80-columns limit, as,
in this specific case, it makes harder to read what's there.

> +				} else {
> +					data[1 + (i * 2)] = 0x00;
> +					data[2 + (i * 2)] = 0x00;
> +				}
> +			}
> +		}
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x50, data, 65);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +	u8 i;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     tnr_dmd->cfg_mem[i].tgt,
> +					     0x00, tnr_dmd->cfg_mem[i].bank);
> +		if (ret)
> +			return ret;
> +
> +		ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +					      tnr_dmd->cfg_mem[i].tgt,
> +					      tnr_dmd->cfg_mem[i].address,
> +					      tnr_dmd->cfg_mem[i].value,
> +					      tnr_dmd->cfg_mem[i].bit_mask);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static int set_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd,
> +		       enum cxd2880_io_tgt tgt,
> +		       u8 bank, u8 address, u8 value, u8 bit_mask)
> +{
> +	u8 i;
> +	u8 value_stored = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	for (i = 0; i < tnr_dmd->cfg_mem_last_entry; i++) {
> +		if ((value_stored == 0) &&
> +		    (tnr_dmd->cfg_mem[i].tgt == tgt) &&
> +		    (tnr_dmd->cfg_mem[i].bank == bank) &&
> +		    (tnr_dmd->cfg_mem[i].address == address)) {
> +			tnr_dmd->cfg_mem[i].value &= ~bit_mask;
> +			tnr_dmd->cfg_mem[i].value |= (value & bit_mask);
> +
> +			tnr_dmd->cfg_mem[i].bit_mask |= bit_mask;
> +
> +			value_stored = 1;
> +		}
> +	}
> +
> +	if (value_stored == 0) {
> +		if (tnr_dmd->cfg_mem_last_entry <
> +		    CXD2880_TNRDMD_MAX_CFG_MEM_COUNT) {
> +			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].tgt = tgt;
> +			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bank =
> +			    bank;
> +			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].address =
> +			    address;
> +			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].value =
> +			    (value & bit_mask);
> +			tnr_dmd->cfg_mem[tnr_dmd->cfg_mem_last_entry].bit_mask =
> +			    bit_mask;

Same on above: better to just violate the 80 cols limit.

> +			tnr_dmd->cfg_mem_last_entry++;
> +		} else {
> +			return -EOVERFLOW;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
> +			  struct cxd2880_io *io,
> +			  struct cxd2880_tnrdmd_create_param
> +			  *create_param)
> +{
> +	if ((!tnr_dmd) || (!io) || (!create_param))
> +		return -EINVAL;
> +
> +	memset(tnr_dmd, 0, sizeof(struct cxd2880_tnrdmd));
> +
> +	tnr_dmd->io = io;
> +	tnr_dmd->create_param = *create_param;
> +
> +	tnr_dmd->diver_mode = CXD2880_TNRDMD_DIVERMODE_SINGLE;
> +	tnr_dmd->diver_sub = NULL;
> +
> +	tnr_dmd->srl_ts_clk_mod_cnts = 1;
> +	tnr_dmd->en_fef_intmtnt_base = 1;
> +	tnr_dmd->en_fef_intmtnt_lite = 1;
> +	tnr_dmd->rf_lvl_cmpstn = NULL;
> +	tnr_dmd->lna_thrs_tbl_air = NULL;
> +	tnr_dmd->lna_thrs_tbl_cable = NULL;
> +	atomic_set(&tnr_dmd->cancel, 0);
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
> +				*tnr_dmd_main,
> +				struct cxd2880_io *io_main,
> +				struct cxd2880_tnrdmd *tnr_dmd_sub,
> +				struct cxd2880_io *io_sub,
> +				struct
> +				cxd2880_tnrdmd_diver_create_param
> +				*create_param)
> +{
> +	if ((!tnr_dmd_main) || (!io_main) || (!tnr_dmd_sub) || (!io_sub) ||
> +	    (!create_param))
> +		return -EINVAL;
> +
> +	memset(tnr_dmd_main, 0, sizeof(struct cxd2880_tnrdmd));
> +	memset(tnr_dmd_sub, 0, sizeof(struct cxd2880_tnrdmd));
> +
> +	tnr_dmd_main->io = io_main;
> +	tnr_dmd_main->diver_mode = CXD2880_TNRDMD_DIVERMODE_MAIN;
> +	tnr_dmd_main->diver_sub = tnr_dmd_sub;
> +	tnr_dmd_main->create_param.en_internal_ldo =
> +	    create_param->en_internal_ldo;
> +	tnr_dmd_main->create_param.ts_output_if = create_param->ts_output_if;
> +	tnr_dmd_main->create_param.xtal_share_type =
> +	    CXD2880_TNRDMD_XTAL_SHARE_MASTER;
> +	tnr_dmd_main->create_param.xosc_cap = create_param->xosc_cap_main;
> +	tnr_dmd_main->create_param.xosc_i = create_param->xosc_i_main;
> +	tnr_dmd_main->create_param.is_cxd2881gg = create_param->is_cxd2881gg;
> +	tnr_dmd_main->create_param.stationary_use =
> +	    create_param->stationary_use;
> +
> +	tnr_dmd_sub->io = io_sub;
> +	tnr_dmd_sub->diver_mode = CXD2880_TNRDMD_DIVERMODE_SUB;
> +	tnr_dmd_sub->diver_sub = NULL;
> +	tnr_dmd_sub->create_param.en_internal_ldo =
> +	    create_param->en_internal_ldo;
> +	tnr_dmd_sub->create_param.ts_output_if = create_param->ts_output_if;
> +	tnr_dmd_sub->create_param.xtal_share_type =
> +	    CXD2880_TNRDMD_XTAL_SHARE_SLAVE;
> +	tnr_dmd_sub->create_param.xosc_cap = 0;
> +	tnr_dmd_sub->create_param.xosc_i = create_param->xosc_i_sub;
> +	tnr_dmd_sub->create_param.is_cxd2881gg = create_param->is_cxd2881gg;
> +	tnr_dmd_sub->create_param.stationary_use = create_param->stationary_use;

Same here: just violate 80 columns limit where needed.

Yet, you could consider, instead, to use memcpy(), just overriding
the fields that would be different, e. g. something like:

      memcpy(tnr_dmd_sub->create_param, create_param,
	     sizeof(*create_param));
      tnr_dmd_sub->create_param.xosc_cap = 0;

Or, alternatively, do something like:

	struct cxd2880_tnrdmd_diver_create_param *sub_param;

	sub_param = &tnr_dmd_sub->create_param;

	sub_param->en_internal_ldo = create_param->en_internal_ldo;
	sub_param->ts_output_if = create_param->ts_output_if;

> +
> +	tnr_dmd_main->srl_ts_clk_mod_cnts = 1;
> +	tnr_dmd_main->en_fef_intmtnt_base = 1;
> +	tnr_dmd_main->en_fef_intmtnt_lite = 1;
> +	tnr_dmd_main->rf_lvl_cmpstn = NULL;
> +	tnr_dmd_main->lna_thrs_tbl_air = NULL;
> +	tnr_dmd_main->lna_thrs_tbl_cable = NULL;
> +
> +	tnr_dmd_sub->srl_ts_clk_mod_cnts = 1;
> +	tnr_dmd_sub->en_fef_intmtnt_base = 1;
> +	tnr_dmd_sub->en_fef_intmtnt_lite = 1;
> +	tnr_dmd_sub->rf_lvl_cmpstn = NULL;
> +	tnr_dmd_sub->lna_thrs_tbl_air = NULL;
> +	tnr_dmd_sub->lna_thrs_tbl_cable = NULL;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB))
> +		return -EINVAL;
> +
> +	tnr_dmd->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
> +	tnr_dmd->state = CXD2880_TNRDMD_STATE_UNKNOWN;
> +	tnr_dmd->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN;
> +	tnr_dmd->frequency_khz = 0;
> +	tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN;
> +	tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN;
> +	tnr_dmd->scan_mode = 0;

if all those *_UNKNOWN are equal to zero, the best would be 
to do, instead:

	memset(tnr_dmd, 0, sizeof(tnr_dmd);

or, if this is allocated with kmalloc(), to use kzalloc() instead.

> +	atomic_set(&tnr_dmd->cancel, 0);
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		tnr_dmd->diver_sub->chip_id = CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
> +		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_UNKNOWN;
> +		tnr_dmd->diver_sub->clk_mode = CXD2880_TNRDMD_CLOCKMODE_UNKNOWN;
> +		tnr_dmd->diver_sub->frequency_khz = 0;
> +		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN;
> +		tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN;
> +		tnr_dmd->diver_sub->scan_mode = 0;

Same here.

> +		atomic_set(&tnr_dmd->diver_sub->cancel, 0);
> +	}
> +
> +	ret = cxd2880_tnrdmd_chip_id(tnr_dmd, &tnr_dmd->chip_id);
> +	if (ret)
> +		return ret;
> +
> +	if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->chip_id))
> +		return -EOPNOTSUPP;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret =
> +		    cxd2880_tnrdmd_chip_id(tnr_dmd->diver_sub,
> +					   &tnr_dmd->diver_sub->chip_id);
> +		if (ret)
> +			return ret;
> +
> +		if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->diver_sub->chip_id))
> +			return -EOPNOTSUPP;
> +	}
> +
> +	ret = p_init1(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = p_init1(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	usleep_range(1000, 2000);
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = p_init2(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = p_init2(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(5000, 6000);
> +
> +	ret = p_init3(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = p_init3(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = rf_init1(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = rf_init1(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	{
> +		u8 cpu_task_completed = 0;

Another indent that needs to be fixed. Won't comment it anymore. You
got the idea ;-)

> +
> +		ret =
> +		    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
> +						     &cpu_task_completed);
> +		if (ret)
> +			return ret;
> +
> +		if (!cpu_task_completed)
> +			return -EBUSY;
> +	}
> +
> +	ret = rf_init2(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = rf_init2(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = load_cfg_mem(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = load_cfg_mem(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
> +					     *tnr_dmd,
> +					     u8 *task_completed)
> +{
> +	u16 cpu_status = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!task_completed))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd, &cpu_status);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		if (cpu_status == 0)
> +			*task_completed = 1;
> +		else
> +			*task_completed = 0;
> +
> +		return ret;
> +	}
> +	if (cpu_status != 0) {
> +		*task_completed = 0;
> +		return ret;
> +	}
> +
> +	ret = cxd2880_tnrdmd_mon_internal_cpu_status_sub(tnr_dmd, &cpu_status);
> +	if (ret)
> +		return ret;
> +
> +	if (cpu_status == 0)
> +		*task_completed = 1;
> +	else
> +		*task_completed = 0;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd *tnr_dmd,
> +					enum cxd2880_dtv_sys sys,
> +					u32 frequency_khz,
> +					enum cxd2880_dtv_bandwidth
> +					bandwidth, u8 one_seg_opt,
> +					u8 one_seg_opt_shft_dir)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	if (frequency_khz < 4000)
> +		return -ERANGE;
> +
> +	ret = cxd2880_tnrdmd_sleep(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data = 0;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x00,
> +					     0x00);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x2b,
> +					     &data,
> +					     1);
> +		if (ret)
> +			return ret;
> +
> +		switch (sys) {
> +		case CXD2880_DTV_SYS_DVBT:
> +			if (data == 0x00) {
> +				ret = t_power_x(tnr_dmd, 1);
> +				if (ret)
> +					return ret;
> +
> +				if (tnr_dmd->diver_mode ==
> +				    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +					ret = t_power_x(tnr_dmd->diver_sub, 1);
> +					if (ret)
> +						return ret;
> +				}
> +			}
> +			break;
> +
> +		case CXD2880_DTV_SYS_DVBT2:
> +			if (data == 0x01) {
> +				ret = t_power_x(tnr_dmd, 0);
> +				if (ret)
> +					return ret;
> +
> +				if (tnr_dmd->diver_mode ==
> +				    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +					ret = t_power_x(tnr_dmd->diver_sub, 0);
> +					if (ret)
> +						return ret;
> +				}
> +			}
> +			break;
> +
> +		default:
> +			return -EINVAL;
> +		}
> +	}
> +
> +	{
> +		enum cxd2880_tnrdmd_clockmode new_clk_mode =
> +		    CXD2880_TNRDMD_CLOCKMODE_A;
> +
> +		ret = spll_reset(tnr_dmd, new_clk_mode);
> +		if (ret)
> +			return ret;
> +
> +		tnr_dmd->clk_mode = new_clk_mode;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret = spll_reset(tnr_dmd->diver_sub, new_clk_mode);
> +			if (ret)
> +				return ret;
> +
> +			tnr_dmd->diver_sub->clk_mode = new_clk_mode;
> +		}
> +
> +		ret = load_cfg_mem(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret = load_cfg_mem(tnr_dmd->diver_sub);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	{
> +		int shift_frequency_khz = 0;
> +
> +		if (one_seg_opt) {
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +				shift_frequency_khz = 350;
> +			} else {
> +				if (one_seg_opt_shft_dir)
> +					shift_frequency_khz = 350;
> +				else
> +					shift_frequency_khz = -350;
> +
> +				if (tnr_dmd->create_param.xtal_share_type ==
> +				    CXD2880_TNRDMD_XTAL_SHARE_SLAVE)
> +					shift_frequency_khz *= -1;
> +			}
> +		} else {
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +				shift_frequency_khz = 150;
> +			} else {
> +				switch (tnr_dmd->create_param.xtal_share_type) {
> +				case CXD2880_TNRDMD_XTAL_SHARE_NONE:
> +				case CXD2880_TNRDMD_XTAL_SHARE_EXTREF:
> +				default:
> +					shift_frequency_khz = 0;
> +					break;
> +				case CXD2880_TNRDMD_XTAL_SHARE_MASTER:
> +					shift_frequency_khz = 150;
> +					break;
> +				case CXD2880_TNRDMD_XTAL_SHARE_SLAVE:
> +					shift_frequency_khz = -150;
> +					break;
> +				}
> +			}
> +		}
> +
> +		ret =
> +		    x_tune1(tnr_dmd, sys, frequency_khz, bandwidth,
> +			    tnr_dmd->is_cable_input, shift_frequency_khz);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret =
> +			    x_tune1(tnr_dmd->diver_sub, sys, frequency_khz,
> +				    bandwidth, tnr_dmd->is_cable_input,
> +				    -shift_frequency_khz);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		usleep_range(10000, 11000);
> +
> +		{
> +			u8 cpu_task_completed = 0;
> +
> +			ret =
> +			    cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd,
> +						     &cpu_task_completed);
> +			if (ret)
> +				return ret;
> +
> +			if (!cpu_task_completed)
> +				return -EBUSY;
> +		}
> +
> +		ret =
> +		    x_tune2(tnr_dmd, bandwidth, tnr_dmd->clk_mode,
> +			    shift_frequency_khz);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret =
> +			    x_tune2(tnr_dmd->diver_sub, bandwidth,
> +				    tnr_dmd->diver_sub->clk_mode,
> +				    -shift_frequency_khz);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) {
> +		ret = set_ts_clk_mode_and_freq(tnr_dmd, sys);
> +		if (ret)
> +			return ret;
> +	} else {
> +		struct cxd2880_tnrdmd_pid_ftr_cfg *pid_ftr_cfg;
> +
> +		if (tnr_dmd->pid_ftr_cfg_en)
> +			pid_ftr_cfg = &tnr_dmd->pid_ftr_cfg;
> +		else
> +			pid_ftr_cfg = NULL;
> +
> +		ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
> +					*tnr_dmd,
> +					enum cxd2880_dtv_sys sys,
> +					u8 en_fef_intmtnt_ctrl)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = x_tune3(tnr_dmd, sys, en_fef_intmtnt_ctrl);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = x_tune3(tnr_dmd->diver_sub, sys, en_fef_intmtnt_ctrl);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = x_tune4(tnr_dmd);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 1);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state == CXD2880_TNRDMD_STATE_SLEEP) {
> +	} else if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) {

Please don't add things like 
	if(foo) {
		// do nothing
	} else {


In this specific case, by looking on what actually happens, I guess the
best would be to write this as:

	if (tnr_dmd->state == CXD2880_TNRDMD_STATE_SLEEP)
		return 0;

	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
		return -EPERM.

And then remove the indent for all the code below. On such case,
you can also change the line that declared ret to just:

	int ret;

As it won't be needed to be initialized anymore.

> +		ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 0);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret = x_sleep1(tnr_dmd);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = x_sleep2(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret = x_sleep2(tnr_dmd->diver_sub);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		switch (tnr_dmd->sys) {
> +		case CXD2880_DTV_SYS_DVBT:
> +			ret = cxd2880_tnrdmd_dvbt_sleep_setting(tnr_dmd);
> +			if (ret)
> +				return ret;
> +			break;
> +
> +		case CXD2880_DTV_SYS_DVBT2:
> +			ret = cxd2880_tnrdmd_dvbt2_sleep_setting(tnr_dmd);
> +			if (ret)
> +				return ret;
> +			break;
> +
> +		default:
> +			return -EPERM;
> +		}
> +
> +		ret = x_sleep3(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret = x_sleep3(tnr_dmd->diver_sub);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = x_sleep4(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			ret = x_sleep4(tnr_dmd->diver_sub);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		tnr_dmd->state = CXD2880_TNRDMD_STATE_SLEEP;
> +		tnr_dmd->frequency_khz = 0;
> +		tnr_dmd->sys = CXD2880_DTV_SYS_UNKNOWN;
> +		tnr_dmd->bandwidth = CXD2880_DTV_BW_UNKNOWN;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_SLEEP;
> +			tnr_dmd->diver_sub->frequency_khz = 0;
> +			tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_UNKNOWN;
> +			tnr_dmd->diver_sub->bandwidth = CXD2880_DTV_BW_UNKNOWN;
> +		}
> +	} else {
> +		return -EPERM;
> +	}
> +
> +	return ret;

Return will always be zero here. So, better to just do:

	return 0;

> +}
> +
> +int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
> +			   enum cxd2880_tnrdmd_cfg_id id,
> +			   int value)
> +{
> +	int ret = 0;

I didn't mentioned on other places, but we only initialize stuff that
requires it. In the case of ret, before using it, you're doing:

	ret = cxd2880_tnrdmd_set_and_save_reg_bits()...

So, it will always be initialized before usage. So, you can declare
it as just:

	int ret;


> +	u8 data[2] = { 0 };
> +	u8 need_sub_setting = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	switch (id) {
> +	case CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc4,
> +							 value ? 0x00 : 0x10,
> +							 0x10);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc5,
> +							 value ? 0x00 : 0x02,
> +							 0x02);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc5,
> +							 value ? 0x00 : 0x04,
> +							 0x04);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xcb,
> +							 value ? 0x00 : 0x01,
> +							 0x01);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc5,
> +							 value ? 0x01 : 0x00,
> +							 0x01);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSCLK_CONT:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		tnr_dmd->srl_ts_clk_mod_cnts = value ? 0x01 : 0x00;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSCLK_MASK:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		if ((value < 0) || (value > 0x1f))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc6, value,
> +							 0x1f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSVALID_MASK:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		if ((value < 0) || (value > 0x1f))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc8, value,
> +							 0x1f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSERR_MASK:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		if ((value < 0) || (value > 0x1f))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xc9, value,
> +							 0x1f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSERR_VALID_DIS:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x91,
> +							 value ? 0x01 : 0x00,
> +							 0x01);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSPIN_CURRENT:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x51, value,
> +							 0x3f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x50,
> +							 value ? 0x80 : 0x00,
> +							 0x80);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSPIN_PULLUP:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x50, value,
> +							 0x3f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSCLK_FREQ:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		if ((value < 0) || (value > 1))
> +			return -ERANGE;
> +
> +		tnr_dmd->srl_ts_clk_frq =
> +		    (enum cxd2880_tnrdmd_serial_ts_clk)value;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		if ((value < 0) || (value > 0xff))
> +			return -ERANGE;
> +
> +		tnr_dmd->ts_byte_clk_manual_setting = value;
> +
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TS_PACKET_GAP:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		if ((value < 0) || (value > 7))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0xd6, value,
> +							 0x07);
> +		if (ret)
> +			return ret;
> +
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE:
> +		if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +			return -EPERM;
> +
> +		tnr_dmd->is_ts_backwards_compatible_mode = value ? 1 : 0;
> +
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_PWM_VALUE:
> +		if ((value < 0) || (value > 0x1000))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x22,
> +							 value ? 0x01 : 0x00,
> +							 0x01);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data[2];
> +
> +			data[0] = (value >> 8) & 0x1f;
> +			data[1] = value & 0xff;
> +
> +			ret =
> +			    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x23,
> +							 data[0], 0x1f);
> +			if (ret)
> +				return ret;
> +
> +			ret =
> +			    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x24,
> +							 data[1], 0xff);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_INTERRUPT:
> +		data[0] = (value >> 8) & 0xff;
> +		data[1] = value & 0xff;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x48, data[0],
> +							 0xff);
> +		if (ret)
> +			return ret;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x49, data[1],
> +							 0xff);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL:
> +		data[0] = value & 0x07;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x4a, data[0],
> +							 0x07);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL:
> +		data[0] = (value & 0x07) << 3;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_SYS,
> +							 0x00, 0x4a, data[0],
> +							 0x38);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE:
> +		if ((value < CXD2880_TNRDMD_CLOCKMODE_UNKNOWN) ||
> +		    (value > CXD2880_TNRDMD_CLOCKMODE_C))
> +			return -ERANGE;
> +		tnr_dmd->fixed_clk_mode = (enum cxd2880_tnrdmd_clockmode)value;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_CABLE_INPUT:
> +		tnr_dmd->is_cable_input = value ? 1 : 0;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE:
> +		tnr_dmd->en_fef_intmtnt_base = value ? 1 : 0;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE:
> +		tnr_dmd->en_fef_intmtnt_lite = value ? 1 : 0;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS:
> +		data[0] = (value >> 8) & 0x07;
> +		data[1] = value & 0xff;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x99, data[0],
> +							 0x07);
> +		if (ret)
> +			return ret;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x9a, data[1],
> +							 0xff);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS:
> +		data[0] = (value >> 8) & 0x07;
> +		data[1] = value & 0xff;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x9b, data[0],
> +							 0x07);
> +		if (ret)
> +			return ret;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x9c, data[1],
> +							 0xff);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS:
> +		data[0] = (value >> 8) & 0x07;
> +		data[1] = value & 0xff;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x9d, data[0],
> +							 0x07);
> +		if (ret)
> +			return ret;
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x00, 0x9e, data[1],
> +							 0xff);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST:
> +		tnr_dmd->blind_tune_dvbt2_first = value ? 1 : 0;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD:
> +		if ((value < 0) || (value > 31))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x10, 0x60,
> +							 value & 0x1f, 0x1f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD:
> +		if ((value < 0) || (value > 7))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x10, 0x6f,
> +							 value & 0x07, 0x07);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT2_BBER_MES:
> +		if ((value < 0) || (value > 15))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x20, 0x72,
> +							 value & 0x0f, 0x0f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT2_LBER_MES:
> +		if ((value < 0) || (value > 15))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x20, 0x6f,
> +							 value & 0x0f, 0x0f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT_PER_MES:
> +		if ((value < 0) || (value > 15))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x10, 0x5c,
> +							 value & 0x0f, 0x0f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case CXD2880_TNRDMD_CFG_DVBT2_PER_MES:
> +		if ((value < 0) || (value > 15))
> +			return -ERANGE;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +							 CXD2880_IO_TGT_DMD,
> +							 0x24, 0xdc,
> +							 value & 0x0f, 0x0f);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	if (need_sub_setting &&
> +	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)) {
> +		ret = cxd2880_tnrdmd_set_cfg(tnr_dmd->diver_sub, id, value);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
> +				u8 id,
> +				u8 en,
> +				enum cxd2880_tnrdmd_gpio_mode mode,
> +				u8 open_drain, u8 invert)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (id > 2)
> +		return -EINVAL;
> +
> +	if (mode > CXD2880_TNRDMD_GPIO_MODE_EEW)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
> +						 0x00, 0x40 + id, mode,
> +						 0x0f);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
> +						 0x00, 0x43,
> +						 open_drain ? (1 << id) : 0,
> +						 1 << id);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
> +						 0x00, 0x44,
> +						 invert ? (1 << id) : 0,
> +						 1 << id);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS,
> +						 0x00, 0x45,
> +						 en ? 0 : (1 << id),
> +						 1 << id);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				    u8 id,
> +				    u8 en,
> +				    enum cxd2880_tnrdmd_gpio_mode
> +				    mode, u8 open_drain, u8 invert)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_gpio_set_cfg(tnr_dmd->diver_sub, id, en, mode,
> +					open_drain, invert);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
> +			     u8 id, u8 *value)
> +{
> +	u8 data = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!value))
> +		return -EINVAL;
> +
> +	if (id > 2)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x20, &data, 1);
> +	if (ret)
> +		return ret;
> +
> +	*value = (data >> id) & 0x01;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u8 id, u8 *value)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_gpio_read(tnr_dmd->diver_sub, id, value);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
> +			      u8 id, u8 value)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (id > 2)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd,
> +						   CXD2880_IO_TGT_SYS,
> +						   0x00, 0x46,
> +						   value ? (1 << id) : 0,
> +						   1 << id);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				  u8 id, u8 value)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_gpio_write(tnr_dmd->diver_sub, id, value);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
> +				  u16 *value)
> +{
> +	int ret = 0;
> +	u8 data[2] = { 0 };
> +
> +	if ((!tnr_dmd) || (!value))
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x15, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	*value = (data[0] << 8) | data[1];
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
> +				   u16 value)
> +{
> +	int ret = 0;
> +	u8 data[2] = { 0 };
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	data[0] = (value >> 8) & 0xff;
> +	data[1] = value & 0xff;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_SYS,
> +				      0x3c, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
> +				u8 clear_overflow_flag,
> +				u8 clear_underflow_flag,
> +				u8 clear_buf)
> +{
> +	int ret = 0;
> +	u8 data[2] = { 0 };
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	data[0] = clear_overflow_flag ? 0x02 : 0x00;
> +	data[0] |= clear_underflow_flag ? 0x01 : 0x00;
> +	data[1] = clear_buf ? 0x01 : 0x00;
> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +				      CXD2880_IO_TGT_DMD,
> +				      0x9f, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
> +			   enum cxd2880_tnrdmd_chip_id *chip_id)
> +{
> +	int ret = 0;
> +	u8 data = 0;
> +
> +	if ((!tnr_dmd) || (!chip_id))
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0xfd, &data, 1);
> +	if (ret)
> +		return ret;
> +
> +	*chip_id = (enum cxd2880_tnrdmd_chip_id)data;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
> +					 *tnr_dmd,
> +					 enum cxd2880_io_tgt tgt,
> +					 u8 bank, u8 address,
> +					 u8 value, u8 bit_mask)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io, tgt, 0x00, bank);
> +	if (ret)
> +		return ret;
> +
> +	ret = cxd2880_io_set_reg_bits(tnr_dmd->io,
> +				      tgt, address, value, bit_mask);
> +	if (ret)
> +		return ret;
> +
> +	ret = set_cfg_mem(tnr_dmd, tgt, bank, address, value, bit_mask);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
> +				 enum cxd2880_dtv_sys sys,
> +				 u8 scan_mode_end)
> +{
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	CXD2880_ARG_UNUSED(sys);
> +
> +	tnr_dmd->scan_mode = scan_mode_end;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		int ret = 0;
> +
> +		ret =
> +		    cxd2880_tnrdmd_set_scan_mode(tnr_dmd->diver_sub, sys,
> +						 scan_mode_end);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
> +			       struct cxd2880_tnrdmd_pid_ftr_cfg
> +			       *pid_ftr_cfg)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS)
> +		return -EOPNOTSUPP;
> +
> +	if (pid_ftr_cfg) {
> +		tnr_dmd->pid_ftr_cfg = *pid_ftr_cfg;
> +		tnr_dmd->pid_ftr_cfg_en = 1;
> +	} else {
> +		tnr_dmd->pid_ftr_cfg_en = 0;
> +	}
> +
> +	if (tnr_dmd->state == CXD2880_TNRDMD_STATE_ACTIVE) {
> +		ret = pid_ftr_setting(tnr_dmd, pid_ftr_cfg);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     int (*rf_lvl_cmpstn)
> +				     (struct cxd2880_tnrdmd *,
> +				     int *))
> +{
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	tnr_dmd->rf_lvl_cmpstn = rf_lvl_cmpstn;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd
> +					 *tnr_dmd,
> +					 int (*rf_lvl_cmpstn)
> +					 (struct cxd2880_tnrdmd *,
> +					 int *))
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_set_rf_lvl_cmpstn(tnr_dmd->diver_sub,
> +					       rf_lvl_cmpstn);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
> +				struct cxd2880_tnrdmd_lna_thrs_tbl_air
> +				*tbl_air,
> +				struct cxd2880_tnrdmd_lna_thrs_tbl_cable
> +				*tbl_cable)
> +{
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	tnr_dmd->lna_thrs_tbl_air = tbl_air;
> +	tnr_dmd->lna_thrs_tbl_cable = tbl_cable;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				    struct
> +				    cxd2880_tnrdmd_lna_thrs_tbl_air
> +				    *tbl_air,
> +				    struct cxd2880_tnrdmd_lna_thrs_tbl_cable
> +				    *tbl_cable)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_set_lna_thrs(tnr_dmd->diver_sub,
> +					  tbl_air, tbl_cable);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 en, u8 value)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP)
> +		return -EPERM;
> +
> +	if (tnr_dmd->create_param.ts_output_if != CXD2880_TNRDMD_TSOUT_IF_TS)
> +		return -EOPNOTSUPP;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	if (en) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x50, ((value & 0x1f) | 0x80));
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x52, (value & 0x1f));
> +		if (ret)
> +			return ret;
> +	} else {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x50, 0x3f);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x52, 0x1f);
> +		if (ret)
> +			return ret;
> +
> +		ret = load_cfg_mem(tnr_dmd);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u8 en)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	switch (tnr_dmd->create_param.ts_output_if) {
> +	case CXD2880_TNRDMD_TSOUT_IF_TS:
> +		if (en) {
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_SYS,
> +						     0x00, 0x00);
> +			if (ret)
> +				return ret;
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_SYS,
> +						     0x52, 0x00);
> +			if (ret)
> +				return ret;
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x00, 0x00);
> +			if (ret)
> +				return ret;
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0xc3, 0x00);
> +			if (ret)
> +				return ret;
> +		} else {
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x00, 0x00);
> +			if (ret)
> +				return ret;
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0xc3, 0x01);
> +			if (ret)
> +				return ret;
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_SYS,
> +						     0x00, 0x00);
> +			if (ret)
> +				return ret;
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_SYS,
> +						     0x52, 0x1f);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_TNRDMD_TSOUT_IF_SPI:
> +		break;
> +
> +	case CXD2880_TNRDMD_TSOUT_IF_SDIO:
> +		break;
> +
> +	default:
> +		return -EPERM;
> +	}
> +
> +	return 0;
> +}
> +
> +int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	switch (tnr_dmd->create_param.ts_output_if) {
> +	case CXD2880_TNRDMD_TSOUT_IF_SPI:
> +	case CXD2880_TNRDMD_TSOUT_IF_SDIO:
> +		{
> +			u8 data = 0;
> +
> +			ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x00, &data, 1);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +	case CXD2880_TNRDMD_TSOUT_IF_TS:
> +	default:
> +		break;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x01, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
> new file mode 100644
> index 000000000000..c168c9f27dad
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h
> @@ -0,0 +1,391 @@
> +/*
> + * cxd2880_tnrdmd.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * common control interface
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_TNRDMD_H
> +#define CXD2880_TNRDMD_H
> +
> +#include <linux/atomic.h>
> +
> +#include "cxd2880_common.h"
> +#include "cxd2880_io.h"
> +#include "cxd2880_dtv.h"
> +#include "cxd2880_dvbt.h"
> +#include "cxd2880_dvbt2.h"
> +
> +#define CXD2880_TNRDMD_MAX_CFG_MEM_COUNT 100
> +
> +#define slvt_unfreeze_reg(tnr_dmd) ((void)((tnr_dmd)->io->write_reg\
> +((tnr_dmd)->io, CXD2880_IO_TGT_DMD, 0x01, 0x00)))
> +
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_UNDERFLOW     0x0001
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_OVERFLOW      0x0002
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_EMPTY  0x0004
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_ALMOST_FULL   0x0008
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_BUF_RRDY	  0x0010
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_COMMAND      0x0020
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_ILLEGAL_ACCESS       0x0040
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_CPU_ERROR	    0x0100
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_LOCK		 0x0200
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_INV_LOCK	     0x0400
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_NOOFDM	       0x0800
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_EWS		  0x1000
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_EEW		  0x2000
> +#define CXD2880_TNRDMD_INTERRUPT_TYPE_FEC_FAIL	     0x4000
> +
> +#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_L1POST_OK	0x01
> +#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_DMD_LOCK	 0x02
> +#define CXD2880_TNRDMD_INTERRUPT_LOCK_SEL_TS_LOCK	  0x04
> +
> +enum cxd2880_tnrdmd_chip_id {
> +	CXD2880_TNRDMD_CHIP_ID_UNKNOWN = 0x00,
> +	CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X = 0x62,
> +	CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11 = 0x6a
> +};
> +
> +#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) (((chip_id) == \
> +CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \
> +((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11))

The line breaks here make it harder to read. Better to declare it as:

#define CXD2880_TNRDMD_CHIP_ID_VALID(chip_id) \
	(((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) || \
	 ((chip_id) == CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11))


> +
> +enum cxd2880_tnrdmd_state {
> +	CXD2880_TNRDMD_STATE_UNKNOWN,
> +	CXD2880_TNRDMD_STATE_SLEEP,
> +	CXD2880_TNRDMD_STATE_ACTIVE,
> +	CXD2880_TNRDMD_STATE_INVALID
> +};
> +
> +enum cxd2880_tnrdmd_divermode {
> +	CXD2880_TNRDMD_DIVERMODE_SINGLE,
> +	CXD2880_TNRDMD_DIVERMODE_MAIN,
> +	CXD2880_TNRDMD_DIVERMODE_SUB
> +};
> +
> +enum cxd2880_tnrdmd_clockmode {
> +	CXD2880_TNRDMD_CLOCKMODE_UNKNOWN,
> +	CXD2880_TNRDMD_CLOCKMODE_A,
> +	CXD2880_TNRDMD_CLOCKMODE_B,
> +	CXD2880_TNRDMD_CLOCKMODE_C
> +};
> +
> +enum cxd2880_tnrdmd_tsout_if {
> +	CXD2880_TNRDMD_TSOUT_IF_TS,
> +	CXD2880_TNRDMD_TSOUT_IF_SPI,
> +	CXD2880_TNRDMD_TSOUT_IF_SDIO
> +};
> +
> +enum cxd2880_tnrdmd_xtal_share {
> +	CXD2880_TNRDMD_XTAL_SHARE_NONE,
> +	CXD2880_TNRDMD_XTAL_SHARE_EXTREF,
> +	CXD2880_TNRDMD_XTAL_SHARE_MASTER,
> +	CXD2880_TNRDMD_XTAL_SHARE_SLAVE
> +};
> +
> +enum cxd2880_tnrdmd_spectrum_sense {
> +	CXD2880_TNRDMD_SPECTRUM_NORMAL,
> +	CXD2880_TNRDMD_SPECTRUM_INV
> +};
> +
> +enum cxd2880_tnrdmd_cfg_id {
> +	CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB,
> +	CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI,
> +	CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI,
> +	CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI,
> +	CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE,
> +	CXD2880_TNRDMD_CFG_TSCLK_CONT,
> +	CXD2880_TNRDMD_CFG_TSCLK_MASK,
> +	CXD2880_TNRDMD_CFG_TSVALID_MASK,
> +	CXD2880_TNRDMD_CFG_TSERR_MASK,
> +	CXD2880_TNRDMD_CFG_TSERR_VALID_DIS,
> +	CXD2880_TNRDMD_CFG_TSPIN_CURRENT,
> +	CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL,
> +	CXD2880_TNRDMD_CFG_TSPIN_PULLUP,
> +	CXD2880_TNRDMD_CFG_TSCLK_FREQ,
> +	CXD2880_TNRDMD_CFG_TSBYTECLK_MANUAL,
> +	CXD2880_TNRDMD_CFG_TS_PACKET_GAP,
> +	CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE,
> +	CXD2880_TNRDMD_CFG_PWM_VALUE,
> +	CXD2880_TNRDMD_CFG_INTERRUPT,
> +	CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL,
> +	CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL,
> +	CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS,
> +	CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS,
> +	CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS,
> +	CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE,
> +	CXD2880_TNRDMD_CFG_CABLE_INPUT,
> +	CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE,
> +	CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE,
> +	CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST,
> +	CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
> +	CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
> +	CXD2880_TNRDMD_CFG_DVBT_PER_MES,
> +	CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
> +	CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
> +	CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
> +};
> +
> +enum cxd2880_tnrdmd_lock_result {
> +	CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT,
> +	CXD2880_TNRDMD_LOCK_RESULT_LOCKED,
> +	CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED
> +};
> +
> +enum cxd2880_tnrdmd_gpio_mode {
> +	CXD2880_TNRDMD_GPIO_MODE_OUTPUT = 0x00,
> +	CXD2880_TNRDMD_GPIO_MODE_INPUT = 0x01,
> +	CXD2880_TNRDMD_GPIO_MODE_INT = 0x02,
> +	CXD2880_TNRDMD_GPIO_MODE_FEC_FAIL = 0x03,
> +	CXD2880_TNRDMD_GPIO_MODE_PWM = 0x04,
> +	CXD2880_TNRDMD_GPIO_MODE_EWS = 0x05,
> +	CXD2880_TNRDMD_GPIO_MODE_EEW = 0x06
> +};
> +
> +enum cxd2880_tnrdmd_serial_ts_clk {
> +	CXD2880_TNRDMD_SERIAL_TS_CLK_FULL,
> +	CXD2880_TNRDMD_SERIAL_TS_CLK_HALF
> +};
> +
> +struct cxd2880_tnrdmd_cfg_mem {
> +	enum cxd2880_io_tgt tgt;
> +	u8 bank;
> +	u8 address;
> +	u8 value;
> +	u8 bit_mask;
> +};
> +
> +struct cxd2880_tnrdmd_pid_cfg {
> +	u8 is_en;
> +	u16 pid;
> +};
> +
> +struct cxd2880_tnrdmd_pid_ftr_cfg {
> +	u8 is_negative;
> +	struct cxd2880_tnrdmd_pid_cfg pid_cfg[32];
> +};
> +
> +struct cxd2880_tnrdmd_ts_buf_info {
> +	u8 read_ready;
> +	u8 almost_full;
> +	u8 almost_empty;
> +	u8 overflow;
> +	u8 underflow;
> +	u16 packet_num;
> +};
> +
> +struct cxd2880_tnrdmd_lna_thrs {
> +	u8 off_on;
> +	u8 on_off;
> +};
> +
> +struct cxd2880_tnrdmd_lna_thrs_tbl_air {
> +	struct cxd2880_tnrdmd_lna_thrs thrs[24];
> +};
> +
> +struct cxd2880_tnrdmd_lna_thrs_tbl_cable {
> +	struct cxd2880_tnrdmd_lna_thrs thrs[32];
> +};
> +
> +struct cxd2880_tnrdmd_create_param {
> +	enum cxd2880_tnrdmd_tsout_if ts_output_if;
> +	u8 en_internal_ldo;
> +	enum cxd2880_tnrdmd_xtal_share xtal_share_type;
> +	u8 xosc_cap;
> +	u8 xosc_i;
> +	u8 is_cxd2881gg;
> +	u8 stationary_use;
> +};
> +
> +struct cxd2880_tnrdmd_diver_create_param {
> +	enum cxd2880_tnrdmd_tsout_if ts_output_if;
> +	u8 en_internal_ldo;
> +	u8 xosc_cap_main;
> +	u8 xosc_i_main;
> +	u8 xosc_i_sub;
> +	u8 is_cxd2881gg;
> +	u8 stationary_use;
> +};
> +
> +struct cxd2880_tnrdmd {
> +	struct cxd2880_tnrdmd *diver_sub;
> +	struct cxd2880_io *io;
> +	struct cxd2880_tnrdmd_create_param create_param;
> +	enum cxd2880_tnrdmd_divermode diver_mode;
> +	enum cxd2880_tnrdmd_clockmode fixed_clk_mode;
> +	u8 is_cable_input;
> +	u8 en_fef_intmtnt_base;
> +	u8 en_fef_intmtnt_lite;
> +	u8 blind_tune_dvbt2_first;
> +	int (*rf_lvl_cmpstn)(struct cxd2880_tnrdmd *tnr_dmd,
> +			     int *rf_lvl_db);
> +	struct cxd2880_tnrdmd_lna_thrs_tbl_air *lna_thrs_tbl_air;
> +	struct cxd2880_tnrdmd_lna_thrs_tbl_cable *lna_thrs_tbl_cable;
> +	u8 srl_ts_clk_mod_cnts;
> +	enum cxd2880_tnrdmd_serial_ts_clk srl_ts_clk_frq;
> +	u8 ts_byte_clk_manual_setting;
> +	u8 is_ts_backwards_compatible_mode;
> +	struct cxd2880_tnrdmd_cfg_mem cfg_mem[CXD2880_TNRDMD_MAX_CFG_MEM_COUNT];
> +	u8 cfg_mem_last_entry;
> +	struct cxd2880_tnrdmd_pid_ftr_cfg pid_ftr_cfg;
> +	u8 pid_ftr_cfg_en;
> +	void *user;
> +	enum cxd2880_tnrdmd_chip_id chip_id;
> +	enum cxd2880_tnrdmd_state state;
> +	enum cxd2880_tnrdmd_clockmode clk_mode;
> +	u32 frequency_khz;
> +	enum cxd2880_dtv_sys sys;
> +	enum cxd2880_dtv_bandwidth bandwidth;
> +	u8 scan_mode;
> +	atomic_t cancel;
> +};
> +
> +int cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd,
> +			  struct cxd2880_io *io,
> +			  struct cxd2880_tnrdmd_create_param
> +			  *create_param);
> +
> +int cxd2880_tnrdmd_diver_create(struct cxd2880_tnrdmd
> +				*tnr_dmd_main,
> +				struct cxd2880_io *io_main,
> +				struct cxd2880_tnrdmd *tnr_dmd_sub,
> +				struct cxd2880_io *io_sub,
> +				struct
> +				cxd2880_tnrdmd_diver_create_param
> +				*create_param);
> +
> +int cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +int cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +int cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd
> +					     *tnr_dmd,
> +					     u8 *task_completed);
> +
> +int cxd2880_tnrdmd_common_tune_setting1(struct cxd2880_tnrdmd
> +					*tnr_dmd,
> +					enum cxd2880_dtv_sys sys,
> +					u32 frequency_khz,
> +					enum cxd2880_dtv_bandwidth
> +					bandwidth, u8 one_seg_opt,
> +					u8 one_seg_opt_shft_dir);
> +
> +int cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd
> +					*tnr_dmd,
> +					enum cxd2880_dtv_sys sys,
> +					u8 en_fef_intmtnt_ctrl);
> +
> +int cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +int cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
> +			   enum cxd2880_tnrdmd_cfg_id id,
> +			   int value);
> +
> +int cxd2880_tnrdmd_gpio_set_cfg(struct cxd2880_tnrdmd *tnr_dmd,
> +				u8 id,
> +				u8 en,
> +				enum cxd2880_tnrdmd_gpio_mode mode,
> +				u8 open_drain, u8 invert);
> +
> +int cxd2880_tnrdmd_gpio_set_cfg_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				    u8 id,
> +				    u8 en,
> +				    enum cxd2880_tnrdmd_gpio_mode
> +				    mode, u8 open_drain,
> +				    u8 invert);
> +
> +int cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd,
> +			     u8 id, u8 *value);
> +
> +int cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u8 id, u8 *value);
> +
> +int cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd,
> +			      u8 id, u8 value);
> +
> +int cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				  u8 id, u8 value);
> +
> +int cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd,
> +				  u16 *value);
> +
> +int cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd,
> +				   u16 value);
> +
> +int cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd,
> +				u8 clear_overflow_flag,
> +				u8 clear_underflow_flag,
> +				u8 clear_buf);
> +
> +int cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd,
> +			   enum cxd2880_tnrdmd_chip_id *chip_id);
> +
> +int cxd2880_tnrdmd_set_and_save_reg_bits(struct cxd2880_tnrdmd
> +					 *tnr_dmd,
> +					 enum cxd2880_io_tgt tgt,
> +					 u8 bank, u8 address,
> +					 u8 value, u8 bit_mask);
> +
> +int cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd,
> +				 enum cxd2880_dtv_sys sys,
> +				 u8 scan_mode_end);
> +
> +int cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd,
> +			       struct cxd2880_tnrdmd_pid_ftr_cfg
> +			       *pid_ftr_cfg);
> +
> +int cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     int (*rf_lvl_cmpstn)
> +				     (struct cxd2880_tnrdmd *,
> +				     int *));
> +
> +int cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +					 int (*rf_lvl_cmpstn)
> +					 (struct cxd2880_tnrdmd *,
> +					 int *));
> +
> +int cxd2880_tnrdmd_set_lna_thrs(struct cxd2880_tnrdmd *tnr_dmd,
> +				struct
> +				cxd2880_tnrdmd_lna_thrs_tbl_air
> +				*tbl_air,
> +				struct
> +				cxd2880_tnrdmd_lna_thrs_tbl_cable
> +				*tbl_cable);
> +
> +int cxd2880_tnrdmd_set_lna_thrs_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				    struct
> +				    cxd2880_tnrdmd_lna_thrs_tbl_air
> +				    *tbl_air,
> +				    struct
> +				    cxd2880_tnrdmd_lna_thrs_tbl_cable
> +				    *tbl_cable);
> +
> +int cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 en, u8 value);
> +
> +int cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u8 en);
> +
> +int slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +#endif
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
> new file mode 100644
> index 000000000000..bb0f6b295ed3
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_driver_version.h
> @@ -0,0 +1,29 @@
> +/*
> + * cxd2880_tnrdmd_driver_version.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * version information
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.2"
> +
> +#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2017-08-07"
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
> new file mode 100644
> index 000000000000..1ed415af3727
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c
> @@ -0,0 +1,221 @@
> +/*
> + * cxd2880_tnrdmd_mon.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * common monitor functions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_common.h"
> +#include "cxd2880_tnrdmd_mon.h"
> +
> +int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
> +			      int *rf_lvl_db)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!rf_lvl_db))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data[2] = { 0x80, 0x00 };
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_SYS,
> +					      0x5b, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	usleep_range(2000, 3000);
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x1a);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data[2];
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x15, data, 2);
> +		if (ret)
> +			return ret;
> +
> +		if ((data[0] != 0) || (data[1] != 0))
> +			return -EPERM;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_SYS,
> +					     0x11, data, 2);
> +		if (ret)
> +			return ret;
> +
> +		*rf_lvl_db =
> +		    cxd2880_convert2s_complement((data[0] << 3) |
> +						 ((data[1] & 0xe0) >> 5), 11);
> +	}
> +
> +	*rf_lvl_db *= 125;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->rf_lvl_cmpstn) {
> +		ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				  int *rf_lvl_db)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!rf_lvl_db))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
> +					   *tnr_dmd, u16 *status)
> +{
> +	u8 data[2] = { 0 };
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!status))
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x1a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x15, data, 2);
> +	if (ret)
> +		return ret;
> +
> +	*status = (data[0] << 8) | data[1];
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
> +					       cxd2880_tnrdmd
> +					       *tnr_dmd,
> +					       u16 *status)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!status))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub, status);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd,
> +				   struct
> +				   cxd2880_tnrdmd_ts_buf_info
> +				   *info)
> +{
> +	u8 data[3] = { 0 };
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!info))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0a);
> +	if (ret)
> +		return ret;
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x50, data, 3);
> +	if (ret)
> +		return ret;
> +
> +	info->read_ready = (data[0] & 0x10) ? 0x01 : 0x00;
> +	info->almost_full = (data[0] & 0x08) ? 0x01 : 0x00;
> +	info->almost_empty = (data[0] & 0x04) ? 0x01 : 0x00;
> +	info->overflow = (data[0] & 0x02) ? 0x01 : 0x00;
> +	info->underflow = (data[0] & 0x01) ? 0x01 : 0x00;
> +
> +	info->packet_num = ((data[1] & 0x07) << 8) | data[2];
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
> new file mode 100644
> index 000000000000..a4c34f56a7a1
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h
> @@ -0,0 +1,52 @@
> +/*
> + * cxd2880_tnrdmd_mon.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * common monitor interface
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_TNRDMD_MON_H
> +#define CXD2880_TNRDMD_MON_H
> +
> +#include "cxd2880_common.h"
> +#include "cxd2880_tnrdmd.h"
> +
> +int cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd,
> +			      int *rf_lvl_db);
> +
> +int cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				  int *rf_lvl_db);
> +
> +int cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd
> +					   *tnr_dmd, u16 *status);
> +
> +int cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct
> +					       cxd2880_tnrdmd
> +					       *tnr_dmd,
> +					       u16 *status);
> +
> +int cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd,
> +				   struct
> +				   cxd2880_tnrdmd_ts_buf_info
> +				   *info);
> +
> +#endif



Thanks,
Mauro
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 05/14] [media] cxd2880: Add tuner part of the driver
  2017-08-27 14:45     ` Mauro Carvalho Chehab
@ 2017-08-27 14:52       ` Mauro Carvalho Chehab
  -1 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 14:52 UTC (permalink / raw)
  To: Yasunari.Takiguchi
  Cc: linux-kernel, devicetree, linux-media, tbird20d, frowand.list,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

Em Sun, 27 Aug 2017 11:45:44 -0300
Mauro Carvalho Chehab <mchehab@s-opensource.com> escreveu:

> Em Wed, 16 Aug 2017 13:37:14 +0900
> <Yasunari.Takiguchi@sony.com> escreveu:
> 
> > From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> > 
> > This part of the driver has the main routines to handle
> > the tuner and demodulator functionality.  The tnrdmd_mon.* files
> > have monitor functions for the driver.
> > This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.
> 
> This series is on a much better state. Thanks!
> 
> Patches 1-4 sound ok to me.
> 
> Still, there are a few issues on this patch. See below.
> 
> > 
> > [Change list]
> > Changes in V3
> >    drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
> >       -removed code relevant to ISDB-T

Forgot to mention... Just a small detail: the change list is important for
us to understand the differences between submitted versions, but it makes
no sense to track them when patches get merged upstream, as the previous
versions of the patches won't be there at the git history.

So, please put change lists after a blank line with just "---", e. g.:


	From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

	This part of the driver has the main routines to handle
	the tuner and demodulator functionality.  The tnrdmd_mon.* files
	have monitor functions for the driver.
	This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

	---

	(change list and whatever other notes that are relevant to the
	 patch reviewers but won't be merged upstream)

The reason is simple: Kernel maintainers' scripts will just remove
everything after the "---" line when applying the series ;-)

Thanks,
Mauro

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 05/14] [media] cxd2880: Add tuner part of the driver
@ 2017-08-27 14:52       ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 14:52 UTC (permalink / raw)
  To: Yasunari.Takiguchi
  Cc: linux-kernel, devicetree, linux-media, tbird20d, frowand.list,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

Em Sun, 27 Aug 2017 11:45:44 -0300
Mauro Carvalho Chehab <mchehab@s-opensource.com> escreveu:

> Em Wed, 16 Aug 2017 13:37:14 +0900
> <Yasunari.Takiguchi@sony.com> escreveu:
> 
> > From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> > 
> > This part of the driver has the main routines to handle
> > the tuner and demodulator functionality.  The tnrdmd_mon.* files
> > have monitor functions for the driver.
> > This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.
> 
> This series is on a much better state. Thanks!
> 
> Patches 1-4 sound ok to me.
> 
> Still, there are a few issues on this patch. See below.
> 
> > 
> > [Change list]
> > Changes in V3
> >    drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
> >       -removed code relevant to ISDB-T

Forgot to mention... Just a small detail: the change list is important for
us to understand the differences between submitted versions, but it makes
no sense to track them when patches get merged upstream, as the previous
versions of the patches won't be there at the git history.

So, please put change lists after a blank line with just "---", e. g.:


	From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>

	This part of the driver has the main routines to handle
	the tuner and demodulator functionality.  The tnrdmd_mon.* files
	have monitor functions for the driver.
	This is part of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.

	---

	(change list and whatever other notes that are relevant to the
	 patch reviewers but won't be merged upstream)

The reason is simple: Kernel maintainers' scripts will just remove
everything after the "---" line when applying the series ;-)

Thanks,
Mauro

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 07/14] [media] cxd2880: Add top level of the driver
@ 2017-08-27 15:12     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 15:12 UTC (permalink / raw)
  To: Yasunari.Takiguchi
  Cc: linux-kernel, devicetree, linux-media, tbird20d, frowand.list,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

Em Wed, 16 Aug 2017 13:39:45 +0900
<Yasunari.Takiguchi@sony.com> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> 
> This provides the main dvb frontend operation functions
> for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.
> 
> [Change list]
> Changes in V3
>    drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
>       -adjusted indent spaces
>       -modified debugging code
>       -removed unnecessary cast
>       -modified return code
>       -modified coding style of if() 
>       -modified about measurement period of PER/BER.
>       -changed hexadecimal code to lower case. 
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
> ---
>  drivers/media/dvb-frontends/cxd2880/cxd2880_top.c | 1879 +++++++++++++++++++++
>  1 file changed, 1879 insertions(+)
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
> 
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
> new file mode 100644
> index 000000000000..306966dd186b
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
> @@ -0,0 +1,1879 @@
> +/*
> + * cxd2880_top.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
> +
> +#include <linux/spi/spi.h>
> +
> +#include "dvb_frontend.h"
> +#include "dvb_math.h"
> +
> +#include "cxd2880.h"
> +#include "cxd2880_tnrdmd_mon.h"
> +#include "cxd2880_tnrdmd_dvbt2_mon.h"
> +#include "cxd2880_tnrdmd_dvbt_mon.h"
> +#include "cxd2880_integ_dvbt2.h"
> +#include "cxd2880_integ_dvbt.h"
> +#include "cxd2880_devio_spi.h"
> +#include "cxd2880_spi_device.h"
> +#include "cxd2880_tnrdmd_driver_version.h"
> +
> +struct cxd2880_priv {
> +	struct cxd2880_tnrdmd tnrdmd;
> +	struct spi_device *spi;
> +	struct cxd2880_io regio;
> +	struct cxd2880_spi_device spi_device;
> +	struct cxd2880_spi cxd2880_spi;
> +	struct cxd2880_dvbt_tune_param dvbt_tune_param;
> +	struct cxd2880_dvbt2_tune_param dvbt2_tune_param;
> +	struct mutex *spi_mutex; /* For SPI access exclusive control */
> +	unsigned long pre_ber_update;
> +	unsigned long pre_ber_interval;
> +	unsigned long post_ber_update;
> +	unsigned long post_ber_interval;
> +	unsigned long ucblock_update;
> +	unsigned long ucblock_interval;
> +};
> +
> +static int cxd2880_pre_bit_err_t(
> +		struct cxd2880_tnrdmd *tnrdmd, u32 *pre_bit_err,
> +		u32 *pre_bit_count)
> +{
> +	u8 rdata[2];
> +	int ret = 0;
> +
> +	if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count))
> +		return -EINVAL;
> +
> +	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnrdmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x10);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x39, rdata, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	if ((rdata[0] & 0x01) == 0) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return -EBUSY;
> +	}
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x22, rdata, 2);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	*pre_bit_err = (rdata[0] << 8) | rdata[1];
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x6f, rdata, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnrdmd);
> +
> +	*pre_bit_count = ((rdata[0] & 0x07) == 0) ?
> +			 256 : (0x1000 << (rdata[0] & 0x07));
> +
> +	return 0;
> +}
> +
> +static int cxd2880_pre_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
> +				  u32 *pre_bit_err,
> +				  u32 *pre_bit_count)
> +{
> +	u32 period_exp = 0;
> +	u32 n_ldpc = 0;
> +	u8 data[5];
> +	int ret = 0;
> +
> +	if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count))
> +		return -EINVAL;
> +
> +	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnrdmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x0b);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x3c, data, sizeof(data));
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	if (!(data[0] & 0x01)) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return -EBUSY;
> +	}
> +	*pre_bit_err =
> +	((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0xa0, data, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) ==
> +	    CXD2880_DVBT2_FEC_LDPC_16K)
> +		n_ldpc = 16200;
> +	else
> +		n_ldpc = 64800;
> +	slvt_unfreeze_reg(tnrdmd);
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x20);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x6f, data, 1);
> +	if (ret)
> +		return ret;
> +
> +	period_exp = data[0] & 0x0f;
> +
> +	*pre_bit_count = (1U << period_exp) * n_ldpc;
> +
> +	return 0;
> +}
> +
> +static int cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd,
> +				  u32 *post_bit_err,
> +				  u32 *post_bit_count)
> +{
> +	u8 rdata[3];
> +	u32 bit_error = 0;
> +	u32 period_exp = 0;
> +	int ret = 0;
> +
> +	if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count))
> +		return -EINVAL;
> +
> +	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x0d);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x15, rdata, 3);
> +	if (ret)
> +		return ret;
> +
> +	if ((rdata[0] & 0x40) == 0)
> +		return -EBUSY;
> +
> +	*post_bit_err = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2];
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x60, rdata, 1);
> +	if (ret)
> +		return ret;
> +
> +	period_exp = (rdata[0] & 0x1f);
> +
> +	if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8))
> +		return -EBUSY;
> +
> +	if (period_exp == 11)
> +		*post_bit_count = 3342336;
> +	else
> +		*post_bit_count = (1U << period_exp) * 204 * 81;
> +
> +	return 0;
> +}
> +
> +static int cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
> +				   u32 *post_bit_err,
> +				   u32 *post_bit_count)
> +{
> +	u32 period_exp = 0;
> +	u32 n_bch = 0;
> +
> +	if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count))
> +		return -EINVAL;
> +
> +	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[3];
> +		enum cxd2880_dvbt2_plp_fec plp_fec_type =
> +			CXD2880_DVBT2_FEC_LDPC_16K;
> +		enum cxd2880_dvbt2_plp_code_rate plp_code_rate =
> +			CXD2880_DVBT2_R1_2;
> +
> +		static const u16 n_bch_bits_lookup[2][8] = {
> +			{7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480},
> +			{32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920}
> +		};
> +		int ret = 0;

Same as pointed on patch 5: don't use a code block, except if you
need (e. g. on if, else, switch, do, etc).

Instead, move static const structs out of the function and put
the remaining data at the beginning of the function.

Also, ret doesn't need to be initialized, as it will already
be initialized before usage.

> +
> +		ret = slvt_freeze_reg(tnrdmd);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnrdmd->io->write_reg(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnrdmd);
> +			return ret;
> +		}
> +
> +		ret = tnrdmd->io->read_regs(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x15, data, 3);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnrdmd);
> +			return ret;
> +		}
> +
> +		if (!(data[0] & 0x40)) {
> +			slvt_unfreeze_reg(tnrdmd);
> +			return -EBUSY;
> +		}
> +
> +		*post_bit_err =
> +			((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2];
> +
> +		ret = tnrdmd->io->read_regs(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x9d, data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnrdmd);
> +			return ret;
> +		}
> +
> +		plp_code_rate =
> +		(enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07);
> +
> +		ret = tnrdmd->io->read_regs(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0xa0, data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnrdmd);
> +			return ret;
> +		}
> +
> +		plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03);
> +
> +		slvt_unfreeze_reg(tnrdmd);
> +
> +		ret = tnrdmd->io->write_reg(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x00, 0x20);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnrdmd->io->read_regs(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x72, data, 1);
> +		if (ret)
> +			return ret;
> +
> +		period_exp = data[0] & 0x0f;
> +
> +		if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) ||
> +		    (plp_code_rate > CXD2880_DVBT2_R2_5))
> +			return -EBUSY;
> +
> +		n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate];
> +	}
> +
> +	if (*post_bit_err > ((1U << period_exp) * n_bch))
> +		return -EBUSY;
> +
> +	*post_bit_count = (1U << period_exp) * n_bch;
> +
> +	return 0;
> +}
> +
> +static int cxd2880_read_block_err_t(struct cxd2880_tnrdmd *tnrdmd,
> +				    u32 *block_err,
> +				    u32 *block_count)
> +{
> +	u8 rdata[3];
> +	int ret = 0;
> +
> +	if ((!tnrdmd) || (!block_err) || (!block_count))
> +		return -EINVAL;
> +
> +	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x0d);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x18, rdata, 3);
> +	if (ret)
> +		return ret;
> +
> +	if ((rdata[0] & 0x01) == 0)
> +		return -EBUSY;
> +
> +	*block_err = (rdata[1] << 8) | rdata[2];
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x5c, rdata, 1);
> +	if (ret)
> +		return ret;
> +
> +	*block_count = 1U << (rdata[0] & 0x0f);
> +
> +	if ((*block_count == 0) || (*block_err > *block_count))
> +		return -EBUSY;
> +
> +	return 0;
> +}
> +
> +static int cxd2880_read_block_err_t2(struct cxd2880_tnrdmd *tnrdmd,
> +				     u32 *block_err,
> +				     u32 *block_count)
> +{
> +	if ((!tnrdmd) || (!block_err) || (!block_count))
> +		return -EINVAL;
> +
> +	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 rdata[3];
> +		int ret = 0;

Same here. Same comment applies to other similar coding.
> +
> +		ret = tnrdmd->io->write_reg(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x00, 0x0b);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnrdmd->io->read_regs(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x18, rdata, 3);
> +		if (ret)
> +			return ret;
> +
> +		if ((rdata[0] & 0x01) == 0)
> +			return -EBUSY;
> +
> +		*block_err = (rdata[1] << 8) | rdata[2];
> +
> +		ret = tnrdmd->io->write_reg(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x00, 0x24);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnrdmd->io->read_regs(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0xdc, rdata, 1);
> +		if (ret)
> +			return ret;
> +
> +		*block_count = 1U << (rdata[0] & 0x0f);
> +	}
> +
> +	if ((*block_count == 0) || (*block_err > *block_count))
> +		return -EBUSY;
> +
> +	return 0;
> +}
> +
> +static void cxd2880_release(struct dvb_frontend *fe)
> +{
> +	struct cxd2880_priv *priv = NULL;
> +
> +	if (!fe) {
> +		pr_err("invalid arg.\n");
> +		return;
> +	}
> +	priv = fe->demodulator_priv;
> +	kfree(priv);
> +}
> +
> +static int cxd2880_init(struct dvb_frontend *fe)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct cxd2880_tnrdmd_create_param create_param;
> +
> +	if (!fe) {
> +		pr_err("invalid arg.\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +
> +	create_param.ts_output_if = CXD2880_TNRDMD_TSOUT_IF_SPI;
> +	create_param.xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_NONE;
> +	create_param.en_internal_ldo = 1;
> +	create_param.xosc_cap = 18;
> +	create_param.xosc_i = 8;
> +	create_param.stationary_use = 1;
> +
> +	mutex_lock(priv->spi_mutex);
> +	if (priv->tnrdmd.io != &priv->regio) {
> +		ret = cxd2880_tnrdmd_create(&priv->tnrdmd,
> +					    &priv->regio, &create_param);
> +		if (ret) {
> +			mutex_unlock(priv->spi_mutex);
> +			pr_info("cxd2880 tnrdmd create failed %d\n", ret);
> +			return ret;
> +		}
> +	}
> +	ret = cxd2880_integ_init(&priv->tnrdmd);
> +	if (ret) {
> +		mutex_unlock(priv->spi_mutex);
> +		pr_err("cxd2880 integ init failed %d\n", ret);
> +		return ret;
> +	}
> +	mutex_unlock(priv->spi_mutex);
> +
> +	pr_debug("OK.\n");
> +
> +	return ret;
> +}
> +
> +static int cxd2880_sleep(struct dvb_frontend *fe)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +
> +	if (!fe) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd);
> +	mutex_unlock(priv->spi_mutex);
> +
> +	pr_debug("tnrdmd_sleep ret %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int cxd2880_read_signal_strength(struct dvb_frontend *fe,
> +					u16 *strength)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct dtv_frontend_properties *c = NULL;
> +	int level = 0;
> +
> +	if ((!fe) || (!strength)) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +
> +	mutex_lock(priv->spi_mutex);
> +	if ((c->delivery_system == SYS_DVBT) ||
> +	    (c->delivery_system == SYS_DVBT2)) {
> +		ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &level);
> +	} else {
> +		pr_debug("invalid system\n");
> +		mutex_unlock(priv->spi_mutex);
> +		return -EINVAL;
> +	}
> +	mutex_unlock(priv->spi_mutex);
> +
> +	level /= 125;
> +	/* -105dBm - -30dBm (-105000/125 = -840, -30000/125 = -240 */

It took me a while to understand what you meant here. I guess you
meant to say:

	/*
	 * Level should be between -105dBm and -30dBm.
	 * E. g. they should be between:
	 *	-105000/125 = -840 and -30000/125 = -240
	 */

(better to be a little clearer here, with something like the above
comment)


> +	level = clamp(level, -840, -240);
> +	/* scale value to 0x0000-0xffff */
> +	*strength = (u16)(((level + 840) * 0xffff) / (-240 + 840));
> +
> +	if (ret)
> +		pr_debug("ret = %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr)
> +{
> +	int ret = 0;
> +	int snrvalue = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct dtv_frontend_properties *c = NULL;
> +
> +	if ((!fe) || (!snr)) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +
> +	mutex_lock(priv->spi_mutex);
> +	if (c->delivery_system == SYS_DVBT) {
> +		ret = cxd2880_tnrdmd_dvbt_mon_snr(&priv->tnrdmd,
> +						  &snrvalue);
> +	} else if (c->delivery_system == SYS_DVBT2) {
> +		ret = cxd2880_tnrdmd_dvbt2_mon_snr(&priv->tnrdmd,
> +						   &snrvalue);
> +	} else {
> +		pr_err("invalid system\n");
> +		mutex_unlock(priv->spi_mutex);
> +		return -EINVAL;
> +	}
> +	mutex_unlock(priv->spi_mutex);
> +
> +	if (snrvalue < 0)
> +		snrvalue = 0;
> +	*snr = (u16)snrvalue;
> +
> +	if (ret)
> +		pr_debug("ret = %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct dtv_frontend_properties *c = NULL;
> +
> +	if ((!fe) || (!ucblocks)) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +
> +	mutex_lock(priv->spi_mutex);
> +	if (c->delivery_system == SYS_DVBT) {
> +		ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number(
> +								&priv->tnrdmd,
> +								ucblocks);
> +	} else if (c->delivery_system == SYS_DVBT2) {
> +		ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number(
> +								&priv->tnrdmd,
> +								ucblocks);
> +	} else {
> +		pr_err("invlaid system\n");

typo: invalid

> +		mutex_unlock(priv->spi_mutex);
> +		return -EINVAL;
> +	}
> +	mutex_unlock(priv->spi_mutex);
> +
> +	if (ret)
> +		pr_debug("ret = %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct dtv_frontend_properties *c = NULL;
> +
> +	if ((!fe) || (!ber)) {
> +		pr_err("inavlid arg\n");

Same typo here:
	inavlid -> invalid

> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +
> +	mutex_lock(priv->spi_mutex);
> +	if (c->delivery_system == SYS_DVBT) {
> +		ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(&priv->tnrdmd,
> +							ber);
> +		/* x100 to change unit.(10^7 -> 10^9 */

Missing ')'

> +		*ber *= 100;
> +	} else if (c->delivery_system == SYS_DVBT2) {
> +		ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(&priv->tnrdmd,
> +							  ber);
> +	} else {
> +		pr_err("invlaid system\n");

Same typo here... better to check the entire code. It seems that it
was copied and pasted on several places :-)

> +		mutex_unlock(priv->spi_mutex);
> +		return -EINVAL;
> +	}
> +	mutex_unlock(priv->spi_mutex);
> +
> +	if (ret)
> +		pr_debug("ret = %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe)
> +{
> +	int ret = 0;
> +	struct dtv_frontend_properties *c;
> +	struct cxd2880_priv *priv;
> +	int cr_table[5] = {31500, 42000, 47250, 52500, 55125};
> +	int denominator_tbl[4] = {125664, 129472, 137088, 152320};

Are both tables static const? If so, declare as such, as it
decreases the Kernel runtime size.

> +	struct cxd2880_dvbt_tpsinfo info;
> +	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
> +	u32 pre_ber_rate = 0;
> +	u32 post_ber_rate = 0;
> +	u32 ucblock_rate = 0;
> +	u32 mes_exp = 0;
> +
> +	if (!fe) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +	bw = priv->dvbt_tune_param.bandwidth;
> +
> +	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd,
> +					       &info);
> +	if (ret) {
> +		pr_err("tps monitor error ret = %d\n", ret);
> +		info.hierarchy = CXD2880_DVBT_HIERARCHY_NON;
> +		info.constellation = CXD2880_DVBT_CONSTELLATION_QPSK;
> +		info.guard = CXD2880_DVBT_GUARD_1_4;
> +		info.rate_hp = CXD2880_DVBT_CODERATE_1_2;
> +		info.rate_lp = CXD2880_DVBT_CODERATE_1_2;
> +	}
> +
> +	if (info.hierarchy == CXD2880_DVBT_HIERARCHY_NON) {
> +		pre_ber_rate = 63000000 * bw * (info.constellation * 2 + 2) /
> +			       denominator_tbl[info.guard];
> +
> +		post_ber_rate =	1000 * cr_table[info.rate_hp] * bw *
> +				(info.constellation * 2 + 2) /
> +				denominator_tbl[info.guard];
> +
> +		ucblock_rate = 875 * cr_table[info.rate_hp] * bw *
> +			       (info.constellation * 2 + 2) /
> +			       denominator_tbl[info.guard];
> +	} else {
> +		u8 data = 0;
> +		struct cxd2880_tnrdmd *tnrdmd = &priv->tnrdmd;
> +
> +		ret = tnrdmd->io->write_reg(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x00, 0x10);
> +		if (!ret) {
> +			ret = tnrdmd->io->read_regs(tnrdmd->io,
> +						    CXD2880_IO_TGT_DMD,
> +						    0x67, &data, 1);
> +			if (ret)
> +				data = 0x00;
> +		} else {
> +			data = 0x00;
> +		}
> +
> +		if (data & 0x01) { /* Low priority */
> +			pre_ber_rate =
> +				63000000 * bw * (info.constellation * 2 + 2) /
> +				denominator_tbl[info.guard];
> +
> +			post_ber_rate = 1000 * cr_table[info.rate_lp] * bw *
> +					(info.constellation * 2 + 2) /
> +					denominator_tbl[info.guard];
> +
> +			ucblock_rate = (1000 * 7 / 8) *	cr_table[info.rate_lp] *
> +				       bw * (info.constellation * 2 + 2) /
> +				       denominator_tbl[info.guard];
> +		} else { /* High priority */
> +			pre_ber_rate =
> +				63000000 * bw * 2 / denominator_tbl[info.guard];
> +
> +			post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * 2 /
> +					denominator_tbl[info.guard];
> +
> +			ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_hp] *
> +					bw * 2 / denominator_tbl[info.guard];
> +		}
> +	}
> +
> +	mes_exp = pre_ber_rate < 8192 ? 8 : intlog2(pre_ber_rate) >> 24;
> +	priv->pre_ber_interval =
> +		((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) /
> +		pre_ber_rate;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
> +			       mes_exp == 8 ? 0 : mes_exp - 12);
> +
> +	mes_exp = intlog2(post_ber_rate) >> 24;
> +	priv->post_ber_interval =
> +		((1U << mes_exp) * 1000 + (post_ber_rate / 2)) /
> +		post_ber_rate;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
> +			       mes_exp);
> +
> +	mes_exp = intlog2(ucblock_rate) >> 24;
> +	priv->ucblock_interval =
> +		((1U << mes_exp) * 1000 + (ucblock_rate / 2)) /
> +		ucblock_rate;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT_PER_MES,
> +			       mes_exp);
> +
> +	return 0;
> +}
> +
> +static int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe)
> +{
> +	int ret = 0;
> +	struct dtv_frontend_properties *c;
> +	struct cxd2880_priv *priv;
> +	struct cxd2880_dvbt2_l1pre l1pre;
> +	struct cxd2880_dvbt2_l1post l1post;
> +	struct cxd2880_dvbt2_plp plp;
> +	struct cxd2880_dvbt2_bbheader bbheader;
> +	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
> +	u32 pre_ber_rate = 0;
> +	u32 post_ber_rate = 0;
> +	u32 ucblock_rate = 0;
> +	u32 mes_exp = 0;
> +	u32 term_a = 0;
> +	u32 term_b = 0;
> +	u32 gi_tbl[7] = {32, 64, 128, 256, 8, 152, 76};
> +	u8  n_tbl[6] = {8, 2, 4, 16, 1, 1};
> +	u8  mode_tbl[6] = {2, 8, 4, 1, 16, 32};
> +	u32 kbch_tbl[2][8] = {
> +			{6952, 9472, 10552, 11632, 12352, 13072, 5152, 6232},
> +			{32128, 38608, 42960, 48328, 51568, 53760, 0, 0} };
> +	u32 denominator = 0;
> +
> +	if (!fe) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +	bw = priv->dvbt2_tune_param.bandwidth;
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
> +	if (ret) {
> +		pr_info("l1 pre error\n");
> +		goto error_ber_setting;
> +	}
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_active_plp(&priv->tnrdmd,
> +						  CXD2880_DVBT2_PLP_DATA, &plp);
> +	if (ret) {
> +		pr_info("plp info error\n");
> +		goto error_ber_setting;
> +	}
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_l1_post(&priv->tnrdmd, &l1post);
> +	if (ret) {
> +		pr_info("l1 post error\n");
> +		goto error_ber_setting;
> +	}
> +
> +	term_a =
> +		(mode_tbl[l1pre.fft_mode] * (1024 + gi_tbl[l1pre.gi])) *
> +		(l1pre.num_symbols + n_tbl[l1pre.fft_mode]) + 2048;
> +
> +	if (l1pre.mixed && l1post.fef_intvl) {
> +		term_b = (l1post.fef_length + (l1post.fef_intvl / 2)) /
> +			 l1post.fef_intvl;
> +	} else {
> +		term_b = 0;
> +	}
> +
> +	switch (bw) {
> +	case CXD2880_DTV_BW_1_7_MHZ:
> +		denominator = ((term_a + term_b) * 71 + (131 / 2)) / 131;
> +		break;
> +	case CXD2880_DTV_BW_5_MHZ:
> +		denominator = ((term_a + term_b) * 7 + 20) / 40;
> +		break;
> +	case CXD2880_DTV_BW_6_MHZ:
> +		denominator = ((term_a + term_b) * 7 + 24) / 48;
> +		break;
> +	case CXD2880_DTV_BW_7_MHZ:
> +		denominator = ((term_a + term_b) + 4) / 8;
> +		break;
> +	case CXD2880_DTV_BW_8_MHZ:
> +	default:
> +		denominator = ((term_a + term_b) * 7 + 32) / 64;
> +		break;
> +	}
> +
> +	if (plp.til_type && plp.til_len) {
> +		pre_ber_rate =
> +			(plp.num_blocks_max * 1000000 + (denominator / 2)) /
> +			denominator;
> +		pre_ber_rate = (pre_ber_rate + (plp.til_len / 2)) /
> +			       plp.til_len;
> +	} else {
> +		pre_ber_rate =
> +			(plp.num_blocks_max * 1000000 + (denominator / 2)) /
> +			denominator;
> +	}
> +
> +	post_ber_rate = pre_ber_rate;
> +
> +	mes_exp = intlog2(pre_ber_rate) >> 24;
> +	priv->pre_ber_interval =
> +		((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) /
> +		pre_ber_rate;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
> +			       mes_exp);
> +
> +	mes_exp = intlog2(post_ber_rate) >> 24;
> +	priv->post_ber_interval =
> +		((1U << mes_exp) * 1000 + (post_ber_rate / 2)) /
> +		post_ber_rate;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
> +			       mes_exp);
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_bbheader(&priv->tnrdmd,
> +						CXD2880_DVBT2_PLP_DATA,
> +						&bbheader);
> +	if (ret) {
> +		pr_info("bb header error\n");
> +		goto error_ucblock_setting;
> +	}
> +
> +	if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
> +		if (!bbheader.issy_indicator) {
> +			ucblock_rate =
> +				(pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] +
> +				752) / 1504;
> +		} else {
> +			ucblock_rate =
> +				(pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] +
> +				764) / 1528;
> +		}
> +	} else if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_HEM) {
> +		ucblock_rate =
> +			(pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 748) /
> +			1496;
> +	} else {
> +		pr_info("plp mode is not Normal or HEM\n");
> +		goto error_ucblock_setting;
> +	}
> +
> +	mes_exp = intlog2(ucblock_rate) >> 24;
> +	priv->ucblock_interval =
> +		((1U << mes_exp) * 1000 + (ucblock_rate / 2)) /
> +		ucblock_rate;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
> +			       mes_exp);
> +
> +	return 0;
> +
> +error_ber_setting:
> +	priv->pre_ber_interval = 1000;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +				     CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, 0);
> +
> +	priv->post_ber_interval = 1000;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, 0);
> +
> +error_ucblock_setting:
> +	priv->ucblock_interval = 1000;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT2_PER_MES, 8);
> +
> +	return 0;
> +}
> +
> +static int cxd2880_set_frontend(struct dvb_frontend *fe)
> +{
> +	int ret = 0;
> +	int ret_val = 0;
> +	struct dtv_frontend_properties *c;
> +	struct cxd2880_priv *priv;
> +	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
> +
> +	if (!fe) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +
> +	c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +	c->pre_bit_error.stat[0].uvalue = 0;
> +	c->pre_bit_error.len = 1;
> +	c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +	c->pre_bit_count.stat[0].uvalue = 0;
> +	c->pre_bit_count.len = 1;
> +	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +	c->post_bit_error.stat[0].uvalue = 0;
> +	c->post_bit_error.len = 1;
> +	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +	c->post_bit_count.stat[0].uvalue = 0;
> +	c->post_bit_count.len = 1;
> +	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +	c->block_error.stat[0].uvalue = 0;
> +	c->block_error.len = 1;
> +	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +	c->block_count.stat[0].uvalue = 0;
> +	c->block_count.len = 1;
> +
> +	switch (c->bandwidth_hz) {
> +	case 1712000:
> +		bw = CXD2880_DTV_BW_1_7_MHZ;
> +		break;
> +	case 5000000:
> +		bw = CXD2880_DTV_BW_5_MHZ;
> +		break;
> +	case 6000000:
> +		bw = CXD2880_DTV_BW_6_MHZ;
> +		break;
> +	case 7000000:
> +		bw = CXD2880_DTV_BW_7_MHZ;
> +		break;
> +	case 8000000:
> +		bw = CXD2880_DTV_BW_8_MHZ;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	pr_info("sys:%d freq:%d bw:%d\n",
> +		c->delivery_system, c->frequency, bw);
> +	mutex_lock(priv->spi_mutex);
> +	if (c->delivery_system == SYS_DVBT) {
> +		priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT;
> +		priv->dvbt_tune_param.center_freq_khz = c->frequency / 1000;
> +		priv->dvbt_tune_param.bandwidth = bw;
> +		priv->dvbt_tune_param.profile = CXD2880_DVBT_PROFILE_HP;
> +		ret = cxd2880_integ_dvbt_tune(&priv->tnrdmd,
> +					      &priv->dvbt_tune_param);
> +		ret_val = cxd2880_set_ber_per_period_t(fe);
> +	} else if (c->delivery_system == SYS_DVBT2) {
> +		priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT2;
> +		priv->dvbt2_tune_param.center_freq_khz = c->frequency / 1000;
> +		priv->dvbt2_tune_param.bandwidth = bw;
> +		priv->dvbt2_tune_param.data_plp_id = (u16)c->stream_id;
> +		priv->dvbt2_tune_param.profile = CXD2880_DVBT2_PROFILE_BASE;
> +		ret = cxd2880_integ_dvbt2_tune(&priv->tnrdmd,
> +					       &priv->dvbt2_tune_param);
> +		ret_val = cxd2880_set_ber_per_period_t2(fe);
> +	} else {
> +		pr_err("invalid system\n");
> +		mutex_unlock(priv->spi_mutex);
> +		return -EINVAL;
> +	}
> +	mutex_unlock(priv->spi_mutex);
> +
> +	pr_info("tune result %d set ber/per result %d\n", ret, ret_val);
> +
> +	return ret;
> +}
> +
> +static int cxd2880_get_stats(struct dvb_frontend *fe,
> +			     enum fe_status status)
> +{
> +	struct cxd2880_priv *priv = NULL;
> +	struct dtv_frontend_properties *c = NULL;
> +	u32 pre_bit_err = 0, pre_bit_count = 0;
> +	u32 post_bit_err = 0, post_bit_count = 0;
> +	u32 block_err = 0, block_count = 0;
> +	int ret = 0;
> +
> +	if (!fe) {
> +		pr_err("invalid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +
> +	if (!(status & FE_HAS_LOCK)) {
> +		c->pre_bit_error.len = 1;
> +		c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		c->pre_bit_count.len = 1;
> +		c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		c->post_bit_error.len = 1;
> +		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		c->post_bit_count.len = 1;
> +		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		c->block_error.len = 1;
> +		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		c->block_count.len = 1;
> +		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +
> +		return 0;
> +	}
> +
> +	if (time_after(jiffies, priv->pre_ber_update)) {
> +		priv->pre_ber_update =
> +			 jiffies + msecs_to_jiffies(priv->pre_ber_interval);
> +		if (c->delivery_system == SYS_DVBT) {
> +			mutex_lock(priv->spi_mutex);
> +			ret = cxd2880_pre_bit_err_t(&priv->tnrdmd,
> +						    &pre_bit_err,
> +						    &pre_bit_count);
> +			mutex_unlock(priv->spi_mutex);
> +		} else if (c->delivery_system == SYS_DVBT2) {
> +			mutex_lock(priv->spi_mutex);
> +			ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd,
> +						     &pre_bit_err,
> +						     &pre_bit_count);
> +			mutex_unlock(priv->spi_mutex);
> +		} else {
> +			return -EINVAL;
> +		}
> +
> +		if (!ret) {
> +			c->pre_bit_error.len = 1;
> +			c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
> +			c->pre_bit_error.stat[0].uvalue += pre_bit_err;
> +			c->pre_bit_count.len = 1;
> +			c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
> +			c->pre_bit_count.stat[0].uvalue += pre_bit_count;
> +		} else {
> +			c->pre_bit_error.len = 1;
> +			c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +			c->pre_bit_count.len = 1;
> +			c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +			pr_debug("pre_bit_error_t failed %d\n", ret);
> +		}
> +	}
> +
> +	if (time_after(jiffies, priv->post_ber_update)) {
> +		priv->post_ber_update =
> +			jiffies + msecs_to_jiffies(priv->post_ber_interval);
> +		if (c->delivery_system == SYS_DVBT) {
> +			mutex_lock(priv->spi_mutex);
> +			ret = cxd2880_post_bit_err_t(&priv->tnrdmd,
> +						     &post_bit_err,
> +						     &post_bit_count);
> +			mutex_unlock(priv->spi_mutex);
> +		} else if (c->delivery_system == SYS_DVBT2) {
> +			mutex_lock(priv->spi_mutex);
> +			ret = cxd2880_post_bit_err_t2(&priv->tnrdmd,
> +						      &post_bit_err,
> +						      &post_bit_count);
> +			mutex_unlock(priv->spi_mutex);
> +		} else {
> +			pr_err();
> +			return -EINVAL;
> +		}
> +
> +		if (!ret) {
> +			c->post_bit_error.len = 1;
> +			c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
> +			c->post_bit_error.stat[0].uvalue += post_bit_err;
> +			c->post_bit_count.len = 1;
> +			c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
> +			c->post_bit_count.stat[0].uvalue += post_bit_count;
> +		} else {
> +			c->post_bit_error.len = 1;
> +			c->post_bit_error.stat[0].scale =
> +							FE_SCALE_NOT_AVAILABLE;
> +			c->post_bit_count.len = 1;
> +			c->post_bit_count.stat[0].scale =
> +							FE_SCALE_NOT_AVAILABLE;
> +			pr_debug("post_bit_err_t %d\n", ret);
> +		}
> +	}
> +
> +	if (time_after(jiffies, priv->ucblock_update)) {
> +		priv->ucblock_update =
> +			jiffies + msecs_to_jiffies(priv->ucblock_interval);
> +		if (c->delivery_system == SYS_DVBT) {
> +			mutex_lock(priv->spi_mutex);
> +			ret = cxd2880_read_block_err_t(&priv->tnrdmd,
> +						       &block_err,
> +						       &block_count);
> +			mutex_unlock(priv->spi_mutex);
> +		} else if (c->delivery_system == SYS_DVBT2) {
> +			mutex_lock(priv->spi_mutex);
> +			ret = cxd2880_read_block_err_t2(&priv->tnrdmd,
> +							&block_err,
> +							&block_count);
> +			mutex_unlock(priv->spi_mutex);
> +		} else {
> +			pr_err();
> +			return -EINVAL;
> +		}
> +		if (!ret) {
> +			c->block_error.len = 1;
> +			c->block_error.stat[0].scale = FE_SCALE_COUNTER;
> +			c->block_error.stat[0].uvalue += block_err;
> +			c->block_count.len = 1;
> +			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
> +			c->block_count.stat[0].uvalue += block_count;
> +		} else {
> +			c->block_error.len = 1;
> +			c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +			c->block_count.len = 1;
> +			c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +			pr_debug("read_block_err_t  %d\n", ret);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int cxd2880_read_status(struct dvb_frontend *fe,
> +			       enum fe_status *status)
> +{
> +	int ret = 0;
> +	u8 sync = 0;
> +	u8 lock = 0;
> +	u8 unlock = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct dtv_frontend_properties *c = NULL;
> +
> +	if ((!fe) || (!status)) {
> +		pr_err("invalid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +	*status = 0;
> +
> +	if (priv->tnrdmd.state == CXD2880_TNRDMD_STATE_ACTIVE) {
> +		mutex_lock(priv->spi_mutex);
> +		if (c->delivery_system == SYS_DVBT) {
> +			ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(
> +							&priv->tnrdmd,
> +							&sync,
> +							&lock,
> +							&unlock);
> +		} else if (c->delivery_system == SYS_DVBT2) {
> +			ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(
> +							&priv->tnrdmd,
> +							&sync,
> +							&lock,
> +							&unlock);
> +		} else {
> +			pr_err("invlaid system");
> +			mutex_unlock(priv->spi_mutex);
> +			return -EINVAL;
> +		}
> +
> +		mutex_unlock(priv->spi_mutex);
> +		if (ret) {
> +			pr_err("failed. sys = %d\n", priv->tnrdmd.sys);
> +			return  ret;
> +		}
> +
> +		if (sync == 6) {
> +			*status = FE_HAS_SIGNAL |
> +				  FE_HAS_CARRIER;
> +		}
> +		if (lock)
> +			*status |= FE_HAS_VITERBI |
> +				   FE_HAS_SYNC |
> +				   FE_HAS_LOCK;
> +	}
> +
> +	pr_debug("status %d result %d\n", *status, ret);
> +
> +	cxd2880_get_stats(fe, *status);
> +	return  0;
> +}
> +
> +static int cxd2880_tune(struct dvb_frontend *fe,
> +			bool retune,
> +			unsigned int mode_flags,
> +			unsigned int *delay,
> +			enum fe_status *status)
> +{
> +	int ret = 0;
> +
> +	if ((!fe) || (!delay) || (!status)) {
> +		pr_err("invalid arg.");
> +		return -EINVAL;
> +	}
> +
> +	if (retune) {
> +		ret = cxd2880_set_frontend(fe);
> +		if (ret) {
> +			pr_err("cxd2880_set_frontend failed %d\n", ret);
> +			return ret;
> +		}
> +	}
> +
> +	*delay = HZ / 5;
> +
> +	return cxd2880_read_status(fe, status);
> +}
> +
> +static int cxd2880_get_frontend_t(struct dvb_frontend *fe,
> +				  struct dtv_frontend_properties *c)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	enum cxd2880_dvbt_mode mode = CXD2880_DVBT_MODE_2K;
> +	enum cxd2880_dvbt_guard guard = CXD2880_DVBT_GUARD_1_32;
> +	struct cxd2880_dvbt_tpsinfo tps;
> +	enum cxd2880_tnrdmd_spectrum_sense sense;
> +	u16 snr = 0;
> +	int strength = 0;
> +
> +	if ((!fe) || (!c)) {
> +		pr_err("invalid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt_mon_mode_guard(&priv->tnrdmd,
> +						 &mode, &guard);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (mode) {
> +		case CXD2880_DVBT_MODE_2K:
> +			c->transmission_mode = TRANSMISSION_MODE_2K;
> +			break;
> +		case CXD2880_DVBT_MODE_8K:
> +			c->transmission_mode = TRANSMISSION_MODE_8K;
> +			break;
> +		default:
> +			c->transmission_mode = TRANSMISSION_MODE_2K;
> +			pr_err("get invalid mode %d\n", mode);
> +			break;
> +		}
> +		switch (guard) {
> +		case CXD2880_DVBT_GUARD_1_32:
> +			c->guard_interval = GUARD_INTERVAL_1_32;
> +			break;
> +		case CXD2880_DVBT_GUARD_1_16:
> +			c->guard_interval = GUARD_INTERVAL_1_16;
> +			break;
> +		case CXD2880_DVBT_GUARD_1_8:
> +			c->guard_interval = GUARD_INTERVAL_1_8;
> +			break;
> +		case CXD2880_DVBT_GUARD_1_4:
> +			c->guard_interval = GUARD_INTERVAL_1_4;
> +			break;
> +		default:
> +			c->guard_interval = GUARD_INTERVAL_1_32;
> +			pr_err("get invalid guard %d\n", guard);
> +			break;
> +		}
> +	} else {
> +		c->transmission_mode = TRANSMISSION_MODE_2K;
> +		c->guard_interval = GUARD_INTERVAL_1_32;
> +		pr_debug("ModeGuard err %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (tps.hierarchy) {
> +		case CXD2880_DVBT_HIERARCHY_NON:
> +			c->hierarchy = HIERARCHY_NONE;
> +			break;
> +		case CXD2880_DVBT_HIERARCHY_1:
> +			c->hierarchy = HIERARCHY_1;
> +			break;
> +		case CXD2880_DVBT_HIERARCHY_2:
> +			c->hierarchy = HIERARCHY_2;
> +			break;
> +		case CXD2880_DVBT_HIERARCHY_4:
> +			c->hierarchy = HIERARCHY_4;
> +			break;
> +		default:
> +			c->hierarchy = HIERARCHY_NONE;
> +			pr_err("TPSInfo hierarchy invalid %d\n",
> +			       tps.hierarchy);
> +			break;
> +		}
> +
> +		switch (tps.rate_hp) {
> +		case CXD2880_DVBT_CODERATE_1_2:
> +			c->code_rate_HP = FEC_1_2;
> +			break;
> +		case CXD2880_DVBT_CODERATE_2_3:
> +			c->code_rate_HP = FEC_2_3;
> +			break;
> +		case CXD2880_DVBT_CODERATE_3_4:
> +			c->code_rate_HP = FEC_3_4;
> +			break;
> +		case CXD2880_DVBT_CODERATE_5_6:
> +			c->code_rate_HP = FEC_5_6;
> +			break;
> +		case CXD2880_DVBT_CODERATE_7_8:
> +			c->code_rate_HP = FEC_7_8;
> +			break;
> +		default:
> +			c->code_rate_HP = FEC_NONE;
> +			pr_err("TPSInfo rateHP invalid %d\n",
> +			       tps.rate_hp);
> +			break;
> +		}
> +		switch (tps.rate_lp) {
> +		case CXD2880_DVBT_CODERATE_1_2:
> +			c->code_rate_LP = FEC_1_2;
> +			break;
> +		case CXD2880_DVBT_CODERATE_2_3:
> +			c->code_rate_LP = FEC_2_3;
> +			break;
> +		case CXD2880_DVBT_CODERATE_3_4:
> +			c->code_rate_LP = FEC_3_4;
> +			break;
> +		case CXD2880_DVBT_CODERATE_5_6:
> +			c->code_rate_LP = FEC_5_6;
> +			break;
> +		case CXD2880_DVBT_CODERATE_7_8:
> +			c->code_rate_LP = FEC_7_8;
> +			break;
> +		default:
> +			c->code_rate_LP = FEC_NONE;
> +			pr_err("TPSInfo rateLP invalid %d\n",
> +			       tps.rate_lp);
> +			break;
> +		}
> +		switch (tps.constellation) {
> +		case CXD2880_DVBT_CONSTELLATION_QPSK:
> +			c->modulation = QPSK;
> +			break;
> +		case CXD2880_DVBT_CONSTELLATION_16QAM:
> +			c->modulation = QAM_16;
> +			break;
> +		case CXD2880_DVBT_CONSTELLATION_64QAM:
> +			c->modulation = QAM_64;
> +			break;
> +		default:
> +			c->modulation = QPSK;
> +			pr_err("TPSInfo constellation invalid %d\n",
> +			       tps.constellation);
> +			break;
> +		}
> +	} else {
> +		c->hierarchy = HIERARCHY_NONE;
> +		c->code_rate_HP = FEC_NONE;
> +		c->code_rate_LP = FEC_NONE;
> +		c->modulation = QPSK;
> +		pr_debug("TPS info err %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (sense) {
> +		case CXD2880_TNRDMD_SPECTRUM_NORMAL:
> +			c->inversion = INVERSION_OFF;
> +			break;
> +		case CXD2880_TNRDMD_SPECTRUM_INV:
> +			c->inversion = INVERSION_ON;
> +			break;
> +		default:
> +			c->inversion = INVERSION_OFF;
> +			pr_err("spectrum sense invalid %d\n", sense);
> +			break;
> +		}
> +	} else {
> +		c->inversion = INVERSION_OFF;
> +		pr_debug("spectrum_sense %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		c->strength.len = 1;
> +		c->strength.stat[0].scale = FE_SCALE_DECIBEL;
> +		c->strength.stat[0].svalue = strength;
> +	} else {
> +		c->strength.len = 1;
> +		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		pr_debug("mon_rf_lvl %d\n", ret);
> +	}
> +
> +	ret = cxd2880_read_snr(fe, &snr);
> +	if (!ret) {
> +		c->cnr.len = 1;
> +		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
> +		c->cnr.stat[0].svalue = snr;
> +	} else {
> +		c->cnr.len = 1;
> +		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		pr_debug("read_snr %d\n", ret);
> +	}
> +
> +	return 0;
> +}
> +
> +static int cxd2880_get_frontend_t2(struct dvb_frontend *fe,
> +				   struct dtv_frontend_properties *c)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct cxd2880_dvbt2_l1pre l1pre;
> +	enum cxd2880_dvbt2_plp_code_rate coderate;
> +	enum cxd2880_dvbt2_plp_constell qam;
> +	enum cxd2880_tnrdmd_spectrum_sense sense;
> +	u16 snr = 0;
> +	int strength = 0;
> +
> +	if ((!fe) || (!c)) {
> +		pr_err("invalid arg.\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (l1pre.fft_mode) {
> +		case CXD2880_DVBT2_M2K:
> +			c->transmission_mode = TRANSMISSION_MODE_2K;
> +			break;
> +		case CXD2880_DVBT2_M8K:
> +			c->transmission_mode = TRANSMISSION_MODE_8K;
> +			break;
> +		case CXD2880_DVBT2_M4K:
> +			c->transmission_mode = TRANSMISSION_MODE_4K;
> +			break;
> +		case CXD2880_DVBT2_M1K:
> +			c->transmission_mode = TRANSMISSION_MODE_1K;
> +			break;
> +		case CXD2880_DVBT2_M16K:
> +			c->transmission_mode = TRANSMISSION_MODE_16K;
> +			break;
> +		case CXD2880_DVBT2_M32K:
> +			c->transmission_mode = TRANSMISSION_MODE_32K;
> +			break;
> +		default:
> +			c->transmission_mode = TRANSMISSION_MODE_2K;
> +			pr_err("L1Pre fft_mode invalid %d\n",
> +			       l1pre.fft_mode);
> +			break;
> +		}
> +		switch (l1pre.gi) {
> +		case CXD2880_DVBT2_G1_32:
> +			c->guard_interval = GUARD_INTERVAL_1_32;
> +			break;
> +		case CXD2880_DVBT2_G1_16:
> +			c->guard_interval = GUARD_INTERVAL_1_16;
> +			break;
> +		case CXD2880_DVBT2_G1_8:
> +			c->guard_interval = GUARD_INTERVAL_1_8;
> +			break;
> +		case CXD2880_DVBT2_G1_4:
> +			c->guard_interval = GUARD_INTERVAL_1_4;
> +			break;
> +		case CXD2880_DVBT2_G1_128:
> +			c->guard_interval = GUARD_INTERVAL_1_128;
> +			break;
> +		case CXD2880_DVBT2_G19_128:
> +			c->guard_interval = GUARD_INTERVAL_19_128;
> +			break;
> +		case CXD2880_DVBT2_G19_256:
> +			c->guard_interval = GUARD_INTERVAL_19_256;
> +			break;
> +		default:
> +			c->guard_interval = GUARD_INTERVAL_1_32;
> +			pr_err("L1Pre gi invalid %d\n", l1pre.gi);

Better to print it in full:
			pr_err("L1Pre guard interval is invalid %d\n", l1pre.gi);

Yet, I guess several of such messages should actually be pr_dbg(),
as, a normal user shouldn't normally see them. Anyway, debug levels
can be adjusted later, after the driver gets merged upstream.

> +			break;
> +		}
> +	} else {
> +		c->transmission_mode = TRANSMISSION_MODE_2K;
> +		c->guard_interval = GUARD_INTERVAL_1_32;
> +		pr_debug("L1Pre err %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(&priv->tnrdmd,
> +						 CXD2880_DVBT2_PLP_DATA,
> +						 &coderate);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (coderate) {
> +		case CXD2880_DVBT2_R1_2:
> +			c->fec_inner = FEC_1_2;
> +			break;
> +		case CXD2880_DVBT2_R3_5:
> +			c->fec_inner = FEC_3_5;
> +			break;
> +		case CXD2880_DVBT2_R2_3:
> +			c->fec_inner = FEC_2_3;
> +			break;
> +		case CXD2880_DVBT2_R3_4:
> +			c->fec_inner = FEC_3_4;
> +			break;
> +		case CXD2880_DVBT2_R4_5:
> +			c->fec_inner = FEC_4_5;
> +			break;
> +		case CXD2880_DVBT2_R5_6:
> +			c->fec_inner = FEC_5_6;
> +			break;
> +		default:
> +			c->fec_inner = FEC_NONE;
> +			pr_err("CodeRate invalid %d\n", coderate);
> +			break;
> +		}
> +	} else {
> +		c->fec_inner = FEC_NONE;
> +		pr_debug("CodeRate %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt2_mon_qam(&priv->tnrdmd,
> +					   CXD2880_DVBT2_PLP_DATA,
> +					   &qam);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (qam) {
> +		case CXD2880_DVBT2_QPSK:
> +			c->modulation = QPSK;
> +			break;
> +		case CXD2880_DVBT2_QAM16:
> +			c->modulation = QAM_16;
> +			break;
> +		case CXD2880_DVBT2_QAM64:
> +			c->modulation = QAM_64;
> +			break;
> +		case CXD2880_DVBT2_QAM256:
> +			c->modulation = QAM_256;
> +			break;
> +		default:
> +			c->modulation = QPSK;
> +			pr_err("QAM invalid %d\n", qam);
> +			break;
> +		}
> +	} else {
> +		c->modulation = QPSK;
> +		pr_debug("QAM %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (sense) {
> +		case CXD2880_TNRDMD_SPECTRUM_NORMAL:
> +			c->inversion = INVERSION_OFF;
> +			break;
> +		case CXD2880_TNRDMD_SPECTRUM_INV:
> +			c->inversion = INVERSION_ON;
> +			break;
> +		default:
> +			c->inversion = INVERSION_OFF;
> +			pr_err("spectrum sense invalid %d\n", sense);
> +			break;
> +		}
> +	} else {
> +		c->inversion = INVERSION_OFF;
> +		pr_debug("SpectrumSense %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		c->strength.len = 1;
> +		c->strength.stat[0].scale = FE_SCALE_DECIBEL;
> +		c->strength.stat[0].svalue = strength;
> +	} else {
> +		c->strength.len = 1;
> +		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		pr_debug("mon_rf_lvl %d\n", ret);
> +	}
> +
> +	ret = cxd2880_read_snr(fe, &snr);
> +	if (!ret) {
> +		c->cnr.len = 1;
> +		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
> +		c->cnr.stat[0].svalue = snr;
> +	} else {
> +		c->cnr.len = 1;
> +		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		pr_debug("read_snr %d\n", ret);
> +	}
> +
> +	return 0;
> +}
> +
> +static int cxd2880_get_frontend(struct dvb_frontend *fe,
> +				struct dtv_frontend_properties *props)
> +{
> +	struct cxd2880_priv *priv = NULL;
> +	int ret = 0;
> +
> +	if ((!fe) || (!props)) {
> +		pr_err("invalid arg.");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +
> +	pr_debug("system=%d\n", fe->dtv_property_cache.delivery_system);
> +	switch (fe->dtv_property_cache.delivery_system) {
> +	case SYS_DVBT:
> +		ret = cxd2880_get_frontend_t(fe, props);
> +		break;
> +	case SYS_DVBT2:
> +		ret = cxd2880_get_frontend_t2(fe, props);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe)
> +{
> +	return DVBFE_ALGO_HW;
> +}
> +
> +static struct dvb_frontend_ops cxd2880_dvbt_t2_ops;
> +
> +struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
> +				    struct cxd2880_config *cfg)
> +{
> +	int ret = 0;
> +	enum cxd2880_tnrdmd_chip_id chipid =
> +					CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
> +	static struct cxd2880_priv *priv;
> +	u8 data = 0;
> +
> +	if (!fe) {
> +		pr_err("invalid arg.\n");
> +		return NULL;
> +	}
> +
> +	priv = kzalloc(sizeof(struct cxd2880_priv), GFP_KERNEL);
> +	if (!priv)
> +		return NULL;
> +
> +	priv->spi = cfg->spi;
> +	priv->spi_mutex = cfg->spi_mutex;
> +	priv->spi_device.spi = cfg->spi;
> +
> +	memcpy(&fe->ops, &cxd2880_dvbt_t2_ops,
> +	       sizeof(struct dvb_frontend_ops));
> +
> +	ret = cxd2880_spi_device_initialize(&priv->spi_device,
> +					    CXD2880_SPI_MODE_0,
> +					    55000000);
> +	if (ret) {
> +		pr_err("spi_device_initialize failed. %d\n", ret);
> +		kfree(priv);
> +		return NULL;
> +	}
> +
> +	ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi,
> +					    &priv->spi_device);
> +	if (ret) {
> +		pr_err("spi_device_create_spi failed. %d\n", ret);
> +		kfree(priv);
> +		return NULL;
> +	}
> +
> +	ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0);
> +	if (ret) {
> +		pr_err("io_spi_create failed. %d\n", ret);
> +		kfree(priv);
> +		return NULL;
> +	}
> +	ret = priv->regio.write_reg(&priv->regio,
> +				    CXD2880_IO_TGT_SYS, 0x00, 0x00);
> +	if (ret) {
> +		pr_err("set bank to 0x00 failed.\n");
> +		kfree(priv);
> +		return NULL;
> +	}
> +	ret = priv->regio.read_regs(&priv->regio,
> +				    CXD2880_IO_TGT_SYS, 0xfd, &data, 1);
> +	if (ret) {
> +		pr_err("read chip id failed.\n");
> +		kfree(priv);
> +		return NULL;
> +	}
> +
> +	chipid = (enum cxd2880_tnrdmd_chip_id)data;
> +	if ((chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) &&
> +	    (chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11)) {
> +		pr_err("chip id invalid.\n");
> +		kfree(priv);
> +		return NULL;
> +	}
> +
> +	fe->demodulator_priv = priv;
> +	pr_info("CXD2880 driver version: Ver %s\n",
> +		CXD2880_TNRDMD_DRIVER_VERSION);
> +
> +	return fe;
> +}
> +EXPORT_SYMBOL(cxd2880_attach);
> +
> +static struct dvb_frontend_ops cxd2880_dvbt_t2_ops = {
> +	.info = {
> +		.name = "Sony CXD2880",
> +		.frequency_min =  174000000,
> +		.frequency_max = 862000000,
> +		.frequency_stepsize = 1000,
> +		.caps = FE_CAN_INVERSION_AUTO |
> +				FE_CAN_FEC_1_2 |
> +				FE_CAN_FEC_2_3 |
> +				FE_CAN_FEC_3_4 |
> +				FE_CAN_FEC_4_5 |
> +				FE_CAN_FEC_5_6	|
> +				FE_CAN_FEC_7_8	|
> +				FE_CAN_FEC_AUTO |
> +				FE_CAN_QPSK |
> +				FE_CAN_QAM_16 |
> +				FE_CAN_QAM_32 |
> +				FE_CAN_QAM_64 |
> +				FE_CAN_QAM_128 |
> +				FE_CAN_QAM_256 |
> +				FE_CAN_QAM_AUTO |
> +				FE_CAN_TRANSMISSION_MODE_AUTO |
> +				FE_CAN_GUARD_INTERVAL_AUTO |
> +				FE_CAN_2G_MODULATION |
> +				FE_CAN_RECOVER |
> +				FE_CAN_MUTE_TS,
> +	},
> +	.delsys = { SYS_DVBT, SYS_DVBT2 },
> +
> +	.release = cxd2880_release,
> +	.init = cxd2880_init,
> +	.sleep = cxd2880_sleep,
> +	.tune = cxd2880_tune,
> +	.set_frontend = cxd2880_set_frontend,
> +	.get_frontend = cxd2880_get_frontend,
> +	.read_status = cxd2880_read_status,
> +	.read_ber = cxd2880_read_ber,
> +	.read_signal_strength = cxd2880_read_signal_strength,
> +	.read_snr = cxd2880_read_snr,
> +	.read_ucblocks = cxd2880_read_ucblocks,
> +	.get_frontend_algo = cxd2880_get_frontend_algo,
> +};
> +
> +MODULE_DESCRIPTION(
> +"Sony CXD2880 DVB-T2/T tuner + demodulator drvier");
> +MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
> +MODULE_LICENSE("GPL v2");



Thanks,
Mauro

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 07/14] [media] cxd2880: Add top level of the driver
@ 2017-08-27 15:12     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 15:12 UTC (permalink / raw)
  To: Yasunari.Takiguchi-7U/KSKJipcs
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

Em Wed, 16 Aug 2017 13:39:45 +0900
<Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
> 
> This provides the main dvb frontend operation functions
> for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.
> 
> [Change list]
> Changes in V3
>    drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
>       -adjusted indent spaces
>       -modified debugging code
>       -removed unnecessary cast
>       -modified return code
>       -modified coding style of if() 
>       -modified about measurement period of PER/BER.
>       -changed hexadecimal code to lower case. 
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
> ---
>  drivers/media/dvb-frontends/cxd2880/cxd2880_top.c | 1879 +++++++++++++++++++++
>  1 file changed, 1879 insertions(+)
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
> 
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
> new file mode 100644
> index 000000000000..306966dd186b
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
> @@ -0,0 +1,1879 @@
> +/*
> + * cxd2880_top.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
> +
> +#include <linux/spi/spi.h>
> +
> +#include "dvb_frontend.h"
> +#include "dvb_math.h"
> +
> +#include "cxd2880.h"
> +#include "cxd2880_tnrdmd_mon.h"
> +#include "cxd2880_tnrdmd_dvbt2_mon.h"
> +#include "cxd2880_tnrdmd_dvbt_mon.h"
> +#include "cxd2880_integ_dvbt2.h"
> +#include "cxd2880_integ_dvbt.h"
> +#include "cxd2880_devio_spi.h"
> +#include "cxd2880_spi_device.h"
> +#include "cxd2880_tnrdmd_driver_version.h"
> +
> +struct cxd2880_priv {
> +	struct cxd2880_tnrdmd tnrdmd;
> +	struct spi_device *spi;
> +	struct cxd2880_io regio;
> +	struct cxd2880_spi_device spi_device;
> +	struct cxd2880_spi cxd2880_spi;
> +	struct cxd2880_dvbt_tune_param dvbt_tune_param;
> +	struct cxd2880_dvbt2_tune_param dvbt2_tune_param;
> +	struct mutex *spi_mutex; /* For SPI access exclusive control */
> +	unsigned long pre_ber_update;
> +	unsigned long pre_ber_interval;
> +	unsigned long post_ber_update;
> +	unsigned long post_ber_interval;
> +	unsigned long ucblock_update;
> +	unsigned long ucblock_interval;
> +};
> +
> +static int cxd2880_pre_bit_err_t(
> +		struct cxd2880_tnrdmd *tnrdmd, u32 *pre_bit_err,
> +		u32 *pre_bit_count)
> +{
> +	u8 rdata[2];
> +	int ret = 0;
> +
> +	if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count))
> +		return -EINVAL;
> +
> +	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnrdmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x10);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x39, rdata, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	if ((rdata[0] & 0x01) == 0) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return -EBUSY;
> +	}
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x22, rdata, 2);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	*pre_bit_err = (rdata[0] << 8) | rdata[1];
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x6f, rdata, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnrdmd);
> +
> +	*pre_bit_count = ((rdata[0] & 0x07) == 0) ?
> +			 256 : (0x1000 << (rdata[0] & 0x07));
> +
> +	return 0;
> +}
> +
> +static int cxd2880_pre_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
> +				  u32 *pre_bit_err,
> +				  u32 *pre_bit_count)
> +{
> +	u32 period_exp = 0;
> +	u32 n_ldpc = 0;
> +	u8 data[5];
> +	int ret = 0;
> +
> +	if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count))
> +		return -EINVAL;
> +
> +	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnrdmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x0b);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x3c, data, sizeof(data));
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	if (!(data[0] & 0x01)) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return -EBUSY;
> +	}
> +	*pre_bit_err =
> +	((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0xa0, data, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnrdmd);
> +		return ret;
> +	}
> +
> +	if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) ==
> +	    CXD2880_DVBT2_FEC_LDPC_16K)
> +		n_ldpc = 16200;
> +	else
> +		n_ldpc = 64800;
> +	slvt_unfreeze_reg(tnrdmd);
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x20);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x6f, data, 1);
> +	if (ret)
> +		return ret;
> +
> +	period_exp = data[0] & 0x0f;
> +
> +	*pre_bit_count = (1U << period_exp) * n_ldpc;
> +
> +	return 0;
> +}
> +
> +static int cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd,
> +				  u32 *post_bit_err,
> +				  u32 *post_bit_count)
> +{
> +	u8 rdata[3];
> +	u32 bit_error = 0;
> +	u32 period_exp = 0;
> +	int ret = 0;
> +
> +	if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count))
> +		return -EINVAL;
> +
> +	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x0d);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x15, rdata, 3);
> +	if (ret)
> +		return ret;
> +
> +	if ((rdata[0] & 0x40) == 0)
> +		return -EBUSY;
> +
> +	*post_bit_err = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2];
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x60, rdata, 1);
> +	if (ret)
> +		return ret;
> +
> +	period_exp = (rdata[0] & 0x1f);
> +
> +	if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8))
> +		return -EBUSY;
> +
> +	if (period_exp == 11)
> +		*post_bit_count = 3342336;
> +	else
> +		*post_bit_count = (1U << period_exp) * 204 * 81;
> +
> +	return 0;
> +}
> +
> +static int cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd,
> +				   u32 *post_bit_err,
> +				   u32 *post_bit_count)
> +{
> +	u32 period_exp = 0;
> +	u32 n_bch = 0;
> +
> +	if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count))
> +		return -EINVAL;
> +
> +	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[3];
> +		enum cxd2880_dvbt2_plp_fec plp_fec_type =
> +			CXD2880_DVBT2_FEC_LDPC_16K;
> +		enum cxd2880_dvbt2_plp_code_rate plp_code_rate =
> +			CXD2880_DVBT2_R1_2;
> +
> +		static const u16 n_bch_bits_lookup[2][8] = {
> +			{7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480},
> +			{32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920}
> +		};
> +		int ret = 0;

Same as pointed on patch 5: don't use a code block, except if you
need (e. g. on if, else, switch, do, etc).

Instead, move static const structs out of the function and put
the remaining data at the beginning of the function.

Also, ret doesn't need to be initialized, as it will already
be initialized before usage.

> +
> +		ret = slvt_freeze_reg(tnrdmd);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnrdmd->io->write_reg(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnrdmd);
> +			return ret;
> +		}
> +
> +		ret = tnrdmd->io->read_regs(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x15, data, 3);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnrdmd);
> +			return ret;
> +		}
> +
> +		if (!(data[0] & 0x40)) {
> +			slvt_unfreeze_reg(tnrdmd);
> +			return -EBUSY;
> +		}
> +
> +		*post_bit_err =
> +			((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2];
> +
> +		ret = tnrdmd->io->read_regs(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x9d, data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnrdmd);
> +			return ret;
> +		}
> +
> +		plp_code_rate =
> +		(enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07);
> +
> +		ret = tnrdmd->io->read_regs(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0xa0, data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnrdmd);
> +			return ret;
> +		}
> +
> +		plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03);
> +
> +		slvt_unfreeze_reg(tnrdmd);
> +
> +		ret = tnrdmd->io->write_reg(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x00, 0x20);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnrdmd->io->read_regs(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x72, data, 1);
> +		if (ret)
> +			return ret;
> +
> +		period_exp = data[0] & 0x0f;
> +
> +		if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) ||
> +		    (plp_code_rate > CXD2880_DVBT2_R2_5))
> +			return -EBUSY;
> +
> +		n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate];
> +	}
> +
> +	if (*post_bit_err > ((1U << period_exp) * n_bch))
> +		return -EBUSY;
> +
> +	*post_bit_count = (1U << period_exp) * n_bch;
> +
> +	return 0;
> +}
> +
> +static int cxd2880_read_block_err_t(struct cxd2880_tnrdmd *tnrdmd,
> +				    u32 *block_err,
> +				    u32 *block_count)
> +{
> +	u8 rdata[3];
> +	int ret = 0;
> +
> +	if ((!tnrdmd) || (!block_err) || (!block_count))
> +		return -EINVAL;
> +
> +	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x0d);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x18, rdata, 3);
> +	if (ret)
> +		return ret;
> +
> +	if ((rdata[0] & 0x01) == 0)
> +		return -EBUSY;
> +
> +	*block_err = (rdata[1] << 8) | rdata[2];
> +
> +	ret = tnrdmd->io->write_reg(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnrdmd->io->read_regs(tnrdmd->io,
> +				    CXD2880_IO_TGT_DMD,
> +				    0x5c, rdata, 1);
> +	if (ret)
> +		return ret;
> +
> +	*block_count = 1U << (rdata[0] & 0x0f);
> +
> +	if ((*block_count == 0) || (*block_err > *block_count))
> +		return -EBUSY;
> +
> +	return 0;
> +}
> +
> +static int cxd2880_read_block_err_t2(struct cxd2880_tnrdmd *tnrdmd,
> +				     u32 *block_err,
> +				     u32 *block_count)
> +{
> +	if ((!tnrdmd) || (!block_err) || (!block_count))
> +		return -EINVAL;
> +
> +	if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +	if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 rdata[3];
> +		int ret = 0;

Same here. Same comment applies to other similar coding.
> +
> +		ret = tnrdmd->io->write_reg(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x00, 0x0b);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnrdmd->io->read_regs(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x18, rdata, 3);
> +		if (ret)
> +			return ret;
> +
> +		if ((rdata[0] & 0x01) == 0)
> +			return -EBUSY;
> +
> +		*block_err = (rdata[1] << 8) | rdata[2];
> +
> +		ret = tnrdmd->io->write_reg(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x00, 0x24);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnrdmd->io->read_regs(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0xdc, rdata, 1);
> +		if (ret)
> +			return ret;
> +
> +		*block_count = 1U << (rdata[0] & 0x0f);
> +	}
> +
> +	if ((*block_count == 0) || (*block_err > *block_count))
> +		return -EBUSY;
> +
> +	return 0;
> +}
> +
> +static void cxd2880_release(struct dvb_frontend *fe)
> +{
> +	struct cxd2880_priv *priv = NULL;
> +
> +	if (!fe) {
> +		pr_err("invalid arg.\n");
> +		return;
> +	}
> +	priv = fe->demodulator_priv;
> +	kfree(priv);
> +}
> +
> +static int cxd2880_init(struct dvb_frontend *fe)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct cxd2880_tnrdmd_create_param create_param;
> +
> +	if (!fe) {
> +		pr_err("invalid arg.\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +
> +	create_param.ts_output_if = CXD2880_TNRDMD_TSOUT_IF_SPI;
> +	create_param.xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_NONE;
> +	create_param.en_internal_ldo = 1;
> +	create_param.xosc_cap = 18;
> +	create_param.xosc_i = 8;
> +	create_param.stationary_use = 1;
> +
> +	mutex_lock(priv->spi_mutex);
> +	if (priv->tnrdmd.io != &priv->regio) {
> +		ret = cxd2880_tnrdmd_create(&priv->tnrdmd,
> +					    &priv->regio, &create_param);
> +		if (ret) {
> +			mutex_unlock(priv->spi_mutex);
> +			pr_info("cxd2880 tnrdmd create failed %d\n", ret);
> +			return ret;
> +		}
> +	}
> +	ret = cxd2880_integ_init(&priv->tnrdmd);
> +	if (ret) {
> +		mutex_unlock(priv->spi_mutex);
> +		pr_err("cxd2880 integ init failed %d\n", ret);
> +		return ret;
> +	}
> +	mutex_unlock(priv->spi_mutex);
> +
> +	pr_debug("OK.\n");
> +
> +	return ret;
> +}
> +
> +static int cxd2880_sleep(struct dvb_frontend *fe)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +
> +	if (!fe) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd);
> +	mutex_unlock(priv->spi_mutex);
> +
> +	pr_debug("tnrdmd_sleep ret %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int cxd2880_read_signal_strength(struct dvb_frontend *fe,
> +					u16 *strength)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct dtv_frontend_properties *c = NULL;
> +	int level = 0;
> +
> +	if ((!fe) || (!strength)) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +
> +	mutex_lock(priv->spi_mutex);
> +	if ((c->delivery_system == SYS_DVBT) ||
> +	    (c->delivery_system == SYS_DVBT2)) {
> +		ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &level);
> +	} else {
> +		pr_debug("invalid system\n");
> +		mutex_unlock(priv->spi_mutex);
> +		return -EINVAL;
> +	}
> +	mutex_unlock(priv->spi_mutex);
> +
> +	level /= 125;
> +	/* -105dBm - -30dBm (-105000/125 = -840, -30000/125 = -240 */

It took me a while to understand what you meant here. I guess you
meant to say:

	/*
	 * Level should be between -105dBm and -30dBm.
	 * E. g. they should be between:
	 *	-105000/125 = -840 and -30000/125 = -240
	 */

(better to be a little clearer here, with something like the above
comment)


> +	level = clamp(level, -840, -240);
> +	/* scale value to 0x0000-0xffff */
> +	*strength = (u16)(((level + 840) * 0xffff) / (-240 + 840));
> +
> +	if (ret)
> +		pr_debug("ret = %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr)
> +{
> +	int ret = 0;
> +	int snrvalue = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct dtv_frontend_properties *c = NULL;
> +
> +	if ((!fe) || (!snr)) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +
> +	mutex_lock(priv->spi_mutex);
> +	if (c->delivery_system == SYS_DVBT) {
> +		ret = cxd2880_tnrdmd_dvbt_mon_snr(&priv->tnrdmd,
> +						  &snrvalue);
> +	} else if (c->delivery_system == SYS_DVBT2) {
> +		ret = cxd2880_tnrdmd_dvbt2_mon_snr(&priv->tnrdmd,
> +						   &snrvalue);
> +	} else {
> +		pr_err("invalid system\n");
> +		mutex_unlock(priv->spi_mutex);
> +		return -EINVAL;
> +	}
> +	mutex_unlock(priv->spi_mutex);
> +
> +	if (snrvalue < 0)
> +		snrvalue = 0;
> +	*snr = (u16)snrvalue;
> +
> +	if (ret)
> +		pr_debug("ret = %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct dtv_frontend_properties *c = NULL;
> +
> +	if ((!fe) || (!ucblocks)) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +
> +	mutex_lock(priv->spi_mutex);
> +	if (c->delivery_system == SYS_DVBT) {
> +		ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number(
> +								&priv->tnrdmd,
> +								ucblocks);
> +	} else if (c->delivery_system == SYS_DVBT2) {
> +		ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number(
> +								&priv->tnrdmd,
> +								ucblocks);
> +	} else {
> +		pr_err("invlaid system\n");

typo: invalid

> +		mutex_unlock(priv->spi_mutex);
> +		return -EINVAL;
> +	}
> +	mutex_unlock(priv->spi_mutex);
> +
> +	if (ret)
> +		pr_debug("ret = %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct dtv_frontend_properties *c = NULL;
> +
> +	if ((!fe) || (!ber)) {
> +		pr_err("inavlid arg\n");

Same typo here:
	inavlid -> invalid

> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +
> +	mutex_lock(priv->spi_mutex);
> +	if (c->delivery_system == SYS_DVBT) {
> +		ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(&priv->tnrdmd,
> +							ber);
> +		/* x100 to change unit.(10^7 -> 10^9 */

Missing ')'

> +		*ber *= 100;
> +	} else if (c->delivery_system == SYS_DVBT2) {
> +		ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(&priv->tnrdmd,
> +							  ber);
> +	} else {
> +		pr_err("invlaid system\n");

Same typo here... better to check the entire code. It seems that it
was copied and pasted on several places :-)

> +		mutex_unlock(priv->spi_mutex);
> +		return -EINVAL;
> +	}
> +	mutex_unlock(priv->spi_mutex);
> +
> +	if (ret)
> +		pr_debug("ret = %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe)
> +{
> +	int ret = 0;
> +	struct dtv_frontend_properties *c;
> +	struct cxd2880_priv *priv;
> +	int cr_table[5] = {31500, 42000, 47250, 52500, 55125};
> +	int denominator_tbl[4] = {125664, 129472, 137088, 152320};

Are both tables static const? If so, declare as such, as it
decreases the Kernel runtime size.

> +	struct cxd2880_dvbt_tpsinfo info;
> +	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
> +	u32 pre_ber_rate = 0;
> +	u32 post_ber_rate = 0;
> +	u32 ucblock_rate = 0;
> +	u32 mes_exp = 0;
> +
> +	if (!fe) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +	bw = priv->dvbt_tune_param.bandwidth;
> +
> +	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd,
> +					       &info);
> +	if (ret) {
> +		pr_err("tps monitor error ret = %d\n", ret);
> +		info.hierarchy = CXD2880_DVBT_HIERARCHY_NON;
> +		info.constellation = CXD2880_DVBT_CONSTELLATION_QPSK;
> +		info.guard = CXD2880_DVBT_GUARD_1_4;
> +		info.rate_hp = CXD2880_DVBT_CODERATE_1_2;
> +		info.rate_lp = CXD2880_DVBT_CODERATE_1_2;
> +	}
> +
> +	if (info.hierarchy == CXD2880_DVBT_HIERARCHY_NON) {
> +		pre_ber_rate = 63000000 * bw * (info.constellation * 2 + 2) /
> +			       denominator_tbl[info.guard];
> +
> +		post_ber_rate =	1000 * cr_table[info.rate_hp] * bw *
> +				(info.constellation * 2 + 2) /
> +				denominator_tbl[info.guard];
> +
> +		ucblock_rate = 875 * cr_table[info.rate_hp] * bw *
> +			       (info.constellation * 2 + 2) /
> +			       denominator_tbl[info.guard];
> +	} else {
> +		u8 data = 0;
> +		struct cxd2880_tnrdmd *tnrdmd = &priv->tnrdmd;
> +
> +		ret = tnrdmd->io->write_reg(tnrdmd->io,
> +					    CXD2880_IO_TGT_DMD,
> +					    0x00, 0x10);
> +		if (!ret) {
> +			ret = tnrdmd->io->read_regs(tnrdmd->io,
> +						    CXD2880_IO_TGT_DMD,
> +						    0x67, &data, 1);
> +			if (ret)
> +				data = 0x00;
> +		} else {
> +			data = 0x00;
> +		}
> +
> +		if (data & 0x01) { /* Low priority */
> +			pre_ber_rate =
> +				63000000 * bw * (info.constellation * 2 + 2) /
> +				denominator_tbl[info.guard];
> +
> +			post_ber_rate = 1000 * cr_table[info.rate_lp] * bw *
> +					(info.constellation * 2 + 2) /
> +					denominator_tbl[info.guard];
> +
> +			ucblock_rate = (1000 * 7 / 8) *	cr_table[info.rate_lp] *
> +				       bw * (info.constellation * 2 + 2) /
> +				       denominator_tbl[info.guard];
> +		} else { /* High priority */
> +			pre_ber_rate =
> +				63000000 * bw * 2 / denominator_tbl[info.guard];
> +
> +			post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * 2 /
> +					denominator_tbl[info.guard];
> +
> +			ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_hp] *
> +					bw * 2 / denominator_tbl[info.guard];
> +		}
> +	}
> +
> +	mes_exp = pre_ber_rate < 8192 ? 8 : intlog2(pre_ber_rate) >> 24;
> +	priv->pre_ber_interval =
> +		((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) /
> +		pre_ber_rate;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD,
> +			       mes_exp == 8 ? 0 : mes_exp - 12);
> +
> +	mes_exp = intlog2(post_ber_rate) >> 24;
> +	priv->post_ber_interval =
> +		((1U << mes_exp) * 1000 + (post_ber_rate / 2)) /
> +		post_ber_rate;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD,
> +			       mes_exp);
> +
> +	mes_exp = intlog2(ucblock_rate) >> 24;
> +	priv->ucblock_interval =
> +		((1U << mes_exp) * 1000 + (ucblock_rate / 2)) /
> +		ucblock_rate;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT_PER_MES,
> +			       mes_exp);
> +
> +	return 0;
> +}
> +
> +static int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe)
> +{
> +	int ret = 0;
> +	struct dtv_frontend_properties *c;
> +	struct cxd2880_priv *priv;
> +	struct cxd2880_dvbt2_l1pre l1pre;
> +	struct cxd2880_dvbt2_l1post l1post;
> +	struct cxd2880_dvbt2_plp plp;
> +	struct cxd2880_dvbt2_bbheader bbheader;
> +	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
> +	u32 pre_ber_rate = 0;
> +	u32 post_ber_rate = 0;
> +	u32 ucblock_rate = 0;
> +	u32 mes_exp = 0;
> +	u32 term_a = 0;
> +	u32 term_b = 0;
> +	u32 gi_tbl[7] = {32, 64, 128, 256, 8, 152, 76};
> +	u8  n_tbl[6] = {8, 2, 4, 16, 1, 1};
> +	u8  mode_tbl[6] = {2, 8, 4, 1, 16, 32};
> +	u32 kbch_tbl[2][8] = {
> +			{6952, 9472, 10552, 11632, 12352, 13072, 5152, 6232},
> +			{32128, 38608, 42960, 48328, 51568, 53760, 0, 0} };
> +	u32 denominator = 0;
> +
> +	if (!fe) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +	bw = priv->dvbt2_tune_param.bandwidth;
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
> +	if (ret) {
> +		pr_info("l1 pre error\n");
> +		goto error_ber_setting;
> +	}
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_active_plp(&priv->tnrdmd,
> +						  CXD2880_DVBT2_PLP_DATA, &plp);
> +	if (ret) {
> +		pr_info("plp info error\n");
> +		goto error_ber_setting;
> +	}
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_l1_post(&priv->tnrdmd, &l1post);
> +	if (ret) {
> +		pr_info("l1 post error\n");
> +		goto error_ber_setting;
> +	}
> +
> +	term_a =
> +		(mode_tbl[l1pre.fft_mode] * (1024 + gi_tbl[l1pre.gi])) *
> +		(l1pre.num_symbols + n_tbl[l1pre.fft_mode]) + 2048;
> +
> +	if (l1pre.mixed && l1post.fef_intvl) {
> +		term_b = (l1post.fef_length + (l1post.fef_intvl / 2)) /
> +			 l1post.fef_intvl;
> +	} else {
> +		term_b = 0;
> +	}
> +
> +	switch (bw) {
> +	case CXD2880_DTV_BW_1_7_MHZ:
> +		denominator = ((term_a + term_b) * 71 + (131 / 2)) / 131;
> +		break;
> +	case CXD2880_DTV_BW_5_MHZ:
> +		denominator = ((term_a + term_b) * 7 + 20) / 40;
> +		break;
> +	case CXD2880_DTV_BW_6_MHZ:
> +		denominator = ((term_a + term_b) * 7 + 24) / 48;
> +		break;
> +	case CXD2880_DTV_BW_7_MHZ:
> +		denominator = ((term_a + term_b) + 4) / 8;
> +		break;
> +	case CXD2880_DTV_BW_8_MHZ:
> +	default:
> +		denominator = ((term_a + term_b) * 7 + 32) / 64;
> +		break;
> +	}
> +
> +	if (plp.til_type && plp.til_len) {
> +		pre_ber_rate =
> +			(plp.num_blocks_max * 1000000 + (denominator / 2)) /
> +			denominator;
> +		pre_ber_rate = (pre_ber_rate + (plp.til_len / 2)) /
> +			       plp.til_len;
> +	} else {
> +		pre_ber_rate =
> +			(plp.num_blocks_max * 1000000 + (denominator / 2)) /
> +			denominator;
> +	}
> +
> +	post_ber_rate = pre_ber_rate;
> +
> +	mes_exp = intlog2(pre_ber_rate) >> 24;
> +	priv->pre_ber_interval =
> +		((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) /
> +		pre_ber_rate;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT2_LBER_MES,
> +			       mes_exp);
> +
> +	mes_exp = intlog2(post_ber_rate) >> 24;
> +	priv->post_ber_interval =
> +		((1U << mes_exp) * 1000 + (post_ber_rate / 2)) /
> +		post_ber_rate;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT2_BBER_MES,
> +			       mes_exp);
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_bbheader(&priv->tnrdmd,
> +						CXD2880_DVBT2_PLP_DATA,
> +						&bbheader);
> +	if (ret) {
> +		pr_info("bb header error\n");
> +		goto error_ucblock_setting;
> +	}
> +
> +	if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
> +		if (!bbheader.issy_indicator) {
> +			ucblock_rate =
> +				(pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] +
> +				752) / 1504;
> +		} else {
> +			ucblock_rate =
> +				(pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] +
> +				764) / 1528;
> +		}
> +	} else if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_HEM) {
> +		ucblock_rate =
> +			(pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 748) /
> +			1496;
> +	} else {
> +		pr_info("plp mode is not Normal or HEM\n");
> +		goto error_ucblock_setting;
> +	}
> +
> +	mes_exp = intlog2(ucblock_rate) >> 24;
> +	priv->ucblock_interval =
> +		((1U << mes_exp) * 1000 + (ucblock_rate / 2)) /
> +		ucblock_rate;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT2_PER_MES,
> +			       mes_exp);
> +
> +	return 0;
> +
> +error_ber_setting:
> +	priv->pre_ber_interval = 1000;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +				     CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, 0);
> +
> +	priv->post_ber_interval = 1000;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, 0);
> +
> +error_ucblock_setting:
> +	priv->ucblock_interval = 1000;
> +	cxd2880_tnrdmd_set_cfg(&priv->tnrdmd,
> +			       CXD2880_TNRDMD_CFG_DVBT2_PER_MES, 8);
> +
> +	return 0;
> +}
> +
> +static int cxd2880_set_frontend(struct dvb_frontend *fe)
> +{
> +	int ret = 0;
> +	int ret_val = 0;
> +	struct dtv_frontend_properties *c;
> +	struct cxd2880_priv *priv;
> +	enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ;
> +
> +	if (!fe) {
> +		pr_err("inavlid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +
> +	c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +	c->pre_bit_error.stat[0].uvalue = 0;
> +	c->pre_bit_error.len = 1;
> +	c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +	c->pre_bit_count.stat[0].uvalue = 0;
> +	c->pre_bit_count.len = 1;
> +	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +	c->post_bit_error.stat[0].uvalue = 0;
> +	c->post_bit_error.len = 1;
> +	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +	c->post_bit_count.stat[0].uvalue = 0;
> +	c->post_bit_count.len = 1;
> +	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +	c->block_error.stat[0].uvalue = 0;
> +	c->block_error.len = 1;
> +	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +	c->block_count.stat[0].uvalue = 0;
> +	c->block_count.len = 1;
> +
> +	switch (c->bandwidth_hz) {
> +	case 1712000:
> +		bw = CXD2880_DTV_BW_1_7_MHZ;
> +		break;
> +	case 5000000:
> +		bw = CXD2880_DTV_BW_5_MHZ;
> +		break;
> +	case 6000000:
> +		bw = CXD2880_DTV_BW_6_MHZ;
> +		break;
> +	case 7000000:
> +		bw = CXD2880_DTV_BW_7_MHZ;
> +		break;
> +	case 8000000:
> +		bw = CXD2880_DTV_BW_8_MHZ;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	pr_info("sys:%d freq:%d bw:%d\n",
> +		c->delivery_system, c->frequency, bw);
> +	mutex_lock(priv->spi_mutex);
> +	if (c->delivery_system == SYS_DVBT) {
> +		priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT;
> +		priv->dvbt_tune_param.center_freq_khz = c->frequency / 1000;
> +		priv->dvbt_tune_param.bandwidth = bw;
> +		priv->dvbt_tune_param.profile = CXD2880_DVBT_PROFILE_HP;
> +		ret = cxd2880_integ_dvbt_tune(&priv->tnrdmd,
> +					      &priv->dvbt_tune_param);
> +		ret_val = cxd2880_set_ber_per_period_t(fe);
> +	} else if (c->delivery_system == SYS_DVBT2) {
> +		priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT2;
> +		priv->dvbt2_tune_param.center_freq_khz = c->frequency / 1000;
> +		priv->dvbt2_tune_param.bandwidth = bw;
> +		priv->dvbt2_tune_param.data_plp_id = (u16)c->stream_id;
> +		priv->dvbt2_tune_param.profile = CXD2880_DVBT2_PROFILE_BASE;
> +		ret = cxd2880_integ_dvbt2_tune(&priv->tnrdmd,
> +					       &priv->dvbt2_tune_param);
> +		ret_val = cxd2880_set_ber_per_period_t2(fe);
> +	} else {
> +		pr_err("invalid system\n");
> +		mutex_unlock(priv->spi_mutex);
> +		return -EINVAL;
> +	}
> +	mutex_unlock(priv->spi_mutex);
> +
> +	pr_info("tune result %d set ber/per result %d\n", ret, ret_val);
> +
> +	return ret;
> +}
> +
> +static int cxd2880_get_stats(struct dvb_frontend *fe,
> +			     enum fe_status status)
> +{
> +	struct cxd2880_priv *priv = NULL;
> +	struct dtv_frontend_properties *c = NULL;
> +	u32 pre_bit_err = 0, pre_bit_count = 0;
> +	u32 post_bit_err = 0, post_bit_count = 0;
> +	u32 block_err = 0, block_count = 0;
> +	int ret = 0;
> +
> +	if (!fe) {
> +		pr_err("invalid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +
> +	if (!(status & FE_HAS_LOCK)) {
> +		c->pre_bit_error.len = 1;
> +		c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		c->pre_bit_count.len = 1;
> +		c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		c->post_bit_error.len = 1;
> +		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		c->post_bit_count.len = 1;
> +		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		c->block_error.len = 1;
> +		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		c->block_count.len = 1;
> +		c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +
> +		return 0;
> +	}
> +
> +	if (time_after(jiffies, priv->pre_ber_update)) {
> +		priv->pre_ber_update =
> +			 jiffies + msecs_to_jiffies(priv->pre_ber_interval);
> +		if (c->delivery_system == SYS_DVBT) {
> +			mutex_lock(priv->spi_mutex);
> +			ret = cxd2880_pre_bit_err_t(&priv->tnrdmd,
> +						    &pre_bit_err,
> +						    &pre_bit_count);
> +			mutex_unlock(priv->spi_mutex);
> +		} else if (c->delivery_system == SYS_DVBT2) {
> +			mutex_lock(priv->spi_mutex);
> +			ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd,
> +						     &pre_bit_err,
> +						     &pre_bit_count);
> +			mutex_unlock(priv->spi_mutex);
> +		} else {
> +			return -EINVAL;
> +		}
> +
> +		if (!ret) {
> +			c->pre_bit_error.len = 1;
> +			c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
> +			c->pre_bit_error.stat[0].uvalue += pre_bit_err;
> +			c->pre_bit_count.len = 1;
> +			c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
> +			c->pre_bit_count.stat[0].uvalue += pre_bit_count;
> +		} else {
> +			c->pre_bit_error.len = 1;
> +			c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +			c->pre_bit_count.len = 1;
> +			c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +			pr_debug("pre_bit_error_t failed %d\n", ret);
> +		}
> +	}
> +
> +	if (time_after(jiffies, priv->post_ber_update)) {
> +		priv->post_ber_update =
> +			jiffies + msecs_to_jiffies(priv->post_ber_interval);
> +		if (c->delivery_system == SYS_DVBT) {
> +			mutex_lock(priv->spi_mutex);
> +			ret = cxd2880_post_bit_err_t(&priv->tnrdmd,
> +						     &post_bit_err,
> +						     &post_bit_count);
> +			mutex_unlock(priv->spi_mutex);
> +		} else if (c->delivery_system == SYS_DVBT2) {
> +			mutex_lock(priv->spi_mutex);
> +			ret = cxd2880_post_bit_err_t2(&priv->tnrdmd,
> +						      &post_bit_err,
> +						      &post_bit_count);
> +			mutex_unlock(priv->spi_mutex);
> +		} else {
> +			pr_err();
> +			return -EINVAL;
> +		}
> +
> +		if (!ret) {
> +			c->post_bit_error.len = 1;
> +			c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
> +			c->post_bit_error.stat[0].uvalue += post_bit_err;
> +			c->post_bit_count.len = 1;
> +			c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
> +			c->post_bit_count.stat[0].uvalue += post_bit_count;
> +		} else {
> +			c->post_bit_error.len = 1;
> +			c->post_bit_error.stat[0].scale =
> +							FE_SCALE_NOT_AVAILABLE;
> +			c->post_bit_count.len = 1;
> +			c->post_bit_count.stat[0].scale =
> +							FE_SCALE_NOT_AVAILABLE;
> +			pr_debug("post_bit_err_t %d\n", ret);
> +		}
> +	}
> +
> +	if (time_after(jiffies, priv->ucblock_update)) {
> +		priv->ucblock_update =
> +			jiffies + msecs_to_jiffies(priv->ucblock_interval);
> +		if (c->delivery_system == SYS_DVBT) {
> +			mutex_lock(priv->spi_mutex);
> +			ret = cxd2880_read_block_err_t(&priv->tnrdmd,
> +						       &block_err,
> +						       &block_count);
> +			mutex_unlock(priv->spi_mutex);
> +		} else if (c->delivery_system == SYS_DVBT2) {
> +			mutex_lock(priv->spi_mutex);
> +			ret = cxd2880_read_block_err_t2(&priv->tnrdmd,
> +							&block_err,
> +							&block_count);
> +			mutex_unlock(priv->spi_mutex);
> +		} else {
> +			pr_err();
> +			return -EINVAL;
> +		}
> +		if (!ret) {
> +			c->block_error.len = 1;
> +			c->block_error.stat[0].scale = FE_SCALE_COUNTER;
> +			c->block_error.stat[0].uvalue += block_err;
> +			c->block_count.len = 1;
> +			c->block_count.stat[0].scale = FE_SCALE_COUNTER;
> +			c->block_count.stat[0].uvalue += block_count;
> +		} else {
> +			c->block_error.len = 1;
> +			c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +			c->block_count.len = 1;
> +			c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +			pr_debug("read_block_err_t  %d\n", ret);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int cxd2880_read_status(struct dvb_frontend *fe,
> +			       enum fe_status *status)
> +{
> +	int ret = 0;
> +	u8 sync = 0;
> +	u8 lock = 0;
> +	u8 unlock = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct dtv_frontend_properties *c = NULL;
> +
> +	if ((!fe) || (!status)) {
> +		pr_err("invalid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +	c = &fe->dtv_property_cache;
> +	*status = 0;
> +
> +	if (priv->tnrdmd.state == CXD2880_TNRDMD_STATE_ACTIVE) {
> +		mutex_lock(priv->spi_mutex);
> +		if (c->delivery_system == SYS_DVBT) {
> +			ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(
> +							&priv->tnrdmd,
> +							&sync,
> +							&lock,
> +							&unlock);
> +		} else if (c->delivery_system == SYS_DVBT2) {
> +			ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(
> +							&priv->tnrdmd,
> +							&sync,
> +							&lock,
> +							&unlock);
> +		} else {
> +			pr_err("invlaid system");
> +			mutex_unlock(priv->spi_mutex);
> +			return -EINVAL;
> +		}
> +
> +		mutex_unlock(priv->spi_mutex);
> +		if (ret) {
> +			pr_err("failed. sys = %d\n", priv->tnrdmd.sys);
> +			return  ret;
> +		}
> +
> +		if (sync == 6) {
> +			*status = FE_HAS_SIGNAL |
> +				  FE_HAS_CARRIER;
> +		}
> +		if (lock)
> +			*status |= FE_HAS_VITERBI |
> +				   FE_HAS_SYNC |
> +				   FE_HAS_LOCK;
> +	}
> +
> +	pr_debug("status %d result %d\n", *status, ret);
> +
> +	cxd2880_get_stats(fe, *status);
> +	return  0;
> +}
> +
> +static int cxd2880_tune(struct dvb_frontend *fe,
> +			bool retune,
> +			unsigned int mode_flags,
> +			unsigned int *delay,
> +			enum fe_status *status)
> +{
> +	int ret = 0;
> +
> +	if ((!fe) || (!delay) || (!status)) {
> +		pr_err("invalid arg.");
> +		return -EINVAL;
> +	}
> +
> +	if (retune) {
> +		ret = cxd2880_set_frontend(fe);
> +		if (ret) {
> +			pr_err("cxd2880_set_frontend failed %d\n", ret);
> +			return ret;
> +		}
> +	}
> +
> +	*delay = HZ / 5;
> +
> +	return cxd2880_read_status(fe, status);
> +}
> +
> +static int cxd2880_get_frontend_t(struct dvb_frontend *fe,
> +				  struct dtv_frontend_properties *c)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	enum cxd2880_dvbt_mode mode = CXD2880_DVBT_MODE_2K;
> +	enum cxd2880_dvbt_guard guard = CXD2880_DVBT_GUARD_1_32;
> +	struct cxd2880_dvbt_tpsinfo tps;
> +	enum cxd2880_tnrdmd_spectrum_sense sense;
> +	u16 snr = 0;
> +	int strength = 0;
> +
> +	if ((!fe) || (!c)) {
> +		pr_err("invalid arg\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt_mon_mode_guard(&priv->tnrdmd,
> +						 &mode, &guard);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (mode) {
> +		case CXD2880_DVBT_MODE_2K:
> +			c->transmission_mode = TRANSMISSION_MODE_2K;
> +			break;
> +		case CXD2880_DVBT_MODE_8K:
> +			c->transmission_mode = TRANSMISSION_MODE_8K;
> +			break;
> +		default:
> +			c->transmission_mode = TRANSMISSION_MODE_2K;
> +			pr_err("get invalid mode %d\n", mode);
> +			break;
> +		}
> +		switch (guard) {
> +		case CXD2880_DVBT_GUARD_1_32:
> +			c->guard_interval = GUARD_INTERVAL_1_32;
> +			break;
> +		case CXD2880_DVBT_GUARD_1_16:
> +			c->guard_interval = GUARD_INTERVAL_1_16;
> +			break;
> +		case CXD2880_DVBT_GUARD_1_8:
> +			c->guard_interval = GUARD_INTERVAL_1_8;
> +			break;
> +		case CXD2880_DVBT_GUARD_1_4:
> +			c->guard_interval = GUARD_INTERVAL_1_4;
> +			break;
> +		default:
> +			c->guard_interval = GUARD_INTERVAL_1_32;
> +			pr_err("get invalid guard %d\n", guard);
> +			break;
> +		}
> +	} else {
> +		c->transmission_mode = TRANSMISSION_MODE_2K;
> +		c->guard_interval = GUARD_INTERVAL_1_32;
> +		pr_debug("ModeGuard err %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (tps.hierarchy) {
> +		case CXD2880_DVBT_HIERARCHY_NON:
> +			c->hierarchy = HIERARCHY_NONE;
> +			break;
> +		case CXD2880_DVBT_HIERARCHY_1:
> +			c->hierarchy = HIERARCHY_1;
> +			break;
> +		case CXD2880_DVBT_HIERARCHY_2:
> +			c->hierarchy = HIERARCHY_2;
> +			break;
> +		case CXD2880_DVBT_HIERARCHY_4:
> +			c->hierarchy = HIERARCHY_4;
> +			break;
> +		default:
> +			c->hierarchy = HIERARCHY_NONE;
> +			pr_err("TPSInfo hierarchy invalid %d\n",
> +			       tps.hierarchy);
> +			break;
> +		}
> +
> +		switch (tps.rate_hp) {
> +		case CXD2880_DVBT_CODERATE_1_2:
> +			c->code_rate_HP = FEC_1_2;
> +			break;
> +		case CXD2880_DVBT_CODERATE_2_3:
> +			c->code_rate_HP = FEC_2_3;
> +			break;
> +		case CXD2880_DVBT_CODERATE_3_4:
> +			c->code_rate_HP = FEC_3_4;
> +			break;
> +		case CXD2880_DVBT_CODERATE_5_6:
> +			c->code_rate_HP = FEC_5_6;
> +			break;
> +		case CXD2880_DVBT_CODERATE_7_8:
> +			c->code_rate_HP = FEC_7_8;
> +			break;
> +		default:
> +			c->code_rate_HP = FEC_NONE;
> +			pr_err("TPSInfo rateHP invalid %d\n",
> +			       tps.rate_hp);
> +			break;
> +		}
> +		switch (tps.rate_lp) {
> +		case CXD2880_DVBT_CODERATE_1_2:
> +			c->code_rate_LP = FEC_1_2;
> +			break;
> +		case CXD2880_DVBT_CODERATE_2_3:
> +			c->code_rate_LP = FEC_2_3;
> +			break;
> +		case CXD2880_DVBT_CODERATE_3_4:
> +			c->code_rate_LP = FEC_3_4;
> +			break;
> +		case CXD2880_DVBT_CODERATE_5_6:
> +			c->code_rate_LP = FEC_5_6;
> +			break;
> +		case CXD2880_DVBT_CODERATE_7_8:
> +			c->code_rate_LP = FEC_7_8;
> +			break;
> +		default:
> +			c->code_rate_LP = FEC_NONE;
> +			pr_err("TPSInfo rateLP invalid %d\n",
> +			       tps.rate_lp);
> +			break;
> +		}
> +		switch (tps.constellation) {
> +		case CXD2880_DVBT_CONSTELLATION_QPSK:
> +			c->modulation = QPSK;
> +			break;
> +		case CXD2880_DVBT_CONSTELLATION_16QAM:
> +			c->modulation = QAM_16;
> +			break;
> +		case CXD2880_DVBT_CONSTELLATION_64QAM:
> +			c->modulation = QAM_64;
> +			break;
> +		default:
> +			c->modulation = QPSK;
> +			pr_err("TPSInfo constellation invalid %d\n",
> +			       tps.constellation);
> +			break;
> +		}
> +	} else {
> +		c->hierarchy = HIERARCHY_NONE;
> +		c->code_rate_HP = FEC_NONE;
> +		c->code_rate_LP = FEC_NONE;
> +		c->modulation = QPSK;
> +		pr_debug("TPS info err %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (sense) {
> +		case CXD2880_TNRDMD_SPECTRUM_NORMAL:
> +			c->inversion = INVERSION_OFF;
> +			break;
> +		case CXD2880_TNRDMD_SPECTRUM_INV:
> +			c->inversion = INVERSION_ON;
> +			break;
> +		default:
> +			c->inversion = INVERSION_OFF;
> +			pr_err("spectrum sense invalid %d\n", sense);
> +			break;
> +		}
> +	} else {
> +		c->inversion = INVERSION_OFF;
> +		pr_debug("spectrum_sense %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		c->strength.len = 1;
> +		c->strength.stat[0].scale = FE_SCALE_DECIBEL;
> +		c->strength.stat[0].svalue = strength;
> +	} else {
> +		c->strength.len = 1;
> +		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		pr_debug("mon_rf_lvl %d\n", ret);
> +	}
> +
> +	ret = cxd2880_read_snr(fe, &snr);
> +	if (!ret) {
> +		c->cnr.len = 1;
> +		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
> +		c->cnr.stat[0].svalue = snr;
> +	} else {
> +		c->cnr.len = 1;
> +		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		pr_debug("read_snr %d\n", ret);
> +	}
> +
> +	return 0;
> +}
> +
> +static int cxd2880_get_frontend_t2(struct dvb_frontend *fe,
> +				   struct dtv_frontend_properties *c)
> +{
> +	int ret = 0;
> +	struct cxd2880_priv *priv = NULL;
> +	struct cxd2880_dvbt2_l1pre l1pre;
> +	enum cxd2880_dvbt2_plp_code_rate coderate;
> +	enum cxd2880_dvbt2_plp_constell qam;
> +	enum cxd2880_tnrdmd_spectrum_sense sense;
> +	u16 snr = 0;
> +	int strength = 0;
> +
> +	if ((!fe) || (!c)) {
> +		pr_err("invalid arg.\n");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(&priv->tnrdmd, &l1pre);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (l1pre.fft_mode) {
> +		case CXD2880_DVBT2_M2K:
> +			c->transmission_mode = TRANSMISSION_MODE_2K;
> +			break;
> +		case CXD2880_DVBT2_M8K:
> +			c->transmission_mode = TRANSMISSION_MODE_8K;
> +			break;
> +		case CXD2880_DVBT2_M4K:
> +			c->transmission_mode = TRANSMISSION_MODE_4K;
> +			break;
> +		case CXD2880_DVBT2_M1K:
> +			c->transmission_mode = TRANSMISSION_MODE_1K;
> +			break;
> +		case CXD2880_DVBT2_M16K:
> +			c->transmission_mode = TRANSMISSION_MODE_16K;
> +			break;
> +		case CXD2880_DVBT2_M32K:
> +			c->transmission_mode = TRANSMISSION_MODE_32K;
> +			break;
> +		default:
> +			c->transmission_mode = TRANSMISSION_MODE_2K;
> +			pr_err("L1Pre fft_mode invalid %d\n",
> +			       l1pre.fft_mode);
> +			break;
> +		}
> +		switch (l1pre.gi) {
> +		case CXD2880_DVBT2_G1_32:
> +			c->guard_interval = GUARD_INTERVAL_1_32;
> +			break;
> +		case CXD2880_DVBT2_G1_16:
> +			c->guard_interval = GUARD_INTERVAL_1_16;
> +			break;
> +		case CXD2880_DVBT2_G1_8:
> +			c->guard_interval = GUARD_INTERVAL_1_8;
> +			break;
> +		case CXD2880_DVBT2_G1_4:
> +			c->guard_interval = GUARD_INTERVAL_1_4;
> +			break;
> +		case CXD2880_DVBT2_G1_128:
> +			c->guard_interval = GUARD_INTERVAL_1_128;
> +			break;
> +		case CXD2880_DVBT2_G19_128:
> +			c->guard_interval = GUARD_INTERVAL_19_128;
> +			break;
> +		case CXD2880_DVBT2_G19_256:
> +			c->guard_interval = GUARD_INTERVAL_19_256;
> +			break;
> +		default:
> +			c->guard_interval = GUARD_INTERVAL_1_32;
> +			pr_err("L1Pre gi invalid %d\n", l1pre.gi);

Better to print it in full:
			pr_err("L1Pre guard interval is invalid %d\n", l1pre.gi);

Yet, I guess several of such messages should actually be pr_dbg(),
as, a normal user shouldn't normally see them. Anyway, debug levels
can be adjusted later, after the driver gets merged upstream.

> +			break;
> +		}
> +	} else {
> +		c->transmission_mode = TRANSMISSION_MODE_2K;
> +		c->guard_interval = GUARD_INTERVAL_1_32;
> +		pr_debug("L1Pre err %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(&priv->tnrdmd,
> +						 CXD2880_DVBT2_PLP_DATA,
> +						 &coderate);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (coderate) {
> +		case CXD2880_DVBT2_R1_2:
> +			c->fec_inner = FEC_1_2;
> +			break;
> +		case CXD2880_DVBT2_R3_5:
> +			c->fec_inner = FEC_3_5;
> +			break;
> +		case CXD2880_DVBT2_R2_3:
> +			c->fec_inner = FEC_2_3;
> +			break;
> +		case CXD2880_DVBT2_R3_4:
> +			c->fec_inner = FEC_3_4;
> +			break;
> +		case CXD2880_DVBT2_R4_5:
> +			c->fec_inner = FEC_4_5;
> +			break;
> +		case CXD2880_DVBT2_R5_6:
> +			c->fec_inner = FEC_5_6;
> +			break;
> +		default:
> +			c->fec_inner = FEC_NONE;
> +			pr_err("CodeRate invalid %d\n", coderate);
> +			break;
> +		}
> +	} else {
> +		c->fec_inner = FEC_NONE;
> +		pr_debug("CodeRate %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt2_mon_qam(&priv->tnrdmd,
> +					   CXD2880_DVBT2_PLP_DATA,
> +					   &qam);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (qam) {
> +		case CXD2880_DVBT2_QPSK:
> +			c->modulation = QPSK;
> +			break;
> +		case CXD2880_DVBT2_QAM16:
> +			c->modulation = QAM_16;
> +			break;
> +		case CXD2880_DVBT2_QAM64:
> +			c->modulation = QAM_64;
> +			break;
> +		case CXD2880_DVBT2_QAM256:
> +			c->modulation = QAM_256;
> +			break;
> +		default:
> +			c->modulation = QPSK;
> +			pr_err("QAM invalid %d\n", qam);
> +			break;
> +		}
> +	} else {
> +		c->modulation = QPSK;
> +		pr_debug("QAM %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		switch (sense) {
> +		case CXD2880_TNRDMD_SPECTRUM_NORMAL:
> +			c->inversion = INVERSION_OFF;
> +			break;
> +		case CXD2880_TNRDMD_SPECTRUM_INV:
> +			c->inversion = INVERSION_ON;
> +			break;
> +		default:
> +			c->inversion = INVERSION_OFF;
> +			pr_err("spectrum sense invalid %d\n", sense);
> +			break;
> +		}
> +	} else {
> +		c->inversion = INVERSION_OFF;
> +		pr_debug("SpectrumSense %d\n", ret);
> +	}
> +
> +	mutex_lock(priv->spi_mutex);
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength);
> +	mutex_unlock(priv->spi_mutex);
> +	if (!ret) {
> +		c->strength.len = 1;
> +		c->strength.stat[0].scale = FE_SCALE_DECIBEL;
> +		c->strength.stat[0].svalue = strength;
> +	} else {
> +		c->strength.len = 1;
> +		c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		pr_debug("mon_rf_lvl %d\n", ret);
> +	}
> +
> +	ret = cxd2880_read_snr(fe, &snr);
> +	if (!ret) {
> +		c->cnr.len = 1;
> +		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
> +		c->cnr.stat[0].svalue = snr;
> +	} else {
> +		c->cnr.len = 1;
> +		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
> +		pr_debug("read_snr %d\n", ret);
> +	}
> +
> +	return 0;
> +}
> +
> +static int cxd2880_get_frontend(struct dvb_frontend *fe,
> +				struct dtv_frontend_properties *props)
> +{
> +	struct cxd2880_priv *priv = NULL;
> +	int ret = 0;
> +
> +	if ((!fe) || (!props)) {
> +		pr_err("invalid arg.");
> +		return -EINVAL;
> +	}
> +
> +	priv = fe->demodulator_priv;
> +
> +	pr_debug("system=%d\n", fe->dtv_property_cache.delivery_system);
> +	switch (fe->dtv_property_cache.delivery_system) {
> +	case SYS_DVBT:
> +		ret = cxd2880_get_frontend_t(fe, props);
> +		break;
> +	case SYS_DVBT2:
> +		ret = cxd2880_get_frontend_t2(fe, props);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe)
> +{
> +	return DVBFE_ALGO_HW;
> +}
> +
> +static struct dvb_frontend_ops cxd2880_dvbt_t2_ops;
> +
> +struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe,
> +				    struct cxd2880_config *cfg)
> +{
> +	int ret = 0;
> +	enum cxd2880_tnrdmd_chip_id chipid =
> +					CXD2880_TNRDMD_CHIP_ID_UNKNOWN;
> +	static struct cxd2880_priv *priv;
> +	u8 data = 0;
> +
> +	if (!fe) {
> +		pr_err("invalid arg.\n");
> +		return NULL;
> +	}
> +
> +	priv = kzalloc(sizeof(struct cxd2880_priv), GFP_KERNEL);
> +	if (!priv)
> +		return NULL;
> +
> +	priv->spi = cfg->spi;
> +	priv->spi_mutex = cfg->spi_mutex;
> +	priv->spi_device.spi = cfg->spi;
> +
> +	memcpy(&fe->ops, &cxd2880_dvbt_t2_ops,
> +	       sizeof(struct dvb_frontend_ops));
> +
> +	ret = cxd2880_spi_device_initialize(&priv->spi_device,
> +					    CXD2880_SPI_MODE_0,
> +					    55000000);
> +	if (ret) {
> +		pr_err("spi_device_initialize failed. %d\n", ret);
> +		kfree(priv);
> +		return NULL;
> +	}
> +
> +	ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi,
> +					    &priv->spi_device);
> +	if (ret) {
> +		pr_err("spi_device_create_spi failed. %d\n", ret);
> +		kfree(priv);
> +		return NULL;
> +	}
> +
> +	ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0);
> +	if (ret) {
> +		pr_err("io_spi_create failed. %d\n", ret);
> +		kfree(priv);
> +		return NULL;
> +	}
> +	ret = priv->regio.write_reg(&priv->regio,
> +				    CXD2880_IO_TGT_SYS, 0x00, 0x00);
> +	if (ret) {
> +		pr_err("set bank to 0x00 failed.\n");
> +		kfree(priv);
> +		return NULL;
> +	}
> +	ret = priv->regio.read_regs(&priv->regio,
> +				    CXD2880_IO_TGT_SYS, 0xfd, &data, 1);
> +	if (ret) {
> +		pr_err("read chip id failed.\n");
> +		kfree(priv);
> +		return NULL;
> +	}
> +
> +	chipid = (enum cxd2880_tnrdmd_chip_id)data;
> +	if ((chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X) &&
> +	    (chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11)) {
> +		pr_err("chip id invalid.\n");
> +		kfree(priv);
> +		return NULL;
> +	}
> +
> +	fe->demodulator_priv = priv;
> +	pr_info("CXD2880 driver version: Ver %s\n",
> +		CXD2880_TNRDMD_DRIVER_VERSION);
> +
> +	return fe;
> +}
> +EXPORT_SYMBOL(cxd2880_attach);
> +
> +static struct dvb_frontend_ops cxd2880_dvbt_t2_ops = {
> +	.info = {
> +		.name = "Sony CXD2880",
> +		.frequency_min =  174000000,
> +		.frequency_max = 862000000,
> +		.frequency_stepsize = 1000,
> +		.caps = FE_CAN_INVERSION_AUTO |
> +				FE_CAN_FEC_1_2 |
> +				FE_CAN_FEC_2_3 |
> +				FE_CAN_FEC_3_4 |
> +				FE_CAN_FEC_4_5 |
> +				FE_CAN_FEC_5_6	|
> +				FE_CAN_FEC_7_8	|
> +				FE_CAN_FEC_AUTO |
> +				FE_CAN_QPSK |
> +				FE_CAN_QAM_16 |
> +				FE_CAN_QAM_32 |
> +				FE_CAN_QAM_64 |
> +				FE_CAN_QAM_128 |
> +				FE_CAN_QAM_256 |
> +				FE_CAN_QAM_AUTO |
> +				FE_CAN_TRANSMISSION_MODE_AUTO |
> +				FE_CAN_GUARD_INTERVAL_AUTO |
> +				FE_CAN_2G_MODULATION |
> +				FE_CAN_RECOVER |
> +				FE_CAN_MUTE_TS,
> +	},
> +	.delsys = { SYS_DVBT, SYS_DVBT2 },
> +
> +	.release = cxd2880_release,
> +	.init = cxd2880_init,
> +	.sleep = cxd2880_sleep,
> +	.tune = cxd2880_tune,
> +	.set_frontend = cxd2880_set_frontend,
> +	.get_frontend = cxd2880_get_frontend,
> +	.read_status = cxd2880_read_status,
> +	.read_ber = cxd2880_read_ber,
> +	.read_signal_strength = cxd2880_read_signal_strength,
> +	.read_snr = cxd2880_read_snr,
> +	.read_ucblocks = cxd2880_read_ucblocks,
> +	.get_frontend_algo = cxd2880_get_frontend_algo,
> +};
> +
> +MODULE_DESCRIPTION(
> +"Sony CXD2880 DVB-T2/T tuner + demodulator drvier");
> +MODULE_AUTHOR("Sony Semiconductor Solutions Corporation");
> +MODULE_LICENSE("GPL v2");



Thanks,
Mauro
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 08/14] [media] cxd2880: Add DVB-T control functions the driver
  2017-08-16  4:40   ` Yasunari.Takiguchi-7U/KSKJipcs
@ 2017-08-27 15:17     ` Mauro Carvalho Chehab
  -1 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 15:17 UTC (permalink / raw)
  To: Yasunari.Takiguchi
  Cc: linux-kernel, devicetree, linux-media, tbird20d, frowand.list,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

Em Wed, 16 Aug 2017 13:40:37 +0900
<Yasunari.Takiguchi@sony.com> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> 
> Provide definitions, interfaces and functions needed for DVB-T
> of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.
> 
> [Change list]
> Changes in V3
>    drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
>       -no change
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
>       -modified return code
>       -modified coding style of if() 
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
>       -modified return code
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
> ---
>  drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h |   91 ++
>  .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c    | 1115 ++++++++++++++++++++
>  .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h    |   62 ++
>  3 files changed, 1268 insertions(+)
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
> 
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
> new file mode 100644
> index 000000000000..345c094760d2
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
> @@ -0,0 +1,91 @@
> +/*
> + * cxd2880_dvbt.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DVB-T related definitions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_DVBT_H
> +#define CXD2880_DVBT_H
> +
> +#include "cxd2880_common.h"
> +
> +enum cxd2880_dvbt_constellation {
> +	CXD2880_DVBT_CONSTELLATION_QPSK,
> +	CXD2880_DVBT_CONSTELLATION_16QAM,
> +	CXD2880_DVBT_CONSTELLATION_64QAM,
> +	CXD2880_DVBT_CONSTELLATION_RESERVED_3
> +};
> +
> +enum cxd2880_dvbt_hierarchy {
> +	CXD2880_DVBT_HIERARCHY_NON,
> +	CXD2880_DVBT_HIERARCHY_1,
> +	CXD2880_DVBT_HIERARCHY_2,
> +	CXD2880_DVBT_HIERARCHY_4
> +};
> +
> +enum cxd2880_dvbt_coderate {
> +	CXD2880_DVBT_CODERATE_1_2,
> +	CXD2880_DVBT_CODERATE_2_3,
> +	CXD2880_DVBT_CODERATE_3_4,
> +	CXD2880_DVBT_CODERATE_5_6,
> +	CXD2880_DVBT_CODERATE_7_8,
> +	CXD2880_DVBT_CODERATE_RESERVED_5,
> +	CXD2880_DVBT_CODERATE_RESERVED_6,
> +	CXD2880_DVBT_CODERATE_RESERVED_7
> +};
> +
> +enum cxd2880_dvbt_guard {
> +	CXD2880_DVBT_GUARD_1_32,
> +	CXD2880_DVBT_GUARD_1_16,
> +	CXD2880_DVBT_GUARD_1_8,
> +	CXD2880_DVBT_GUARD_1_4
> +};
> +
> +enum cxd2880_dvbt_mode {
> +	CXD2880_DVBT_MODE_2K,
> +	CXD2880_DVBT_MODE_8K,
> +	CXD2880_DVBT_MODE_RESERVED_2,
> +	CXD2880_DVBT_MODE_RESERVED_3
> +};
> +
> +enum cxd2880_dvbt_profile {
> +	CXD2880_DVBT_PROFILE_HP = 0,
> +	CXD2880_DVBT_PROFILE_LP
> +};
> +
> +struct cxd2880_dvbt_tpsinfo {
> +	enum cxd2880_dvbt_constellation constellation;
> +	enum cxd2880_dvbt_hierarchy hierarchy;
> +	enum cxd2880_dvbt_coderate rate_hp;
> +	enum cxd2880_dvbt_coderate rate_lp;
> +	enum cxd2880_dvbt_guard guard;
> +	enum cxd2880_dvbt_mode mode;
> +	u8 fnum;
> +	u8 length_indicator;
> +	u16 cell_id;
> +	u8 cell_id_ok;
> +	u8 reserved_even;
> +	u8 reserved_odd;
> +};
> +
> +#endif
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
> new file mode 100644
> index 000000000000..8a16cb359171
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
> @@ -0,0 +1,1115 @@
> +/*
> + * cxd2880_tnrdmd_dvbt.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * control functions for DVB-T
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_tnrdmd_dvbt.h"
> +#include "cxd2880_tnrdmd_dvbt_mon.h"
> +
> +static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dtv_bandwidth
> +				     bandwidth,
> +				     enum cxd2880_tnrdmd_clockmode
> +				     clk_mode)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x31, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data_a[2] = { 0x52, 0x49 };
> +		u8 data_b[2] = { 0x5d, 0x55 };
> +		u8 data_c[2] = { 0x60, 0x00 };

Always declare immutable data as "static const".

Same note I did before about using a code block here just to declare
new data applies here and on other parts of this code.

> +		u8 *data = NULL;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x04);
> +		if (ret)
> +			return ret;
> +
> +		switch (clk_mode) {
> +		case CXD2880_TNRDMD_CLOCKMODE_A:
> +			data = data_a;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_B:
> +			data = data_b;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_C:
> +			data = data_c;
> +			break;
> +		default:
> +			return -EPERM;
> +		}
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x65, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x5d, 0x07);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
> +		u8 data[2] = { 0x01, 0x01 };
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x00);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xce, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x04);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x5c, 0xfb);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xa4, 0x03);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x14);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xb0, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x25);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data[2] = { 0x01, 0xf0 };
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xf0, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) ||
> +	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x12);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x44, 0x00);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x11);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x87, 0xd2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
> +		u8 data_a[3] = { 0x73, 0xca, 0x49 };
> +		u8 data_b[3] = { 0xc8, 0x13, 0xaa };
> +		u8 data_c[3] = { 0xdc, 0x6c, 0x00 };

const?

> +		u8 *data = NULL;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x04);
> +		if (ret)
> +			return ret;
> +
> +		switch (clk_mode) {
> +		case CXD2880_TNRDMD_CLOCKMODE_A:
> +			data = data_a;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_B:
> +			data = data_b;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_C:
> +			data = data_c;
> +			break;
> +		default:
> +			return -EPERM;
> +		}
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x68, data, 3);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x04);
> +	if (ret)
> +		return ret;
> +
> +	switch (bandwidth) {
> +	case CXD2880_DTV_BW_8_MHZ:
> +
> +		{
> +			u8 data_ac[5] = { 0x15, 0x00, 0x00, 0x00,
> +				0x00
> +			};
> +			u8 data_b[5] = { 0x14, 0x6a, 0xaa, 0xaa,
> +				0xaa
> +			};

const?

> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x60, data, 5);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x00);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data_a[2] = { 0x01, 0x28 };
> +			u8 data_b[2] = { 0x11, 0x44 };
> +			u8 data_c[2] = { 0x15, 0x28 };

const?

> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x7d, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data = 0;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = 0x35;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = 0x34;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x71, data);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[5] = { 0x30, 0x00, 0x00, 0x90,
> +				0x00
> +			};
> +			u8 data_b[5] = { 0x36, 0x71, 0x00, 0xa3,
> +				0x55
> +			};
> +			u8 data_c[5] = { 0x38, 0x00, 0x00, 0xa8,
> +				0x00
> +			};

const?

> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x51, &data[2], 3);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data[4] = { 0xb3, 0x00, 0x01, 0x02 };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x72, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x6b, &data[2], 2);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_7_MHZ:
> +
> +		{
> +			u8 data_ac[5] = { 0x18, 0x00, 0x00, 0x00,
> +				0x00
> +			};
> +			u8 data_b[5] = { 0x17, 0x55, 0x55, 0x55,
> +				0x55
> +			};

const?

> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x60, data, 5);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x02);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data_a[2] = { 0x12, 0x4c };
> +			u8 data_b[2] = { 0x1f, 0x15 };
> +			u8 data_c[2] = { 0x1f, 0xf8 };

const? (will stop pinpoint those static const data)

> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x7d, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data = 0;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = 0x2f;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = 0x2e;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x71, data);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[5] = { 0x36, 0xdb, 0x00, 0xa4,
> +				0x92
> +			};
> +			u8 data_b[5] = { 0x3e, 0x38, 0x00, 0xba,
> +				0xaa
> +			};
> +			u8 data_c[5] = { 0x40, 0x00, 0x00, 0xc0,
> +				0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x51, &data[2], 3);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data[4] = { 0xb8, 0x00, 0x00, 0x03 };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x72, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x6b, &data[2], 2);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_6_MHZ:
> +
> +		{
> +			u8 data_ac[5] = { 0x1c, 0x00, 0x00, 0x00,
> +				0x00
> +			};
> +			u8 data_b[5] = { 0x1b, 0x38, 0xe3, 0x8e,
> +				0x38
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x60, data, 5);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x04);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data_a[2] = { 0x1f, 0xf8 };
> +			u8 data_b[2] = { 0x24, 0x43 };
> +			u8 data_c[2] = { 0x25, 0x4c };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x7d, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data = 0;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = 0x29;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = 0x2a;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x71, data);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[5] = { 0x40, 0x00, 0x00, 0xc0,
> +				0x00
> +			};
> +			u8 data_b[5] = { 0x48, 0x97, 0x00, 0xd9,
> +				0xc7
> +			};
> +			u8 data_c[5] = { 0x4a, 0xaa, 0x00, 0xdf,
> +				0xff
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x51, &data[2], 3);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data[4] = { 0xbe, 0xab, 0x00, 0x03 };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x72, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x6b, &data[2], 2);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_5_MHZ:
> +
> +		{
> +			u8 data_ac[5] = { 0x21, 0x99, 0x99, 0x99,
> +				0x99
> +			};
> +			u8 data_b[5] = { 0x20, 0xaa, 0xaa, 0xaa,
> +				0xaa
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x60, data, 5);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x06);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data_a[2] = { 0x26, 0x5d };
> +			u8 data_b[2] = { 0x2b, 0x84 };
> +			u8 data_c[2] = { 0x2c, 0xc2 };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x7d, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data = 0;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = 0x24;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = 0x23;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x71, data);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[5] = { 0x4c, 0xcc, 0x00, 0xe6,
> +				0x66
> +			};
> +			u8 data_b[5] = { 0x57, 0x1c, 0x01, 0x05,
> +				0x55
> +			};
> +			u8 data_c[5] = { 0x59, 0x99, 0x01, 0x0c,
> +				0xcc
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x51, &data[2], 3);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data[4] = { 0xc8, 0x01, 0x00, 0x03 };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x72, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x6b, &data[2], 2);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	default:
> +		return -EPERM;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xfd, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd
> +						   *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x04);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x5c, 0xd8);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xa4, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x11);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x87, 0x04);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
> +			    enum cxd2880_dvbt_profile profile)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x67,
> +				     (profile == CXD2880_DVBT_PROFILE_HP)
> +				     ? 0x00 : 0x01);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
> +			      struct cxd2880_dvbt_tune_param
> +			      *tune_param)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!tune_param))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT,
> +						tune_param->center_freq_khz,
> +						tune_param->bandwidth, 0, 0);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth,
> +				      tnr_dmd->clk_mode);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret =
> +		    x_tune_dvbt_demod_setting(tnr_dmd->diver_sub,
> +					      tune_param->bandwidth,
> +					      tnr_dmd->diver_sub->clk_mode);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = dvbt_set_profile(tnr_dmd, tune_param->profile);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
> +			      struct cxd2880_dvbt_tune_param
> +			      *tune_param)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!tune_param))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT,
> +						0);
> +	if (ret)
> +		return ret;
> +
> +	tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
> +	tnr_dmd->frequency_khz = tune_param->center_freq_khz;
> +	tnr_dmd->sys = CXD2880_DTV_SYS_DVBT;
> +	tnr_dmd->bandwidth = tune_param->bandwidth;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
> +		tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
> +		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT;
> +		tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = x_sleep_dvbt_demod_setting(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
> +					 *tnr_dmd,
> +					 enum
> +					 cxd2880_tnrdmd_lock_result
> +					 *lock)
> +{
> +	int ret = 0;
> +
> +	u8 sync_stat = 0;
> +	u8 ts_lock = 0;
> +	u8 unlock_detected = 0;
> +	u8 unlock_detected_sub = 0;
> +
> +	if ((!tnr_dmd) || (!lock))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
> +					      &unlock_detected);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		if (sync_stat == 6)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		else if (unlock_detected)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +		else
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +		return ret;
> +	}
> +
> +	if (sync_stat == 6) {
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		return ret;
> +	}
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
> +						  &unlock_detected_sub);
> +	if (ret)
> +		return ret;
> +
> +	if (sync_stat == 6)
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +	else if (unlock_detected && unlock_detected_sub)
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +	else
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
> +				      *tnr_dmd,
> +				      enum
> +				      cxd2880_tnrdmd_lock_result
> +				      *lock)
> +{
> +	int ret = 0;
> +
> +	u8 sync_stat = 0;
> +	u8 ts_lock = 0;
> +	u8 unlock_detected = 0;
> +	u8 unlock_detected_sub = 0;
> +
> +	if ((!tnr_dmd) || (!lock))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
> +					      &unlock_detected);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		if (ts_lock)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		else if (unlock_detected)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +		else
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +		return ret;
> +	}
> +
> +	if (ts_lock) {
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		return ret;
> +	} else if (!unlock_detected) {
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +		return ret;
> +	}
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
> +						  &unlock_detected_sub);
> +	if (ret)
> +		return ret;
> +
> +	if (unlock_detected && unlock_detected_sub)
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +	else
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
> new file mode 100644
> index 000000000000..f0a36040da3b
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
> @@ -0,0 +1,62 @@
> +/*
> + * cxd2880_tnrdmd_dvbt.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * control interface for DVB-T
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_TNRDMD_DVBT_H
> +#define CXD2880_TNRDMD_DVBT_H
> +
> +#include "cxd2880_common.h"
> +#include "cxd2880_tnrdmd.h"
> +
> +struct cxd2880_dvbt_tune_param {
> +	u32 center_freq_khz;
> +	enum cxd2880_dtv_bandwidth bandwidth;
> +	enum cxd2880_dvbt_profile profile;
> +};
> +
> +int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
> +			      struct cxd2880_dvbt_tune_param
> +			      *tune_param);
> +
> +int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
> +			      struct cxd2880_dvbt_tune_param
> +			      *tune_param);
> +
> +int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd
> +				      *tnr_dmd);
> +
> +int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
> +					 *tnr_dmd,
> +					 enum
> +					 cxd2880_tnrdmd_lock_result
> +					 *lock);
> +
> +int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
> +				      *tnr_dmd,
> +				      enum
> +				      cxd2880_tnrdmd_lock_result
> +				      *lock);
> +
> +#endif



Thanks,
Mauro

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 08/14] [media] cxd2880: Add DVB-T control functions the driver
@ 2017-08-27 15:17     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 15:17 UTC (permalink / raw)
  To: Yasunari.Takiguchi
  Cc: linux-kernel, devicetree, linux-media, tbird20d, frowand.list,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

Em Wed, 16 Aug 2017 13:40:37 +0900
<Yasunari.Takiguchi@sony.com> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> 
> Provide definitions, interfaces and functions needed for DVB-T
> of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.
> 
> [Change list]
> Changes in V3
>    drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
>       -no change
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
>       -modified return code
>       -modified coding style of if() 
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
>       -modified return code
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
> ---
>  drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h |   91 ++
>  .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c    | 1115 ++++++++++++++++++++
>  .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h    |   62 ++
>  3 files changed, 1268 insertions(+)
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
> 
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
> new file mode 100644
> index 000000000000..345c094760d2
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h
> @@ -0,0 +1,91 @@
> +/*
> + * cxd2880_dvbt.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DVB-T related definitions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_DVBT_H
> +#define CXD2880_DVBT_H
> +
> +#include "cxd2880_common.h"
> +
> +enum cxd2880_dvbt_constellation {
> +	CXD2880_DVBT_CONSTELLATION_QPSK,
> +	CXD2880_DVBT_CONSTELLATION_16QAM,
> +	CXD2880_DVBT_CONSTELLATION_64QAM,
> +	CXD2880_DVBT_CONSTELLATION_RESERVED_3
> +};
> +
> +enum cxd2880_dvbt_hierarchy {
> +	CXD2880_DVBT_HIERARCHY_NON,
> +	CXD2880_DVBT_HIERARCHY_1,
> +	CXD2880_DVBT_HIERARCHY_2,
> +	CXD2880_DVBT_HIERARCHY_4
> +};
> +
> +enum cxd2880_dvbt_coderate {
> +	CXD2880_DVBT_CODERATE_1_2,
> +	CXD2880_DVBT_CODERATE_2_3,
> +	CXD2880_DVBT_CODERATE_3_4,
> +	CXD2880_DVBT_CODERATE_5_6,
> +	CXD2880_DVBT_CODERATE_7_8,
> +	CXD2880_DVBT_CODERATE_RESERVED_5,
> +	CXD2880_DVBT_CODERATE_RESERVED_6,
> +	CXD2880_DVBT_CODERATE_RESERVED_7
> +};
> +
> +enum cxd2880_dvbt_guard {
> +	CXD2880_DVBT_GUARD_1_32,
> +	CXD2880_DVBT_GUARD_1_16,
> +	CXD2880_DVBT_GUARD_1_8,
> +	CXD2880_DVBT_GUARD_1_4
> +};
> +
> +enum cxd2880_dvbt_mode {
> +	CXD2880_DVBT_MODE_2K,
> +	CXD2880_DVBT_MODE_8K,
> +	CXD2880_DVBT_MODE_RESERVED_2,
> +	CXD2880_DVBT_MODE_RESERVED_3
> +};
> +
> +enum cxd2880_dvbt_profile {
> +	CXD2880_DVBT_PROFILE_HP = 0,
> +	CXD2880_DVBT_PROFILE_LP
> +};
> +
> +struct cxd2880_dvbt_tpsinfo {
> +	enum cxd2880_dvbt_constellation constellation;
> +	enum cxd2880_dvbt_hierarchy hierarchy;
> +	enum cxd2880_dvbt_coderate rate_hp;
> +	enum cxd2880_dvbt_coderate rate_lp;
> +	enum cxd2880_dvbt_guard guard;
> +	enum cxd2880_dvbt_mode mode;
> +	u8 fnum;
> +	u8 length_indicator;
> +	u16 cell_id;
> +	u8 cell_id_ok;
> +	u8 reserved_even;
> +	u8 reserved_odd;
> +};
> +
> +#endif
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
> new file mode 100644
> index 000000000000..8a16cb359171
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
> @@ -0,0 +1,1115 @@
> +/*
> + * cxd2880_tnrdmd_dvbt.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * control functions for DVB-T
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_tnrdmd_dvbt.h"
> +#include "cxd2880_tnrdmd_dvbt_mon.h"
> +
> +static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dtv_bandwidth
> +				     bandwidth,
> +				     enum cxd2880_tnrdmd_clockmode
> +				     clk_mode)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x31, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data_a[2] = { 0x52, 0x49 };
> +		u8 data_b[2] = { 0x5d, 0x55 };
> +		u8 data_c[2] = { 0x60, 0x00 };

Always declare immutable data as "static const".

Same note I did before about using a code block here just to declare
new data applies here and on other parts of this code.

> +		u8 *data = NULL;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x04);
> +		if (ret)
> +			return ret;
> +
> +		switch (clk_mode) {
> +		case CXD2880_TNRDMD_CLOCKMODE_A:
> +			data = data_a;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_B:
> +			data = data_b;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_C:
> +			data = data_c;
> +			break;
> +		default:
> +			return -EPERM;
> +		}
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x65, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x5d, 0x07);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
> +		u8 data[2] = { 0x01, 0x01 };
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x00);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xce, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x04);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x5c, 0xfb);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xa4, 0x03);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x14);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xb0, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x25);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data[2] = { 0x01, 0xf0 };
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xf0, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) ||
> +	    (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x12);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x44, 0x00);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x11);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x87, 0xd2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
> +		u8 data_a[3] = { 0x73, 0xca, 0x49 };
> +		u8 data_b[3] = { 0xc8, 0x13, 0xaa };
> +		u8 data_c[3] = { 0xdc, 0x6c, 0x00 };

const?

> +		u8 *data = NULL;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x04);
> +		if (ret)
> +			return ret;
> +
> +		switch (clk_mode) {
> +		case CXD2880_TNRDMD_CLOCKMODE_A:
> +			data = data_a;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_B:
> +			data = data_b;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_C:
> +			data = data_c;
> +			break;
> +		default:
> +			return -EPERM;
> +		}
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x68, data, 3);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x04);
> +	if (ret)
> +		return ret;
> +
> +	switch (bandwidth) {
> +	case CXD2880_DTV_BW_8_MHZ:
> +
> +		{
> +			u8 data_ac[5] = { 0x15, 0x00, 0x00, 0x00,
> +				0x00
> +			};
> +			u8 data_b[5] = { 0x14, 0x6a, 0xaa, 0xaa,
> +				0xaa
> +			};

const?

> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x60, data, 5);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x00);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data_a[2] = { 0x01, 0x28 };
> +			u8 data_b[2] = { 0x11, 0x44 };
> +			u8 data_c[2] = { 0x15, 0x28 };

const?

> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x7d, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data = 0;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = 0x35;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = 0x34;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x71, data);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[5] = { 0x30, 0x00, 0x00, 0x90,
> +				0x00
> +			};
> +			u8 data_b[5] = { 0x36, 0x71, 0x00, 0xa3,
> +				0x55
> +			};
> +			u8 data_c[5] = { 0x38, 0x00, 0x00, 0xa8,
> +				0x00
> +			};

const?

> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x51, &data[2], 3);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data[4] = { 0xb3, 0x00, 0x01, 0x02 };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x72, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x6b, &data[2], 2);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_7_MHZ:
> +
> +		{
> +			u8 data_ac[5] = { 0x18, 0x00, 0x00, 0x00,
> +				0x00
> +			};
> +			u8 data_b[5] = { 0x17, 0x55, 0x55, 0x55,
> +				0x55
> +			};

const?

> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x60, data, 5);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x02);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data_a[2] = { 0x12, 0x4c };
> +			u8 data_b[2] = { 0x1f, 0x15 };
> +			u8 data_c[2] = { 0x1f, 0xf8 };

const? (will stop pinpoint those static const data)

> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x7d, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data = 0;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = 0x2f;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = 0x2e;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x71, data);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[5] = { 0x36, 0xdb, 0x00, 0xa4,
> +				0x92
> +			};
> +			u8 data_b[5] = { 0x3e, 0x38, 0x00, 0xba,
> +				0xaa
> +			};
> +			u8 data_c[5] = { 0x40, 0x00, 0x00, 0xc0,
> +				0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x51, &data[2], 3);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data[4] = { 0xb8, 0x00, 0x00, 0x03 };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x72, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x6b, &data[2], 2);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_6_MHZ:
> +
> +		{
> +			u8 data_ac[5] = { 0x1c, 0x00, 0x00, 0x00,
> +				0x00
> +			};
> +			u8 data_b[5] = { 0x1b, 0x38, 0xe3, 0x8e,
> +				0x38
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x60, data, 5);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x04);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data_a[2] = { 0x1f, 0xf8 };
> +			u8 data_b[2] = { 0x24, 0x43 };
> +			u8 data_c[2] = { 0x25, 0x4c };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x7d, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data = 0;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = 0x29;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = 0x2a;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x71, data);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[5] = { 0x40, 0x00, 0x00, 0xc0,
> +				0x00
> +			};
> +			u8 data_b[5] = { 0x48, 0x97, 0x00, 0xd9,
> +				0xc7
> +			};
> +			u8 data_c[5] = { 0x4a, 0xaa, 0x00, 0xdf,
> +				0xff
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x51, &data[2], 3);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data[4] = { 0xbe, 0xab, 0x00, 0x03 };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x72, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x6b, &data[2], 2);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_5_MHZ:
> +
> +		{
> +			u8 data_ac[5] = { 0x21, 0x99, 0x99, 0x99,
> +				0x99
> +			};
> +			u8 data_b[5] = { 0x20, 0xaa, 0xaa, 0xaa,
> +				0xaa
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x60, data, 5);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x06);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data_a[2] = { 0x26, 0x5d };
> +			u8 data_b[2] = { 0x2b, 0x84 };
> +			u8 data_c[2] = { 0x2c, 0xc2 };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x7d, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data = 0;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = 0x24;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = 0x23;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x71, data);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[5] = { 0x4c, 0xcc, 0x00, 0xe6,
> +				0x66
> +			};
> +			u8 data_b[5] = { 0x57, 0x1c, 0x01, 0x05,
> +				0x55
> +			};
> +			u8 data_c[5] = { 0x59, 0x99, 0x01, 0x0c,
> +				0xcc
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x51, &data[2], 3);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data[4] = { 0xc8, 0x01, 0x00, 0x03 };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x72, &data[0], 2);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x6b, &data[2], 2);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	default:
> +		return -EPERM;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xfd, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd
> +						   *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x04);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x5c, 0xd8);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xa4, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x11);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x87, 0x04);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
> +			    enum cxd2880_dvbt_profile profile)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x67,
> +				     (profile == CXD2880_DVBT_PROFILE_HP)
> +				     ? 0x00 : 0x01);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
> +			      struct cxd2880_dvbt_tune_param
> +			      *tune_param)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!tune_param))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT,
> +						tune_param->center_freq_khz,
> +						tune_param->bandwidth, 0, 0);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth,
> +				      tnr_dmd->clk_mode);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret =
> +		    x_tune_dvbt_demod_setting(tnr_dmd->diver_sub,
> +					      tune_param->bandwidth,
> +					      tnr_dmd->diver_sub->clk_mode);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = dvbt_set_profile(tnr_dmd, tune_param->profile);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
> +			      struct cxd2880_dvbt_tune_param
> +			      *tune_param)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!tune_param))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT,
> +						0);
> +	if (ret)
> +		return ret;
> +
> +	tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
> +	tnr_dmd->frequency_khz = tune_param->center_freq_khz;
> +	tnr_dmd->sys = CXD2880_DTV_SYS_DVBT;
> +	tnr_dmd->bandwidth = tune_param->bandwidth;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
> +		tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
> +		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT;
> +		tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = x_sleep_dvbt_demod_setting(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
> +					 *tnr_dmd,
> +					 enum
> +					 cxd2880_tnrdmd_lock_result
> +					 *lock)
> +{
> +	int ret = 0;
> +
> +	u8 sync_stat = 0;
> +	u8 ts_lock = 0;
> +	u8 unlock_detected = 0;
> +	u8 unlock_detected_sub = 0;
> +
> +	if ((!tnr_dmd) || (!lock))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
> +					      &unlock_detected);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		if (sync_stat == 6)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		else if (unlock_detected)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +		else
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +		return ret;
> +	}
> +
> +	if (sync_stat == 6) {
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		return ret;
> +	}
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
> +						  &unlock_detected_sub);
> +	if (ret)
> +		return ret;
> +
> +	if (sync_stat == 6)
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +	else if (unlock_detected && unlock_detected_sub)
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +	else
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
> +				      *tnr_dmd,
> +				      enum
> +				      cxd2880_tnrdmd_lock_result
> +				      *lock)
> +{
> +	int ret = 0;
> +
> +	u8 sync_stat = 0;
> +	u8 ts_lock = 0;
> +	u8 unlock_detected = 0;
> +	u8 unlock_detected_sub = 0;
> +
> +	if ((!tnr_dmd) || (!lock))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
> +					      &unlock_detected);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		if (ts_lock)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		else if (unlock_detected)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +		else
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +		return ret;
> +	}
> +
> +	if (ts_lock) {
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		return ret;
> +	} else if (!unlock_detected) {
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +		return ret;
> +	}
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
> +						  &unlock_detected_sub);
> +	if (ret)
> +		return ret;
> +
> +	if (unlock_detected && unlock_detected_sub)
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +	else
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
> new file mode 100644
> index 000000000000..f0a36040da3b
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h
> @@ -0,0 +1,62 @@
> +/*
> + * cxd2880_tnrdmd_dvbt.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * control interface for DVB-T
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_TNRDMD_DVBT_H
> +#define CXD2880_TNRDMD_DVBT_H
> +
> +#include "cxd2880_common.h"
> +#include "cxd2880_tnrdmd.h"
> +
> +struct cxd2880_dvbt_tune_param {
> +	u32 center_freq_khz;
> +	enum cxd2880_dtv_bandwidth bandwidth;
> +	enum cxd2880_dvbt_profile profile;
> +};
> +
> +int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
> +			      struct cxd2880_dvbt_tune_param
> +			      *tune_param);
> +
> +int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
> +			      struct cxd2880_dvbt_tune_param
> +			      *tune_param);
> +
> +int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd
> +				      *tnr_dmd);
> +
> +int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
> +					 *tnr_dmd,
> +					 enum
> +					 cxd2880_tnrdmd_lock_result
> +					 *lock);
> +
> +int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
> +				      *tnr_dmd,
> +				      enum
> +				      cxd2880_tnrdmd_lock_result
> +				      *lock);
> +
> +#endif



Thanks,
Mauro

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 09/14] [media] cxd2880: Add DVB-T monitor and integration layer functions
@ 2017-08-27 15:34     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 15:34 UTC (permalink / raw)
  To: Yasunari.Takiguchi
  Cc: linux-kernel, devicetree, linux-media, tbird20d, frowand.list,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

Em Wed, 16 Aug 2017 13:41:42 +0900
<Yasunari.Takiguchi@sony.com> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> 
> Provide monitor and integration layer functions (DVB-T)
> for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.
> 
> [Change list]
> Changes in V3
>    drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
>       -changed CXD2880_SLEEP to usleep_range
>       -chnaged cxd2880_atomic_set to atomic_set
>       -modified return code
>       -modified coding style of if() 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
>       -modified return code
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
>       -removed unnecessary cast
>       -changed cxd2880_math_log to intlog10
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
>       -modified return code
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
> ---
>  .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.c     |  198 ++++
>  .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.h     |   58 +
>  .../cxd2880/cxd2880_tnrdmd_dvbt_mon.c              | 1227 ++++++++++++++++++++
>  .../cxd2880/cxd2880_tnrdmd_dvbt_mon.h              |  106 ++
>  4 files changed, 1589 insertions(+)
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
> 
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
> new file mode 100644
> index 000000000000..729cb0939203
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
> @@ -0,0 +1,198 @@
> +/*
> + * cxd2880_integ_dvbt.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * integration layer functions for DVB-T
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_tnrdmd_dvbt.h"
> +#include "cxd2880_integ_dvbt.h"
> +
> +static int dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +int cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd,
> +			    struct cxd2880_dvbt_tune_param
> +			    *tune_param)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!tune_param))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	atomic_set(&tnr_dmd->cancel, 0);
> +
> +	if ((tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ)) {
> +		return -EOPNOTSUPP;
> +	}
> +
> +	ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000,
> +		     CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000);
> +
> +	ret = cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param);
> +	if (ret)
> +		return ret;
> +
> +	ret = dvbt_wait_demod_lock(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +	enum cxd2880_tnrdmd_lock_result lock =
> +	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +	struct cxd2880_stopwatch timer;
> +	u8 continue_wait = 1;
> +	unsigned int elapsed = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret = cxd2880_stopwatch_start(&timer);
> +	if (ret)
> +		return ret;
> +
> +	for (;;) {
> +		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
> +		if (ret)
> +			return ret;
> +
> +		if (elapsed >= CXD2880_DVBT_WAIT_TS_LOCK)
> +			continue_wait = 0;
> +
> +		ret = cxd2880_tnrdmd_dvbt_check_ts_lock(tnr_dmd, &lock);
> +		if (ret)
> +			return ret;
> +
> +		switch (lock) {
> +		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
> +			return 0;
> +
> +		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
> +			return -EAGAIN;
> +
> +		default:
> +			break;
> +		}
> +
> +		ret = cxd2880_integ_check_cancellation(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (continue_wait) {
> +			ret =
> +			    cxd2880_stopwatch_sleep(&timer,
> +					    CXD2880_DVBT_WAIT_LOCK_INTVL);
> +			if (ret)
> +				return ret;
> +		} else {
> +			ret = -ETIME;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd)

I can't actually see why you want a function to wait for demod to lock,
as this is usually done in userspace.

Are there any reason why such wait can't be performed on userspace?

> +{
> +	int ret = 0;
> +	enum cxd2880_tnrdmd_lock_result lock =
> +	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +	struct cxd2880_stopwatch timer;
> +	u8 continue_wait = 1;
> +	unsigned int elapsed = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret = cxd2880_stopwatch_start(&timer);
> +	if (ret)
> +		return ret;
> +
> +	for (;;) {

No. Please use, instead:

	while (1) {
	}

as it is clearer that this is an infinite loop. Btw, extra care should
be taken with that, in order to not hang out the Kernel, specially
if the code in question is not inside a kthread.


> +		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
> +		if (ret)
> +			return ret;
> +
> +		if (elapsed >= CXD2880_DVBT_WAIT_DMD_LOCK)
> +			continue_wait = 0;
> +
> +		ret = cxd2880_tnrdmd_dvbt_check_demod_lock(tnr_dmd, &lock);
> +		if (ret)
> +			return ret;
> +
> +		switch (lock) {
> +		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
> +			return 0;
> +
> +		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
> +			return -EAGAIN;
> +
> +		default:
> +			break;
> +		}
> +
> +		ret = cxd2880_integ_check_cancellation(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (continue_wait) {
> +			ret =
> +			    cxd2880_stopwatch_sleep(&timer,
> +					    CXD2880_DVBT_WAIT_LOCK_INTVL);
> +			if (ret)
> +				return ret;
> +		} else {
> +			ret = -ETIME;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
> new file mode 100644
> index 000000000000..07f9b71a3006
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
> @@ -0,0 +1,58 @@
> +/*
> + * cxd2880_integ_dvbt.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * integration layer interface for DVB-T
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_INTEG_DVBT_H
> +#define CXD2880_INTEG_DVBT_H
> +
> +#include "cxd2880_tnrdmd.h"
> +#include "cxd2880_tnrdmd_dvbt.h"
> +#include "cxd2880_integ.h"
> +
> +#define CXD2880_DVBT_WAIT_DMD_LOCK	1000
> +#define CXD2880_DVBT_WAIT_TS_LOCK	1000
> +#define CXD2880_DVBT_WAIT_LOCK_INTVL	10
> +
> +struct cxd2880_integ_dvbt_scan_param {
> +	u32 start_frequency_khz;
> +	u32 end_frequency_khz;
> +	u32 step_frequency_khz;
> +	enum cxd2880_dtv_bandwidth bandwidth;
> +};
> +
> +struct cxd2880_integ_dvbt_scan_result {
> +	u32 center_freq_khz;
> +	int tune_result;
> +	struct cxd2880_dvbt_tune_param dvbt_tune_param;
> +};
> +
> +int cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd,
> +			    struct cxd2880_dvbt_tune_param
> +			    *tune_param);
> +
> +int cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd
> +				    *tnr_dmd);
> +
> +#endif
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
> new file mode 100644
> index 000000000000..37396a071727
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
> @@ -0,0 +1,1227 @@
> +/*
> + * cxd2880_tnrdmd_dvbt_mon.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DVB-T monitor functions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_tnrdmd_mon.h"
> +#include "cxd2880_tnrdmd_dvbt.h"
> +#include "cxd2880_tnrdmd_dvbt_mon.h"
> +
> +#include "dvb_math.h"
> +
> +static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
> +				      *tnr_dmd, u8 *sync_stat,
> +				      u8 *ts_lock_stat,
> +				      u8 *unlock_detected)
> +{
> +	u8 rdata = 0x00;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, &rdata, 1);
> +	if (ret)
> +		return ret;
> +
> +	*unlock_detected = (rdata & 0x10) ? 1 : 0;
> +	*sync_stat = rdata & 0x07;
> +	*ts_lock_stat = (rdata & 0x20) ? 1 : 0;
> +
> +	if (*sync_stat == 0x07)
> +		return -EBUSY;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
> +					  *tnr_dmd, u8 *sync_stat,
> +					  u8 *unlock_detected)
> +{
> +	u8 ts_lock_stat = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub, sync_stat,
> +					      &ts_lock_stat, unlock_detected);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
> +				       *tnr_dmd,
> +				       enum cxd2880_dvbt_mode
> +				       *mode,
> +				       enum cxd2880_dvbt_guard
> +				       *guard)
> +{
> +	u8 rdata = 0x00;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!mode) || (!guard))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = is_tps_locked(tnr_dmd);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
> +			ret =
> +			    cxd2880_tnrdmd_dvbt_mon_mode_guard(
> +					tnr_dmd->diver_sub, mode, guard);
> +
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x1b, &rdata, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	*mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03);
> +	*guard = (enum cxd2880_dvbt_guard)(rdata & 0x03);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
> +					   *tnr_dmd, int *offset)
> +{
> +	u8 rdata[4];
> +	u32 ctl_val = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!offset))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = is_tps_locked(tnr_dmd);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x1d, rdata, 4);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	ctl_val =
> +	    ((rdata[0] & 0x1f) << 24) | (rdata[1] << 16) | (rdata[2] << 8) |
> +	    (rdata[3]);
> +	*offset = cxd2880_convert2s_complement(ctl_val, 29);
> +	*offset = -1 * ((*offset) * tnr_dmd->bandwidth / 235);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
> +					       cxd2880_tnrdmd
> +					       *tnr_dmd,
> +					       int *offset)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!offset))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub, offset);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd
> +					   *tnr_dmd, u32 *ber)
> +{
> +	u8 rdata[2];
> +	u32 bit_error = 0;
> +	u32 period = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ber))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x10);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x39, rdata, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	if ((rdata[0] & 0x01) == 0) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return -EBUSY;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x22, rdata, 2);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	bit_error = (rdata[0] << 8) | rdata[1];
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x6f, rdata, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	period = ((rdata[0] & 0x07) == 0) ? 256 : (0x1000 << (rdata[0] & 0x07));
> +
> +	if ((period == 0) || (bit_error > period))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		div = period / 128;
> +
> +		Q = (bit_error * 3125) / div;
> +		R = (bit_error * 3125) % div;
> +
> +		R *= 25;
> +		Q = Q * 25 + R / div;
> +		R = R % div;
> +
> +		if (div / 2 <= R)
> +			*ber = Q + 1;
> +		else
> +			*ber = Q;
> +	}
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd
> +				      *tnr_dmd, u32 *ber)
> +{
> +	u8 rdata[3];
> +	u32 bit_error = 0;
> +	u32 period_exp = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ber))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x15, rdata, 3);
> +	if (ret)
> +		return ret;
> +
> +	if ((rdata[0] & 0x40) == 0)
> +		return -EBUSY;
> +
> +	bit_error = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2];
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x60, rdata, 1);
> +	if (ret)
> +		return ret;
> +
> +	period_exp = (rdata[0] & 0x1f);
> +
> +	if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		if (period_exp <= 8)
> +			div = (1U << period_exp) * 51;
> +		else
> +			div = (1U << 8) * 51;
> +
> +		Q = (bit_error * 250) / div;
> +		R = (bit_error * 250) % div;
> +
> +		R *= 1250;
> +		Q = Q * 1250 + R / div;
> +		R = R % div;
> +
> +		if (period_exp > 8) {
> +			*ber =
> +			    (Q + (1 << (period_exp - 9))) >> (period_exp - 8);
> +		} else {
> +			if (div / 2 <= R)
> +				*ber = Q + 1;
> +			else
> +				*ber = Q;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     struct cxd2880_dvbt_tpsinfo
> +				     *info)
> +{
> +	u8 rdata[7];
> +	u8 cell_id_ok = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!info))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = is_tps_locked(tnr_dmd);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
> +			ret =
> +			    cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd->diver_sub,
> +							     info);
> +
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x29, rdata, 7);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x11);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xd5, &cell_id_ok, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	info->constellation =
> +	    (enum cxd2880_dvbt_constellation)((rdata[0] >> 6) & 0x03);
> +	info->hierarchy = (enum cxd2880_dvbt_hierarchy)((rdata[0] >> 3) & 0x07);
> +	info->rate_hp = (enum cxd2880_dvbt_coderate)(rdata[0] & 0x07);
> +	info->rate_lp = (enum cxd2880_dvbt_coderate)((rdata[1] >> 5) & 0x07);
> +	info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03);
> +	info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03);
> +	info->fnum = (rdata[2] >> 6) & 0x03;
> +	info->length_indicator = rdata[2] & 0x3f;
> +	info->cell_id = (rdata[3] << 8) | rdata[4];
> +	info->reserved_even = rdata[5] & 0x3f;
> +	info->reserved_odd = rdata[6] & 0x3f;
> +
> +	info->cell_id_ok = cell_id_ok & 0x01;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
> +						cxd2880_tnrdmd
> +						*tnr_dmd,
> +						u32 *pen)
> +{
> +	u8 rdata[3];
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!pen))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x26, rdata, 3);
> +	if (ret)
> +		return ret;
> +
> +	if (!(rdata[0] & 0x01))
> +		return -EBUSY;
> +
> +	*pen = (rdata[1] << 8) | rdata[2];
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
> +					   *tnr_dmd,
> +					    enum
> +					    cxd2880_tnrdmd_spectrum_sense
> +					    *sense)
> +{
> +	u8 data = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!sense))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = is_tps_locked(tnr_dmd);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
> +			ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(
> +					tnr_dmd->diver_sub, sense);
> +
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x1c, &data, sizeof(data));
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	*sense =
> +	    (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
> +	    CXD2880_TNRDMD_SPECTRUM_NORMAL;
> +
> +	return ret;
> +}
> +
> +static int dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
> +			     u16 *reg_value)
> +{
> +	u8 rdata[2];
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!reg_value))
> +		return -EINVAL;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = is_tps_locked(tnr_dmd);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x13, rdata, 2);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	*reg_value = (rdata[0] << 8) | rdata[1];
> +
> +	return ret;
> +}
> +
> +static int dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
> +			 u32 reg_value, int *snr)
> +{
> +	if ((!tnr_dmd) || (!snr))
> +		return -EINVAL;
> +
> +	if (reg_value == 0)
> +		return -EBUSY;
> +
> +	if (reg_value > 4996)
> +		reg_value = 4996;
> +
> +	*snr = intlog10(reg_value) - intlog10(5350 - reg_value);
> +	*snr = (*snr + 839) / 1678 + 28500;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
> +				int *snr)
> +{
> +	u16 reg_value = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!snr))
> +		return -EINVAL;
> +
> +	*snr = -1000 * 1000;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
> +		if (ret)
> +			return ret;
> +
> +		ret = dvbt_calc_snr(tnr_dmd, reg_value, snr);
> +		if (ret)
> +			return ret;
> +	} else {
> +		int snr_main = 0;
> +		int snr_sub = 0;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main,
> +						      &snr_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
> +				      *tnr_dmd, int *snr,
> +				      int *snr_main, int *snr_sub)
> +{
> +	u16 reg_value = 0;
> +	u32 reg_value_sum = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub))
> +		return -EINVAL;
> +
> +	*snr = -1000 * 1000;
> +	*snr_main = -1000 * 1000;
> +	*snr_sub = -1000 * 1000;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
> +	if (!ret) {
> +		ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main);
> +		if (ret)
> +			reg_value = 0;
> +	} else if (ret == -EBUSY) {
> +		reg_value = 0;
> +	} else {
> +		return ret;
> +	}
> +
> +	reg_value_sum += reg_value;
> +
> +	ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
> +	if (!ret) {
> +		ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
> +		if (ret)
> +			reg_value = 0;
> +	} else if (ret == -EBUSY) {
> +		reg_value = 0;
> +	} else {
> +		return ret;
> +	}
> +
> +	reg_value_sum += reg_value;
> +
> +	ret = dvbt_calc_snr(tnr_dmd, reg_value_sum, snr);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
> +					    *tnr_dmd, int *ppm)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ppm))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	{
> +		u8 ctl_val_reg[5];
> +		u8 nominal_rate_reg[5];
> +		u32 trl_ctl_val = 0;
> +		u32 trcg_nominal_rate = 0;
> +		int num;
> +		int den;
> +		s8 diff_upper = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret = is_tps_locked(tnr_dmd);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0d);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x21, ctl_val_reg,
> +					     sizeof(ctl_val_reg));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x04);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x60, nominal_rate_reg,
> +					     sizeof(nominal_rate_reg));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		diff_upper =
> +		    (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
> +
> +		if ((diff_upper < -1) || (diff_upper > 1))
> +			return -EBUSY;
> +
> +		trl_ctl_val = ctl_val_reg[1] << 24;
> +		trl_ctl_val |= ctl_val_reg[2] << 16;
> +		trl_ctl_val |= ctl_val_reg[3] << 8;
> +		trl_ctl_val |= ctl_val_reg[4];
> +
> +		trcg_nominal_rate = nominal_rate_reg[1] << 24;
> +		trcg_nominal_rate |= nominal_rate_reg[2] << 16;
> +		trcg_nominal_rate |= nominal_rate_reg[3] << 8;
> +		trcg_nominal_rate |= nominal_rate_reg[4];
> +
> +		trl_ctl_val >>= 1;
> +		trcg_nominal_rate >>= 1;
> +
> +		if (diff_upper == 1)
> +			num =
> +			    (int)((trl_ctl_val + 0x80000000u) -
> +				  trcg_nominal_rate);
> +		else if (diff_upper == -1)
> +			num =
> +			    -(int)((trcg_nominal_rate + 0x80000000u) -
> +				   trl_ctl_val);
> +		else
> +			num = (int)(trl_ctl_val - trcg_nominal_rate);
> +
> +		den = (nominal_rate_reg[0] & 0x7f) << 24;
> +		den |= nominal_rate_reg[1] << 16;
> +		den |= nominal_rate_reg[2] << 8;
> +		den |= nominal_rate_reg[3];
> +		den = (den + (390625 / 2)) / 390625;
> +
> +		den >>= 1;
> +
> +		if (num >= 0)
> +			*ppm = (num + (den / 2)) / den;
> +		else
> +			*ppm = (num - (den / 2)) / den;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
> +						cxd2880_tnrdmd
> +						*tnr_dmd, int *ppm)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ppm))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd,
> +				    u8 *quality)
> +{
> +	struct cxd2880_dvbt_tpsinfo tps;
> +	enum cxd2880_dvbt_profile profile = CXD2880_DVBT_PROFILE_HP;
> +	u32 ber = 0;
> +	int sn = 0;
> +	int sn_rel = 0;
> +	int ber_sqi = 0;
> +
> +	static const int nordig_non_hdvbt_db_1000[3][5] = {
> +		{5100, 6900, 7900, 8900, 9700},
> +		{10800, 13100, 14600, 15600, 16000},
> +		{16500, 18700, 20200, 21600, 22500}
> +	};
> +
> +	static const int nordig_hier_hp_dvbt_db_1000[3][2][5] = {
> +		{
> +		 {9100, 12000, 13600, 15000, 16600},
> +		 {10900, 14100, 15700, 19400, 20600}
> +		 },
> +		{

As explained before, we actually use:

		}, {

Still, better to move all those static consts out of the functions,
as it improves the code reading.

> +		 {6800, 9100, 10400, 11900, 12700},
> +		 {8500, 11000, 12800, 15000, 16000}
> +		 },
> +		{
> +		 {5800, 7900, 9100, 10300, 12100},
> +		 {8000, 9300, 11600, 13000, 12900}
> +		}
> +	};
> +
> +	static const int nordig_hier_lp_dvbt_db_1000[3][2][5] = {
> +		{
> +		 {12500, 14300, 15300, 16300, 16900},
> +		 {16700, 19100, 20900, 22500, 23700}
> +		 },
> +		{
> +		 {15000, 17200, 18400, 19100, 20100},
> +		 {18500, 21200, 23600, 24700, 25900}
> +		 },
> +		{
> +		 {19500, 21400, 22500, 23700, 24700},
> +		 {21900, 24200, 25600, 26900, 27800}
> +		}
> +	};
> +
> +	int ret = 0;

no need to initialize.

> +
> +	if ((!tnr_dmd) || (!quality))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
> +	if (ret)
> +		return ret;
> +
> +	if (tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) {
> +		u8 data = 0;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x10);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x67, &data, 1);
> +		if (ret)
> +			return ret;
> +
> +		profile =
> +		    ((data & 0x01) ==
> +		     0x01) ? CXD2880_DVBT_PROFILE_LP : CXD2880_DVBT_PROFILE_HP;
> +	}
> +
> +	ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(tnr_dmd, &ber);
> +	if (ret)
> +		return ret;
> +
> +	ret = cxd2880_tnrdmd_dvbt_mon_snr(tnr_dmd, &sn);
> +	if (ret)
> +		return ret;
> +
> +	if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) ||
> +	    (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5) ||
> +	    (tps.rate_lp >= CXD2880_DVBT_CODERATE_RESERVED_5) ||
> +	    (tps.hierarchy > CXD2880_DVBT_HIERARCHY_4)) {
> +		return -EPERM;
> +	}
> +
> +	if ((tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) &&
> +	    (tps.constellation == CXD2880_DVBT_CONSTELLATION_QPSK))
> +		return -EPERM;
> +
> +	if (tps.hierarchy == CXD2880_DVBT_HIERARCHY_NON)
> +		sn_rel =
> +		    sn -
> +		    nordig_non_hdvbt_db_1000[tps.constellation][tps.rate_hp];
> +	else if (profile == CXD2880_DVBT_PROFILE_LP)
> +		sn_rel =
> +		    sn - nordig_hier_lp_dvbt_db_1000[tps.hierarchy - 1]
> +						    [tps.constellation - 1]
> +						    [tps.rate_lp];
> +	else
> +		sn_rel =
> +		    sn - nordig_hier_hp_dvbt_db_1000[tps.hierarchy - 1]
> +						    [tps.constellation - 1]
> +						    [tps.rate_hp];
> +
> +	if (ber > 10000) {
> +		ber_sqi = 0;
> +	} else if (ber > 1) {
> +		ber_sqi = (int)((intlog10(ber) + 8388) / 16777);
> +		ber_sqi = 20 * (7 * 1000 - (ber_sqi)) - 40 * 1000;
> +	} else {
> +		ber_sqi = 100 * 1000;
> +	}
> +
> +	if (sn_rel < -7 * 1000) {
> +		*quality = 0;
> +	} else if (sn_rel < 3 * 1000) {
> +		int tmp_sqi = (((sn_rel - (3 * 1000)) / 10) + 1000);
> +		*quality =
> +		    (u8)(((tmp_sqi * ber_sqi) +
> +			   (1000000 / 2)) / (1000000)) & 0xff;
> +	} else {
> +		*quality = (u8)((ber_sqi + 500) / 1000);
> +	}
> +
> +	if (*quality > 100)
> +		*quality = 100;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
> +				u32 *per)
> +{
> +	u32 packet_error = 0;
> +	u32 period = 0;
> +	u8 rdata[3];
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!per))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x18, rdata, 3);
> +	if (ret)
> +		return ret;
> +
> +	if ((rdata[0] & 0x01) == 0)
> +		return -EBUSY;
> +
> +	packet_error = (rdata[1] << 8) | rdata[2];
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x5c, rdata, 1);
> +	if (ret)
> +		return ret;
> +
> +	period = 1U << (rdata[0] & 0x0f);
> +
> +	if ((period == 0) || (packet_error > period))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		div = period;
> +
> +		Q = (packet_error * 1000) / div;
> +		R = (packet_error * 1000) % div;
> +
> +		R *= 1000;
> +		Q = Q * 1000 + R / div;
> +		R = R % div;
> +
> +		if ((div != 1) && (div / 2 <= R))
> +			*per = Q + 1;
> +		else
> +			*per = Q;
> +	}
> +
> +	return ret;
> +}
> +
> +static int dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
> +			 int rf_lvl, u8 *ssi)
> +{
> +	struct cxd2880_dvbt_tpsinfo tps;
> +	int prel;
> +	int temp_ssi = 0;
> +	int ret = 0;
> +
> +	static const int ref_dbm_1000[3][5] = {
> +		{-93000, -91000, -90000, -89000, -88000},
> +		{-87000, -85000, -84000, -83000, -82000},
> +		{-82000, -80000, -78000, -77000, -76000},
> +	};
> +
> +	if ((!tnr_dmd) || (!ssi))
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
> +	if (ret)
> +		return ret;
> +
> +	if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) ||
> +	    (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5))
> +		return -EPERM;
> +
> +	prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp];
> +
> +	if (prel < -15000)
> +		temp_ssi = 0;
> +	else if (prel < 0)
> +		temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
> +	else if (prel < 20000)
> +		temp_ssi = (((4 * prel) + 500) / 1000) + 10;
> +	else if (prel < 35000)
> +		temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
> +	else
> +		temp_ssi = 100;
> +
> +	*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
> +				u8 *ssi)
> +{
> +	int rf_lvl = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ssi))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
> +	if (ret)
> +		return ret;
> +
> +	ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				    u8 *ssi)
> +{
> +	int rf_lvl = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ssi))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
> +	if (ret)
> +		return ret;
> +
> +	ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 sync = 0;
> +	u8 tslock = 0;
> +	u8 early_unlock = 0;
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock,
> +					      &early_unlock);
> +	if (ret)
> +		return ret;
> +
> +	if (sync != 6)
> +		return -EBUSY;
> +
> +	return 0;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
> new file mode 100644
> index 000000000000..ce966270c69b
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
> @@ -0,0 +1,106 @@
> +/*
> + * cxd2880_tnrdmd_dvbt_mon.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DVB-T monitor interface
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_TNRDMD_DVBT_MON_H
> +#define CXD2880_TNRDMD_DVBT_MON_H
> +
> +#include "cxd2880_tnrdmd.h"
> +#include "cxd2880_dvbt.h"
> +
> +int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
> +				      *tnr_dmd, u8 *sync_stat,
> +				      u8 *ts_lock_stat,
> +				      u8 *unlock_detected);
> +
> +int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
> +					  *tnr_dmd, u8 *sync_stat,
> +					  u8 *unlock_detected);
> +
> +int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
> +				       *tnr_dmd,
> +				       enum cxd2880_dvbt_mode
> +				       *mode,
> +				       enum cxd2880_dvbt_guard
> +				       *guard);
> +
> +int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
> +					   *tnr_dmd, int *offset);
> +
> +int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
> +					       cxd2880_tnrdmd
> +					       *tnr_dmd,
> +					       int *offset);
> +
> +int cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd
> +					   *tnr_dmd, u32 *ber);
> +
> +int cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd
> +				      *tnr_dmd, u32 *ber);
> +
> +int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     struct cxd2880_dvbt_tpsinfo
> +				     *info);
> +
> +int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
> +						cxd2880_tnrdmd
> +						*tnr_dmd,
> +						u32 *pen);
> +
> +int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
> +					   *tnr_dmd,
> +					   enum
> +					   cxd2880_tnrdmd_spectrum_sense
> +					   *sense);
> +
> +int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
> +				int *snr);
> +
> +int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
> +				      *tnr_dmd, int *snr,
> +				      int *snr_main, int *snr_sub);
> +
> +int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
> +					    *tnr_dmd, int *ppm);
> +
> +int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
> +						cxd2880_tnrdmd
> +						*tnr_dmd,
> +						int *ppm);
> +
> +int cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd,
> +				    u8 *quality);
> +
> +int cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
> +				u32 *per);
> +
> +int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
> +				u8 *ssi);
> +
> +int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				    u8 *ssi);
> +
> +#endif



Thanks,
Mauro

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 09/14] [media] cxd2880: Add DVB-T monitor and integration layer functions
@ 2017-08-27 15:34     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 15:34 UTC (permalink / raw)
  To: Yasunari.Takiguchi-7U/KSKJipcs
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

Em Wed, 16 Aug 2017 13:41:42 +0900
<Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
> 
> Provide monitor and integration layer functions (DVB-T)
> for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.
> 
> [Change list]
> Changes in V3
>    drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
>       -changed CXD2880_SLEEP to usleep_range
>       -chnaged cxd2880_atomic_set to atomic_set
>       -modified return code
>       -modified coding style of if() 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
>       -modified return code
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
>       -removed unnecessary cast
>       -changed cxd2880_math_log to intlog10
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
>       -modified return code
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
> ---
>  .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.c     |  198 ++++
>  .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.h     |   58 +
>  .../cxd2880/cxd2880_tnrdmd_dvbt_mon.c              | 1227 ++++++++++++++++++++
>  .../cxd2880/cxd2880_tnrdmd_dvbt_mon.h              |  106 ++
>  4 files changed, 1589 insertions(+)
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
> 
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
> new file mode 100644
> index 000000000000..729cb0939203
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c
> @@ -0,0 +1,198 @@
> +/*
> + * cxd2880_integ_dvbt.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * integration layer functions for DVB-T
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_tnrdmd_dvbt.h"
> +#include "cxd2880_integ_dvbt.h"
> +
> +static int dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +int cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd,
> +			    struct cxd2880_dvbt_tune_param
> +			    *tune_param)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!tune_param))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	atomic_set(&tnr_dmd->cancel, 0);
> +
> +	if ((tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ)) {
> +		return -EOPNOTSUPP;
> +	}
> +
> +	ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000,
> +		     CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000);
> +
> +	ret = cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param);
> +	if (ret)
> +		return ret;
> +
> +	ret = dvbt_wait_demod_lock(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +	enum cxd2880_tnrdmd_lock_result lock =
> +	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +	struct cxd2880_stopwatch timer;
> +	u8 continue_wait = 1;
> +	unsigned int elapsed = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret = cxd2880_stopwatch_start(&timer);
> +	if (ret)
> +		return ret;
> +
> +	for (;;) {
> +		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
> +		if (ret)
> +			return ret;
> +
> +		if (elapsed >= CXD2880_DVBT_WAIT_TS_LOCK)
> +			continue_wait = 0;
> +
> +		ret = cxd2880_tnrdmd_dvbt_check_ts_lock(tnr_dmd, &lock);
> +		if (ret)
> +			return ret;
> +
> +		switch (lock) {
> +		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
> +			return 0;
> +
> +		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
> +			return -EAGAIN;
> +
> +		default:
> +			break;
> +		}
> +
> +		ret = cxd2880_integ_check_cancellation(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (continue_wait) {
> +			ret =
> +			    cxd2880_stopwatch_sleep(&timer,
> +					    CXD2880_DVBT_WAIT_LOCK_INTVL);
> +			if (ret)
> +				return ret;
> +		} else {
> +			ret = -ETIME;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd)

I can't actually see why you want a function to wait for demod to lock,
as this is usually done in userspace.

Are there any reason why such wait can't be performed on userspace?

> +{
> +	int ret = 0;
> +	enum cxd2880_tnrdmd_lock_result lock =
> +	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +	struct cxd2880_stopwatch timer;
> +	u8 continue_wait = 1;
> +	unsigned int elapsed = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret = cxd2880_stopwatch_start(&timer);
> +	if (ret)
> +		return ret;
> +
> +	for (;;) {

No. Please use, instead:

	while (1) {
	}

as it is clearer that this is an infinite loop. Btw, extra care should
be taken with that, in order to not hang out the Kernel, specially
if the code in question is not inside a kthread.


> +		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
> +		if (ret)
> +			return ret;
> +
> +		if (elapsed >= CXD2880_DVBT_WAIT_DMD_LOCK)
> +			continue_wait = 0;
> +
> +		ret = cxd2880_tnrdmd_dvbt_check_demod_lock(tnr_dmd, &lock);
> +		if (ret)
> +			return ret;
> +
> +		switch (lock) {
> +		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
> +			return 0;
> +
> +		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
> +			return -EAGAIN;
> +
> +		default:
> +			break;
> +		}
> +
> +		ret = cxd2880_integ_check_cancellation(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (continue_wait) {
> +			ret =
> +			    cxd2880_stopwatch_sleep(&timer,
> +					    CXD2880_DVBT_WAIT_LOCK_INTVL);
> +			if (ret)
> +				return ret;
> +		} else {
> +			ret = -ETIME;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
> new file mode 100644
> index 000000000000..07f9b71a3006
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.h
> @@ -0,0 +1,58 @@
> +/*
> + * cxd2880_integ_dvbt.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * integration layer interface for DVB-T
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_INTEG_DVBT_H
> +#define CXD2880_INTEG_DVBT_H
> +
> +#include "cxd2880_tnrdmd.h"
> +#include "cxd2880_tnrdmd_dvbt.h"
> +#include "cxd2880_integ.h"
> +
> +#define CXD2880_DVBT_WAIT_DMD_LOCK	1000
> +#define CXD2880_DVBT_WAIT_TS_LOCK	1000
> +#define CXD2880_DVBT_WAIT_LOCK_INTVL	10
> +
> +struct cxd2880_integ_dvbt_scan_param {
> +	u32 start_frequency_khz;
> +	u32 end_frequency_khz;
> +	u32 step_frequency_khz;
> +	enum cxd2880_dtv_bandwidth bandwidth;
> +};
> +
> +struct cxd2880_integ_dvbt_scan_result {
> +	u32 center_freq_khz;
> +	int tune_result;
> +	struct cxd2880_dvbt_tune_param dvbt_tune_param;
> +};
> +
> +int cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd,
> +			    struct cxd2880_dvbt_tune_param
> +			    *tune_param);
> +
> +int cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd
> +				    *tnr_dmd);
> +
> +#endif
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
> new file mode 100644
> index 000000000000..37396a071727
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
> @@ -0,0 +1,1227 @@
> +/*
> + * cxd2880_tnrdmd_dvbt_mon.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DVB-T monitor functions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_tnrdmd_mon.h"
> +#include "cxd2880_tnrdmd_dvbt.h"
> +#include "cxd2880_tnrdmd_dvbt_mon.h"
> +
> +#include "dvb_math.h"
> +
> +static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
> +				      *tnr_dmd, u8 *sync_stat,
> +				      u8 *ts_lock_stat,
> +				      u8 *unlock_detected)
> +{
> +	u8 rdata = 0x00;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, &rdata, 1);
> +	if (ret)
> +		return ret;
> +
> +	*unlock_detected = (rdata & 0x10) ? 1 : 0;
> +	*sync_stat = rdata & 0x07;
> +	*ts_lock_stat = (rdata & 0x20) ? 1 : 0;
> +
> +	if (*sync_stat == 0x07)
> +		return -EBUSY;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
> +					  *tnr_dmd, u8 *sync_stat,
> +					  u8 *unlock_detected)
> +{
> +	u8 ts_lock_stat = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub, sync_stat,
> +					      &ts_lock_stat, unlock_detected);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
> +				       *tnr_dmd,
> +				       enum cxd2880_dvbt_mode
> +				       *mode,
> +				       enum cxd2880_dvbt_guard
> +				       *guard)
> +{
> +	u8 rdata = 0x00;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!mode) || (!guard))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = is_tps_locked(tnr_dmd);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
> +			ret =
> +			    cxd2880_tnrdmd_dvbt_mon_mode_guard(
> +					tnr_dmd->diver_sub, mode, guard);
> +
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x1b, &rdata, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	*mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03);
> +	*guard = (enum cxd2880_dvbt_guard)(rdata & 0x03);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
> +					   *tnr_dmd, int *offset)
> +{
> +	u8 rdata[4];
> +	u32 ctl_val = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!offset))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = is_tps_locked(tnr_dmd);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x1d, rdata, 4);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	ctl_val =
> +	    ((rdata[0] & 0x1f) << 24) | (rdata[1] << 16) | (rdata[2] << 8) |
> +	    (rdata[3]);
> +	*offset = cxd2880_convert2s_complement(ctl_val, 29);
> +	*offset = -1 * ((*offset) * tnr_dmd->bandwidth / 235);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
> +					       cxd2880_tnrdmd
> +					       *tnr_dmd,
> +					       int *offset)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!offset))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub, offset);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd
> +					   *tnr_dmd, u32 *ber)
> +{
> +	u8 rdata[2];
> +	u32 bit_error = 0;
> +	u32 period = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ber))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x10);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x39, rdata, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	if ((rdata[0] & 0x01) == 0) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return -EBUSY;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x22, rdata, 2);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	bit_error = (rdata[0] << 8) | rdata[1];
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x6f, rdata, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	period = ((rdata[0] & 0x07) == 0) ? 256 : (0x1000 << (rdata[0] & 0x07));
> +
> +	if ((period == 0) || (bit_error > period))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		div = period / 128;
> +
> +		Q = (bit_error * 3125) / div;
> +		R = (bit_error * 3125) % div;
> +
> +		R *= 25;
> +		Q = Q * 25 + R / div;
> +		R = R % div;
> +
> +		if (div / 2 <= R)
> +			*ber = Q + 1;
> +		else
> +			*ber = Q;
> +	}
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd
> +				      *tnr_dmd, u32 *ber)
> +{
> +	u8 rdata[3];
> +	u32 bit_error = 0;
> +	u32 period_exp = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ber))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x15, rdata, 3);
> +	if (ret)
> +		return ret;
> +
> +	if ((rdata[0] & 0x40) == 0)
> +		return -EBUSY;
> +
> +	bit_error = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2];
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x60, rdata, 1);
> +	if (ret)
> +		return ret;
> +
> +	period_exp = (rdata[0] & 0x1f);
> +
> +	if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		if (period_exp <= 8)
> +			div = (1U << period_exp) * 51;
> +		else
> +			div = (1U << 8) * 51;
> +
> +		Q = (bit_error * 250) / div;
> +		R = (bit_error * 250) % div;
> +
> +		R *= 1250;
> +		Q = Q * 1250 + R / div;
> +		R = R % div;
> +
> +		if (period_exp > 8) {
> +			*ber =
> +			    (Q + (1 << (period_exp - 9))) >> (period_exp - 8);
> +		} else {
> +			if (div / 2 <= R)
> +				*ber = Q + 1;
> +			else
> +				*ber = Q;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     struct cxd2880_dvbt_tpsinfo
> +				     *info)
> +{
> +	u8 rdata[7];
> +	u8 cell_id_ok = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!info))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = is_tps_locked(tnr_dmd);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
> +			ret =
> +			    cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd->diver_sub,
> +							     info);
> +
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x29, rdata, 7);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x11);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xd5, &cell_id_ok, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	info->constellation =
> +	    (enum cxd2880_dvbt_constellation)((rdata[0] >> 6) & 0x03);
> +	info->hierarchy = (enum cxd2880_dvbt_hierarchy)((rdata[0] >> 3) & 0x07);
> +	info->rate_hp = (enum cxd2880_dvbt_coderate)(rdata[0] & 0x07);
> +	info->rate_lp = (enum cxd2880_dvbt_coderate)((rdata[1] >> 5) & 0x07);
> +	info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03);
> +	info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03);
> +	info->fnum = (rdata[2] >> 6) & 0x03;
> +	info->length_indicator = rdata[2] & 0x3f;
> +	info->cell_id = (rdata[3] << 8) | rdata[4];
> +	info->reserved_even = rdata[5] & 0x3f;
> +	info->reserved_odd = rdata[6] & 0x3f;
> +
> +	info->cell_id_ok = cell_id_ok & 0x01;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
> +						cxd2880_tnrdmd
> +						*tnr_dmd,
> +						u32 *pen)
> +{
> +	u8 rdata[3];
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!pen))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x26, rdata, 3);
> +	if (ret)
> +		return ret;
> +
> +	if (!(rdata[0] & 0x01))
> +		return -EBUSY;
> +
> +	*pen = (rdata[1] << 8) | rdata[2];
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
> +					   *tnr_dmd,
> +					    enum
> +					    cxd2880_tnrdmd_spectrum_sense
> +					    *sense)
> +{
> +	u8 data = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!sense))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = is_tps_locked(tnr_dmd);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
> +			ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(
> +					tnr_dmd->diver_sub, sense);
> +
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x1c, &data, sizeof(data));
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	*sense =
> +	    (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
> +	    CXD2880_TNRDMD_SPECTRUM_NORMAL;
> +
> +	return ret;
> +}
> +
> +static int dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
> +			     u16 *reg_value)
> +{
> +	u8 rdata[2];
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!reg_value))
> +		return -EINVAL;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = is_tps_locked(tnr_dmd);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x13, rdata, 2);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	*reg_value = (rdata[0] << 8) | rdata[1];
> +
> +	return ret;
> +}
> +
> +static int dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
> +			 u32 reg_value, int *snr)
> +{
> +	if ((!tnr_dmd) || (!snr))
> +		return -EINVAL;
> +
> +	if (reg_value == 0)
> +		return -EBUSY;
> +
> +	if (reg_value > 4996)
> +		reg_value = 4996;
> +
> +	*snr = intlog10(reg_value) - intlog10(5350 - reg_value);
> +	*snr = (*snr + 839) / 1678 + 28500;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
> +				int *snr)
> +{
> +	u16 reg_value = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!snr))
> +		return -EINVAL;
> +
> +	*snr = -1000 * 1000;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
> +		if (ret)
> +			return ret;
> +
> +		ret = dvbt_calc_snr(tnr_dmd, reg_value, snr);
> +		if (ret)
> +			return ret;
> +	} else {
> +		int snr_main = 0;
> +		int snr_sub = 0;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main,
> +						      &snr_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
> +				      *tnr_dmd, int *snr,
> +				      int *snr_main, int *snr_sub)
> +{
> +	u16 reg_value = 0;
> +	u32 reg_value_sum = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub))
> +		return -EINVAL;
> +
> +	*snr = -1000 * 1000;
> +	*snr_main = -1000 * 1000;
> +	*snr_sub = -1000 * 1000;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
> +	if (!ret) {
> +		ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main);
> +		if (ret)
> +			reg_value = 0;
> +	} else if (ret == -EBUSY) {
> +		reg_value = 0;
> +	} else {
> +		return ret;
> +	}
> +
> +	reg_value_sum += reg_value;
> +
> +	ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
> +	if (!ret) {
> +		ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
> +		if (ret)
> +			reg_value = 0;
> +	} else if (ret == -EBUSY) {
> +		reg_value = 0;
> +	} else {
> +		return ret;
> +	}
> +
> +	reg_value_sum += reg_value;
> +
> +	ret = dvbt_calc_snr(tnr_dmd, reg_value_sum, snr);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
> +					    *tnr_dmd, int *ppm)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ppm))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	{
> +		u8 ctl_val_reg[5];
> +		u8 nominal_rate_reg[5];
> +		u32 trl_ctl_val = 0;
> +		u32 trcg_nominal_rate = 0;
> +		int num;
> +		int den;
> +		s8 diff_upper = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret = is_tps_locked(tnr_dmd);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0d);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x21, ctl_val_reg,
> +					     sizeof(ctl_val_reg));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x04);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x60, nominal_rate_reg,
> +					     sizeof(nominal_rate_reg));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		diff_upper =
> +		    (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
> +
> +		if ((diff_upper < -1) || (diff_upper > 1))
> +			return -EBUSY;
> +
> +		trl_ctl_val = ctl_val_reg[1] << 24;
> +		trl_ctl_val |= ctl_val_reg[2] << 16;
> +		trl_ctl_val |= ctl_val_reg[3] << 8;
> +		trl_ctl_val |= ctl_val_reg[4];
> +
> +		trcg_nominal_rate = nominal_rate_reg[1] << 24;
> +		trcg_nominal_rate |= nominal_rate_reg[2] << 16;
> +		trcg_nominal_rate |= nominal_rate_reg[3] << 8;
> +		trcg_nominal_rate |= nominal_rate_reg[4];
> +
> +		trl_ctl_val >>= 1;
> +		trcg_nominal_rate >>= 1;
> +
> +		if (diff_upper == 1)
> +			num =
> +			    (int)((trl_ctl_val + 0x80000000u) -
> +				  trcg_nominal_rate);
> +		else if (diff_upper == -1)
> +			num =
> +			    -(int)((trcg_nominal_rate + 0x80000000u) -
> +				   trl_ctl_val);
> +		else
> +			num = (int)(trl_ctl_val - trcg_nominal_rate);
> +
> +		den = (nominal_rate_reg[0] & 0x7f) << 24;
> +		den |= nominal_rate_reg[1] << 16;
> +		den |= nominal_rate_reg[2] << 8;
> +		den |= nominal_rate_reg[3];
> +		den = (den + (390625 / 2)) / 390625;
> +
> +		den >>= 1;
> +
> +		if (num >= 0)
> +			*ppm = (num + (den / 2)) / den;
> +		else
> +			*ppm = (num - (den / 2)) / den;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
> +						cxd2880_tnrdmd
> +						*tnr_dmd, int *ppm)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ppm))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd,
> +				    u8 *quality)
> +{
> +	struct cxd2880_dvbt_tpsinfo tps;
> +	enum cxd2880_dvbt_profile profile = CXD2880_DVBT_PROFILE_HP;
> +	u32 ber = 0;
> +	int sn = 0;
> +	int sn_rel = 0;
> +	int ber_sqi = 0;
> +
> +	static const int nordig_non_hdvbt_db_1000[3][5] = {
> +		{5100, 6900, 7900, 8900, 9700},
> +		{10800, 13100, 14600, 15600, 16000},
> +		{16500, 18700, 20200, 21600, 22500}
> +	};
> +
> +	static const int nordig_hier_hp_dvbt_db_1000[3][2][5] = {
> +		{
> +		 {9100, 12000, 13600, 15000, 16600},
> +		 {10900, 14100, 15700, 19400, 20600}
> +		 },
> +		{

As explained before, we actually use:

		}, {

Still, better to move all those static consts out of the functions,
as it improves the code reading.

> +		 {6800, 9100, 10400, 11900, 12700},
> +		 {8500, 11000, 12800, 15000, 16000}
> +		 },
> +		{
> +		 {5800, 7900, 9100, 10300, 12100},
> +		 {8000, 9300, 11600, 13000, 12900}
> +		}
> +	};
> +
> +	static const int nordig_hier_lp_dvbt_db_1000[3][2][5] = {
> +		{
> +		 {12500, 14300, 15300, 16300, 16900},
> +		 {16700, 19100, 20900, 22500, 23700}
> +		 },
> +		{
> +		 {15000, 17200, 18400, 19100, 20100},
> +		 {18500, 21200, 23600, 24700, 25900}
> +		 },
> +		{
> +		 {19500, 21400, 22500, 23700, 24700},
> +		 {21900, 24200, 25600, 26900, 27800}
> +		}
> +	};
> +
> +	int ret = 0;

no need to initialize.

> +
> +	if ((!tnr_dmd) || (!quality))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
> +	if (ret)
> +		return ret;
> +
> +	if (tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) {
> +		u8 data = 0;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x10);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x67, &data, 1);
> +		if (ret)
> +			return ret;
> +
> +		profile =
> +		    ((data & 0x01) ==
> +		     0x01) ? CXD2880_DVBT_PROFILE_LP : CXD2880_DVBT_PROFILE_HP;
> +	}
> +
> +	ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(tnr_dmd, &ber);
> +	if (ret)
> +		return ret;
> +
> +	ret = cxd2880_tnrdmd_dvbt_mon_snr(tnr_dmd, &sn);
> +	if (ret)
> +		return ret;
> +
> +	if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) ||
> +	    (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5) ||
> +	    (tps.rate_lp >= CXD2880_DVBT_CODERATE_RESERVED_5) ||
> +	    (tps.hierarchy > CXD2880_DVBT_HIERARCHY_4)) {
> +		return -EPERM;
> +	}
> +
> +	if ((tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) &&
> +	    (tps.constellation == CXD2880_DVBT_CONSTELLATION_QPSK))
> +		return -EPERM;
> +
> +	if (tps.hierarchy == CXD2880_DVBT_HIERARCHY_NON)
> +		sn_rel =
> +		    sn -
> +		    nordig_non_hdvbt_db_1000[tps.constellation][tps.rate_hp];
> +	else if (profile == CXD2880_DVBT_PROFILE_LP)
> +		sn_rel =
> +		    sn - nordig_hier_lp_dvbt_db_1000[tps.hierarchy - 1]
> +						    [tps.constellation - 1]
> +						    [tps.rate_lp];
> +	else
> +		sn_rel =
> +		    sn - nordig_hier_hp_dvbt_db_1000[tps.hierarchy - 1]
> +						    [tps.constellation - 1]
> +						    [tps.rate_hp];
> +
> +	if (ber > 10000) {
> +		ber_sqi = 0;
> +	} else if (ber > 1) {
> +		ber_sqi = (int)((intlog10(ber) + 8388) / 16777);
> +		ber_sqi = 20 * (7 * 1000 - (ber_sqi)) - 40 * 1000;
> +	} else {
> +		ber_sqi = 100 * 1000;
> +	}
> +
> +	if (sn_rel < -7 * 1000) {
> +		*quality = 0;
> +	} else if (sn_rel < 3 * 1000) {
> +		int tmp_sqi = (((sn_rel - (3 * 1000)) / 10) + 1000);
> +		*quality =
> +		    (u8)(((tmp_sqi * ber_sqi) +
> +			   (1000000 / 2)) / (1000000)) & 0xff;
> +	} else {
> +		*quality = (u8)((ber_sqi + 500) / 1000);
> +	}
> +
> +	if (*quality > 100)
> +		*quality = 100;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
> +				u32 *per)
> +{
> +	u32 packet_error = 0;
> +	u32 period = 0;
> +	u8 rdata[3];
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!per))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0d);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x18, rdata, 3);
> +	if (ret)
> +		return ret;
> +
> +	if ((rdata[0] & 0x01) == 0)
> +		return -EBUSY;
> +
> +	packet_error = (rdata[1] << 8) | rdata[2];
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x10);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x5c, rdata, 1);
> +	if (ret)
> +		return ret;
> +
> +	period = 1U << (rdata[0] & 0x0f);
> +
> +	if ((period == 0) || (packet_error > period))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		div = period;
> +
> +		Q = (packet_error * 1000) / div;
> +		R = (packet_error * 1000) % div;
> +
> +		R *= 1000;
> +		Q = Q * 1000 + R / div;
> +		R = R % div;
> +
> +		if ((div != 1) && (div / 2 <= R))
> +			*per = Q + 1;
> +		else
> +			*per = Q;
> +	}
> +
> +	return ret;
> +}
> +
> +static int dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
> +			 int rf_lvl, u8 *ssi)
> +{
> +	struct cxd2880_dvbt_tpsinfo tps;
> +	int prel;
> +	int temp_ssi = 0;
> +	int ret = 0;
> +
> +	static const int ref_dbm_1000[3][5] = {
> +		{-93000, -91000, -90000, -89000, -88000},
> +		{-87000, -85000, -84000, -83000, -82000},
> +		{-82000, -80000, -78000, -77000, -76000},
> +	};
> +
> +	if ((!tnr_dmd) || (!ssi))
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
> +	if (ret)
> +		return ret;
> +
> +	if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) ||
> +	    (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5))
> +		return -EPERM;
> +
> +	prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp];
> +
> +	if (prel < -15000)
> +		temp_ssi = 0;
> +	else if (prel < 0)
> +		temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
> +	else if (prel < 20000)
> +		temp_ssi = (((4 * prel) + 500) / 1000) + 10;
> +	else if (prel < 35000)
> +		temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
> +	else
> +		temp_ssi = 100;
> +
> +	*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
> +				u8 *ssi)
> +{
> +	int rf_lvl = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ssi))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
> +	if (ret)
> +		return ret;
> +
> +	ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				    u8 *ssi)
> +{
> +	int rf_lvl = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ssi))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
> +	if (ret)
> +		return ret;
> +
> +	ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	u8 sync = 0;
> +	u8 tslock = 0;
> +	u8 early_unlock = 0;
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock,
> +					      &early_unlock);
> +	if (ret)
> +		return ret;
> +
> +	if (sync != 6)
> +		return -EBUSY;
> +
> +	return 0;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
> new file mode 100644
> index 000000000000..ce966270c69b
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.h
> @@ -0,0 +1,106 @@
> +/*
> + * cxd2880_tnrdmd_dvbt_mon.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DVB-T monitor interface
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_TNRDMD_DVBT_MON_H
> +#define CXD2880_TNRDMD_DVBT_MON_H
> +
> +#include "cxd2880_tnrdmd.h"
> +#include "cxd2880_dvbt.h"
> +
> +int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
> +				      *tnr_dmd, u8 *sync_stat,
> +				      u8 *ts_lock_stat,
> +				      u8 *unlock_detected);
> +
> +int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
> +					  *tnr_dmd, u8 *sync_stat,
> +					  u8 *unlock_detected);
> +
> +int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
> +				       *tnr_dmd,
> +				       enum cxd2880_dvbt_mode
> +				       *mode,
> +				       enum cxd2880_dvbt_guard
> +				       *guard);
> +
> +int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
> +					   *tnr_dmd, int *offset);
> +
> +int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
> +					       cxd2880_tnrdmd
> +					       *tnr_dmd,
> +					       int *offset);
> +
> +int cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd
> +					   *tnr_dmd, u32 *ber);
> +
> +int cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd
> +				      *tnr_dmd, u32 *ber);
> +
> +int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     struct cxd2880_dvbt_tpsinfo
> +				     *info);
> +
> +int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
> +						cxd2880_tnrdmd
> +						*tnr_dmd,
> +						u32 *pen);
> +
> +int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
> +					   *tnr_dmd,
> +					   enum
> +					   cxd2880_tnrdmd_spectrum_sense
> +					   *sense);
> +
> +int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
> +				int *snr);
> +
> +int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
> +				      *tnr_dmd, int *snr,
> +				      int *snr_main, int *snr_sub);
> +
> +int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
> +					    *tnr_dmd, int *ppm);
> +
> +int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
> +						cxd2880_tnrdmd
> +						*tnr_dmd,
> +						int *ppm);
> +
> +int cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd,
> +				    u8 *quality);
> +
> +int cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
> +				u32 *per);
> +
> +int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
> +				u8 *ssi);
> +
> +int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
> +				    u8 *ssi);
> +
> +#endif



Thanks,
Mauro

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 10/14] [media] cxd2880: Add DVB-T2 control functions for the driver
@ 2017-08-27 15:38     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 15:38 UTC (permalink / raw)
  To: Yasunari.Takiguchi
  Cc: linux-kernel, devicetree, linux-media, tbird20d, frowand.list,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

Em Wed, 16 Aug 2017 13:42:32 +0900
<Yasunari.Takiguchi@sony.com> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> 
> Provide definitions, interfaces and functions needed for DVB-T2
> of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.
> 
> [Change list]
> Changes in V3
>    drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
>       -modified return code
>       -modified coding style of if() 
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
>       -modified return code
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
> ---
>  .../media/dvb-frontends/cxd2880/cxd2880_dvbt2.h    |  402 ++++++
>  .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c   | 1359 ++++++++++++++++++++
>  .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h   |   82 ++
>  3 files changed, 1843 insertions(+)
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
> 
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
> new file mode 100644
> index 000000000000..674ed17deef5
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
> @@ -0,0 +1,402 @@
> +/*
> + * cxd2880_dvbt2.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DVB-T2 related definitions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_DVBT2_H
> +#define CXD2880_DVBT2_H
> +
> +#include "cxd2880_common.h"
> +
> +enum cxd2880_dvbt2_profile {
> +	CXD2880_DVBT2_PROFILE_BASE,
> +	CXD2880_DVBT2_PROFILE_LITE,
> +	CXD2880_DVBT2_PROFILE_ANY
> +};
> +
> +enum cxd2880_dvbt2_version {
> +	CXD2880_DVBT2_V111,
> +	CXD2880_DVBT2_V121,
> +	CXD2880_DVBT2_V131
> +};
> +
> +enum cxd2880_dvbt2_s1 {
> +	CXD2880_DVBT2_S1_BASE_SISO = 0x00,
> +	CXD2880_DVBT2_S1_BASE_MISO = 0x01,
> +	CXD2880_DVBT2_S1_NON_DVBT2 = 0x02,
> +	CXD2880_DVBT2_S1_LITE_SISO = 0x03,
> +	CXD2880_DVBT2_S1_LITE_MISO = 0x04,
> +	CXD2880_DVBT2_S1_RSVD3 = 0x05,
> +	CXD2880_DVBT2_S1_RSVD4 = 0x06,
> +	CXD2880_DVBT2_S1_RSVD5 = 0x07,
> +	CXD2880_DVBT2_S1_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_base_s2 {
> +	CXD2880_DVBT2_BASE_S2_M2K_G_ANY = 0x00,
> +	CXD2880_DVBT2_BASE_S2_M8K_G_DVBT = 0x01,
> +	CXD2880_DVBT2_BASE_S2_M4K_G_ANY = 0x02,
> +	CXD2880_DVBT2_BASE_S2_M1K_G_ANY = 0x03,
> +	CXD2880_DVBT2_BASE_S2_M16K_G_ANY = 0x04,
> +	CXD2880_DVBT2_BASE_S2_M32K_G_DVBT = 0x05,
> +	CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2 = 0x06,
> +	CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2 = 0x07,
> +	CXD2880_DVBT2_BASE_S2_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_lite_s2 {
> +	CXD2880_DVBT2_LITE_S2_M2K_G_ANY = 0x00,
> +	CXD2880_DVBT2_LITE_S2_M8K_G_DVBT = 0x01,
> +	CXD2880_DVBT2_LITE_S2_M4K_G_ANY = 0x02,
> +	CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2 = 0x03,
> +	CXD2880_DVBT2_LITE_S2_M16K_G_DVBT = 0x04,
> +	CXD2880_DVBT2_LITE_S2_RSVD1 = 0x05,
> +	CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2 = 0x06,
> +	CXD2880_DVBT2_LITE_S2_RSVD2 = 0x07,
> +	CXD2880_DVBT2_LITE_S2_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_guard {
> +	CXD2880_DVBT2_G1_32 = 0x00,
> +	CXD2880_DVBT2_G1_16 = 0x01,
> +	CXD2880_DVBT2_G1_8 = 0x02,
> +	CXD2880_DVBT2_G1_4 = 0x03,
> +	CXD2880_DVBT2_G1_128 = 0x04,
> +	CXD2880_DVBT2_G19_128 = 0x05,
> +	CXD2880_DVBT2_G19_256 = 0x06,
> +	CXD2880_DVBT2_G_RSVD1 = 0x07,
> +	CXD2880_DVBT2_G_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_mode {
> +	CXD2880_DVBT2_M2K = 0x00,
> +	CXD2880_DVBT2_M8K = 0x01,
> +	CXD2880_DVBT2_M4K = 0x02,
> +	CXD2880_DVBT2_M1K = 0x03,
> +	CXD2880_DVBT2_M16K = 0x04,
> +	CXD2880_DVBT2_M32K = 0x05,
> +	CXD2880_DVBT2_M_RSVD1 = 0x06,
> +	CXD2880_DVBT2_M_RSVD2 = 0x07
> +};
> +
> +enum cxd2880_dvbt2_bw {
> +	CXD2880_DVBT2_BW_8 = 0x00,
> +	CXD2880_DVBT2_BW_7 = 0x01,
> +	CXD2880_DVBT2_BW_6 = 0x02,
> +	CXD2880_DVBT2_BW_5 = 0x03,
> +	CXD2880_DVBT2_BW_10 = 0x04,
> +	CXD2880_DVBT2_BW_1_7 = 0x05,
> +	CXD2880_DVBT2_BW_RSVD1 = 0x06,
> +	CXD2880_DVBT2_BW_RSVD2 = 0x07,
> +	CXD2880_DVBT2_BW_RSVD3 = 0x08,
> +	CXD2880_DVBT2_BW_RSVD4 = 0x09,
> +	CXD2880_DVBT2_BW_RSVD5 = 0x0a,
> +	CXD2880_DVBT2_BW_RSVD6 = 0x0b,
> +	CXD2880_DVBT2_BW_RSVD7 = 0x0c,
> +	CXD2880_DVBT2_BW_RSVD8 = 0x0d,
> +	CXD2880_DVBT2_BW_RSVD9 = 0x0e,
> +	CXD2880_DVBT2_BW_RSVD10 = 0x0f,
> +	CXD2880_DVBT2_BW_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_l1pre_type {
> +	CXD2880_DVBT2_L1PRE_TYPE_TS = 0x00,
> +	CXD2880_DVBT2_L1PRE_TYPE_GS = 0x01,
> +	CXD2880_DVBT2_L1PRE_TYPE_TS_GS = 0x02,
> +	CXD2880_DVBT2_L1PRE_TYPE_RESERVED = 0x03,
> +	CXD2880_DVBT2_L1PRE_TYPE_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_papr {
> +	CXD2880_DVBT2_PAPR_0 = 0x00,
> +	CXD2880_DVBT2_PAPR_1 = 0x01,
> +	CXD2880_DVBT2_PAPR_2 = 0x02,
> +	CXD2880_DVBT2_PAPR_3 = 0x03,
> +	CXD2880_DVBT2_PAPR_RSVD1 = 0x04,
> +	CXD2880_DVBT2_PAPR_RSVD2 = 0x05,
> +	CXD2880_DVBT2_PAPR_RSVD3 = 0x06,
> +	CXD2880_DVBT2_PAPR_RSVD4 = 0x07,
> +	CXD2880_DVBT2_PAPR_RSVD5 = 0x08,
> +	CXD2880_DVBT2_PAPR_RSVD6 = 0x09,
> +	CXD2880_DVBT2_PAPR_RSVD7 = 0x0a,
> +	CXD2880_DVBT2_PAPR_RSVD8 = 0x0b,
> +	CXD2880_DVBT2_PAPR_RSVD9 = 0x0c,
> +	CXD2880_DVBT2_PAPR_RSVD10 = 0x0d,
> +	CXD2880_DVBT2_PAPR_RSVD11 = 0x0e,
> +	CXD2880_DVBT2_PAPR_RSVD12 = 0x0f,
> +	CXD2880_DVBT2_PAPR_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_l1post_constell {
> +	CXD2880_DVBT2_L1POST_BPSK = 0x00,
> +	CXD2880_DVBT2_L1POST_QPSK = 0x01,
> +	CXD2880_DVBT2_L1POST_QAM16 = 0x02,
> +	CXD2880_DVBT2_L1POST_QAM64 = 0x03,
> +	CXD2880_DVBT2_L1POST_C_RSVD1 = 0x04,
> +	CXD2880_DVBT2_L1POST_C_RSVD2 = 0x05,
> +	CXD2880_DVBT2_L1POST_C_RSVD3 = 0x06,
> +	CXD2880_DVBT2_L1POST_C_RSVD4 = 0x07,
> +	CXD2880_DVBT2_L1POST_C_RSVD5 = 0x08,
> +	CXD2880_DVBT2_L1POST_C_RSVD6 = 0x09,
> +	CXD2880_DVBT2_L1POST_C_RSVD7 = 0x0a,
> +	CXD2880_DVBT2_L1POST_C_RSVD8 = 0x0b,
> +	CXD2880_DVBT2_L1POST_C_RSVD9 = 0x0c,
> +	CXD2880_DVBT2_L1POST_C_RSVD10 = 0x0d,
> +	CXD2880_DVBT2_L1POST_C_RSVD11 = 0x0e,
> +	CXD2880_DVBT2_L1POST_C_RSVD12 = 0x0f,
> +	CXD2880_DVBT2_L1POST_CONSTELL_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_l1post_cr {
> +	CXD2880_DVBT2_L1POST_R1_2 = 0x00,
> +	CXD2880_DVBT2_L1POST_R_RSVD1 = 0x01,
> +	CXD2880_DVBT2_L1POST_R_RSVD2 = 0x02,
> +	CXD2880_DVBT2_L1POST_R_RSVD3 = 0x03,
> +	CXD2880_DVBT2_L1POST_R_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_l1post_fec_type {
> +	CXD2880_DVBT2_L1POST_FEC_LDPC16K = 0x00,
> +	CXD2880_DVBT2_L1POST_FEC_RSVD1 = 0x01,
> +	CXD2880_DVBT2_L1POST_FEC_RSVD2 = 0x02,
> +	CXD2880_DVBT2_L1POST_FEC_RSVD3 = 0x03,
> +	CXD2880_DVBT2_L1POST_FEC_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_pp {
> +	CXD2880_DVBT2_PP1 = 0x00,
> +	CXD2880_DVBT2_PP2 = 0x01,
> +	CXD2880_DVBT2_PP3 = 0x02,
> +	CXD2880_DVBT2_PP4 = 0x03,
> +	CXD2880_DVBT2_PP5 = 0x04,
> +	CXD2880_DVBT2_PP6 = 0x05,
> +	CXD2880_DVBT2_PP7 = 0x06,
> +	CXD2880_DVBT2_PP8 = 0x07,
> +	CXD2880_DVBT2_PP_RSVD1 = 0x08,
> +	CXD2880_DVBT2_PP_RSVD2 = 0x09,
> +	CXD2880_DVBT2_PP_RSVD3 = 0x0a,
> +	CXD2880_DVBT2_PP_RSVD4 = 0x0b,
> +	CXD2880_DVBT2_PP_RSVD5 = 0x0c,
> +	CXD2880_DVBT2_PP_RSVD6 = 0x0d,
> +	CXD2880_DVBT2_PP_RSVD7 = 0x0e,
> +	CXD2880_DVBT2_PP_RSVD8 = 0x0f,
> +	CXD2880_DVBT2_PP_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_code_rate {
> +	CXD2880_DVBT2_R1_2 = 0x00,
> +	CXD2880_DVBT2_R3_5 = 0x01,
> +	CXD2880_DVBT2_R2_3 = 0x02,
> +	CXD2880_DVBT2_R3_4 = 0x03,
> +	CXD2880_DVBT2_R4_5 = 0x04,
> +	CXD2880_DVBT2_R5_6 = 0x05,
> +	CXD2880_DVBT2_R1_3 = 0x06,
> +	CXD2880_DVBT2_R2_5 = 0x07,
> +	CXD2880_DVBT2_PLP_CR_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_constell {
> +	CXD2880_DVBT2_QPSK = 0x00,
> +	CXD2880_DVBT2_QAM16 = 0x01,
> +	CXD2880_DVBT2_QAM64 = 0x02,
> +	CXD2880_DVBT2_QAM256 = 0x03,
> +	CXD2880_DVBT2_CON_RSVD1 = 0x04,
> +	CXD2880_DVBT2_CON_RSVD2 = 0x05,
> +	CXD2880_DVBT2_CON_RSVD3 = 0x06,
> +	CXD2880_DVBT2_CON_RSVD4 = 0x07,
> +	CXD2880_DVBT2_CONSTELL_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_type {
> +	CXD2880_DVBT2_PLP_TYPE_COMMON = 0x00,
> +	CXD2880_DVBT2_PLP_TYPE_DATA1 = 0x01,
> +	CXD2880_DVBT2_PLP_TYPE_DATA2 = 0x02,
> +	CXD2880_DVBT2_PLP_TYPE_RSVD1 = 0x03,
> +	CXD2880_DVBT2_PLP_TYPE_RSVD2 = 0x04,
> +	CXD2880_DVBT2_PLP_TYPE_RSVD3 = 0x05,
> +	CXD2880_DVBT2_PLP_TYPE_RSVD4 = 0x06,
> +	CXD2880_DVBT2_PLP_TYPE_RSVD5 = 0x07,
> +	CXD2880_DVBT2_PLP_TYPE_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_payload {
> +	CXD2880_DVBT2_PLP_PAYLOAD_GFPS = 0x00,
> +	CXD2880_DVBT2_PLP_PAYLOAD_GCS = 0x01,
> +	CXD2880_DVBT2_PLP_PAYLOAD_GSE = 0x02,
> +	CXD2880_DVBT2_PLP_PAYLOAD_TS = 0x03,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD1 = 0x04,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD2 = 0x05,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD3 = 0x06,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD4 = 0x07,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD5 = 0x08,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD6 = 0x09,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD7 = 0x0a,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD8 = 0x0b,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD9 = 0x0c,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD10 = 0x0d,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD11 = 0x0e,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD12 = 0x0f,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD13 = 0x10,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD14 = 0x11,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD15 = 0x12,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD16 = 0x13,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD17 = 0x14,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD18 = 0x15,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD19 = 0x16,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD20 = 0x17,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD21 = 0x18,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD22 = 0x19,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD23 = 0x1a,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD24 = 0x1b,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD25 = 0x1c,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD26 = 0x1d,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD27 = 0x1e,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD28 = 0x1f,
> +	CXD2880_DVBT2_PLP_PAYLOAD_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_fec {
> +	CXD2880_DVBT2_FEC_LDPC_16K = 0x00,
> +	CXD2880_DVBT2_FEC_LDPC_64K = 0x01,
> +	CXD2880_DVBT2_FEC_RSVD1 = 0x02,
> +	CXD2880_DVBT2_FEC_RSVD2 = 0x03,
> +	CXD2880_DVBT2_FEC_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_mode {
> +	CXD2880_DVBT2_PLP_MODE_NOTSPECIFIED = 0x00,
> +	CXD2880_DVBT2_PLP_MODE_NM = 0x01,
> +	CXD2880_DVBT2_PLP_MODE_HEM = 0x02,
> +	CXD2880_DVBT2_PLP_MODE_RESERVED = 0x03,
> +	CXD2880_DVBT2_PLP_MODE_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_btype {
> +	CXD2880_DVBT2_PLP_COMMON,
> +	CXD2880_DVBT2_PLP_DATA
> +};
> +
> +enum cxd2880_dvbt2_stream {
> +	CXD2880_DVBT2_STREAM_GENERIC_PACKETIZED = 0x00,
> +	CXD2880_DVBT2_STREAM_GENERIC_CONTINUOUS = 0x01,
> +	CXD2880_DVBT2_STREAM_GENERIC_ENCAPSULATED = 0x02,
> +	CXD2880_DVBT2_STREAM_TRANSPORT = 0x03,
> +	CXD2880_DVBT2_STREAM_UNKNOWN = 0xff
> +};
> +
> +struct cxd2880_dvbt2_l1pre {
> +	enum cxd2880_dvbt2_l1pre_type type;
> +	u8 bw_ext;
> +	enum cxd2880_dvbt2_s1 s1;
> +	u8 s2;
> +	u8 mixed;
> +	enum cxd2880_dvbt2_mode fft_mode;
> +	u8 l1_rep;
> +	enum cxd2880_dvbt2_guard gi;
> +	enum cxd2880_dvbt2_papr papr;
> +	enum cxd2880_dvbt2_l1post_constell mod;
> +	enum cxd2880_dvbt2_l1post_cr cr;
> +	enum cxd2880_dvbt2_l1post_fec_type fec;
> +	u32 l1_post_size;
> +	u32 l1_post_info_size;
> +	enum cxd2880_dvbt2_pp pp;
> +	u8 tx_id_availability;
> +	u16 cell_id;
> +	u16 network_id;
> +	u16 sys_id;
> +	u8 num_frames;
> +	u16 num_symbols;
> +	u8 regen;
> +	u8 post_ext;
> +	u8 num_rf_freqs;
> +	u8 rf_idx;
> +	enum cxd2880_dvbt2_version t2_version;
> +	u8 l1_post_scrambled;
> +	u8 t2_base_lite;
> +	u32 crc32;
> +};
> +
> +struct cxd2880_dvbt2_plp {
> +	u8 id;
> +	enum cxd2880_dvbt2_plp_type type;
> +	enum cxd2880_dvbt2_plp_payload payload;
> +	u8 ff;
> +	u8 first_rf_idx;
> +	u8 first_frm_idx;
> +	u8 group_id;
> +	enum cxd2880_dvbt2_plp_constell constell;
> +	enum cxd2880_dvbt2_plp_code_rate plp_cr;
> +	u8 rot;
> +	enum cxd2880_dvbt2_plp_fec fec;
> +	u16 num_blocks_max;
> +	u8 frm_int;
> +	u8 til_len;
> +	u8 til_type;
> +	u8 in_band_a_flag;
> +	u8 in_band_b_flag;
> +	u16 rsvd;
> +	enum cxd2880_dvbt2_plp_mode plp_mode;
> +	u8 static_flag;
> +	u8 static_padding_flag;
> +};
> +
> +struct cxd2880_dvbt2_l1post {
> +	u16 sub_slices_per_frame;
> +	u8 num_plps;
> +	u8 num_aux;
> +	u8 aux_cfg_rfu;
> +	u8 rf_idx;
> +	u32 freq;
> +	u8 fef_type;
> +	u32 fef_length;
> +	u8 fef_intvl;
> +};
> +
> +struct cxd2880_dvbt2_ofdm {
> +	u8 mixed;
> +	u8 is_miso;
> +	enum cxd2880_dvbt2_mode mode;
> +	enum cxd2880_dvbt2_guard gi;
> +	enum cxd2880_dvbt2_pp pp;
> +	u8 bw_ext;
> +	enum cxd2880_dvbt2_papr papr;
> +	u16 num_symbols;
> +};
> +
> +struct cxd2880_dvbt2_bbheader {
> +	enum cxd2880_dvbt2_stream stream_input;
> +	u8 is_single_input_stream;
> +	u8 is_constant_coding_modulation;
> +	u8 issy_indicator;
> +	u8 null_packet_deletion;
> +	u8 ext;
> +	u8 input_stream_identifier;
> +	u16 user_packet_length;
> +	u16 data_field_length;
> +	u8 sync_byte;
> +	u32 issy;
> +	enum cxd2880_dvbt2_plp_mode plp_mode;
> +};
> +
> +#endif
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
> new file mode 100644
> index 000000000000..3df0648598a1
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
> @@ -0,0 +1,1359 @@
> +/*
> + * cxd2880_tnrdmd_dvbt2.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * control functions for DVB-T2
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_tnrdmd_dvbt2.h"
> +#include "cxd2880_tnrdmd_dvbt2_mon.h"
> +
> +static int x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd
> +				      *tnr_dmd,
> +				      enum cxd2880_dtv_bandwidth
> +				      bandwidth,
> +				      enum cxd2880_tnrdmd_clockmode
> +				      clk_mode)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x31, 0x02);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x04);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x5d, 0x0b);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
> +		u8 data[2] = { 0x01, 0x01 };

static const.

> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x00);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xce, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		u8 data[14] = { 0x07, 0x06, 0x01, 0xf0,
> +			0x00, 0x00, 0x04, 0xb0, 0x00, 0x00, 0x09, 0x9c, 0x0e,
> +			    0x4c
> +		};

same notes I made to other patches apply:
	- static const;
	- don't use a code block where not needed.

Won't repeat it. Please look on other similar stuff.

> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x20);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x8a, data[0]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x90, data[1]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x25);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xf0, &data[2], 2);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x2a);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xdc, data[4]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xde, data[5]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x2d);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x73, &data[6], 4);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x8f, &data[10], 4);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		u8 data_a_1[9] = { 0x52, 0x49, 0x2c, 0x51,
> +			0x51, 0x3d, 0x15, 0x29, 0x0c
> +		};
> +		u8 data_b_1[9] = { 0x5d, 0x55, 0x32, 0x5c,
> +			0x5c, 0x45, 0x17, 0x2e, 0x0d
> +		};
> +		u8 data_c_1[9] = { 0x60, 0x00, 0x34, 0x5e,
> +			0x5e, 0x47, 0x18, 0x2f, 0x0e
> +		};
> +
> +		u8 data_a_2[13] = { 0x04, 0xe7, 0x94, 0x92,
> +			0x09, 0xcf, 0x7e, 0xd0, 0x49, 0xcd, 0xcd, 0x1f, 0x5b
> +		};
> +		u8 data_b_2[13] = { 0x05, 0x90, 0x27, 0x55,
> +			0x0b, 0x20, 0x8f, 0xd6, 0xea, 0xc8, 0xc8, 0x23, 0x91
> +		};
> +		u8 data_c_2[13] = { 0x05, 0xb8, 0xd8, 0x00,
> +			0x0b, 0x72, 0x93, 0xf3, 0x00, 0xcd, 0xcd, 0x24, 0x95
> +		};
> +
> +		u8 data_a_3[5] = { 0x0b, 0x6a, 0xc9, 0x03,
> +			0x33
> +		};
> +		u8 data_b_3[5] = { 0x01, 0x02, 0xe4, 0x03,
> +			0x39
> +		};
> +		u8 data_c_3[5] = { 0x01, 0x02, 0xeb, 0x03,
> +			0x3b
> +		};
> +
> +		u8 *data_1 = NULL;
> +		u8 *data_2 = NULL;
> +		u8 *data_3 = NULL;
> +
> +		switch (clk_mode) {
> +		case CXD2880_TNRDMD_CLOCKMODE_A:
> +			data_1 = data_a_1;
> +			data_2 = data_a_2;
> +			data_3 = data_a_3;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_B:
> +			data_1 = data_b_1;
> +			data_2 = data_b_2;
> +			data_3 = data_b_3;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_C:
> +			data_1 = data_c_1;
> +			data_2 = data_c_2;
> +			data_3 = data_c_3;
> +			break;
> +		default:
> +			return -EPERM;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x04);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x1d, &data_1[0], 3);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x22, data_1[3]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x24, data_1[4]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x26, data_1[5]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x29, &data_1[6], 2);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x2d, data_1[8]);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x2e, &data_2[0], 6);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x35, &data_2[6], 7);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x3c, &data_3[0], 2);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x56, &data_3[2], 3);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	switch (bandwidth) {
> +	case CXD2880_DTV_BW_8_MHZ:
> +
> +		{
> +			u8 data_ac[6] = { 0x15, 0x00, 0x00, 0x00,
> +				0x00, 0x00
> +			};
> +			u8 data_b[6] = { 0x14, 0x6a, 0xaa, 0xaa,
> +				0xab, 0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x10, data, 6);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x00);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data_a[2] = { 0x19, 0xd2 };
> +			u8 data_bc[2] = { 0x3f, 0xff };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_bc;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x19, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data_a[2] = { 0x06, 0x2a };
> +			u8 data_b[2] = { 0x06, 0x29 };
> +			u8 data_c[2] = { 0x06, 0x28 };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x1b, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[9] = { 0x28, 0x00, 0x50, 0x00,
> +				0x60, 0x00, 0x00, 0x90, 0x00
> +			};
> +			u8 data_b[9] = { 0x2d, 0x5e, 0x5a, 0xbd,
> +				0x6c, 0xe3, 0x00, 0xa3, 0x55
> +			};
> +			u8 data_c[9] = { 0x2e, 0xaa, 0x5d, 0x55,
> +				0x70, 0x00, 0x00, 0xa8, 0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, data, 9);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_7_MHZ:
> +
> +		{
> +			u8 data_ac[6] = { 0x18, 0x00, 0x00, 0x00,
> +				0x00, 0x00
> +			};
> +			u8 data_b[6] = { 0x17, 0x55, 0x55, 0x55,
> +				0x55, 0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x10, data, 6);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x02);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data[2] = { 0x3f, 0xff };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x19, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data_a[2] = { 0x06, 0x23 };
> +			u8 data_b[2] = { 0x06, 0x22 };
> +			u8 data_c[2] = { 0x06, 0x21 };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x1b, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[9] = { 0x2d, 0xb6, 0x5b, 0x6d,
> +				0x6d, 0xb6, 0x00, 0xa4, 0x92
> +			};
> +			u8 data_b[9] = { 0x33, 0xda, 0x67, 0xb4,
> +				0x7c, 0x71, 0x00, 0xba, 0xaa
> +			};
> +			u8 data_c[9] = { 0x35, 0x55, 0x6a, 0xaa,
> +				0x80, 0x00, 0x00, 0xc0, 0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, data, 9);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_6_MHZ:
> +
> +		{
> +			u8 data_ac[6] = { 0x1c, 0x00, 0x00, 0x00,
> +				0x00, 0x00
> +			};
> +			u8 data_b[6] = { 0x1b, 0x38, 0xe3, 0x8e,
> +				0x39, 0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x10, data, 6);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x04);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data[2] = { 0x3f, 0xff };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x19, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data_a[2] = { 0x06, 0x1c };
> +			u8 data_b[2] = { 0x06, 0x1b };
> +			u8 data_c[2] = { 0x06, 0x1a };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x1b, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[9] = { 0x35, 0x55, 0x6a, 0xaa,
> +				0x80, 0x00, 0x00, 0xc0, 0x00
> +			};
> +			u8 data_b[9] = { 0x3c, 0x7e, 0x78, 0xfc,
> +				0x91, 0x2f, 0x00, 0xd9, 0xc7
> +			};
> +			u8 data_c[9] = { 0x3e, 0x38, 0x7c, 0x71,
> +				0x95, 0x55, 0x00, 0xdf, 0xff
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, data, 9);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_5_MHZ:
> +
> +		{
> +			u8 data_ac[6] = { 0x21, 0x99, 0x99, 0x99,
> +				0x9a, 0x00
> +			};
> +			u8 data_b[6] = { 0x20, 0xaa, 0xaa, 0xaa,
> +				0xab, 0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x10, data, 6);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x06);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data[2] = { 0x3f, 0xff };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x19, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data_a[2] = { 0x06, 0x15 };
> +			u8 data_b[2] = { 0x06, 0x15 };
> +			u8 data_c[2] = { 0x06, 0x14 };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x1b, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[9] = { 0x40, 0x00, 0x6a, 0xaa,
> +				0x80, 0x00, 0x00, 0xe6, 0x66
> +			};
> +			u8 data_b[9] = { 0x48, 0x97, 0x78, 0xfc,
> +				0x91, 0x2f, 0x01, 0x05, 0x55
> +			};
> +			u8 data_c[9] = { 0x4a, 0xaa, 0x7c, 0x71,
> +				0x95, 0x55, 0x01, 0x0c, 0xcc
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, data, 9);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_1_7_MHZ:
> +
> +		{
> +			u8 data_a[6] = { 0x68, 0x0f, 0xa2, 0x32,
> +				0xcf, 0x03
> +			};
> +			u8 data_c[6] = { 0x68, 0x0f, 0xa2, 0x32,
> +				0xcf, 0x03
> +			};
> +			u8 data_b[6] = { 0x65, 0x2b, 0xa4, 0xcd,
> +				0xd8, 0x03
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x10, data, 6);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x03);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data[2] = { 0x3f, 0xff };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x19, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data_a[2] = { 0x06, 0x0c };
> +			u8 data_b[2] = { 0x06, 0x0c };
> +			u8 data_c[2] = { 0x06, 0x0b };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x1b, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[9] = { 0x40, 0x00, 0x6a, 0xaa,
> +				0x80, 0x00, 0x02, 0xc9, 0x8f
> +			};
> +			u8 data_b[9] = { 0x48, 0x97, 0x78, 0xfc,
> +				0x91, 0x2f, 0x03, 0x29, 0x5d
> +			};
> +			u8 data_c[9] = { 0x4a, 0xaa, 0x7c, 0x71,
> +				0x95, 0x55, 0x03, 0x40, 0x7d
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, data, 9);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	default:
> +		return -EPERM;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xfd, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd
> +				       *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		u8 data[] = { 0, 1, 0, 2,
> +			0, 4, 0, 8, 0, 16, 0, 32
> +		};
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x1d);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x47, data, 12);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
> +			     enum cxd2880_dvbt2_profile profile)
> +{
> +	u8 t2_mode_tune_mode = 0;
> +	u8 seq_not2_dtime = 0;
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	{
> +		u8 dtime1 = 0;
> +		u8 dtime2 = 0;
> +
> +		switch (tnr_dmd->clk_mode) {
> +		case CXD2880_TNRDMD_CLOCKMODE_A:
> +			dtime1 = 0x27;
> +			dtime2 = 0x0c;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_B:
> +			dtime1 = 0x2c;
> +			dtime2 = 0x0d;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_C:
> +			dtime1 = 0x2e;
> +			dtime2 = 0x0e;
> +			break;
> +		default:
> +			return -EPERM;
> +		}
> +
> +		switch (profile) {
> +		case CXD2880_DVBT2_PROFILE_BASE:
> +			t2_mode_tune_mode = 0x01;
> +			seq_not2_dtime = dtime2;
> +			break;
> +
> +		case CXD2880_DVBT2_PROFILE_LITE:
> +			t2_mode_tune_mode = 0x05;
> +			seq_not2_dtime = dtime1;
> +			break;
> +
> +		case CXD2880_DVBT2_PROFILE_ANY:
> +			t2_mode_tune_mode = 0x00;
> +			seq_not2_dtime = dtime1;
> +			break;
> +
> +		default:
> +			return -EINVAL;
> +		}
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x2e);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, t2_mode_tune_mode);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x04);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x2c, seq_not2_dtime);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
> +			       struct cxd2880_dvbt2_tune_param
> +			       *tune_param)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!tune_param))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) &&
> +	    (tune_param->profile == CXD2880_DVBT2_PROFILE_ANY))
> +		return -EOPNOTSUPP;
> +
> +	ret =
> +	    cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2,
> +						tune_param->center_freq_khz,
> +						tune_param->bandwidth, 0, 0);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth,
> +				       tnr_dmd->clk_mode);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret =
> +		    x_tune_dvbt2_demod_setting(tnr_dmd->diver_sub,
> +					       tune_param->bandwidth,
> +					       tnr_dmd->diver_sub->clk_mode);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = dvbt2_set_profile(tnr_dmd, tune_param->profile);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret =
> +		    dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (tune_param->data_plp_id == CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO) {
> +		ret = cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 1, 0);
> +		if (ret)
> +			return ret;
> +	} else {
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0,
> +					     (u8)(tune_param->data_plp_id));
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
> +			       struct cxd2880_dvbt2_tune_param
> +			       *tune_param)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!tune_param))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	{
> +		u8 en_fef_intmtnt_ctrl = 1;
> +
> +		switch (tune_param->profile) {
> +		case CXD2880_DVBT2_PROFILE_BASE:
> +			en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_base;
> +			break;
> +		case CXD2880_DVBT2_PROFILE_LITE:
> +			en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_lite;
> +			break;
> +		case CXD2880_DVBT2_PROFILE_ANY:
> +			if (tnr_dmd->en_fef_intmtnt_base &&
> +			    tnr_dmd->en_fef_intmtnt_lite)
> +				en_fef_intmtnt_ctrl = 1;
> +			else
> +				en_fef_intmtnt_ctrl = 0;
> +			break;
> +		default:
> +			return -EINVAL;
> +		}
> +
> +		ret =
> +		    cxd2880_tnrdmd_common_tune_setting2(tnr_dmd,
> +							CXD2880_DTV_SYS_DVBT2,
> +							en_fef_intmtnt_ctrl);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
> +	tnr_dmd->frequency_khz = tune_param->center_freq_khz;
> +	tnr_dmd->sys = CXD2880_DTV_SYS_DVBT2;
> +	tnr_dmd->bandwidth = tune_param->bandwidth;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
> +		tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
> +		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT2;
> +		tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
> +				       *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = x_sleep_dvbt2_demod_setting(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
> +					  *tnr_dmd,
> +					  enum
> +					  cxd2880_tnrdmd_lock_result
> +					  *lock)
> +{
> +	int ret = 0;
> +
> +	u8 sync_stat = 0;
> +	u8 ts_lock = 0;
> +	u8 unlock_detected = 0;
> +	u8 unlock_detected_sub = 0;
> +
> +	if ((!tnr_dmd) || (!lock))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
> +					       &unlock_detected);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		if (sync_stat == 6)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		else if (unlock_detected)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +		else
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +		return ret;
> +	}
> +
> +	if (sync_stat == 6) {
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		return ret;
> +	}
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
> +						   &unlock_detected_sub);
> +	if (ret)
> +		return ret;
> +
> +	if (sync_stat == 6)
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +	else if (unlock_detected && unlock_detected_sub)
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +	else
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
> +				       *tnr_dmd,
> +				       enum
> +				       cxd2880_tnrdmd_lock_result
> +				       *lock)
> +{
> +	int ret = 0;
> +
> +	u8 sync_stat = 0;
> +	u8 ts_lock = 0;
> +	u8 unlock_detected = 0;
> +	u8 unlock_detected_sub = 0;
> +
> +	if ((!tnr_dmd) || (!lock))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
> +					       &unlock_detected);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		if (ts_lock)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		else if (unlock_detected)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +		else
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +		return ret;
> +	}
> +
> +	if (ts_lock) {
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		return ret;
> +	} else if (!unlock_detected) {
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +		return ret;
> +	}
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
> +						   &unlock_detected_sub);
> +	if (ret)
> +		return ret;
> +
> +	if (unlock_detected && unlock_detected_sub)
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +	else
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u8 auto_plp,
> +				     u8 plp_id)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x23);
> +	if (ret)
> +		return ret;
> +
> +	if (!auto_plp) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xaf, plp_id);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xad, auto_plp ? 0x00 : 0x01);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
> +					   *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE)
> +		return 0;
> +
> +	{
> +		struct cxd2880_dvbt2_ofdm ofdm;
> +
> +		ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm);
> +		if (ret)
> +			return ret;
> +
> +		if (!ofdm.mixed)
> +			return 0;
> +	}
> +
> +	{
> +		u8 data[] = { 0, 8, 0, 16,
> +			0, 32, 0, 64, 0, 128, 1, 0
> +		};
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x1d);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x47, data, 12);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
> +					    *tnr_dmd,
> +					    u8 *l1_post_valid)
> +{
> +	int ret = 0;
> +
> +	u8 data;
> +
> +	if ((!tnr_dmd) || (!l1_post_valid))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x86, &data, 1);
> +	if (ret)
> +		return ret;
> +
> +	*l1_post_valid = data & 0x01;
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
> new file mode 100644
> index 000000000000..409685425b53
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
> @@ -0,0 +1,82 @@
> +/*
> + * cxd2880_tnrdmd_dvbt2.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * control interface for DVB-T2
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_TNRDMD_DVBT2_H
> +#define CXD2880_TNRDMD_DVBT2_H
> +
> +#include "cxd2880_common.h"
> +#include "cxd2880_tnrdmd.h"
> +
> +enum cxd2880_tnrdmd_dvbt2_tune_info {
> +	CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK,
> +	CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID
> +};
> +
> +struct cxd2880_dvbt2_tune_param {
> +	u32 center_freq_khz;
> +	enum cxd2880_dtv_bandwidth bandwidth;
> +	u16 data_plp_id;
> +	enum cxd2880_dvbt2_profile profile;
> +	enum cxd2880_tnrdmd_dvbt2_tune_info tune_info;
> +};
> +
> +#define CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO  0xffff
> +
> +int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
> +			       struct cxd2880_dvbt2_tune_param
> +			       *tune_param);
> +
> +int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
> +			       struct cxd2880_dvbt2_tune_param
> +			       *tune_param);
> +
> +int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
> +				       *tnr_dmd);
> +
> +int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
> +					  *tnr_dmd,
> +					  enum
> +					  cxd2880_tnrdmd_lock_result
> +					  *lock);
> +
> +int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
> +				       *tnr_dmd,
> +				       enum
> +				       cxd2880_tnrdmd_lock_result
> +				       *lock);
> +
> +int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u8 auto_plp,
> +				     u8 plp_id);
> +
> +int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
> +					   *tnr_dmd);
> +
> +int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
> +					    *tnr_dmd,
> +					    u8 *l1_post_valid);
> +
> +#endif



Thanks,
Mauro

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 10/14] [media] cxd2880: Add DVB-T2 control functions for the driver
@ 2017-08-27 15:38     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 15:38 UTC (permalink / raw)
  To: Yasunari.Takiguchi-7U/KSKJipcs
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

Em Wed, 16 Aug 2017 13:42:32 +0900
<Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
> 
> Provide definitions, interfaces and functions needed for DVB-T2
> of the Sony CXD2880 DVB-T2/T tuner + demodulator driver.
> 
> [Change list]
> Changes in V3
>    drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
>       -modified return code
>       -modified coding style of if() 
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
>       -modified return code
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
> ---
>  .../media/dvb-frontends/cxd2880/cxd2880_dvbt2.h    |  402 ++++++
>  .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c   | 1359 ++++++++++++++++++++
>  .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h   |   82 ++
>  3 files changed, 1843 insertions(+)
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
> 
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
> new file mode 100644
> index 000000000000..674ed17deef5
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h
> @@ -0,0 +1,402 @@
> +/*
> + * cxd2880_dvbt2.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DVB-T2 related definitions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_DVBT2_H
> +#define CXD2880_DVBT2_H
> +
> +#include "cxd2880_common.h"
> +
> +enum cxd2880_dvbt2_profile {
> +	CXD2880_DVBT2_PROFILE_BASE,
> +	CXD2880_DVBT2_PROFILE_LITE,
> +	CXD2880_DVBT2_PROFILE_ANY
> +};
> +
> +enum cxd2880_dvbt2_version {
> +	CXD2880_DVBT2_V111,
> +	CXD2880_DVBT2_V121,
> +	CXD2880_DVBT2_V131
> +};
> +
> +enum cxd2880_dvbt2_s1 {
> +	CXD2880_DVBT2_S1_BASE_SISO = 0x00,
> +	CXD2880_DVBT2_S1_BASE_MISO = 0x01,
> +	CXD2880_DVBT2_S1_NON_DVBT2 = 0x02,
> +	CXD2880_DVBT2_S1_LITE_SISO = 0x03,
> +	CXD2880_DVBT2_S1_LITE_MISO = 0x04,
> +	CXD2880_DVBT2_S1_RSVD3 = 0x05,
> +	CXD2880_DVBT2_S1_RSVD4 = 0x06,
> +	CXD2880_DVBT2_S1_RSVD5 = 0x07,
> +	CXD2880_DVBT2_S1_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_base_s2 {
> +	CXD2880_DVBT2_BASE_S2_M2K_G_ANY = 0x00,
> +	CXD2880_DVBT2_BASE_S2_M8K_G_DVBT = 0x01,
> +	CXD2880_DVBT2_BASE_S2_M4K_G_ANY = 0x02,
> +	CXD2880_DVBT2_BASE_S2_M1K_G_ANY = 0x03,
> +	CXD2880_DVBT2_BASE_S2_M16K_G_ANY = 0x04,
> +	CXD2880_DVBT2_BASE_S2_M32K_G_DVBT = 0x05,
> +	CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2 = 0x06,
> +	CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2 = 0x07,
> +	CXD2880_DVBT2_BASE_S2_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_lite_s2 {
> +	CXD2880_DVBT2_LITE_S2_M2K_G_ANY = 0x00,
> +	CXD2880_DVBT2_LITE_S2_M8K_G_DVBT = 0x01,
> +	CXD2880_DVBT2_LITE_S2_M4K_G_ANY = 0x02,
> +	CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2 = 0x03,
> +	CXD2880_DVBT2_LITE_S2_M16K_G_DVBT = 0x04,
> +	CXD2880_DVBT2_LITE_S2_RSVD1 = 0x05,
> +	CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2 = 0x06,
> +	CXD2880_DVBT2_LITE_S2_RSVD2 = 0x07,
> +	CXD2880_DVBT2_LITE_S2_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_guard {
> +	CXD2880_DVBT2_G1_32 = 0x00,
> +	CXD2880_DVBT2_G1_16 = 0x01,
> +	CXD2880_DVBT2_G1_8 = 0x02,
> +	CXD2880_DVBT2_G1_4 = 0x03,
> +	CXD2880_DVBT2_G1_128 = 0x04,
> +	CXD2880_DVBT2_G19_128 = 0x05,
> +	CXD2880_DVBT2_G19_256 = 0x06,
> +	CXD2880_DVBT2_G_RSVD1 = 0x07,
> +	CXD2880_DVBT2_G_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_mode {
> +	CXD2880_DVBT2_M2K = 0x00,
> +	CXD2880_DVBT2_M8K = 0x01,
> +	CXD2880_DVBT2_M4K = 0x02,
> +	CXD2880_DVBT2_M1K = 0x03,
> +	CXD2880_DVBT2_M16K = 0x04,
> +	CXD2880_DVBT2_M32K = 0x05,
> +	CXD2880_DVBT2_M_RSVD1 = 0x06,
> +	CXD2880_DVBT2_M_RSVD2 = 0x07
> +};
> +
> +enum cxd2880_dvbt2_bw {
> +	CXD2880_DVBT2_BW_8 = 0x00,
> +	CXD2880_DVBT2_BW_7 = 0x01,
> +	CXD2880_DVBT2_BW_6 = 0x02,
> +	CXD2880_DVBT2_BW_5 = 0x03,
> +	CXD2880_DVBT2_BW_10 = 0x04,
> +	CXD2880_DVBT2_BW_1_7 = 0x05,
> +	CXD2880_DVBT2_BW_RSVD1 = 0x06,
> +	CXD2880_DVBT2_BW_RSVD2 = 0x07,
> +	CXD2880_DVBT2_BW_RSVD3 = 0x08,
> +	CXD2880_DVBT2_BW_RSVD4 = 0x09,
> +	CXD2880_DVBT2_BW_RSVD5 = 0x0a,
> +	CXD2880_DVBT2_BW_RSVD6 = 0x0b,
> +	CXD2880_DVBT2_BW_RSVD7 = 0x0c,
> +	CXD2880_DVBT2_BW_RSVD8 = 0x0d,
> +	CXD2880_DVBT2_BW_RSVD9 = 0x0e,
> +	CXD2880_DVBT2_BW_RSVD10 = 0x0f,
> +	CXD2880_DVBT2_BW_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_l1pre_type {
> +	CXD2880_DVBT2_L1PRE_TYPE_TS = 0x00,
> +	CXD2880_DVBT2_L1PRE_TYPE_GS = 0x01,
> +	CXD2880_DVBT2_L1PRE_TYPE_TS_GS = 0x02,
> +	CXD2880_DVBT2_L1PRE_TYPE_RESERVED = 0x03,
> +	CXD2880_DVBT2_L1PRE_TYPE_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_papr {
> +	CXD2880_DVBT2_PAPR_0 = 0x00,
> +	CXD2880_DVBT2_PAPR_1 = 0x01,
> +	CXD2880_DVBT2_PAPR_2 = 0x02,
> +	CXD2880_DVBT2_PAPR_3 = 0x03,
> +	CXD2880_DVBT2_PAPR_RSVD1 = 0x04,
> +	CXD2880_DVBT2_PAPR_RSVD2 = 0x05,
> +	CXD2880_DVBT2_PAPR_RSVD3 = 0x06,
> +	CXD2880_DVBT2_PAPR_RSVD4 = 0x07,
> +	CXD2880_DVBT2_PAPR_RSVD5 = 0x08,
> +	CXD2880_DVBT2_PAPR_RSVD6 = 0x09,
> +	CXD2880_DVBT2_PAPR_RSVD7 = 0x0a,
> +	CXD2880_DVBT2_PAPR_RSVD8 = 0x0b,
> +	CXD2880_DVBT2_PAPR_RSVD9 = 0x0c,
> +	CXD2880_DVBT2_PAPR_RSVD10 = 0x0d,
> +	CXD2880_DVBT2_PAPR_RSVD11 = 0x0e,
> +	CXD2880_DVBT2_PAPR_RSVD12 = 0x0f,
> +	CXD2880_DVBT2_PAPR_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_l1post_constell {
> +	CXD2880_DVBT2_L1POST_BPSK = 0x00,
> +	CXD2880_DVBT2_L1POST_QPSK = 0x01,
> +	CXD2880_DVBT2_L1POST_QAM16 = 0x02,
> +	CXD2880_DVBT2_L1POST_QAM64 = 0x03,
> +	CXD2880_DVBT2_L1POST_C_RSVD1 = 0x04,
> +	CXD2880_DVBT2_L1POST_C_RSVD2 = 0x05,
> +	CXD2880_DVBT2_L1POST_C_RSVD3 = 0x06,
> +	CXD2880_DVBT2_L1POST_C_RSVD4 = 0x07,
> +	CXD2880_DVBT2_L1POST_C_RSVD5 = 0x08,
> +	CXD2880_DVBT2_L1POST_C_RSVD6 = 0x09,
> +	CXD2880_DVBT2_L1POST_C_RSVD7 = 0x0a,
> +	CXD2880_DVBT2_L1POST_C_RSVD8 = 0x0b,
> +	CXD2880_DVBT2_L1POST_C_RSVD9 = 0x0c,
> +	CXD2880_DVBT2_L1POST_C_RSVD10 = 0x0d,
> +	CXD2880_DVBT2_L1POST_C_RSVD11 = 0x0e,
> +	CXD2880_DVBT2_L1POST_C_RSVD12 = 0x0f,
> +	CXD2880_DVBT2_L1POST_CONSTELL_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_l1post_cr {
> +	CXD2880_DVBT2_L1POST_R1_2 = 0x00,
> +	CXD2880_DVBT2_L1POST_R_RSVD1 = 0x01,
> +	CXD2880_DVBT2_L1POST_R_RSVD2 = 0x02,
> +	CXD2880_DVBT2_L1POST_R_RSVD3 = 0x03,
> +	CXD2880_DVBT2_L1POST_R_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_l1post_fec_type {
> +	CXD2880_DVBT2_L1POST_FEC_LDPC16K = 0x00,
> +	CXD2880_DVBT2_L1POST_FEC_RSVD1 = 0x01,
> +	CXD2880_DVBT2_L1POST_FEC_RSVD2 = 0x02,
> +	CXD2880_DVBT2_L1POST_FEC_RSVD3 = 0x03,
> +	CXD2880_DVBT2_L1POST_FEC_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_pp {
> +	CXD2880_DVBT2_PP1 = 0x00,
> +	CXD2880_DVBT2_PP2 = 0x01,
> +	CXD2880_DVBT2_PP3 = 0x02,
> +	CXD2880_DVBT2_PP4 = 0x03,
> +	CXD2880_DVBT2_PP5 = 0x04,
> +	CXD2880_DVBT2_PP6 = 0x05,
> +	CXD2880_DVBT2_PP7 = 0x06,
> +	CXD2880_DVBT2_PP8 = 0x07,
> +	CXD2880_DVBT2_PP_RSVD1 = 0x08,
> +	CXD2880_DVBT2_PP_RSVD2 = 0x09,
> +	CXD2880_DVBT2_PP_RSVD3 = 0x0a,
> +	CXD2880_DVBT2_PP_RSVD4 = 0x0b,
> +	CXD2880_DVBT2_PP_RSVD5 = 0x0c,
> +	CXD2880_DVBT2_PP_RSVD6 = 0x0d,
> +	CXD2880_DVBT2_PP_RSVD7 = 0x0e,
> +	CXD2880_DVBT2_PP_RSVD8 = 0x0f,
> +	CXD2880_DVBT2_PP_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_code_rate {
> +	CXD2880_DVBT2_R1_2 = 0x00,
> +	CXD2880_DVBT2_R3_5 = 0x01,
> +	CXD2880_DVBT2_R2_3 = 0x02,
> +	CXD2880_DVBT2_R3_4 = 0x03,
> +	CXD2880_DVBT2_R4_5 = 0x04,
> +	CXD2880_DVBT2_R5_6 = 0x05,
> +	CXD2880_DVBT2_R1_3 = 0x06,
> +	CXD2880_DVBT2_R2_5 = 0x07,
> +	CXD2880_DVBT2_PLP_CR_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_constell {
> +	CXD2880_DVBT2_QPSK = 0x00,
> +	CXD2880_DVBT2_QAM16 = 0x01,
> +	CXD2880_DVBT2_QAM64 = 0x02,
> +	CXD2880_DVBT2_QAM256 = 0x03,
> +	CXD2880_DVBT2_CON_RSVD1 = 0x04,
> +	CXD2880_DVBT2_CON_RSVD2 = 0x05,
> +	CXD2880_DVBT2_CON_RSVD3 = 0x06,
> +	CXD2880_DVBT2_CON_RSVD4 = 0x07,
> +	CXD2880_DVBT2_CONSTELL_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_type {
> +	CXD2880_DVBT2_PLP_TYPE_COMMON = 0x00,
> +	CXD2880_DVBT2_PLP_TYPE_DATA1 = 0x01,
> +	CXD2880_DVBT2_PLP_TYPE_DATA2 = 0x02,
> +	CXD2880_DVBT2_PLP_TYPE_RSVD1 = 0x03,
> +	CXD2880_DVBT2_PLP_TYPE_RSVD2 = 0x04,
> +	CXD2880_DVBT2_PLP_TYPE_RSVD3 = 0x05,
> +	CXD2880_DVBT2_PLP_TYPE_RSVD4 = 0x06,
> +	CXD2880_DVBT2_PLP_TYPE_RSVD5 = 0x07,
> +	CXD2880_DVBT2_PLP_TYPE_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_payload {
> +	CXD2880_DVBT2_PLP_PAYLOAD_GFPS = 0x00,
> +	CXD2880_DVBT2_PLP_PAYLOAD_GCS = 0x01,
> +	CXD2880_DVBT2_PLP_PAYLOAD_GSE = 0x02,
> +	CXD2880_DVBT2_PLP_PAYLOAD_TS = 0x03,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD1 = 0x04,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD2 = 0x05,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD3 = 0x06,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD4 = 0x07,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD5 = 0x08,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD6 = 0x09,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD7 = 0x0a,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD8 = 0x0b,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD9 = 0x0c,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD10 = 0x0d,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD11 = 0x0e,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD12 = 0x0f,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD13 = 0x10,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD14 = 0x11,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD15 = 0x12,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD16 = 0x13,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD17 = 0x14,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD18 = 0x15,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD19 = 0x16,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD20 = 0x17,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD21 = 0x18,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD22 = 0x19,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD23 = 0x1a,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD24 = 0x1b,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD25 = 0x1c,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD26 = 0x1d,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD27 = 0x1e,
> +	CXD2880_DVBT2_PLP_PAYLOAD_RSVD28 = 0x1f,
> +	CXD2880_DVBT2_PLP_PAYLOAD_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_fec {
> +	CXD2880_DVBT2_FEC_LDPC_16K = 0x00,
> +	CXD2880_DVBT2_FEC_LDPC_64K = 0x01,
> +	CXD2880_DVBT2_FEC_RSVD1 = 0x02,
> +	CXD2880_DVBT2_FEC_RSVD2 = 0x03,
> +	CXD2880_DVBT2_FEC_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_mode {
> +	CXD2880_DVBT2_PLP_MODE_NOTSPECIFIED = 0x00,
> +	CXD2880_DVBT2_PLP_MODE_NM = 0x01,
> +	CXD2880_DVBT2_PLP_MODE_HEM = 0x02,
> +	CXD2880_DVBT2_PLP_MODE_RESERVED = 0x03,
> +	CXD2880_DVBT2_PLP_MODE_UNKNOWN = 0xff
> +};
> +
> +enum cxd2880_dvbt2_plp_btype {
> +	CXD2880_DVBT2_PLP_COMMON,
> +	CXD2880_DVBT2_PLP_DATA
> +};
> +
> +enum cxd2880_dvbt2_stream {
> +	CXD2880_DVBT2_STREAM_GENERIC_PACKETIZED = 0x00,
> +	CXD2880_DVBT2_STREAM_GENERIC_CONTINUOUS = 0x01,
> +	CXD2880_DVBT2_STREAM_GENERIC_ENCAPSULATED = 0x02,
> +	CXD2880_DVBT2_STREAM_TRANSPORT = 0x03,
> +	CXD2880_DVBT2_STREAM_UNKNOWN = 0xff
> +};
> +
> +struct cxd2880_dvbt2_l1pre {
> +	enum cxd2880_dvbt2_l1pre_type type;
> +	u8 bw_ext;
> +	enum cxd2880_dvbt2_s1 s1;
> +	u8 s2;
> +	u8 mixed;
> +	enum cxd2880_dvbt2_mode fft_mode;
> +	u8 l1_rep;
> +	enum cxd2880_dvbt2_guard gi;
> +	enum cxd2880_dvbt2_papr papr;
> +	enum cxd2880_dvbt2_l1post_constell mod;
> +	enum cxd2880_dvbt2_l1post_cr cr;
> +	enum cxd2880_dvbt2_l1post_fec_type fec;
> +	u32 l1_post_size;
> +	u32 l1_post_info_size;
> +	enum cxd2880_dvbt2_pp pp;
> +	u8 tx_id_availability;
> +	u16 cell_id;
> +	u16 network_id;
> +	u16 sys_id;
> +	u8 num_frames;
> +	u16 num_symbols;
> +	u8 regen;
> +	u8 post_ext;
> +	u8 num_rf_freqs;
> +	u8 rf_idx;
> +	enum cxd2880_dvbt2_version t2_version;
> +	u8 l1_post_scrambled;
> +	u8 t2_base_lite;
> +	u32 crc32;
> +};
> +
> +struct cxd2880_dvbt2_plp {
> +	u8 id;
> +	enum cxd2880_dvbt2_plp_type type;
> +	enum cxd2880_dvbt2_plp_payload payload;
> +	u8 ff;
> +	u8 first_rf_idx;
> +	u8 first_frm_idx;
> +	u8 group_id;
> +	enum cxd2880_dvbt2_plp_constell constell;
> +	enum cxd2880_dvbt2_plp_code_rate plp_cr;
> +	u8 rot;
> +	enum cxd2880_dvbt2_plp_fec fec;
> +	u16 num_blocks_max;
> +	u8 frm_int;
> +	u8 til_len;
> +	u8 til_type;
> +	u8 in_band_a_flag;
> +	u8 in_band_b_flag;
> +	u16 rsvd;
> +	enum cxd2880_dvbt2_plp_mode plp_mode;
> +	u8 static_flag;
> +	u8 static_padding_flag;
> +};
> +
> +struct cxd2880_dvbt2_l1post {
> +	u16 sub_slices_per_frame;
> +	u8 num_plps;
> +	u8 num_aux;
> +	u8 aux_cfg_rfu;
> +	u8 rf_idx;
> +	u32 freq;
> +	u8 fef_type;
> +	u32 fef_length;
> +	u8 fef_intvl;
> +};
> +
> +struct cxd2880_dvbt2_ofdm {
> +	u8 mixed;
> +	u8 is_miso;
> +	enum cxd2880_dvbt2_mode mode;
> +	enum cxd2880_dvbt2_guard gi;
> +	enum cxd2880_dvbt2_pp pp;
> +	u8 bw_ext;
> +	enum cxd2880_dvbt2_papr papr;
> +	u16 num_symbols;
> +};
> +
> +struct cxd2880_dvbt2_bbheader {
> +	enum cxd2880_dvbt2_stream stream_input;
> +	u8 is_single_input_stream;
> +	u8 is_constant_coding_modulation;
> +	u8 issy_indicator;
> +	u8 null_packet_deletion;
> +	u8 ext;
> +	u8 input_stream_identifier;
> +	u16 user_packet_length;
> +	u16 data_field_length;
> +	u8 sync_byte;
> +	u32 issy;
> +	enum cxd2880_dvbt2_plp_mode plp_mode;
> +};
> +
> +#endif
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
> new file mode 100644
> index 000000000000..3df0648598a1
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c
> @@ -0,0 +1,1359 @@
> +/*
> + * cxd2880_tnrdmd_dvbt2.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * control functions for DVB-T2
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_tnrdmd_dvbt2.h"
> +#include "cxd2880_tnrdmd_dvbt2_mon.h"
> +
> +static int x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd
> +				      *tnr_dmd,
> +				      enum cxd2880_dtv_bandwidth
> +				      bandwidth,
> +				      enum cxd2880_tnrdmd_clockmode
> +				      clk_mode)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_SYS,
> +				     0x31, 0x02);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x04);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x5d, 0x0b);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
> +		u8 data[2] = { 0x01, 0x01 };

static const.

> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x00);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xce, data, 2);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		u8 data[14] = { 0x07, 0x06, 0x01, 0xf0,
> +			0x00, 0x00, 0x04, 0xb0, 0x00, 0x00, 0x09, 0x9c, 0x0e,
> +			    0x4c
> +		};

same notes I made to other patches apply:
	- static const;
	- don't use a code block where not needed.

Won't repeat it. Please look on other similar stuff.

> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x20);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x8a, data[0]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x90, data[1]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x25);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0xf0, &data[2], 2);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x2a);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xdc, data[4]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xde, data[5]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x2d);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x73, &data[6], 4);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x8f, &data[10], 4);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	{
> +		u8 data_a_1[9] = { 0x52, 0x49, 0x2c, 0x51,
> +			0x51, 0x3d, 0x15, 0x29, 0x0c
> +		};
> +		u8 data_b_1[9] = { 0x5d, 0x55, 0x32, 0x5c,
> +			0x5c, 0x45, 0x17, 0x2e, 0x0d
> +		};
> +		u8 data_c_1[9] = { 0x60, 0x00, 0x34, 0x5e,
> +			0x5e, 0x47, 0x18, 0x2f, 0x0e
> +		};
> +
> +		u8 data_a_2[13] = { 0x04, 0xe7, 0x94, 0x92,
> +			0x09, 0xcf, 0x7e, 0xd0, 0x49, 0xcd, 0xcd, 0x1f, 0x5b
> +		};
> +		u8 data_b_2[13] = { 0x05, 0x90, 0x27, 0x55,
> +			0x0b, 0x20, 0x8f, 0xd6, 0xea, 0xc8, 0xc8, 0x23, 0x91
> +		};
> +		u8 data_c_2[13] = { 0x05, 0xb8, 0xd8, 0x00,
> +			0x0b, 0x72, 0x93, 0xf3, 0x00, 0xcd, 0xcd, 0x24, 0x95
> +		};
> +
> +		u8 data_a_3[5] = { 0x0b, 0x6a, 0xc9, 0x03,
> +			0x33
> +		};
> +		u8 data_b_3[5] = { 0x01, 0x02, 0xe4, 0x03,
> +			0x39
> +		};
> +		u8 data_c_3[5] = { 0x01, 0x02, 0xeb, 0x03,
> +			0x3b
> +		};
> +
> +		u8 *data_1 = NULL;
> +		u8 *data_2 = NULL;
> +		u8 *data_3 = NULL;
> +
> +		switch (clk_mode) {
> +		case CXD2880_TNRDMD_CLOCKMODE_A:
> +			data_1 = data_a_1;
> +			data_2 = data_a_2;
> +			data_3 = data_a_3;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_B:
> +			data_1 = data_b_1;
> +			data_2 = data_b_2;
> +			data_3 = data_b_3;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_C:
> +			data_1 = data_c_1;
> +			data_2 = data_c_2;
> +			data_3 = data_c_3;
> +			break;
> +		default:
> +			return -EPERM;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x04);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x1d, &data_1[0], 3);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x22, data_1[3]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x24, data_1[4]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x26, data_1[5]);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x29, &data_1[6], 2);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x2d, data_1[8]);
> +		if (ret)
> +			return ret;
> +
> +		if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x2e, &data_2[0], 6);
> +			if (ret)
> +				return ret;
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x35, &data_2[6], 7);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x3c, &data_3[0], 2);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x56, &data_3[2], 3);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	switch (bandwidth) {
> +	case CXD2880_DTV_BW_8_MHZ:
> +
> +		{
> +			u8 data_ac[6] = { 0x15, 0x00, 0x00, 0x00,
> +				0x00, 0x00
> +			};
> +			u8 data_b[6] = { 0x14, 0x6a, 0xaa, 0xaa,
> +				0xab, 0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x10, data, 6);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x00);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data_a[2] = { 0x19, 0xd2 };
> +			u8 data_bc[2] = { 0x3f, 0xff };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_bc;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x19, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data_a[2] = { 0x06, 0x2a };
> +			u8 data_b[2] = { 0x06, 0x29 };
> +			u8 data_c[2] = { 0x06, 0x28 };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x1b, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[9] = { 0x28, 0x00, 0x50, 0x00,
> +				0x60, 0x00, 0x00, 0x90, 0x00
> +			};
> +			u8 data_b[9] = { 0x2d, 0x5e, 0x5a, 0xbd,
> +				0x6c, 0xe3, 0x00, 0xa3, 0x55
> +			};
> +			u8 data_c[9] = { 0x2e, 0xaa, 0x5d, 0x55,
> +				0x70, 0x00, 0x00, 0xa8, 0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, data, 9);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_7_MHZ:
> +
> +		{
> +			u8 data_ac[6] = { 0x18, 0x00, 0x00, 0x00,
> +				0x00, 0x00
> +			};
> +			u8 data_b[6] = { 0x17, 0x55, 0x55, 0x55,
> +				0x55, 0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x10, data, 6);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x02);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data[2] = { 0x3f, 0xff };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x19, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data_a[2] = { 0x06, 0x23 };
> +			u8 data_b[2] = { 0x06, 0x22 };
> +			u8 data_c[2] = { 0x06, 0x21 };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x1b, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[9] = { 0x2d, 0xb6, 0x5b, 0x6d,
> +				0x6d, 0xb6, 0x00, 0xa4, 0x92
> +			};
> +			u8 data_b[9] = { 0x33, 0xda, 0x67, 0xb4,
> +				0x7c, 0x71, 0x00, 0xba, 0xaa
> +			};
> +			u8 data_c[9] = { 0x35, 0x55, 0x6a, 0xaa,
> +				0x80, 0x00, 0x00, 0xc0, 0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, data, 9);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_6_MHZ:
> +
> +		{
> +			u8 data_ac[6] = { 0x1c, 0x00, 0x00, 0x00,
> +				0x00, 0x00
> +			};
> +			u8 data_b[6] = { 0x1b, 0x38, 0xe3, 0x8e,
> +				0x39, 0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x10, data, 6);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x04);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data[2] = { 0x3f, 0xff };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x19, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data_a[2] = { 0x06, 0x1c };
> +			u8 data_b[2] = { 0x06, 0x1b };
> +			u8 data_c[2] = { 0x06, 0x1a };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x1b, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[9] = { 0x35, 0x55, 0x6a, 0xaa,
> +				0x80, 0x00, 0x00, 0xc0, 0x00
> +			};
> +			u8 data_b[9] = { 0x3c, 0x7e, 0x78, 0xfc,
> +				0x91, 0x2f, 0x00, 0xd9, 0xc7
> +			};
> +			u8 data_c[9] = { 0x3e, 0x38, 0x7c, 0x71,
> +				0x95, 0x55, 0x00, 0xdf, 0xff
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, data, 9);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_5_MHZ:
> +
> +		{
> +			u8 data_ac[6] = { 0x21, 0x99, 0x99, 0x99,
> +				0x9a, 0x00
> +			};
> +			u8 data_b[6] = { 0x20, 0xaa, 0xaa, 0xaa,
> +				0xab, 0x00
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_ac;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x10, data, 6);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x06);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data[2] = { 0x3f, 0xff };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x19, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data_a[2] = { 0x06, 0x15 };
> +			u8 data_b[2] = { 0x06, 0x15 };
> +			u8 data_c[2] = { 0x06, 0x14 };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x1b, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[9] = { 0x40, 0x00, 0x6a, 0xaa,
> +				0x80, 0x00, 0x00, 0xe6, 0x66
> +			};
> +			u8 data_b[9] = { 0x48, 0x97, 0x78, 0xfc,
> +				0x91, 0x2f, 0x01, 0x05, 0x55
> +			};
> +			u8 data_c[9] = { 0x4a, 0xaa, 0x7c, 0x71,
> +				0x95, 0x55, 0x01, 0x0c, 0xcc
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, data, 9);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	case CXD2880_DTV_BW_1_7_MHZ:
> +
> +		{
> +			u8 data_a[6] = { 0x68, 0x0f, 0xa2, 0x32,
> +				0xcf, 0x03
> +			};
> +			u8 data_c[6] = { 0x68, 0x0f, 0xa2, 0x32,
> +				0xcf, 0x03
> +			};
> +			u8 data_b[6] = { 0x65, 0x2b, 0xa4, 0xcd,
> +				0xd8, 0x03
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x10, data, 6);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x4a, 0x03);
> +		if (ret)
> +			return ret;
> +
> +		{
> +			u8 data[2] = { 0x3f, 0xff };
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x19, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		{
> +			u8 data_a[2] = { 0x06, 0x0c };
> +			u8 data_b[2] = { 0x06, 0x0c };
> +			u8 data_c[2] = { 0x06, 0x0b };
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x1b, data, 2);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +			u8 data_a[9] = { 0x40, 0x00, 0x6a, 0xaa,
> +				0x80, 0x00, 0x02, 0xc9, 0x8f
> +			};
> +			u8 data_b[9] = { 0x48, 0x97, 0x78, 0xfc,
> +				0x91, 0x2f, 0x03, 0x29, 0x5d
> +			};
> +			u8 data_c[9] = { 0x4a, 0xaa, 0x7c, 0x71,
> +				0x95, 0x55, 0x03, 0x40, 0x7d
> +			};
> +			u8 *data = NULL;
> +
> +			switch (clk_mode) {
> +			case CXD2880_TNRDMD_CLOCKMODE_A:
> +				data = data_a;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_B:
> +				data = data_b;
> +				break;
> +			case CXD2880_TNRDMD_CLOCKMODE_C:
> +				data = data_c;
> +				break;
> +			default:
> +				return -EPERM;
> +			}
> +
> +			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +						      CXD2880_IO_TGT_DMD,
> +						      0x4b, data, 9);
> +			if (ret)
> +				return ret;
> +		}
> +		break;
> +
> +	default:
> +		return -EPERM;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x00);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xfd, 0x01);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd
> +				       *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		u8 data[] = { 0, 1, 0, 2,
> +			0, 4, 0, 8, 0, 16, 0, 32
> +		};
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x1d);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x47, data, 12);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
> +			     enum cxd2880_dvbt2_profile profile)
> +{
> +	u8 t2_mode_tune_mode = 0;
> +	u8 seq_not2_dtime = 0;
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	{
> +		u8 dtime1 = 0;
> +		u8 dtime2 = 0;
> +
> +		switch (tnr_dmd->clk_mode) {
> +		case CXD2880_TNRDMD_CLOCKMODE_A:
> +			dtime1 = 0x27;
> +			dtime2 = 0x0c;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_B:
> +			dtime1 = 0x2c;
> +			dtime2 = 0x0d;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_C:
> +			dtime1 = 0x2e;
> +			dtime2 = 0x0e;
> +			break;
> +		default:
> +			return -EPERM;
> +		}
> +
> +		switch (profile) {
> +		case CXD2880_DVBT2_PROFILE_BASE:
> +			t2_mode_tune_mode = 0x01;
> +			seq_not2_dtime = dtime2;
> +			break;
> +
> +		case CXD2880_DVBT2_PROFILE_LITE:
> +			t2_mode_tune_mode = 0x05;
> +			seq_not2_dtime = dtime1;
> +			break;
> +
> +		case CXD2880_DVBT2_PROFILE_ANY:
> +			t2_mode_tune_mode = 0x00;
> +			seq_not2_dtime = dtime1;
> +			break;
> +
> +		default:
> +			return -EINVAL;
> +		}
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x2e);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x10, t2_mode_tune_mode);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x04);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x2c, seq_not2_dtime);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
> +			       struct cxd2880_dvbt2_tune_param
> +			       *tune_param)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!tune_param))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) &&
> +	    (tune_param->profile == CXD2880_DVBT2_PROFILE_ANY))
> +		return -EOPNOTSUPP;
> +
> +	ret =
> +	    cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2,
> +						tune_param->center_freq_khz,
> +						tune_param->bandwidth, 0, 0);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth,
> +				       tnr_dmd->clk_mode);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret =
> +		    x_tune_dvbt2_demod_setting(tnr_dmd->diver_sub,
> +					       tune_param->bandwidth,
> +					       tnr_dmd->diver_sub->clk_mode);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = dvbt2_set_profile(tnr_dmd, tune_param->profile);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret =
> +		    dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (tune_param->data_plp_id == CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO) {
> +		ret = cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 1, 0);
> +		if (ret)
> +			return ret;
> +	} else {
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0,
> +					     (u8)(tune_param->data_plp_id));
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
> +			       struct cxd2880_dvbt2_tune_param
> +			       *tune_param)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!tune_param))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	{
> +		u8 en_fef_intmtnt_ctrl = 1;
> +
> +		switch (tune_param->profile) {
> +		case CXD2880_DVBT2_PROFILE_BASE:
> +			en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_base;
> +			break;
> +		case CXD2880_DVBT2_PROFILE_LITE:
> +			en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_lite;
> +			break;
> +		case CXD2880_DVBT2_PROFILE_ANY:
> +			if (tnr_dmd->en_fef_intmtnt_base &&
> +			    tnr_dmd->en_fef_intmtnt_lite)
> +				en_fef_intmtnt_ctrl = 1;
> +			else
> +				en_fef_intmtnt_ctrl = 0;
> +			break;
> +		default:
> +			return -EINVAL;
> +		}
> +
> +		ret =
> +		    cxd2880_tnrdmd_common_tune_setting2(tnr_dmd,
> +							CXD2880_DTV_SYS_DVBT2,
> +							en_fef_intmtnt_ctrl);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
> +	tnr_dmd->frequency_khz = tune_param->center_freq_khz;
> +	tnr_dmd->sys = CXD2880_DTV_SYS_DVBT2;
> +	tnr_dmd->bandwidth = tune_param->bandwidth;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
> +		tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
> +		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT2;
> +		tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
> +				       *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = x_sleep_dvbt2_demod_setting(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +		ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
> +					  *tnr_dmd,
> +					  enum
> +					  cxd2880_tnrdmd_lock_result
> +					  *lock)
> +{
> +	int ret = 0;
> +
> +	u8 sync_stat = 0;
> +	u8 ts_lock = 0;
> +	u8 unlock_detected = 0;
> +	u8 unlock_detected_sub = 0;
> +
> +	if ((!tnr_dmd) || (!lock))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
> +					       &unlock_detected);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		if (sync_stat == 6)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		else if (unlock_detected)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +		else
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +		return ret;
> +	}
> +
> +	if (sync_stat == 6) {
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		return ret;
> +	}
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
> +						   &unlock_detected_sub);
> +	if (ret)
> +		return ret;
> +
> +	if (sync_stat == 6)
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +	else if (unlock_detected && unlock_detected_sub)
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +	else
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
> +				       *tnr_dmd,
> +				       enum
> +				       cxd2880_tnrdmd_lock_result
> +				       *lock)
> +{
> +	int ret = 0;
> +
> +	u8 sync_stat = 0;
> +	u8 ts_lock = 0;
> +	u8 unlock_detected = 0;
> +	u8 unlock_detected_sub = 0;
> +
> +	if ((!tnr_dmd) || (!lock))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
> +					       &unlock_detected);
> +	if (ret)
> +		return ret;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		if (ts_lock)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		else if (unlock_detected)
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +		else
> +			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +		return ret;
> +	}
> +
> +	if (ts_lock) {
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
> +		return ret;
> +	} else if (!unlock_detected) {
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +		return ret;
> +	}
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
> +						   &unlock_detected_sub);
> +	if (ret)
> +		return ret;
> +
> +	if (unlock_detected && unlock_detected_sub)
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
> +	else
> +		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u8 auto_plp,
> +				     u8 plp_id)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x23);
> +	if (ret)
> +		return ret;
> +
> +	if (!auto_plp) {
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xaf, plp_id);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0xad, auto_plp ? 0x00 : 0x01);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
> +					   *tnr_dmd)
> +{
> +	int ret = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE)
> +		return 0;
> +
> +	{
> +		struct cxd2880_dvbt2_ofdm ofdm;
> +
> +		ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm);
> +		if (ret)
> +			return ret;
> +
> +		if (!ofdm.mixed)
> +			return 0;
> +	}
> +
> +	{
> +		u8 data[] = { 0, 8, 0, 16,
> +			0, 32, 0, 64, 0, 128, 1, 0
> +		};
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x1d);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> +					      CXD2880_IO_TGT_DMD,
> +					      0x47, data, 12);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
> +					    *tnr_dmd,
> +					    u8 *l1_post_valid)
> +{
> +	int ret = 0;
> +
> +	u8 data;
> +
> +	if ((!tnr_dmd) || (!l1_post_valid))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x86, &data, 1);
> +	if (ret)
> +		return ret;
> +
> +	*l1_post_valid = data & 0x01;
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
> new file mode 100644
> index 000000000000..409685425b53
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h
> @@ -0,0 +1,82 @@
> +/*
> + * cxd2880_tnrdmd_dvbt2.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * control interface for DVB-T2
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_TNRDMD_DVBT2_H
> +#define CXD2880_TNRDMD_DVBT2_H
> +
> +#include "cxd2880_common.h"
> +#include "cxd2880_tnrdmd.h"
> +
> +enum cxd2880_tnrdmd_dvbt2_tune_info {
> +	CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK,
> +	CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID
> +};
> +
> +struct cxd2880_dvbt2_tune_param {
> +	u32 center_freq_khz;
> +	enum cxd2880_dtv_bandwidth bandwidth;
> +	u16 data_plp_id;
> +	enum cxd2880_dvbt2_profile profile;
> +	enum cxd2880_tnrdmd_dvbt2_tune_info tune_info;
> +};
> +
> +#define CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO  0xffff
> +
> +int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
> +			       struct cxd2880_dvbt2_tune_param
> +			       *tune_param);
> +
> +int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
> +			       struct cxd2880_dvbt2_tune_param
> +			       *tune_param);
> +
> +int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
> +				       *tnr_dmd);
> +
> +int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
> +					  *tnr_dmd,
> +					  enum
> +					  cxd2880_tnrdmd_lock_result
> +					  *lock);
> +
> +int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
> +				       *tnr_dmd,
> +				       enum
> +				       cxd2880_tnrdmd_lock_result
> +				       *lock);
> +
> +int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u8 auto_plp,
> +				     u8 plp_id);
> +
> +int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
> +					   *tnr_dmd);
> +
> +int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
> +					    *tnr_dmd,
> +					    u8 *l1_post_valid);
> +
> +#endif



Thanks,
Mauro
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 11/14] [media] cxd2880: Add DVB-T2 monitor and integration layer functions
@ 2017-08-27 15:44     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 15:44 UTC (permalink / raw)
  To: Yasunari.Takiguchi
  Cc: linux-kernel, devicetree, linux-media, tbird20d, frowand.list,
	Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

Em Wed, 16 Aug 2017 13:43:41 +0900
<Yasunari.Takiguchi@sony.com> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> 
> Provide monitor and integration layer functions (DVB-T2)
> for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.
> 
> [Change list]
> Changes in V3
>    drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
>       -changed CXD2880_SLEEP to usleep_range
>       -replaced cxd2880_atomic_set to atomic_set
>       -modified return code
>       -modified coding style of if()  
>    drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
>       -modified return code
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
>       -removed unnecessary cast
>       -changed cxd2880_math_log to intlog10
>       -modified return code
>       -modified coding style of if() 
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
>       -modified return code
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
> ---
>  .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c    |  312 +++
>  .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h    |   64 +
>  .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.c             | 2622 ++++++++++++++++++++
>  .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.h             |  170 ++
>  4 files changed, 3168 insertions(+)
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
> 
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
> new file mode 100644
> index 000000000000..ac049820d797
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
> @@ -0,0 +1,312 @@
> +/*
> + * cxd2880_integ_dvbt2.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * integration layer functions for DVB-T2
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_tnrdmd_dvbt2.h"
> +#include "cxd2880_tnrdmd_dvbt2_mon.h"
> +#include "cxd2880_integ_dvbt2.h"
> +
> +static int dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd,
> +				 enum cxd2880_dvbt2_profile
> +				 profile);
> +
> +static int dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +int cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd,
> +			     struct cxd2880_dvbt2_tune_param
> +			     *tune_param)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!tune_param))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	atomic_set(&tnr_dmd->cancel, 0);
> +
> +	if ((tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ)) {
> +		return -EOPNOTSUPP;
> +	}
> +
> +	if ((tune_param->profile != CXD2880_DVBT2_PROFILE_BASE) &&
> +	    (tune_param->profile != CXD2880_DVBT2_PROFILE_LITE))
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000,
> +		     CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000);
> +
> +	ret = cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param);
> +	if (ret)
> +		return ret;
> +
> +	ret = dvbt2_wait_demod_lock(tnr_dmd, tune_param->profile);
> +	if (ret)
> +		return ret;
> +
> +	ret = cxd2880_tnrdmd_dvbt2_diver_fef_setting(tnr_dmd);
> +	if (ret == -EBUSY)
> +		return -EAGAIN;
> +	else if (ret)
> +		return ret;
> +
> +	ret = dvbt2_wait_l1_post_lock(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 plp_not_found;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_data_plp_error(tnr_dmd,
> +							    &plp_not_found);
> +		if (ret == -EBUSY)
> +			return -EAGAIN;
> +		else if (ret)
> +			return ret;
> +
> +		if (plp_not_found) {
> +			ret = -0;
> +			tune_param->tune_info =
> +			    CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID;
> +		} else {
> +			tune_param->tune_info =
> +			    CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dvbt2_profile
> +				     profile)
> +{

Same notes I made for DVB-T apply: it is up to userspace to wait for
device's lock. Are there any special reason why in this hardware
such lock should be done by the Kernel driver?

> +	int ret = 0;
> +	enum cxd2880_tnrdmd_lock_result lock =
> +	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +	u16 timeout = 0;
> +	struct cxd2880_stopwatch timer;
> +	u8 continue_wait = 1;
> +	unsigned int elapsed = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret = cxd2880_stopwatch_start(&timer);
> +	if (ret)
> +		return ret;
> +
> +	if (profile == CXD2880_DVBT2_PROFILE_BASE)
> +		timeout = CXD2880_DVBT2_BASE_WAIT_TS_LOCK;
> +	else if (profile == CXD2880_DVBT2_PROFILE_LITE)
> +		timeout = CXD2880_DVBT2_LITE_WAIT_TS_LOCK;
> +	else
> +		return -EINVAL;
> +
> +	for (;;) {

Same note here: use while(1) {} for infinite loops. Extra care is
required to not hang the Kernel.

> +		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
> +		if (ret)
> +			return ret;
> +
> +		if (elapsed >= timeout)
> +			continue_wait = 0;
> +
> +		ret = cxd2880_tnrdmd_dvbt2_check_ts_lock(tnr_dmd, &lock);
> +		if (ret)
> +			return ret;
> +
> +		switch (lock) {
> +		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
> +			return 0;
> +
> +		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
> +			return -EAGAIN;
> +
> +		default:
> +			break;
> +		}
> +
> +		ret = cxd2880_integ_check_cancellation(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (continue_wait) {
> +			ret =
> +			    cxd2880_stopwatch_sleep(&timer,
> +					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
> +			if (ret)
> +				return ret;
> +		} else {
> +			ret = -ETIME;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd,
> +				 enum cxd2880_dvbt2_profile
> +				 profile)
> +{
> +	int ret = 0;
> +	enum cxd2880_tnrdmd_lock_result lock =
> +	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +	u16 timeout = 0;
> +	struct cxd2880_stopwatch timer;
> +	u8 continue_wait = 1;
> +	unsigned int elapsed = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret = cxd2880_stopwatch_start(&timer);
> +	if (ret)
> +		return ret;
> +
> +	if (profile == CXD2880_DVBT2_PROFILE_BASE)
> +		timeout = CXD2880_DVBT2_BASE_WAIT_DMD_LOCK;
> +	else if ((profile == CXD2880_DVBT2_PROFILE_LITE) ||
> +		 (profile == CXD2880_DVBT2_PROFILE_ANY))
> +		timeout = CXD2880_DVBT2_LITE_WAIT_DMD_LOCK;
> +	else
> +		return -EPERM;
> +
> +	for (;;) {
> +		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
> +		if (ret)
> +			return ret;
> +
> +		if (elapsed >= timeout)
> +			continue_wait = 0;
> +
> +		ret = cxd2880_tnrdmd_dvbt2_check_demod_lock(tnr_dmd, &lock);
> +		if (ret)
> +			return ret;
> +
> +		switch (lock) {
> +		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
> +			return 0;
> +
> +		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
> +			return -EAGAIN;
> +
> +		default:
> +			break;
> +		}
> +
> +		ret = cxd2880_integ_check_cancellation(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (continue_wait) {
> +			ret =
> +			    cxd2880_stopwatch_sleep(&timer,
> +					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
> +			if (ret)
> +				return ret;
> +		} else {
> +			ret = -ETIME;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +	struct cxd2880_stopwatch timer;
> +	u8 continue_wait = 1;
> +	unsigned int elapsed = 0;
> +	u8 l1_post_valid;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = cxd2880_stopwatch_start(&timer);
> +	if (ret)
> +		return ret;
> +
> +	for (;;) {
> +		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
> +		if (ret)
> +			return ret;
> +
> +		if (elapsed >= CXD2880_DVBT2_L1POST_TIMEOUT)
> +			continue_wait = 0;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_check_l1post_valid(tnr_dmd,
> +							    &l1_post_valid);
> +		if (ret)
> +			return ret;
> +
> +		if (l1_post_valid)
> +			return 0;
> +
> +		ret = cxd2880_integ_check_cancellation(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (continue_wait) {
> +			ret =
> +			    cxd2880_stopwatch_sleep(&timer,
> +					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
> +			if (ret)
> +				return ret;
> +		} else {
> +			ret = -ETIME;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
> new file mode 100644
> index 000000000000..c7b1df6306df
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
> @@ -0,0 +1,64 @@
> +/*
> + * cxd2880_integ_dvbt2.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * integration layer interface for DVB-T2
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_INTEG_DVBT2_H
> +#define CXD2880_INTEG_DVBT2_H
> +
> +#include "cxd2880_tnrdmd.h"
> +#include "cxd2880_tnrdmd_dvbt2.h"
> +#include "cxd2880_integ.h"
> +
> +#define CXD2880_DVBT2_BASE_WAIT_DMD_LOCK     3500
> +#define CXD2880_DVBT2_BASE_WAIT_TS_LOCK	1500
> +#define CXD2880_DVBT2_LITE_WAIT_DMD_LOCK     5000
> +#define CXD2880_DVBT2_LITE_WAIT_TS_LOCK	2300
> +#define CXD2880_DVBT2_WAIT_LOCK_INTVL       10
> +#define CXD2880_DVBT2_L1POST_TIMEOUT	   500
> +
> +struct cxd2880_integ_dvbt2_scan_param {
> +	u32 start_frequency_khz;
> +	u32 end_frequency_khz;
> +	u32 step_frequency_khz;
> +	enum cxd2880_dtv_bandwidth bandwidth;
> +	enum cxd2880_dvbt2_profile t2_profile;
> +};
> +
> +struct cxd2880_integ_dvbt2_scan_result {
> +	u32 center_freq_khz;
> +	int tune_result;
> +	struct cxd2880_dvbt2_tune_param dvbt2_tune_param;
> +};
> +
> +int cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd,
> +			     struct cxd2880_dvbt2_tune_param
> +			     *tune_param);
> +
> +int cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dvbt2_profile
> +				     profile);
> +
> +#endif
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
> new file mode 100644
> index 000000000000..62ee5d540dff
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
> @@ -0,0 +1,2622 @@
> +/*
> + * cxd2880_tnrdmd_dvbt2_mon.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DVB-T2 monitor functions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_tnrdmd_mon.h"
> +#include "cxd2880_tnrdmd_dvbt2.h"
> +#include "cxd2880_tnrdmd_dvbt2_mon.h"
> +
> +#include "dvb_math.h"
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 *sync_stat,
> +				       u8 *ts_lock_stat,
> +				       u8 *unlock_detected)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data;

Same notes that I made to other patches apply here.

> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x10, &data, sizeof(data));
> +		if (ret)
> +			return ret;
> +
> +		*sync_stat = data & 0x07;
> +		*ts_lock_stat = ((data & 0x20) ? 1 : 0);
> +		*unlock_detected = ((data & 0x10) ? 1 : 0);
> +	}
> +
> +	if (*sync_stat == 0x07)
> +		return -EBUSY;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
> +					   *tnr_dmd,
> +					   u8 *sync_stat,
> +					   u8 *unlock_detected)
> +{
> +	u8 ts_lock_stat = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub, sync_stat,
> +					       &ts_lock_stat, unlock_detected);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
> +					    *tnr_dmd, int *offset)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!offset))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[4];
> +		u32 ctl_val = 0;
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state != 6) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x30, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		ctl_val =
> +		    ((data[0] & 0x0f) << 24) | (data[1] << 16) | (data[2] << 8)
> +		    | (data[3]);
> +		*offset = cxd2880_convert2s_complement(ctl_val, 28);
> +
> +		switch (tnr_dmd->bandwidth) {
> +		case CXD2880_DTV_BW_1_7_MHZ:
> +			*offset = -1 * ((*offset) / 582);
> +			break;
> +		case CXD2880_DTV_BW_5_MHZ:
> +		case CXD2880_DTV_BW_6_MHZ:
> +		case CXD2880_DTV_BW_7_MHZ:
> +		case CXD2880_DTV_BW_8_MHZ:
> +			*offset =
> +			    -1 * ((*offset) * tnr_dmd->bandwidth / 940);
> +			break;
> +		default:
> +			return -EPERM;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
> +						cxd2880_tnrdmd
> +						*tnr_dmd,
> +						int *offset)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!offset))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub, offset);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
> +				    struct cxd2880_dvbt2_l1pre
> +				    *l1_pre)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!l1_pre))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[37];
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +		u8 version = 0;
> +		enum cxd2880_dvbt2_profile profile;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state < 5) {
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +				ret =
> +				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
> +				    (tnr_dmd, &sync_state, &unlock_detected);
> +				if (ret) {
> +					slvt_unfreeze_reg(tnr_dmd);
> +					return ret;
> +				}
> +
> +				if (sync_state < 5) {
> +					slvt_unfreeze_reg(tnr_dmd);
> +					return -EBUSY;
> +				}
> +			} else {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return -EBUSY;
> +			}
> +		}
> +
> +		ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x61, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0];
> +		l1_pre->bw_ext = data[1] & 0x01;
> +		l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07);
> +		l1_pre->s2 = data[3] & 0x0f;
> +		l1_pre->l1_rep = data[4] & 0x01;
> +		l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07);
> +		l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0f);
> +		l1_pre->mod =
> +		    (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0f);
> +		l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03);
> +		l1_pre->fec =
> +		    (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03);
> +		l1_pre->l1_post_size = (data[10] & 0x03) << 16;
> +		l1_pre->l1_post_size |= (data[11]) << 8;
> +		l1_pre->l1_post_size |= (data[12]);
> +		l1_pre->l1_post_info_size = (data[13] & 0x03) << 16;
> +		l1_pre->l1_post_info_size |= (data[14]) << 8;
> +		l1_pre->l1_post_info_size |= (data[15]);
> +		l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0f);
> +		l1_pre->tx_id_availability = data[17];
> +		l1_pre->cell_id = (data[18] << 8);
> +		l1_pre->cell_id |= (data[19]);
> +		l1_pre->network_id = (data[20] << 8);
> +		l1_pre->network_id |= (data[21]);
> +		l1_pre->sys_id = (data[22] << 8);
> +		l1_pre->sys_id |= (data[23]);
> +		l1_pre->num_frames = data[24];
> +		l1_pre->num_symbols = (data[25] & 0x0f) << 8;
> +		l1_pre->num_symbols |= data[26];
> +		l1_pre->regen = data[27] & 0x07;
> +		l1_pre->post_ext = data[28] & 0x01;
> +		l1_pre->num_rf_freqs = data[29] & 0x07;
> +		l1_pre->rf_idx = data[30] & 0x07;
> +		version = (data[31] & 0x03) << 2;
> +		version |= (data[32] & 0xc0) >> 6;
> +		l1_pre->t2_version = (enum cxd2880_dvbt2_version)version;
> +		l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5;
> +		l1_pre->t2_base_lite = (data[32] & 0x10) >> 4;
> +		l1_pre->crc32 = (data[33] << 24);
> +		l1_pre->crc32 |= (data[34] << 16);
> +		l1_pre->crc32 |= (data[35] << 8);
> +		l1_pre->crc32 |= data[36];
> +
> +		if (profile == CXD2880_DVBT2_PROFILE_BASE) {
> +			switch ((l1_pre->s2 >> 1)) {
> +			case CXD2880_DVBT2_BASE_S2_M1K_G_ANY:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M1K;
> +				break;
> +			case CXD2880_DVBT2_BASE_S2_M2K_G_ANY:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M2K;
> +				break;
> +			case CXD2880_DVBT2_BASE_S2_M4K_G_ANY:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M4K;
> +				break;
> +			case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT:
> +			case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M8K;
> +				break;
> +			case CXD2880_DVBT2_BASE_S2_M16K_G_ANY:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M16K;
> +				break;
> +			case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT:
> +			case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M32K;
> +				break;
> +			default:
> +				return -EBUSY;
> +			}
> +		} else if (profile == CXD2880_DVBT2_PROFILE_LITE) {
> +			switch ((l1_pre->s2 >> 1)) {
> +			case CXD2880_DVBT2_LITE_S2_M2K_G_ANY:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M2K;
> +				break;
> +			case CXD2880_DVBT2_LITE_S2_M4K_G_ANY:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M4K;
> +				break;
> +			case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT:
> +			case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M8K;
> +				break;
> +			case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT:
> +			case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M16K;
> +				break;
> +			default:
> +				return -EBUSY;
> +			}
> +		} else {
> +			return -EBUSY;
> +		}
> +
> +		l1_pre->mixed = l1_pre->s2 & 0x01;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dvbt2_version
> +				     *ver)
> +{
> +	int ret = 0;
> +	u8 version = 0;
> +
> +	if ((!tnr_dmd) || (!ver))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[2];
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state < 5) {
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +				ret =
> +				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
> +				    (tnr_dmd, &sync_state, &unlock_detected);
> +				if (ret) {
> +					slvt_unfreeze_reg(tnr_dmd);
> +					return ret;
> +				}
> +
> +				if (sync_state < 5) {
> +					slvt_unfreeze_reg(tnr_dmd);
> +					return -EBUSY;
> +				}
> +			} else {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return -EBUSY;
> +			}
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x80, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		version = ((data[0] & 0x03) << 2);
> +		version |= ((data[1] & 0xc0) >> 6);
> +		*ver = (enum cxd2880_dvbt2_version)version;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
> +				  struct cxd2880_dvbt2_ofdm *ofdm)
> +{
> +	if ((!tnr_dmd) || (!ofdm))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[5];
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +		int ret = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state != 6) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +
> +			ret = -EBUSY;
> +
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN)
> +				ret =
> +				    cxd2880_tnrdmd_dvbt2_mon_ofdm(
> +					tnr_dmd->diver_sub, ofdm);
> +
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x1d, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		ofdm->mixed = ((data[0] & 0x20) ? 1 : 0);
> +		ofdm->is_miso = ((data[0] & 0x10) >> 4);
> +		ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07);
> +		ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4);
> +		ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07);
> +		ofdm->bw_ext = (data[2] & 0x10) >> 4;
> +		ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0f);
> +		ofdm->num_symbols = (data[3] << 8) | data[4];
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 *plp_ids,
> +				       u8 *num_plps)
> +{
> +	if ((!tnr_dmd) || (!num_plps))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 l1_post_ok = 0;
> +		int ret = 0;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret)
> +			return ret;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x86, &l1_post_ok, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!(l1_post_ok & 0x01)) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xc1, num_plps, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (*num_plps == 0) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EPERM;
> +		}
> +
> +		if (!plp_ids) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return 0;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xc2,
> +					     plp_ids,
> +					     ((*num_plps > 62) ?
> +					     62 : *num_plps));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (*num_plps > 62) {
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x00, 0x0c);
> +			if (ret) {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return ret;
> +			}
> +
> +			ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x10, plp_ids + 62,
> +						     *num_plps - 62);
> +			if (ret) {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return ret;
> +			}
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +	}
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
> +					*tnr_dmd,
> +					enum
> +					cxd2880_dvbt2_plp_btype
> +					type,
> +					struct cxd2880_dvbt2_plp
> +					*plp_info)
> +{
> +	if ((!tnr_dmd) || (!plp_info))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[20];
> +		u8 addr = 0;
> +		u8 index = 0;
> +		u8 l1_post_ok = 0;
> +		int ret = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x86, &l1_post_ok, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!l1_post_ok) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		if (type == CXD2880_DVBT2_PLP_COMMON)
> +			addr = 0xa9;
> +		else
> +			addr = 0x96;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     addr, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		if ((type == CXD2880_DVBT2_PLP_COMMON) && (data[13] == 0))
> +			return -EBUSY;
> +
> +		plp_info->id = data[index++];
> +		plp_info->type =
> +		    (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07);
> +		plp_info->payload =
> +		    (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1f);
> +		plp_info->ff = data[index++] & 0x01;
> +		plp_info->first_rf_idx = data[index++] & 0x07;
> +		plp_info->first_frm_idx = data[index++];
> +		plp_info->group_id = data[index++];
> +		plp_info->plp_cr =
> +		    (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07);
> +		plp_info->constell =
> +		    (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07);
> +		plp_info->rot = data[index++] & 0x01;
> +		plp_info->fec =
> +		    (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03);
> +		plp_info->num_blocks_max = (data[index++] & 0x03) << 8;
> +		plp_info->num_blocks_max |= data[index++];
> +		plp_info->frm_int = data[index++];
> +		plp_info->til_len = data[index++];
> +		plp_info->til_type = data[index++] & 0x01;
> +
> +		plp_info->in_band_a_flag = data[index++] & 0x01;
> +		plp_info->rsvd = data[index++] << 8;
> +		plp_info->rsvd |= data[index++];
> +
> +		plp_info->in_band_b_flag =
> +		    (plp_info->rsvd & 0x8000) >> 15;
> +		plp_info->plp_mode =
> +		    (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000c) >>
> +						  2);
> +		plp_info->static_flag = (plp_info->rsvd & 0x0002) >> 1;
> +		plp_info->static_padding_flag = plp_info->rsvd & 0x0001;
> +		plp_info->rsvd = (plp_info->rsvd & 0x7ff0) >> 4;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
> +					    *tnr_dmd,
> +					    u8 *plp_error)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!plp_error))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x86, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if ((data & 0x01) == 0x00) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xc0, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		*plp_error = data & 0x01;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 *l1_change)
> +{
> +	if ((!tnr_dmd) || (!l1_change))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data;
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +		int ret = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state < 5) {
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +				ret =
> +				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
> +				    (tnr_dmd, &sync_state, &unlock_detected);
> +				if (ret) {
> +					slvt_unfreeze_reg(tnr_dmd);
> +					return ret;
> +				}
> +
> +				if (sync_state < 5) {
> +					slvt_unfreeze_reg(tnr_dmd);
> +					return -EBUSY;
> +				}
> +			} else {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return -EBUSY;
> +			}
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x5f, &data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		*l1_change = data & 0x01;
> +		if (*l1_change) {
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x00, 0x22);
> +			if (ret) {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return ret;
> +			}
> +
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x16, 0x01);
> +			if (ret) {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return ret;
> +			}
> +		}
> +		slvt_unfreeze_reg(tnr_dmd);
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     struct cxd2880_dvbt2_l1post
> +				     *l1_post)
> +{
> +	if ((!tnr_dmd) || (!l1_post))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[16];
> +		int ret = 0;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x86, data, sizeof(data));
> +		if (ret)
> +			return ret;
> +
> +		if (!(data[0] & 0x01))
> +			return -EBUSY;
> +
> +		l1_post->sub_slices_per_frame = (data[1] & 0x7f) << 8;
> +		l1_post->sub_slices_per_frame |= data[2];
> +		l1_post->num_plps = data[3];
> +		l1_post->num_aux = data[4] & 0x0f;
> +		l1_post->aux_cfg_rfu = data[5];
> +		l1_post->rf_idx = data[6] & 0x07;
> +		l1_post->freq = data[7] << 24;
> +		l1_post->freq |= data[8] << 16;
> +		l1_post->freq |= data[9] << 8;
> +		l1_post->freq |= data[10];
> +		l1_post->fef_type = data[11] & 0x0f;
> +		l1_post->fef_length = data[12] << 16;
> +		l1_post->fef_length |= data[13] << 8;
> +		l1_post->fef_length |= data[14];
> +		l1_post->fef_intvl = data[15];
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
> +				      *tnr_dmd,
> +				      enum cxd2880_dvbt2_plp_btype
> +				      type,
> +				      struct cxd2880_dvbt2_bbheader
> +				      *bbheader)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!bbheader))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!ts_lock) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	if (type == CXD2880_DVBT2_PLP_COMMON) {
> +		u8 l1_post_ok;
> +		u8 data;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x86, &l1_post_ok, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!(l1_post_ok & 0x01)) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xb6, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (data == 0) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +	}
> +
> +	{
> +		u8 data[14];
> +		u8 addr = 0;
> +
> +		if (type == CXD2880_DVBT2_PLP_COMMON)
> +			addr = 0x51;
> +		else
> +			addr = 0x42;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     addr, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		bbheader->stream_input =
> +		    (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03);
> +		bbheader->is_single_input_stream = (data[0] >> 5) & 0x01;
> +		bbheader->is_constant_coding_modulation =
> +		    (data[0] >> 4) & 0x01;
> +		bbheader->issy_indicator = (data[0] >> 3) & 0x01;
> +		bbheader->null_packet_deletion = (data[0] >> 2) & 0x01;
> +		bbheader->ext = data[0] & 0x03;
> +
> +		bbheader->input_stream_identifier = data[1];
> +		bbheader->plp_mode =
> +		    (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM :
> +		    CXD2880_DVBT2_PLP_MODE_NM;
> +		bbheader->data_field_length = (data[4] << 8) | data[5];
> +
> +		if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
> +			bbheader->user_packet_length =
> +			    (data[6] << 8) | data[7];
> +			bbheader->sync_byte = data[8];
> +			bbheader->issy = 0;
> +		} else {
> +			bbheader->user_packet_length = 0;
> +			bbheader->sync_byte = 0;
> +			bbheader->issy =
> +			    (data[11] << 16) | (data[12] << 8) | data[13];
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
> +					      *tnr_dmd,
> +					      enum
> +					      cxd2880_dvbt2_plp_btype
> +					      type,
> +					      u32 *ts_rate_bps)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ts_rate_bps))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!ts_lock) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	{
> +		u8 l1_post_ok = 0;
> +		u8 addr = 0;
> +		u8 data = 0;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x86, &l1_post_ok, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!(l1_post_ok & 0x01)) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		if (type == CXD2880_DVBT2_PLP_COMMON)
> +			addr = 0xba;
> +		else
> +			addr = 0xa7;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     addr, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if ((data & 0x80) == 0x00) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x25);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	{
> +		u8 data[4];
> +		u8 addr = 0;
> +
> +		if (type == CXD2880_DVBT2_PLP_COMMON)
> +			addr = 0xa6;
> +		else
> +			addr = 0xaa;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     addr, &data[0], 4);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		*ts_rate_bps = ((data[0] & 0x07) << 24) | (data[1] << 16) |
> +			       (data[2] << 8) | data[3];
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
> +					    *tnr_dmd,
> +					    enum
> +					    cxd2880_tnrdmd_spectrum_sense
> +					    *sense)
> +{
> +	int ret = 0;
> +	u8 sync_state = 0;
> +	u8 ts_lock = 0;
> +	u8 early_unlock = 0;
> +
> +	if ((!tnr_dmd) || (!sense))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock,
> +					       &early_unlock);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	if (sync_state != 6) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		ret = -EBUSY;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
> +			ret =
> +			    cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(
> +				tnr_dmd->diver_sub, sense);
> +
> +		return ret;
> +	}
> +
> +	{
> +		u8 data = 0;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x2f, &data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		*sense =
> +		    (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
> +		    CXD2880_TNRDMD_SPECTRUM_NORMAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
> +			      u16 *reg_value)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!reg_value))
> +		return -EINVAL;
> +
> +	{
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +		u8 data[2];
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state != 6) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x13, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		*reg_value = (data[0] << 8) | data[1];
> +	}
> +
> +	return ret;
> +}
> +
> +static int dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
> +			  u32 reg_value, int *snr)
> +{
> +	if ((!tnr_dmd) || (!snr))
> +		return -EINVAL;
> +
> +	if (reg_value == 0)
> +		return -EBUSY;
> +
> +	if (reg_value > 10876)
> +		reg_value = 10876;
> +
> +	*snr = intlog10(reg_value) - intlog10(12600 - reg_value);
> +	*snr = (*snr + 839) / 1678 + 32000;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
> +				 int *snr)
> +{
> +	u16 reg_value = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!snr))
> +		return -EINVAL;
> +
> +	*snr = -1000 * 1000;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
> +		if (ret)
> +			return ret;
> +
> +		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr);
> +		if (ret)
> +			return ret;
> +	} else {
> +		int snr_main = 0;
> +		int snr_sub = 0;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main,
> +						       &snr_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
> +				       *tnr_dmd, int *snr,
> +				       int *snr_main, int *snr_sub)
> +{
> +	u16 reg_value = 0;
> +	u32 reg_value_sum = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub))
> +		return -EINVAL;
> +
> +	*snr = -1000 * 1000;
> +	*snr_main = -1000 * 1000;
> +	*snr_sub = -1000 * 1000;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
> +	if (!ret) {
> +		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main);
> +		if (ret)
> +			reg_value = 0;
> +	} else if (ret == -EBUSY) {
> +		reg_value = 0;
> +	} else {
> +		return ret;
> +	}
> +
> +	reg_value_sum += reg_value;
> +
> +	ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
> +	if (!ret) {
> +		ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
> +		if (ret)
> +			reg_value = 0;
> +	} else if (ret == -EBUSY) {
> +		reg_value = 0;
> +	} else {
> +		return ret;
> +	}
> +
> +	reg_value_sum += reg_value;
> +
> +	ret = dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd
> +					 *tnr_dmd, u32 *ber)
> +{
> +	int ret = 0;
> +	u32 bit_error = 0;
> +	u32 period_exp = 0;
> +	u32 n_ldpc = 0;
> +
> +	if ((!tnr_dmd) || (!ber))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	{
> +		u8 data[5];
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x3c, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!(data[0] & 0x01)) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		bit_error =
> +		    ((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8)
> +		    | data[4];
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xa0, data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) ==
> +		    CXD2880_DVBT2_FEC_LDPC_16K)
> +			n_ldpc = 16200;
> +		else
> +			n_ldpc = 64800;
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x20);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x6f, data, 1);
> +		if (ret)
> +			return ret;
> +
> +		period_exp = data[0] & 0x0f;
> +	}
> +
> +	if (bit_error > ((1U << period_exp) * n_ldpc))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		if (period_exp >= 4) {
> +			div = (1U << (period_exp - 4)) * (n_ldpc / 200);
> +
> +			Q = (bit_error * 5) / div;
> +			R = (bit_error * 5) % div;
> +
> +			R *= 625;
> +			Q = Q * 625 + R / div;
> +			R = R % div;
> +		} else {
> +			div = (1U << period_exp) * (n_ldpc / 200);
> +
> +			Q = (bit_error * 10) / div;
> +			R = (bit_error * 10) % div;
> +
> +			R *= 5000;
> +			Q = Q * 5000 + R / div;
> +			R = R % div;
> +		}
> +
> +		if (div / 2 <= R)
> +			*ber = Q + 1;
> +		else
> +			*ber = Q;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd
> +					 *tnr_dmd, u32 *fer)
> +{
> +	int ret = 0;
> +	u32 fec_error = 0;
> +	u32 period = 0;
> +
> +	if ((!tnr_dmd) || (!fer))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data[2];
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x1b, data, 2);
> +		if (ret)
> +			return ret;
> +
> +		if (!(data[0] & 0x80))
> +			return -EBUSY;
> +
> +		fec_error = ((data[0] & 0x7f) << 8) | (data[1]);
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x20);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x72, data, 1);
> +		if (ret)
> +			return ret;
> +
> +		period = (1 << (data[0] & 0x0f));
> +	}
> +
> +	if ((period == 0) || (fec_error > period))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		div = period;
> +
> +		Q = (fec_error * 1000) / div;
> +		R = (fec_error * 1000) % div;
> +
> +		R *= 1000;
> +		Q = Q * 1000 + R / div;
> +		R = R % div;
> +
> +		if ((div != 1) && (div / 2 <= R))
> +			*fer = Q + 1;
> +		else
> +			*fer = Q;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd
> +					*tnr_dmd, u32 *ber)
> +{
> +	int ret = 0;
> +	u32 bit_error = 0;
> +	u32 period_exp = 0;
> +	u32 n_bch = 0;
> +
> +	if ((!tnr_dmd) || (!ber))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[3];
> +		enum cxd2880_dvbt2_plp_fec plp_fec_type =
> +		    CXD2880_DVBT2_FEC_LDPC_16K;
> +		enum cxd2880_dvbt2_plp_code_rate plp_cr = CXD2880_DVBT2_R1_2;
> +
> +		static const u16 n_bch_bits_lookup[2][8] = {
> +			{7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480},
> +			{32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920}
> +		};
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x15, data, 3);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!(data[0] & 0x40)) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		bit_error = ((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2];
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x9d, data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		plp_cr = (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07);
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xa0, data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03);
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x20);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x72, data, 1);
> +		if (ret)
> +			return ret;
> +
> +		period_exp = data[0] & 0x0f;
> +
> +		if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) ||
> +		    (plp_cr > CXD2880_DVBT2_R2_5))
> +			return -EBUSY;
> +
> +		n_bch = n_bch_bits_lookup[plp_fec_type][plp_cr];
> +	}
> +
> +	if (bit_error > ((1U << period_exp) * n_bch))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		if (period_exp >= 6) {
> +			div = (1U << (period_exp - 6)) * (n_bch / 40);
> +
> +			Q = (bit_error * 625) / div;
> +			R = (bit_error * 625) % div;
> +
> +			R *= 625;
> +			Q = Q * 625 + R / div;
> +			R = R % div;
> +		} else {
> +			div = (1U << period_exp) * (n_bch / 40);
> +
> +			Q = (bit_error * 1000) / div;
> +			R = (bit_error * 1000) % div;
> +
> +			R *= 25000;
> +			Q = Q * 25000 + R / div;
> +			R = R % div;
> +		}
> +
> +		if (div / 2 <= R)
> +			*ber = Q + 1;
> +		else
> +			*ber = Q;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
> +						 cxd2880_tnrdmd
> +						 *tnr_dmd,
> +						 u32 *pen)
> +{
> +	int ret = 0;
> +
> +	u8 data[3];
> +
> +	if ((!tnr_dmd) || (!pen))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x39, data, sizeof(data));
> +	if (ret)
> +		return ret;
> +
> +	if (!(data[0] & 0x01))
> +		return -EBUSY;
> +
> +	*pen = ((data[1] << 8) | data[2]);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
> +					     *tnr_dmd, int *ppm)
> +{
> +	if ((!tnr_dmd) || (!ppm))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 ctl_val_reg[5];
> +		u8 nominal_rate_reg[5];
> +		u32 trl_ctl_val = 0;
> +		u32 trcg_nominal_rate = 0;
> +		int num;
> +		int den;
> +		int ret = 0;
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +		s8 diff_upper = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state != 6) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x34, ctl_val_reg,
> +					     sizeof(ctl_val_reg));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x04);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x10, nominal_rate_reg,
> +					     sizeof(nominal_rate_reg));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		diff_upper =
> +		    (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
> +
> +		if ((diff_upper < -1) || (diff_upper > 1))
> +			return -EBUSY;
> +
> +		trl_ctl_val = ctl_val_reg[1] << 24;
> +		trl_ctl_val |= ctl_val_reg[2] << 16;
> +		trl_ctl_val |= ctl_val_reg[3] << 8;
> +		trl_ctl_val |= ctl_val_reg[4];
> +
> +		trcg_nominal_rate = nominal_rate_reg[1] << 24;
> +		trcg_nominal_rate |= nominal_rate_reg[2] << 16;
> +		trcg_nominal_rate |= nominal_rate_reg[3] << 8;
> +		trcg_nominal_rate |= nominal_rate_reg[4];
> +
> +		trl_ctl_val >>= 1;
> +		trcg_nominal_rate >>= 1;
> +
> +		if (diff_upper == 1)
> +			num =
> +			    (int)((trl_ctl_val + 0x80000000u) -
> +				  trcg_nominal_rate);
> +		else if (diff_upper == -1)
> +			num =
> +			    -(int)((trcg_nominal_rate + 0x80000000u) -
> +				   trl_ctl_val);
> +		else
> +			num = (int)(trl_ctl_val - trcg_nominal_rate);
> +
> +		den = (nominal_rate_reg[0] & 0x7f) << 24;
> +		den |= nominal_rate_reg[1] << 16;
> +		den |= nominal_rate_reg[2] << 8;
> +		den |= nominal_rate_reg[3];
> +		den = (den + (390625 / 2)) / 390625;
> +
> +		den >>= 1;
> +
> +		if (num >= 0)
> +			*ppm = (num + (den / 2)) / den;
> +		else
> +			*ppm = (num - (den / 2)) / den;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
> +						 cxd2880_tnrdmd
> +						 *tnr_dmd,
> +						 int *ppm)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ppm))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u8 *quality)
> +{
> +	int ret = 0;
> +	int snr = 0;
> +	int snr_rel = 0;
> +	u32 ber = 0;
> +	u32 ber_sqi = 0;
> +	enum cxd2880_dvbt2_plp_constell qam;
> +	enum cxd2880_dvbt2_plp_code_rate code_rate;
> +
> +	static const int snr_nordig_p1_db_1000[4][8] = {
> +		{3500, 4700, 5600, 6600, 7200, 7700, 1300, 2200},
> +		{8700, 10100, 11400, 12500, 13300, 13800, 6000, 7200},
> +		{13000, 14800, 16200, 17700, 18700, 19400, 9800, 11100},
> +		{17000, 19400, 20800, 22900, 24300, 25100, 13200, 14800},
> +	};
> +
> +	if ((!tnr_dmd) || (!quality))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(tnr_dmd, &ber);
> +	if (ret)
> +		return ret;
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_snr(tnr_dmd, &snr);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
> +					       &code_rate);
> +	if (ret)
> +		return ret;
> +
> +	if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256))
> +		return -EPERM;
> +
> +	if (ber > 100000)
> +		ber_sqi = 0;
> +	else if (ber >= 100)
> +		ber_sqi = 6667;
> +	else
> +		ber_sqi = 16667;
> +
> +	snr_rel = snr - snr_nordig_p1_db_1000[qam][code_rate];
> +
> +	if (snr_rel < -3000) {
> +		*quality = 0;
> +	} else if (snr_rel <= 3000) {
> +		u32 temp_sqi =
> +		    (((snr_rel + 3000) * ber_sqi) + 500000) / 1000000;
> +		*quality = (temp_sqi > 100) ? 100 : (u8)temp_sqi;
> +	} else {
> +		*quality = 100;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u32 *ts_rate_kbps)
> +{
> +	int ret = 0;
> +	u32 rd_smooth_dp = 0;
> +	u32 ep_ck_nume = 0;
> +	u32 ep_ck_deno = 0;
> +	u8 issy_on_data = 0;
> +
> +	if ((!tnr_dmd) || (!ts_rate_kbps))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[12];
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!ts_lock) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x23, data, 12);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		rd_smooth_dp = (data[0] & 0x1f) << 24;
> +		rd_smooth_dp |= data[1] << 16;
> +		rd_smooth_dp |= data[2] << 8;
> +		rd_smooth_dp |= data[3];
> +
> +		if (rd_smooth_dp < 214958) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ep_ck_nume = (data[4] & 0x3f) << 24;
> +		ep_ck_nume |= data[5] << 16;
> +		ep_ck_nume |= data[6] << 8;
> +		ep_ck_nume |= data[7];
> +
> +		ep_ck_deno = (data[8] & 0x3f) << 24;
> +		ep_ck_deno |= data[9] << 16;
> +		ep_ck_deno |= data[10] << 8;
> +		ep_ck_deno |= data[11];
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x41, data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		issy_on_data = data[0] & 0x01;
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +	}
> +
> +	if (issy_on_data) {
> +		if ((ep_ck_deno == 0) || (ep_ck_nume == 0) ||
> +		    (ep_ck_deno >= ep_ck_nume))
> +			return -EBUSY;
> +	}
> +
> +	{
> +		u32 ick_x100;
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		switch (tnr_dmd->clk_mode) {
> +		case CXD2880_TNRDMD_CLOCKMODE_A:
> +			ick_x100 = 8228;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_B:
> +			ick_x100 = 9330;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_C:
> +			ick_x100 = 9600;
> +			break;
> +		default:
> +			return -EPERM;
> +		}
> +
> +		div = rd_smooth_dp;
> +
> +		Q = ick_x100 * 262144U / div;
> +		R = ick_x100 * 262144U % div;
> +
> +		R *= 5U;
> +		Q = Q * 5 + R / div;
> +		R = R % div;
> +
> +		R *= 2U;
> +		Q = Q * 2 + R / div;
> +		R = R % div;
> +
> +		if (div / 2 <= R)
> +			*ts_rate_kbps = Q + 1;
> +		else
> +			*ts_rate_kbps = Q;
> +	}
> +
> +	if (issy_on_data) {
> +		u32 diff = ep_ck_nume - ep_ck_deno;
> +
> +		while (diff > 0x7fff) {
> +			diff >>= 1;
> +			ep_ck_nume >>= 1;
> +		}
> +
> +		*ts_rate_kbps -=
> +		    (*ts_rate_kbps * diff + ep_ck_nume / 2) / ep_ck_nume;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u32 *per)
> +{
> +	int ret = 0;
> +	u32 packet_error = 0;
> +	u32 period = 0;
> +
> +	if (!tnr_dmd || !per)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 rdata[3];
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x18, rdata, 3);
> +		if (ret)
> +			return ret;
> +
> +		if ((rdata[0] & 0x01) == 0)
> +			return -EBUSY;
> +
> +		packet_error = (rdata[1] << 8) | rdata[2];
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x24);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xdc, rdata, 1);
> +		if (ret)
> +			return ret;
> +
> +		period = 1U << (rdata[0] & 0x0f);
> +	}
> +
> +	if ((period == 0) || (packet_error > period))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		div = period;
> +
> +		Q = (packet_error * 1000) / div;
> +		R = (packet_error * 1000) % div;
> +
> +		R *= 1000;
> +		Q = Q * 1000 + R / div;
> +		R = R % div;
> +
> +		if ((div != 1) && (div / 2 <= R))
> +			*per = Q + 1;
> +		else
> +			*per = Q;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
> +				 enum cxd2880_dvbt2_plp_btype type,
> +				 enum cxd2880_dvbt2_plp_constell *qam)
> +{
> +	u8 data;
> +	u8 l1_post_ok = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!qam))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x86, &l1_post_ok, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	if (!(l1_post_ok & 0x01)) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return -EBUSY;
> +	}
> +
> +	if (type == CXD2880_DVBT2_PLP_COMMON) {
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xb6, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (data == 0) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xb1, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +	} else {
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x9e, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	*qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
> +				       *tnr_dmd,
> +				       enum cxd2880_dvbt2_plp_btype
> +				       type,
> +				       enum
> +				       cxd2880_dvbt2_plp_code_rate
> +				       *code_rate)
> +{
> +	u8 data;
> +	u8 l1_post_ok = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!code_rate))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x86, &l1_post_ok, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	if (!(l1_post_ok & 0x01)) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return -EBUSY;
> +	}
> +
> +	if (type == CXD2880_DVBT2_PLP_COMMON) {
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xb6, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (data == 0) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xb0, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +	} else {
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x9d, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	*code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dvbt2_profile
> +				     *profile)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!profile))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x22, &data, sizeof(data));
> +		if (ret)
> +			return ret;
> +
> +		if (data & 0x02) {
> +			if (data & 0x01)
> +				*profile = CXD2880_DVBT2_PROFILE_LITE;
> +			else
> +				*profile = CXD2880_DVBT2_PROFILE_BASE;
> +		} else {
> +			ret = -EBUSY;
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN)
> +				ret =
> +				    cxd2880_tnrdmd_dvbt2_mon_profile(
> +					tnr_dmd->diver_sub, profile);
> +
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int dvbt2_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
> +			  int rf_lvl, u8 *ssi)
> +{
> +	enum cxd2880_dvbt2_plp_constell qam;
> +	enum cxd2880_dvbt2_plp_code_rate code_rate;
> +	int prel;
> +	int temp_ssi = 0;
> +	int ret = 0;
> +
> +	static const int ref_dbm_1000[4][8] = {
> +		{-96000, -95000, -94000, -93000, -92000, -92000, -98000,
> +		 -97000},
> +		{-91000, -89000, -88000, -87000, -86000, -86000, -93000,
> +		 -92000},
> +		{-86000, -85000, -83000, -82000, -81000, -80000, -89000,
> +		 -88000},
> +		{-82000, -80000, -78000, -76000, -75000, -74000, -86000,
> +		 -84000},
> +	};
> +
> +	if ((!tnr_dmd) || (!ssi))
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
> +					       &code_rate);
> +	if (ret)
> +		return ret;
> +
> +	if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256))
> +		return -EPERM;
> +
> +	prel = rf_lvl - ref_dbm_1000[qam][code_rate];
> +
> +	if (prel < -15000)
> +		temp_ssi = 0;
> +	else if (prel < 0)
> +		temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
> +	else if (prel < 20000)
> +		temp_ssi = (((4 * prel) + 500) / 1000) + 10;
> +	else if (prel < 35000)
> +		temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
> +	else
> +		temp_ssi = 100;
> +
> +	*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u8 *ssi)
> +{
> +	int rf_lvl = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ssi))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
> +	if (ret)
> +		return ret;
> +
> +	ret = dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u8 *ssi)
> +{
> +	int rf_lvl = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ssi))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
> +	if (ret)
> +		return ret;
> +
> +	ret = dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
> new file mode 100644
> index 000000000000..f7b2f618e80f
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
> @@ -0,0 +1,170 @@
> +/*
> + * cxd2880_tnrdmd_dvbt2_mon.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DVB-T2 monitor interface
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_TNRDMD_DVBT2_MON_H
> +#define CXD2880_TNRDMD_DVBT2_MON_H
> +
> +#include "cxd2880_tnrdmd.h"
> +#include "cxd2880_dvbt2.h"
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 *sync_stat,
> +				       u8 *ts_lock_stat,
> +				       u8 *unlock_detected);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
> +					   *tnr_dmd,
> +					   u8 *sync_stat,
> +					   u8 *unlock_detected);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
> +					    *tnr_dmd, int *offset);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
> +						cxd2880_tnrdmd
> +						*tnr_dmd,
> +						int *offset);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
> +				    struct cxd2880_dvbt2_l1pre
> +				    *l1_pre);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dvbt2_version
> +				     *ver);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
> +				  struct cxd2880_dvbt2_ofdm *ofdm);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 *plp_ids,
> +				       u8 *num_plps);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
> +					*tnr_dmd,
> +					enum
> +					cxd2880_dvbt2_plp_btype
> +					type,
> +					struct cxd2880_dvbt2_plp
> +					*plp_info);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
> +					    *tnr_dmd,
> +					    u8 *plp_error);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 *l1_change);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     struct cxd2880_dvbt2_l1post
> +				     *l1_post);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
> +				      *tnr_dmd,
> +				      enum cxd2880_dvbt2_plp_btype
> +				      type,
> +				      struct cxd2880_dvbt2_bbheader
> +				      *bbheader);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
> +					      *tnr_dmd,
> +					      enum
> +					      cxd2880_dvbt2_plp_btype
> +					      type,
> +					      u32 *ts_rate_bps);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
> +					    *tnr_dmd,
> +					    enum
> +					    cxd2880_tnrdmd_spectrum_sense
> +					    *sense);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
> +				 int *snr);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
> +				       *tnr_dmd, int *snr,
> +				       int *snr_main,
> +				       int *snr_sub);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd
> +					 *tnr_dmd, u32 *ber);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd
> +					 *tnr_dmd, u32 *fer);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd
> +					*tnr_dmd, u32 *ber);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
> +						 cxd2880_tnrdmd
> +						 *tnr_dmd,
> +						 u32 *pen);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
> +					     *tnr_dmd, int *ppm);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
> +						 cxd2880_tnrdmd
> +						 *tnr_dmd,
> +						 int *ppm);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u32 *ts_rate_kbps);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u8 *quality);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u32 *per);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
> +				 enum cxd2880_dvbt2_plp_btype type,
> +				 enum cxd2880_dvbt2_plp_constell
> +				 *qam);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
> +				       *tnr_dmd,
> +				       enum cxd2880_dvbt2_plp_btype
> +				       type,
> +				       enum
> +				       cxd2880_dvbt2_plp_code_rate
> +				       *code_rate);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dvbt2_profile
> +				     *profile);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u8 *ssi);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u8 *ssi);
> +
> +#endif



Thanks,
Mauro

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 11/14] [media] cxd2880: Add DVB-T2 monitor and integration layer functions
@ 2017-08-27 15:44     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 15:44 UTC (permalink / raw)
  To: Yasunari.Takiguchi-7U/KSKJipcs
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	tbird20d-Re5JQEeQqe8AvxtiuMwx3w,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w, Masayuki Yamamoto,
	Hideki Nozawa, Kota Yonezawa, Toshihiko Matsumoto,
	Satoshi Watanabe

Em Wed, 16 Aug 2017 13:43:41 +0900
<Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
> 
> Provide monitor and integration layer functions (DVB-T2)
> for the Sony CXD2880 DVB-T2/T tuner + demodulator driver.
> 
> [Change list]
> Changes in V3
>    drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
>       -changed CXD2880_SLEEP to usleep_range
>       -replaced cxd2880_atomic_set to atomic_set
>       -modified return code
>       -modified coding style of if()  
>    drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
>       -modified return code
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
>       -removed unnecessary cast
>       -changed cxd2880_math_log to intlog10
>       -modified return code
>       -modified coding style of if() 
>       -changed hexadecimal code to lower case. 
>    drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
>       -modified return code
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto-7U/KSKJipcs@public.gmane.org>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe-7U/KSKJipcs@public.gmane.org>
> ---
>  .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c    |  312 +++
>  .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h    |   64 +
>  .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.c             | 2622 ++++++++++++++++++++
>  .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.h             |  170 ++
>  4 files changed, 3168 insertions(+)
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
>  create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
> 
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
> new file mode 100644
> index 000000000000..ac049820d797
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c
> @@ -0,0 +1,312 @@
> +/*
> + * cxd2880_integ_dvbt2.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * integration layer functions for DVB-T2
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_tnrdmd_dvbt2.h"
> +#include "cxd2880_tnrdmd_dvbt2_mon.h"
> +#include "cxd2880_integ_dvbt2.h"
> +
> +static int dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd,
> +				 enum cxd2880_dvbt2_profile
> +				 profile);
> +
> +static int dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd);
> +
> +int cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd,
> +			     struct cxd2880_dvbt2_tune_param
> +			     *tune_param)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!tune_param))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) &&
> +	    (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE))
> +		return -EPERM;
> +
> +	atomic_set(&tnr_dmd->cancel, 0);
> +
> +	if ((tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ) &&
> +	    (tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ)) {
> +		return -EOPNOTSUPP;
> +	}
> +
> +	if ((tune_param->profile != CXD2880_DVBT2_PROFILE_BASE) &&
> +	    (tune_param->profile != CXD2880_DVBT2_PROFILE_LITE))
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param);
> +	if (ret)
> +		return ret;
> +
> +	usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000,
> +		     CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000);
> +
> +	ret = cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param);
> +	if (ret)
> +		return ret;
> +
> +	ret = dvbt2_wait_demod_lock(tnr_dmd, tune_param->profile);
> +	if (ret)
> +		return ret;
> +
> +	ret = cxd2880_tnrdmd_dvbt2_diver_fef_setting(tnr_dmd);
> +	if (ret == -EBUSY)
> +		return -EAGAIN;
> +	else if (ret)
> +		return ret;
> +
> +	ret = dvbt2_wait_l1_post_lock(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 plp_not_found;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_data_plp_error(tnr_dmd,
> +							    &plp_not_found);
> +		if (ret == -EBUSY)
> +			return -EAGAIN;
> +		else if (ret)
> +			return ret;
> +
> +		if (plp_not_found) {
> +			ret = -0;
> +			tune_param->tune_info =
> +			    CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID;
> +		} else {
> +			tune_param->tune_info =
> +			    CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dvbt2_profile
> +				     profile)
> +{

Same notes I made for DVB-T apply: it is up to userspace to wait for
device's lock. Are there any special reason why in this hardware
such lock should be done by the Kernel driver?

> +	int ret = 0;
> +	enum cxd2880_tnrdmd_lock_result lock =
> +	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +	u16 timeout = 0;
> +	struct cxd2880_stopwatch timer;
> +	u8 continue_wait = 1;
> +	unsigned int elapsed = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret = cxd2880_stopwatch_start(&timer);
> +	if (ret)
> +		return ret;
> +
> +	if (profile == CXD2880_DVBT2_PROFILE_BASE)
> +		timeout = CXD2880_DVBT2_BASE_WAIT_TS_LOCK;
> +	else if (profile == CXD2880_DVBT2_PROFILE_LITE)
> +		timeout = CXD2880_DVBT2_LITE_WAIT_TS_LOCK;
> +	else
> +		return -EINVAL;
> +
> +	for (;;) {

Same note here: use while(1) {} for infinite loops. Extra care is
required to not hang the Kernel.

> +		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
> +		if (ret)
> +			return ret;
> +
> +		if (elapsed >= timeout)
> +			continue_wait = 0;
> +
> +		ret = cxd2880_tnrdmd_dvbt2_check_ts_lock(tnr_dmd, &lock);
> +		if (ret)
> +			return ret;
> +
> +		switch (lock) {
> +		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
> +			return 0;
> +
> +		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
> +			return -EAGAIN;
> +
> +		default:
> +			break;
> +		}
> +
> +		ret = cxd2880_integ_check_cancellation(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (continue_wait) {
> +			ret =
> +			    cxd2880_stopwatch_sleep(&timer,
> +					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
> +			if (ret)
> +				return ret;
> +		} else {
> +			ret = -ETIME;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd,
> +				 enum cxd2880_dvbt2_profile
> +				 profile)
> +{
> +	int ret = 0;
> +	enum cxd2880_tnrdmd_lock_result lock =
> +	    CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
> +	u16 timeout = 0;
> +	struct cxd2880_stopwatch timer;
> +	u8 continue_wait = 1;
> +	unsigned int elapsed = 0;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	ret = cxd2880_stopwatch_start(&timer);
> +	if (ret)
> +		return ret;
> +
> +	if (profile == CXD2880_DVBT2_PROFILE_BASE)
> +		timeout = CXD2880_DVBT2_BASE_WAIT_DMD_LOCK;
> +	else if ((profile == CXD2880_DVBT2_PROFILE_LITE) ||
> +		 (profile == CXD2880_DVBT2_PROFILE_ANY))
> +		timeout = CXD2880_DVBT2_LITE_WAIT_DMD_LOCK;
> +	else
> +		return -EPERM;
> +
> +	for (;;) {
> +		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
> +		if (ret)
> +			return ret;
> +
> +		if (elapsed >= timeout)
> +			continue_wait = 0;
> +
> +		ret = cxd2880_tnrdmd_dvbt2_check_demod_lock(tnr_dmd, &lock);
> +		if (ret)
> +			return ret;
> +
> +		switch (lock) {
> +		case CXD2880_TNRDMD_LOCK_RESULT_LOCKED:
> +			return 0;
> +
> +		case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED:
> +			return -EAGAIN;
> +
> +		default:
> +			break;
> +		}
> +
> +		ret = cxd2880_integ_check_cancellation(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (continue_wait) {
> +			ret =
> +			    cxd2880_stopwatch_sleep(&timer,
> +					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
> +			if (ret)
> +				return ret;
> +		} else {
> +			ret = -ETIME;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd)
> +{
> +	int ret = 0;
> +	struct cxd2880_stopwatch timer;
> +	u8 continue_wait = 1;
> +	unsigned int elapsed = 0;
> +	u8 l1_post_valid;
> +
> +	if (!tnr_dmd)
> +		return -EINVAL;
> +
> +	ret = cxd2880_stopwatch_start(&timer);
> +	if (ret)
> +		return ret;
> +
> +	for (;;) {
> +		ret = cxd2880_stopwatch_elapsed(&timer, &elapsed);
> +		if (ret)
> +			return ret;
> +
> +		if (elapsed >= CXD2880_DVBT2_L1POST_TIMEOUT)
> +			continue_wait = 0;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_check_l1post_valid(tnr_dmd,
> +							    &l1_post_valid);
> +		if (ret)
> +			return ret;
> +
> +		if (l1_post_valid)
> +			return 0;
> +
> +		ret = cxd2880_integ_check_cancellation(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		if (continue_wait) {
> +			ret =
> +			    cxd2880_stopwatch_sleep(&timer,
> +					    CXD2880_DVBT2_WAIT_LOCK_INTVL);
> +			if (ret)
> +				return ret;
> +		} else {
> +			ret = -ETIME;
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
> new file mode 100644
> index 000000000000..c7b1df6306df
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h
> @@ -0,0 +1,64 @@
> +/*
> + * cxd2880_integ_dvbt2.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * integration layer interface for DVB-T2
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_INTEG_DVBT2_H
> +#define CXD2880_INTEG_DVBT2_H
> +
> +#include "cxd2880_tnrdmd.h"
> +#include "cxd2880_tnrdmd_dvbt2.h"
> +#include "cxd2880_integ.h"
> +
> +#define CXD2880_DVBT2_BASE_WAIT_DMD_LOCK     3500
> +#define CXD2880_DVBT2_BASE_WAIT_TS_LOCK	1500
> +#define CXD2880_DVBT2_LITE_WAIT_DMD_LOCK     5000
> +#define CXD2880_DVBT2_LITE_WAIT_TS_LOCK	2300
> +#define CXD2880_DVBT2_WAIT_LOCK_INTVL       10
> +#define CXD2880_DVBT2_L1POST_TIMEOUT	   500
> +
> +struct cxd2880_integ_dvbt2_scan_param {
> +	u32 start_frequency_khz;
> +	u32 end_frequency_khz;
> +	u32 step_frequency_khz;
> +	enum cxd2880_dtv_bandwidth bandwidth;
> +	enum cxd2880_dvbt2_profile t2_profile;
> +};
> +
> +struct cxd2880_integ_dvbt2_scan_result {
> +	u32 center_freq_khz;
> +	int tune_result;
> +	struct cxd2880_dvbt2_tune_param dvbt2_tune_param;
> +};
> +
> +int cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd,
> +			     struct cxd2880_dvbt2_tune_param
> +			     *tune_param);
> +
> +int cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dvbt2_profile
> +				     profile);
> +
> +#endif
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
> new file mode 100644
> index 000000000000..62ee5d540dff
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
> @@ -0,0 +1,2622 @@
> +/*
> + * cxd2880_tnrdmd_dvbt2_mon.c
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DVB-T2 monitor functions
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "cxd2880_tnrdmd_mon.h"
> +#include "cxd2880_tnrdmd_dvbt2.h"
> +#include "cxd2880_tnrdmd_dvbt2_mon.h"
> +
> +#include "dvb_math.h"
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 *sync_stat,
> +				       u8 *ts_lock_stat,
> +				       u8 *unlock_detected)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data;

Same notes that I made to other patches apply here.

> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x10, &data, sizeof(data));
> +		if (ret)
> +			return ret;
> +
> +		*sync_stat = data & 0x07;
> +		*ts_lock_stat = ((data & 0x20) ? 1 : 0);
> +		*unlock_detected = ((data & 0x10) ? 1 : 0);
> +	}
> +
> +	if (*sync_stat == 0x07)
> +		return -EBUSY;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
> +					   *tnr_dmd,
> +					   u8 *sync_stat,
> +					   u8 *unlock_detected)
> +{
> +	u8 ts_lock_stat = 0;
> +
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub, sync_stat,
> +					       &ts_lock_stat, unlock_detected);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
> +					    *tnr_dmd, int *offset)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!offset))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[4];
> +		u32 ctl_val = 0;
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state != 6) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x30, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		ctl_val =
> +		    ((data[0] & 0x0f) << 24) | (data[1] << 16) | (data[2] << 8)
> +		    | (data[3]);
> +		*offset = cxd2880_convert2s_complement(ctl_val, 28);
> +
> +		switch (tnr_dmd->bandwidth) {
> +		case CXD2880_DTV_BW_1_7_MHZ:
> +			*offset = -1 * ((*offset) / 582);
> +			break;
> +		case CXD2880_DTV_BW_5_MHZ:
> +		case CXD2880_DTV_BW_6_MHZ:
> +		case CXD2880_DTV_BW_7_MHZ:
> +		case CXD2880_DTV_BW_8_MHZ:
> +			*offset =
> +			    -1 * ((*offset) * tnr_dmd->bandwidth / 940);
> +			break;
> +		default:
> +			return -EPERM;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
> +						cxd2880_tnrdmd
> +						*tnr_dmd,
> +						int *offset)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!offset))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub, offset);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
> +				    struct cxd2880_dvbt2_l1pre
> +				    *l1_pre)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!l1_pre))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[37];
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +		u8 version = 0;
> +		enum cxd2880_dvbt2_profile profile;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state < 5) {
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +				ret =
> +				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
> +				    (tnr_dmd, &sync_state, &unlock_detected);
> +				if (ret) {
> +					slvt_unfreeze_reg(tnr_dmd);
> +					return ret;
> +				}
> +
> +				if (sync_state < 5) {
> +					slvt_unfreeze_reg(tnr_dmd);
> +					return -EBUSY;
> +				}
> +			} else {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return -EBUSY;
> +			}
> +		}
> +
> +		ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x61, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0];
> +		l1_pre->bw_ext = data[1] & 0x01;
> +		l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07);
> +		l1_pre->s2 = data[3] & 0x0f;
> +		l1_pre->l1_rep = data[4] & 0x01;
> +		l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07);
> +		l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0f);
> +		l1_pre->mod =
> +		    (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0f);
> +		l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03);
> +		l1_pre->fec =
> +		    (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03);
> +		l1_pre->l1_post_size = (data[10] & 0x03) << 16;
> +		l1_pre->l1_post_size |= (data[11]) << 8;
> +		l1_pre->l1_post_size |= (data[12]);
> +		l1_pre->l1_post_info_size = (data[13] & 0x03) << 16;
> +		l1_pre->l1_post_info_size |= (data[14]) << 8;
> +		l1_pre->l1_post_info_size |= (data[15]);
> +		l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0f);
> +		l1_pre->tx_id_availability = data[17];
> +		l1_pre->cell_id = (data[18] << 8);
> +		l1_pre->cell_id |= (data[19]);
> +		l1_pre->network_id = (data[20] << 8);
> +		l1_pre->network_id |= (data[21]);
> +		l1_pre->sys_id = (data[22] << 8);
> +		l1_pre->sys_id |= (data[23]);
> +		l1_pre->num_frames = data[24];
> +		l1_pre->num_symbols = (data[25] & 0x0f) << 8;
> +		l1_pre->num_symbols |= data[26];
> +		l1_pre->regen = data[27] & 0x07;
> +		l1_pre->post_ext = data[28] & 0x01;
> +		l1_pre->num_rf_freqs = data[29] & 0x07;
> +		l1_pre->rf_idx = data[30] & 0x07;
> +		version = (data[31] & 0x03) << 2;
> +		version |= (data[32] & 0xc0) >> 6;
> +		l1_pre->t2_version = (enum cxd2880_dvbt2_version)version;
> +		l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5;
> +		l1_pre->t2_base_lite = (data[32] & 0x10) >> 4;
> +		l1_pre->crc32 = (data[33] << 24);
> +		l1_pre->crc32 |= (data[34] << 16);
> +		l1_pre->crc32 |= (data[35] << 8);
> +		l1_pre->crc32 |= data[36];
> +
> +		if (profile == CXD2880_DVBT2_PROFILE_BASE) {
> +			switch ((l1_pre->s2 >> 1)) {
> +			case CXD2880_DVBT2_BASE_S2_M1K_G_ANY:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M1K;
> +				break;
> +			case CXD2880_DVBT2_BASE_S2_M2K_G_ANY:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M2K;
> +				break;
> +			case CXD2880_DVBT2_BASE_S2_M4K_G_ANY:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M4K;
> +				break;
> +			case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT:
> +			case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M8K;
> +				break;
> +			case CXD2880_DVBT2_BASE_S2_M16K_G_ANY:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M16K;
> +				break;
> +			case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT:
> +			case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M32K;
> +				break;
> +			default:
> +				return -EBUSY;
> +			}
> +		} else if (profile == CXD2880_DVBT2_PROFILE_LITE) {
> +			switch ((l1_pre->s2 >> 1)) {
> +			case CXD2880_DVBT2_LITE_S2_M2K_G_ANY:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M2K;
> +				break;
> +			case CXD2880_DVBT2_LITE_S2_M4K_G_ANY:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M4K;
> +				break;
> +			case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT:
> +			case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M8K;
> +				break;
> +			case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT:
> +			case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2:
> +				l1_pre->fft_mode = CXD2880_DVBT2_M16K;
> +				break;
> +			default:
> +				return -EBUSY;
> +			}
> +		} else {
> +			return -EBUSY;
> +		}
> +
> +		l1_pre->mixed = l1_pre->s2 & 0x01;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dvbt2_version
> +				     *ver)
> +{
> +	int ret = 0;
> +	u8 version = 0;
> +
> +	if ((!tnr_dmd) || (!ver))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[2];
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state < 5) {
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +				ret =
> +				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
> +				    (tnr_dmd, &sync_state, &unlock_detected);
> +				if (ret) {
> +					slvt_unfreeze_reg(tnr_dmd);
> +					return ret;
> +				}
> +
> +				if (sync_state < 5) {
> +					slvt_unfreeze_reg(tnr_dmd);
> +					return -EBUSY;
> +				}
> +			} else {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return -EBUSY;
> +			}
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x80, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		version = ((data[0] & 0x03) << 2);
> +		version |= ((data[1] & 0xc0) >> 6);
> +		*ver = (enum cxd2880_dvbt2_version)version;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
> +				  struct cxd2880_dvbt2_ofdm *ofdm)
> +{
> +	if ((!tnr_dmd) || (!ofdm))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[5];
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +		int ret = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state != 6) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +
> +			ret = -EBUSY;
> +
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN)
> +				ret =
> +				    cxd2880_tnrdmd_dvbt2_mon_ofdm(
> +					tnr_dmd->diver_sub, ofdm);
> +
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x1d, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		ofdm->mixed = ((data[0] & 0x20) ? 1 : 0);
> +		ofdm->is_miso = ((data[0] & 0x10) >> 4);
> +		ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07);
> +		ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4);
> +		ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07);
> +		ofdm->bw_ext = (data[2] & 0x10) >> 4;
> +		ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0f);
> +		ofdm->num_symbols = (data[3] << 8) | data[4];
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 *plp_ids,
> +				       u8 *num_plps)
> +{
> +	if ((!tnr_dmd) || (!num_plps))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 l1_post_ok = 0;
> +		int ret = 0;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret)
> +			return ret;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x86, &l1_post_ok, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!(l1_post_ok & 0x01)) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xc1, num_plps, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (*num_plps == 0) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EPERM;
> +		}
> +
> +		if (!plp_ids) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return 0;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xc2,
> +					     plp_ids,
> +					     ((*num_plps > 62) ?
> +					     62 : *num_plps));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (*num_plps > 62) {
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x00, 0x0c);
> +			if (ret) {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return ret;
> +			}
> +
> +			ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x10, plp_ids + 62,
> +						     *num_plps - 62);
> +			if (ret) {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return ret;
> +			}
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +	}
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
> +					*tnr_dmd,
> +					enum
> +					cxd2880_dvbt2_plp_btype
> +					type,
> +					struct cxd2880_dvbt2_plp
> +					*plp_info)
> +{
> +	if ((!tnr_dmd) || (!plp_info))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[20];
> +		u8 addr = 0;
> +		u8 index = 0;
> +		u8 l1_post_ok = 0;
> +		int ret = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x86, &l1_post_ok, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!l1_post_ok) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		if (type == CXD2880_DVBT2_PLP_COMMON)
> +			addr = 0xa9;
> +		else
> +			addr = 0x96;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     addr, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		if ((type == CXD2880_DVBT2_PLP_COMMON) && (data[13] == 0))
> +			return -EBUSY;
> +
> +		plp_info->id = data[index++];
> +		plp_info->type =
> +		    (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07);
> +		plp_info->payload =
> +		    (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1f);
> +		plp_info->ff = data[index++] & 0x01;
> +		plp_info->first_rf_idx = data[index++] & 0x07;
> +		plp_info->first_frm_idx = data[index++];
> +		plp_info->group_id = data[index++];
> +		plp_info->plp_cr =
> +		    (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07);
> +		plp_info->constell =
> +		    (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07);
> +		plp_info->rot = data[index++] & 0x01;
> +		plp_info->fec =
> +		    (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03);
> +		plp_info->num_blocks_max = (data[index++] & 0x03) << 8;
> +		plp_info->num_blocks_max |= data[index++];
> +		plp_info->frm_int = data[index++];
> +		plp_info->til_len = data[index++];
> +		plp_info->til_type = data[index++] & 0x01;
> +
> +		plp_info->in_band_a_flag = data[index++] & 0x01;
> +		plp_info->rsvd = data[index++] << 8;
> +		plp_info->rsvd |= data[index++];
> +
> +		plp_info->in_band_b_flag =
> +		    (plp_info->rsvd & 0x8000) >> 15;
> +		plp_info->plp_mode =
> +		    (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000c) >>
> +						  2);
> +		plp_info->static_flag = (plp_info->rsvd & 0x0002) >> 1;
> +		plp_info->static_padding_flag = plp_info->rsvd & 0x0001;
> +		plp_info->rsvd = (plp_info->rsvd & 0x7ff0) >> 4;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
> +					    *tnr_dmd,
> +					    u8 *plp_error)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!plp_error))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x86, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if ((data & 0x01) == 0x00) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xc0, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		*plp_error = data & 0x01;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 *l1_change)
> +{
> +	if ((!tnr_dmd) || (!l1_change))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data;
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +		int ret = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state < 5) {
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN) {
> +				ret =
> +				    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
> +				    (tnr_dmd, &sync_state, &unlock_detected);
> +				if (ret) {
> +					slvt_unfreeze_reg(tnr_dmd);
> +					return ret;
> +				}
> +
> +				if (sync_state < 5) {
> +					slvt_unfreeze_reg(tnr_dmd);
> +					return -EBUSY;
> +				}
> +			} else {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return -EBUSY;
> +			}
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x5f, &data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		*l1_change = data & 0x01;
> +		if (*l1_change) {
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x00, 0x22);
> +			if (ret) {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return ret;
> +			}
> +
> +			ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +						     CXD2880_IO_TGT_DMD,
> +						     0x16, 0x01);
> +			if (ret) {
> +				slvt_unfreeze_reg(tnr_dmd);
> +				return ret;
> +			}
> +		}
> +		slvt_unfreeze_reg(tnr_dmd);
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     struct cxd2880_dvbt2_l1post
> +				     *l1_post)
> +{
> +	if ((!tnr_dmd) || (!l1_post))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[16];
> +		int ret = 0;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x86, data, sizeof(data));
> +		if (ret)
> +			return ret;
> +
> +		if (!(data[0] & 0x01))
> +			return -EBUSY;
> +
> +		l1_post->sub_slices_per_frame = (data[1] & 0x7f) << 8;
> +		l1_post->sub_slices_per_frame |= data[2];
> +		l1_post->num_plps = data[3];
> +		l1_post->num_aux = data[4] & 0x0f;
> +		l1_post->aux_cfg_rfu = data[5];
> +		l1_post->rf_idx = data[6] & 0x07;
> +		l1_post->freq = data[7] << 24;
> +		l1_post->freq |= data[8] << 16;
> +		l1_post->freq |= data[9] << 8;
> +		l1_post->freq |= data[10];
> +		l1_post->fef_type = data[11] & 0x0f;
> +		l1_post->fef_length = data[12] << 16;
> +		l1_post->fef_length |= data[13] << 8;
> +		l1_post->fef_length |= data[14];
> +		l1_post->fef_intvl = data[15];
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
> +				      *tnr_dmd,
> +				      enum cxd2880_dvbt2_plp_btype
> +				      type,
> +				      struct cxd2880_dvbt2_bbheader
> +				      *bbheader)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!bbheader))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!ts_lock) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	if (type == CXD2880_DVBT2_PLP_COMMON) {
> +		u8 l1_post_ok;
> +		u8 data;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x86, &l1_post_ok, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!(l1_post_ok & 0x01)) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xb6, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (data == 0) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +	}
> +
> +	{
> +		u8 data[14];
> +		u8 addr = 0;
> +
> +		if (type == CXD2880_DVBT2_PLP_COMMON)
> +			addr = 0x51;
> +		else
> +			addr = 0x42;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     addr, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		bbheader->stream_input =
> +		    (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03);
> +		bbheader->is_single_input_stream = (data[0] >> 5) & 0x01;
> +		bbheader->is_constant_coding_modulation =
> +		    (data[0] >> 4) & 0x01;
> +		bbheader->issy_indicator = (data[0] >> 3) & 0x01;
> +		bbheader->null_packet_deletion = (data[0] >> 2) & 0x01;
> +		bbheader->ext = data[0] & 0x03;
> +
> +		bbheader->input_stream_identifier = data[1];
> +		bbheader->plp_mode =
> +		    (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM :
> +		    CXD2880_DVBT2_PLP_MODE_NM;
> +		bbheader->data_field_length = (data[4] << 8) | data[5];
> +
> +		if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
> +			bbheader->user_packet_length =
> +			    (data[6] << 8) | data[7];
> +			bbheader->sync_byte = data[8];
> +			bbheader->issy = 0;
> +		} else {
> +			bbheader->user_packet_length = 0;
> +			bbheader->sync_byte = 0;
> +			bbheader->issy =
> +			    (data[11] << 16) | (data[12] << 8) | data[13];
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
> +					      *tnr_dmd,
> +					      enum
> +					      cxd2880_dvbt2_plp_btype
> +					      type,
> +					      u32 *ts_rate_bps)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ts_rate_bps))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!ts_lock) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	{
> +		u8 l1_post_ok = 0;
> +		u8 addr = 0;
> +		u8 data = 0;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x86, &l1_post_ok, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!(l1_post_ok & 0x01)) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		if (type == CXD2880_DVBT2_PLP_COMMON)
> +			addr = 0xba;
> +		else
> +			addr = 0xa7;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     addr, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if ((data & 0x80) == 0x00) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +	}
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x25);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	{
> +		u8 data[4];
> +		u8 addr = 0;
> +
> +		if (type == CXD2880_DVBT2_PLP_COMMON)
> +			addr = 0xa6;
> +		else
> +			addr = 0xaa;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     addr, &data[0], 4);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		*ts_rate_bps = ((data[0] & 0x07) << 24) | (data[1] << 16) |
> +			       (data[2] << 8) | data[3];
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
> +					    *tnr_dmd,
> +					    enum
> +					    cxd2880_tnrdmd_spectrum_sense
> +					    *sense)
> +{
> +	int ret = 0;
> +	u8 sync_state = 0;
> +	u8 ts_lock = 0;
> +	u8 early_unlock = 0;
> +
> +	if ((!tnr_dmd) || (!sense))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock,
> +					       &early_unlock);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	if (sync_state != 6) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		ret = -EBUSY;
> +
> +		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
> +			ret =
> +			    cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(
> +				tnr_dmd->diver_sub, sense);
> +
> +		return ret;
> +	}
> +
> +	{
> +		u8 data = 0;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x2f, &data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		*sense =
> +		    (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
> +		    CXD2880_TNRDMD_SPECTRUM_NORMAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
> +			      u16 *reg_value)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!reg_value))
> +		return -EINVAL;
> +
> +	{
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +		u8 data[2];
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state != 6) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x13, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		*reg_value = (data[0] << 8) | data[1];
> +	}
> +
> +	return ret;
> +}
> +
> +static int dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
> +			  u32 reg_value, int *snr)
> +{
> +	if ((!tnr_dmd) || (!snr))
> +		return -EINVAL;
> +
> +	if (reg_value == 0)
> +		return -EBUSY;
> +
> +	if (reg_value > 10876)
> +		reg_value = 10876;
> +
> +	*snr = intlog10(reg_value) - intlog10(12600 - reg_value);
> +	*snr = (*snr + 839) / 1678 + 32000;
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
> +				 int *snr)
> +{
> +	u16 reg_value = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!snr))
> +		return -EINVAL;
> +
> +	*snr = -1000 * 1000;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
> +		ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
> +		if (ret)
> +			return ret;
> +
> +		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr);
> +		if (ret)
> +			return ret;
> +	} else {
> +		int snr_main = 0;
> +		int snr_sub = 0;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main,
> +						       &snr_sub);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
> +				       *tnr_dmd, int *snr,
> +				       int *snr_main, int *snr_sub)
> +{
> +	u16 reg_value = 0;
> +	u32 reg_value_sum = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub))
> +		return -EINVAL;
> +
> +	*snr = -1000 * 1000;
> +	*snr_main = -1000 * 1000;
> +	*snr_sub = -1000 * 1000;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
> +	if (!ret) {
> +		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main);
> +		if (ret)
> +			reg_value = 0;
> +	} else if (ret == -EBUSY) {
> +		reg_value = 0;
> +	} else {
> +		return ret;
> +	}
> +
> +	reg_value_sum += reg_value;
> +
> +	ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
> +	if (!ret) {
> +		ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
> +		if (ret)
> +			reg_value = 0;
> +	} else if (ret == -EBUSY) {
> +		reg_value = 0;
> +	} else {
> +		return ret;
> +	}
> +
> +	reg_value_sum += reg_value;
> +
> +	ret = dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd
> +					 *tnr_dmd, u32 *ber)
> +{
> +	int ret = 0;
> +	u32 bit_error = 0;
> +	u32 period_exp = 0;
> +	u32 n_ldpc = 0;
> +
> +	if ((!tnr_dmd) || (!ber))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	{
> +		u8 data[5];
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x3c, data, sizeof(data));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!(data[0] & 0x01)) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		bit_error =
> +		    ((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8)
> +		    | data[4];
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xa0, data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) ==
> +		    CXD2880_DVBT2_FEC_LDPC_16K)
> +			n_ldpc = 16200;
> +		else
> +			n_ldpc = 64800;
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x20);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x6f, data, 1);
> +		if (ret)
> +			return ret;
> +
> +		period_exp = data[0] & 0x0f;
> +	}
> +
> +	if (bit_error > ((1U << period_exp) * n_ldpc))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		if (period_exp >= 4) {
> +			div = (1U << (period_exp - 4)) * (n_ldpc / 200);
> +
> +			Q = (bit_error * 5) / div;
> +			R = (bit_error * 5) % div;
> +
> +			R *= 625;
> +			Q = Q * 625 + R / div;
> +			R = R % div;
> +		} else {
> +			div = (1U << period_exp) * (n_ldpc / 200);
> +
> +			Q = (bit_error * 10) / div;
> +			R = (bit_error * 10) % div;
> +
> +			R *= 5000;
> +			Q = Q * 5000 + R / div;
> +			R = R % div;
> +		}
> +
> +		if (div / 2 <= R)
> +			*ber = Q + 1;
> +		else
> +			*ber = Q;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd
> +					 *tnr_dmd, u32 *fer)
> +{
> +	int ret = 0;
> +	u32 fec_error = 0;
> +	u32 period = 0;
> +
> +	if ((!tnr_dmd) || (!fer))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data[2];
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x1b, data, 2);
> +		if (ret)
> +			return ret;
> +
> +		if (!(data[0] & 0x80))
> +			return -EBUSY;
> +
> +		fec_error = ((data[0] & 0x7f) << 8) | (data[1]);
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x20);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x72, data, 1);
> +		if (ret)
> +			return ret;
> +
> +		period = (1 << (data[0] & 0x0f));
> +	}
> +
> +	if ((period == 0) || (fec_error > period))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		div = period;
> +
> +		Q = (fec_error * 1000) / div;
> +		R = (fec_error * 1000) % div;
> +
> +		R *= 1000;
> +		Q = Q * 1000 + R / div;
> +		R = R % div;
> +
> +		if ((div != 1) && (div / 2 <= R))
> +			*fer = Q + 1;
> +		else
> +			*fer = Q;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd
> +					*tnr_dmd, u32 *ber)
> +{
> +	int ret = 0;
> +	u32 bit_error = 0;
> +	u32 period_exp = 0;
> +	u32 n_bch = 0;
> +
> +	if ((!tnr_dmd) || (!ber))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[3];
> +		enum cxd2880_dvbt2_plp_fec plp_fec_type =
> +		    CXD2880_DVBT2_FEC_LDPC_16K;
> +		enum cxd2880_dvbt2_plp_code_rate plp_cr = CXD2880_DVBT2_R1_2;
> +
> +		static const u16 n_bch_bits_lookup[2][8] = {
> +			{7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480},
> +			{32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920}
> +		};
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x15, data, 3);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!(data[0] & 0x40)) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		bit_error = ((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2];
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x9d, data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		plp_cr = (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07);
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xa0, data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03);
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x20);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x72, data, 1);
> +		if (ret)
> +			return ret;
> +
> +		period_exp = data[0] & 0x0f;
> +
> +		if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) ||
> +		    (plp_cr > CXD2880_DVBT2_R2_5))
> +			return -EBUSY;
> +
> +		n_bch = n_bch_bits_lookup[plp_fec_type][plp_cr];
> +	}
> +
> +	if (bit_error > ((1U << period_exp) * n_bch))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		if (period_exp >= 6) {
> +			div = (1U << (period_exp - 6)) * (n_bch / 40);
> +
> +			Q = (bit_error * 625) / div;
> +			R = (bit_error * 625) % div;
> +
> +			R *= 625;
> +			Q = Q * 625 + R / div;
> +			R = R % div;
> +		} else {
> +			div = (1U << period_exp) * (n_bch / 40);
> +
> +			Q = (bit_error * 1000) / div;
> +			R = (bit_error * 1000) % div;
> +
> +			R *= 25000;
> +			Q = Q * 25000 + R / div;
> +			R = R % div;
> +		}
> +
> +		if (div / 2 <= R)
> +			*ber = Q + 1;
> +		else
> +			*ber = Q;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
> +						 cxd2880_tnrdmd
> +						 *tnr_dmd,
> +						 u32 *pen)
> +{
> +	int ret = 0;
> +
> +	u8 data[3];
> +
> +	if ((!tnr_dmd) || (!pen))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x39, data, sizeof(data));
> +	if (ret)
> +		return ret;
> +
> +	if (!(data[0] & 0x01))
> +		return -EBUSY;
> +
> +	*pen = ((data[1] << 8) | data[2]);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
> +					     *tnr_dmd, int *ppm)
> +{
> +	if ((!tnr_dmd) || (!ppm))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 ctl_val_reg[5];
> +		u8 nominal_rate_reg[5];
> +		u32 trl_ctl_val = 0;
> +		u32 trcg_nominal_rate = 0;
> +		int num;
> +		int den;
> +		int ret = 0;
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +		s8 diff_upper = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (sync_state != 6) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x34, ctl_val_reg,
> +					     sizeof(ctl_val_reg));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x04);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x10, nominal_rate_reg,
> +					     sizeof(nominal_rate_reg));
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +
> +		diff_upper =
> +		    (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
> +
> +		if ((diff_upper < -1) || (diff_upper > 1))
> +			return -EBUSY;
> +
> +		trl_ctl_val = ctl_val_reg[1] << 24;
> +		trl_ctl_val |= ctl_val_reg[2] << 16;
> +		trl_ctl_val |= ctl_val_reg[3] << 8;
> +		trl_ctl_val |= ctl_val_reg[4];
> +
> +		trcg_nominal_rate = nominal_rate_reg[1] << 24;
> +		trcg_nominal_rate |= nominal_rate_reg[2] << 16;
> +		trcg_nominal_rate |= nominal_rate_reg[3] << 8;
> +		trcg_nominal_rate |= nominal_rate_reg[4];
> +
> +		trl_ctl_val >>= 1;
> +		trcg_nominal_rate >>= 1;
> +
> +		if (diff_upper == 1)
> +			num =
> +			    (int)((trl_ctl_val + 0x80000000u) -
> +				  trcg_nominal_rate);
> +		else if (diff_upper == -1)
> +			num =
> +			    -(int)((trcg_nominal_rate + 0x80000000u) -
> +				   trl_ctl_val);
> +		else
> +			num = (int)(trl_ctl_val - trcg_nominal_rate);
> +
> +		den = (nominal_rate_reg[0] & 0x7f) << 24;
> +		den |= nominal_rate_reg[1] << 16;
> +		den |= nominal_rate_reg[2] << 8;
> +		den |= nominal_rate_reg[3];
> +		den = (den + (390625 / 2)) / 390625;
> +
> +		den >>= 1;
> +
> +		if (num >= 0)
> +			*ppm = (num + (den / 2)) / den;
> +		else
> +			*ppm = (num - (den / 2)) / den;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
> +						 cxd2880_tnrdmd
> +						 *tnr_dmd,
> +						 int *ppm)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ppm))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u8 *quality)
> +{
> +	int ret = 0;
> +	int snr = 0;
> +	int snr_rel = 0;
> +	u32 ber = 0;
> +	u32 ber_sqi = 0;
> +	enum cxd2880_dvbt2_plp_constell qam;
> +	enum cxd2880_dvbt2_plp_code_rate code_rate;
> +
> +	static const int snr_nordig_p1_db_1000[4][8] = {
> +		{3500, 4700, 5600, 6600, 7200, 7700, 1300, 2200},
> +		{8700, 10100, 11400, 12500, 13300, 13800, 6000, 7200},
> +		{13000, 14800, 16200, 17700, 18700, 19400, 9800, 11100},
> +		{17000, 19400, 20800, 22900, 24300, 25100, 13200, 14800},
> +	};
> +
> +	if ((!tnr_dmd) || (!quality))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(tnr_dmd, &ber);
> +	if (ret)
> +		return ret;
> +
> +	ret = cxd2880_tnrdmd_dvbt2_mon_snr(tnr_dmd, &snr);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
> +					       &code_rate);
> +	if (ret)
> +		return ret;
> +
> +	if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256))
> +		return -EPERM;
> +
> +	if (ber > 100000)
> +		ber_sqi = 0;
> +	else if (ber >= 100)
> +		ber_sqi = 6667;
> +	else
> +		ber_sqi = 16667;
> +
> +	snr_rel = snr - snr_nordig_p1_db_1000[qam][code_rate];
> +
> +	if (snr_rel < -3000) {
> +		*quality = 0;
> +	} else if (snr_rel <= 3000) {
> +		u32 temp_sqi =
> +		    (((snr_rel + 3000) * ber_sqi) + 500000) / 1000000;
> +		*quality = (temp_sqi > 100) ? 100 : (u8)temp_sqi;
> +	} else {
> +		*quality = 100;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u32 *ts_rate_kbps)
> +{
> +	int ret = 0;
> +	u32 rd_smooth_dp = 0;
> +	u32 ep_ck_nume = 0;
> +	u32 ep_ck_deno = 0;
> +	u8 issy_on_data = 0;
> +
> +	if ((!tnr_dmd) || (!ts_rate_kbps))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 data[12];
> +		u8 sync_state = 0;
> +		u8 ts_lock = 0;
> +		u8 unlock_detected = 0;
> +
> +		ret = slvt_freeze_reg(tnr_dmd);
> +		if (ret)
> +			return ret;
> +
> +		ret =
> +		    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
> +						       &ts_lock,
> +						       &unlock_detected);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (!ts_lock) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x23, data, 12);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		rd_smooth_dp = (data[0] & 0x1f) << 24;
> +		rd_smooth_dp |= data[1] << 16;
> +		rd_smooth_dp |= data[2] << 8;
> +		rd_smooth_dp |= data[3];
> +
> +		if (rd_smooth_dp < 214958) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ep_ck_nume = (data[4] & 0x3f) << 24;
> +		ep_ck_nume |= data[5] << 16;
> +		ep_ck_nume |= data[6] << 8;
> +		ep_ck_nume |= data[7];
> +
> +		ep_ck_deno = (data[8] & 0x3f) << 24;
> +		ep_ck_deno |= data[9] << 16;
> +		ep_ck_deno |= data[10] << 8;
> +		ep_ck_deno |= data[11];
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x41, data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		issy_on_data = data[0] & 0x01;
> +
> +		slvt_unfreeze_reg(tnr_dmd);
> +	}
> +
> +	if (issy_on_data) {
> +		if ((ep_ck_deno == 0) || (ep_ck_nume == 0) ||
> +		    (ep_ck_deno >= ep_ck_nume))
> +			return -EBUSY;
> +	}
> +
> +	{
> +		u32 ick_x100;
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		switch (tnr_dmd->clk_mode) {
> +		case CXD2880_TNRDMD_CLOCKMODE_A:
> +			ick_x100 = 8228;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_B:
> +			ick_x100 = 9330;
> +			break;
> +		case CXD2880_TNRDMD_CLOCKMODE_C:
> +			ick_x100 = 9600;
> +			break;
> +		default:
> +			return -EPERM;
> +		}
> +
> +		div = rd_smooth_dp;
> +
> +		Q = ick_x100 * 262144U / div;
> +		R = ick_x100 * 262144U % div;
> +
> +		R *= 5U;
> +		Q = Q * 5 + R / div;
> +		R = R % div;
> +
> +		R *= 2U;
> +		Q = Q * 2 + R / div;
> +		R = R % div;
> +
> +		if (div / 2 <= R)
> +			*ts_rate_kbps = Q + 1;
> +		else
> +			*ts_rate_kbps = Q;
> +	}
> +
> +	if (issy_on_data) {
> +		u32 diff = ep_ck_nume - ep_ck_deno;
> +
> +		while (diff > 0x7fff) {
> +			diff >>= 1;
> +			ep_ck_nume >>= 1;
> +		}
> +
> +		*ts_rate_kbps -=
> +		    (*ts_rate_kbps * diff + ep_ck_nume / 2) / ep_ck_nume;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u32 *per)
> +{
> +	int ret = 0;
> +	u32 packet_error = 0;
> +	u32 period = 0;
> +
> +	if (!tnr_dmd || !per)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	{
> +		u8 rdata[3];
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x0b);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x18, rdata, 3);
> +		if (ret)
> +			return ret;
> +
> +		if ((rdata[0] & 0x01) == 0)
> +			return -EBUSY;
> +
> +		packet_error = (rdata[1] << 8) | rdata[2];
> +
> +		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x00, 0x24);
> +		if (ret)
> +			return ret;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xdc, rdata, 1);
> +		if (ret)
> +			return ret;
> +
> +		period = 1U << (rdata[0] & 0x0f);
> +	}
> +
> +	if ((period == 0) || (packet_error > period))
> +		return -EBUSY;
> +
> +	{
> +		u32 div = 0;
> +		u32 Q = 0;
> +		u32 R = 0;
> +
> +		div = period;
> +
> +		Q = (packet_error * 1000) / div;
> +		R = (packet_error * 1000) % div;
> +
> +		R *= 1000;
> +		Q = Q * 1000 + R / div;
> +		R = R % div;
> +
> +		if ((div != 1) && (div / 2 <= R))
> +			*per = Q + 1;
> +		else
> +			*per = Q;
> +	}
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
> +				 enum cxd2880_dvbt2_plp_btype type,
> +				 enum cxd2880_dvbt2_plp_constell *qam)
> +{
> +	u8 data;
> +	u8 l1_post_ok = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!qam))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x86, &l1_post_ok, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	if (!(l1_post_ok & 0x01)) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return -EBUSY;
> +	}
> +
> +	if (type == CXD2880_DVBT2_PLP_COMMON) {
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xb6, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (data == 0) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xb1, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +	} else {
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x9e, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	*qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
> +				       *tnr_dmd,
> +				       enum cxd2880_dvbt2_plp_btype
> +				       type,
> +				       enum
> +				       cxd2880_dvbt2_plp_code_rate
> +				       *code_rate)
> +{
> +	u8 data;
> +	u8 l1_post_ok = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!code_rate))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = slvt_freeze_reg(tnr_dmd);
> +	if (ret)
> +		return ret;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x86, &l1_post_ok, 1);
> +	if (ret) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return ret;
> +	}
> +
> +	if (!(l1_post_ok & 0x01)) {
> +		slvt_unfreeze_reg(tnr_dmd);
> +		return -EBUSY;
> +	}
> +
> +	if (type == CXD2880_DVBT2_PLP_COMMON) {
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xb6, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +
> +		if (data == 0) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return -EBUSY;
> +		}
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0xb0, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +	} else {
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x9d, &data, 1);
> +		if (ret) {
> +			slvt_unfreeze_reg(tnr_dmd);
> +			return ret;
> +		}
> +	}
> +
> +	slvt_unfreeze_reg(tnr_dmd);
> +
> +	*code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07);
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dvbt2_profile
> +				     *profile)
> +{
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!profile))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> +				     CXD2880_IO_TGT_DMD,
> +				     0x00, 0x0b);
> +	if (ret)
> +		return ret;
> +
> +	{
> +		u8 data;
> +
> +		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
> +					     CXD2880_IO_TGT_DMD,
> +					     0x22, &data, sizeof(data));
> +		if (ret)
> +			return ret;
> +
> +		if (data & 0x02) {
> +			if (data & 0x01)
> +				*profile = CXD2880_DVBT2_PROFILE_LITE;
> +			else
> +				*profile = CXD2880_DVBT2_PROFILE_BASE;
> +		} else {
> +			ret = -EBUSY;
> +			if (tnr_dmd->diver_mode ==
> +			    CXD2880_TNRDMD_DIVERMODE_MAIN)
> +				ret =
> +				    cxd2880_tnrdmd_dvbt2_mon_profile(
> +					tnr_dmd->diver_sub, profile);
> +
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int dvbt2_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
> +			  int rf_lvl, u8 *ssi)
> +{
> +	enum cxd2880_dvbt2_plp_constell qam;
> +	enum cxd2880_dvbt2_plp_code_rate code_rate;
> +	int prel;
> +	int temp_ssi = 0;
> +	int ret = 0;
> +
> +	static const int ref_dbm_1000[4][8] = {
> +		{-96000, -95000, -94000, -93000, -92000, -92000, -98000,
> +		 -97000},
> +		{-91000, -89000, -88000, -87000, -86000, -86000, -93000,
> +		 -92000},
> +		{-86000, -85000, -83000, -82000, -81000, -80000, -89000,
> +		 -88000},
> +		{-82000, -80000, -78000, -76000, -75000, -74000, -86000,
> +		 -84000},
> +	};
> +
> +	if ((!tnr_dmd) || (!ssi))
> +		return -EINVAL;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
> +	if (ret)
> +		return ret;
> +
> +	ret =
> +	    cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
> +					       &code_rate);
> +	if (ret)
> +		return ret;
> +
> +	if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256))
> +		return -EPERM;
> +
> +	prel = rf_lvl - ref_dbm_1000[qam][code_rate];
> +
> +	if (prel < -15000)
> +		temp_ssi = 0;
> +	else if (prel < 0)
> +		temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
> +	else if (prel < 20000)
> +		temp_ssi = (((4 * prel) + 500) / 1000) + 10;
> +	else if (prel < 35000)
> +		temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
> +	else
> +		temp_ssi = 100;
> +
> +	*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u8 *ssi)
> +{
> +	int rf_lvl = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ssi))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
> +	if (ret)
> +		return ret;
> +
> +	ret = dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u8 *ssi)
> +{
> +	int rf_lvl = 0;
> +	int ret = 0;
> +
> +	if ((!tnr_dmd) || (!ssi))
> +		return -EINVAL;
> +
> +	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
> +		return -EINVAL;
> +
> +	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
> +		return -EPERM;
> +
> +	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
> +		return -EPERM;
> +
> +	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
> +	if (ret)
> +		return ret;
> +
> +	ret = dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
> new file mode 100644
> index 000000000000..f7b2f618e80f
> --- /dev/null
> +++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.h
> @@ -0,0 +1,170 @@
> +/*
> + * cxd2880_tnrdmd_dvbt2_mon.h
> + * Sony CXD2880 DVB-T2/T tuner + demodulator driver
> + * DVB-T2 monitor interface
> + *
> + * Copyright (C) 2016, 2017 Sony Semiconductor Solutions Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
> + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
> + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CXD2880_TNRDMD_DVBT2_MON_H
> +#define CXD2880_TNRDMD_DVBT2_MON_H
> +
> +#include "cxd2880_tnrdmd.h"
> +#include "cxd2880_dvbt2.h"
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 *sync_stat,
> +				       u8 *ts_lock_stat,
> +				       u8 *unlock_detected);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
> +					   *tnr_dmd,
> +					   u8 *sync_stat,
> +					   u8 *unlock_detected);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
> +					    *tnr_dmd, int *offset);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
> +						cxd2880_tnrdmd
> +						*tnr_dmd,
> +						int *offset);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
> +				    struct cxd2880_dvbt2_l1pre
> +				    *l1_pre);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dvbt2_version
> +				     *ver);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
> +				  struct cxd2880_dvbt2_ofdm *ofdm);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 *plp_ids,
> +				       u8 *num_plps);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
> +					*tnr_dmd,
> +					enum
> +					cxd2880_dvbt2_plp_btype
> +					type,
> +					struct cxd2880_dvbt2_plp
> +					*plp_info);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
> +					    *tnr_dmd,
> +					    u8 *plp_error);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
> +				       *tnr_dmd, u8 *l1_change);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     struct cxd2880_dvbt2_l1post
> +				     *l1_post);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
> +				      *tnr_dmd,
> +				      enum cxd2880_dvbt2_plp_btype
> +				      type,
> +				      struct cxd2880_dvbt2_bbheader
> +				      *bbheader);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
> +					      *tnr_dmd,
> +					      enum
> +					      cxd2880_dvbt2_plp_btype
> +					      type,
> +					      u32 *ts_rate_bps);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
> +					    *tnr_dmd,
> +					    enum
> +					    cxd2880_tnrdmd_spectrum_sense
> +					    *sense);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
> +				 int *snr);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
> +				       *tnr_dmd, int *snr,
> +				       int *snr_main,
> +				       int *snr_sub);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd
> +					 *tnr_dmd, u32 *ber);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd
> +					 *tnr_dmd, u32 *fer);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd
> +					*tnr_dmd, u32 *ber);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
> +						 cxd2880_tnrdmd
> +						 *tnr_dmd,
> +						 u32 *pen);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
> +					     *tnr_dmd, int *ppm);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
> +						 cxd2880_tnrdmd
> +						 *tnr_dmd,
> +						 int *ppm);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u32 *ts_rate_kbps);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u8 *quality);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u32 *per);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
> +				 enum cxd2880_dvbt2_plp_btype type,
> +				 enum cxd2880_dvbt2_plp_constell
> +				 *qam);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
> +				       *tnr_dmd,
> +				       enum cxd2880_dvbt2_plp_btype
> +				       type,
> +				       enum
> +				       cxd2880_dvbt2_plp_code_rate
> +				       *code_rate);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
> +				     *tnr_dmd,
> +				     enum cxd2880_dvbt2_profile
> +				     *profile);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
> +				 u8 *ssi);
> +
> +int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
> +				     *tnr_dmd, u8 *ssi);
> +
> +#endif



Thanks,
Mauro
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 14/14] [media] cxd2880 : Update MAINTAINERS file for CXD2880 driver
  2017-08-16  8:02     ` Takiguchi, Yasunari
@ 2017-08-27 15:48       ` Mauro Carvalho Chehab
  -1 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 15:48 UTC (permalink / raw)
  To: Takiguchi, Yasunari
  Cc: linux-kernel, devicetree, linux-media, akpm, tbird20d,
	frowand.list, Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

Em Wed, 16 Aug 2017 17:02:05 +0900
"Takiguchi, Yasunari" <Yasunari.Takiguchi@sony.com> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> 
> I add an e-mail address and re-send this mail again.
> 
> This is MAINTAINERS file update about the driver for
> the Sony CXD2880 DVB-T2/T tuner + demodulator.

Patches 12-14 look OK to me (although I didn't try to compile).

You can likely fold them into a single patch adding an entry to 
MAINTAINERS and the driver to Kconfig/Makefile.

Regards,
Mauro

> 
> [Change list]
> Changes in V3
>    MAINTAINERS
>       -no change
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
> ---
>  MAINTAINERS | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 6f7721d1634c..12a80c33c194 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -8302,6 +8302,15 @@ T:	git git://linuxtv.org/media_tree.git
>  S:	Supported
>  F:	drivers/media/dvb-frontends/cxd2841er*
>  
> +MEDIA DRIVERS FOR CXD2880
> +M:	Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> +L:	linux-media@vger.kernel.org
> +W:	http://linuxtv.org/
> +T:	git git://linuxtv.org/media_tree.git
> +S:	Supported
> +F:	drivers/media/dvb-frontends/cxd2880/*
> +F:	drivers/media/spi/cxd2880*
> +
>  MEDIA DRIVERS FOR FREESCALE IMX
>  M:	Steve Longerbeam <slongerbeam@gmail.com>
>  M:	Philipp Zabel <p.zabel@pengutronix.de>



Thanks,
Mauro

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 14/14] [media] cxd2880 : Update MAINTAINERS file for CXD2880 driver
@ 2017-08-27 15:48       ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-08-27 15:48 UTC (permalink / raw)
  To: Takiguchi, Yasunari
  Cc: linux-kernel, devicetree, linux-media, akpm, tbird20d,
	frowand.list, Masayuki Yamamoto, Hideki Nozawa, Kota Yonezawa,
	Toshihiko Matsumoto, Satoshi Watanabe

Em Wed, 16 Aug 2017 17:02:05 +0900
"Takiguchi, Yasunari" <Yasunari.Takiguchi@sony.com> escreveu:

> From: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> 
> I add an e-mail address and re-send this mail again.
> 
> This is MAINTAINERS file update about the driver for
> the Sony CXD2880 DVB-T2/T tuner + demodulator.

Patches 12-14 look OK to me (although I didn't try to compile).

You can likely fold them into a single patch adding an entry to 
MAINTAINERS and the driver to Kconfig/Makefile.

Regards,
Mauro

> 
> [Change list]
> Changes in V3
>    MAINTAINERS
>       -no change
> 
> Signed-off-by: Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> Signed-off-by: Masayuki Yamamoto <Masayuki.Yamamoto@sony.com>
> Signed-off-by: Hideki Nozawa <Hideki.Nozawa@sony.com>
> Signed-off-by: Kota Yonezawa <Kota.Yonezawa@sony.com>
> Signed-off-by: Toshihiko Matsumoto <Toshihiko.Matsumoto@sony.com>
> Signed-off-by: Satoshi Watanabe <Satoshi.C.Watanabe@sony.com>
> ---
>  MAINTAINERS | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 6f7721d1634c..12a80c33c194 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -8302,6 +8302,15 @@ T:	git git://linuxtv.org/media_tree.git
>  S:	Supported
>  F:	drivers/media/dvb-frontends/cxd2841er*
>  
> +MEDIA DRIVERS FOR CXD2880
> +M:	Yasunari Takiguchi <Yasunari.Takiguchi@sony.com>
> +L:	linux-media@vger.kernel.org
> +W:	http://linuxtv.org/
> +T:	git git://linuxtv.org/media_tree.git
> +S:	Supported
> +F:	drivers/media/dvb-frontends/cxd2880/*
> +F:	drivers/media/spi/cxd2880*
> +
>  MEDIA DRIVERS FOR FREESCALE IMX
>  M:	Steve Longerbeam <slongerbeam@gmail.com>
>  M:	Philipp Zabel <p.zabel@pengutronix.de>



Thanks,
Mauro

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 05/14] [media] cxd2880: Add tuner part of the driver
  2017-08-27 14:45     ` Mauro Carvalho Chehab
@ 2017-09-07 10:12       ` Takiguchi, Yasunari
  -1 siblings, 0 replies; 51+ messages in thread
From: Takiguchi, Yasunari @ 2017-09-07 10:12 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linux-kernel, devicetree, linux-media, tbird20d, frowand.list,
	Yamamoto, Masayuki, Nozawa, Hideki (STWN),
	Yonezawa, Kota, Matsumoto, Toshihiko, Watanabe, Satoshi (SSS),
	yasunari.takiguchi

Dear Mauro

Thanks for your review and reply.

We are going to discuss how to change our code with your comments internally.

I reply for your  2 comments,

>> [Change list]
>> Changes in V3
>>    drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
>>       -removed code relevant to ISDB-T
> 
> Just curiosity here: why is it removed?
We decided to withhold the ISDB-T functionality as it contains some company proprietary code.


>> +	if (ret)
>> +		return ret;
>> +	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl) {
>> +		data[0] = 0x01;
>> +		data[1] = 0x01;
>> +		data[2] = 0x01;
>> +		data[3] = 0x01;
>> +		data[4] = 0x01;
>> +		data[5] = 0x01;
>> +	} else {
>> +		data[0] = 0x00;
>> +		data[1] = 0x00;
>> +		data[2] = 0x00;
>> +		data[3] = 0x00;
>> +		data[4] = 0x00;
>> +		data[5] = 0x00;
>> +	}
> 
> Instead, just do:
> 
> 	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
> 		memset(data, 0x01, sizeof(data));
> 	else
> 		memset(data, 0x00, sizeof(data));
> 
>> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
>> +				      CXD2880_IO_TGT_SYS,
>> +				      0xef, data, 6);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
>> +				     CXD2880_IO_TGT_DMD,
>> +				     0x00, 0x2d);
>> +	if (ret)
>> +		return ret;
> 
>> +	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
>> +		data[0] = 0x00;
>> +	else
>> +		data[0] = 0x01;
> 
> Not actually needed, as the previous logic already set data[0]
> accordingly.
> 
>> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
>> +				     CXD2880_IO_TGT_DMD,
>> +				     0xb1, data[0]);

In this case、logic of data[0]( logic of if() ) is different from that of previous one.
And with setting register for address 0xb1, a bug might occur in the future, 
if our software specification (sequence) is changed.
So we would like to keep setting value of data[0] for address 0xb1.

Thanks,
Takiguchi

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 05/14] [media] cxd2880: Add tuner part of the driver
@ 2017-09-07 10:12       ` Takiguchi, Yasunari
  0 siblings, 0 replies; 51+ messages in thread
From: Takiguchi, Yasunari @ 2017-09-07 10:12 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: linux-kernel, devicetree, linux-media, tbird20d, frowand.list,
	Yamamoto, Masayuki, Nozawa, Hideki (STWN),
	Yonezawa, Kota, Matsumoto, Toshihiko, Watanabe, Satoshi (SSS),
	yasunari.takiguchi

Dear Mauro

Thanks for your review and reply.

We are going to discuss how to change our code with your comments internally.

I reply for your  2 comments,

>> [Change list]
>> Changes in V3
>>    drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
>>       -removed code relevant to ISDB-T
> 
> Just curiosity here: why is it removed?
We decided to withhold the ISDB-T functionality as it contains some company proprietary code.


>> +	if (ret)
>> +		return ret;
>> +	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl) {
>> +		data[0] = 0x01;
>> +		data[1] = 0x01;
>> +		data[2] = 0x01;
>> +		data[3] = 0x01;
>> +		data[4] = 0x01;
>> +		data[5] = 0x01;
>> +	} else {
>> +		data[0] = 0x00;
>> +		data[1] = 0x00;
>> +		data[2] = 0x00;
>> +		data[3] = 0x00;
>> +		data[4] = 0x00;
>> +		data[5] = 0x00;
>> +	}
> 
> Instead, just do:
> 
> 	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
> 		memset(data, 0x01, sizeof(data));
> 	else
> 		memset(data, 0x00, sizeof(data));
> 
>> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
>> +				      CXD2880_IO_TGT_SYS,
>> +				      0xef, data, 6);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
>> +				     CXD2880_IO_TGT_DMD,
>> +				     0x00, 0x2d);
>> +	if (ret)
>> +		return ret;
> 
>> +	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
>> +		data[0] = 0x00;
>> +	else
>> +		data[0] = 0x01;
> 
> Not actually needed, as the previous logic already set data[0]
> accordingly.
> 
>> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
>> +				     CXD2880_IO_TGT_DMD,
>> +				     0xb1, data[0]);

In this case、logic of data[0]( logic of if() ) is different from that of previous one.
And with setting register for address 0xb1, a bug might occur in the future, 
if our software specification (sequence) is changed.
So we would like to keep setting value of data[0] for address 0xb1.

Thanks,
Takiguchi

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 05/14] [media] cxd2880: Add tuner part of the driver
  2017-09-07 10:12       ` Takiguchi, Yasunari
  (?)
@ 2017-09-07 10:26       ` Mauro Carvalho Chehab
  -1 siblings, 0 replies; 51+ messages in thread
From: Mauro Carvalho Chehab @ 2017-09-07 10:26 UTC (permalink / raw)
  To: Takiguchi, Yasunari
  Cc: linux-kernel, devicetree, linux-media, tbird20d, frowand.list,
	Yamamoto, Masayuki, Nozawa, Hideki (STWN),
	Yonezawa, Kota, Matsumoto, Toshihiko, Watanabe, Satoshi (SSS)

Em Thu, 7 Sep 2017 19:12:57 +0900
"Takiguchi, Yasunari" <Yasunari.Takiguchi@sony.com> escreveu:

> Dear Mauro
> 
> Thanks for your review and reply.
> 
> We are going to discuss how to change our code with your comments internally.
> 
> I reply for your  2 comments,
> 
> >> [Change list]
> >> Changes in V3
> >>    drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h
> >>       -removed code relevant to ISDB-T
> > 
> > Just curiosity here: why is it removed?
> We decided to withhold the ISDB-T functionality as it contains some company proprietary code.

I'm sorry to hear. I hope that such code could be released
on some future.

> >> +	if (ret)
> >> +		return ret;
> >> +	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl) {
> >> +		data[0] = 0x01;
> >> +		data[1] = 0x01;
> >> +		data[2] = 0x01;
> >> +		data[3] = 0x01;
> >> +		data[4] = 0x01;
> >> +		data[5] = 0x01;
> >> +	} else {
> >> +		data[0] = 0x00;
> >> +		data[1] = 0x00;
> >> +		data[2] = 0x00;
> >> +		data[3] = 0x00;
> >> +		data[4] = 0x00;
> >> +		data[5] = 0x00;
> >> +	}
> > 
> > Instead, just do:
> > 
> > 	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
> > 		memset(data, 0x01, sizeof(data));
> > 	else
> > 		memset(data, 0x00, sizeof(data));
> > 
> >> +	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
> >> +				      CXD2880_IO_TGT_SYS,
> >> +				      0xef, data, 6);
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> >> +				     CXD2880_IO_TGT_DMD,
> >> +				     0x00, 0x2d);
> >> +	if (ret)
> >> +		return ret;
> > 
> >> +	if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl)
> >> +		data[0] = 0x00;
> >> +	else
> >> +		data[0] = 0x01;
> > 
> > Not actually needed, as the previous logic already set data[0]
> > accordingly.
> > 
> >> +	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
> >> +				     CXD2880_IO_TGT_DMD,
> >> +				     0xb1, data[0]);
> 
> In this case、logic of data[0]( logic of if() ) is different from that of previous one.
> And with setting register for address 0xb1, a bug might occur in the future, 
> if our software specification (sequence) is changed.
> So we would like to keep setting value of data[0] for address 0xb1.

OK. Better to document it then, as otherwise someone might
end by sending cleanup patches that would touch it.

> 
> Thanks,
> Takiguchi



Thanks,
Mauro

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2017-09-07 10:26 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-16  4:17 [PATCH v3 00/14] [dt-bindings] [media] Add document file and driver for Sony CXD2880 DVB-T2/T tuner + demodulator Yasunari.Takiguchi
2017-08-16  4:17 ` Yasunari.Takiguchi-7U/KSKJipcs
2017-08-16  4:24 ` [PATCH v3 01/14] [dt-bindings] [media] Add document file for CXD2880 SPI I/F Yasunari.Takiguchi
2017-08-16  4:24   ` Yasunari.Takiguchi
2017-08-16  4:25 ` [PATCH v3 02/14] [media] cxd2880-spi: Add support for CXD2880 SPI interface Yasunari.Takiguchi
2017-08-16  4:25   ` Yasunari.Takiguchi-7U/KSKJipcs
2017-08-16  4:33 ` [PATCH v3 03/14] [media] cxd2880: Add common files for the driver Yasunari.Takiguchi
2017-08-16  4:33   ` Yasunari.Takiguchi
2017-08-16  4:35 ` [PATCH v3 04/14] [media] cxd2880: Add spi device IO routines Yasunari.Takiguchi
2017-08-16  4:35   ` Yasunari.Takiguchi-7U/KSKJipcs
2017-08-16  4:37 ` [PATCH v3 05/14] [media] cxd2880: Add tuner part of the driver Yasunari.Takiguchi
2017-08-16  4:37   ` Yasunari.Takiguchi
2017-08-27 14:45   ` Mauro Carvalho Chehab
2017-08-27 14:45     ` Mauro Carvalho Chehab
2017-08-27 14:52     ` Mauro Carvalho Chehab
2017-08-27 14:52       ` Mauro Carvalho Chehab
2017-09-07 10:12     ` Takiguchi, Yasunari
2017-09-07 10:12       ` Takiguchi, Yasunari
2017-09-07 10:26       ` Mauro Carvalho Chehab
2017-08-16  4:38 ` [PATCH v3 06/14] [media] cxd2880: Add integration layer for " Yasunari.Takiguchi
2017-08-16  4:38   ` Yasunari.Takiguchi
2017-08-16  4:39 ` [PATCH v3 07/14] [media] cxd2880: Add top level of " Yasunari.Takiguchi
2017-08-16  4:39   ` Yasunari.Takiguchi
2017-08-27 15:12   ` Mauro Carvalho Chehab
2017-08-27 15:12     ` Mauro Carvalho Chehab
2017-08-16  4:40 ` [PATCH v3 08/14] [media] cxd2880: Add DVB-T control functions " Yasunari.Takiguchi
2017-08-16  4:40   ` Yasunari.Takiguchi-7U/KSKJipcs
2017-08-27 15:17   ` Mauro Carvalho Chehab
2017-08-27 15:17     ` Mauro Carvalho Chehab
2017-08-16  4:41 ` [PATCH v3 09/14] [media] cxd2880: Add DVB-T monitor and integration layer functions Yasunari.Takiguchi
2017-08-16  4:41   ` Yasunari.Takiguchi-7U/KSKJipcs
2017-08-27 15:34   ` Mauro Carvalho Chehab
2017-08-27 15:34     ` Mauro Carvalho Chehab
2017-08-16  4:42 ` [PATCH v3 10/14] [media] cxd2880: Add DVB-T2 control functions for the driver Yasunari.Takiguchi
2017-08-16  4:42   ` Yasunari.Takiguchi-7U/KSKJipcs
2017-08-27 15:38   ` Mauro Carvalho Chehab
2017-08-27 15:38     ` Mauro Carvalho Chehab
2017-08-16  4:43 ` [PATCH v3 11/14] [media] cxd2880: Add DVB-T2 monitor and integration layer functions Yasunari.Takiguchi
2017-08-16  4:43   ` Yasunari.Takiguchi-7U/KSKJipcs
2017-08-27 15:44   ` Mauro Carvalho Chehab
2017-08-27 15:44     ` Mauro Carvalho Chehab
2017-08-16  4:44 ` [PATCH v3 12/14] [media] cxd2880: Add all Makefile files for the driver Yasunari.Takiguchi
2017-08-16  4:44   ` Yasunari.Takiguchi-7U/KSKJipcs
2017-08-16  4:45 ` [PATCH v3 13/14] [media] cxd2880: Add all Kconfig " Yasunari.Takiguchi
2017-08-16  4:45   ` Yasunari.Takiguchi-7U/KSKJipcs
2017-08-16  4:47 ` [PATCH v3 14/14] [media] cxd2880 : Update MAINTAINERS file for CXD2880 driver Yasunari.Takiguchi
2017-08-16  4:47   ` Yasunari.Takiguchi
2017-08-16  8:02   ` Takiguchi, Yasunari
2017-08-16  8:02     ` Takiguchi, Yasunari
2017-08-27 15:48     ` Mauro Carvalho Chehab
2017-08-27 15:48       ` Mauro Carvalho Chehab

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.