diff --git a/packages/graphics/bcm2835-driver/package.mk b/packages/graphics/bcm2835-driver/package.mk index b10a8a6076..6cce455489 100644 --- a/packages/graphics/bcm2835-driver/package.mk +++ b/packages/graphics/bcm2835-driver/package.mk @@ -17,7 +17,7 @@ ################################################################################ PKG_NAME="bcm2835-driver" -PKG_VERSION="b038854" +PKG_VERSION="570b095" PKG_ARCH="any" PKG_LICENSE="nonfree" PKG_SITE="http://www.broadcom.com" diff --git a/packages/linux/package.mk b/packages/linux/package.mk index 07fb2cde7e..0bc99e0d1d 100644 --- a/packages/linux/package.mk +++ b/packages/linux/package.mk @@ -59,7 +59,7 @@ case "$LINUX" in PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET imx6-status-led imx6-soc-fan irqbalanced" ;; *) - PKG_VERSION="4.9.20" + PKG_VERSION="4.9.24" PKG_URL="http://www.kernel.org/pub/linux/kernel/v4.x/$PKG_NAME-$PKG_VERSION.tar.xz" PKG_PATCH_DIRS="default" ;; diff --git a/packages/linux/patches/default/linux-999-i915-use-legacy-turbo.patch b/packages/linux/patches/default/linux-999-i915-use-legacy-turbo.patch deleted file mode 100644 index a8df9d68d2..0000000000 --- a/packages/linux/patches/default/linux-999-i915-use-legacy-turbo.patch +++ /dev/null @@ -1,27 +0,0 @@ -From aefcd1a6b1ec22e4e0d26eb932b618c5d12f7e9c Mon Sep 17 00:00:00 2001 -From: fritsch -Date: Sun, 21 Feb 2016 12:39:16 +0100 -Subject: [PATCH] i915_irq: enable legacy turbo (4.6) - ---- - drivers/gpu/drm/i915/i915_irq.c | 7 +------ - 1 file changed, 1 insertion(+), 6 deletions(-) - -diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c -index 1c21220..6507643 100644 ---- a/drivers/gpu/drm/i915/i915_irq.c -+++ b/drivers/gpu/drm/i915/i915_irq.c -@@ -4557,12 +4557,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) - INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); - INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); - -- /* Let's track the enabled rps events */ -- if (IS_VALLEYVIEW(dev_priv)) -- /* WaGsvRC0ResidencyMethod:vlv */ -- dev_priv->pm_rps_events = GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED; -- else -- dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS; -+ dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS; - - INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work, - i915_hangcheck_elapsed); diff --git a/packages/tools/bcm2835-bootloader/package.mk b/packages/tools/bcm2835-bootloader/package.mk index aff3c915b9..ec642320e6 100644 --- a/packages/tools/bcm2835-bootloader/package.mk +++ b/packages/tools/bcm2835-bootloader/package.mk @@ -17,7 +17,7 @@ ################################################################################ PKG_NAME="bcm2835-bootloader" -PKG_VERSION="b038854" +PKG_VERSION="570b095" PKG_ARCH="arm" PKG_LICENSE="nonfree" PKG_SITE="http://www.broadcom.com" diff --git a/projects/Generic/linux/linux.x86_64.conf b/projects/Generic/linux/linux.x86_64.conf index 6e87ad0f39..a7b07682f1 100644 --- a/projects/Generic/linux/linux.x86_64.conf +++ b/projects/Generic/linux/linux.x86_64.conf @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86_64 4.9.0 Kernel Configuration +# Linux/x86_64 4.9.24 Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y @@ -3560,6 +3560,7 @@ CONFIG_SND_SOC_INTEL_SST_MATCH=m # CONFIG_SND_SOC_INTEL_HASWELL_MACH is not set # CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH is not set # CONFIG_SND_SOC_INTEL_BXT_RT298_MACH is not set +# CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH is not set # CONFIG_SND_SOC_INTEL_BROADWELL_MACH is not set CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH=m # CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH is not set diff --git a/projects/RPi/linux/linux.arm.conf b/projects/RPi/linux/linux.arm.conf index 9a9e11f7e7..e6270c375d 100644 --- a/projects/RPi/linux/linux.arm.conf +++ b/projects/RPi/linux/linux.arm.conf @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 4.9.20 Kernel Configuration +# Linux/arm 4.9.24 Kernel Configuration # CONFIG_ARM=y CONFIG_ARM_HAS_SG_CHAIN=y @@ -2473,6 +2473,11 @@ CONFIG_VIDEO_CX25840=m # # Sensors used on soc_camera driver # + +# +# Media SPI Adapters +# +CONFIG_CXD2880_SPI_DRV=m CONFIG_MEDIA_TUNER=m CONFIG_MEDIA_TUNER_SIMPLE=m CONFIG_MEDIA_TUNER_TDA8290=m diff --git a/projects/RPi/patches/linux/linux-01-RPi_support.patch b/projects/RPi/patches/linux/linux-01-RPi_support.patch index 4a8a74abea..3e05740020 100644 --- a/projects/RPi/patches/linux/linux-01-RPi_support.patch +++ b/projects/RPi/patches/linux/linux-01-RPi_support.patch @@ -1,7 +1,7 @@ -From ace6fd3ca18068ece94afeee6eddb8d190ea8c79 Mon Sep 17 00:00:00 2001 +From cb8066936db1d23446c81d21d6b4bb55056acc30 Mon Sep 17 00:00:00 2001 From: Steve Glendinning Date: Thu, 19 Feb 2015 18:47:12 +0000 -Subject: [PATCH 001/220] smsx95xx: fix crimes against truesize +Subject: [PATCH 001/229] smsx95xx: fix crimes against truesize smsc95xx is adjusting truesize when it shouldn't, and following a recent patch from Eric this is now triggering warnings. @@ -48,10 +48,10 @@ index 831aa33d078ae7d2dd57fdded5de71d1eb915f99..b77935bded8c0ff7808b00f170ff10e5 usbnet_skb_return(dev, ax_skb); } -From 77227dfd51d9f6cb24da1ee9fce7c29d8fdd26d8 Mon Sep 17 00:00:00 2001 +From 32919b70d04f9735170481b00f6ba04a12a40895 Mon Sep 17 00:00:00 2001 From: Sam Nazarko Date: Fri, 1 Apr 2016 17:27:21 +0100 -Subject: [PATCH 002/220] smsc95xx: Experimental: Enable turbo_mode and +Subject: [PATCH 002/229] smsc95xx: Experimental: Enable turbo_mode and packetsize=2560 by default See: http://forum.kodi.tv/showthread.php?tid=285288 @@ -94,10 +94,10 @@ index b77935bded8c0ff7808b00f170ff10e594300ad0..693f163684de921404738e33244881e0 netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n", -From bfcc45ab8ec29eddf9068f709e19a71c0750ca35 Mon Sep 17 00:00:00 2001 +From e4dd221bccc5aa86f27569bf87c623972e11df63 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 003/220] Allow mac address to be set in smsc95xx +Subject: [PATCH 003/229] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -193,10 +193,10 @@ index 693f163684de921404738e33244881e0aab92ec9..df60c989fc229bf0aab3c27e95ccd453 eth_hw_addr_random(dev->net); netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); -From 5c7af355f2985972bffc0c547818bc67bd9f2d47 Mon Sep 17 00:00:00 2001 +From b94bb3ddcf5368a84e9dc00864dd63dd8cae8b58 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 13 Mar 2015 12:43:36 +0000 -Subject: [PATCH 004/220] Protect __release_resource against resources without +Subject: [PATCH 004/229] Protect __release_resource against resources without parents Without this patch, removing a device tree overlay can crash here. @@ -224,10 +224,10 @@ index 9b5f04404152c296af3a96132f27cfc80ffa9af9..f8a9af6e6b915812be2ba2c1c2b40106 for (;;) { tmp = *p; -From 8b39431fedbaa4e15cc8187416649b679aa88517 Mon Sep 17 00:00:00 2001 +From 9269e1fb3edbbe45407f327ec8192095795e2894 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 18 Dec 2014 16:07:15 -0800 -Subject: [PATCH 005/220] mm: Remove the PFN busy warning +Subject: [PATCH 005/229] mm: Remove the PFN busy warning See commit dae803e165a11bc88ca8dbc07a11077caf97bbcb -- the warning is expected sometimes when using CMA. However, that commit still spams @@ -239,7 +239,7 @@ Signed-off-by: Eric Anholt 1 file changed, 2 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 1460e6ad5e141788edea4b4ea3a294352d788af1..69dc54cf662fbac6b67af7bdfb7b7a41deb78d06 100644 +index e5b159b88e3968857c2b02d4c6bb0589a83930b3..84271c72e2b98ab0135908776cb220c790a9cd4c 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -7323,8 +7323,6 @@ int alloc_contig_range(unsigned long start, unsigned long end, @@ -252,10 +252,10 @@ index 1460e6ad5e141788edea4b4ea3a294352d788af1..69dc54cf662fbac6b67af7bdfb7b7a41 goto done; } -From 73f0130d019611fe110d734bd94cb5384140f035 Mon Sep 17 00:00:00 2001 +From a3d0748addb1db79bf2938b2f73f2787c8142c0d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 4 Dec 2015 17:41:50 +0000 -Subject: [PATCH 006/220] irq-bcm2836: Prevent spurious interrupts, and trap +Subject: [PATCH 006/229] irq-bcm2836: Prevent spurious interrupts, and trap them early The old arch-specific IRQ macros included a dsb to ensure the @@ -282,10 +282,10 @@ index d96b2c947e74e3edab3917551c64fbd1ced0f34c..93e3f7660c4230c9f1dd3b195958cb49 #endif } else if (stat) { -From 2ccd0c4c9b5fb75670cb506403c52b1b1fe38d9d Mon Sep 17 00:00:00 2001 +From ef009f2619a7cef201c14af374391cbe2bb804b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 12 Jun 2015 19:01:05 +0200 -Subject: [PATCH 007/220] irqchip: bcm2835: Add FIQ support +Subject: [PATCH 007/229] irqchip: bcm2835: Add FIQ support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -414,10 +414,10 @@ index 44d7c38dde479d771f3552e914bf8c1c1f5019f7..42ff5e6a8e0d532f5b60a1e7af7cc4d9 } -From 0e091203819ee3c24cb7d9ef27fda64160b0cee5 Mon Sep 17 00:00:00 2001 +From 62aaeef510e9438692129b3dddcbf42f0329736d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Oct 2015 16:26:55 +0200 -Subject: [PATCH 008/220] irqchip: irq-bcm2835: Add 2836 FIQ support +Subject: [PATCH 008/229] irqchip: irq-bcm2835: Add 2836 FIQ support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -516,10 +516,10 @@ index 42ff5e6a8e0d532f5b60a1e7af7cc4d941bd5008..eccf6ed025299cb480884f5bcbe77abf for (b = 0; b < NR_BANKS; b++) { for (i = 0; i < bank_irqs[b]; i++) { -From 1f36307a91673999b54a458708660828bbb57e87 Mon Sep 17 00:00:00 2001 +From 2cbc1ae91a761b3d13e536207025681a6f9b07aa Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 10:26:09 +0100 -Subject: [PATCH 009/220] spidev: Add "spidev" compatible string to silence +Subject: [PATCH 009/229] spidev: Add "spidev" compatible string to silence warning See: https://github.com/raspberrypi/linux/issues/1054 @@ -540,10 +540,10 @@ index 2e05046f866bd01bf87edcdeff0d5b76d4d0aea7..d780491b8013a4e97fa843958964454e }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); -From 098c16955ecffe714b0b9c8a1e71155a39be354c Mon Sep 17 00:00:00 2001 +From cbf8e59e110417902cc0a33d80846e92668d0959 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 14:12:42 +0100 -Subject: [PATCH 010/220] serial: 8250: Don't crash when nr_uarts is 0 +Subject: [PATCH 010/229] serial: 8250: Don't crash when nr_uarts is 0 --- drivers/tty/serial/8250/8250_core.c | 2 ++ @@ -563,10 +563,10 @@ index e8819aa20415603c80547e382838a8fa3ce54792..cf9c7d2e3f95e1a19410247a89c2e49c for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; -From 4f351bb67f89906f34b83cc9fa32223e8e9e9887 Mon Sep 17 00:00:00 2001 +From cd51d76d165de45326a6dd1c2de3bfe7bf1cae3f Mon Sep 17 00:00:00 2001 From: notro Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 011/220] pinctrl-bcm2835: Set base to 0 give expected gpio +Subject: [PATCH 011/229] pinctrl-bcm2835: Set base to 0 give expected gpio numbering Signed-off-by: Noralf Tronnes @@ -588,10 +588,10 @@ index fa77165fab2c1348163979da507df17e7168c49b..d11e2e4ea189466e686d762cb6c6fef9 .can_sleep = false, }; -From f9b822f58271c75e81a9354f1167dc719f9a233d Mon Sep 17 00:00:00 2001 +From 3c9de5fca5b74c711b41abe6b6395b1f37c65892 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 24 Feb 2015 13:40:50 +0000 -Subject: [PATCH 012/220] pinctrl-bcm2835: Fix interrupt handling for GPIOs +Subject: [PATCH 012/229] pinctrl-bcm2835: Fix interrupt handling for GPIOs 28-31 and 46-53 Contrary to the documentation, the BCM2835 GPIO controller actually has @@ -737,10 +737,10 @@ index d11e2e4ea189466e686d762cb6c6fef9111ecf8e..107ad7d58de8f8a7f55e09c9cdcf7d66 }, }; -From d2dc0ee0513fbcdd90576a0765e061dc29b8067c Mon Sep 17 00:00:00 2001 +From feeffef9b6523e4435355de13920f47d01e0b4d8 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 26 Feb 2015 09:58:22 +0000 -Subject: [PATCH 013/220] pinctrl-bcm2835: Only request the interrupts listed +Subject: [PATCH 013/229] pinctrl-bcm2835: Only request the interrupts listed in the DTB Although the GPIO controller can generate three interrupts (four counting @@ -767,10 +767,10 @@ index 107ad7d58de8f8a7f55e09c9cdcf7d66fa7ab66b..644bdecbcfcb79d3b84a33769265fca5 pc->irq_data[i].irqgroup = i; -From e4d48693d7cf2b97fc189e4344ec3f09c333903d Mon Sep 17 00:00:00 2001 +From ff925faea8508f57604e78ee21a1025e748c47f0 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 May 2016 12:32:47 +0100 -Subject: [PATCH 014/220] pinctrl-bcm2835: Return pins to inputs when freed +Subject: [PATCH 014/229] pinctrl-bcm2835: Return pins to inputs when freed When dynamically unloading overlays, it is important that freed pins are restored to being inputs to prevent functions from being enabled in @@ -811,10 +811,10 @@ index 644bdecbcfcb79d3b84a33769265fca5d3d0c9e5..81a66cba2ab0f7e3ae179de7edd10122 .get_function_name = bcm2835_pmx_get_function_name, .get_function_groups = bcm2835_pmx_get_function_groups, -From ca1600077e78e1a5cde5e329aa2aaa8b4261453a Mon Sep 17 00:00:00 2001 +From 0f7a0e45617c0f98ed82c08971d26b95597b8988 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 24 Jun 2015 14:10:44 +0100 -Subject: [PATCH 015/220] spi-bcm2835: Support pin groups other than 7-11 +Subject: [PATCH 015/229] spi-bcm2835: Support pin groups other than 7-11 The spi-bcm2835 driver automatically uses GPIO chip-selects due to some unreliability of the native ones. In doing so it chooses the @@ -895,10 +895,10 @@ index f35cc10772f6670397ea923ad30158270dd68578..5dfe20ffc2866fa6789825016c585175 /* and set up the "mode" and level */ dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n", -From aa8c3ce9cad4a9c450f305b25bf6e099fc788102 Mon Sep 17 00:00:00 2001 +From ff0aa7f8e9c8f79130dc2f63b87156683b1b54b1 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 1 Jul 2016 22:09:24 +0100 -Subject: [PATCH 016/220] spi-bcm2835: Disable forced software CS +Subject: [PATCH 016/229] spi-bcm2835: Disable forced software CS Select software CS in bcm2708_common.dtsi, and disable the automatic conversion in the driver to allow hardware CS to be re-enabled with an @@ -932,10 +932,10 @@ index 5dfe20ffc2866fa6789825016c585175a29705b6..8493474d286f7a1ac6454a22c61c8c2c return 0; } -From d13a1d0c1b9ae58ff0cd262d8d79ce4c4ef342d2 Mon Sep 17 00:00:00 2001 +From 770219991e8e487d9eda05b0aff7d2977b4ba56b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 8 Nov 2016 21:35:38 +0000 -Subject: [PATCH 017/220] spi-bcm2835: Remove unused code +Subject: [PATCH 017/229] spi-bcm2835: Remove unused code --- drivers/spi/spi-bcm2835.c | 61 ----------------------------------------------- @@ -1023,10 +1023,10 @@ index 8493474d286f7a1ac6454a22c61c8c2cef9121bf..33d75ad38a7f77d085321ace9101900a } -From c893ea9baa610d6c6348d7628279c77679055d97 Mon Sep 17 00:00:00 2001 +From 6fab21d4b1999469dbf9d4a8428f38fffe98dea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 3 Jun 2015 12:26:13 +0200 -Subject: [PATCH 018/220] ARM: bcm2835: Set Serial number and Revision +Subject: [PATCH 018/229] ARM: bcm2835: Set Serial number and Revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -1079,10 +1079,10 @@ index 0c1edfc98696da0e0bb7f4a18cdfbcdd27a9795d..8f152266ba9b470df2eaaed9ebcf158e static const char * const bcm2835_compat[] = { -From e997f981519f0c1b0d922cf3b893fb799f7f4686 Mon Sep 17 00:00:00 2001 +From fae16613c032abcd4e39076a1ba35b1d5828a783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sat, 3 Oct 2015 22:22:55 +0200 -Subject: [PATCH 019/220] dmaengine: bcm2835: Load driver early and support +Subject: [PATCH 019/229] dmaengine: bcm2835: Load driver early and support legacy API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -1185,10 +1185,10 @@ index e18dc596cf2447fa9ef7e41b62d9396e29043426..80d35f760b4a4a51e60c355a84d538ba MODULE_ALIAS("platform:bcm2835-dma"); MODULE_DESCRIPTION("BCM2835 DMA engine driver"); -From a0a01cf3fd1469a6b94a16d21aa7cfb61d02d7cb Mon Sep 17 00:00:00 2001 +From bec04405036485dd65f6fc47e84348ae853562af Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 25 Jan 2016 17:25:12 +0000 -Subject: [PATCH 020/220] firmware: Updated mailbox header +Subject: [PATCH 020/229] firmware: Updated mailbox header --- include/soc/bcm2835/raspberrypi-firmware.h | 11 +++++++++++ @@ -1251,10 +1251,10 @@ index 3fb357193f09914fe21f8555a4b8613f74f22bc3..227a107214a02deadcca3db202da265e RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, -From c7b70d7bf562b9611f342862653ad7f68fa9e0c6 Mon Sep 17 00:00:00 2001 +From 82f922d58232d082f55ad3b710f82c3210b35683 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 9 May 2016 17:28:18 -0700 -Subject: [PATCH 021/220] clk: bcm2835: Mark GPIO clocks enabled at boot as +Subject: [PATCH 021/229] clk: bcm2835: Mark GPIO clocks enabled at boot as critical. These divide off of PLLD_PER and are used for the ethernet and wifi @@ -1292,10 +1292,10 @@ index 2acaa77ad482a99f28ea64ea43c891501125304c..d13cbbf5bbe06314bfdf103ff85d5cd7 init.ops = &bcm2835_vpu_clock_clk_ops; } else { -From 70bd41a7fa143e6083f8e6fda573ccc8b11d5de0 Mon Sep 17 00:00:00 2001 +From 5cd10e36b0a4b7a94c019db2595ca6a196c7e8ca Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 15 Jun 2016 16:48:41 +0100 -Subject: [PATCH 022/220] rtc: Add SPI alias for pcf2123 driver +Subject: [PATCH 022/229] rtc: Add SPI alias for pcf2123 driver Without this alias, Device Tree won't cause the driver to be loaded. @@ -1315,10 +1315,10 @@ index 8895f77726e8da5444afcd602dceff8f25a9b3fd..1833b8853ceb0e6147cceb93a00e558c MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:rtc-pcf2123"); -From ea7d87c6e8212f5559000d9471f9e87169797430 Mon Sep 17 00:00:00 2001 +From 441b7b516839ee78346d0fd9278e4b2ebdf8ae2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 7 Oct 2016 16:50:59 +0200 -Subject: [PATCH 023/220] watchdog: bcm2835: Support setting reboot partition +Subject: [PATCH 023/229] watchdog: bcm2835: Support setting reboot partition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -1442,10 +1442,10 @@ index 4dddd8298a227d64862f2e92954a465f2e44b3f6..1f545e024422f59280932713e6a1b051 register_restart_handler(&wdt->restart_handler); if (pm_power_off == NULL) -From 639060b6afee11534ce54ab416abeb0ed7fd6965 Mon Sep 17 00:00:00 2001 +From e15fd788eff11cf229e0049e075a6a3a956398a8 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 5 Apr 2016 19:40:12 +0100 -Subject: [PATCH 024/220] reboot: Use power off rather than busy spinning when +Subject: [PATCH 024/229] reboot: Use power off rather than busy spinning when halt is requested --- @@ -1468,10 +1468,10 @@ index 3fa867a2aae672755c6ce6448f4148c989dbf964..80dca8dcd6709034b643c6a3f35729e0 /* -From c020700a444e1e3ed5db75038f9b6c299b890e64 Mon Sep 17 00:00:00 2001 +From 6665032094afa9ac298d8f60d8b900169d545509 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 9 Nov 2016 13:02:52 +0000 -Subject: [PATCH 025/220] bcm: Make RASPBERRYPI_POWER depend on PM +Subject: [PATCH 025/229] bcm: Make RASPBERRYPI_POWER depend on PM --- drivers/soc/bcm/Kconfig | 1 + @@ -1490,10 +1490,10 @@ index a39b0d58ddd0fdf0ac1cc7295f8aafb12546e226..e037a6dd79d1881a09e3ca9115782709 help This enables support for the RPi power domains which can be enabled -From a2bda2acba829767aeead5be052c7b6eee905d97 Mon Sep 17 00:00:00 2001 +From 5151700add5effb47213ab307c1e67a0cdee9c0c Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Fri, 2 Sep 2016 16:45:27 +0100 -Subject: [PATCH 026/220] Register the clocks early during the boot process, so +Subject: [PATCH 026/229] Register the clocks early during the boot process, so that special/critical clocks can get enabled early on in the boot process avoiding the risk of disabling a clock, pll_divider or pll when a claiming driver fails to install propperly - maybe it needs to defer. @@ -1538,10 +1538,10 @@ index d13cbbf5bbe06314bfdf103ff85d5cd73cbf7f7a..a99ccf9f056d3a3e7c482339e08483f3 MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("BCM2835 clock driver"); -From f8fdbafbd1b8a67f07ae454be34e61e9e420998a Mon Sep 17 00:00:00 2001 +From 107b440406fad9cfec531d1c67921047d96bcb14 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 6 Dec 2016 17:05:39 +0000 -Subject: [PATCH 027/220] bcm2835-rng: Avoid initialising if already enabled +Subject: [PATCH 027/229] bcm2835-rng: Avoid initialising if already enabled Avoids the 0x40000 cycles of warmup again if firmware has already used it --- @@ -1567,10 +1567,10 @@ index 574211a495491d9d6021dcaefe4274a63ed02055..e66c0fca8c6090e32f72796c0877a1cf err = hwrng_register(&bcm2835_rng_ops); if (err) { -From d917a5b2280fe48ef807f0c67b23fa8f55fb7687 Mon Sep 17 00:00:00 2001 +From 878e5404accdb54a7dbdb04fca64fd388b519c27 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 24 Aug 2016 16:28:44 +0100 -Subject: [PATCH 028/220] kbuild: Ignore dtco targets when filtering symbols +Subject: [PATCH 028/229] kbuild: Ignore dtco targets when filtering symbols --- scripts/Kbuild.include | 2 +- @@ -1590,10 +1590,10 @@ index 179219845dfcdfbeb586d12c5ec1296095d9fbf4..e0743e44f84188667a0c322e8c3d36f1 esac | tr ";" "\n" | sed -rn 's/^.*=== __KSYM_(.*) ===.*$$/KSYM_\1/p' -From e668d477605548f3bda8ccaaa3d8cfde214ef748 Mon Sep 17 00:00:00 2001 +From 01111f91ba6ca8650464a2d63be3a5efbecc286b Mon Sep 17 00:00:00 2001 From: Robert Tiemann Date: Mon, 20 Jul 2015 11:01:25 +0200 -Subject: [PATCH 029/220] BCM2835_DT: Fix I2S register map +Subject: [PATCH 029/229] BCM2835_DT: Fix I2S register map --- Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt | 4 ++-- @@ -1631,10 +1631,10 @@ index 65783de0aedf3da79adc36fd077b7a89954ddb6b..a89fe4220fdc3f26f75ee66daf187554 dmas = <&dma 2>, <&dma 3>; -From 79b139ddbe668e2f2b05d54b3caa01ac837cc01f Mon Sep 17 00:00:00 2001 +From fc3efa2b58407f9120532a75a0eb31e3d946e324 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 030/220] Main bcm2708/bcm2709 linux port +Subject: [PATCH 030/229] Main bcm2708/bcm2709 linux port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -1841,10 +1841,10 @@ index cfb4b4496dd9f61362dea012176c146120fada07..d9c6c217c4d6a2408abe2665bf7f2700 MODULE_AUTHOR("Lubomir Rintel "); MODULE_DESCRIPTION("BCM2835 mailbox IPC driver"); -From 255056f5891a55df23e6bd9b6239022cb30c9806 Mon Sep 17 00:00:00 2001 +From e6b0c3acbc8ed89dec1a97037fda008a0d65c554 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 031/220] Add dwc_otg driver +Subject: [PATCH 031/229] Add dwc_otg driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -2546,10 +2546,10 @@ index 358ca8dd784fe43700ae070764fa783500a792fe..abaac7c7142d8887c1516957fc52162c return i; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index c28ccf1b5a1fe285044024fff3f70bf9ae7cc91f..0e65cb92d12eb9645ddc21b902cd8b141cafef47 100644 +index 35fb2bef0e45971568dbbafd2699fe0b1d3a4e5b..28d781209de161d4dd02ee9dcf2b86e43c8858a3 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c -@@ -5009,7 +5009,7 @@ static void port_event(struct usb_hub *hub, int port1) +@@ -5016,7 +5016,7 @@ static void port_event(struct usb_hub *hub, int port1) if (portchange & USB_PORT_STAT_C_OVERCURRENT) { u16 status = 0, unused; @@ -62901,10 +62901,10 @@ index 0000000000000000000000000000000000000000..cdc9963176e5a4a0d5250613b61e26c5 +test_main(); +0; -From e4ae0eb3bfe63196bb9577dda90d44b377fff72b Mon Sep 17 00:00:00 2001 +From 720b024065112322f1f8d8adad09e24d9b8b3a33 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 17:06:34 +0100 -Subject: [PATCH 032/220] bcm2708 framebuffer driver +Subject: [PATCH 032/229] bcm2708 framebuffer driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -66363,10 +66363,10 @@ index 3c14e43b82fefe1d32f591d1b2f61d2cd28d0fa8..7626beb6a5bb8df601ddf0f6e6909d1f +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 -From 1c2a6d9e3cfab206f4a7f9498a30bb38d39eb3d1 Mon Sep 17 00:00:00 2001 +From 5170d3020760803904fb33f948a08e3f2fe9c99a Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 033/220] dmaengine: Add support for BCM2708 +Subject: [PATCH 033/229] dmaengine: Add support for BCM2708 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -66997,10 +66997,10 @@ index 0000000000000000000000000000000000000000..c5bfff2765be4606077e6c8af73040ec + +#endif /* _PLAT_BCM2708_DMA_H */ -From fdc5c1e17bb8cdaa612dde04bbd1b6b3f5636686 Mon Sep 17 00:00:00 2001 +From 65050c0d8eee5ee8951136cf37ab79a16714a439 Mon Sep 17 00:00:00 2001 From: gellert Date: Fri, 15 Aug 2014 16:35:06 +0100 -Subject: [PATCH 034/220] MMC: added alternative MMC driver +Subject: [PATCH 034/229] MMC: added alternative MMC driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -68750,10 +68750,10 @@ index 0000000000000000000000000000000000000000..4fe8d1fe44578fbefcd48f8c327ba3d0 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gellert Weisz"); -From e47f0fe40ec129cab52f07ad0c315d37a2d57fe2 Mon Sep 17 00:00:00 2001 +From 11a2ec26cc0c9a4a901683bcc5db431495785c73 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 25 Mar 2015 17:49:47 +0000 -Subject: [PATCH 035/220] Adding bcm2835-sdhost driver, and an overlay to +Subject: [PATCH 035/229] Adding bcm2835-sdhost driver, and an overlay to enable it BCM2835 has two SD card interfaces. This driver uses the other one. @@ -71158,10 +71158,10 @@ index 0000000000000000000000000000000000000000..a9bc79bfdbb71807819dfe2d8f165144 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Phil Elwell"); -From 5fcecb8e60f05180c91e2a18b779d5c8461ab620 Mon Sep 17 00:00:00 2001 +From 2d193c7dae8a2303209a2fe91fda9ae8533c5f20 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 11 May 2016 12:50:33 +0100 -Subject: [PATCH 036/220] mmc: Add MMC_QUIRK_ERASE_BROKEN for some cards +Subject: [PATCH 036/229] mmc: Add MMC_QUIRK_ERASE_BROKEN for some cards Some SD cards have been found that corrupt data when small blocks are erased. Add a quirk to indicate that ERASE should not be used, @@ -71297,10 +71297,10 @@ index 73fad83acbcb6a157587180516f9ffe7c61eb7d7..e7c9d3098ac06e3c6554fa3373a311f9 unsigned int erase_shift; /* if erase unit is power 2 */ unsigned int pref_erase; /* in sectors */ -From f7c278edaa5dc994fb610ccf72ba33c340925972 Mon Sep 17 00:00:00 2001 +From bf2cb577cae2292835fa1b23d6a7bc4e6e57cd83 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 037/220] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 037/229] cma: Add vc_cma driver to enable use of CMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -71332,7 +71332,7 @@ Signed-off-by: Noralf Trønnes create mode 100644 include/linux/broadcom/vc_cma.h diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index dcc09739a54ef860343ac2fca5acf59724ca60e2..6d518c7635ae128f4554945dd3ffd351f9d325bf 100644 +index 8453a49471d72aee4f1c30c7cf7fd5d11e9975ba..5e5924a51ff56d314af315e0198bd61aece084f1 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -4,6 +4,8 @@ @@ -72636,10 +72636,10 @@ index 0000000000000000000000000000000000000000..be2819d5d41f9d5ed65daf8eedb94c9e + +#endif /* VC_CMA_H */ -From a38618ea5e2cc3f84de75fa11b46725b178f1810 Mon Sep 17 00:00:00 2001 +From 007cc2317a385a0ee577ad7c10ae670445961824 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 038/220] bcm2708: alsa sound driver +Subject: [PATCH 038/229] bcm2708: alsa sound driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -75374,10 +75374,10 @@ index 0000000000000000000000000000000000000000..af3e6eb690113fc32ce9e06bd2f0f294 + +#endif // _VC_AUDIO_DEFS_H_ -From cd2ed566ba3b675d81f8ba3cfd8bd4c116e391b7 Mon Sep 17 00:00:00 2001 +From d65ea31e609388eda13399b5d76fa78b83962c0a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 28 Oct 2016 15:36:43 +0100 -Subject: [PATCH 039/220] vc_mem: Add vc_mem driver for querying firmware +Subject: [PATCH 039/229] vc_mem: Add vc_mem driver for querying firmware memory addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -75901,10 +75901,10 @@ index 0000000000000000000000000000000000000000..20a475377eb3078ea1ecaef2b24efc35 + +#endif /* _VC_MEM_H */ -From 3bca045578853ff455fa5aa9ce3cb6625a72da10 Mon Sep 17 00:00:00 2001 +From 6ec4aeb958e0f4369097c42dee73a2e3ea56acd2 Mon Sep 17 00:00:00 2001 From: Tim Gover Date: Tue, 22 Jul 2014 15:41:04 +0100 -Subject: [PATCH 040/220] vcsm: VideoCore shared memory service for BCM2835 +Subject: [PATCH 040/229] vcsm: VideoCore shared memory service for BCM2835 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -80311,10 +80311,10 @@ index 0000000000000000000000000000000000000000..334f36d0d697b047df2922b5f2db67f3 + +#endif /* __VMCS_SM_IOCTL_H__INCLUDED__ */ -From 7e2f2a04538763e7af2b66b2ef6e301c9f402590 Mon Sep 17 00:00:00 2001 +From 50677b57028c716da928d1f37ee2660d7f047986 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Fri, 21 Aug 2015 23:14:48 +0100 -Subject: [PATCH 041/220] Add /dev/gpiomem device for rootless user GPIO access +Subject: [PATCH 041/229] Add /dev/gpiomem device for rootless user GPIO access Signed-off-by: Luke Wren @@ -80625,10 +80625,10 @@ index 0000000000000000000000000000000000000000..911f5b7393ed48ceed8751f06967ae64 +MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace"); +MODULE_AUTHOR("Luke Wren "); -From 372c91d3d0d0a137618fa4df8ad8d076bc7229f4 Mon Sep 17 00:00:00 2001 +From 37c315c77e0854a6f0d0cbd59e59b423b2dafbd5 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 5 Sep 2015 01:14:45 +0100 -Subject: [PATCH 042/220] Add SMI driver +Subject: [PATCH 042/229] Add SMI driver Signed-off-by: Luke Wren --- @@ -82579,10 +82579,10 @@ index 0000000000000000000000000000000000000000..ee3a75edfc033eeb0d90a687ffb68b10 + +#endif /* BCM2835_SMI_H */ -From f3f809a8023342dd2dd4bfb36c4a6b99e34aeb20 Mon Sep 17 00:00:00 2001 +From c45bdc33fcdc9b8fc27f73e5856a0cda534c6df1 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Tue, 26 Apr 2016 14:59:21 +0000 -Subject: [PATCH 043/220] MISC: bcm2835: smi: use clock manager and fix reload +Subject: [PATCH 043/229] MISC: bcm2835: smi: use clock manager and fix reload issues Use clock manager instead of self-made clockmanager. @@ -82752,10 +82752,10 @@ index 63a4ea08b9930a3a31a985f0a1d969b488ed49ec..1261540703127d1d63b9f3c87042c6e5 return 0; } -From f2bfd53319709e8d543eb7ae3dc4d59ae3908093 Mon Sep 17 00:00:00 2001 +From 04f085b20286938b2edbaee180d154792ed2c8b3 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 5 Sep 2015 01:16:10 +0100 -Subject: [PATCH 044/220] Add SMI NAND driver +Subject: [PATCH 044/229] Add SMI NAND driver Signed-off-by: Luke Wren --- @@ -83120,10 +83120,10 @@ index 0000000000000000000000000000000000000000..02adda6da18bd0ba9ab19a104975b79d + ("Driver for NAND chips using Broadcom Secondary Memory Interface"); +MODULE_AUTHOR("Luke Wren "); -From 30a6c2c5267914444f95d7c70b56318deca21efb Mon Sep 17 00:00:00 2001 +From 703a412e030de0a175b587b44bc0738354de2e4c Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 045/220] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 045/229] lirc: added support for RaspberryPi GPIO lirc_rpi: Use read_current_timer to determine transmitter delay. Thanks to jjmz and others See: https://github.com/raspberrypi/linux/issues/525 @@ -83986,10 +83986,10 @@ index 0000000000000000000000000000000000000000..fb69624ccef00ddbdccf8256d6baf1b1 + +#endif -From b74ad641f8868ca5d3c3aef7baea0ae1f03ec341 Mon Sep 17 00:00:00 2001 +From 3a261e33ae9c95d3772670611169ac85607b5be9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 046/220] Add cpufreq driver +Subject: [PATCH 046/229] Add cpufreq driver Signed-off-by: popcornmix --- @@ -84256,10 +84256,10 @@ index 0000000000000000000000000000000000000000..414fbdc10dfbfc6e4bb47870a7af3fd5 +module_init(bcm2835_cpufreq_module_init); +module_exit(bcm2835_cpufreq_module_exit); -From 20e4a967e3f3b88d63e3d7c46c8198afd6581bd2 Mon Sep 17 00:00:00 2001 +From c1737e0db817d17df8147e80d45eeb095e27a7a9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 047/220] Added hwmon/thermal driver for reporting core +Subject: [PATCH 047/229] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -84425,10 +84425,10 @@ index 0000000000000000000000000000000000000000..c63fb9f9d143e19612a18fe530c7b2b3 +MODULE_DESCRIPTION("Thermal driver for bcm2835 chip"); +MODULE_LICENSE("GPL"); -From e485d7218d11ef86bf03a948c3df1dd6e2264683 Mon Sep 17 00:00:00 2001 +From f73a86da3d30b9a334b262026ddfe87bfd9ae8c1 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 15:44:08 +0100 -Subject: [PATCH 048/220] Add Chris Boot's i2c driver +Subject: [PATCH 048/229] Add Chris Boot's i2c driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -85093,10 +85093,10 @@ index 0000000000000000000000000000000000000000..962f2e5c7455d91bf32925d785f5f16b +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From a867b62a2fc6e866a52d3742894727045a15cc67 Mon Sep 17 00:00:00 2001 +From 1db902a5f1e80f377cf093db330ad9617375ea45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:27:06 +0200 -Subject: [PATCH 049/220] char: broadcom: Add vcio module +Subject: [PATCH 049/229] char: broadcom: Add vcio module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -85322,10 +85322,10 @@ index 0000000000000000000000000000000000000000..c19bc2075c77879563ef5e59038b5a14 +MODULE_DESCRIPTION("Mailbox userspace access"); +MODULE_LICENSE("GPL"); -From c3895f611eafd3c731d2964df1581f07fb2f9522 Mon Sep 17 00:00:00 2001 +From 53ce66f55753253f3e9adcec3d59640e1c797560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:25:01 +0200 -Subject: [PATCH 050/220] firmware: bcm2835: Support ARCH_BCM270x +Subject: [PATCH 050/229] firmware: bcm2835: Support ARCH_BCM270x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -85408,10 +85408,10 @@ index dd506cd3a5b874f9e1acd07efb8cd151bb6145d1..3f070bd38a91511c986e3fb114b15bd4 MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("Raspberry Pi firmware driver"); -From 0bd5079a80dd6bc9c593e13e52b8e64ef9b79da5 Mon Sep 17 00:00:00 2001 +From 9ae97b240e6285f7a47b6d5aa1a13aa01609f3ad Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 051/220] bcm2835: add v4l2 camera device +Subject: [PATCH 051/229] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -93153,10 +93153,10 @@ index 0000000000000000000000000000000000000000..9d1d11e4a53e510c04a416d92d195a7d + +#endif /* MMAL_VCHIQ_H */ -From 201640f5760f1d84cf0b8a8a49d695809f78e365 Mon Sep 17 00:00:00 2001 +From a15ffe27fd20c8835a1404679e70e0a6f4c312a6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 11 May 2015 09:00:42 +0100 -Subject: [PATCH 052/220] scripts: Add mkknlimg and knlinfo scripts from tools +Subject: [PATCH 052/229] scripts: Add mkknlimg and knlinfo scripts from tools repo The Raspberry Pi firmware looks for a trailer on the kernel image to @@ -93676,10 +93676,10 @@ index 0000000000000000000000000000000000000000..60206de7fa9a49bd027c635306674a29 + return $trailer; +} -From 75eaa71803c4d693ae6a2c8e0b4e5510f036c1f2 Mon Sep 17 00:00:00 2001 +From 03ab2da6d25acf5c13aab3dba565e9ad498ef0b4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 10 Aug 2015 09:49:15 +0100 -Subject: [PATCH 053/220] scripts/dtc: Update to upstream version 1.4.1 +Subject: [PATCH 053/229] scripts/dtc: Update to upstream version 1.4.1 Includes the new localfixups format. @@ -96530,10 +96530,10 @@ index ad9b05ae698b0495ecbda42ffcf4743555313a27..2595dfda020fd9e03f0beff5006f229d -#define DTC_VERSION "DTC 1.4.1-g53bf130b" +#define DTC_VERSION "DTC 1.4.1-g25efc119" -From 7cea97bde2fb5a4958335b884aee20a5d5f03262 Mon Sep 17 00:00:00 2001 +From 8ade2c47ccf954e386bfec5ff051435975a669dc Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:46:08 +0200 -Subject: [PATCH 054/220] BCM2708: Add core Device Tree support +Subject: [PATCH 054/229] BCM2708: Add core Device Tree support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -106661,10 +106661,10 @@ index 0a07f9014944ed92a8e2e42983ae43be60b3e471..1967878a843461c3ff1f473b9a030eb0 # Bzip2 -From 2294dcf5e531118e721e9a4ff946aa7eaa1de06d Mon Sep 17 00:00:00 2001 +From a1262117d6c9ed2e113a57eb004ac3b0bbfb138c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 Feb 2015 13:50:57 +0000 -Subject: [PATCH 055/220] BCM270x_DT: Add pwr_led, and the required "input" +Subject: [PATCH 055/229] BCM270x_DT: Add pwr_led, and the required "input" trigger The "input" trigger makes the associated GPIO an input. This is to support @@ -106840,10 +106840,10 @@ index ddfcb2df3656cf0ab6aebd1fa3d624a6ec2e94e9..271563eb835f9018712e2076a88f341d /* Set LED brightness level * Must not sleep. Use brightness_set_blocking for drivers -From 2ba877036465a3cd0848a8bf576650e01575571f Mon Sep 17 00:00:00 2001 +From 71d39d01810797ce92e8f29cf824a64d2e8104d8 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 056/220] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 056/229] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -107095,10 +107095,10 @@ index fb795c3b3c178ad3cd7c9e9e4547ffd492bac181..703fa8a70574323abe2fb32599254582 __u32 dx; /* screen-relative */ __u32 dy; -From 051268acb9fcf7b4bbd5fa81a46af4989c419b27 Mon Sep 17 00:00:00 2001 +From d75614a783a4c69c60d7b19bcf141f8503bcfa22 Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 057/220] Speed up console framebuffer imageblit function +Subject: [PATCH 057/229] Speed up console framebuffer imageblit function Especially on platforms with a slower CPU but a relatively high framebuffer fill bandwidth, like current ARM devices, the existing @@ -107307,10 +107307,10 @@ index a2bb276a8b2463eee98eb237c4647bc00cd93601..436494fba15abecb400ef28688466faf start_index, pitch_index); } else -From aa6d09ed8941a36181549e9a273d5c2be4a3210e Mon Sep 17 00:00:00 2001 +From 5797ce2ede3c2df641c6a9e70d410b2f2b098911 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 058/220] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 058/229] enabling the realtime clock 1-wire chip DS1307 and 1-wire on GPIO4 (as a module) 1-wire: Add support for configuring pin for w1-gpio kernel module @@ -107560,10 +107560,10 @@ index d58594a3232492e33f1dd4babd3798b03e0f0203..feae94256256316fd9d850c3d83325af unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; -From 26d60ab559d4ea92afc001308765d4c3f07be640 Mon Sep 17 00:00:00 2001 +From cc604f99ccdffe1276d5031294f69a660b01c638 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 059/220] config: Enable CONFIG_MEMCG, but leave it disabled +Subject: [PATCH 059/229] config: Enable CONFIG_MEMCG, but leave it disabled (due to memory cost). Enable with cgroup_enable=memory. --- @@ -107571,10 +107571,10 @@ Subject: [PATCH 059/220] config: Enable CONFIG_MEMCG, but leave it disabled 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c -index 4e2f3de0e40bff4caef5ee9c587ea19140d07f85..4b687fba53c58e744e04608a9510f9b811f26343 100644 +index a3d2aad2443f3314396d25086d891eca22317cf8..45db7dee21858fc80e571f463717e51afce4262c 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c -@@ -5626,7 +5626,7 @@ int __init cgroup_init_early(void) +@@ -5627,7 +5627,7 @@ int __init cgroup_init_early(void) return 0; } @@ -107583,7 +107583,7 @@ index 4e2f3de0e40bff4caef5ee9c587ea19140d07f85..4b687fba53c58e744e04608a9510f9b8 /** * cgroup_init - cgroup initialization -@@ -6163,6 +6163,28 @@ static int __init cgroup_no_v1(char *str) +@@ -6164,6 +6164,28 @@ static int __init cgroup_no_v1(char *str) } __setup("cgroup_no_v1=", cgroup_no_v1); @@ -107613,10 +107613,10 @@ index 4e2f3de0e40bff4caef5ee9c587ea19140d07f85..4b687fba53c58e744e04608a9510f9b8 * css_tryget_online_from_dir - get corresponding css from a cgroup dentry * @dentry: directory dentry of interest -From 5d758fbf4aca0b7c1edf791f2592a6da5141b023 Mon Sep 17 00:00:00 2001 +From 4f6e576e8cafa2c4cef2bfd1298d8beff5f3d4ab Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 14 Jul 2014 22:02:09 +0100 -Subject: [PATCH 060/220] hid: Reduce default mouse polling interval to 60Hz +Subject: [PATCH 060/229] hid: Reduce default mouse polling interval to 60Hz Reduces overhead when using X --- @@ -107652,10 +107652,10 @@ index ae83af649a607f67239f1a64bf45dd4b5770cc7d..4a7af9d0b910f59d17421ce14138400d ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { -From 8c9b2d7d5038f9824f2de9194704680d99e1b982 Mon Sep 17 00:00:00 2001 +From 06a98a9947af50301d550e0d25b84b9638e670cb Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Tue, 12 May 2015 14:47:56 +0100 -Subject: [PATCH 061/220] rpi-ft5406: Add touchscreen driver for pi LCD display +Subject: [PATCH 061/229] rpi-ft5406: Add touchscreen driver for pi LCD display Fix driver detection failure Check that the buffer response is non-zero meaning the touchscreen was detected @@ -108013,10 +108013,10 @@ index 227a107214a02deadcca3db202da265eba1fdd21..b0f6e33bd30c35664ceee057f4c3ad32 RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f, -From efeb9051d9d8cc32d7bb6acdac458b7bf658a29e Mon Sep 17 00:00:00 2001 +From c989ab09b298d8f44d70d200e2f8daa693d6e080 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 28 Nov 2016 16:50:04 +0000 -Subject: [PATCH 062/220] Improve __copy_to_user and __copy_from_user +Subject: [PATCH 062/229] Improve __copy_to_user and __copy_from_user performance Provide a __copy_from_user that uses memcpy. On BCM2708, use @@ -109591,10 +109591,10 @@ index 333dc3c2e5ffbb2c5ab8fcfb6115b6162643cf20..46b787a6474ffa857da9b663948863ec bool "Broadcom BCM63xx DSL SoC" depends on ARCH_MULTI_V7 -From c3ae87038305b92e9180cb80fc55a181806702b2 Mon Sep 17 00:00:00 2001 +From 101ea4dcb4d6e197c8205c6ed768310a87a2ec06 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 25 Jun 2015 12:16:11 +0100 -Subject: [PATCH 063/220] gpio-poweroff: Allow it to work on Raspberry Pi +Subject: [PATCH 063/229] gpio-poweroff: Allow it to work on Raspberry Pi The Raspberry Pi firmware manages the power-down and reboot process. To do this it installs a pm_power_off handler, causing @@ -109629,10 +109629,10 @@ index be3d81ff51cc3f510d85e4eed7a52960e51e7bc1..a030ae9fb1fca325061c093696e82186 "%s: pm_power_off function already registered", __func__); -From d4819a37276f0ef6f3e2cdcd5eccfb0b011cff81 Mon Sep 17 00:00:00 2001 +From 9e3b24f5e14f4ee5e245273e438264cdaae253e5 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 14:32:47 +0100 -Subject: [PATCH 064/220] mfd: Add Raspberry Pi Sense HAT core driver +Subject: [PATCH 064/229] mfd: Add Raspberry Pi Sense HAT core driver --- drivers/input/joystick/Kconfig | 8 + @@ -110497,10 +110497,10 @@ index 0000000000000000000000000000000000000000..56196dc2af10e464a1e3f98b028dca1c + +#endif -From 9f6bdc019a388b1ea4b3a27e46ca8726118c9552 Mon Sep 17 00:00:00 2001 +From 855bc2c77914c65c0545e34ca8b616ce21a293ff Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 065/220] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 065/229] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -110675,10 +110675,10 @@ index 0000000000000000000000000000000000000000..45f2b770ad9e67728ca599a7445d6ae9 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); +MODULE_LICENSE("GPL v2"); -From d7f0d75af3c821a8c21b2d901e96e13a10e0fff0 Mon Sep 17 00:00:00 2001 +From bba1ca849bd063ca5222ff21b6c6d4111b519806 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Mon, 25 Jan 2016 15:48:59 +0000 -Subject: [PATCH 066/220] ASoC: Add support for Rpi-DAC +Subject: [PATCH 066/229] ASoC: Add support for Rpi-DAC --- sound/soc/bcm/Kconfig | 7 +++ @@ -110962,10 +110962,10 @@ index 0000000000000000000000000000000000000000..afe1b419582aa40c4b2729d242bb13cd +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From fe26ef9411dc01b92a3e34e3d2dbfcce78555ab4 Mon Sep 17 00:00:00 2001 +From 0f9b79e7c14e113edd3b333709c3a7bb0d06744f Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 067/220] ASoC: wm8804: Implement MCLK configuration options, +Subject: [PATCH 067/229] ASoC: wm8804: Implement MCLK configuration options, add 32bit support WM8804 can run with PLL frequencies of 256xfs and 128xfs for most sample rates. At 192kHz only 128xfs is supported. The existing driver selects 128xfs automatically for some lower samples rates. By using an @@ -111014,10 +111014,10 @@ index af95d648265b3e92e345101542b332aee35191d4..513f56ba132929662802d15cdc653af3 .component_driver = { .dapm_widgets = wm8804_dapm_widgets, -From d688169c6c2216690e615b8b539ec1886ac83eeb Mon Sep 17 00:00:00 2001 +From eafee11cda0f176ddb444c59ebf790344e5a5b03 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 068/220] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 068/229] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -111361,10 +111361,10 @@ index 0000000000000000000000000000000000000000..19dc953b7227ba86123fc7a2ba654499 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); +MODULE_LICENSE("GPL v2"); -From 9882b17f502ab6eba3e60ec3ec04744f669b6bfc Mon Sep 17 00:00:00 2001 +From b4e4db59ea48160171b6a01b003abef5ac6ed38d Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 069/220] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 069/229] Add IQaudIO Sound Card support for Raspberry Pi Set a limit of 0dB on Digital Volume Control @@ -111694,10 +111694,10 @@ index 0000000000000000000000000000000000000000..4e8e6dec14bcf4a1ff286c43742d4097 +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); -From 94eeca6a279f8e3c395d0048a4c24e0dbc4093f9 Mon Sep 17 00:00:00 2001 +From 9c16bec9bc7f8bc87099cf0130f44adfb0d27a01 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 25 Jul 2016 17:06:50 +0100 -Subject: [PATCH 070/220] iqaudio-dac: Compile fix - untested +Subject: [PATCH 070/229] iqaudio-dac: Compile fix - untested --- sound/soc/bcm/iqaudio-dac.c | 6 +++++- @@ -111721,10 +111721,10 @@ index 4e8e6dec14bcf4a1ff286c43742d4097249d6777..aa15bc4b49ca95edec905fddd8fd0a6d if (dapm->dev != codec_dai->dev) return 0; -From c3c66b676e27402aa8f6df477b14c3b25ab00e1f Mon Sep 17 00:00:00 2001 +From 0e74e8e4d9ac3510421ce91d095456d490bf33c2 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 10:06:56 +0200 -Subject: [PATCH 071/220] Added support for HiFiBerry DAC+ +Subject: [PATCH 071/229] Added support for HiFiBerry DAC+ The driver is based on the HiFiBerry DAC driver. However HiFiBerry DAC+ uses a different codec chip (PCM5122), therefore a new driver is necessary. @@ -112354,10 +112354,10 @@ index 72b19e62f6267698aea45d2410d616d91c1825cb..c6839ef6e16754ed9de2698507b8986a dev_err(dev, "No LRCLK?\n"); return -EINVAL; -From b32b2cfa080c1bb6689ccf00857896d57534682f Mon Sep 17 00:00:00 2001 +From ec92c2143d9505b6829cb4ff13ec33ff90f3adb0 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 11:09:58 +0200 -Subject: [PATCH 072/220] Added driver for HiFiBerry Amp amplifier add-on board +Subject: [PATCH 072/229] Added driver for HiFiBerry Amp amplifier add-on board The driver contains a low-level hardware driver for the TAS5713 and the drivers for the Raspberry Pi I2S subsystem. @@ -113197,10 +113197,10 @@ index 0000000000000000000000000000000000000000..8f019e04898754d2f87e9630137be9e8 + +#endif /* _TAS5713_H */ -From 6c6253ced927fd8a4a4bc7dbfd96cb934e3f2f85 Mon Sep 17 00:00:00 2001 +From 9f40f104f6893e8ba6d3eaf69bfdeb8c4dc5108f Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:25:49 -0700 -Subject: [PATCH 073/220] Update ds1307 driver for device-tree support +Subject: [PATCH 073/229] Update ds1307 driver for device-tree support Signed-off-by: Ryan Coe --- @@ -113227,10 +113227,10 @@ index 4e31036ee2596dec93accd26f627c5b95591ae9f..b92044cf03e750afa521a93519500e9d .driver = { .name = "rtc-ds1307", -From b6529d4aa9141d702f95c06227af481cffd823c3 Mon Sep 17 00:00:00 2001 +From 7fcc953a86eefbc84fa31a5f35396b3f7989aca1 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 25 Mar 2015 09:26:17 +0100 -Subject: [PATCH 074/220] Add driver for rpi-proto +Subject: [PATCH 074/229] Add driver for rpi-proto Forward port of 3.10.x driver from https://github.com/koalo We are using a custom board and would like to use rpi 3.18.x @@ -113446,10 +113446,10 @@ index 0000000000000000000000000000000000000000..9db678e885efd63d84d60a098a84ed67 +MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)"); +MODULE_LICENSE("GPL"); -From 477089266946852344ffa0af34aa55a5935140a5 Mon Sep 17 00:00:00 2001 +From eda93dadf2ff70fa40bc6e25cfbcf4c002d497b4 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Mon, 24 Aug 2015 16:03:47 +0100 -Subject: [PATCH 075/220] RaspiDAC3 support +Subject: [PATCH 075/229] RaspiDAC3 support Signed-off-by: Jan Grulich @@ -113692,10 +113692,10 @@ index 0000000000000000000000000000000000000000..dd9eeea2af0382307f437e6db09d1546 +MODULE_DESCRIPTION("ASoC Driver for RaspiDAC Rev.3x"); +MODULE_LICENSE("GPL v2"); -From 21769c8cd7439b9e3e50e774d65ae484d388be8d Mon Sep 17 00:00:00 2001 +From 15aa080d980f651b5d97f4d6e481abf18fbe74f6 Mon Sep 17 00:00:00 2001 From: Aaron Shaw Date: Thu, 7 Apr 2016 21:26:21 +0100 -Subject: [PATCH 076/220] Add Support for JustBoom Audio boards +Subject: [PATCH 076/229] Add Support for JustBoom Audio boards justboom-dac: Adjust for ALSA API change @@ -114149,10 +114149,10 @@ index 0000000000000000000000000000000000000000..91acb666380faa3c0deb2230f8a0f8bb +MODULE_DESCRIPTION("ASoC Driver for JustBoom PI Digi HAT Sound Card"); +MODULE_LICENSE("GPL v2"); -From 8e16cb34280580accee4d4b246a2bf1f68898014 Mon Sep 17 00:00:00 2001 +From bf13321d80233017145d5fda5b01e34f8de9a166 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky Date: Tue, 3 May 2016 22:10:59 -0400 -Subject: [PATCH 077/220] ARM: adau1977-adc: Add basic machine driver for +Subject: [PATCH 077/229] ARM: adau1977-adc: Add basic machine driver for adau1977 codec driver. This commit adds basic support for the codec usage including: Device tree overlay, @@ -114334,10 +114334,10 @@ index 0000000000000000000000000000000000000000..6e2ee027926ee63c89222f75ceb89e3d +MODULE_DESCRIPTION("ASoC Driver for ADAU1977 ADC"); +MODULE_LICENSE("GPL v2"); -From e2bb2f096bf36883b8e7b026f2fabb48d64e137a Mon Sep 17 00:00:00 2001 +From 661232aaff54122beaa4a9ad08b5d9e547a6a31f Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Mon, 16 May 2016 21:36:31 +1000 -Subject: [PATCH 078/220] New AudioInjector.net Pi soundcard with low jitter +Subject: [PATCH 078/229] New AudioInjector.net Pi soundcard with low jitter audio in and out. Contains the sound/soc/bcm ALSA machine driver and necessary alterations to the Kconfig and Makefile. @@ -114588,10 +114588,10 @@ index 0000000000000000000000000000000000000000..ef54e0f07ea03f59e9957b5d98f3e7fd +MODULE_ALIAS("platform:audioinjector-pi-soundcard"); + -From 8ad7c0ce666a8d9bf54dffcffe99230986e80683 Mon Sep 17 00:00:00 2001 +From 0de5e9aa69797bbadd19ab02752c87453ec79f91 Mon Sep 17 00:00:00 2001 From: DigitalDreamtime Date: Thu, 30 Jun 2016 18:38:42 +0100 -Subject: [PATCH 079/220] Add IQAudIO Digi WM8804 board support +Subject: [PATCH 079/229] Add IQAudIO Digi WM8804 board support Support IQAudIO Digi board with iqaudio_digi machine driver and iqaudio-digi-wm8804-audio overlay. @@ -114891,10 +114891,10 @@ index 0000000000000000000000000000000000000000..9b6e829bcb5b1762a853775e78163196 +MODULE_DESCRIPTION("ASoC Driver for IQAudIO WM8804 Digi"); +MODULE_LICENSE("GPL v2"); -From 9eddb99275e246c9fbc00591001b94250908445d Mon Sep 17 00:00:00 2001 +From a4095054f656362613c191ee300b9e65ba0bdc8b Mon Sep 17 00:00:00 2001 From: escalator2015 Date: Tue, 24 May 2016 16:20:09 +0100 -Subject: [PATCH 080/220] New driver for RRA DigiDAC1 soundcard using WM8741 + +Subject: [PATCH 080/229] New driver for RRA DigiDAC1 soundcard using WM8741 + WM8804 --- @@ -115367,10 +115367,10 @@ index 0000000000000000000000000000000000000000..446796e7e4c14a7d95b2f2a01211d9a0 +MODULE_DESCRIPTION("ASoC Driver for RRA DigiDAC1"); +MODULE_LICENSE("GPL v2"); -From ef311a15a728dd13d735f09f6214b89b8551ebd7 Mon Sep 17 00:00:00 2001 +From 3bf19276b1b847b1d96caee3c746c0d29d603e0e Mon Sep 17 00:00:00 2001 From: DigitalDreamtime Date: Sat, 2 Jul 2016 16:26:19 +0100 -Subject: [PATCH 081/220] Add support for Dion Audio LOCO DAC-AMP HAT +Subject: [PATCH 081/229] Add support for Dion Audio LOCO DAC-AMP HAT Using dedicated machine driver and pcm5102a codec driver. @@ -115543,10 +115543,10 @@ index 0000000000000000000000000000000000000000..89e65317512bc774453ac8d0d5b0ff98 +MODULE_DESCRIPTION("ASoC Driver for DionAudio LOCO"); +MODULE_LICENSE("GPL v2"); -From f0095d1c98b5bf40e328f7459b49793e68f45350 Mon Sep 17 00:00:00 2001 +From 12fe276699395b039afff7dea0ee0179a690f5f5 Mon Sep 17 00:00:00 2001 From: Clive Messer Date: Mon, 19 Sep 2016 14:01:04 +0100 -Subject: [PATCH 082/220] Allo Piano DAC boards: Initial 2 channel (stereo) +Subject: [PATCH 082/229] Allo Piano DAC boards: Initial 2 channel (stereo) support (#1645) Add initial 2 channel (stereo) support for Allo Piano DAC (2.0/2.1) boards, @@ -115753,10 +115753,10 @@ index 0000000000000000000000000000000000000000..8e8e62e5a36a279b425ed4655cfbac99 +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Piano DAC"); +MODULE_LICENSE("GPL v2"); -From 067375121b334db7e3ab4b09ceac310a0723d95a Mon Sep 17 00:00:00 2001 +From 3807cf287bc29c2a2fb95369349a7c6757bbc2b3 Mon Sep 17 00:00:00 2001 From: gtrainavicius Date: Sun, 23 Oct 2016 12:06:53 +0300 -Subject: [PATCH 083/220] Support for Blokas Labs pisound board +Subject: [PATCH 083/229] Support for Blokas Labs pisound board Pisound dynamic overlay (#1760) @@ -116933,10 +116933,10 @@ index 0000000000000000000000000000000000000000..4b8545487d06e4ea70073a5d063fb231 +MODULE_DESCRIPTION("ASoC Driver for pisound, http://blokas.io/pisound"); +MODULE_LICENSE("GPL v2"); -From 33ce233ed2584afe96636773ae8e160bf158c36f Mon Sep 17 00:00:00 2001 +From c375d01c52d73c3e83814310c5f9f21bc8b7a394 Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 21 Oct 2015 14:55:21 +0100 -Subject: [PATCH 084/220] rpi_display: add backlight driver and overlay +Subject: [PATCH 084/229] rpi_display: add backlight driver and overlay Add a mailbox-driven backlight controller for the Raspberry Pi DSI touchscreen display. Requires updated GPU firmware to recognise the @@ -117105,10 +117105,10 @@ index 0000000000000000000000000000000000000000..14a0d9b037395497c1fdae2961feccd5 +MODULE_DESCRIPTION("Raspberry Pi mailbox based Backlight Driver"); +MODULE_LICENSE("GPL"); -From 54e1dbaef697f6fc4546e0939a8deb77e3ad4033 Mon Sep 17 00:00:00 2001 +From 271dfcf951d3ac0ef459b1aa063b066b169d4786 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 23 Feb 2016 19:56:04 +0000 -Subject: [PATCH 085/220] bcm2835-virtgpio: Virtual GPIO driver +Subject: [PATCH 085/229] bcm2835-virtgpio: Virtual GPIO driver Add a virtual GPIO driver that uses the firmware mailbox interface to request that the VPU toggles LEDs. @@ -117382,10 +117382,10 @@ index b0f6e33bd30c35664ceee057f4c3ad32b914291d..e92278968b2b979db2a1f855f70e7aaf RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f, -From ac53d48c62fe76b1e1cc9efd499f24e98ebf4b72 Mon Sep 17 00:00:00 2001 +From 1e615d35b3a8ce4f3433174cf813e77cff0e3a00 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 23 Feb 2016 17:26:48 +0000 -Subject: [PATCH 086/220] amba_pl011: Don't use DT aliases for numbering +Subject: [PATCH 086/229] amba_pl011: Don't use DT aliases for numbering The pl011 driver looks for DT aliases of the form "serial", and if found uses as the device ID. This can cause @@ -117414,10 +117414,10 @@ index e2c33b9528d82ed7a2c27d083d7b1d222da68178..5a11ff833e1fd112ba04df3a427cd94b uap->old_cr = 0; uap->port.dev = dev; -From 9ba7fae58e91f74bb16cbbfb09d7144a39bc5035 Mon Sep 17 00:00:00 2001 +From 21e66cfc8bfc2195a7b769388fa98af584d8b58b Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Wed, 3 Dec 2014 13:23:28 +0200 -Subject: [PATCH 087/220] OF: DT-Overlay configfs interface +Subject: [PATCH 087/229] OF: DT-Overlay configfs interface This is a port of Pantelis Antoniou's v3 port that makes use of the new upstreamed configfs support for binary attributes. @@ -117849,10 +117849,10 @@ index 0000000000000000000000000000000000000000..0037e6868a6cda8706c88194c6a4454b +} +late_initcall(of_cfs_init); -From 3d1029a97572b0b870c97325b5ba6715f2893687 Mon Sep 17 00:00:00 2001 +From 66577977b62c8b1b9b2e30baf0f16435ec96ae35 Mon Sep 17 00:00:00 2001 From: Cheong2K Date: Fri, 26 Feb 2016 18:20:10 +0800 -Subject: [PATCH 088/220] brcm: adds support for BCM43341 wifi +Subject: [PATCH 088/229] brcm: adds support for BCM43341 wifi brcmfmac: Disable power management @@ -118015,10 +118015,10 @@ index d0407d9ad7827cd756b6311410ffe2d9a7cacc78..f1fb8a3c7a3211e8429585861f2f42e0 #define BRCM_CC_4335_CHIP_ID 0x4335 #define BRCM_CC_4339_CHIP_ID 0x4339 -From bee032889b6506b0860b46998f4e762fe0ad68f5 Mon Sep 17 00:00:00 2001 +From c9ca6019b268dd73f61430b0406d04b298219528 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 17 Dec 2015 13:37:07 +0000 -Subject: [PATCH 089/220] hci_h5: Don't send conf_req when ACTIVE +Subject: [PATCH 089/229] hci_h5: Don't send conf_req when ACTIVE Without this patch, a modem and kernel can continuously bombard each other with conf_req and conf_rsp messages, in a demented game of tag. @@ -118041,10 +118041,10 @@ index 0879d64b1caf58afb6e5d494c07d9ab7e7cdf983..5161ab30fd533d50f516bb93d5b9f402 if (H5_HDR_LEN(hdr) > 2) h5->tx_win = (data[2] & 0x07); -From 6ef0c0f087f212d6968ae96d957381cc683683a7 Mon Sep 17 00:00:00 2001 +From 80becbfb1eb526e8dc82520503c2f92d3120ab82 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 17:16:29 +0100 -Subject: [PATCH 090/220] config: Add default configs +Subject: [PATCH 090/229] config: Add default configs --- arch/arm/configs/bcm2709_defconfig | 1297 +++++++++++++++++++++++++++++++++++ @@ -120671,10 +120671,10 @@ index 0000000000000000000000000000000000000000..8acee9f31202ec14f2933d92dd70831c +CONFIG_CRC_ITU_T=y +CONFIG_LIBCRC32C=y -From e5f988ef5fd9496bec35b230dfb4289b75f1cb71 Mon Sep 17 00:00:00 2001 +From d067fb0bd2225f5ca5cf5334ea20372dc32b3355 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Wed, 24 Aug 2016 03:35:56 -0700 -Subject: [PATCH 091/220] Add arm64 configuration and device tree differences. +Subject: [PATCH 091/229] Add arm64 configuration and device tree differences. Disable MMC_BCM2835_SDHOST and MMC_BCM2835 since these drivers are crashing at the moment. @@ -122089,10 +122089,10 @@ index 0000000000000000000000000000000000000000..d7406f5a4620151044b8f716b4d10bb8 +CONFIG_LIBCRC32C=y +CONFIG_BCM2708_VCHIQ=n -From ae5882f60d59db76fcb08c3bb7d26188ab5a0c9b Mon Sep 17 00:00:00 2001 +From 048ec555bde80f0d45a509590811cf06b8683a91 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 7 Mar 2016 15:05:11 +0000 -Subject: [PATCH 092/220] vchiq_arm: Tweak the logging output +Subject: [PATCH 092/229] vchiq_arm: Tweak the logging output Signed-off-by: Phil Elwell --- @@ -122167,10 +122167,10 @@ index 2c98da4307dff994a00dc246574ef0aaee05d5da..160db24aeea33a8296923501009c1f02 switch (type) { -From a2531fd0535770cad254ea80e8bd2a94c4ada2f4 Mon Sep 17 00:00:00 2001 +From 7d957ebc37354b5e062ab797d906fa1b3192c33e Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 23 Mar 2016 14:16:25 +0000 -Subject: [PATCH 093/220] vchiq_arm: Access the dequeue_pending flag locked +Subject: [PATCH 093/229] vchiq_arm: Access the dequeue_pending flag locked Reading through this code looking for another problem (now found in userland) the use of dequeue_pending outside a lock didn't seem safe. @@ -122228,10 +122228,10 @@ index 7b6cd4d80621e38ff6d47fcd87b45fbe9cd4259b..d8669fa7f39b077877eca1829ba9538b return add_completion(instance, reason, header, user_service, -From 0abf254dd70f7520670534959d9f24840ec0bef4 Mon Sep 17 00:00:00 2001 +From 37d9af85ed4cb135e3cc842eca5d3c21edbd3df8 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 23 Mar 2016 20:53:47 +0000 -Subject: [PATCH 094/220] vchiq_arm: Service callbacks must not fail +Subject: [PATCH 094/229] vchiq_arm: Service callbacks must not fail Service callbacks are not allowed to return an error. The internal callback that delivers events and messages to user tasks does not enqueue them if @@ -122257,10 +122257,10 @@ index d8669fa7f39b077877eca1829ba9538bf2e21a82..54552c6ce54f413c9781ba279b936f98 DEBUG_TRACE(SERVICE_CALLBACK_LINE); } -From 2644cc28982a3f59033c2b6ed5cd85327f7d08d9 Mon Sep 17 00:00:00 2001 +From 8901e803a85bdad7aed4ece564a972e1479d633a Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 21 Apr 2016 13:49:32 +0100 -Subject: [PATCH 095/220] vchiq_arm: Add completion records under the mutex +Subject: [PATCH 095/229] vchiq_arm: Add completion records under the mutex An issue was observed when flushing openmax components which generate a large number of messages returning @@ -122323,10 +122323,10 @@ index 54552c6ce54f413c9781ba279b936f98be4f47b0..bde8955b7d8505d73579b77b5b392154 return VCHIQ_SUCCESS; -From dde2a0205bb9cfde62ce87b495d0c7bd69930cb9 Mon Sep 17 00:00:00 2001 +From f7818783188ad1ca3dfa917eef8a7b1c44d00c24 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 20 Jun 2016 13:51:44 +0100 -Subject: [PATCH 096/220] vchiq_arm: Avoid use of mutex in add_completion +Subject: [PATCH 096/229] vchiq_arm: Avoid use of mutex in add_completion Claiming the completion_mutex within add_completion did prevent some messages appearing twice, but provokes a deadlock caused by vcsm using @@ -122520,10 +122520,10 @@ index 160db24aeea33a8296923501009c1f02bc41e599..71a3bedc55314f3b22dbff40c05dedf0 up(&state->slot_available_event); } -From 19689de74e1902269bcac64510b987ad657e8bb9 Mon Sep 17 00:00:00 2001 +From a3670b6bf343df0f90c9035aef4becb0397526d7 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Oct 2016 10:14:10 -0700 -Subject: [PATCH 097/220] staging/vchi: Convert to current get_user_pages() +Subject: [PATCH 097/229] staging/vchi: Convert to current get_user_pages() arguments. Signed-off-by: Eric Anholt @@ -122560,10 +122560,10 @@ index e5cdda12c7e5c35c69eb96991cfdb8326def167f..085d37588c59198b4e5f00b9249bb842 num_pages, /* len */ 0, /* gup_flags */ -From 227e5348ac80d55e144540cc52cb83fac71ebcae Mon Sep 17 00:00:00 2001 +From 5d2e4bf27aef87c693de1ed6e988b5624863b918 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Oct 2016 10:16:03 -0700 -Subject: [PATCH 098/220] staging/vchi: Update for rename of +Subject: [PATCH 098/229] staging/vchi: Update for rename of page_cache_release() to put_page(). Signed-off-by: Eric Anholt @@ -122608,10 +122608,10 @@ index 085d37588c59198b4e5f00b9249bb8421695854f..5a2b8fb459ebe086ec229f37b6381bdb kfree(pages); } -From a7e01ebd2ab71bf7fa6a180164553a43acb1d61a Mon Sep 17 00:00:00 2001 +From af0be25de2e646b6f55a8c407fc504277e7d21ee Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Oct 2016 10:21:17 -0700 -Subject: [PATCH 099/220] drivers/vchi: Remove dependency on CONFIG_BROKEN. +Subject: [PATCH 099/229] drivers/vchi: Remove dependency on CONFIG_BROKEN. The driver builds now. @@ -122633,10 +122633,10 @@ index 9676fb29075a457109e4d4235f086987aec74868..db8e1beb89f9f8c48ea5964016c8285e help Kernel to VideoCore communication interface for the -From b3fd781539c0fc82d066dff19acb6678a6182547 Mon Sep 17 00:00:00 2001 +From 9db7c44044af7ca93638725180b277084f83284c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 14 Sep 2016 09:16:19 +0100 -Subject: [PATCH 100/220] raspberrypi-firmware: Export the general transaction +Subject: [PATCH 100/229] raspberrypi-firmware: Export the general transaction function. The vc4-firmware-kms module is going to be doing the MBOX FB call. @@ -122680,10 +122680,10 @@ index e92278968b2b979db2a1f855f70e7aafb224fa98..09e3d871d110eb0762ebdb5ea3293537 #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ -From acdb7331d3942780bc5391de89d9a2281646db42 Mon Sep 17 00:00:00 2001 +From 2e9d6b6d3d819ef8a26d61c260976e8af226f646 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 14 Sep 2016 09:18:09 +0100 -Subject: [PATCH 101/220] raspberrypi-firmware: Define the MBOX channel in the +Subject: [PATCH 101/229] raspberrypi-firmware: Define the MBOX channel in the header. Signed-off-by: Eric Anholt @@ -122705,10 +122705,10 @@ index 09e3d871d110eb0762ebdb5ea329353738d58661..2859db09e25bb945251e85edb39bc434 enum rpi_firmware_property_status { -From 388a0c696f392f9641658d6648d5ccf98c57ebfa Mon Sep 17 00:00:00 2001 +From e195fb27ffe8e99d6e5f975e963972e6173ad56e Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 14 Sep 2016 08:39:33 +0100 -Subject: [PATCH 102/220] drm/vc4: Add a mode for using the closed firmware for +Subject: [PATCH 102/229] drm/vc4: Add a mode for using the closed firmware for display. Signed-off-by: Eric Anholt @@ -122734,7 +122734,7 @@ index fb77db755e0a29d8589860da82186c7a1f394c72..c6dd06cca9830018c39b3b16afe4045e vc4_gem.o \ vc4_hdmi.o \ diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c -index 7aadce1f7e7a0e56b302bded53ad8c0d5977cc22..bdf32c572fc2c46932daca934dfb002d05493883 100644 +index c7e6c9839c9abfa5b4a9086024ebe3f854b13b38..c7e478f672e184974a33bb9ca72b8aa62d76e97e 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -162,6 +162,9 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, @@ -123475,103 +123475,10 @@ index 0000000000000000000000000000000000000000..d18a1dae51a2275846c9826b5bf1ba57 + }, +}; -From efa272fcf3b5d4feb8e970f5f3adaedbb52cff56 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= -Date: Sat, 17 Sep 2016 15:07:10 +0200 -Subject: [PATCH 103/220] i2c: bcm2835: Fix hang for writing messages larger - than 16 bytes -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Writing messages larger than the FIFO size results in a hang, rendering -the machine unusable. This is because the RXD status flag is set on the -first interrupt which results in bcm2835_drain_rxfifo() stealing bytes -from the buffer. The controller continues to trigger interrupts waiting -for the missing bytes, but bcm2835_fill_txfifo() has none to give. -In this situation wait_for_completion_timeout() apparently is unable to -stop the madness. - -The BCM2835 ARM Peripherals datasheet has this to say about the flags: - TXD: is set when the FIFO has space for at least one byte of data. - RXD: is set when the FIFO contains at least one byte of data. - TXW: is set during a write transfer and the FIFO is less than full. - RXR: is set during a read transfer and the FIFO is or more full. - -Implementing the logic from the downstream i2c-bcm2708 driver solved -the hang problem. - -Signed-off-by: Noralf Trønnes -Reviewed-by: Eric Anholt -Reviewed-by: Martin Sperl ---- - drivers/i2c/busses/i2c-bcm2835.c | 22 ++++++++++++++-------- - 1 file changed, 14 insertions(+), 8 deletions(-) - -diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c -index d4f3239b56865919e1b781b20a7c5ebcd76b4eb9..f283b714aa79e2e4685ed95b04b6b289f7e9eee7 100644 ---- a/drivers/i2c/busses/i2c-bcm2835.c -+++ b/drivers/i2c/busses/i2c-bcm2835.c -@@ -64,6 +64,7 @@ struct bcm2835_i2c_dev { - int irq; - struct i2c_adapter adapter; - struct completion completion; -+ struct i2c_msg *curr_msg; - u32 msg_err; - u8 *msg_buf; - size_t msg_buf_remaining; -@@ -126,14 +127,13 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) - return IRQ_HANDLED; - } - -- if (val & BCM2835_I2C_S_RXD) { -- bcm2835_drain_rxfifo(i2c_dev); -- if (!(val & BCM2835_I2C_S_DONE)) -- return IRQ_HANDLED; -- } -- - if (val & BCM2835_I2C_S_DONE) { -- if (i2c_dev->msg_buf_remaining) -+ if (i2c_dev->curr_msg->flags & I2C_M_RD) { -+ bcm2835_drain_rxfifo(i2c_dev); -+ val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); -+ } -+ -+ if ((val & BCM2835_I2C_S_RXD) || i2c_dev->msg_buf_remaining) - i2c_dev->msg_err = BCM2835_I2C_S_LEN; - else - i2c_dev->msg_err = 0; -@@ -141,11 +141,16 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) - return IRQ_HANDLED; - } - -- if (val & BCM2835_I2C_S_TXD) { -+ if (val & BCM2835_I2C_S_TXW) { - bcm2835_fill_txfifo(i2c_dev); - return IRQ_HANDLED; - } - -+ if (val & BCM2835_I2C_S_RXR) { -+ bcm2835_drain_rxfifo(i2c_dev); -+ return IRQ_HANDLED; -+ } -+ - return IRQ_NONE; - } - -@@ -155,6 +160,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, - u32 c; - unsigned long time_left; - -+ i2c_dev->curr_msg = msg; - i2c_dev->msg_buf = msg->buf; - i2c_dev->msg_buf_remaining = msg->len; - reinit_completion(&i2c_dev->completion); - -From 912ba8c7f00b0fcca8a476275730822209a876f2 Mon Sep 17 00:00:00 2001 +From c9e79874b1619a2f841c1dbde4a7aa3c39245e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Sep 2016 18:24:38 +0200 -Subject: [PATCH 104/220] i2c: bcm2835: Protect against unexpected TXW/RXR +Subject: [PATCH 103/229] i2c: bcm2835: Protect against unexpected TXW/RXR interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -123696,10 +123603,10 @@ index f283b714aa79e2e4685ed95b04b6b289f7e9eee7..d2ba1a4de36af512e8e3c97251bd3537 return -ETIMEDOUT; } -From 60c779f9cd724410a7f515ca7dd2c74b0d70ff19 Mon Sep 17 00:00:00 2001 +From 362aa18575e46d38641515073f377126be10bdae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 19 Sep 2016 17:19:41 +0200 -Subject: [PATCH 105/220] i2c: bcm2835: Use dev_dbg logging on transfer errors +Subject: [PATCH 104/229] i2c: bcm2835: Use dev_dbg logging on transfer errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -123731,10 +123638,10 @@ index d2ba1a4de36af512e8e3c97251bd3537ae61591a..54d510abd46a117c9238fc6d7edec840 if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) return -EREMOTEIO; -From d25a488c3d2cbe416f18eebda107beb959e0d1a1 Mon Sep 17 00:00:00 2001 +From 4052b875979e5a2a4512064121f28a83bd9b51f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Thu, 22 Sep 2016 22:05:50 +0200 -Subject: [PATCH 106/220] i2c: bcm2835: Can't support I2C_M_IGNORE_NAK +Subject: [PATCH 105/229] i2c: bcm2835: Can't support I2C_M_IGNORE_NAK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -123778,10 +123685,10 @@ index 54d510abd46a117c9238fc6d7edec84019d1f60d..565ef69ce61423544dc0558c85ef318b if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) -From db00e4a5449b4c07b42647cb7602d289a5f069dc Mon Sep 17 00:00:00 2001 +From e2621b15db86c88529b68dd09a74074b18340720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Sep 2016 04:54:27 +0200 -Subject: [PATCH 107/220] i2c: bcm2835: Add support for Repeated Start +Subject: [PATCH 106/229] i2c: bcm2835: Add support for Repeated Start Condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -123963,10 +123870,10 @@ index 565ef69ce61423544dc0558c85ef318b0ae9c324..241e08ae7c27cec23fad3c1bf3ebad3a static u32 bcm2835_i2c_func(struct i2c_adapter *adap) -From 8833865b9f400d0ed56a9d4d6145a937b9065f52 Mon Sep 17 00:00:00 2001 +From 4a6c08fa3e49a680330f7b1d37277b9bf7f2a146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Sep 2016 04:57:17 +0200 -Subject: [PATCH 108/220] i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT +Subject: [PATCH 107/229] i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124003,10 +123910,10 @@ index 241e08ae7c27cec23fad3c1bf3ebad3a4d2a8e6f..d2085dd3742eabebc537621968088261 bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); -From 37473a5dc43a3906a40b10ea5fe01a707c0befdc Mon Sep 17 00:00:00 2001 +From 1cb94068391d98e357edf70e524fbf1aa0123554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 27 Sep 2016 01:00:08 +0200 -Subject: [PATCH 109/220] i2c: bcm2835: Add support for dynamic clock +Subject: [PATCH 108/229] i2c: bcm2835: Add support for dynamic clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124122,10 +124029,10 @@ index d2085dd3742eabebc537621968088261f8dc7ea8..c3436f627028477f7e21b47e079fd5ab irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq) { -From 1cff038969748df4e53086ff17b956d12832053a Mon Sep 17 00:00:00 2001 +From 9ff203ee6916687ccdc23059827981833668776d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 1 Nov 2016 15:15:41 +0100 -Subject: [PATCH 110/220] i2c: bcm2835: Add debug support +Subject: [PATCH 109/229] i2c: bcm2835: Add debug support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124314,10 +124221,10 @@ index c3436f627028477f7e21b47e079fd5ab06ec188a..8642f580ce41803bd22c76a0fa80d083 if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) return -EREMOTEIO; -From 70aa7700bd80535743fb9beef96d0b637cebed3e Mon Sep 17 00:00:00 2001 +From ec8ddef211c52c295f2f8d9bfe6117fe71a13d7b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 31 Dec 2016 14:15:50 +0000 -Subject: [PATCH 111/220] arm64: Add CONFIG_ARCH_BCM2835 +Subject: [PATCH 110/229] arm64: Add CONFIG_ARCH_BCM2835 --- arch/arm64/configs/bcmrpi3_defconfig | 1 + @@ -124333,10 +124240,10 @@ index d7406f5a4620151044b8f716b4d10bb818648e06..53da5c7a33e5898a66e549fb0c39fe3d CONFIG_BCM2708_VCHIQ=n +CONFIG_ARCH_BCM2835=y -From 1413a4cbb0bee9ceaa67b42518b62b1f56e09934 Mon Sep 17 00:00:00 2001 +From 15f326747fc083b56f27d2d57554591439008b55 Mon Sep 17 00:00:00 2001 From: Alex Tucker Date: Tue, 13 Dec 2016 19:50:18 +0000 -Subject: [PATCH 112/220] Add support for Silicon Labs Si7013/20/21 +Subject: [PATCH 111/229] Add support for Silicon Labs Si7013/20/21 humidity/temperature sensor. --- @@ -124411,10 +124318,10 @@ index f6d134c095af2398fc55ae7d2b0e86456c30627c..31bda8da4cb6a56bfe493a81b9189009 }; }; -From f9e98bf01a071940ac897648f18a528a373e3b07 Mon Sep 17 00:00:00 2001 +From 001451767991156606435b6650a321fe5c4461aa Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 3 Jan 2017 21:27:46 +0000 -Subject: [PATCH 113/220] Document the si7020 option +Subject: [PATCH 112/229] Document the si7020 option --- arch/arm/boot/dts/overlays/README | 3 +++ @@ -124435,10 +124342,10 @@ index 81d991803be335e5a1bc3bb0a8c7a2c9f5c392bd..e8fa4ccb44c34a20485c4e6155467af9 Name: i2c0-bcm2708 Info: Enable the i2c_bcm2708 driver for the i2c0 bus. Not all pin combinations -From 89ebf453db75349f9b5b46f47925f3731b5e9eef Mon Sep 17 00:00:00 2001 +From 7491fd8defc166f29a912a340b2b3d3a7b0fbf20 Mon Sep 17 00:00:00 2001 From: Giedrius Trainavicius Date: Thu, 5 Jan 2017 02:38:16 +0200 -Subject: [PATCH 114/220] pisound improvements: +Subject: [PATCH 113/229] pisound improvements: * Added a writable sysfs object to enable scripts / user space software to blink MIDI activity LEDs for variable duration. @@ -124732,10 +124639,10 @@ index 4b8545487d06e4ea70073a5d063fb2310b3b94d0..ba70734b89e61a11201657406223f0b3 }; -From fd7556ce597c3332b4f5b342e7e2c7a38e2b6a27 Mon Sep 17 00:00:00 2001 +From fe0f2b309061b58f33bb4c5057f5b020c461c57e Mon Sep 17 00:00:00 2001 From: Aaron Shaw Date: Tue, 10 Jan 2017 16:05:41 +0000 -Subject: [PATCH 115/220] Add driver_name property +Subject: [PATCH 114/229] Add driver_name property Add driver name property for use with 5.1 passthrough audio in LibreElec and other Kodi based OSs --- @@ -124755,10 +124662,10 @@ index 8fd50dbe681508a2cfe8fdde1c9fedbe9a507fa7..05a224ec712d06b8b7587ab6b8bb562d .dai_link = snd_rpi_justboom_dac_dai, .num_links = ARRAY_SIZE(snd_rpi_justboom_dac_dai), -From f782f8effc0d78303a984ec66ac967939e9c4e20 Mon Sep 17 00:00:00 2001 +From 395fe72c974551ea765a21ac762f9477d59b242a Mon Sep 17 00:00:00 2001 From: Aaron Shaw Date: Tue, 10 Jan 2017 16:11:04 +0000 -Subject: [PATCH 116/220] Add driver_name paramater +Subject: [PATCH 115/229] Add driver_name paramater Add driver_name parameter for use with 5.1 passthrough audio in LibreElec and other Kodi OSs --- @@ -124778,10 +124685,10 @@ index 91acb666380faa3c0deb2230f8a0f8bbec59417b..abfdc5c4dd5811e6847bddda4921abe3 .dai_link = snd_rpi_justboom_digi_dai, .num_links = ARRAY_SIZE(snd_rpi_justboom_digi_dai), -From f407f07800ccbda10269c7d000a2cb518456efdf Mon Sep 17 00:00:00 2001 +From 11591b5b5b3a83c5537bd4085a0c0baa87d2a213 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 11 Jan 2017 13:01:21 +0000 -Subject: [PATCH 117/220] BCM270X_DT: Add pi3-disable-wifi overlay +Subject: [PATCH 116/229] BCM270X_DT: Add pi3-disable-wifi overlay pi3-disable-wifi is a minimal overlay to disable the onboard WiFi. @@ -124842,10 +124749,10 @@ index 0000000000000000000000000000000000000000..017199554bf2f4e381efcc7bb71e750c + }; +}; -From 5d44b8be50fa1b6bb4d5a06a2394b915e4560049 Mon Sep 17 00:00:00 2001 +From 5a54679ce859d2c34fb89ccd1142d79928fa95a5 Mon Sep 17 00:00:00 2001 From: Electron752 Date: Thu, 12 Jan 2017 07:07:08 -0800 -Subject: [PATCH 118/220] ARM64: Make it work again on 4.9 (#1790) +Subject: [PATCH 117/229] ARM64: Make it work again on 4.9 (#1790) * Invoke the dtc compiler with the same options used in arm mode. * ARM64 now uses the bcm2835 platform just like ARM32. @@ -125250,10 +125157,10 @@ index 53da5c7a33e5898a66e549fb0c39fe3da555ca87..c7e891d72969a388d9b135a36dbfc9c9 -CONFIG_BCM2708_VCHIQ=n -CONFIG_ARCH_BCM2835=y -From 230c1dc4e998e421082cbd988c60df28a07b80ac Mon Sep 17 00:00:00 2001 +From 9468c54af05cd96712b20ae0d6a45e73f7808cd9 Mon Sep 17 00:00:00 2001 From: Electron752 Date: Sat, 14 Jan 2017 02:54:26 -0800 -Subject: [PATCH 119/220] ARM64: Enable Kernel Address Space Randomization +Subject: [PATCH 118/229] ARM64: Enable Kernel Address Space Randomization (#1792) Randomization allows the mapping between virtual addresses and physical @@ -125285,10 +125192,10 @@ index c7e891d72969a388d9b135a36dbfc9c9cb609bf8..974d8889c0cf695eb88b57bbef11bc5a CONFIG_BINFMT_MISC=y CONFIG_COMPAT=y -From ff859e7f5700e9c44eeb4dcff97173f54fe1a30c Mon Sep 17 00:00:00 2001 +From a2905214f8f9a5d577544b3cf6267f7c3dc954ab Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sun, 15 Jan 2017 07:31:59 -0800 -Subject: [PATCH 120/220] ARM64: Enable RTL8187/RTL8192CU wifi in build config +Subject: [PATCH 119/229] ARM64: Enable RTL8187/RTL8192CU wifi in build config These drivers build now, so they can be enabled back in the build configuration just like they are for @@ -125313,10 +125220,10 @@ index 974d8889c0cf695eb88b57bbef11bc5aa556b635..4670a490dfb1e582ec24a3b39a3cb9b2 CONFIG_ZD1211RW=m CONFIG_MAC80211_HWSIM=m -From 7705397444fcbbac1c3f2a4847ffec6e8fcbf21b Mon Sep 17 00:00:00 2001 +From 428018a0e81e6f2b721175114d134cf30e71c1bf Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 16 Jan 2017 14:53:12 +0000 -Subject: [PATCH 121/220] BCM270X_DT: Add spi0-cs overlay +Subject: [PATCH 120/229] BCM270X_DT: Add spi0-cs overlay The spi0-cs overlay allows the software chip selectts to be modified using the cs0_pin and cs1_pin parameters. @@ -125404,10 +125311,10 @@ index 0000000000000000000000000000000000000000..7f79029d043c04d7496c7c3480450c69 + }; +}; -From 4c71408224f6f93f9ac9682321b1c147d45b1b67 Mon Sep 17 00:00:00 2001 +From aabd8a056966109f49e5d114861b5c16801ad4de Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 1 Jul 2016 22:09:24 +0100 -Subject: [PATCH 122/220] spi-bcm2835: Disable forced software CS +Subject: [PATCH 121/229] spi-bcm2835: Disable forced software CS Select software CS in bcm2708_common.dtsi, and disable the automatic conversion in the driver to allow hardware CS to be re-enabled with an @@ -125433,10 +125340,10 @@ index 74dd21b7373c7564ede01d84a4f63b93a6d52fa7..51cdefbf5eb265f49bd05e0aa91dfbee i2c0: i2c@7e205000 { -From 9ea5a212d20eaf9baf53b852460ed0179febc6b8 Mon Sep 17 00:00:00 2001 +From 139c8c6cff3ca80644fd2895ed23f7fa5434ea84 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 16 Jan 2017 16:33:54 +0000 -Subject: [PATCH 123/220] config: Add CONFIG_TCP_CONG_BBR See: +Subject: [PATCH 122/229] config: Add CONFIG_TCP_CONG_BBR See: https://github.com/raspberrypi/linux/issues/1784 --- @@ -125471,10 +125378,10 @@ index 8acee9f31202ec14f2933d92dd70831cda8d7b51..219f67051a2542329449b0099165ae28 CONFIG_IPV6_ROUTER_PREF=y CONFIG_INET6_AH=m -From b6703000e7089e86684fdcccd6da4f1fc8860acc Mon Sep 17 00:00:00 2001 +From 0f058832b94fba5bd5e602cb8bff12fb4131697f Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 17 Jan 2017 11:34:58 +0000 -Subject: [PATCH 124/220] BCM270X_DT: Enable UART0 on CM3 +Subject: [PATCH 123/229] BCM270X_DT: Enable UART0 on CM3 Signed-off-by: Phil Elwell --- @@ -125497,10 +125404,10 @@ index 41874c25a84226c0e4af92ec4059e0a571fe6123..3ba6e621856c288ae4694f758604619f sdhost_pins: sdhost_pins { brcm,pins = <48 49 50 51 52 53>; -From 21415f899907b9f02eca30a5ab4e411d5bec315c Mon Sep 17 00:00:00 2001 +From 9a984ea6c04c9c4c13c75b606ad85c9fd006aeda Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 17 Jan 2017 14:39:39 +0000 -Subject: [PATCH 125/220] config: Add CONFIG_MD_M25P80 and CONFIG_MD_SPI_NOR +Subject: [PATCH 124/229] config: Add CONFIG_MD_M25P80 and CONFIG_MD_SPI_NOR See: https://github.com/raspberrypi/linux/issues/1781 @@ -125539,10 +125446,10 @@ index 219f67051a2542329449b0099165ae2885022bec..c4898d63d74718097ec3a1d1fe60b230 CONFIG_OF_CONFIGFS=y CONFIG_ZRAM=m -From fc58c11e6fc82ca1c9d855135f56d953649ca366 Mon Sep 17 00:00:00 2001 +From db4243fd802325f324c91edf63b82c51fa037ef2 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:33:51 -0800 -Subject: [PATCH 126/220] ARM64/DWC_OTG: Port dwc_otg driver to ARM64 +Subject: [PATCH 125/229] ARM64/DWC_OTG: Port dwc_otg driver to ARM64 In ARM64, the FIQ mechanism used by this driver is not current implemented. As a workaround, reqular IRQ is used instead @@ -125885,10 +125792,10 @@ index 6b2c7d0c93f36a63863ff4b0ecc1f3eab77e058b..d7b700ff17821ad1944e36721fe6b2db /** The OS page size */ #define DWC_OS_PAGE_SIZE PAGE_SIZE -From 4167e54b9c6897a8a0eadb434d78a56860af0703 Mon Sep 17 00:00:00 2001 +From 9a4ec231ceb9d9ac814c4f8e9632e10d224c446f Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:43:57 -0800 -Subject: [PATCH 127/220] ARM64: Round-Robin dispatch IRQs between CPUs. +Subject: [PATCH 126/229] ARM64: Round-Robin dispatch IRQs between CPUs. IRQ-CPU mapping is round robined on ARM64 to increase concurrency and allow multiple interrupts to be serviced @@ -125962,10 +125869,10 @@ index 93e3f7660c4230c9f1dd3b195958cb498949b0ca..486bcbfb32305ee417f6b3be7e91a3ff .name = "bcm2836-gpu", .irq_mask = bcm2836_arm_irqchip_mask_gpu_irq, -From e18b3bd37e43924b0952b4c5bc225915e5af6ff8 Mon Sep 17 00:00:00 2001 +From 90ad4ba6d1d5d314626c74e5f1d383c1aaaf69ab Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:45:03 -0800 -Subject: [PATCH 128/220] ARM64: Enable DWC_OTG Driver In ARM64 Build +Subject: [PATCH 127/229] ARM64: Enable DWC_OTG Driver In ARM64 Build Config(bcmrpi3_defconfig) Signed-off-by: Michael Zoran @@ -125986,10 +125893,10 @@ index 4670a490dfb1e582ec24a3b39a3cb9b2488b1864..8c4392344eb4495689c220d5d176ee8c CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_REALTEK=m -From 0a46af1c0e5a2987d69cbab275f694a7c4153535 Mon Sep 17 00:00:00 2001 +From 97e3419592acaa360b86a6444bb67f946d919024 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:46:04 -0800 -Subject: [PATCH 129/220] ARM64: Use dwc_otg driver by default for USB. +Subject: [PATCH 128/229] ARM64: Use dwc_otg driver by default for USB. If it breaks on anybody, they can use the standard device tree overlays to switch back to the dwc2 driver. @@ -126015,10 +125922,10 @@ index f6def5d7e5d622cf09e8f87332c7374fe28da08b..3e134a1208610b90e2d0fc22f03c6e9f -}; -#endif -From 9ec14630d64986b52384438389772804c4b8bd56 Mon Sep 17 00:00:00 2001 +From c4cbd1b95c15f0e179ffd733ecd80bb868d3c29e Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 23 Jan 2017 17:36:50 +0000 -Subject: [PATCH 130/220] BCM270X_DT: Add reference to audio_pins to CM dtb +Subject: [PATCH 129/229] BCM270X_DT: Add reference to audio_pins to CM dtb The CM1 dtb contains an empty audio_pins node, but no reference to it. Adding the usual pinctrl reference from the audio node enables the @@ -126046,10 +125953,10 @@ index eb8662f0d222b4c0a9a2bcb8bccb13e86a0006b3..10be69972bd1440f574e35d515f3d6a0 hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; }; -From 61d7842d32cf765e132da3c91e292b372f969ea4 Mon Sep 17 00:00:00 2001 +From 64b84190e8f82dcbdb81a3c0780684168218f2dc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 25 Jan 2017 11:30:38 +0000 -Subject: [PATCH 131/220] config: Add additional network scheduling modules +Subject: [PATCH 130/229] config: Add additional network scheduling modules --- arch/arm/configs/bcm2709_defconfig | 4 ++++ @@ -126101,10 +126008,10 @@ index c4898d63d74718097ec3a1d1fe60b2307a6a3140..b448eaa866c200f48351819072c7fefc CONFIG_NET_SCH_PLUG=m CONFIG_NET_CLS_BASIC=m -From 1e02a58f4e9fcdf4df7bfa8f0a1a5847bd0533a6 Mon Sep 17 00:00:00 2001 +From 1a2d2836a996533ce62a30b4c7f420a4bee3eb0a Mon Sep 17 00:00:00 2001 From: chris johnson Date: Sun, 22 Jan 2017 03:27:31 +0000 -Subject: [PATCH 132/220] ASoC: A simple-card overlay for ADAU7002 +Subject: [PATCH 131/229] ASoC: A simple-card overlay for ADAU7002 Usage: `dtoverlay=adau7002-simple` --- @@ -126202,10 +126109,10 @@ index 0000000000000000000000000000000000000000..e67e6625d7967abc92cf00cb604d4c12 + }; +}; -From b68346a7aaf560a3c0f5bb0d8f3368fa0fe24902 Mon Sep 17 00:00:00 2001 +From 74920b1c374b91ce84e1985bc203f8aadc37df4f Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 25 Jan 2017 21:17:23 +0000 -Subject: [PATCH 133/220] config: Add SND_SOC_ADAU7002 codec module +Subject: [PATCH 132/229] config: Add SND_SOC_ADAU7002 codec module As there is now an overlay requiring it, build the codec module. @@ -126240,10 +126147,10 @@ index b448eaa866c200f48351819072c7fefcd8ad8132..5105a592c9bcfee1cc6a8b50fd1c6c32 CONFIG_SND_SOC_WM8804_I2C=m CONFIG_SND_SIMPLE_CARD=m -From dc9c7db126e9c43f02e274eba0a9642c2860e939 Mon Sep 17 00:00:00 2001 +From 44e8842d6af9cfe7c25872b24e635982da9d6a5e Mon Sep 17 00:00:00 2001 From: Scott Ellis Date: Fri, 27 Jan 2017 06:42:42 -0500 -Subject: [PATCH 134/220] Add overlay for mcp3008 adc (#1818) +Subject: [PATCH 133/229] Add overlay for mcp3008 adc (#1818) Some example usage: @@ -126529,10 +126436,10 @@ index 0000000000000000000000000000000000000000..06bf4264959c380d8a9f90f74e780397 + }; +}; -From 0ce341d5fba2be9d92ba7ab47cb3522c2adebcdc Mon Sep 17 00:00:00 2001 +From 04cb2b6d07495a43ef358d682335d50375a89c33 Mon Sep 17 00:00:00 2001 From: ED6E0F17 Date: Fri, 3 Feb 2017 14:52:42 +0000 -Subject: [PATCH 135/220] usb: dwc2: Avoid suspending if we're in gadget mode +Subject: [PATCH 134/229] usb: dwc2: Avoid suspending if we're in gadget mode (#1825) I've found when booting HiKey with the usb gadget cable attached @@ -126584,10 +126491,10 @@ index df5a065780054f21841ca9f08b8ab118922c530b..619ccfe1eafc4643b16970f8a1129ff9 goto skip_power_saving; -From 8693790f2fed00d8924d88a41c5acafdd04e547a Mon Sep 17 00:00:00 2001 +From 43e63a937e2502763d25f20ab86d02f9c50ed7c2 Mon Sep 17 00:00:00 2001 From: JamesH65 Date: Mon, 6 Feb 2017 15:24:47 +0000 -Subject: [PATCH 136/220] gpio_mem: Remove unnecessary dev_info output (#1830) +Subject: [PATCH 135/229] gpio_mem: Remove unnecessary dev_info output (#1830) The open function was spamming syslog every time called, so have removed call completely. @@ -126609,10 +126516,10 @@ index 911f5b7393ed48ceed8751f06967ae6463453f9c..f5e7f1ba8fb6f18dee77fad06a17480c dev_err(inst->dev, "Unknown minor device: %d", dev); ret = -ENXIO; -From 717a8a38685825e7aa32c98e0060d4c1c548fcc8 Mon Sep 17 00:00:00 2001 +From 485bcbae2ea29432fc86bc307d3857d3045ab1a3 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Sun, 22 Jan 2017 12:49:36 +0100 -Subject: [PATCH 137/220] config: Enable regulator support +Subject: [PATCH 136/229] config: Enable regulator support Signed-off-by: Matthias Reichl --- @@ -126647,10 +126554,10 @@ index 5105a592c9bcfee1cc6a8b50fd1c6c32f1381158..74bc0d81bcb4d7f6676368926cdcc10e CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_ANALOG_TV_SUPPORT=y -From defe868ac9c7aea28dfe3d674cca4ac237a42a28 Mon Sep 17 00:00:00 2001 +From 5d3a02f750e9eb547a6db6e9405154d0d4b36641 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Sun, 22 Jan 2017 12:49:36 +0100 -Subject: [PATCH 138/220] BCM270x DT: expose 3.3V and 5V system rails +Subject: [PATCH 137/229] BCM270x DT: expose 3.3V and 5V system rails Signed-off-by: Matthias Reichl --- @@ -126683,10 +126590,10 @@ index a46cb4a8b1419edd95e0e07c18b0f373222dc2bf..36d853715f2379e1952ce3d3be58dd67 + }; }; -From 628011120453bc609f27087fc87c9d919356bc7e Mon Sep 17 00:00:00 2001 +From 69311a52ed134f9cd20ee838b963415534d4c3fd Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Sun, 22 Jan 2017 12:49:36 +0100 -Subject: [PATCH 139/220] BCM270x DT: Consolidate audio card overlays +Subject: [PATCH 138/229] BCM270x DT: Consolidate audio card overlays Reference 3.3V / 5V system rails instead of instantiating local regulators. @@ -126981,10 +126888,10 @@ index 16b1247bfa618ff85936ddf78c3aea58075eaa67..f8d48233e28c7c18509b4a95692f6aff __overlay__ { compatible = "rra,digidac1-soundcard"; -From 95ca969b2e456bb562ed0566375eb7ae340c51f8 Mon Sep 17 00:00:00 2001 +From 03ce521ccd30fe64b294c85c44e4ace162911b93 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Sun, 22 Jan 2017 12:49:37 +0100 -Subject: [PATCH 140/220] ASoC: Add driver for Cirrus Logic Audio Card +Subject: [PATCH 139/229] ASoC: Add driver for Cirrus Logic Audio Card Note: due to problems with deferred probing of regulators the following softdep should be added to a modprobe.d file @@ -128234,10 +128141,10 @@ index 0000000000000000000000000000000000000000..ac8651ddff7bd3701dffe22c7fb88352 +MODULE_DESCRIPTION("ASoC driver for Cirrus Logic Audio Card"); +MODULE_LICENSE("GPL"); -From f44dfb33964a1c4605f4f9cf481c7bc0b9d2bff6 Mon Sep 17 00:00:00 2001 +From 64255853d68677b808a3180c98b7cd74e261d10f Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Sun, 22 Jan 2017 12:49:37 +0100 -Subject: [PATCH 141/220] config: enable Cirrus Logic Audio Card +Subject: [PATCH 140/229] config: enable Cirrus Logic Audio Card Signed-off-by: Matthias Reichl --- @@ -128286,10 +128193,10 @@ index 74bc0d81bcb4d7f6676368926cdcc10e581fbcae..f0b87d15e959d88eb26e5a11244365da CONFIG_SND_BCM2708_SOC_RPI_PROTO=m CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m -From 2c0b23c58a5b98e6e4ed872285009ab404a36327 Mon Sep 17 00:00:00 2001 +From 28979551fcf782d3fff4e62cfb33f70576689534 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 9 Feb 2017 14:33:30 +0000 -Subject: [PATCH 142/220] irq-bcm2836: Avoid "Invalid trigger warning" +Subject: [PATCH 141/229] irq-bcm2836: Avoid "Invalid trigger warning" Initialise the level for each IRQ to avoid a warning from the arm arch timer code. @@ -128313,10 +128220,10 @@ index 486bcbfb32305ee417f6b3be7e91a3ff069a586c..e10597c1a1e51e5e27aa574b6a26d871 static void -From eb17d3c8b7537d536f873e4a8cbceff01d52b4ab Mon Sep 17 00:00:00 2001 +From 4a26c514f3ceadc5fac1f60c20270094cd5683d6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 9 Feb 2017 14:36:44 +0000 -Subject: [PATCH 143/220] sound: Demote deferral errors to INFO level +Subject: [PATCH 142/229] sound: Demote deferral errors to INFO level At present there is no mechanism to specify driver load order, which can lead to deferrals and repeated retries until successful. @@ -128351,10 +128258,10 @@ index c0bbcd9032613a78aef551ce697cabc792880bad..a2504d8c83d74d7227e65be142a26cc9 goto _err_defer; } -From 63afb4ab766224a831fdf16e534250d60384edb4 Mon Sep 17 00:00:00 2001 +From dfaae9e11853b96a79aecc1ca7bf4cea2d12d2ca Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 9 Feb 2017 14:40:33 +0000 -Subject: [PATCH 144/220] sound: Suppress error message about deferrals +Subject: [PATCH 143/229] sound: Suppress error message about deferrals Since driver load deferrals are expected and will already have resulted in a kernel message, suppress an essentially @@ -128601,10 +128508,10 @@ index 9db678e885efd63d84d60a098a84ed6772b19a2d..fadbfade100228aaafabb0d3bdf35c01 return ret; } -From 5ae4f5002dd0d56ec5a5f0460dbc6f23e9a1d563 Mon Sep 17 00:00:00 2001 +From 70a5074730562de432cd1414e4f651769ff3611e Mon Sep 17 00:00:00 2001 From: Claggy3 Date: Sat, 11 Feb 2017 14:00:30 +0000 -Subject: [PATCH 145/220] Update vfpmodule.c +Subject: [PATCH 144/229] Update vfpmodule.c Christopher Alexander Tobias Schulze - May 2, 2015, 11:57 a.m. This patch fixes a problem with VFP state save and restore related @@ -128741,10 +128648,10 @@ index da0b33deba6d3c2906eef271f253ab7a30a92680..c6f1d6da808cda78a58f184e19e83522 /* * Save the userland NEON/VFP state. Under UP, -From 08cb651151531dc65340f990bdf8e592188a9395 Mon Sep 17 00:00:00 2001 +From dfd4e143cb7bdc1ccebe1d48f4e49fc6dd5a2f9a Mon Sep 17 00:00:00 2001 From: Martin Cerveny Date: Mon, 13 Feb 2017 17:23:47 +0100 -Subject: [PATCH 146/220] dwc_otg: fix summarize urb->actual_length for +Subject: [PATCH 145/229] dwc_otg: fix summarize urb->actual_length for isochronous transfers Kernel does not copy input data of ISO transfers to userspace @@ -128772,10 +128679,10 @@ index 162a656501988e56c9d780b7793d365fde09f801..992269d61ecf48126379a38e528f7190 dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i); } -From faf677a63e70517cd59a04f6aed3b11a8de295d7 Mon Sep 17 00:00:00 2001 +From 576b5c9de48614542ad32cb61c75d77281d7845f Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 1 Dec 2016 22:00:19 +0100 -Subject: [PATCH 147/220] clk: bcm: Support rate change propagation on bcm2835 +Subject: [PATCH 146/229] clk: bcm: Support rate change propagation on bcm2835 clocks Some peripheral clocks, like the VEC (Video EnCoder) clock need to be set @@ -128900,10 +128807,10 @@ index a99ccf9f056d3a3e7c482339e08483f3701ebc04..dafaa6b22724ab41dac1327cfa81de09 init.ops = &bcm2835_vpu_clock_clk_ops; } else { -From 3638f582dd0f8588d85467a6e1c0832807092dd4 Mon Sep 17 00:00:00 2001 +From e5efacb9b223f6ffd713e2e30769e4a4f3ed36dc Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 1 Dec 2016 22:00:20 +0100 -Subject: [PATCH 148/220] clk: bcm: Allow rate change propagation to PLLH_AUX +Subject: [PATCH 147/229] clk: bcm: Allow rate change propagation to PLLH_AUX on VEC clock The VEC clock requires needs to be set at exactly 108MHz. Allow rate @@ -128938,10 +128845,10 @@ index dafaa6b22724ab41dac1327cfa81de09908a4dfd..0453d7c6a63923370e4191db2c4d083b /* dsi clocks */ [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK( -From 9060ca4581c44c6c5c5b4deae146cfcf44f9e10c Mon Sep 17 00:00:00 2001 +From 38e87f3c4f8869155fc0e158daf081477a30e8dc Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 12 Dec 2016 09:00:53 +0100 -Subject: [PATCH 149/220] clk: bcm: Fix 'maybe-uninitialized' warning in +Subject: [PATCH 148/229] clk: bcm: Fix 'maybe-uninitialized' warning in bcm2835_clock_choose_div_and_prate() best_rate is reported as potentially uninitialized by gcc. @@ -128970,10 +128877,10 @@ index 0453d7c6a63923370e4191db2c4d083b893b3b47..9d895726ebb24bc78a2014870dbdd7c7 struct clk_hw *parent; -From 5834187e64129c0e106d29bb872f81695b168815 Mon Sep 17 00:00:00 2001 +From 200123c63be7a15943470ac28ad36a833f7b230b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 18 Jan 2017 07:31:55 +1100 -Subject: [PATCH 150/220] clk: bcm2835: Don't rate change PLLs on behalf of DSI +Subject: [PATCH 149/229] clk: bcm2835: Don't rate change PLLs on behalf of DSI PLL dividers. Our core PLLs are intended to be configured once and left alone. With @@ -129145,10 +129052,10 @@ index 9d895726ebb24bc78a2014870dbdd7c779cd1cdf..b58cff2756581ba7e0be8a818cdbdf72 /* the clocks */ -From 2e8e35870b82fb5de73255fa7af66565f8fb50e5 Mon Sep 17 00:00:00 2001 +From 360fff2ec652b2f2e5ba70d7866bbca3e4de4340 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 18 Jan 2017 07:31:56 +1100 -Subject: [PATCH 151/220] clk: bcm2835: Register the DSI0/DSI1 pixel clocks. +Subject: [PATCH 150/229] clk: bcm2835: Register the DSI0/DSI1 pixel clocks. The DSI pixel clocks are muxed from clocks generated in the analog phy by the DSI driver. In order to set them as parents, we need to do the @@ -129390,10 +129297,10 @@ index 360e00cefd35679b49890234b5c369fb52b89e20..a0c812b0fa391d149b4f546db39bdc4b +#define BCM2835_CLOCK_DSI0P 49 +#define BCM2835_CLOCK_DSI1P 50 -From 61a75db41f54a9792d7e84647dacee8610247139 Mon Sep 17 00:00:00 2001 +From 9ff06b257d97ee933e6ce72895f8045fe3f796ac Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 18 Jan 2017 07:31:57 +1100 -Subject: [PATCH 152/220] clk: bcm2835: Add leaf clock measurement support, +Subject: [PATCH 151/229] clk: bcm2835: Add leaf clock measurement support, disabled by default This proved incredibly useful during debugging of the DSI driver, to @@ -129739,10 +129646,10 @@ index b2c277b378ee799a4f8e05ad076d1253e85cb392..136e5d28f9eaeaa10d45382a0f31da9f /* the gates */ -From 218ade97d646c5cb8e0570d3f48f505d9a93b844 Mon Sep 17 00:00:00 2001 +From edfb256b81b5759de8c1ae604a9207f32485bb90 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 26 Apr 2016 13:46:13 -0700 -Subject: [PATCH 153/220] drm/panel: Add support for the Raspberry Pi 7" +Subject: [PATCH 152/229] drm/panel: Add support for the Raspberry Pi 7" Touchscreen. This driver communicates with the Atmel microcontroller for sequencing @@ -130323,10 +130230,10 @@ index 0000000000000000000000000000000000000000..1a536fe4d040f5fafe324baee110a622 +MODULE_DESCRIPTION("Raspberry Pi 7-inch touchscreen driver"); +MODULE_LICENSE("GPL v2"); -From 63053a5639161cfd102eab240fc0ea17eb7ae2a9 Mon Sep 17 00:00:00 2001 +From 971722af64e67ce4d6b95334cb5ef9eb106de78c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 2 Jun 2016 12:29:45 -0700 -Subject: [PATCH 154/220] BCM270X: Add the DSI panel to the defconfig. +Subject: [PATCH 153/229] BCM270X: Add the DSI panel to the defconfig. Signed-off-by: Eric Anholt --- @@ -130375,10 +130282,10 @@ index 8c4392344eb4495689c220d5d176ee8c189079fd..301611d2283f5f8800339271cea59aed CONFIG_DRM_VC4=m CONFIG_FB=y -From 38cc16a87a73c268f0b2f8a48804c309f9c51b93 Mon Sep 17 00:00:00 2001 +From 43367ec7cb74fe771991888f2a32f91c128224b8 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 13 Dec 2016 15:15:10 -0800 -Subject: [PATCH 155/220] ARM: bcm2835: dt: Add the DSI module nodes and +Subject: [PATCH 154/229] ARM: bcm2835: dt: Add the DSI module nodes and clocks. The modules stay disabled by default, and if you want to enable DSI @@ -130482,10 +130389,10 @@ index 51cdefbf5eb265f49bd05e0aa91dfbeee3fbfdcc..41776b97b4b6b1c053d07fd357fac4ba compatible = "brcm,bcm2835-i2c"; reg = <0x7e804000 0x1000>; -From 83e93acdc1971583e26e5e5d073f38b0210ada55 Mon Sep 17 00:00:00 2001 +From 45e66e1dae71050403d0c54e3b5d12666fb86f83 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 2 Jun 2016 15:09:35 -0700 -Subject: [PATCH 156/220] BCM270X: Enable the DSI panel node in the VC4 +Subject: [PATCH 155/229] BCM270X: Enable the DSI panel node in the VC4 overlay. Signed-off-by: Eric Anholt @@ -130636,10 +130543,10 @@ index 4f1cc20f90dc6780f74e08ebee00e5a1a6062c85..f25cd9a3936861920b0d518ff2d773ee cma-256 = <0>,"+0-1-2-3-4"; cma-192 = <0>,"-0+1-2-3-4"; -From ee952b37b9f922003ee9585cfc2a42e2114352a6 Mon Sep 17 00:00:00 2001 +From 9e135ea40fb0e583455fc8050bf7ecdd9eab9275 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 3 Nov 2016 18:53:10 -0700 -Subject: [PATCH 157/220] drm/vc4: Add support for rendering with ETC1 +Subject: [PATCH 156/229] drm/vc4: Add support for rendering with ETC1 textures. The validation for it ends up being quite simple, but I hadn't got @@ -130699,10 +130606,10 @@ index ad7edc3edf7ca1d653a0bc025a5eda6692b74370..69caa21f0cb23c9439238f6239c0041b struct drm_vc4_get_param { __u32 param; -From 52b3d9cf40d631805d4024ed9e3c4a98417fae5e Mon Sep 17 00:00:00 2001 +From b19682fb87dd6393ae3685f081f6e154889ffa2d Mon Sep 17 00:00:00 2001 From: Jonas Pfeil Date: Tue, 8 Nov 2016 00:18:39 +0100 -Subject: [PATCH 158/220] drm/vc4: Add fragment shader threading support +Subject: [PATCH 157/229] drm/vc4: Add fragment shader threading support FS threading brings performance improvements of 0-20% in glmark2. @@ -130938,10 +130845,10 @@ index 69caa21f0cb23c9439238f6239c0041b178d5669..f07a090167261131076438960c1dec17 struct drm_vc4_get_param { __u32 param; -From 332076ec2c47807ce3a887b1d5f553cfe3726327 Mon Sep 17 00:00:00 2001 +From 14b543648ecaac69b9d2aa32c6d72a994812517c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 2 Dec 2016 14:48:09 +0100 -Subject: [PATCH 159/220] drm: Add TV connector states to drm_connector_state +Subject: [PATCH 158/229] drm: Add TV connector states to drm_connector_state Some generic TV connector properties are exposed in drm_mode_config, but they are currently handled independently in each DRM encoder driver. @@ -131091,10 +130998,10 @@ index ac9d7d8e0e43a807e9fc9a0b66de5f26b49d3348..2645e803857253ff98eb94aa1bacc825 /** -From a6b2130dbab5288f1b71bf07172db1d5fdd7fca0 Mon Sep 17 00:00:00 2001 +From 53806e85b0e28114d335f5f1e1cc44ac7f324965 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 2 Dec 2016 14:48:08 +0100 -Subject: [PATCH 160/220] drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into +Subject: [PATCH 159/229] drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum List of values like the DRM_MODE_SUBCONNECTOR_xx ones are better @@ -131141,10 +131048,10 @@ index df0e3504c349a950bf41540fbcd6cd944cf11d2f..970bfc0d7107451e5bc4e29c524a764c #define DRM_MODE_CONNECTOR_Unknown 0 #define DRM_MODE_CONNECTOR_VGA 1 -From e7d68f5b95e20acbfbb8cc5b511ef866567594c4 Mon Sep 17 00:00:00 2001 +From 23f61d053734a6ad483786b3efe9b9975ac7f732 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 2 Dec 2016 14:48:10 +0100 -Subject: [PATCH 161/220] drm/vc4: Add support for the VEC (Video Encoder) IP +Subject: [PATCH 160/229] drm/vc4: Add support for the VEC (Video Encoder) IP The VEC IP is a TV DAC, providing support for PAL and NTSC standards. @@ -131883,10 +131790,10 @@ index 0000000000000000000000000000000000000000..32bb8ef985fbc6f39f9e5f459846bb77 + }, +}; -From e94a14543823231f5ab650e1e9bc59be54b5a19b Mon Sep 17 00:00:00 2001 +From 966bbd4c2c379b753065dc168a690231cf1673dc Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 15 Sep 2016 15:25:23 +0100 -Subject: [PATCH 162/220] drm/vc4: Set up SCALER_DISPCTRL at boot. +Subject: [PATCH 161/229] drm/vc4: Set up SCALER_DISPCTRL at boot. We want the HVS on, obviously, and we also want DSP3 (PV1's source) to be muxed from HVS channel 2 like we expect in vc4_crtc.c. The @@ -131946,10 +131853,10 @@ index 39f6886b24100c43b590e47e0c7bc44846721d65..b3b297fba7097bc495fa8916292c5479 * SCALER_DISPSTAT_IRQDISP0. Note that short frame contributions are * always enabled. -From faac17bf8b9cb3632accb22b0c9145a8ea75960b Mon Sep 17 00:00:00 2001 +From 54721806cc59807aa15ca137bf38ee22bdc58132 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 10 Feb 2016 16:17:29 -0800 -Subject: [PATCH 163/220] drm/vc4: Add support for feeding DSI encoders from +Subject: [PATCH 162/229] drm/vc4: Add support for feeding DSI encoders from the pixel valve. We have to set a different pixel format, which tells the hardware to @@ -131963,7 +131870,7 @@ Signed-off-by: Eric Anholt 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c -index bdf32c572fc2c46932daca934dfb002d05493883..0a861158740586836d2d47cccae4109ad4ec968d 100644 +index c7e478f672e184974a33bb9ca72b8aa62d76e97e..a4937e261202748924a5a327995b6f700afd5a97 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -352,38 +352,40 @@ static u32 vc4_get_fifo_full_level(u32 format) @@ -132064,10 +131971,10 @@ index b3b297fba7097bc495fa8916292c547925720199..385405a2df05eb3dd86d4f687aa82053 # define PV_VCONTROL_VIDEN BIT(0) -From c7c932bf0e314be090c2f9563c4083d3f90e4ec5 Mon Sep 17 00:00:00 2001 +From ba6346905722f941f3ed1849bbcbeddeb3e3134c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 10 Feb 2016 11:42:32 -0800 -Subject: [PATCH 164/220] drm/vc4: Add DSI driver +Subject: [PATCH 163/229] drm/vc4: Add DSI driver The DSI0 and DSI1 blocks on the 2835 are related hardware blocks. Some registers move around, and the featureset is slightly different, @@ -133895,10 +133802,10 @@ index 0000000000000000000000000000000000000000..17fcac381dbb37cd9a5ff210ad8578f4 + }, +}; -From f989d336154383fb68900bdd474cd765f2422216 Mon Sep 17 00:00:00 2001 +From 40b37524ea6056707d4fa2ab232cab7132816a6e Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 2 Dec 2016 14:48:12 +0100 -Subject: [PATCH 165/220] ARM: dts: bcm283x: Add VEC node in bcm283x.dtsi +Subject: [PATCH 164/229] ARM: dts: bcm283x: Add VEC node in bcm283x.dtsi Add the VEC (Video EnCoder) node definition in bcm283x.dtsi. @@ -133929,10 +133836,10 @@ index 41776b97b4b6b1c053d07fd357fac4ba4787ac53..d3cc586661f903e67a840189c0446aa8 compatible = "brcm,bcm2835-pixelvalve2"; reg = <0x7e807000 0x100>; -From b912118cbba61496211f790134093433a9e13487 Mon Sep 17 00:00:00 2001 +From dc1d5236f122dd294d9333680bc4f19cc782f54c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 2 Dec 2016 14:48:13 +0100 -Subject: [PATCH 166/220] ARM: dts: bcm283x: Enable the VEC IP on all +Subject: [PATCH 165/229] ARM: dts: bcm283x: Enable the VEC IP on all RaspberryPi boards Enable the VEC IP on all RaspberryPi boards. @@ -133958,10 +133865,10 @@ index 365648898f3acc4f82dc6cb58e4bbebbe249be94..d4577a51e678cb600b475d3d3395ca4e + status = "okay"; +}; -From 1d878f349a231e3d6adaa38600eb138a8d5ae3f8 Mon Sep 17 00:00:00 2001 +From 74f587581a6e7ca01674619b38699d7588a6c230 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 23 Jan 2017 11:41:54 -0800 -Subject: [PATCH 167/220] BCM270X: Disable VEC unless vc4-kms-v3d is present. +Subject: [PATCH 166/229] BCM270X: Disable VEC unless vc4-kms-v3d is present. Signed-off-by: Eric Anholt --- @@ -134000,10 +133907,10 @@ index f25cd9a3936861920b0d518ff2d773ee467e2f49..a8ef8c9051668a7477dea30aa262568c cma-256 = <0>,"+0-1-2-3-4"; cma-192 = <0>,"-0+1-2-3-4"; -From 404c6a5d9c07a89b3c6c07c1ccac1222c31d27cf Mon Sep 17 00:00:00 2001 +From 7c0bed1aaed0e68b94d0e66610c180b36aaf221a Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 1 Feb 2017 17:09:18 -0800 -Subject: [PATCH 168/220] drm/vc4: Name the primary and cursor planes in fkms. +Subject: [PATCH 167/229] drm/vc4: Name the primary and cursor planes in fkms. This makes debugging nicer, compared to trying to remember what the IDs are. @@ -134027,10 +133934,10 @@ index d18a1dae51a2275846c9826b5bf1ba57ae97b55c..e49ce68b607a7ffc2329e3235362f3bc if (type == DRM_PLANE_TYPE_PRIMARY) { vc4_plane->fbinfo = -From c093ed979e0a69557ebfcbaa1f44bea1e232ba7f Mon Sep 17 00:00:00 2001 +From 6e27de8364a6cef10ca9e0ee71136c8e3e97387b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 1 Feb 2017 17:10:09 -0800 -Subject: [PATCH 169/220] drm/vc4: Add DRM_DEBUG_ATOMIC for the insides of +Subject: [PATCH 168/229] drm/vc4: Add DRM_DEBUG_ATOMIC for the insides of fkms. Trying to debug weston on fkms involved figuring out what calls I was @@ -134100,10 +134007,10 @@ index e49ce68b607a7ffc2329e3235362f3bc21ed5cbb..dbf065677202fbebf8e3a0cffbe880aa RPI_FIRMWARE_SET_CURSOR_STATE, &packet_state, -From 69298e6cd8f0b2e5c63d200dcb4728c151d51c8c Mon Sep 17 00:00:00 2001 +From 9603c092bb73984198d90990c206c4cdb2ca0d27 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 2 Feb 2017 09:42:18 -0800 -Subject: [PATCH 170/220] drm/vc4: Fix sending of page flip completion events +Subject: [PATCH 169/229] drm/vc4: Fix sending of page flip completion events in FKMS mode. In the rewrite of vc4_crtc.c for fkms, I dropped the part of the @@ -134145,10 +134052,10 @@ index dbf065677202fbebf8e3a0cffbe880aa42daef3f..da818a207bfa639b8cea48d94bcf4566 static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) -From ad245132fc0f2ebe6e367f8b3e42a9aa65bd7b4a Mon Sep 17 00:00:00 2001 +From 063fdbf198e68bf5acf896d170351c2021da0114 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 8 Feb 2017 15:00:54 -0800 -Subject: [PATCH 171/220] drm/vc4: Fulfill user BO creation requests from the +Subject: [PATCH 170/229] drm/vc4: Fulfill user BO creation requests from the kernel BO cache. The from_cache flag was actually "the BO is invisible to userspace", @@ -134201,10 +134108,10 @@ index 3f6704cf6608d7be47637c6aa585de087b7f74ee..5ec14f25625dde6fd61e10415092fa25 cma_obj = drm_gem_cma_create(dev, size); -From d38462637c46bfaf7e456a05c950c57a9d74a6bd Mon Sep 17 00:00:00 2001 +From e4042424a6af42f9f2b3450f091c600655aa27a4 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 9 Feb 2017 09:23:34 -0800 -Subject: [PATCH 172/220] drm/vc4: Fix OOPSes from trying to cache a partially +Subject: [PATCH 171/229] drm/vc4: Fix OOPSes from trying to cache a partially constructed BO. If a CMA allocation failed, the partially constructed BO would be @@ -134238,10 +134145,10 @@ index 5ec14f25625dde6fd61e10415092fa25527cc151..fd83a28076564b9ea5cf0f2ba29b884e if (!cache_list) { vc4_bo_destroy(bo); -From e8c7c517a4ec706104026119188765393a6b01c0 Mon Sep 17 00:00:00 2001 +From fe89695150b22bea927c6351ea8e0ed8ee2b780d Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 12 Oct 2015 08:58:08 -0700 -Subject: [PATCH 173/220] drm/vc4: Verify at boot that CMA doesn't cross a +Subject: [PATCH 172/229] drm/vc4: Verify at boot that CMA doesn't cross a 256MB boundary. I've seen lots of users cranking CMA up higher, so throw an error if @@ -134324,10 +134231,10 @@ index c960459eda7e640ea55be1d4ed80c6a9125a8877..b50245282a18bc790da0f901944c2e67 static unsigned long cma_bitmap_aligned_mask(const struct cma *cma, int align_order) -From f13fc1876a6218896b4ffa952dfcd9c6651ac542 Mon Sep 17 00:00:00 2001 +From 8bc34cf4015adcf7f81205122b9541398a596762 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 17 Feb 2017 09:47:11 +0000 -Subject: [PATCH 174/220] BCM270X_DT: Add SMSC ethernet controller to DT +Subject: [PATCH 173/229] BCM270X_DT: Add SMSC ethernet controller to DT With an ethernet node in the DT, a suitable firmware can populate the local-mac-address property, removing the need for a downstream patch @@ -134390,10 +134297,10 @@ index d29ba72de727fe26b5a586e0bd0a41181c68ae04..78101849441679baf3624cf67a0ff7a2 / { model = "Raspberry Pi 3 Model B"; -From 6582c676aee037189fc29847dd11a8558841d77f Mon Sep 17 00:00:00 2001 +From e1666ea2024adaa3745e1ddfd171e2e2f9b871f2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 17 Feb 2017 15:26:13 +0000 -Subject: [PATCH 175/220] brcmfmac: Mute expected startup 'errors' +Subject: [PATCH 174/229] brcmfmac: Mute expected startup 'errors' The brcmfmac WiFi driver always complains about the '00' country code and the firmware version is reported as an error. Modify the driver to @@ -134432,10 +134339,10 @@ index 4051780f64f44a5ce522babe6c371a1beb79a824..b081673abcb4aa72d70d8e0834b608f6 /* locate firmware version number for ethtool */ ptr = strrchr(buf, ' ') + 1; -From f2e36f81e3c8055950ceeab46639b9396386ba37 Mon Sep 17 00:00:00 2001 +From 77a9e71e9aa65d4b9037580f3e2454edb30fccc6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Feb 2017 17:20:08 +0000 -Subject: [PATCH 176/220] clk-bcm2835: Mark used PLLs and dividers CRITICAL +Subject: [PATCH 175/229] clk-bcm2835: Mark used PLLs and dividers CRITICAL The VPU configures and relies on several PLLs and dividers. Mark all enabled dividers and their PLLs as CRITICAL to prevent the kernel from @@ -134463,10 +134370,10 @@ index 136e5d28f9eaeaa10d45382a0f31da9f4adb91ef..4192863778c8009aacfc9a49ee38ad1c divider->data = data; -From 75204fb0be1d1c4d3bfafc95ab4ce6f95be9f21d Mon Sep 17 00:00:00 2001 +From e34c5f1346b7125471e6bb6063f6f48055688738 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Feb 2017 17:20:08 +0000 -Subject: [PATCH 177/220] clk-bcm2835: Add claim-clocks property +Subject: [PATCH 176/229] clk-bcm2835: Add claim-clocks property The claim-clocks property can be used to prevent PLLs and dividers from being marked as critical. It contains a vector of clock IDs, @@ -134601,10 +134508,10 @@ index 4192863778c8009aacfc9a49ee38ad1ca62a01e4..6b245357e4e93c19a839eee92a82f95a sizeof(cprman_parent_names)); of_clk_parent_fill(dev->of_node, cprman->real_parent_names, -From ecd92075685f3d97757db3408223901af0a17475 Mon Sep 17 00:00:00 2001 +From be10b2ef524572ca6161a1d8b1dfaff7e8821166 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Mon, 20 Feb 2017 20:01:16 +0100 -Subject: [PATCH 178/220] dmaengine: bcm2835: Fix cyclic DMA period splitting +Subject: [PATCH 177/229] dmaengine: bcm2835: Fix cyclic DMA period splitting The code responsible for splitting periods into chunks that can be handled by the DMA controller missed to update total_len, @@ -134643,10 +134550,10 @@ index 80d35f760b4a4a51e60c355a84d538bac3892a4d..599c218dc8a73172dd4bd4a058fc8f95 /* calculate the length that remains to reach period_length */ control_block->length = period_len - *total_len; -From f292e0c479d6bc88781a77dc1626b31595bf9ac2 Mon Sep 17 00:00:00 2001 +From 96de3f8a9aedb7ee89be98e8f0f5c002d97f2446 Mon Sep 17 00:00:00 2001 From: Scott Ellis Date: Thu, 23 Feb 2017 11:56:20 -0500 -Subject: [PATCH 179/220] Add ads1015 driver to config +Subject: [PATCH 178/229] Add ads1015 driver to config --- arch/arm/configs/bcm2709_defconfig | 3 ++- @@ -134700,10 +134607,10 @@ index 9a9cd1cdcb2f76d4408568681ec80885293bae48..554fed3a4fbfd1940422b808046c6d2b CONFIG_FB=y CONFIG_FB_BCM2708=y -From 6689e68ab8efe29a3cafbe7398a4f26e55cc223e Mon Sep 17 00:00:00 2001 +From c208ea3209328063c8df1bf1b2046b0d0b72cdd5 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 27 Jan 2017 18:49:30 +0000 -Subject: [PATCH 180/220] config: add slcan kernel module +Subject: [PATCH 179/229] config: add slcan kernel module See: https://github.com/raspberrypi/linux/issues/1819 --- @@ -134736,10 +134643,10 @@ index 554fed3a4fbfd1940422b808046c6d2b1f508394..99888182259b280790a7506b248a8130 CONFIG_IRDA=m CONFIG_IRLAN=m -From 5476da49a0513f2782a6ccae1fedf2cc38201d80 Mon Sep 17 00:00:00 2001 +From 00d0301a093b7f79d4809fcc113b9839b5029e97 Mon Sep 17 00:00:00 2001 From: Miquel Date: Fri, 24 Feb 2017 20:51:06 +0100 -Subject: [PATCH 181/220] sound: Support for Dion Audio LOCO-V2 DAC-AMP HAT +Subject: [PATCH 180/229] sound: Support for Dion Audio LOCO-V2 DAC-AMP HAT Signed-off-by: Miquel Blauw --- @@ -135003,10 +134910,10 @@ index 0000000000000000000000000000000000000000..a009c49477972a9832175d86f201b035 +MODULE_DESCRIPTION("ASoC Driver for DionAudio LOCO-V2"); +MODULE_LICENSE("GPL v2"); -From 910ace3d10614d67b74540f5975740a6711b6709 Mon Sep 17 00:00:00 2001 +From 84f9e798ff7f63f2de7d5ce97b5fc9cc642cc995 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Sun, 26 Feb 2017 01:13:02 +0000 -Subject: [PATCH 182/220] SQUASH: Add LOCO-V2 overlay from last commit +Subject: [PATCH 181/229] SQUASH: Add LOCO-V2 overlay from last commit --- .../dts/overlays/dionaudio-loco-v2-overlay.dts | 49 ++++++++++++++++++++++ @@ -135069,10 +134976,10 @@ index 0000000000000000000000000000000000000000..a1af93de30119734e8d14cbd454589d3 + }; +}; -From aaa9491e3b03a685d8b336411ef75ecc29452ff6 Mon Sep 17 00:00:00 2001 +From 5532e4a2891e94cad11a2c9f5238e073ad98b2fd Mon Sep 17 00:00:00 2001 From: Fe-Pi Date: Wed, 1 Mar 2017 04:42:43 -0700 -Subject: [PATCH 183/220] Add support for Fe-Pi audio sound card. (#1867) +Subject: [PATCH 182/229] Add support for Fe-Pi audio sound card. (#1867) Fe-Pi Audio Sound Card is based on NXP SGTL5000 codec. Mechanical specification of the board is the same the Raspberry Pi Zero. @@ -135421,10 +135328,10 @@ index 0000000000000000000000000000000000000000..015b56fd73cc36be5b5eecd17548fd03 +MODULE_DESCRIPTION("ASoC Driver for Fe-Pi Audio"); +MODULE_LICENSE("GPL v2"); -From 07dc8de314890c5718b766ac02f5c889fc362abd Mon Sep 17 00:00:00 2001 +From 14a2bffb1f12e8f4fea74332aa3286c53d620502 Mon Sep 17 00:00:00 2001 From: Scott Ellis Date: Wed, 1 Mar 2017 07:22:24 -0500 -Subject: [PATCH 184/220] Add overlay for ads1115 ADCs (#1864) +Subject: [PATCH 183/229] Add overlay for ads1115 ADCs (#1864) --- arch/arm/boot/dts/overlays/Makefile | 1 + @@ -135588,10 +135495,10 @@ index 0000000000000000000000000000000000000000..7c16a1af3172d14e1a976b1776b9f167 + }; +}; -From 045d35e72184011869bdfccf740c5b0625d7917f Mon Sep 17 00:00:00 2001 +From cb3b58cca69fe52de364c33109e50471d5b13dda Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 1 Mar 2017 16:06:53 +0000 -Subject: [PATCH 185/220] clk-bcm2835: Correct the prediv logic +Subject: [PATCH 184/229] clk-bcm2835: Correct the prediv logic If a clock has the prediv flag set, both the integer and fractional parts must be scaled when calculating the resulting frequency. @@ -135618,10 +135525,10 @@ index 6b245357e4e93c19a839eee92a82f95aec996e4e..8ea29fbc8dc451b9cff502bc1a918ae6 return bcm2835_pll_rate_from_divisors(parent_rate, ndiv, fdiv, pdiv); } -From 9833d81be5ae7b8301cd846efdacddb9954a8331 Mon Sep 17 00:00:00 2001 +From 4d154d37fead1447c7221ca0d4b0b8dbcfc297cf Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 1 Mar 2017 16:07:39 +0000 -Subject: [PATCH 186/220] amba_pl011: Round input clock up +Subject: [PATCH 185/229] amba_pl011: Round input clock up The UART clock is initialised to be as close to the requested frequency as possible without exceeding it. Now that there is a @@ -135707,10 +135614,10 @@ index 5a11ff833e1fd112ba04df3a427cd94bf6793ec5..003a5b0c30295dbbcb94a28d0c64d124 /* unregisters the driver also if no more ports are left */ static void pl011_unregister_port(struct uart_amba_port *uap) -From 0f1383deac133e518b7c1e84e2f6cb6b0918b9f5 Mon Sep 17 00:00:00 2001 +From 30382da357246ac32d4d445c495b95bd57146e56 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 13 Feb 2017 11:10:50 +0000 -Subject: [PATCH 187/220] BCM2835-V4L2: Ensure H264 header bytes get a sensible +Subject: [PATCH 186/229] BCM2835-V4L2: Ensure H264 header bytes get a sensible timestamp H264 header come off VC with 0 timestamps, which means they get a @@ -135799,10 +135706,10 @@ index e6aeb7e7e381de65d6c6586205069a4c5cd33274..7f8a68916a67001bc9241bce2928519a struct vchiq_mmal_port *port; /* port being used for capture */ /* camera port being used for capture */ -From 568318dde09bbbaeb5c6ffe813d9885ca9cd0b1c Mon Sep 17 00:00:00 2001 +From e37b420844cab750b4b0ca1ed5eeb0aab65577c4 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 13 Feb 2017 13:11:41 +0000 -Subject: [PATCH 188/220] BCM2835-V4L2: Correctly denote key frames in encoded +Subject: [PATCH 187/229] BCM2835-V4L2: Correctly denote key frames in encoded data Forward MMAL key frame flags to the V4L2 buffers. @@ -135827,10 +135734,10 @@ index e69731320f4e59249933bc21843913deab4a1209..6bdec0806126044cf7146d53326e4da5 "Buffer has ts %llu", dev->capture.last_timestamp); -From 51ecb04f5852f54bdeeef4485f729f9e070ecc82 Mon Sep 17 00:00:00 2001 +From d798550b4fa22e6947eac75b9f626bd2d07ffc9d Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 20 Feb 2017 17:01:21 +0000 -Subject: [PATCH 189/220] bcm2835-gpio-exp: Driver for GPIO expander via +Subject: [PATCH 188/229] bcm2835-gpio-exp: Driver for GPIO expander via mailbox service Pi3 and Compute Module 3 have a GPIO expander that the @@ -136248,10 +136155,10 @@ index 2859db09e25bb945251e85edb39bc43430857168..56b3f0fe1ea3d22fcf207e6df90b640e /* Dispmanx TAGS */ RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001, -From 843d61b8346e9a2c49c2d4cbdef680175b503b2e Mon Sep 17 00:00:00 2001 +From 398c0b7dd08ce4698e8fa058a212293113d57741 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 24 May 2016 16:30:05 +0100 -Subject: [PATCH 190/220] BCM270X_DT: Add bcm2708-rpi-0-w.dts +Subject: [PATCH 189/229] BCM270X_DT: Add bcm2708-rpi-0-w.dts Add DT support for the Pi Zero W. N.B. It will not be loaded automatically without a corresponding change to the firmware. @@ -136479,10 +136386,10 @@ index 0000000000000000000000000000000000000000..db0f99ddf2f46e83827d56e21c4846dd + }; +}; -From d005b22695f92ac66e1a7405c98e6acff08e5e92 Mon Sep 17 00:00:00 2001 +From 67e2a753965b663de7de65220d47e3439b9bece3 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 6 Mar 2017 09:06:18 +0000 -Subject: [PATCH 191/220] clk-bcm2835: Read max core clock from firmware +Subject: [PATCH 190/229] clk-bcm2835: Read max core clock from firmware The VPU is responsible for managing the core clock, usually under direction from the bcm2835-cpufreq driver but not via the clk-bcm2835 @@ -136610,10 +136517,10 @@ index 8ea29fbc8dc451b9cff502bc1a918ae65fb1b306..fe3298b54cdfb96bd90fb4f39e13921d for (i = 0; !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks", -From e7f6dfb5b3ce261660cf5e67b1cfa9d984e9d5b7 Mon Sep 17 00:00:00 2001 +From 2d3684c4b3333b0f1270beac6343860f4f807862 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 7 Mar 2017 19:48:23 +0000 -Subject: [PATCH 192/220] config: Add CONFIG_CRYPTO_LZ4 +Subject: [PATCH 191/229] config: Add CONFIG_CRYPTO_LZ4 Enabling this options allows LZ4 memory compression. @@ -136650,10 +136557,10 @@ index 2c124bbfa343bf2c160250d055e1509678a80850..1748fcb84bdc3853ffccba93a41cd2dc # CONFIG_CRYPTO_HW is not set CONFIG_ARM_CRYPTO=y -From d60a07e2fc0abda4aafc9e029b125389d8a0f714 Mon Sep 17 00:00:00 2001 +From 9aa1e9e321bc7a9a0529baad81fb43f30a3dad0d Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Thu, 23 Feb 2017 17:54:31 -0800 -Subject: [PATCH 193/220] drm/vc4: Don't wait for vblank when updating the +Subject: [PATCH 192/229] drm/vc4: Don't wait for vblank when updating the cursor Commonly used desktop environments such as xfce4 and gnome @@ -136710,10 +136617,10 @@ index 881bf489478b01b34e9e4df6013fe608c42215ee..14d69bb4967dedcd3bbc475639a8c27e * expected change from the drm_mode_cursor_universal() * helper. -From dba84088915d1ecfb2d7fd4cc5f02d662c46b23f Mon Sep 17 00:00:00 2001 +From a9ba13528c4bf6f3c21f1c7ca98e7ff6cef48f02 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 6 Mar 2017 12:17:16 -0800 -Subject: [PATCH 194/220] panel-raspberrypi-touchscreen: Round up clk rate to +Subject: [PATCH 193/229] panel-raspberrypi-touchscreen: Round up clk rate to fix DSI panel. Commit 488f9bc8e3def93e0baef53cee2026c2cb0d8956 slightly increased the @@ -136748,10 +136655,10 @@ index 1a536fe4d040f5fafe324baee110a6225dd0be08..7f315f04b109621ca7f3861fdd8acf95 .hsync_start = HACT + HFP, .hsync_end = HACT + HFP + HSW, -From 90afefde8ad6549e102301761f790041182ec27b Mon Sep 17 00:00:00 2001 +From b69080b69bb9ed31405bb0ece685f908e29b8530 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Wed, 8 Mar 2017 20:04:13 +1100 -Subject: [PATCH 195/220] Add support for the AudioInjector.net Octo sound card +Subject: [PATCH 194/229] Add support for the AudioInjector.net Octo sound card --- arch/arm/boot/dts/overlays/Makefile | 1 + @@ -137222,10 +137129,10 @@ index 0000000000000000000000000000000000000000..9effea725798640887755dfa688da453 +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:audioinjector-octo-soundcard"); -From 8ffb640336c5094288c8c7876b76d9b0089bfaf0 Mon Sep 17 00:00:00 2001 +From d0cff46e369056e6b3c44cf5404e59c86d9e6014 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Wed, 8 Mar 2017 21:13:24 +1100 -Subject: [PATCH 196/220] ASoC: bcm2835_i2s.c: relax the ch2 register setting +Subject: [PATCH 195/229] ASoC: bcm2835_i2s.c: relax the ch2 register setting for 8 channels This patch allows ch2 registers to be set for 8 channels of audio. @@ -137254,10 +137161,10 @@ index 6ba20498202ed36906b52096893a88867a79269f..c8dd065aea8414b47aa2ea4fc04168b5 format |= BCM2835_I2S_CH1(BCM2835_I2S_CHPOS(ch1pos)); format |= BCM2835_I2S_CH2(BCM2835_I2S_CHPOS(ch2pos)); -From bb30772aa51c75e61e9e8187f22a3b46392da30a Mon Sep 17 00:00:00 2001 +From e1d1177a35fba39eb6bdcedba11870a64debf3f6 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 10 Mar 2017 14:43:15 +0000 -Subject: [PATCH 197/220] bcm2835-v4l2: Fix buffer overflow problem +Subject: [PATCH 196/229] bcm2835-v4l2: Fix buffer overflow problem https://github.com/raspberrypi/linux/issues/1447 port_parameter_get() failed to account for the header @@ -137293,10 +137200,10 @@ index 781322542d5a8295f3d7d5a3eaaf0cac29930c30..e4b243b33f58913f3d2952c97d2a2e3f * but report true size of parameter */ -From 27701c533dd68188ce983afa3a355db0d2418199 Mon Sep 17 00:00:00 2001 +From 59af39c8490b563fd9fe26b2881f20a7b90b8aa1 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Fri, 10 Feb 2017 17:57:08 -0800 -Subject: [PATCH 198/220] build/arm64: Add rules for .dtbo files for dts +Subject: [PATCH 197/229] build/arm64: Add rules for .dtbo files for dts overlays We now create overlays as .dtbo files. @@ -137321,10 +137228,10 @@ index 3635b8662724569d3338ebb620d603c644fe38b7..822fefeb1cd0aa2dc8398f885cf28e9b dtbs: prepare scripts -From 1419ba1eecbca87bb837bf10ea8f44ca48b9ee53 Mon Sep 17 00:00:00 2001 +From 44e344eece74eb129ebbe21352553d51e582bea3 Mon Sep 17 00:00:00 2001 From: John Greb Date: Wed, 8 Mar 2017 15:12:29 +0000 -Subject: [PATCH 199/220] Match dwc2 device-tree fifo sizes to the hardware +Subject: [PATCH 198/229] Match dwc2 device-tree fifo sizes to the hardware values. Since commit aa381a7259c3f53727bcaa8c5f9359e940a0e3fd was reverted with 3fa9538539ac737096c81f3315a14670b1609092 the g-tx-fifo-size array in the device-tree needs to match the preset values in the bcm2835. @@ -137355,10 +137262,10 @@ index 527abc9f0ddf71f4dc7d58336d87684c931cc2f3..265a16bab008453edba198cf2366c423 }; }; -From ec646318b5d58d3ce5037528470468100f157c33 Mon Sep 17 00:00:00 2001 +From c26228c832d36ee5578898c898005c4a8dd06e33 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 5 Mar 2017 11:46:41 +0000 -Subject: [PATCH 200/220] config: Add RTL8XXXU wifi module +Subject: [PATCH 199/229] config: Add RTL8XXXU wifi module --- arch/arm/configs/bcm2709_defconfig | 1 + @@ -137390,10 +137297,10 @@ index bf52db66afb2aa18d6f6f9fb9b64dcbd97e24521..4bc0f8b52b7f39f99d650cb9c4cdfdba CONFIG_ZD1211RW=m CONFIG_MAC80211_HWSIM=m -From d21416717bbf4df7a53962e72978c5307579f5f8 Mon Sep 17 00:00:00 2001 +From 6012d3a1b078d1a0a56088193ed58b6462792993 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 7 Mar 2017 12:18:20 +0000 -Subject: [PATCH 201/220] BCM270X_DT: Invert Pi3 power LED to match fw change +Subject: [PATCH 200/229] BCM270X_DT: Invert Pi3 power LED to match fw change Firmware expgpio driver reworked due to complaint over hotplug detect. @@ -137419,10 +137326,10 @@ index 173103aaca503833b5e29530ed94e14c7cab0444..b21d2866d204adc533b46d581028f290 }; -From e95d839d186dbffe488aefc930cadd28f18002a0 Mon Sep 17 00:00:00 2001 +From 94dc319b9e2a3da3acba4c0216906cb183c945e0 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Mar 2017 09:10:05 +0000 -Subject: [PATCH 202/220] BCM270X_DT: Add lm75 to i2c-sensor overlay +Subject: [PATCH 201/229] BCM270X_DT: Add lm75 to i2c-sensor overlay See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=177236 @@ -137485,10 +137392,10 @@ index 31bda8da4cb6a56bfe493a81b918900995fb0589..606b2d5012abf2e85712be631c42ea40 }; }; -From 0ce5e90cdcdcb7f11e8efeb969762c15562ca5dd Mon Sep 17 00:00:00 2001 +From c8e0b6101fd2ecdeb76720a474785cf5c06d8254 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 14 Mar 2017 14:23:06 +0000 -Subject: [PATCH 203/220] bcm2835-gpio-exp: Copy/paste error adding base twice +Subject: [PATCH 202/229] bcm2835-gpio-exp: Copy/paste error adding base twice brcmexp_gpio_set was adding gpio->gc.base to the offset twice, so passing an invalid number to the mailbox service. @@ -137514,10 +137421,10 @@ index 681a91492d4c33bdfd42416e069218e8611cc4d9..d68adafaee4ad406f45f4ff0d6b7c1ad set.state = val; /* Output state */ -From 11ba49a5dcf9f5f5619e8c05f32306b430886e76 Mon Sep 17 00:00:00 2001 +From b7701d7e7f150854ad3ef0f1554022464557ea3e Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 15 Mar 2017 11:12:40 +0000 -Subject: [PATCH 204/220] bcm2835-camera: Correct port_parameter_get return +Subject: [PATCH 203/229] bcm2835-camera: Correct port_parameter_get return value The API for port_parameter_get() requires that the @@ -137575,10 +137482,10 @@ index e4b243b33f58913f3d2952c97d2a2e3fbbbd0ae8..ec2853ba9d4b1b0cd6e07a495a424e15 pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__, ret, port->component->handle, port->handle, parameter_id); -From b5c1fb2410ca88175189123afdbdc8e805f5af1c Mon Sep 17 00:00:00 2001 +From 42fba0cbde85f4fc2ece0f1491b4d3aa3f3489ea Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 17 Mar 2017 12:24:41 +0000 -Subject: [PATCH 205/220] config: Make spidev a loadable module +Subject: [PATCH 204/229] config: Make spidev a loadable module spidev isn't required early in the boot process, and not all users need it (spi_bcm2835 is a module), so make it a loadable module. @@ -137634,10 +137541,10 @@ index 4bc0f8b52b7f39f99d650cb9c4cdfdba6fac59dd..8d64ce4465f6f276b2d58ed1e2e45fb0 CONFIG_SND_SIMPLE_CARD=m CONFIG_SOUND_PRIME=m -From 1911ea02d3d4dd1563bb56307cc5aa952446e43a Mon Sep 17 00:00:00 2001 +From 57b8961f4b7371e51b9d75ca8e820d9b80b8b2d2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 23 Mar 2017 10:06:56 +0000 -Subject: [PATCH 206/220] ASoC: Add prompt for ICS43432 codec +Subject: [PATCH 205/229] ASoC: Add prompt for ICS43432 codec Without a prompt string, a config setting can't be included in a defconfig. Give CONFIG_SND_SOC_ICS43432 a prompt so that Pi soundcards @@ -137662,10 +137569,10 @@ index 9824cdd04b0c11c45b8cedd0187a0eba8f1dc2d4..c0b88d43df0de283c58ed6158680bc7e config SND_SOC_INNO_RK3036 tristate "Inno codec driver for RK3036 SoC" -From b15a4e9186b8f5ae89c254cc034450d8c87b2f25 Mon Sep 17 00:00:00 2001 +From c0ba2c5008f51ac66a7e9fddc41add243a94a867 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 23 Mar 2017 16:34:46 +0000 -Subject: [PATCH 207/220] bcm2835-aux: Add aux interrupt controller +Subject: [PATCH 206/229] bcm2835-aux: Add aux interrupt controller The AUX block has a shared interrupt line with a register indicating which devices have active IRQs. Expose this as a nested interrupt @@ -137829,10 +137736,10 @@ index bd750cf2238d61489811e7d7bd3b5f9950ed53c8..41e0702fae4692221980b0d02aed1ba6 BCM2835_AUX_CLOCK_COUNT, GFP_KERNEL); if (!onecell) -From 276b4a46685a5195d0c49d13900a342683ced706 Mon Sep 17 00:00:00 2001 +From 7d8f0b2bebc31971821a4c1d63f5fef7441fc197 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 23 Mar 2017 17:08:44 +0000 -Subject: [PATCH 208/220] BCM270X_DT: Enable AUX interrupt controller in DT +Subject: [PATCH 207/229] BCM270X_DT: Enable AUX interrupt controller in DT See: https://github.com/raspberrypi/linux/issues/1484 https://github.com/raspberrypi/linux/issues/1573 @@ -137885,10 +137792,10 @@ index d3cc586661f903e67a840189c0446aa80e16a44e..348c71bbc913644c04bab43fcb95abe9 #address-cells = <1>; #size-cells = <0>; -From f0d1516f1a0cd098dba3baa2884a3f8e197d0f82 Mon Sep 17 00:00:00 2001 +From 8899614857b2e3417d669450ac21e3010cdbb7dc Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Mon, 27 Mar 2017 22:26:49 +1100 -Subject: [PATCH 209/220] Audioinjector addons dts : add reset and regulators +Subject: [PATCH 208/229] Audioinjector addons dts : add reset and regulators for the Octo product. This patch adds a reset GPIO for the AudioInjector.net octo sound card. @@ -137955,10 +137862,10 @@ index dbf2f3cacc2e6bf5b7116fbadd97f2781580a79c..a36fa85a61f7eaab35ca481ed1dac621 codec = <&cs42448>; status = "okay"; -From 66cf592b878498381efad6ab14116e38b5d12462 Mon Sep 17 00:00:00 2001 +From 9b039f5cb19f7b5718c5c21d1dcc1d494c0a63bd Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Mon, 27 Mar 2017 22:27:26 +1100 -Subject: [PATCH 210/220] AudioInjector Octo : Consolidate sample rates and add +Subject: [PATCH 209/229] AudioInjector Octo : Consolidate sample rates and add a codec reset. This patch consolidates the sample rates which the audioinjector.net octo @@ -138098,10 +138005,10 @@ index 9effea725798640887755dfa688da45338718afc..1198c36c4563b8673e5d386d1dfa92d4 dai->cpu_dai_name = NULL; dai->cpu_of_node = i2s_node; -From cd90a81a5b257615b2d602ac794008c1f74d22c1 Mon Sep 17 00:00:00 2001 +From 6f3d9b375793a4e9fac48da15467a06aa795fdc5 Mon Sep 17 00:00:00 2001 From: Peter Malkin Date: Mon, 27 Mar 2017 16:38:21 -0700 -Subject: [PATCH 211/220] Driver support for Google voiceHAT soundcard. +Subject: [PATCH 210/229] Driver support for Google voiceHAT soundcard. --- arch/arm/boot/dts/overlays/Makefile | 1 + @@ -138606,10 +138513,10 @@ index 0000000000000000000000000000000000000000..225854b8e5298b3c3018f59a49404354 +MODULE_DESCRIPTION("ASoC Driver for Google voiceHAT SoundCard"); +MODULE_LICENSE("GPL v2"); -From bbc44acd1168da5c90ef281ee5c1c432254f94d9 Mon Sep 17 00:00:00 2001 +From bd26dc547a4151ff27c27a6e6d355acea71416d9 Mon Sep 17 00:00:00 2001 From: Raashid Muhammed Date: Mon, 27 Mar 2017 12:35:00 +0530 -Subject: [PATCH 212/220] Add support for Allo Piano DAC 2.1 plus add-on board +Subject: [PATCH 211/229] Add support for Allo Piano DAC 2.1 plus add-on board for Raspberry Pi. The Piano DAC 2.1 has support for 4 channels with subwoofer. @@ -139237,10 +139144,10 @@ index 0000000000000000000000000000000000000000..f66f42abadbd5f9d3fe000676e8297ed +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Piano DAC Plus"); +MODULE_LICENSE("GPL v2"); -From da12961a62933749b87d6e6ae1903e75d8501c3d Mon Sep 17 00:00:00 2001 +From 86ad0d5d97902245ab40a9465f9e1038efe77c04 Mon Sep 17 00:00:00 2001 From: BabuSubashChandar Date: Tue, 28 Mar 2017 20:04:42 +0530 -Subject: [PATCH 213/220] Add support for Allo Boss DAC add-on board for +Subject: [PATCH 212/229] Add support for Allo Boss DAC add-on board for Raspberry Pi. (#1924) Signed-off-by: Baswaraj K @@ -139970,10 +139877,10 @@ index 0000000000000000000000000000000000000000..c080e31065d99ab309ab3bdf41a44adf +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Boss DAC"); +MODULE_LICENSE("GPL v2"); -From 8023e80635527d669f70ff9a6fcdaca2ad458818 Mon Sep 17 00:00:00 2001 +From 1d6787a5b15ae9978b894198fa3c9f6e40c5fa90 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 28 Mar 2017 14:22:20 +0100 -Subject: [PATCH 214/220] BCM270X_DT: Allow multiple instances of w1-gpio +Subject: [PATCH 213/229] BCM270X_DT: Allow multiple instances of w1-gpio overlays Upcoming firmware will modify the address portion of node names when @@ -140038,10 +139945,10 @@ index 66a98f6c9601f51483f27803995bec772bb3350e..ef8bfbcabdb31231075d5c281df3b38b <&w1_pins>,"brcm,pins:4"; pullup = <&w1>,"rpi,parasitic-power:0"; -From 0a07667778a5b2c5e556c15199c5be30a3887c60 Mon Sep 17 00:00:00 2001 +From 6b723831ce7f33feb5725649eeb4983b47bf448b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 28 Mar 2017 17:41:30 +0100 -Subject: [PATCH 215/220] leds-gpio: Remove stray assignment to brightness_set +Subject: [PATCH 214/229] leds-gpio: Remove stray assignment to brightness_set The brightness_set method is intended for use cases that must not block, and can only be used if the GPIO provider can never sleep. @@ -140067,10 +139974,10 @@ index 6a27a693034825de2897bb7b338b60cc10c9e59f..a6b352cb003ff5e6c87cf6d37d6502b6 if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP) { state = gpiod_get_value_cansleep(led_dat->gpiod); -From 1e448652dbc96e7d9ab2016536eac218f59af577 Mon Sep 17 00:00:00 2001 +From 611806fca5b173d987ade185fe31dc5f29525971 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Thu, 30 Mar 2017 11:43:57 +1100 -Subject: [PATCH 216/220] Audioinjector Octo : add extra sample rates, fix rst +Subject: [PATCH 215/229] Audioinjector Octo : add extra sample rates, fix rst and use bcm270x regs This patch adds new sample rates to the Audioinjector Octo sound card. The @@ -140232,10 +140139,10 @@ index 1198c36c4563b8673e5d386d1dfa92d43689e297..dcf403ab37639ba79e38278d7e4b1ade if (i2s_node && codec_node) { dai->cpu_dai_name = NULL; -From 51ab3c74bc14237229c4bdf6286969e3809bb53f Mon Sep 17 00:00:00 2001 +From 92635064cc8dd80ab824296a3b6800e29ca14f91 Mon Sep 17 00:00:00 2001 From: BabuSubashChandar C Date: Thu, 30 Mar 2017 20:17:27 +0530 -Subject: [PATCH 217/220] Add support for new clock rate and mute gpios. +Subject: [PATCH 216/229] Add support for new clock rate and mute gpios. Signed-off-by: Baswaraj K Reviewed-by: Deepak @@ -140888,10 +140795,10 @@ index c080e31065d99ab309ab3bdf41a44adfdd8f8039..203ab76c7045b081578e23bda1099dd1 } -From 30994f05cc060da85ff6546f5b4e4e7cef63c1b1 Mon Sep 17 00:00:00 2001 +From cfc68e1ea68c3fcf639133e3e2480b7e2888410f Mon Sep 17 00:00:00 2001 From: BabuSubashChandar Date: Sat, 1 Apr 2017 00:46:52 +0530 -Subject: [PATCH 218/220] Add clock changes and mute gpios (#1938) +Subject: [PATCH 217/229] Add clock changes and mute gpios (#1938) Also improve code style and adhere to ALSA coding conventions. @@ -141584,10 +141491,10 @@ index f66f42abadbd5f9d3fe000676e8297ed91630e47..56e43f98846b41e487b3089813f7edc3 } -From 9f610278ad940a5265ea3417913eb2f887391008 Mon Sep 17 00:00:00 2001 +From 04f11f2061e4ba6f51b54036c47c007e3eac9736 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Tue, 4 Apr 2017 19:20:59 +1000 -Subject: [PATCH 219/220] Audioinjector : make the octo and pi sound cards have +Subject: [PATCH 218/229] Audioinjector : make the octo and pi sound cards have different driver names This patch gives the audioinjector octo and pi soundcards different driver @@ -141624,10 +141531,10 @@ index ef54e0f07ea03f59e9957b5d98f3e7fdc998e469..491906bbf446826e55dd843f28e4860f .of_match_table = audioinjector_pi_soundcard_of_match, }, -From 107d4574cc3765ad8530e6d9cce70b560b0563fd Mon Sep 17 00:00:00 2001 +From 47250496327a7a8222723df2e3b6c585a17a0258 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Tue, 4 Apr 2017 19:23:04 +1000 -Subject: [PATCH 220/220] Audioinjector octo : Make the playback and capture +Subject: [PATCH 219/229] Audioinjector octo : Make the playback and capture symmetric This patch ensures that the sample rate and channel count of the audioinjector @@ -141649,3 +141556,17746 @@ index 49115c8e20ce1a2ba5a99feb8983a1cafb052ca2..5e79f4eff93a21ed3495c77a90f73525 }, }; + +From 6a9230f331e56feff0c3b16cbd83e9a448150169 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Tue, 7 Mar 2017 14:51:03 -0800 +Subject: [PATCH 220/229] drm/vc4: Allow using more than 256MB of CMA memory. + +Until now, we've had to limit Raspberry Pi to 256MB of CMA memory to +keep from triggering the hardware addressing bug between of the tile +binner of the tile alloc memory (where the top 4 bits come from the +tile state data array's address). + +To work around that and allow more memory to be reserved for graphics, +allocate a single BO to store tile state data arrays and tile +alloc/overflow memory while the GPU is active, and make sure that that +one BO doesn't happen to cross a 256MB boundary. With that in place, +we can allocate textures and shaders anywhere in system memory (still +contiguous, of course). + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_drv.h | 28 +++++-- + drivers/gpu/drm/vc4/vc4_gem.c | 12 ++- + drivers/gpu/drm/vc4/vc4_irq.c | 61 +++++++-------- + drivers/gpu/drm/vc4/vc4_render_cl.c | 3 +- + drivers/gpu/drm/vc4/vc4_v3d.c | 150 ++++++++++++++++++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_validate.c | 54 ++++++------- + 6 files changed, 234 insertions(+), 74 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index 44a8e6fda2b576fed63d93ef34e076cebf90d64c..9e50bc25b2be71079d52a861c25f3fe7c4db0830 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -97,12 +97,23 @@ struct vc4_dev { + */ + struct list_head seqno_cb_list; + +- /* The binner overflow memory that's currently set up in +- * BPOA/BPOS registers. When overflow occurs and a new one is +- * allocated, the previous one will be moved to +- * vc4->current_exec's free list. ++ /* The memory used for storing binner tile alloc, tile state, ++ * and overflow memory allocations. This is freed when V3D ++ * powers down. + */ +- struct vc4_bo *overflow_mem; ++ struct vc4_bo *bin_bo; ++ ++ /* Size of blocks allocated within bin_bo. */ ++ uint32_t bin_alloc_size; ++ ++ /* Bitmask of the bin_alloc_size chunks in bin_bo that are ++ * used. ++ */ ++ uint32_t bin_alloc_used; ++ ++ /* Bitmask of the current bin_alloc used for overflow memory. */ ++ uint32_t bin_alloc_overflow; ++ + struct work_struct overflow_mem_work; + + int power_refcount; +@@ -295,8 +306,12 @@ struct vc4_exec_info { + bool found_increment_semaphore_packet; + bool found_flush; + uint8_t bin_tiles_x, bin_tiles_y; +- struct drm_gem_cma_object *tile_bo; ++ /* Physical address of the start of the tile alloc array ++ * (where each tile's binned CL will start) ++ */ + uint32_t tile_alloc_offset; ++ /* Bitmask of which binner slots are freed when this job completes. */ ++ uint32_t bin_slots; + + /** + * Computed addresses pointing into exec_bo where we start the +@@ -531,6 +546,7 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, + extern struct platform_driver vc4_v3d_driver; + int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused); + int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused); ++int vc4_v3d_get_bin_slot(struct vc4_dev *vc4); + + /* vc4_validate.c */ + int +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index ab3016982466c3ca35ba479050ee107d26eb50ac..a5029ab49068bdbd69411cccbdb6f5111f387e38 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -695,6 +695,7 @@ static void + vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) + { + struct vc4_dev *vc4 = to_vc4_dev(dev); ++ unsigned long irqflags; + unsigned i; + + if (exec->bo) { +@@ -710,6 +711,11 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) + drm_gem_object_unreference_unlocked(&bo->base.base); + } + ++ /* Free up the allocation of any bin slots we used. */ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ vc4->bin_alloc_used &= ~exec->bin_slots; ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ + mutex_lock(&vc4->power_lock); + if (--vc4->power_refcount == 0) { + pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); +@@ -951,9 +957,9 @@ vc4_gem_destroy(struct drm_device *dev) + /* V3D should already have disabled its interrupt and cleared + * the overflow allocation registers. Now free the object. + */ +- if (vc4->overflow_mem) { +- drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base); +- vc4->overflow_mem = NULL; ++ if (vc4->bin_bo) { ++ drm_gem_object_unreference_unlocked(&vc4->bin_bo->base.base); ++ vc4->bin_bo = NULL; + } + + if (vc4->hang_state) +diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c +index 094bc6a475c1773923dfe8225cba9886fc9e5026..c43ee1e646f6dd68fe19dacdbcf9322da13c4280 100644 +--- a/drivers/gpu/drm/vc4/vc4_irq.c ++++ b/drivers/gpu/drm/vc4/vc4_irq.c +@@ -58,50 +58,45 @@ vc4_overflow_mem_work(struct work_struct *work) + { + struct vc4_dev *vc4 = + container_of(work, struct vc4_dev, overflow_mem_work); +- struct drm_device *dev = vc4->dev; +- struct vc4_bo *bo; ++ struct vc4_bo *bo = vc4->bin_bo; ++ int bin_bo_slot; ++ struct vc4_exec_info *exec; ++ unsigned long irqflags; + +- bo = vc4_bo_create(dev, 256 * 1024, true); +- if (IS_ERR(bo)) { ++ bin_bo_slot = vc4_v3d_get_bin_slot(vc4); ++ if (bin_bo_slot < 0) { + DRM_ERROR("Couldn't allocate binner overflow mem\n"); + return; + } + +- /* If there's a job executing currently, then our previous +- * overflow allocation is getting used in that job and we need +- * to queue it to be released when the job is done. But if no +- * job is executing at all, then we can free the old overflow +- * object direcctly. +- * +- * No lock necessary for this pointer since we're the only +- * ones that update the pointer, and our workqueue won't +- * reenter. +- */ +- if (vc4->overflow_mem) { +- struct vc4_exec_info *current_exec; +- unsigned long irqflags; +- +- spin_lock_irqsave(&vc4->job_lock, irqflags); +- current_exec = vc4_first_bin_job(vc4); +- if (!current_exec) +- current_exec = vc4_last_render_job(vc4); +- if (current_exec) { +- vc4->overflow_mem->seqno = current_exec->seqno; +- list_add_tail(&vc4->overflow_mem->unref_head, +- ¤t_exec->unref_list); +- vc4->overflow_mem = NULL; ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ ++ if (vc4->bin_alloc_overflow) { ++ /* If we had overflow memory allocated previously, ++ * then that chunk will free when the current bin job ++ * is done. If we don't have a bin job running, then ++ * the chunk will be done whenever the list of render ++ * jobs has drained. ++ */ ++ exec = vc4_first_bin_job(vc4); ++ if (!exec) ++ exec = vc4_last_render_job(vc4); ++ if (exec) { ++ exec->bin_slots |= vc4->bin_alloc_overflow; ++ } else { ++ /* There's nothing queued in the hardware, so ++ * the old slot is free immediately. ++ */ ++ vc4->bin_alloc_used &= ~vc4->bin_alloc_overflow; + } +- spin_unlock_irqrestore(&vc4->job_lock, irqflags); + } ++ vc4->bin_alloc_overflow = BIT(bin_bo_slot); + +- if (vc4->overflow_mem) +- drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base); +- vc4->overflow_mem = bo; +- +- V3D_WRITE(V3D_BPOA, bo->base.paddr); ++ V3D_WRITE(V3D_BPOA, bo->base.paddr + bin_bo_slot * vc4->bin_alloc_size); + V3D_WRITE(V3D_BPOS, bo->base.base.size); + V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM); + V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM); ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); + } + + static void +diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c +index 5cdd003605f57c99faf31832e3f3dd38a75b7402..6face6aa0890b59bc91d3740fa063a5c46f7cc21 100644 +--- a/drivers/gpu/drm/vc4/vc4_render_cl.c ++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c +@@ -178,8 +178,7 @@ static void emit_tile(struct vc4_exec_info *exec, + + if (has_bin) { + rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST); +- rcl_u32(setup, (exec->tile_bo->paddr + +- exec->tile_alloc_offset + ++ rcl_u32(setup, (exec->tile_alloc_offset + + (y * exec->bin_tiles_x + x) * 32)); + } + +diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c +index 1d9e5a6edd22c29ce8b2990c9c35627aa1af2bd8..da79d8511dfb4f631fd3ad4c3680b312f44bd454 100644 +--- a/drivers/gpu/drm/vc4/vc4_v3d.c ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -159,6 +159,144 @@ static void vc4_v3d_init_hw(struct drm_device *dev) + V3D_WRITE(V3D_VPMBASE, 0); + } + ++int vc4_v3d_get_bin_slot(struct vc4_dev *vc4) ++{ ++ struct drm_device *dev = vc4->dev; ++ unsigned long irqflags; ++ int slot; ++ uint64_t seqno = 0; ++ struct vc4_exec_info *exec; ++ ++try_again: ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ slot = ffs(~vc4->bin_alloc_used); ++ if (slot != 0) { ++ /* Switch from ffs() bit index to a 0-based index. */ ++ slot--; ++ vc4->bin_alloc_used |= BIT(slot); ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ return slot; ++ } ++ ++ /* Couldn't find an open slot. Wait for render to complete ++ * and try again. ++ */ ++ exec = vc4_last_render_job(vc4); ++ if (exec) ++ seqno = exec->seqno; ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ ++ if (seqno) { ++ int ret = vc4_wait_for_seqno(dev, seqno, ~0ull, true); ++ ++ if (ret == 0) ++ goto try_again; ++ ++ return ret; ++ } ++ ++ return -ENOMEM; ++} ++ ++/** ++ * vc4_allocate_bin_bo() - allocates the memory that will be used for ++ * tile binning. ++ * ++ * The binner has a limitation that the addresses in the tile state ++ * buffer that point into the tile alloc buffer or binner overflow ++ * memory only have 28 bits (256MB), and the top 4 on the bus for ++ * tile alloc references end up coming from the tile state buffer's ++ * address. ++ * ++ * To work around this, we allocate a single large buffer while V3D is ++ * in use, make sure that it has the top 4 bits constant across its ++ * entire extent, and then put the tile state, tile alloc, and binner ++ * overflow memory inside that buffer. ++ * ++ * This creates a limitation where we may not be able to execute a job ++ * if it doesn't fit within the buffer that we allocated up front. ++ * However, it turns out that 16MB is "enough for anybody", and ++ * real-world applications run into allocation failures from the ++ * overall CMA pool before they make scenes complicated enough to run ++ * out of bin space. ++ */ ++int ++vc4_allocate_bin_bo(struct drm_device *drm) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_v3d *v3d = vc4->v3d; ++ uint32_t size = 16 * 1024 * 1024; ++ int ret = 0; ++ struct list_head list; ++ ++ /* We may need to try allocating more than once to get a BO ++ * that doesn't cross 256MB. Track the ones we've allocated ++ * that failed so far, so that we can free them when we've got ++ * one that succeeded (if we freed them right away, our next ++ * allocation would probably be the same chunk of memory). ++ */ ++ INIT_LIST_HEAD(&list); ++ ++ while (true) { ++ struct vc4_bo *bo = vc4_bo_create(drm, size, true); ++ ++ if (IS_ERR(bo)) { ++ ret = PTR_ERR(bo); ++ ++ dev_err(&v3d->pdev->dev, ++ "Failed to allocate memory for tile binning: " ++ "%d. You may need to enable CMA or give it " ++ "more memory.", ++ ret); ++ break; ++ } ++ ++ /* Check if this BO won't trigger the addressing bug. */ ++ if ((bo->base.paddr & 0xf0000000) == ++ ((bo->base.paddr + bo->base.base.size - 1) & 0xf0000000)) { ++ vc4->bin_bo = bo; ++ ++ /* Set up for allocating 512KB chunks of ++ * binner memory. The biggest allocation we ++ * need to do is for the initial tile alloc + ++ * tile state buffer. We can render to a ++ * maximum of ((2048*2048) / (32*32) = 4096 ++ * tiles in a frame (until we do floating ++ * point rendering, at which point it would be ++ * 8192). Tile state is 48b/tile (rounded to ++ * a page), and tile alloc is 32b/tile ++ * (rounded to a page), plus a page of extra, ++ * for a total of 320kb for our worst-case. ++ * We choose 512kb so that it divides evenly ++ * into our 16MB, and the rest of the 512kb ++ * will be used as storage for the overflow ++ * from the initial 32b CL per bin. ++ */ ++ vc4->bin_alloc_size = 512 * 1024; ++ vc4->bin_alloc_used = 0; ++ vc4->bin_alloc_overflow = 0; ++ WARN_ON_ONCE(sizeof(vc4->bin_alloc_used) * 8 != ++ bo->base.base.size / vc4->bin_alloc_size); ++ ++ break; ++ } ++ ++ /* Put it on the list to free later, and try again. */ ++ list_add(&bo->unref_head, &list); ++ } ++ ++ /* Free all the BOs we allocated but didn't choose. */ ++ while (!list_empty(&list)) { ++ struct vc4_bo *bo = list_last_entry(&list, ++ struct vc4_bo, unref_head); ++ ++ list_del(&bo->unref_head); ++ drm_gem_object_unreference_unlocked(&bo->base.base); ++ } ++ ++ return ret; ++} ++ + #ifdef CONFIG_PM + static int vc4_v3d_runtime_suspend(struct device *dev) + { +@@ -167,6 +305,9 @@ static int vc4_v3d_runtime_suspend(struct device *dev) + + vc4_irq_uninstall(vc4->dev); + ++ drm_gem_object_unreference_unlocked(&vc4->bin_bo->base.base); ++ vc4->bin_bo = NULL; ++ + return 0; + } + +@@ -174,6 +315,11 @@ static int vc4_v3d_runtime_resume(struct device *dev) + { + struct vc4_v3d *v3d = dev_get_drvdata(dev); + struct vc4_dev *vc4 = v3d->vc4; ++ int ret; ++ ++ ret = vc4_allocate_bin_bo(vc4->dev); ++ if (ret) ++ return ret; + + vc4_v3d_init_hw(vc4->dev); + vc4_irq_postinstall(vc4->dev); +@@ -226,6 +372,10 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) + return -EINVAL; + } + ++ ret = vc4_allocate_bin_bo(drm); ++ if (ret) ++ return ret; ++ + /* Reset the binner overflow address/size at setup, to be sure + * we don't reuse an old one. + */ +diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c +index 9fd171c361c23b52a4d507919ec7e26fd1e87aac..59d808e2a6cc6f3173b1309cc4f491098886cf36 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate.c ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -340,10 +340,11 @@ static int + validate_tile_binning_config(VALIDATE_ARGS) + { + struct drm_device *dev = exec->exec_bo->base.dev; +- struct vc4_bo *tile_bo; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); + uint8_t flags; +- uint32_t tile_state_size, tile_alloc_size; +- uint32_t tile_count; ++ uint32_t tile_state_size; ++ uint32_t tile_count, bin_addr; ++ int bin_slot; + + if (exec->found_tile_binning_mode_config_packet) { + DRM_ERROR("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n"); +@@ -369,13 +370,28 @@ validate_tile_binning_config(VALIDATE_ARGS) + return -EINVAL; + } + ++ bin_slot = vc4_v3d_get_bin_slot(vc4); ++ if (bin_slot < 0) { ++ if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS) { ++ DRM_ERROR("Failed to allocate binner memory: %d\n", ++ bin_slot); ++ } ++ return bin_slot; ++ } ++ ++ /* The slot we allocated will only be used by this job, and is ++ * free when the job completes rendering. ++ */ ++ exec->bin_slots |= BIT(bin_slot); ++ bin_addr = vc4->bin_bo->base.paddr + bin_slot * vc4->bin_alloc_size; ++ + /* The tile state data array is 48 bytes per tile, and we put it at + * the start of a BO containing both it and the tile alloc. + */ + tile_state_size = 48 * tile_count; + + /* Since the tile alloc array will follow us, align. */ +- exec->tile_alloc_offset = roundup(tile_state_size, 4096); ++ exec->tile_alloc_offset = bin_addr + roundup(tile_state_size, 4096); + + *(uint8_t *)(validated + 14) = + ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK | +@@ -386,35 +402,13 @@ validate_tile_binning_config(VALIDATE_ARGS) + VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128, + VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE)); + +- /* Initial block size. */ +- tile_alloc_size = 32 * tile_count; +- +- /* +- * The initial allocation gets rounded to the next 256 bytes before +- * the hardware starts fulfilling further allocations. +- */ +- tile_alloc_size = roundup(tile_alloc_size, 256); +- +- /* Add space for the extra allocations. This is what gets used first, +- * before overflow memory. It must have at least 4096 bytes, but we +- * want to avoid overflow memory usage if possible. +- */ +- tile_alloc_size += 1024 * 1024; +- +- tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size, +- true); +- exec->tile_bo = &tile_bo->base; +- if (IS_ERR(exec->tile_bo)) +- return PTR_ERR(exec->tile_bo); +- list_add_tail(&tile_bo->unref_head, &exec->unref_list); +- + /* tile alloc address. */ +- *(uint32_t *)(validated + 0) = (exec->tile_bo->paddr + +- exec->tile_alloc_offset); ++ *(uint32_t *)(validated + 0) = exec->tile_alloc_offset; + /* tile alloc size. */ +- *(uint32_t *)(validated + 4) = tile_alloc_size; ++ *(uint32_t *)(validated + 4) = (bin_addr + vc4->bin_alloc_size - ++ exec->tile_alloc_offset); + /* tile state address. */ +- *(uint32_t *)(validated + 8) = exec->tile_bo->paddr; ++ *(uint32_t *)(validated + 8) = bin_addr; + + return 0; + } + +From c9198914d5f724e33f1b4e15a38acbd5439a50c5 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 30 Mar 2017 10:23:27 -0700 +Subject: [PATCH 221/229] Revert "drm/vc4: Verify at boot that CMA doesn't + cross a 256MB boundary." + +This reverts commit 016c804fa69381bd23a1a13cba08a3c4557fcdff. The +restriction was lifted by the previous commit. +--- + drivers/base/dma-contiguous.c | 1 - + drivers/gpu/drm/vc4/vc4_v3d.c | 18 ------------------ + mm/cma.c | 2 -- + 3 files changed, 21 deletions(-) + +diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c +index 60f5c2591ccdb0202461458eab4035cfba731b8b..e167a1e1bccb062efef2595fcd5299301a97df80 100644 +--- a/drivers/base/dma-contiguous.c ++++ b/drivers/base/dma-contiguous.c +@@ -35,7 +35,6 @@ + #endif + + struct cma *dma_contiguous_default_area; +-EXPORT_SYMBOL(dma_contiguous_default_area); + + /* + * Default global CMA area size can be defined in kernel's .config. +diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c +index da79d8511dfb4f631fd3ad4c3680b312f44bd454..882ec06225f1d5caca71bdb5c69664188192c2e2 100644 +--- a/drivers/gpu/drm/vc4/vc4_v3d.c ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -16,10 +16,7 @@ + * this program. If not, see . + */ + +-#include "linux/init.h" +-#include "linux/cma.h" + #include "linux/component.h" +-#include "linux/dma-contiguous.h" + #include "linux/pm_runtime.h" + #include "vc4_drv.h" + #include "vc4_regs.h" +@@ -334,23 +331,8 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_v3d *v3d = NULL; +- struct cma *cma; + int ret; + +- cma = dev_get_cma_area(dev); +- if (!cma) +- return -EINVAL; +- +- if ((cma_get_base(cma) & 0xf0000000) != +- ((cma_get_base(cma) + cma_get_size(cma) - 1) & 0xf0000000)) { +- DRM_ERROR("V3D requires that the CMA area (0x%08lx - 0x%08lx) " +- "not span a 256MB boundary, or memory corruption " +- "would happen.\n", +- (long)cma_get_base(cma), +- cma_get_base(cma) + cma_get_size(cma)); +- return -EINVAL; +- } +- + v3d = devm_kzalloc(&pdev->dev, sizeof(*v3d), GFP_KERNEL); + if (!v3d) + return -ENOMEM; +diff --git a/mm/cma.c b/mm/cma.c +index b50245282a18bc790da0f901944c2e670ffac2d2..c960459eda7e640ea55be1d4ed80c6a9125a8877 100644 +--- a/mm/cma.c ++++ b/mm/cma.c +@@ -47,13 +47,11 @@ phys_addr_t cma_get_base(const struct cma *cma) + { + return PFN_PHYS(cma->base_pfn); + } +-EXPORT_SYMBOL(cma_get_base); + + unsigned long cma_get_size(const struct cma *cma) + { + return cma->count << PAGE_SHIFT; + } +-EXPORT_SYMBOL(cma_get_size); + + static unsigned long cma_bitmap_aligned_mask(const struct cma *cma, + int align_order) + +From c22d272c517370c8e6f5a8a4850bca6219a1e34b Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 27 Feb 2017 12:28:02 -0800 +Subject: [PATCH 222/229] drm/vc4: Add HDMI audio support + +The HDMI encoder IP embeds all needed blocks to output audio, with a +custom DAI called MAI moving audio between the two parts of the HDMI +core. This driver now exposes a sound card to let users stream audio +to their display. + +Using the hdmi-codec driver has been considered here, but MAI meant +having to significantly rework hdmi-codec, and it would have left +little shared code with the I2S mode anyway. + +The encoder requires that the audio be SPDIF-formatted frames only, +which alsalib will format-convert for us. + +This patch is the combined work of Eric Anholt (initial register setup +with a separate dmaengine driver and using simple-audio-card) and +Boris Brezillon (moving it all into HDMI, massive debug to get it +actually working), and which Eric has the permission to release. + +v2: Drop "-audio" from sound card name, since that's already implied + (suggestion by Boris) + +Signed-off-by: Eric Anholt +Acked-by: Boris Brezillon +Link: http://patchwork.freedesktop.org/patch/msgid/20170227202803.12855-2-eric@anholt.net +--- + drivers/gpu/drm/vc4/Kconfig | 4 + + drivers/gpu/drm/vc4/vc4_hdmi.c | 494 ++++++++++++++++++++++++++++++++++++++++- + drivers/gpu/drm/vc4/vc4_regs.h | 107 ++++++++- + 3 files changed, 603 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig +index e1517d07cb7d22776ca164a5d2d9b87e55a5563a..973b4203c0b264115b7cd9d4a433b449bd0ec3b3 100644 +--- a/drivers/gpu/drm/vc4/Kconfig ++++ b/drivers/gpu/drm/vc4/Kconfig +@@ -2,11 +2,15 @@ config DRM_VC4 + tristate "Broadcom VC4 Graphics" + depends on ARCH_BCM2835 || COMPILE_TEST + depends on DRM ++ depends on SND && SND_SOC + depends on COMMON_CLK + select DRM_KMS_HELPER + select DRM_KMS_CMA_HELPER + select DRM_GEM_CMA_HELPER + select DRM_PANEL ++ select SND_PCM ++ select SND_PCM_ELD ++ select SND_SOC_GENERIC_DMAENGINE_PCM + select DRM_MIPI_DSI + help + Choose this option if you have a system that has a Broadcom +diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c +index c4cb2e26de32f06db0abf3fd94b3117c3292eed5..8db1016cad929438f30ea44c6974dcb340b74596 100644 +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -31,11 +31,27 @@ + #include "linux/clk.h" + #include "linux/component.h" + #include "linux/i2c.h" ++#include "linux/of_address.h" + #include "linux/of_gpio.h" + #include "linux/of_platform.h" ++#include "linux/rational.h" ++#include "sound/dmaengine_pcm.h" ++#include "sound/pcm_drm_eld.h" ++#include "sound/pcm_params.h" ++#include "sound/soc.h" + #include "vc4_drv.h" + #include "vc4_regs.h" + ++/* HDMI audio information */ ++struct vc4_hdmi_audio { ++ struct snd_soc_card card; ++ struct snd_soc_dai_link link; ++ int samplerate; ++ int channels; ++ struct snd_dmaengine_dai_dma_data dma_data; ++ struct snd_pcm_substream *substream; ++}; ++ + /* General HDMI hardware state. */ + struct vc4_hdmi { + struct platform_device *pdev; +@@ -43,6 +59,8 @@ struct vc4_hdmi { + struct drm_encoder *encoder; + struct drm_connector *connector; + ++ struct vc4_hdmi_audio audio; ++ + struct i2c_adapter *ddc; + void __iomem *hdmicore_regs; + void __iomem *hd_regs; +@@ -98,6 +116,10 @@ static const struct { + HDMI_REG(VC4_HDMI_SW_RESET_CONTROL), + HDMI_REG(VC4_HDMI_HOTPLUG_INT), + HDMI_REG(VC4_HDMI_HOTPLUG), ++ HDMI_REG(VC4_HDMI_MAI_CHANNEL_MAP), ++ HDMI_REG(VC4_HDMI_MAI_CONFIG), ++ HDMI_REG(VC4_HDMI_MAI_FORMAT), ++ HDMI_REG(VC4_HDMI_AUDIO_PACKET_CONFIG), + HDMI_REG(VC4_HDMI_RAM_PACKET_CONFIG), + HDMI_REG(VC4_HDMI_HORZA), + HDMI_REG(VC4_HDMI_HORZB), +@@ -108,6 +130,7 @@ static const struct { + HDMI_REG(VC4_HDMI_VERTB0), + HDMI_REG(VC4_HDMI_VERTB1), + HDMI_REG(VC4_HDMI_TX_PHY_RESET_CTL), ++ HDMI_REG(VC4_HDMI_TX_PHY_CTL0), + }; + + static const struct { +@@ -116,6 +139,9 @@ static const struct { + } hd_regs[] = { + HDMI_REG(VC4_HD_M_CTL), + HDMI_REG(VC4_HD_MAI_CTL), ++ HDMI_REG(VC4_HD_MAI_THR), ++ HDMI_REG(VC4_HD_MAI_FMT), ++ HDMI_REG(VC4_HD_MAI_SMP), + HDMI_REG(VC4_HD_VID_CTL), + HDMI_REG(VC4_HD_CSC_CTL), + HDMI_REG(VC4_HD_FRAME_COUNT), +@@ -215,6 +241,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) + + drm_mode_connector_update_edid_property(connector, edid); + ret = drm_add_edid_modes(connector, edid); ++ drm_edid_to_eld(connector, edid); + + return ret; + } +@@ -300,7 +327,7 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + u32 packet_id = frame->any.type - 0x80; +- u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id; ++ u32 packet_reg = VC4_HDMI_RAM_PACKET(packet_id); + uint8_t buffer[VC4_HDMI_PACKET_STRIDE]; + ssize_t len, i; + int ret; +@@ -385,6 +412,24 @@ static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder) + vc4_hdmi_write_infoframe(encoder, &frame); + } + ++static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder) ++{ ++ struct drm_device *drm = encoder->dev; ++ struct vc4_dev *vc4 = drm->dev_private; ++ struct vc4_hdmi *hdmi = vc4->hdmi; ++ union hdmi_infoframe frame; ++ int ret; ++ ++ ret = hdmi_audio_infoframe_init(&frame.audio); ++ ++ frame.audio.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; ++ frame.audio.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; ++ frame.audio.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; ++ frame.audio.channels = hdmi->audio.channels; ++ ++ vc4_hdmi_write_infoframe(encoder, &frame); ++} ++ + static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) + { + vc4_hdmi_set_avi_infoframe(encoder); +@@ -591,6 +636,447 @@ static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { + .enable = vc4_hdmi_encoder_enable, + }; + ++/* HDMI audio codec callbacks */ ++static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *hdmi) ++{ ++ struct drm_device *drm = hdmi->encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ u32 hsm_clock = clk_get_rate(hdmi->hsm_clock); ++ unsigned long n, m; ++ ++ rational_best_approximation(hsm_clock, hdmi->audio.samplerate, ++ VC4_HD_MAI_SMP_N_MASK >> ++ VC4_HD_MAI_SMP_N_SHIFT, ++ (VC4_HD_MAI_SMP_M_MASK >> ++ VC4_HD_MAI_SMP_M_SHIFT) + 1, ++ &n, &m); ++ ++ HD_WRITE(VC4_HD_MAI_SMP, ++ VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) | ++ VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M)); ++} ++ ++static void vc4_hdmi_set_n_cts(struct vc4_hdmi *hdmi) ++{ ++ struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_crtc *crtc = encoder->crtc; ++ struct drm_device *drm = encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ const struct drm_display_mode *mode = &crtc->state->adjusted_mode; ++ u32 samplerate = hdmi->audio.samplerate; ++ u32 n, cts; ++ u64 tmp; ++ ++ n = 128 * samplerate / 1000; ++ tmp = (u64)(mode->clock * 1000) * n; ++ do_div(tmp, 128 * samplerate); ++ cts = tmp; ++ ++ HDMI_WRITE(VC4_HDMI_CRP_CFG, ++ VC4_HDMI_CRP_CFG_EXTERNAL_CTS_EN | ++ VC4_SET_FIELD(n, VC4_HDMI_CRP_CFG_N)); ++ ++ /* ++ * We could get slightly more accurate clocks in some cases by ++ * providing a CTS_1 value. The two CTS values are alternated ++ * between based on the period fields ++ */ ++ HDMI_WRITE(VC4_HDMI_CTS_0, cts); ++ HDMI_WRITE(VC4_HDMI_CTS_1, cts); ++} ++ ++static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai) ++{ ++ struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai); ++ ++ return snd_soc_card_get_drvdata(card); ++} ++ ++static int vc4_hdmi_audio_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct vc4_hdmi *hdmi = dai_to_hdmi(dai); ++ struct drm_encoder *encoder = hdmi->encoder; ++ struct vc4_dev *vc4 = to_vc4_dev(encoder->dev); ++ int ret; ++ ++ if (hdmi->audio.substream && hdmi->audio.substream != substream) ++ return -EINVAL; ++ ++ hdmi->audio.substream = substream; ++ ++ /* ++ * If the HDMI encoder hasn't probed, or the encoder is ++ * currently in DVI mode, treat the codec dai as missing. ++ */ ++ if (!encoder->crtc || !(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ++ VC4_HDMI_RAM_PACKET_ENABLE)) ++ return -ENODEV; ++ ++ ret = snd_pcm_hw_constraint_eld(substream->runtime, ++ hdmi->connector->eld); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int vc4_hdmi_audio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++{ ++ return 0; ++} ++ ++static void vc4_hdmi_audio_reset(struct vc4_hdmi *hdmi) ++{ ++ struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_device *drm = encoder->dev; ++ struct device *dev = &hdmi->pdev->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ int ret; ++ ++ ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO); ++ if (ret) ++ dev_err(dev, "Failed to stop audio infoframe: %d\n", ret); ++ ++ HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_RESET); ++ HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_ERRORF); ++ HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_FLUSH); ++} ++ ++static void vc4_hdmi_audio_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct vc4_hdmi *hdmi = dai_to_hdmi(dai); ++ ++ if (substream != hdmi->audio.substream) ++ return; ++ ++ vc4_hdmi_audio_reset(hdmi); ++ ++ hdmi->audio.substream = NULL; ++} ++ ++/* HDMI audio codec callbacks */ ++static int vc4_hdmi_audio_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct vc4_hdmi *hdmi = dai_to_hdmi(dai); ++ struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_device *drm = encoder->dev; ++ struct device *dev = &hdmi->pdev->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ u32 audio_packet_config, channel_mask; ++ u32 channel_map, i; ++ ++ if (substream != hdmi->audio.substream) ++ return -EINVAL; ++ ++ dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__, ++ params_rate(params), params_width(params), ++ params_channels(params)); ++ ++ hdmi->audio.channels = params_channels(params); ++ hdmi->audio.samplerate = params_rate(params); ++ ++ HD_WRITE(VC4_HD_MAI_CTL, ++ VC4_HD_MAI_CTL_RESET | ++ VC4_HD_MAI_CTL_FLUSH | ++ VC4_HD_MAI_CTL_DLATE | ++ VC4_HD_MAI_CTL_ERRORE | ++ VC4_HD_MAI_CTL_ERRORF); ++ ++ vc4_hdmi_audio_set_mai_clock(hdmi); ++ ++ audio_packet_config = ++ VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT | ++ VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS | ++ VC4_SET_FIELD(0xf, VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER); ++ ++ channel_mask = GENMASK(hdmi->audio.channels - 1, 0); ++ audio_packet_config |= VC4_SET_FIELD(channel_mask, ++ VC4_HDMI_AUDIO_PACKET_CEA_MASK); ++ ++ /* Set the MAI threshold. This logic mimics the firmware's. */ ++ if (hdmi->audio.samplerate > 96000) { ++ HD_WRITE(VC4_HD_MAI_THR, ++ VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQHIGH) | ++ VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW)); ++ } else if (hdmi->audio.samplerate > 48000) { ++ HD_WRITE(VC4_HD_MAI_THR, ++ VC4_SET_FIELD(0x14, VC4_HD_MAI_THR_DREQHIGH) | ++ VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW)); ++ } else { ++ HD_WRITE(VC4_HD_MAI_THR, ++ VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) | ++ VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) | ++ VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQHIGH) | ++ VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQLOW)); ++ } ++ ++ HDMI_WRITE(VC4_HDMI_MAI_CONFIG, ++ VC4_HDMI_MAI_CONFIG_BIT_REVERSE | ++ VC4_SET_FIELD(channel_mask, VC4_HDMI_MAI_CHANNEL_MASK)); ++ ++ channel_map = 0; ++ for (i = 0; i < 8; i++) { ++ if (channel_mask & BIT(i)) ++ channel_map |= i << (3 * i); ++ } ++ ++ HDMI_WRITE(VC4_HDMI_MAI_CHANNEL_MAP, channel_map); ++ HDMI_WRITE(VC4_HDMI_AUDIO_PACKET_CONFIG, audio_packet_config); ++ vc4_hdmi_set_n_cts(hdmi); ++ ++ return 0; ++} ++ ++static int vc4_hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, ++ struct snd_soc_dai *dai) ++{ ++ struct vc4_hdmi *hdmi = dai_to_hdmi(dai); ++ struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_device *drm = encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ vc4_hdmi_set_audio_infoframe(encoder); ++ HDMI_WRITE(VC4_HDMI_TX_PHY_CTL0, ++ HDMI_READ(VC4_HDMI_TX_PHY_CTL0) & ++ ~VC4_HDMI_TX_PHY_RNG_PWRDN); ++ HD_WRITE(VC4_HD_MAI_CTL, ++ VC4_SET_FIELD(hdmi->audio.channels, ++ VC4_HD_MAI_CTL_CHNUM) | ++ VC4_HD_MAI_CTL_ENABLE); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ HD_WRITE(VC4_HD_MAI_CTL, ++ VC4_HD_MAI_CTL_DLATE | ++ VC4_HD_MAI_CTL_ERRORE | ++ VC4_HD_MAI_CTL_ERRORF); ++ HDMI_WRITE(VC4_HDMI_TX_PHY_CTL0, ++ HDMI_READ(VC4_HDMI_TX_PHY_CTL0) | ++ VC4_HDMI_TX_PHY_RNG_PWRDN); ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static inline struct vc4_hdmi * ++snd_component_to_hdmi(struct snd_soc_component *component) ++{ ++ struct snd_soc_card *card = snd_soc_component_get_drvdata(component); ++ ++ return snd_soc_card_get_drvdata(card); ++} ++ ++static int vc4_hdmi_audio_eld_ctl_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); ++ struct vc4_hdmi *hdmi = snd_component_to_hdmi(component); ++ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; ++ uinfo->count = sizeof(hdmi->connector->eld); ++ ++ return 0; ++} ++ ++static int vc4_hdmi_audio_eld_ctl_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); ++ struct vc4_hdmi *hdmi = snd_component_to_hdmi(component); ++ ++ memcpy(ucontrol->value.bytes.data, hdmi->connector->eld, ++ sizeof(hdmi->connector->eld)); ++ ++ return 0; ++} ++ ++static const struct snd_kcontrol_new vc4_hdmi_audio_controls[] = { ++ { ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | ++ SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .iface = SNDRV_CTL_ELEM_IFACE_PCM, ++ .name = "ELD", ++ .info = vc4_hdmi_audio_eld_ctl_info, ++ .get = vc4_hdmi_audio_eld_ctl_get, ++ }, ++}; ++ ++static const struct snd_soc_dapm_widget vc4_hdmi_audio_widgets[] = { ++ SND_SOC_DAPM_OUTPUT("TX"), ++}; ++ ++static const struct snd_soc_dapm_route vc4_hdmi_audio_routes[] = { ++ { "TX", NULL, "Playback" }, ++}; ++ ++static const struct snd_soc_codec_driver vc4_hdmi_audio_codec_drv = { ++ .component_driver = { ++ .controls = vc4_hdmi_audio_controls, ++ .num_controls = ARRAY_SIZE(vc4_hdmi_audio_controls), ++ .dapm_widgets = vc4_hdmi_audio_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(vc4_hdmi_audio_widgets), ++ .dapm_routes = vc4_hdmi_audio_routes, ++ .num_dapm_routes = ARRAY_SIZE(vc4_hdmi_audio_routes), ++ }, ++}; ++ ++static const struct snd_soc_dai_ops vc4_hdmi_audio_dai_ops = { ++ .startup = vc4_hdmi_audio_startup, ++ .shutdown = vc4_hdmi_audio_shutdown, ++ .hw_params = vc4_hdmi_audio_hw_params, ++ .set_fmt = vc4_hdmi_audio_set_fmt, ++ .trigger = vc4_hdmi_audio_trigger, ++}; ++ ++static struct snd_soc_dai_driver vc4_hdmi_audio_codec_dai_drv = { ++ .name = "vc4-hdmi-hifi", ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 2, ++ .channels_max = 8, ++ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | ++ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | ++ SNDRV_PCM_RATE_192000, ++ .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, ++ }, ++}; ++ ++static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = { ++ .name = "vc4-hdmi-cpu-dai-component", ++}; ++ ++static int vc4_hdmi_audio_cpu_dai_probe(struct snd_soc_dai *dai) ++{ ++ struct vc4_hdmi *hdmi = dai_to_hdmi(dai); ++ ++ snd_soc_dai_init_dma_data(dai, &hdmi->audio.dma_data, NULL); ++ ++ return 0; ++} ++ ++static struct snd_soc_dai_driver vc4_hdmi_audio_cpu_dai_drv = { ++ .name = "vc4-hdmi-cpu-dai", ++ .probe = vc4_hdmi_audio_cpu_dai_probe, ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 1, ++ .channels_max = 8, ++ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | ++ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | ++ SNDRV_PCM_RATE_192000, ++ .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, ++ }, ++ .ops = &vc4_hdmi_audio_dai_ops, ++}; ++ ++static const struct snd_dmaengine_pcm_config pcm_conf = { ++ .chan_names[SNDRV_PCM_STREAM_PLAYBACK] = "audio-rx", ++ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, ++}; ++ ++static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi) ++{ ++ struct snd_soc_dai_link *dai_link = &hdmi->audio.link; ++ struct snd_soc_card *card = &hdmi->audio.card; ++ struct device *dev = &hdmi->pdev->dev; ++ const __be32 *addr; ++ int ret; ++ ++ if (!of_find_property(dev->of_node, "dmas", NULL)) { ++ dev_warn(dev, ++ "'dmas' DT property is missing, no HDMI audio\n"); ++ return 0; ++ } ++ ++ /* ++ * Get the physical address of VC4_HD_MAI_DATA. We need to retrieve ++ * the bus address specified in the DT, because the physical address ++ * (the one returned by platform_get_resource()) is not appropriate ++ * for DMA transfers. ++ * This VC/MMU should probably be exposed to avoid this kind of hacks. ++ */ ++ addr = of_get_address(dev->of_node, 1, NULL, NULL); ++ hdmi->audio.dma_data.addr = be32_to_cpup(addr) + VC4_HD_MAI_DATA; ++ hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ hdmi->audio.dma_data.maxburst = 2; ++ ++ ret = devm_snd_dmaengine_pcm_register(dev, &pcm_conf, 0); ++ if (ret) { ++ dev_err(dev, "Could not register PCM component: %d\n", ret); ++ return ret; ++ } ++ ++ ret = devm_snd_soc_register_component(dev, &vc4_hdmi_audio_cpu_dai_comp, ++ &vc4_hdmi_audio_cpu_dai_drv, 1); ++ if (ret) { ++ dev_err(dev, "Could not register CPU DAI: %d\n", ret); ++ return ret; ++ } ++ ++ /* register codec and codec dai */ ++ ret = snd_soc_register_codec(dev, &vc4_hdmi_audio_codec_drv, ++ &vc4_hdmi_audio_codec_dai_drv, 1); ++ if (ret) { ++ dev_err(dev, "Could not register codec: %d\n", ret); ++ return ret; ++ } ++ ++ dai_link->name = "MAI"; ++ dai_link->stream_name = "MAI PCM"; ++ dai_link->codec_dai_name = vc4_hdmi_audio_codec_dai_drv.name; ++ dai_link->cpu_dai_name = dev_name(dev); ++ dai_link->codec_name = dev_name(dev); ++ dai_link->platform_name = dev_name(dev); ++ ++ card->dai_link = dai_link; ++ card->num_links = 1; ++ card->name = "vc4-hdmi"; ++ card->dev = dev; ++ ++ /* ++ * Be careful, snd_soc_register_card() calls dev_set_drvdata() and ++ * stores a pointer to the snd card object in dev->driver_data. This ++ * means we cannot use it for something else. The hdmi back-pointer is ++ * now stored in card->drvdata and should be retrieved with ++ * snd_soc_card_get_drvdata() if needed. ++ */ ++ snd_soc_card_set_drvdata(card, hdmi); ++ ret = devm_snd_soc_register_card(dev, card); ++ if (ret) { ++ dev_err(dev, "Could not register sound card: %d\n", ret); ++ goto unregister_codec; ++ } ++ ++ return 0; ++ ++unregister_codec: ++ snd_soc_unregister_codec(dev); ++ ++ return ret; ++} ++ ++static void vc4_hdmi_audio_cleanup(struct vc4_hdmi *hdmi) ++{ ++ struct device *dev = &hdmi->pdev->dev; ++ ++ /* ++ * If drvdata is not set this means the audio card was not ++ * registered, just skip codec unregistration in this case. ++ */ ++ if (dev_get_drvdata(dev)) ++ snd_soc_unregister_codec(dev); ++} ++ + static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) + { + struct platform_device *pdev = to_platform_device(dev); +@@ -722,6 +1208,10 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) + goto err_destroy_encoder; + } + ++ ret = vc4_hdmi_audio_init(hdmi); ++ if (ret) ++ goto err_destroy_encoder; ++ + return 0; + + err_destroy_encoder: +@@ -743,6 +1233,8 @@ static void vc4_hdmi_unbind(struct device *dev, struct device *master, + struct vc4_dev *vc4 = drm->dev_private; + struct vc4_hdmi *hdmi = vc4->hdmi; + ++ vc4_hdmi_audio_cleanup(hdmi); ++ + vc4_hdmi_connector_destroy(hdmi->connector); + vc4_hdmi_encoder_destroy(hdmi->encoder); + +diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h +index 385405a2df05eb3dd86d4f687aa8205331bec3cc..932093936178674173a84002b33e07e9a37fdfe9 100644 +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -446,11 +446,62 @@ + #define VC4_HDMI_HOTPLUG 0x00c + # define VC4_HDMI_HOTPLUG_CONNECTED BIT(0) + ++/* 3 bits per field, where each field maps from that corresponding MAI ++ * bus channel to the given HDMI channel. ++ */ ++#define VC4_HDMI_MAI_CHANNEL_MAP 0x090 ++ ++#define VC4_HDMI_MAI_CONFIG 0x094 ++# define VC4_HDMI_MAI_CONFIG_FORMAT_REVERSE BIT(27) ++# define VC4_HDMI_MAI_CONFIG_BIT_REVERSE BIT(26) ++# define VC4_HDMI_MAI_CHANNEL_MASK_MASK VC4_MASK(15, 0) ++# define VC4_HDMI_MAI_CHANNEL_MASK_SHIFT 0 ++ ++/* Last received format word on the MAI bus. */ ++#define VC4_HDMI_MAI_FORMAT 0x098 ++ ++#define VC4_HDMI_AUDIO_PACKET_CONFIG 0x09c ++# define VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT BIT(29) ++# define VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS BIT(24) ++# define VC4_HDMI_AUDIO_PACKET_FORCE_SAMPLE_PRESENT BIT(19) ++# define VC4_HDMI_AUDIO_PACKET_FORCE_B_FRAME BIT(18) ++# define VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER_MASK VC4_MASK(13, 10) ++# define VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER_SHIFT 10 ++/* If set, then multichannel, otherwise 2 channel. */ ++# define VC4_HDMI_AUDIO_PACKET_AUDIO_LAYOUT BIT(9) ++/* If set, then AUDIO_LAYOUT overrides audio_cea_mask */ ++# define VC4_HDMI_AUDIO_PACKET_FORCE_AUDIO_LAYOUT BIT(8) ++# define VC4_HDMI_AUDIO_PACKET_CEA_MASK_MASK VC4_MASK(7, 0) ++# define VC4_HDMI_AUDIO_PACKET_CEA_MASK_SHIFT 0 ++ + #define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 + # define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) + + #define VC4_HDMI_RAM_PACKET_STATUS 0x0a4 + ++#define VC4_HDMI_CRP_CFG 0x0a8 ++/* When set, the CTS_PERIOD counts based on MAI bus sync pulse instead ++ * of pixel clock. ++ */ ++# define VC4_HDMI_CRP_USE_MAI_BUS_SYNC_FOR_CTS BIT(26) ++/* When set, no CRP packets will be sent. */ ++# define VC4_HDMI_CRP_CFG_DISABLE BIT(25) ++/* If set, generates CTS values based on N, audio clock, and video ++ * clock. N must be divisible by 128. ++ */ ++# define VC4_HDMI_CRP_CFG_EXTERNAL_CTS_EN BIT(24) ++# define VC4_HDMI_CRP_CFG_N_MASK VC4_MASK(19, 0) ++# define VC4_HDMI_CRP_CFG_N_SHIFT 0 ++ ++/* 20-bit fields containing CTS values to be transmitted if !EXTERNAL_CTS_EN */ ++#define VC4_HDMI_CTS_0 0x0ac ++#define VC4_HDMI_CTS_1 0x0b0 ++/* 20-bit fields containing number of clocks to send CTS0/1 before ++ * switching to the other one. ++ */ ++#define VC4_HDMI_CTS_PERIOD_0 0x0b4 ++#define VC4_HDMI_CTS_PERIOD_1 0x0b8 ++ + #define VC4_HDMI_HORZA 0x0c4 + # define VC4_HDMI_HORZA_VPOS BIT(14) + # define VC4_HDMI_HORZA_HPOS BIT(13) +@@ -512,7 +563,11 @@ + + #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 + +-#define VC4_HDMI_GCP_0 0x400 ++#define VC4_HDMI_TX_PHY_CTL0 0x2c4 ++# define VC4_HDMI_TX_PHY_RNG_PWRDN BIT(25) ++ ++#define VC4_HDMI_GCP(x) (0x400 + ((x) * 0x4)) ++#define VC4_HDMI_RAM_PACKET(x) (0x400 + ((x) * 0x24)) + #define VC4_HDMI_PACKET_STRIDE 0x24 + + #define VC4_HD_M_CTL 0x00c +@@ -522,6 +577,56 @@ + # define VC4_HD_M_ENABLE BIT(0) + + #define VC4_HD_MAI_CTL 0x014 ++/* Set when audio stream is received at a slower rate than the ++ * sampling period, so MAI fifo goes empty. Write 1 to clear. ++ */ ++# define VC4_HD_MAI_CTL_DLATE BIT(15) ++# define VC4_HD_MAI_CTL_BUSY BIT(14) ++# define VC4_HD_MAI_CTL_CHALIGN BIT(13) ++# define VC4_HD_MAI_CTL_WHOLSMP BIT(12) ++# define VC4_HD_MAI_CTL_FULL BIT(11) ++# define VC4_HD_MAI_CTL_EMPTY BIT(10) ++# define VC4_HD_MAI_CTL_FLUSH BIT(9) ++/* If set, MAI bus generates SPDIF (bit 31) parity instead of passing ++ * through. ++ */ ++# define VC4_HD_MAI_CTL_PAREN BIT(8) ++# define VC4_HD_MAI_CTL_CHNUM_MASK VC4_MASK(7, 4) ++# define VC4_HD_MAI_CTL_CHNUM_SHIFT 4 ++# define VC4_HD_MAI_CTL_ENABLE BIT(3) ++/* Underflow error status bit, write 1 to clear. */ ++# define VC4_HD_MAI_CTL_ERRORE BIT(2) ++/* Overflow error status bit, write 1 to clear. */ ++# define VC4_HD_MAI_CTL_ERRORF BIT(1) ++/* Single-shot reset bit. Read value is undefined. */ ++# define VC4_HD_MAI_CTL_RESET BIT(0) ++ ++#define VC4_HD_MAI_THR 0x018 ++# define VC4_HD_MAI_THR_PANICHIGH_MASK VC4_MASK(29, 24) ++# define VC4_HD_MAI_THR_PANICHIGH_SHIFT 24 ++# define VC4_HD_MAI_THR_PANICLOW_MASK VC4_MASK(21, 16) ++# define VC4_HD_MAI_THR_PANICLOW_SHIFT 16 ++# define VC4_HD_MAI_THR_DREQHIGH_MASK VC4_MASK(13, 8) ++# define VC4_HD_MAI_THR_DREQHIGH_SHIFT 8 ++# define VC4_HD_MAI_THR_DREQLOW_MASK VC4_MASK(5, 0) ++# define VC4_HD_MAI_THR_DREQLOW_SHIFT 0 ++ ++/* Format header to be placed on the MAI data. Unused. */ ++#define VC4_HD_MAI_FMT 0x01c ++ ++/* Register for DMAing in audio data to be transported over the MAI ++ * bus to the Falcon core. ++ */ ++#define VC4_HD_MAI_DATA 0x020 ++ ++/* Divider from HDMI HSM clock to MAI serial clock. Sampling period ++ * converges to N / (M + 1) cycles. ++ */ ++#define VC4_HD_MAI_SMP 0x02c ++# define VC4_HD_MAI_SMP_N_MASK VC4_MASK(31, 8) ++# define VC4_HD_MAI_SMP_N_SHIFT 8 ++# define VC4_HD_MAI_SMP_M_MASK VC4_MASK(7, 0) ++# define VC4_HD_MAI_SMP_M_SHIFT 0 + + #define VC4_HD_VID_CTL 0x038 + # define VC4_HD_VID_CTL_ENABLE BIT(31) + +From b0e084829f6a7ad74dfcc469a0270b95e7c7abe7 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Thu, 2 Feb 2017 11:37:36 +0100 +Subject: [PATCH 223/229] ARM: dts: bcm283x: Add HDMI audio related properties + +Add the dmas and dma-names properties to support HDMI audio. + +Signed-off-by: Boris Brezillon +Signed-off-by: Eric Anholt +(cherry picked from commit d46d2c6380c10e80e99f6af9067356128bffac6b) +--- + arch/arm/boot/dts/bcm283x.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi +index 348c71bbc913644c04bab43fcb95abe9b6c9c640..7d58cd79ac6bd99f0b47a909ac827c61aac642d9 100644 +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -339,6 +339,8 @@ + clocks = <&clocks BCM2835_PLLH_PIX>, + <&clocks BCM2835_CLOCK_HSM>; + clock-names = "pixel", "hdmi"; ++ dmas = <&dma 17>; ++ dma-names = "audio-rx"; + status = "disabled"; + }; + + +From 4bb790470fe058b8a784ec7da6bd9366cca287da Mon Sep 17 00:00:00 2001 +From: Yasunari Takiguchi +Date: Fri, 14 Apr 2017 10:43:57 +0100 +Subject: [PATCH 224/229] This is the driver for Sony CXD2880 DVB-T2/T tuner + + demodulator. It includes the CXD2880 driver and the CXD2880 SPI adapter. The + current CXD2880 driver version is 1.4.1 - 1.0.1 released on April 13, 2017. + +Signed-off-by: Yasunari Takiguchi +Signed-off-by: Masayuki Yamamoto +Signed-off-by: Hideki Nozawa +Signed-off-by: Kota Yonezawa +Signed-off-by: Toshihiko Matsumoto +Signed-off-by: Satoshi Watanabe +--- + drivers/media/dvb-frontends/Kconfig | 2 + + drivers/media/dvb-frontends/Makefile | 1 + + drivers/media/dvb-frontends/cxd2880/Kconfig | 6 + + drivers/media/dvb-frontends/cxd2880/Makefile | 21 + + drivers/media/dvb-frontends/cxd2880/cxd2880.h | 46 + + .../media/dvb-frontends/cxd2880/cxd2880_common.c | 84 + + .../media/dvb-frontends/cxd2880/cxd2880_common.h | 86 + + .../dvb-frontends/cxd2880/cxd2880_devio_spi.c | 147 + + .../dvb-frontends/cxd2880/cxd2880_devio_spi.h | 40 + + drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h | 50 + + drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h | 91 + + .../media/dvb-frontends/cxd2880/cxd2880_dvbt2.h | 402 ++ + .../media/dvb-frontends/cxd2880/cxd2880_integ.c | 99 + + .../media/dvb-frontends/cxd2880/cxd2880_integ.h | 44 + + .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.c | 197 + + .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.h | 58 + + .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c | 311 ++ + .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h | 64 + + drivers/media/dvb-frontends/cxd2880/cxd2880_io.c | 68 + + drivers/media/dvb-frontends/cxd2880/cxd2880_io.h | 62 + + drivers/media/dvb-frontends/cxd2880/cxd2880_math.c | 89 + + drivers/media/dvb-frontends/cxd2880/cxd2880_math.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 | 45 + + .../media/dvb-frontends/cxd2880/cxd2880_stdlib.h | 35 + + .../dvb-frontends/cxd2880/cxd2880_stopwatch_port.c | 71 + + .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c | 3925 ++++++++++++++++++++ + .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h | 395 ++ + .../cxd2880/cxd2880_tnrdmd_driver_version.h | 29 + + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c | 1072 ++++++ + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h | 62 + + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c | 1309 +++++++ + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h | 82 + + .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.c | 2523 +++++++++++++ + .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.h | 170 + + .../cxd2880/cxd2880_tnrdmd_dvbt_mon.c | 1190 ++++++ + .../cxd2880/cxd2880_tnrdmd_dvbt_mon.h | 106 + + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c | 207 ++ + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h | 52 + + drivers/media/dvb-frontends/cxd2880/cxd2880_top.c | 1550 ++++++++ + drivers/media/spi/Kconfig | 14 + + drivers/media/spi/Makefile | 5 + + drivers/media/spi/cxd2880-spi.c | 728 ++++ + 44 files changed, 15759 insertions(+) + create mode 100644 drivers/media/dvb-frontends/cxd2880/Kconfig + create mode 100644 drivers/media/dvb-frontends/cxd2880/Makefile + 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_devio_spi.c + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.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_integ_dvbt.c + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.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_io.c + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_math.c + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_math.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_stdlib.h + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c + 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_dvbt.c + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.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_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/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_tnrdmd_mon.c + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c + create mode 100644 drivers/media/spi/cxd2880-spi.c + +diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig +index b71b747ee0baae22a68c081b24132bef5f05bf2a..4b59e4a8bdab149226d8d6ff8fc7678bf65ffaa3 100644 +--- a/drivers/media/dvb-frontends/Kconfig ++++ b/drivers/media/dvb-frontends/Kconfig +@@ -518,6 +518,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/Makefile b/drivers/media/dvb-frontends/Makefile +index 93921a4eaa275997a5ed4178de1acb1a54409430..5629631ffb2f044363fd1e1d820e4df75ec41c2b 100644 +--- a/drivers/media/dvb-frontends/Makefile ++++ b/drivers/media/dvb-frontends/Makefile +@@ -126,3 +126,4 @@ obj-$(CONFIG_DVB_TC90522) += tc90522.o + obj-$(CONFIG_DVB_HORUS3A) += horus3a.o + obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o + obj-$(CONFIG_DVB_HELENE) += helene.o ++obj-$(CONFIG_DVB_CXD2880) += cxd2880/ +diff --git a/drivers/media/dvb-frontends/cxd2880/Kconfig b/drivers/media/dvb-frontends/cxd2880/Kconfig +new file mode 100644 +index 0000000000000000000000000000000000000000..36b8b6f7c4f71d9b0b8539c2713e800a32913d8e +--- /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/dvb-frontends/cxd2880/Makefile b/drivers/media/dvb-frontends/cxd2880/Makefile +new file mode 100644 +index 0000000000000000000000000000000000000000..2672c4a3d65cf4ff65e9dc8d240ae88cdfa1eb19 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/Makefile +@@ -0,0 +1,21 @@ ++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_math.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/dvb-frontends/cxd2880/cxd2880.h b/drivers/media/dvb-frontends/cxd2880/cxd2880.h +new file mode 100644 +index 0000000000000000000000000000000000000000..281f9a784eb530355bcf94500609d17180b9f73c +--- /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 . ++ */ ++ ++#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 0000000000000000000000000000000000000000..850f3a76b2c79808fd080801507f8edcda5d4b4d +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c +@@ -0,0 +1,84 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_common.h" ++ ++#define MASKUPPER(n) (((n) == 0) ? 0 : (0xFFFFFFFFU << (32 - (n)))) ++#define MASKLOWER(n) (((n) == 0) ? 0 : (0xFFFFFFFFU >> (32 - (n)))) ++ ++int cxd2880_convert2s_complement(u32 value, u32 bitlen) ++{ ++ if ((bitlen == 0) || (bitlen >= 32)) ++ return (int)value; ++ ++ if (value & (u32)(1 << (bitlen - 1))) ++ return (int)(MASKUPPER(32 - bitlen) | value); ++ else ++ return (int)(MASKLOWER(bitlen) & value); ++} ++ ++u32 cxd2880_bit_split_from_byte_array(u8 *array, u32 start_bit, u32 bit_num) ++{ ++ u32 value = 0; ++ u8 *array_read; ++ u8 bit_read; ++ u32 len_remain; ++ ++ if (!array) ++ return 0; ++ if ((bit_num == 0) || (bit_num > 32)) ++ return 0; ++ ++ array_read = array + (start_bit / 8); ++ bit_read = (u8)(start_bit % 8); ++ len_remain = bit_num; ++ ++ if (bit_read != 0) { ++ if (((int)len_remain) <= 8 - bit_read) { ++ value = (*array_read) >> ((8 - bit_read) - len_remain); ++ len_remain = 0; ++ } else { ++ value = *array_read++; ++ len_remain -= 8 - bit_read; ++ } ++ } ++ ++ while (len_remain > 0) { ++ if (len_remain < 8) { ++ value <<= len_remain; ++ value |= (*array_read++ >> (8 - len_remain)); ++ len_remain = 0; ++ } else { ++ value <<= 8; ++ value |= (u32)(*array_read++); ++ len_remain -= 8; ++ } ++ } ++ ++ value &= MASKLOWER(bit_num); ++ ++ return 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 0000000000000000000000000000000000000000..b1ecb44bca10f730b1dc6add663c469ade5784c9 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h +@@ -0,0 +1,86 @@ ++/* ++ * 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 . ++ */ ++ ++#ifndef CXD2880_COMMON_H ++#define CXD2880_COMMON_H ++ ++#include ++ ++#ifndef NULL ++#ifdef __cplusplus ++#define NULL 0 ++#else ++#define NULL ((void *)0) ++#endif ++#endif ++ ++#include ++#define CXD2880_SLEEP(n) msleep(n) ++#ifndef CXD2880_SLEEP_IN_MON ++#define CXD2880_SLEEP_IN_MON(n, obj) CXD2880_SLEEP(n) ++#endif ++ ++#define CXD2880_ARG_UNUSED(arg) ((void)(arg)) ++ ++enum cxd2880_ret { ++ CXD2880_RESULT_OK, ++ CXD2880_RESULT_ERROR_ARG, ++ CXD2880_RESULT_ERROR_IO, ++ CXD2880_RESULT_ERROR_SW_STATE, ++ CXD2880_RESULT_ERROR_HW_STATE, ++ CXD2880_RESULT_ERROR_TIMEOUT, ++ CXD2880_RESULT_ERROR_UNLOCK, ++ CXD2880_RESULT_ERROR_RANGE, ++ CXD2880_RESULT_ERROR_NOSUPPORT, ++ CXD2880_RESULT_ERROR_CANCEL, ++ CXD2880_RESULT_ERROR_OTHER, ++ CXD2880_RESULT_ERROR_OVERFLOW, ++ CXD2880_RESULT_OK_CONFIRM ++}; ++ ++int cxd2880_convert2s_complement(u32 value, u32 bitlen); ++ ++u32 cxd2880_bit_split_from_byte_array(u8 *array, u32 start_bit, u32 bit_num); ++ ++struct cxd2880_atomic { ++ int counter; ++}; ++ ++#define cxd2880_atomic_set(a, i) ((a)->counter = i) ++#define cxd2880_atomic_read(a) ((a)->counter) ++ ++struct cxd2880_stopwatch { ++ u32 start_time; ++}; ++ ++enum cxd2880_ret cxd2880_stopwatch_start(struct cxd2880_stopwatch *stopwatch); ++ ++enum cxd2880_ret cxd2880_stopwatch_sleep(struct cxd2880_stopwatch *stopwatch, ++ u32 ms); ++ ++enum cxd2880_ret cxd2880_stopwatch_elapsed(struct cxd2880_stopwatch *stopwatch, ++ u32 *elapsed); ++ ++#endif +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 0000000000000000000000000000000000000000..516efade6bf586629f5df6a72e7cd0f81544ee90 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c +@@ -0,0 +1,147 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_devio_spi.h" ++#include "cxd2880_stdlib.h" ++ ++#define BURST_WRITE_MAX 128 ++ ++static enum cxd2880_ret cxd2880_io_spi_read_reg(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, ++ u8 sub_address, u8 *data, ++ u32 size) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_spi *spi = NULL; ++ u8 send_data[6]; ++ u8 *read_data_top = data; ++ ++ if ((!io) || (!io->if_object) || (!data)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (sub_address + size > 0x100) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ spi = (struct cxd2880_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] = (u8)size; ++ ++ ret = ++ spi->write_read(spi, send_data, sizeof(send_data), ++ read_data_top, send_data[2]); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ sub_address += send_data[2]; ++ read_data_top += send_data[2]; ++ size -= send_data[2]; ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret cxd2880_io_spi_write_reg(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, ++ u8 sub_address, ++ const u8 *data, u32 size) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ if (size > BURST_WRITE_MAX) ++ return CXD2880_RESULT_ERROR_OVERFLOW; ++ ++ if (sub_address + size > 0x100) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ spi = (struct cxd2880_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] = (u8)size; ++ ++ cxd2880_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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ sub_address += send_data[2]; ++ write_data_top += send_data[2]; ++ size -= send_data[2]; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_io_spi_create(struct cxd2880_io *io, ++ struct cxd2880_spi *spi, u8 slave_select) ++{ ++ if ((!io) || (!spi)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ 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 CXD2880_RESULT_OK; ++} +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 0000000000000000000000000000000000000000..15934bf11935bb0da08996f3441891fb8710b15c +--- /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 . ++ */ ++ ++#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" ++ ++enum cxd2880_ret 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_dtv.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h +new file mode 100644 +index 0000000000000000000000000000000000000000..7de098d556fec6a90f7335328059de4c69d66df2 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h +@@ -0,0 +1,50 @@ ++/* ++ * 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 . ++ */ ++ ++#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_ISDBT, ++ CXD2880_DTV_SYS_ISDBTSB, ++ CXD2880_DTV_SYS_ISDBTMM_A, ++ CXD2880_DTV_SYS_ISDBTMM_B, ++ 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_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h +new file mode 100644 +index 0000000000000000000000000000000000000000..345c094760d28a48995aca91b61ff034fa475db0 +--- /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 . ++ */ ++ ++#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_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h +new file mode 100644 +index 0000000000000000000000000000000000000000..1870398cba9da50143a0c0d0774763edd8a31e78 +--- /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 . ++ */ ++ ++#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_integ.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c +new file mode 100644 +index 0000000000000000000000000000000000000000..5ad6685e2a1d457c5a9b8d31a1d6f4aed526dd04 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c +@@ -0,0 +1,99 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd.h" ++#include "cxd2880_tnrdmd_mon.h" ++#include "cxd2880_integ.h" ++ ++enum cxd2880_ret cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_stopwatch timer; ++ u32 elapsed_time = 0; ++ u8 cpu_task_completed = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_init1(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = cxd2880_stopwatch_start(&timer); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ while (1) { ++ ret = cxd2880_stopwatch_elapsed(&timer, &elapsed_time); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, ++ &cpu_task_completed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (cpu_task_completed) ++ break; ++ ++ if (elapsed_time > CXD2880_TNRDMD_WAIT_INIT_TIMEOUT) ++ return CXD2880_RESULT_ERROR_TIMEOUT; ++ ret = ++ cxd2880_stopwatch_sleep(&timer, ++ CXD2880_TNRDMD_WAIT_INIT_INTVL); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = cxd2880_tnrdmd_init2(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ cxd2880_atomic_set(&tnr_dmd->cancel, 1); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd ++ *tnr_dmd) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (cxd2880_atomic_read(&tnr_dmd->cancel) != 0) ++ return CXD2880_RESULT_ERROR_CANCEL; ++ ++ return CXD2880_RESULT_OK; ++} +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 0000000000000000000000000000000000000000..9cfc52dbf9d4fc128506ee355461cd6ca9f9ab53 +--- /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 . ++ */ ++ ++#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 ++ ++enum cxd2880_ret cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd ++ *tnr_dmd); ++ ++#endif +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 0000000000000000000000000000000000000000..43b7da69fc6d689c2246047d06473074f48f69e8 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c +@@ -0,0 +1,197 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd_dvbt.h" ++#include "cxd2880_integ_dvbt.h" ++ ++static enum cxd2880_ret dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt_tune_param ++ *tune_param) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!tune_param)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ cxd2880_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 CXD2880_RESULT_ERROR_NOSUPPORT; ++ } ++ ++ ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ CXD2880_SLEEP(CXD2880_TNRDMD_WAIT_AGC_STABLE); ++ ++ ret = cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt_wait_demod_lock(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ enum cxd2880_tnrdmd_lock_result lock = ++ CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; ++ struct cxd2880_stopwatch timer; ++ u8 continue_wait = 1; ++ u32 elapsed = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_stopwatch_start(&timer); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ for (;;) { ++ ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (elapsed >= CXD2880_DVBT_WAIT_TS_LOCK) ++ continue_wait = 0; ++ ++ ret = cxd2880_tnrdmd_dvbt_check_ts_lock(tnr_dmd, &lock); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ switch (lock) { ++ case CXD2880_TNRDMD_LOCK_RESULT_LOCKED: ++ return CXD2880_RESULT_OK; ++ ++ case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED: ++ return CXD2880_RESULT_ERROR_UNLOCK; ++ ++ default: ++ break; ++ } ++ ++ ret = cxd2880_integ_check_cancellation(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (continue_wait) { ++ ret = ++ cxd2880_stopwatch_sleep(&timer, ++ CXD2880_DVBT_WAIT_LOCK_INTVL); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } else { ++ ret = CXD2880_RESULT_ERROR_TIMEOUT; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ enum cxd2880_tnrdmd_lock_result lock = ++ CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; ++ struct cxd2880_stopwatch timer; ++ u8 continue_wait = 1; ++ u32 elapsed = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_stopwatch_start(&timer); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ for (;;) { ++ ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (elapsed >= CXD2880_DVBT_WAIT_DMD_LOCK) ++ continue_wait = 0; ++ ++ ret = cxd2880_tnrdmd_dvbt_check_demod_lock(tnr_dmd, &lock); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ switch (lock) { ++ case CXD2880_TNRDMD_LOCK_RESULT_LOCKED: ++ return CXD2880_RESULT_OK; ++ ++ case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED: ++ return CXD2880_RESULT_ERROR_UNLOCK; ++ ++ default: ++ break; ++ } ++ ++ ret = cxd2880_integ_check_cancellation(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (continue_wait) { ++ ret = ++ cxd2880_stopwatch_sleep(&timer, ++ CXD2880_DVBT_WAIT_LOCK_INTVL); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } else { ++ ret = CXD2880_RESULT_ERROR_TIMEOUT; ++ 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 0000000000000000000000000000000000000000..41f35c07a15e5052d3c09a21f1cc5c2085158690 +--- /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 . ++ */ ++ ++#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; ++ enum cxd2880_ret tune_result; ++ struct cxd2880_dvbt_tune_param dvbt_tune_param; ++}; ++ ++enum cxd2880_ret cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt_tune_param ++ *tune_param); ++ ++enum cxd2880_ret cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd ++ *tnr_dmd); ++ ++#endif +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 0000000000000000000000000000000000000000..1d60b9c236d844df239e3adfa0da40192555c7ee +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c +@@ -0,0 +1,311 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd_dvbt2.h" ++#include "cxd2880_tnrdmd_dvbt2_mon.h" ++#include "cxd2880_integ_dvbt2.h" ++ ++static enum cxd2880_ret dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dvbt2_profile ++ profile); ++ ++static enum cxd2880_ret dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_tune_param ++ *tune_param) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!tune_param)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ cxd2880_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 CXD2880_RESULT_ERROR_NOSUPPORT; ++ } ++ ++ if ((tune_param->profile != CXD2880_DVBT2_PROFILE_BASE) && ++ (tune_param->profile != CXD2880_DVBT2_PROFILE_LITE)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ CXD2880_SLEEP(CXD2880_TNRDMD_WAIT_AGC_STABLE); ++ ++ ret = cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt2_wait_demod_lock(tnr_dmd, tune_param->profile); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = cxd2880_tnrdmd_dvbt2_diver_fef_setting(tnr_dmd); ++ if (ret == CXD2880_RESULT_ERROR_HW_STATE) ++ return CXD2880_RESULT_ERROR_UNLOCK; ++ else if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt2_wait_l1_post_lock(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ { ++ u8 plp_not_found; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_data_plp_error(tnr_dmd, ++ &plp_not_found); ++ if (ret == CXD2880_RESULT_ERROR_HW_STATE) ++ return CXD2880_RESULT_ERROR_UNLOCK; ++ else if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (plp_not_found) { ++ ret = CXD2880_RESULT_OK_CONFIRM; ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_profile ++ profile) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ enum cxd2880_tnrdmd_lock_result lock = ++ CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; ++ u16 timeout = 0; ++ struct cxd2880_stopwatch timer; ++ u8 continue_wait = 1; ++ u32 elapsed = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_stopwatch_start(&timer); ++ if (ret != CXD2880_RESULT_OK) ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ for (;;) { ++ ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (elapsed >= timeout) ++ continue_wait = 0; ++ ++ ret = cxd2880_tnrdmd_dvbt2_check_ts_lock(tnr_dmd, &lock); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ switch (lock) { ++ case CXD2880_TNRDMD_LOCK_RESULT_LOCKED: ++ return CXD2880_RESULT_OK; ++ ++ case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED: ++ return CXD2880_RESULT_ERROR_UNLOCK; ++ ++ default: ++ break; ++ } ++ ++ ret = cxd2880_integ_check_cancellation(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (continue_wait) { ++ ret = ++ cxd2880_stopwatch_sleep(&timer, ++ CXD2880_DVBT2_WAIT_LOCK_INTVL); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } else { ++ ret = CXD2880_RESULT_ERROR_TIMEOUT; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dvbt2_profile ++ profile) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ enum cxd2880_tnrdmd_lock_result lock = ++ CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; ++ u16 timeout = 0; ++ struct cxd2880_stopwatch timer; ++ u8 continue_wait = 1; ++ u32 elapsed = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_stopwatch_start(&timer); ++ if (ret != CXD2880_RESULT_OK) ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ ++ for (;;) { ++ ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (elapsed >= timeout) ++ continue_wait = 0; ++ ++ ret = cxd2880_tnrdmd_dvbt2_check_demod_lock(tnr_dmd, &lock); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ switch (lock) { ++ case CXD2880_TNRDMD_LOCK_RESULT_LOCKED: ++ return CXD2880_RESULT_OK; ++ ++ case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED: ++ return CXD2880_RESULT_ERROR_UNLOCK; ++ ++ default: ++ break; ++ } ++ ++ ret = cxd2880_integ_check_cancellation(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (continue_wait) { ++ ret = ++ cxd2880_stopwatch_sleep(&timer, ++ CXD2880_DVBT2_WAIT_LOCK_INTVL); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } else { ++ ret = CXD2880_RESULT_ERROR_TIMEOUT; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_stopwatch timer; ++ u8 continue_wait = 1; ++ u32 elapsed = 0; ++ u8 l1_post_valid; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_stopwatch_start(&timer); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ for (;;) { ++ ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (l1_post_valid) ++ return CXD2880_RESULT_OK; ++ ++ ret = cxd2880_integ_check_cancellation(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (continue_wait) { ++ ret = ++ cxd2880_stopwatch_sleep(&timer, ++ CXD2880_DVBT2_WAIT_LOCK_INTVL); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } else { ++ ret = CXD2880_RESULT_ERROR_TIMEOUT; ++ 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 0000000000000000000000000000000000000000..bc72eb8188f2e5304cef7db687291b56eb728f8d +--- /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 . ++ */ ++ ++#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; ++ enum cxd2880_ret tune_result; ++ struct cxd2880_dvbt2_tune_param dvbt2_tune_param; ++}; ++ ++enum cxd2880_ret cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_tune_param ++ *tune_param); ++ ++enum cxd2880_ret 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_io.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c +new file mode 100644 +index 0000000000000000000000000000000000000000..f0f82055a953337a3fed96feedc2ca5b8d961c4f +--- /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 . ++ */ ++ ++#include "cxd2880_io.h" ++ ++enum cxd2880_ret cxd2880_io_common_write_one_reg(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, ++ u8 sub_address, u8 data) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!io) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = io->write_regs(io, tgt, sub_address, &data, 1); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_io_set_reg_bits(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, ++ u8 sub_address, u8 data, u8 mask) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!io) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (mask == 0x00) ++ return CXD2880_RESULT_OK; ++ ++ if (mask != 0xFF) { ++ u8 rdata = 0x00; ++ ++ ret = io->read_regs(io, tgt, sub_address, &rdata, 1); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ data = (u8)((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 0000000000000000000000000000000000000000..4d6db13cf9109373eb1262218b853ef37283958b +--- /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 . ++ */ ++ ++#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 { ++ enum cxd2880_ret (*read_regs)(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, u8 sub_address, ++ u8 *data, u32 size); ++ enum cxd2880_ret (*write_regs)(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, u8 sub_address, ++ const u8 *data, u32 size); ++ enum cxd2880_ret (*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; ++}; ++ ++enum cxd2880_ret cxd2880_io_common_write_one_reg(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, ++ u8 sub_address, u8 data); ++ ++enum cxd2880_ret 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_math.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.c +new file mode 100644 +index 0000000000000000000000000000000000000000..434c827898ff5f4a44bcc013fa7df43c168cafc4 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.c +@@ -0,0 +1,89 @@ ++/* ++ * cxd2880_math.c ++ * Sony CXD2880 DVB-T2/T tuner + demodulator driver ++ * mathmatics 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 . ++ */ ++ ++#include "cxd2880_math.h" ++ ++#define MAX_BIT_PRECISION 5 ++#define FRAC_BITMASK 0x1F ++#define LOG2_10_100X 332 ++#define LOG2_E_100X 144 ++ ++static const u8 log2_look_up[] = { ++ 0, 4, ++ 9, 13, ++ 17, 21, ++ 25, 29, ++ 32, 36, ++ 39, 43, ++ 46, 49, ++ 52, 55, ++ 58, 61, ++ 64, 67, ++ 70, 73, ++ 75, 78, ++ 81, 83, ++ 86, 88, ++ 91, 93, ++ 95, 98 ++}; ++ ++u32 cxd2880_math_log2(u32 x) ++{ ++ u8 count = 0; ++ u8 index = 0; ++ u32 xval = x; ++ ++ for (x >>= 1; x > 0; x >>= 1) ++ count++; ++ ++ x = count * 100; ++ ++ if (count > 0) { ++ if (count <= MAX_BIT_PRECISION) { ++ index = ++ (u8)(xval << (MAX_BIT_PRECISION - count)) & ++ FRAC_BITMASK; ++ x += log2_look_up[index]; ++ } else { ++ index = ++ (u8)(xval >> (count - MAX_BIT_PRECISION)) & ++ FRAC_BITMASK; ++ x += log2_look_up[index]; ++ } ++ } ++ ++ return x; ++} ++ ++u32 cxd2880_math_log10(u32 x) ++{ ++ return ((100 * cxd2880_math_log2(x) + LOG2_10_100X / 2) / LOG2_10_100X); ++} ++ ++u32 cxd2880_math_log(u32 x) ++{ ++ return ((100 * cxd2880_math_log2(x) + LOG2_E_100X / 2) / LOG2_E_100X); ++} +diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_math.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.h +new file mode 100644 +index 0000000000000000000000000000000000000000..94211835a4adca74e4ddad3ea417f01d9f8eedef +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.h +@@ -0,0 +1,40 @@ ++/* ++ * cxd2880_math.h ++ * Sony CXD2880 DVB-T2/T tuner + demodulator driver ++ * mathmatics 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 . ++ */ ++ ++#ifndef CXD2880_MATH_H_ ++#define CXD2880_MATH_H_ ++ ++#include "cxd2880_common.h" ++ ++u32 cxd2880_math_log2(u32 x); ++u32 cxd2880_math_log10(u32 x); ++u32 cxd2880_math_log(u32 x); ++ ++#ifndef min ++#define min(a, b) (((a) < (b)) ? (a) : (b)) ++#endif ++ ++#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 0000000000000000000000000000000000000000..81e5be7479623e536f6b472a38ae8af785291506 +--- /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 . ++ */ ++ ++#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 { ++ enum cxd2880_ret (*read)(struct cxd2880_spi *spi, u8 *data, ++ u32 size); ++ enum cxd2880_ret (*write)(struct cxd2880_spi *spi, const u8 *data, ++ u32 size); ++ enum cxd2880_ret (*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 0000000000000000000000000000000000000000..af9ed40c900b09c0566748d56991573965233ab4 +--- /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 . ++ */ ++ ++#include ++ ++#include "cxd2880_spi_device.h" ++ ++static enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ spi_device = (struct cxd2880_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 CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ spi_device = (struct cxd2880_spi_device *)(spi->user); ++ ++ result = spi_write_then_read(spi_device->spi, tx_data, ++ tx_size, rx_data, rx_size); ++ if (result < 0) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret ++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 CXD2880_RESULT_ERROR_ARG; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, ++ struct cxd2880_spi_device *spi_device) ++{ ++ if ((!spi) || (!spi_device)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ 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 CXD2880_RESULT_OK; ++} +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 0000000000000000000000000000000000000000..343d9161d537b2eb5bcc61e5cbd4c9fa04f5f8fe +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h +@@ -0,0 +1,45 @@ ++/* ++ * 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 . ++ */ ++ ++#ifndef CXD2880_SPI_DEVICE_H ++#define CXD2880_SPI_DEVICE_H ++ ++#include "cxd2880_spi.h" ++ ++struct cxd2880_spi_device { ++ struct spi_device *spi; ++}; ++ ++enum cxd2880_ret ++cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device, ++ enum cxd2880_spi_mode mode, ++ u32 speedHz); ++ ++enum cxd2880_ret ++cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, ++ struct cxd2880_spi_device *spi_device); ++ ++#endif /* CXD2880_SPI_DEVICE_H */ +diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h +new file mode 100644 +index 0000000000000000000000000000000000000000..b9ca1b9df1101b3a1cd78db593c9f36b08f67e01 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h +@@ -0,0 +1,35 @@ ++/* ++ * cxd2880_stdlib.h ++ * Sony CXD2880 DVB-T2/T tuner + demodulator driver ++ * standard lib function aliases ++ * ++ * 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 . ++ */ ++ ++#ifndef CXD2880_STDLIB_H ++#define CXD2880_STDLIB_H ++ ++#include ++ ++#define cxd2880_memcpy memcpy ++#define cxd2880_memset memset ++ ++#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 0000000000000000000000000000000000000000..14ad6aa6c4c0500c0e0ed59ab1c28f1dfe13f1d3 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c +@@ -0,0 +1,71 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_common.h" ++ ++#include ++#include ++#include ++ ++static u32 get_time_count(void) ++{ ++ struct timespec tp; ++ ++ getnstimeofday(&tp); ++ ++ return (u32)((tp.tv_sec * 1000) + (tp.tv_nsec / 1000000)); ++} ++ ++enum cxd2880_ret cxd2880_stopwatch_start(struct cxd2880_stopwatch *stopwatch) ++{ ++ if (!stopwatch) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ stopwatch->start_time = get_time_count(); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_stopwatch_sleep(struct cxd2880_stopwatch *stopwatch, ++ u32 ms) ++{ ++ if (!stopwatch) ++ return CXD2880_RESULT_ERROR_ARG; ++ CXD2880_ARG_UNUSED(*stopwatch); ++ CXD2880_SLEEP(ms); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_stopwatch_elapsed(struct cxd2880_stopwatch *stopwatch, ++ u32 *elapsed) ++{ ++ if (!stopwatch || !elapsed) ++ return CXD2880_RESULT_ERROR_ARG; ++ *elapsed = get_time_count() - stopwatch->start_time; ++ ++ return CXD2880_RESULT_OK; ++} +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 0000000000000000000000000000000000000000..286384ae012443c432a232401ff35157c57ed0f5 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c +@@ -0,0 +1,3925 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_common.h" ++#include "cxd2880_stdlib.h" ++#include "cxd2880_tnrdmd.h" ++#include "cxd2880_tnrdmd_mon.h" ++#include "cxd2880_tnrdmd_dvbt.h" ++#include "cxd2880_tnrdmd_dvbt2.h" ++ ++static enum cxd2880_ret p_init1(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x11, ++ 0x16) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_NOSUPPORT; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->create_param.en_internal_ldo) ++ data = 0x01; ++ else ++ data = 0x00; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x11, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x13, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x12, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_NOSUPPORT; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x69, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret p_init2(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data[6] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ data[4] = 0x06; ++ data[5] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x13, data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret p_init3(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data[2] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ ++ data[1] = 0x01; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x1F, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret rf_init1(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data[80] = { 0 }; ++ u8 addr = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x01; ++ data[1] = 0x00; ++ data[2] = 0x01; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x21, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x01; ++ data[1] = 0x01; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x17, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->create_param.stationary_use) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x1A, ++ 0x06) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x4F, ++ 0x18) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x61, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x71, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x9D, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x7D, ++ 0x02) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x8F, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x8B, ++ 0xC6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x9A, ++ 0x03) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x1C, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xB5, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xB9, ++ 0x07) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x33, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xC1, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xC4, ++ 0x1E) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xD9, data, ++ 8) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x6C; ++ data[1] = 0x10; ++ data[2] = 0xA6; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x44, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x16; ++ data[1] = 0xA8; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x50, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x22; ++ data[2] = 0x00; ++ data[3] = 0x88; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x62, data, ++ 4) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x74, ++ 0x75) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x05; ++ data[1] = 0x05; ++ data[2] = 0x05; ++ data[3] = 0x05; ++ data[4] = 0x05; ++ data[5] = 0x05; ++ data[6] = 0x05; ++ data[7] = 0x05; ++ data[8] = 0x05; ++ data[9] = 0x04; ++ data[10] = 0x04; ++ data[11] = 0x04; ++ data[12] = 0x03; ++ data[13] = 0x03; ++ data[14] = 0x03; ++ data[15] = 0x04; ++ data[16] = 0x04; ++ data[17] = 0x05; ++ data[18] = 0x05; ++ data[19] = 0x05; ++ data[20] = 0x02; ++ data[21] = 0x02; ++ data[22] = 0x02; ++ data[23] = 0x02; ++ data[24] = 0x02; ++ data[25] = 0x02; ++ data[26] = 0x02; ++ data[27] = 0x02; ++ data[28] = 0x02; ++ data[29] = 0x03; ++ data[30] = 0x02; ++ data[31] = 0x01; ++ data[32] = 0x01; ++ data[33] = 0x01; ++ data[34] = 0x02; ++ data[35] = 0x02; ++ data[36] = 0x03; ++ data[37] = 0x04; ++ data[38] = 0x04; ++ data[39] = 0x04; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x7F, data, ++ 40) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x16) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x71; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x23, ++ 0x89) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0xFF; ++ data[1] = 0x00; ++ data[2] = 0x00; ++ data[3] = 0x00; ++ data[4] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x00; ++ data[2] = 0x00; ++ data[3] = 0x00; ++ data[4] = 0x00; ++ data[5] = 0x01; ++ data[6] = 0x00; ++ data[7] = 0x01; ++ data[8] = 0x00; ++ data[9] = 0x02; ++ data[10] = 0x00; ++ data[11] = 0x63; ++ data[12] = 0x00; ++ data[13] = 0x00; ++ data[14] = 0x00; ++ data[15] = 0x03; ++ data[16] = 0x00; ++ data[17] = 0x04; ++ data[18] = 0x00; ++ data[19] = 0x04; ++ data[20] = 0x00; ++ data[21] = 0x06; ++ data[22] = 0x00; ++ data[23] = 0x06; ++ data[24] = 0x00; ++ data[25] = 0x08; ++ data[26] = 0x00; ++ data[27] = 0x09; ++ data[28] = 0x00; ++ data[29] = 0x0B; ++ data[30] = 0x00; ++ data[31] = 0x0B; ++ data[32] = 0x00; ++ data[33] = 0x0D; ++ data[34] = 0x00; ++ data[35] = 0x0D; ++ data[36] = 0x00; ++ data[37] = 0x0F; ++ data[38] = 0x00; ++ data[39] = 0x0F; ++ data[40] = 0x00; ++ data[41] = 0x0F; ++ data[42] = 0x00; ++ data[43] = 0x10; ++ data[44] = 0x00; ++ data[45] = 0x79; ++ data[46] = 0x00; ++ data[47] = 0x00; ++ data[48] = 0x00; ++ data[49] = 0x02; ++ data[50] = 0x00; ++ data[51] = 0x00; ++ data[52] = 0x00; ++ data[53] = 0x03; ++ data[54] = 0x00; ++ data[55] = 0x01; ++ data[56] = 0x00; ++ data[57] = 0x03; ++ data[58] = 0x00; ++ data[59] = 0x03; ++ data[60] = 0x00; ++ data[61] = 0x03; ++ data[62] = 0x00; ++ data[63] = 0x04; ++ data[64] = 0x00; ++ data[65] = 0x04; ++ data[66] = 0x00; ++ data[67] = 0x06; ++ data[68] = 0x00; ++ data[69] = 0x05; ++ data[70] = 0x00; ++ data[71] = 0x07; ++ data[72] = 0x00; ++ data[73] = 0x07; ++ data[74] = 0x00; ++ data[75] = 0x08; ++ data[76] = 0x00; ++ data[77] = 0x0A; ++ data[78] = 0x03; ++ data[79] = 0xE0; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x3A, data, ++ 80) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = 0x03; ++ data[1] = 0xE0; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xBC, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x51, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xC5, ++ 0x07) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x70, ++ 0xE9) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x76, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x78, ++ 0x32) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x7A, ++ 0x46) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x7C, ++ 0x86) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x7E, ++ 0xA4) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xE1, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x12) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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; ++ } ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, addr, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x13) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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; ++ } ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, addr, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x08; ++ data[1] = 0x09; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xBD, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x08; ++ data[1] = 0x09; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xC4, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x20; ++ data[1] = 0x20; ++ data[2] = 0x30; ++ data[3] = 0x41; ++ data[4] = 0x50; ++ data[5] = 0x5F; ++ data[6] = 0x6F; ++ data[7] = 0x80; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xC9, data, ++ 8) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x14) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x15; ++ data[1] = 0x18; ++ data[2] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x15, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x16) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x09; ++ data[2] = 0x00; ++ data[3] = 0x08; ++ data[4] = 0x00; ++ data[5] = 0x07; ++ data[6] = 0x00; ++ data[7] = 0x06; ++ data[8] = 0x00; ++ data[9] = 0x05; ++ data[10] = 0x00; ++ data[11] = 0x03; ++ data[12] = 0x00; ++ data[13] = 0x02; ++ data[14] = 0x00; ++ data[15] = 0x00; ++ data[16] = 0x00; ++ data[17] = 0x78; ++ data[18] = 0x00; ++ data[19] = 0x00; ++ data[20] = 0x00; ++ data[21] = 0x06; ++ data[22] = 0x00; ++ data[23] = 0x08; ++ data[24] = 0x00; ++ data[25] = 0x08; ++ data[26] = 0x00; ++ data[27] = 0x0C; ++ data[28] = 0x00; ++ data[29] = 0x0C; ++ data[30] = 0x00; ++ data[31] = 0x0D; ++ data[32] = 0x00; ++ data[33] = 0x0F; ++ data[34] = 0x00; ++ data[35] = 0x0E; ++ data[36] = 0x00; ++ data[37] = 0x0E; ++ data[38] = 0x00; ++ data[39] = 0x10; ++ data[40] = 0x00; ++ data[41] = 0x0F; ++ data[42] = 0x00; ++ data[43] = 0x0E; ++ data[44] = 0x00; ++ data[45] = 0x10; ++ data[46] = 0x00; ++ data[47] = 0x0F; ++ data[48] = 0x00; ++ data[49] = 0x0E; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x12, data, ++ 50) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0x00) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x25, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x11, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0x00) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x02, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x8F, ++ 0x16) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x67, ++ 0x60) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6A, ++ 0x0F) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6C, ++ 0x17) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0xFE; ++ data[2] = 0xEE; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6E, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0xA1; ++ data[1] = 0x8B; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x8D, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x08; ++ data[1] = 0x09; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x77, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->create_param.stationary_use) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x80, ++ 0xAA) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x41, ++ 0xA0) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ 0x68) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x25, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x1A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0x00) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x14, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x26, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret rf_init2(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data[5] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x40; ++ data[1] = 0x40; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xEA, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ 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; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x30, data, ++ 4) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x14) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x1B, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xD3, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret 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 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = 0x00; ++ data[1] = 0x00; ++ data[2] = 0x0E; ++ data[3] = 0x00; ++ data[4] = 0x03; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xE7, data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = 0x1F; ++ data[1] = 0x80; ++ data[2] = 0x18; ++ data[3] = 0x00; ++ data[4] = 0x07; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xE7, data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ 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: ++ case CXD2880_DTV_SYS_ISDBT: ++ case CXD2880_DTV_SYS_ISDBTSB: ++ case CXD2880_DTV_SYS_ISDBTMM_A: ++ case CXD2880_DTV_SYS_ISDBTMM_B: ++ data[2] = 0x94; ++ data[6] = 0x91; ++ break; ++ case CXD2880_DTV_SYS_DVBT2: ++ data[2] = 0x96; ++ data[6] = 0x93; ++ break; ++ default: ++ return CXD2880_RESULT_ERROR_ARG; ++ } ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x44, data, ++ 8) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x62, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x15) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x03; ++ data[1] = 0xE2; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x1E, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = (u8)(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 CXD2880_RESULT_ERROR_ARG; ++ } ++ ++ data[5] = 0x00; ++ ++ freq_khz += shift_frequency_khz; ++ ++ data[6] = (u8)((freq_khz >> 16) & 0x0F); ++ data[7] = (u8)((freq_khz >> 8) & 0xFF); ++ data[8] = (u8)(freq_khz & 0xFF); ++ data[9] = 0xFF; ++ data[10] = 0xFE; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x52, data, ++ 11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret 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 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = 0x01; ++ data[1] = 0x0E; ++ data[2] = 0x01; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2D, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x1A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x29, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2C, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x60, ++ data[0]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x62, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2D, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2F, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (shift_frequency_khz != 0) { ++ int shift_freq = 0; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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] = (u8)(((u32)shift_freq >> 8) & 0xFF); ++ data[1] = (u8)((u32)shift_freq & 0xFF); ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x69, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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] = (u8)((u32)shift_freq & 0xFF); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x69, ++ data[0]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->create_param.stationary_use) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x8A, ++ 0x87) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_tune3(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dtv_sys sys, ++ u8 en_fef_intmtnt_ctrl) ++{ ++ u8 data[6] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x41, ++ 0xA0) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xFE, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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; ++ } ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xEF, data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x2D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl) ++ data[0] = 0x00; ++ else ++ data[0] = 0x01; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB1, ++ data[0]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_tune4(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data[2] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ { ++ if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != ++ CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x14; ++ data[1] = 0x00; ++ if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x55, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x0B; ++ data[1] = 0xFF; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x53, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x57, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x0B; ++ data[1] = 0xFF; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x55, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != ++ CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x14; ++ data[1] = 0x00; ++ if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x53, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x57, ++ 0x02) != ++ CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xFE, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_DMD, 0xFE, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_sleep1(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data[3] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x57, ++ 0x03) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x53, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != ++ CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x1F; ++ data[1] = 0xFF; ++ data[2] = 0x03; ++ if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x55, ++ data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x00; ++ if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x53, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x1F; ++ data[1] = 0xFF; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x55, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_sleep2(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x2D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB1, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB2, &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data & 0x01) == 0x00) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xF4, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xF3, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xF2, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xF1, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xF0, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xEF, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_sleep3(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xFD, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_sleep4(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x41, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret spll_reset(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_tnrdmd_clockmode clockmode) ++{ ++ u8 data[4] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x29, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x28, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x26, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x22, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x30, ++ data[0]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x22, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(2); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0x00) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x00; ++ data[2] = 0x00; ++ data[3] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x26, data, ++ 4) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret t_power_x(struct cxd2880_tnrdmd *tnr_dmd, u8 on) ++{ ++ u8 data[3] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x29, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x28, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x25, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (on) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2B, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x12, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2A, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } else { ++ data[0] = 0x03; ++ data[1] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2A, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x13, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x25, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x11, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x00; ++ data[2] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++struct cxd2880_tnrdmd_ts_clk_cfg { ++ u8 srl_clk_mode; ++ u8 srl_duty_mode; ++ u8 ts_clk_period; ++}; ++ ++static enum cxd2880_ret set_ts_clk_mode_and_freq(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dtv_sys sys) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 ts_rate_ctrl_off = 0; ++ u8 ts_in_off = 0; ++ u8 ts_clk_manaul_on = 0; ++ ++ if ((sys == CXD2880_DTV_SYS_ISDBT) || ++ (sys == CXD2880_DTV_SYS_ISDBTSB) || ++ (sys == CXD2880_DTV_SYS_ISDBTMM_A) || ++ (sys == CXD2880_DTV_SYS_ISDBTMM_B)) { ++ backwards_compatible = 0; ++ ts_rate_ctrl_off = 1; ++ ts_in_off = 0; ++ } else 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD, ++ 0xDE, ts_in_off, 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD, ++ 0xDA, ts_clk_manaul_on, 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ts_clk_cfg = ++ srl_ts_clk_stgs[tnr_dmd->srl_ts_clk_mod_cnts] ++ [(u8)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 != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xD9, ++ ts_clk_cfg.ts_clk_period); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ { ++ u8 data = (u8)(backwards_compatible ? 0x00 : 0x01); ++ ++ if (sys == CXD2880_DTV_SYS_DVBT) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_io_set_reg_bits(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x66, ++ data, 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret pid_ftr_setting(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_tnrdmd_pid_ftr_cfg ++ *pid_ftr_cfg) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (!pid_ftr_cfg) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x50, ++ 0x02) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } else { ++ u8 data[65]; ++ ++ data[0] = (u8)(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)] = ++ (u8)((u8) ++ (pid_ftr_cfg->pid_cfg[i].pid ++ >> 8) | 0x20); ++ data[2 + (i * 2)] = ++ (u8)(pid_ftr_cfg->pid_cfg[i].pid ++ & 0xFF); ++ } else { ++ data[1 + (i * 2)] = 0x00; ++ data[2 + (i * 2)] = 0x00; ++ } ++ } ++ } ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x50, data, ++ 65) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u8 i; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ 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 != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ 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 CXD2880_RESULT_ERROR_OVERFLOW; ++ } ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ cxd2880_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; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ cxd2880_memset(tnr_dmd_main, 0, sizeof(struct cxd2880_tnrdmd)); ++ cxd2880_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 CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ 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; ++ cxd2880_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; ++ cxd2880_atomic_set(&tnr_dmd->diver_sub->cancel, 0); ++ } ++ ++ ret = cxd2880_tnrdmd_chip_id(tnr_dmd, &tnr_dmd->chip_id); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->chip_id)) ++ return CXD2880_RESULT_ERROR_NOSUPPORT; ++ ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->diver_sub->chip_id)) ++ return CXD2880_RESULT_ERROR_NOSUPPORT; ++ } ++ ++ ret = p_init1(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = p_init1(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = p_init2(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = p_init2(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ CXD2880_SLEEP(5); ++ ++ ret = p_init3(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = p_init3(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = rf_init1(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = rf_init1(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ { ++ u8 cpu_task_completed = 0; ++ ++ ret = ++ cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, ++ &cpu_task_completed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (!cpu_task_completed) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ ret = rf_init2(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = rf_init2(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = load_cfg_mem(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = load_cfg_mem(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *task_completed) ++{ ++ u16 cpu_status = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!task_completed)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd, &cpu_status); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (cpu_status == 0) ++ *task_completed = 1; ++ else ++ *task_completed = 0; ++ ++ return ret; ++} ++ ++enum cxd2880_ret 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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (frequency_khz < 4000) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = cxd2880_tnrdmd_sleep(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ { ++ u8 data = 0; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2B, &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ switch (sys) { ++ case CXD2880_DTV_SYS_DVBT: ++ case CXD2880_DTV_SYS_ISDBT: ++ case CXD2880_DTV_SYS_ISDBTSB: ++ case CXD2880_DTV_SYS_ISDBTMM_A: ++ case CXD2880_DTV_SYS_ISDBTMM_B: ++ if (data == 0x00) { ++ ret = t_power_x(tnr_dmd, 1); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == ++ CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = t_power_x(tnr_dmd->diver_sub, 1); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ } ++ break; ++ ++ case CXD2880_DTV_SYS_DVBT2: ++ if (data == 0x01) { ++ ret = t_power_x(tnr_dmd, 0); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == ++ CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = t_power_x(tnr_dmd->diver_sub, 0); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ } ++ break; ++ ++ default: ++ return CXD2880_RESULT_ERROR_ARG; ++ } ++ } ++ ++ { ++ enum cxd2880_tnrdmd_clockmode new_clk_mode = ++ CXD2880_TNRDMD_CLOCKMODE_A; ++ ++ ret = spll_reset(tnr_dmd, new_clk_mode); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ tnr_dmd->diver_sub->clk_mode = new_clk_mode; ++ } ++ ++ ret = load_cfg_mem(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = load_cfg_mem(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ CXD2880_SLEEP(10); ++ ++ { ++ u8 cpu_task_completed = 0; ++ ++ ret = ++ cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, ++ &cpu_task_completed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (!cpu_task_completed) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ ret = ++ x_tune2(tnr_dmd, bandwidth, tnr_dmd->clk_mode, ++ shift_frequency_khz); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dtv_sys sys, ++ u8 en_fef_intmtnt_ctrl) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = x_tune3(tnr_dmd, sys, en_fef_intmtnt_ctrl); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_tune4(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 1); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_sleep1(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = x_sleep2(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_sleep2(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ switch (tnr_dmd->sys) { ++ case CXD2880_DTV_SYS_DVBT: ++ ret = cxd2880_tnrdmd_dvbt_sleep_setting(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_DTV_SYS_DVBT2: ++ ret = cxd2880_tnrdmd_dvbt2_sleep_setting(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ default: ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ ret = x_sleep3(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_sleep3(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = x_sleep4(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_sleep4(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_tnrdmd_cfg_id id, ++ int value) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u8 data[2] = { 0 }; ++ u8 need_sub_setting = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ switch (id) { ++ case CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC4, ++ (u8)(value ? 0x00 : ++ 0x10), 0x10); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC5, ++ (u8)(value ? 0x00 : ++ 0x02), 0x02); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC5, ++ (u8)(value ? 0x00 : ++ 0x04), 0x04); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xCB, ++ (u8)(value ? 0x00 : ++ 0x01), 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC5, ++ (u8)(value ? 0x01 : ++ 0x00), 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSCLK_CONT: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ tnr_dmd->srl_ts_clk_mod_cnts = (u8)(value ? 0x01 : 0x00); ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSCLK_MASK: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((value < 0) || (value > 0x1F)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC6, (u8)value, ++ 0x1F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSVALID_MASK: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((value < 0) || (value > 0x1F)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC8, (u8)value, ++ 0x1F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSERR_MASK: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((value < 0) || (value > 0x1F)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC9, (u8)value, ++ 0x1F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSERR_VALID_DIS: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x91, ++ (u8)(value ? 0x01 : ++ 0x00), 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSPIN_CURRENT: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x51, (u8)value, ++ 0x3F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x50, ++ (u8)(value ? 0x80 : ++ 0x00), 0x80); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSPIN_PULLUP: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x50, (u8)value, ++ 0x3F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSCLK_FREQ: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((value < 0) || (value > 1)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((value < 0) || (value > 0xFF)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ tnr_dmd->ts_byte_clk_manual_setting = (u8)value; ++ ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TS_PACKET_GAP: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((value < 0) || (value > 7)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xD6, (u8)value, ++ 0x07); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ tnr_dmd->is_ts_backwards_compatible_mode = (u8)(value ? 1 : 0); ++ ++ break; ++ ++ case CXD2880_TNRDMD_CFG_PWM_VALUE: ++ if ((value < 0) || (value > 0x1000)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x22, ++ (u8)(value ? 0x01 : ++ 0x00), 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ { ++ u8 data[2]; ++ ++ data[0] = (u8)(((u16)value >> 8) & 0x1F); ++ data[1] = (u8)((u16)value & 0xFF); ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x23, ++ data[0], 0x1F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x24, ++ data[1], 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ break; ++ ++ case CXD2880_TNRDMD_CFG_INTERRUPT: ++ data[0] = (u8)((value >> 8) & 0xFF); ++ data[1] = (u8)(value & 0xFF); ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x48, data[0], ++ 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x49, data[1], ++ 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL: ++ data[0] = (u8)(value & 0x07); ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x4A, data[0], ++ 0x07); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL: ++ data[0] = (u8)((value & 0x07) << 3); ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x4A, data[0], ++ 0x38); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE: ++ if ((value < (int)CXD2880_TNRDMD_CLOCKMODE_UNKNOWN) || ++ (value > (int)CXD2880_TNRDMD_CLOCKMODE_C)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ tnr_dmd->fixed_clk_mode = (enum cxd2880_tnrdmd_clockmode)value; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_CABLE_INPUT: ++ tnr_dmd->is_cable_input = (u8)(value ? 1 : 0); ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE: ++ tnr_dmd->en_fef_intmtnt_base = (u8)(value ? 1 : 0); ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE: ++ tnr_dmd->en_fef_intmtnt_lite = (u8)(value ? 1 : 0); ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS: ++ data[0] = (u8)((value >> 8) & 0x07); ++ data[1] = (u8)(value & 0xFF); ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x99, data[0], ++ 0x07); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x9A, data[1], ++ 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS: ++ data[0] = (u8)((value >> 8) & 0x07); ++ data[1] = (u8)(value & 0xFF); ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x9B, data[0], ++ 0x07); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x9C, data[1], ++ 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS: ++ data[0] = (u8)((value >> 8) & 0x07); ++ data[1] = (u8)(value & 0xFF); ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x9D, data[0], ++ 0x07); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x9E, data[1], ++ 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST: ++ tnr_dmd->blind_tune_dvbt2_first = (u8)(value ? 1 : 0); ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD: ++ if ((value < 0) || (value > 31)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x10, 0x60, ++ (u8)(value & 0x1F), ++ 0x1F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD: ++ if ((value < 0) || (value > 7)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x10, 0x6F, ++ (u8)(value & 0x07), ++ 0x07); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT2_BBER_MES: ++ if ((value < 0) || (value > 15)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x20, 0x72, ++ (u8)(value & 0x0F), ++ 0x0F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT2_LBER_MES: ++ if ((value < 0) || (value > 15)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x20, 0x6F, ++ (u8)(value & 0x0F), ++ 0x0F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT_PER_MES: ++ if ((value < 0) || (value > 15)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x10, 0x5C, ++ (u8)(value & 0x0F), ++ 0x0F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT2_PER_MES: ++ if ((value < 0) || (value > 15)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x24, 0xDC, ++ (u8)(value & 0x0F), ++ 0x0F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_ISDBT_BERPER_PERIOD: ++ { ++ u8 data[2]; ++ ++ data[0] = (u8)((value & 0x00007F00) >> 8); ++ data[1] = (u8)(value & 0x000000FF); ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x60, 0x5B, ++ data[0], 0x7F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x60, 0x5C, ++ data[1], 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ break; ++ ++ default: ++ return CXD2880_RESULT_ERROR_ARG; ++ } ++ ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (id > 2) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (mode > CXD2880_TNRDMD_GPIO_MODE_EEW) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, ++ 0x00, 0x40 + id, (u8)mode, ++ 0x0F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, ++ 0x00, 0x43, ++ (u8)(open_drain ? (1 << id) : ++ 0), (u8)(1 << id)); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, ++ 0x00, 0x44, ++ (u8)(invert ? (1 << id) : 0), ++ (u8)(1 << id)); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, ++ 0x00, 0x45, ++ (u8)(en ? 0 : (1 << id)), ++ (u8)(1 << id)); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_gpio_set_cfg(tnr_dmd->diver_sub, id, en, mode, ++ open_drain, invert); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 *value) ++{ ++ u8 data = 0; ++ ++ if ((!tnr_dmd) || (!value)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (id > 2) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x20, &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *value = (u8)((data >> id) & 0x01); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 *value) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_gpio_read(tnr_dmd->diver_sub, id, value); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 value) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (id > 2) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, ++ 0x00, 0x46, ++ (u8)(value ? (1 << id) : 0), ++ (u8)(1 << id)); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 value) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_gpio_write(tnr_dmd->diver_sub, id, value); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd, ++ u16 *value) ++{ ++ u8 data[2] = { 0 }; ++ ++ if ((!tnr_dmd) || (!value)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x15, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *value = (u16)(((u16)data[0] << 8) | (data[1])); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd, ++ u16 value) ++{ ++ u8 data[2] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = (u8)((value >> 8) & 0xFF); ++ data[1] = (u8)(value & 0xFF); ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x3C, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 clear_overflow_flag, ++ u8 clear_underflow_flag, ++ u8 clear_buf) ++{ ++ u8 data[2] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = (u8)(clear_overflow_flag ? 0x02 : 0x00); ++ data[0] |= (u8)(clear_underflow_flag ? 0x01 : 0x00); ++ data[1] = (u8)(clear_buf ? 0x01 : 0x00); ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x9F, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_tnrdmd_chip_id *chip_id) ++{ ++ u8 data = 0; ++ ++ if ((!tnr_dmd) || (!chip_id)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xFD, &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *chip_id = (enum cxd2880_tnrdmd_chip_id)data; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ tgt, 0x00, bank) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (cxd2880_io_set_reg_bits(tnr_dmd->io, tgt, address, value, bit_mask) ++ != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = set_cfg_mem(tnr_dmd, tgt, bank, address, value, bit_mask); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dtv_sys sys, ++ u8 scan_mode_end) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ CXD2880_ARG_UNUSED(sys); ++ ++ tnr_dmd->scan_mode = scan_mode_end; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ ret = ++ cxd2880_tnrdmd_set_scan_mode(tnr_dmd->diver_sub, sys, ++ scan_mode_end); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_tnrdmd_pid_ftr_cfg ++ *pid_ftr_cfg) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) ++ return CXD2880_RESULT_ERROR_NOSUPPORT; ++ ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_ret(*rf_lvl_cmpstn) ++ (struct cxd2880_tnrdmd *, ++ int *)) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ tnr_dmd->rf_lvl_cmpstn = rf_lvl_cmpstn; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_ret ++ (*rf_lvl_cmpstn)(struct ++ cxd2880_tnrdmd ++ *, ++ int *)) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_set_rf_lvl_cmpstn(tnr_dmd->diver_sub, rf_lvl_cmpstn); ++ ++ return ret; ++} ++ ++enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ tnr_dmd->lna_thrs_tbl_air = tbl_air; ++ tnr_dmd->lna_thrs_tbl_cable = tbl_cable; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_set_lna_thrs(tnr_dmd->diver_sub, tbl_air, tbl_cable); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 en, u8 value) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->create_param.ts_output_if != CXD2880_TNRDMD_TSOUT_IF_TS) ++ return CXD2880_RESULT_ERROR_NOSUPPORT; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (en) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x50, ++ ((value & 0x1F) | 0x80)) != ++ CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x52, ++ (value & 0x1F)) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } else { ++ ret = tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x50, 0x3F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x52, ++ 0x1F) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = load_cfg_mem(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 en) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ switch (tnr_dmd->create_param.ts_output_if) { ++ case CXD2880_TNRDMD_TSOUT_IF_TS: ++ if (en) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x52, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xC3, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } else { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xC3, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x52, ++ 0x1F) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ break; ++ ++ case CXD2880_TNRDMD_TSOUT_IF_SPI: ++ break; ++ ++ case CXD2880_TNRDMD_TSOUT_IF_SDIO: ++ break; ++ ++ default: ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ switch (tnr_dmd->create_param.ts_output_if) { ++ case CXD2880_TNRDMD_TSOUT_IF_SPI: ++ case CXD2880_TNRDMD_TSOUT_IF_SDIO: ++ { ++ u8 data = 0; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ break; ++ case CXD2880_TNRDMD_TSOUT_IF_TS: ++ default: ++ break; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x01, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 0000000000000000000000000000000000000000..26e29b3b9f6bdba32a181595e8298cda3325112c +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h +@@ -0,0 +1,395 @@ ++/* ++ * 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 . ++ */ ++ ++#ifndef CXD2880_TNRDMD_H ++#define CXD2880_TNRDMD_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, ++ CXD2880_TNRDMD_CFG_ISDBT_BERPER_PERIOD ++}; ++ ++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; ++ enum cxd2880_ret (*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; ++ struct cxd2880_atomic cancel; ++}; ++ ++enum cxd2880_ret cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_io *io, ++ struct cxd2880_tnrdmd_create_param ++ *create_param); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *task_completed); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dtv_sys sys, ++ u8 en_fef_intmtnt_ctrl); ++ ++enum cxd2880_ret cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_tnrdmd_cfg_id id, ++ int value); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 *value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 *value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd, ++ u16 *value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd, ++ u16 value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 clear_overflow_flag, ++ u8 clear_underflow_flag, ++ u8 clear_buf); ++ ++enum cxd2880_ret cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_tnrdmd_chip_id *chip_id); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dtv_sys sys, ++ u8 scan_mode_end); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_tnrdmd_pid_ftr_cfg ++ *pid_ftr_cfg); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_ret(*rf_lvl_cmpstn) ++ (struct cxd2880_tnrdmd *, ++ int *)); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_ret ++ (*rf_lvl_cmpstn)(struct ++ cxd2880_tnrdmd ++ *, ++ int *)); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 en, u8 value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 en); ++ ++enum cxd2880_ret 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 0000000000000000000000000000000000000000..68fb3af04bd41719d407f333314635622cd982b0 +--- /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 . ++ */ ++ ++#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.1" ++ ++#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2017-04-13" +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 0000000000000000000000000000000000000000..f36cf533ec1795bf033531b0a347b60d917fe35f +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c +@@ -0,0 +1,1072 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd_dvbt.h" ++#include "cxd2880_tnrdmd_dvbt_mon.h" ++ ++static enum cxd2880_ret x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dtv_bandwidth ++ bandwidth, ++ enum cxd2880_tnrdmd_clockmode ++ clk_mode) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x31, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data_a[2] = { 0x52, 0x49 }; ++ u8 data_b[2] = { 0x5D, 0x55 }; ++ u8 data_c[2] = { 0x60, 0x00 }; ++ u8 *data = NULL; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x65, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x5D, ++ 0x07) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { ++ u8 data[2] = { 0x01, 0x01 }; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xCE, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x5C, ++ 0xFB) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xA4, ++ 0x03) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x14) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB0, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x25) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2] = { 0x01, 0xF0 }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xF0, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) || ++ (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x12) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x44, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x87, ++ 0xD2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x68, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, ++ data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x7D, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x71, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x51, ++ &data[2], ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[4] = { 0xB3, 0x00, 0x01, 0x02 }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x72, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6B, ++ &data[2], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, ++ data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x02) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x7D, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x71, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x51, ++ &data[2], ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[4] = { 0xB8, 0x00, 0x00, 0x03 }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x72, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6B, ++ &data[2], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, ++ data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x7D, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x71, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x51, ++ &data[2], ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[4] = { 0xBE, 0xAB, 0x00, 0x03 }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x72, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6B, ++ &data[2], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, ++ data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x06) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x7D, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x71, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x51, ++ &data[2], ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[4] = { 0xC8, 0x01, 0x00, 0x03 }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x72, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6B, ++ &data[2], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ break; ++ ++ default: ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xFD, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd ++ *tnr_dmd) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x5C, ++ 0xD8) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xA4, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x87, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dvbt_profile profile) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x67, ++ (profile == ++ CXD2880_DVBT_PROFILE_HP) ? 0x00 : 0x01) != ++ CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt_tune_param ++ *tune_param) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!tune_param)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT, ++ tune_param->center_freq_khz, ++ tune_param->bandwidth, 0, 0); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth, ++ tnr_dmd->clk_mode); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = dvbt_set_profile(tnr_dmd, tune_param->profile); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt_tune_param ++ *tune_param) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!tune_param)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT, ++ 0); ++ if (ret != CXD2880_RESULT_OK) ++ 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 CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd ++ *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = x_sleep_dvbt_demod_setting(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ u8 sync_stat = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ u8 unlock_detected_sub = 0; ++ ++ if ((!tnr_dmd) || (!lock)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ u8 sync_stat = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ u8 unlock_detected_sub = 0; ++ ++ if ((!tnr_dmd) || (!lock)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ 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 0000000000000000000000000000000000000000..de394d8e27f323a9ccfacbe3e56a3d6f40b6babe +--- /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 . ++ */ ++ ++#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; ++}; ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt_tune_param ++ *tune_param); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt_tune_param ++ *tune_param); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd ++ *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock); ++ ++#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 0000000000000000000000000000000000000000..bdad65b7298ab0ad131a6e6579e304fb279359a5 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c +@@ -0,0 +1,1309 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd_dvbt2.h" ++#include "cxd2880_tnrdmd_dvbt2_mon.h" ++ ++static enum cxd2880_ret x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dtv_bandwidth ++ bandwidth, ++ enum cxd2880_tnrdmd_clockmode ++ clk_mode) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x31, ++ 0x02) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x5D, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { ++ u8 data[2] = { 0x01, 0x01 }; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xCE, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[14] = { 0x07, 0x06, 0x01, 0xF0, ++ 0x00, 0x00, 0x04, 0xB0, 0x00, 0x00, 0x09, 0x9C, 0x0E, ++ 0x4C ++ }; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x20) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x8A, ++ data[0]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x90, ++ data[1]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x25) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xF0, &data[2], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x2A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xDC, ++ data[4]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xDE, ++ data[5]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x2D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x73, &data[6], ++ 4) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x8F, &data[10], ++ 4) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1D, ++ &data_1[0], 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x22, ++ data_1[3]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x24, ++ data_1[4]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x26, ++ data_1[5]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x29, ++ &data_1[6], 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x2D, ++ data_1[8]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x2E, ++ &data_2[0], ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x35, ++ &data_2[6], ++ 7) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x3C, ++ &data_3[0], 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x56, ++ &data_3[2], 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x19, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ data, ++ 9) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x02) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2] = { 0x3F, 0xFF }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x19, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ data, ++ 9) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2] = { 0x3F, 0xFF }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x19, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ data, ++ 9) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x06) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2] = { 0x3F, 0xFF }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x19, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ data, ++ 9) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x03) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2] = { 0x3F, 0xFF }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x19, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ data, ++ 9) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ break; ++ ++ default: ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xFD, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd ++ *tnr_dmd) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ u8 data[] = { 0, 1, 0, 2, ++ 0, 4, 0, 8, 0, 16, 0, 32 ++ }; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x1D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x47, data, ++ 12) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dvbt2_profile profile) ++{ ++ u8 t2_mode_tune_mode = 0; ++ u8 seq_not2_dtime = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x2E) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ t2_mode_tune_mode) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x2C, ++ seq_not2_dtime) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_tune_param ++ *tune_param) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!tune_param)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) && ++ (tune_param->profile == CXD2880_DVBT2_PROFILE_ANY)) ++ return CXD2880_RESULT_ERROR_NOSUPPORT; ++ ++ ret = ++ cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2, ++ tune_param->center_freq_khz, ++ tune_param->bandwidth, 0, 0); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth, ++ tnr_dmd->clk_mode); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = dvbt2_set_profile(tnr_dmd, tune_param->profile); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = ++ dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } else { ++ ret = ++ cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0, ++ (u8)(tune_param->data_plp_id)); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_tune_param ++ *tune_param) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!tune_param)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ ++ ret = ++ cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, ++ CXD2880_DTV_SYS_DVBT2, ++ en_fef_intmtnt_ctrl); ++ if (ret != CXD2880_RESULT_OK) ++ 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 CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd ++ *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = x_sleep_dvbt2_demod_setting(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ u8 sync_stat = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ u8 unlock_detected_sub = 0; ++ ++ if ((!tnr_dmd) || (!lock)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ u8 sync_stat = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ u8 unlock_detected_sub = 0; ++ ++ if ((!tnr_dmd) || (!lock)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (unlock_detected && unlock_detected_sub) ++ *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; ++ else ++ *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 auto_plp, ++ u8 plp_id) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x23) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (!auto_plp) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xAF, ++ plp_id) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xAD, ++ auto_plp ? 0x00 : 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd ++ *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) ++ return CXD2880_RESULT_OK; ++ ++ { ++ struct cxd2880_dvbt2_ofdm ofdm; ++ ++ ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (!ofdm.mixed) ++ return CXD2880_RESULT_OK; ++ } ++ ++ { ++ u8 data[] = { 0, 8, 0, 16, ++ 0, 32, 0, 64, 0, 128, 1, 0 ++ }; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x1D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x47, data, ++ 12) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *l1_post_valid) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ u8 data; ++ ++ if ((!tnr_dmd) || (!l1_post_valid)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *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 0000000000000000000000000000000000000000..8735280f0143ec5a7304dbeca39a510e346a0071 +--- /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 . ++ */ ++ ++#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 ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_tune_param ++ *tune_param); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_tune_param ++ *tune_param); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd ++ *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 auto_plp, ++ u8 plp_id); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd ++ *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *l1_post_valid); ++ ++#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 0000000000000000000000000000000000000000..235db16f4a08faf05db3aea737251fa5f82f143e +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c +@@ -0,0 +1,2523 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd_mon.h" ++#include "cxd2880_tnrdmd_dvbt2.h" ++#include "cxd2880_tnrdmd_dvbt2_mon.h" ++#include "cxd2880_math.h" ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *sync_stat, ++ u8 *ts_lock_stat, ++ u8 *unlock_detected) ++{ ++ if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, &data, ++ sizeof(data)) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *sync_stat = data & 0x07; ++ *ts_lock_stat = ((data & 0x20) ? 1 : 0); ++ *unlock_detected = ((data & 0x10) ? 1 : 0); ++ } ++ ++ if (*sync_stat == 0x07) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *sync_stat, ++ u8 *unlock_detected) ++{ ++ u8 ts_lock_stat = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub, sync_stat, ++ &ts_lock_stat, unlock_detected); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *offset) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!offset)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[4]; ++ u32 ctl_val = 0; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (sync_state != 6) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x30, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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) * (u8)tnr_dmd->bandwidth / 940); ++ break; ++ default: ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *offset) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!offset)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub, offset); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_l1pre ++ *l1_pre) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!l1_pre)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[37]; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ u8 version = 0; ++ enum cxd2880_dvbt2_profile profile; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ 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 != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (sync_state < 5) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } else { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x61, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } 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 CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } else { ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ l1_pre->mixed = l1_pre->s2 & 0x01; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_version ++ *ver) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u8 version = 0; ++ ++ if ((!tnr_dmd) || (!ver)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[2]; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (sync_state < 5) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } else { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x80, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ version = ((data[0] & 0x03) << 2); ++ version |= ((data[1] & 0xC0) >> 6); ++ *ver = (enum cxd2880_dvbt2_version)version; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_ofdm *ofdm) ++{ ++ if ((!tnr_dmd) || (!ofdm)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[5]; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (sync_state != 6) { ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ ret = CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->diver_mode == ++ CXD2880_TNRDMD_DIVERMODE_MAIN) ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_ofdm( ++ tnr_dmd->diver_sub, ofdm); ++ ++ return ret; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1D, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *plp_ids, ++ u8 *num_plps) ++{ ++ if ((!tnr_dmd) || (!num_plps)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 l1_post_ok = 0; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, ++ &l1_post_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(l1_post_ok & 0x01)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xC1, num_plps, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (*num_plps == 0) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_OTHER; ++ } ++ ++ if (!plp_ids) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_OK; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xC2, plp_ids, ++ ((*num_plps > ++ 62) ? 62 : *num_plps)) != ++ CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (*num_plps > 62) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0C) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ plp_ids + 62, ++ *num_plps - 62) != ++ CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ } ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[20]; ++ u8 addr = 0; ++ u8 index = 0; ++ u8 l1_post_ok = 0; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, ++ &l1_post_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!l1_post_ok) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) ++ addr = 0xA9; ++ else ++ addr = 0x96; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, addr, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ if ((type == CXD2880_DVBT2_PLP_COMMON) && (data[13] == 0)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ 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 = (u16)((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 = ++ (u8)((plp_info->rsvd & 0x8000) >> 15); ++ plp_info->plp_mode = ++ (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000C) >> ++ 2); ++ plp_info->static_flag = (u8)((plp_info->rsvd & 0x0002) >> 1); ++ plp_info->static_padding_flag = (u8)(plp_info->rsvd & 0x0001); ++ plp_info->rsvd = (u16)((plp_info->rsvd & 0x7FF0) >> 4); ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *plp_error) ++{ ++ if ((!tnr_dmd) || (!plp_error)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if ((data & 0x01) == 0x00) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xC0, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *plp_error = data & 0x01; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *l1_change) ++{ ++ if ((!tnr_dmd) || (!l1_change)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (sync_state < 5) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } else { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x5F, &data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ *l1_change = data & 0x01; ++ if (*l1_change) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x22) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x16, ++ 0x01) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ } ++ slvt_unfreeze_reg(tnr_dmd); ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ struct cxd2880_dvbt2_l1post ++ *l1_post) ++{ ++ if ((!tnr_dmd) || (!l1_post)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[16]; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, data, ++ sizeof(data)) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (!(data[0] & 0x01)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ 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 CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_plp_btype ++ type, ++ struct cxd2880_dvbt2_bbheader ++ *bbheader) ++{ ++ if ((!tnr_dmd) || (!bbheader)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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 != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (!ts_lock) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) { ++ u8 l1_post_ok; ++ u8 data; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, ++ &l1_post_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(l1_post_ok & 0x01)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB6, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (data == 0) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ { ++ u8 data[14]; ++ u8 addr = 0; ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) ++ addr = 0x51; ++ else ++ addr = 0x42; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, addr, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ bbheader->stream_input = ++ (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03); ++ bbheader->is_single_input_stream = (u8)((data[0] >> 5) & 0x01); ++ bbheader->is_constant_coding_modulation = ++ (u8)((data[0] >> 4) & 0x01); ++ bbheader->issy_indicator = (u8)((data[0] >> 3) & 0x01); ++ bbheader->null_packet_deletion = (u8)((data[0] >> 2) & 0x01); ++ bbheader->ext = (u8)(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 = (u16)((data[4] << 8) | data[5]); ++ ++ if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) { ++ bbheader->user_packet_length = ++ (u16)((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 = ++ (u32)((data[11] << 16) | (data[12] << 8) | ++ data[13]); ++ } ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_dvbt2_plp_btype ++ type, ++ u32 *ts_rate_bps) ++{ ++ if ((!tnr_dmd) || (!ts_rate_bps)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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 != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (!ts_lock) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 l1_post_ok = 0; ++ u8 addr = 0; ++ u8 data = 0; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, ++ &l1_post_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(l1_post_ok & 0x01)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) ++ addr = 0xBA; ++ else ++ addr = 0xA7; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, addr, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if ((data & 0x80) == 0x00) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x25) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[4]; ++ u8 addr = 0; ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) ++ addr = 0xA6; ++ else ++ addr = 0xAA; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, addr, &data[0], ++ 4) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ *ts_rate_bps = ++ (u32)(((data[0] & 0x07) << 24) | (data[1] << 16) | ++ (data[2] << 8) | data[3]); ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_spectrum_sense ++ *sense) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 early_unlock = 0; ++ ++ if ((!tnr_dmd) || (!sense)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock, ++ &early_unlock); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (sync_state != 6) { ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ ret = CXD2880_RESULT_ERROR_HW_STATE; ++ ++ 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; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x2F, &data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *sense = ++ (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV : ++ CXD2880_TNRDMD_SPECTRUM_NORMAL; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, ++ u16 *reg_value) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!reg_value)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ { ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ u8 data[2]; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (sync_state != 6) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x13, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *reg_value = (data[0] << 8) | data[1]; ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, ++ u32 reg_value, int *snr) ++{ ++ if ((!tnr_dmd) || (!snr)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (reg_value == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (reg_value > 10876) ++ reg_value = 10876; ++ ++ *snr = ++ 10 * 10 * ((int)cxd2880_math_log10(reg_value) - ++ (int)cxd2880_math_log10(12600 - reg_value)); ++ *snr += 32000; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, ++ int *snr) ++{ ++ u16 reg_value = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!snr)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ *snr = -1000 * 1000; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { ++ ret = dvbt2_read_snr_reg(tnr_dmd, ®_value); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret 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; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ *snr = -1000 * 1000; ++ *snr_main = -1000 * 1000; ++ *snr_sub = -1000 * 1000; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = dvbt2_read_snr_reg(tnr_dmd, ®_value); ++ if (ret == CXD2880_RESULT_OK) { ++ ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main); ++ if (ret != CXD2880_RESULT_OK) ++ reg_value = 0; ++ } else if (ret == CXD2880_RESULT_ERROR_HW_STATE) { ++ reg_value = 0; ++ } else { ++ return ret; ++ } ++ ++ reg_value_sum += reg_value; ++ ++ ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, ®_value); ++ if (ret == CXD2880_RESULT_OK) { ++ ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub); ++ if (ret != CXD2880_RESULT_OK) ++ reg_value = 0; ++ } else if (ret == CXD2880_RESULT_ERROR_HW_STATE) { ++ reg_value = 0; ++ } else { ++ return ret; ++ } ++ ++ reg_value_sum += reg_value; ++ ++ ret = dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u32 bit_error = 0; ++ u32 period_exp = 0; ++ u32 n_ldpc = 0; ++ ++ if ((!tnr_dmd) || (!ber)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[5]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x3C, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(data[0] & 0x01)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ bit_error = ++ ((data[1] & 0x0F) << 24) | (data[2] << 16) | (data[3] << 8) ++ | data[4]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xA0, data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x20) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6F, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period_exp = data[0] & 0x0F; ++ } ++ ++ if (bit_error > ((1U << period_exp) * n_ldpc)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *fer) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u32 fec_error = 0; ++ u32 period = 0; ++ ++ if ((!tnr_dmd) || (!fer)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (!(data[0] & 0x80)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ fec_error = ((data[0] & 0x7F) << 8) | (data[1]); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x20) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x72, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period = (1 << (data[0] & 0x0F)); ++ } ++ ++ if ((period == 0) || (fec_error > period)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u32 bit_error = 0; ++ u32 period_exp = 0; ++ u32 n_bch = 0; ++ ++ if ((!tnr_dmd) || (!ber)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ 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} ++ }; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x15, data, ++ 3) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(data[0] & 0x40)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ bit_error = ((data[0] & 0x3F) << 16) | (data[1] << 8) | data[2]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x9D, data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ plp_cr = (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07); ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xA0, data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03); ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x20) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x72, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period_exp = data[0] & 0x0F; ++ ++ if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) || ++ (plp_cr > CXD2880_DVBT2_R2_5)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ n_bch = n_bch_bits_lookup[plp_fec_type][plp_cr]; ++ } ++ ++ if (bit_error > ((1U << period_exp) * n_bch)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ u32 *pen) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ u8 data[3]; ++ ++ if ((!tnr_dmd) || (!pen)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x39, data, ++ sizeof(data)) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (!(data[0] & 0x01)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ *pen = ((data[1] << 8) | data[2]); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *ppm) ++{ ++ if ((!tnr_dmd) || (!ppm)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 ctl_val_reg[5]; ++ u8 nominal_rate_reg[5]; ++ u32 trl_ctl_val = 0; ++ u32 trcg_nominal_rate = 0; ++ int num; ++ int den; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ s8 diff_upper = 0; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (sync_state != 6) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x34, ++ ctl_val_reg, ++ sizeof(ctl_val_reg)) != ++ CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ nominal_rate_reg, ++ sizeof(nominal_rate_reg)) != ++ CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_HW_STATE; ++ ++ 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 CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *ppm) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ppm)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub, ppm); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *quality) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(tnr_dmd, &ber); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = cxd2880_tnrdmd_dvbt2_mon_snr(tnr_dmd, &snr); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA, ++ &code_rate); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256)) ++ return CXD2880_RESULT_ERROR_OTHER; ++ ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ts_rate_kbps) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[12]; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!ts_lock) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x23, data, ++ 12) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ rd_smooth_dp = (u32)((data[0] & 0x1F) << 24); ++ rd_smooth_dp |= (u32)(data[1] << 16); ++ rd_smooth_dp |= (u32)(data[2] << 8); ++ rd_smooth_dp |= (u32)data[3]; ++ ++ if (rd_smooth_dp < 214958) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ ep_ck_nume = (u32)((data[4] & 0x3F) << 24); ++ ep_ck_nume |= (u32)(data[5] << 16); ++ ep_ck_nume |= (u32)(data[6] << 8); ++ ep_ck_nume |= (u32)data[7]; ++ ++ ep_ck_deno = (u32)((data[8] & 0x3F) << 24); ++ ep_ck_deno |= (u32)(data[9] << 16); ++ ep_ck_deno |= (u32)(data[10] << 8); ++ ep_ck_deno |= (u32)data[11]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x41, data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd, ++ u32 *per) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u32 packet_error = 0; ++ u32 period = 0; ++ ++ if (!tnr_dmd || !per) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 rdata[3]; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x18, rdata, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((rdata[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ packet_error = (rdata[1] << 8) | rdata[2]; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x24) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xDC, rdata, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period = 1U << (rdata[0] & 0x0F); ++ } ++ ++ if ((period == 0) || (packet_error > period)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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; ++} ++ ++enum cxd2880_ret 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; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!qam)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, &l1_post_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(l1_post_ok & 0x01)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) { ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB6, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (data == 0) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB1, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ } else { ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x9E, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07); ++ ++ return ret; ++} ++ ++enum cxd2880_ret 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; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!code_rate)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, &l1_post_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(l1_post_ok & 0x01)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) { ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB6, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (data == 0) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB0, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ } else { ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x9D, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_profile ++ *profile) ++{ ++ if ((!tnr_dmd) || (!profile)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x22, &data, ++ sizeof(data)) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (data & 0x02) { ++ if (data & 0x01) ++ *profile = CXD2880_DVBT2_PROFILE_LITE; ++ else ++ *profile = CXD2880_DVBT2_PROFILE_BASE; ++ } else { ++ enum cxd2880_ret ret = CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->diver_mode == ++ CXD2880_TNRDMD_DIVERMODE_MAIN) ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_profile( ++ tnr_dmd->diver_sub, profile); ++ ++ return ret; ++ } ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret dvbt2_calc_sdi(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; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA, ++ &code_rate); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256)) ++ return CXD2880_RESULT_ERROR_OTHER; ++ ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *ssi) ++{ ++ int rf_lvl = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ssi)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt2_calc_sdi(tnr_dmd, rf_lvl, ssi); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *ssi) ++{ ++ int rf_lvl = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ssi)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt2_calc_sdi(tnr_dmd, rf_lvl, ssi); ++ if (ret != CXD2880_RESULT_OK) ++ 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 0000000000000000000000000000000000000000..784ad2844d1b06af8594c25f1f6f6b67ded9dc71 +--- /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 . ++ */ ++ ++#ifndef CXD2880_TNRDMD_DVBT2_MON_H ++#define CXD2880_TNRDMD_DVBT2_MON_H ++ ++#include "cxd2880_tnrdmd.h" ++#include "cxd2880_dvbt2.h" ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *sync_stat, ++ u8 *ts_lock_stat, ++ u8 *unlock_detected); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *sync_stat, ++ u8 *unlock_detected); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *offset); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *offset); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_l1pre ++ *l1_pre); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_version ++ *ver); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_ofdm *ofdm); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *plp_ids, ++ u8 *num_plps); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_dvbt2_plp_btype ++ type, ++ struct cxd2880_dvbt2_plp ++ *plp_info); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *plp_error); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *l1_change); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ struct cxd2880_dvbt2_l1post ++ *l1_post); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_plp_btype ++ type, ++ struct cxd2880_dvbt2_bbheader ++ *bbheader); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_dvbt2_plp_btype ++ type, ++ u32 *ts_rate_bps); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_spectrum_sense ++ *sense); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, ++ int *snr); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd ++ *tnr_dmd, int *snr, ++ int *snr_main, ++ int *snr_sub); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *fer); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ u32 *pen); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *ppm); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *ppm); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ts_rate_kbps); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *quality); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd, ++ u32 *per); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dvbt2_plp_btype type, ++ enum cxd2880_dvbt2_plp_constell ++ *qam); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_profile ++ *profile); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *ssi); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *ssi); ++ ++#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 0000000000000000000000000000000000000000..d890081b6424b51ddce4fc770a8ed94af14e153e +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c +@@ -0,0 +1,1190 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd_mon.h" ++#include "cxd2880_tnrdmd_dvbt.h" ++#include "cxd2880_tnrdmd_dvbt_mon.h" ++#include "cxd2880_math.h" ++ ++static enum cxd2880_ret is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *sync_stat, ++ u8 *ts_lock_stat, ++ u8 *unlock_detected) ++{ ++ u8 rdata = 0x00; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, &rdata, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *unlock_detected = (u8)((rdata & 0x10) ? 1 : 0); ++ *sync_stat = (u8)(rdata & 0x07); ++ *ts_lock_stat = (u8)((rdata & 0x20) ? 1 : 0); ++ ++ if (*sync_stat == 0x07) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *sync_stat, ++ u8 *unlock_detected) ++{ ++ u8 ts_lock_stat = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub, sync_stat, ++ &ts_lock_stat, unlock_detected); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt_mode ++ *mode, ++ enum cxd2880_dvbt_guard ++ *guard) ++{ ++ u8 rdata = 0x00; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!mode) || (!guard)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = is_tps_locked(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) { ++ 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; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, &rdata, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03); ++ *guard = (enum cxd2880_dvbt_guard)(rdata & 0x03); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *offset) ++{ ++ u8 rdata[4]; ++ u32 ctl_val = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!offset)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = is_tps_locked(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1D, rdata, ++ 4) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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) * (u8)tnr_dmd->bandwidth / 235); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *offset) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!offset)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub, offset); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber) ++{ ++ u8 rdata[2]; ++ u32 bit_error = 0; ++ u32 period = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ber)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x39, rdata, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if ((rdata[0] & 0x01) == 0) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x22, rdata, ++ 2) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ bit_error = (rdata[0] << 8) | rdata[1]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6F, rdata, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ period = ((rdata[0] & 0x07) == 0) ? 256 : (0x1000 << (rdata[0] & 0x07)); ++ ++ if ((period == 0) || (bit_error > period)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber) ++{ ++ u8 rdata[3]; ++ u32 bit_error = 0; ++ u32 period_exp = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ber)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x15, rdata, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((rdata[0] & 0x40) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ bit_error = ((rdata[0] & 0x3F) << 16) | (rdata[1] << 8) | rdata[2]; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, rdata, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period_exp = (rdata[0] & 0x1F); ++ ++ if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ struct cxd2880_dvbt_tpsinfo ++ *info) ++{ ++ u8 rdata[7]; ++ u8 cell_id_ok = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!info)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = is_tps_locked(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) { ++ 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; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x29, rdata, ++ 7) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x11) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xD5, &cell_id_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 = (u16)((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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ u32 *pen) ++{ ++ u8 rdata[3]; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!pen)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x26, rdata, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (!(rdata[0] & 0x01)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ *pen = (rdata[1] << 8) | rdata[2]; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_spectrum_sense ++ *sense) ++{ ++ u8 data = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!sense)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = is_tps_locked(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) { ++ 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; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1C, &data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *sense = ++ (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV : ++ CXD2880_TNRDMD_SPECTRUM_NORMAL; ++ ++ return ret; ++} ++ ++static enum cxd2880_ret dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, ++ u16 *reg_value) ++{ ++ u8 rdata[2]; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!reg_value)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = is_tps_locked(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x13, rdata, ++ 2) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *reg_value = (rdata[0] << 8) | rdata[1]; ++ ++ return ret; ++} ++ ++static enum cxd2880_ret dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, ++ u32 reg_value, int *snr) ++{ ++ if ((!tnr_dmd) || (!snr)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (reg_value == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (reg_value > 4996) ++ reg_value = 4996; ++ ++ *snr = ++ 10 * 10 * ((int)cxd2880_math_log10(reg_value) - ++ (int)cxd2880_math_log10(5350 - reg_value)); ++ *snr += 28500; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, ++ int *snr) ++{ ++ u16 reg_value = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!snr)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ *snr = -1000 * 1000; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { ++ ret = dvbt_read_snr_reg(tnr_dmd, ®_value); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt_calc_snr(tnr_dmd, reg_value, snr); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret 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; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ *snr = -1000 * 1000; ++ *snr_main = -1000 * 1000; ++ *snr_sub = -1000 * 1000; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = dvbt_read_snr_reg(tnr_dmd, ®_value); ++ if (ret == CXD2880_RESULT_OK) { ++ ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main); ++ if (ret != CXD2880_RESULT_OK) ++ reg_value = 0; ++ } else if (ret == CXD2880_RESULT_ERROR_HW_STATE) { ++ reg_value = 0; ++ } else { ++ return ret; ++ } ++ ++ reg_value_sum += reg_value; ++ ++ ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, ®_value); ++ if (ret == CXD2880_RESULT_OK) { ++ ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub); ++ if (ret != CXD2880_RESULT_OK) ++ reg_value = 0; ++ } else if (ret == CXD2880_RESULT_ERROR_HW_STATE) { ++ reg_value = 0; ++ } else { ++ return ret; ++ } ++ ++ reg_value_sum += reg_value; ++ ++ ret = dvbt_calc_snr(tnr_dmd, reg_value_sum, snr); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *ppm) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ppm)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ 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; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = is_tps_locked(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ ctl_val_reg, ++ sizeof(ctl_val_reg)) != ++ CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, ++ nominal_rate_reg, ++ sizeof(nominal_rate_reg)) != ++ CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_HW_STATE; ++ ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, int *ppm) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ppm)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm); ++ ++ return ret; ++} ++ ++enum cxd2880_ret 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} ++ } ++ }; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!quality)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) { ++ u8 data = 0; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x67, &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ profile = ++ ((data & 0x01) == ++ 0x01) ? CXD2880_DVBT_PROFILE_LP : CXD2880_DVBT_PROFILE_HP; ++ } ++ ++ ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(tnr_dmd, &ber); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = cxd2880_tnrdmd_dvbt_mon_snr(tnr_dmd, &sn); ++ if (ret != CXD2880_RESULT_OK) ++ 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 CXD2880_RESULT_ERROR_OTHER; ++ } ++ ++ if ((tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) && ++ (tps.constellation == CXD2880_DVBT_CONSTELLATION_QPSK)) ++ return CXD2880_RESULT_ERROR_OTHER; ++ ++ 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[(int)tps.hierarchy - ++ 1][(int)tps.constellation - ++ 1][tps.rate_lp]; ++ else ++ sn_rel = ++ sn - nordig_hier_hp_dvbt_db_1000[(int)tps.hierarchy - ++ 1][(int)tps.constellation - ++ 1][tps.rate_hp]; ++ ++ if (ber > 10000) { ++ ber_sqi = 0; ++ } else if (ber > 1) { ++ ber_sqi = (int)(10 * cxd2880_math_log10(ber)); ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd, ++ u32 *per) ++{ ++ u32 packet_error = 0; ++ u32 period = 0; ++ u8 rdata[3]; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!per)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x18, rdata, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((rdata[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ packet_error = (rdata[1] << 8) | rdata[2]; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x5C, rdata, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period = 1U << (rdata[0] & 0x0F); ++ ++ if ((period == 0) || (packet_error > period)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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 enum cxd2880_ret dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd, ++ int rf_lvl, u8 *ssi) ++{ ++ struct cxd2880_dvbt_tpsinfo tps; ++ int prel; ++ int temp_ssi = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) || ++ (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5)) ++ return CXD2880_RESULT_ERROR_OTHER; ++ ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *ssi) ++{ ++ int rf_lvl = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ssi)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *ssi) ++{ ++ int rf_lvl = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ssi)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return ret; ++} ++ ++static enum cxd2880_ret is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 sync = 0; ++ u8 tslock = 0; ++ u8 early_unlock = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock, ++ &early_unlock); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (sync != 6) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ return CXD2880_RESULT_OK; ++} +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 0000000000000000000000000000000000000000..486fc466272e762cd0f647296e2d818c8b28702c +--- /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 . ++ */ ++ ++#ifndef CXD2880_TNRDMD_DVBT_MON_H ++#define CXD2880_TNRDMD_DVBT_MON_H ++ ++#include "cxd2880_tnrdmd.h" ++#include "cxd2880_dvbt.h" ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *sync_stat, ++ u8 *ts_lock_stat, ++ u8 *unlock_detected); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *sync_stat, ++ u8 *unlock_detected); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt_mode ++ *mode, ++ enum cxd2880_dvbt_guard ++ *guard); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *offset); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *offset); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ struct cxd2880_dvbt_tpsinfo ++ *info); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ u32 *pen); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_spectrum_sense ++ *sense); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, ++ int *snr); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd ++ *tnr_dmd, int *snr, ++ int *snr_main, int *snr_sub); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *ppm); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *ppm); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *quality); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd, ++ u32 *per); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *ssi); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *ssi); ++ ++#endif +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 0000000000000000000000000000000000000000..0ac5b9bf3be803d5ea99c1aca67052142cfabff1 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c +@@ -0,0 +1,207 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_common.h" ++#include "cxd2880_tnrdmd_mon.h" ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd, ++ int *rf_lvl_db) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!rf_lvl_db)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2] = { 0x80, 0x00 }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x5B, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ CXD2880_SLEEP_IN_MON(2, tnr_dmd); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x1A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x15, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((data[0] != 0) || (data[1] != 0)) ++ return CXD2880_RESULT_ERROR_OTHER; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x11, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *rf_lvl_db = ++ cxd2880_convert2s_complement((data[0] << 3) | ++ ((data[1] & 0xE0) >> 5), 11); ++ } ++ ++ *rf_lvl_db *= 125; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->rf_lvl_cmpstn) { ++ ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ int *rf_lvl_db) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!rf_lvl_db)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd ++ *tnr_dmd, u16 *status) ++{ ++ u8 data[2] = { 0 }; ++ ++ if ((!tnr_dmd) || (!status)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x1A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x15, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *status = (u16)(((u16)data[0] << 8) | data[1]); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ u16 *status) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!status)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub, status); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd, ++ struct ++ cxd2880_tnrdmd_ts_buf_info ++ *info) ++{ ++ u8 data[3] = { 0 }; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!info)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x50, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ info->read_ready = (u8)((data[0] & 0x10) ? 0x01 : 0x00); ++ info->almost_full = (u8)((data[0] & 0x08) ? 0x01 : 0x00); ++ info->almost_empty = (u8)((data[0] & 0x04) ? 0x01 : 0x00); ++ info->overflow = (u8)((data[0] & 0x02) ? 0x01 : 0x00); ++ info->underflow = (u8)((data[0] & 0x01) ? 0x01 : 0x00); ++ ++ info->packet_num = (u16)(((u32)(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 0000000000000000000000000000000000000000..506bd559668ff39fb9ca14a3a423569df3239ad1 +--- /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 . ++ */ ++ ++#ifndef CXD2880_TNRDMD_MON_H ++#define CXD2880_TNRDMD_MON_H ++ ++#include "cxd2880_common.h" ++#include "cxd2880_tnrdmd.h" ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd, ++ int *rf_lvl_db); ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ int *rf_lvl_db); ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd ++ *tnr_dmd, u16 *status); ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ u16 *status); ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd, ++ struct ++ cxd2880_tnrdmd_ts_buf_info ++ *info); ++ ++#endif +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 0000000000000000000000000000000000000000..66d78fb93a13264f60f6e34904704644133ffd59 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c +@@ -0,0 +1,1550 @@ ++/* ++ * 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 . ++ */ ++ ++#include ++ ++#include "dvb_frontend.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 */ ++}; ++ ++/* ++ * return value conversion table ++ */ ++static int return_tbl[] = { ++ 0, /* CXD2880_RESULT_OK */ ++ -EINVAL, /* CXD2880_RESULT_ERROR_ARG*/ ++ -EIO, /* CXD2880_RESULT_ERROR_IO */ ++ -EPERM, /* CXD2880_RESULT_ERROR_SW_STATE */ ++ -EBUSY, /* CXD2880_RESULT_ERROR_HW_STATE */ ++ -ETIME, /* CXD2880_RESULT_ERROR_TIMEOUT */ ++ -EAGAIN, /* CXD2880_RESULT_ERROR_UNLOCK */ ++ -ERANGE, /* CXD2880_RESULT_ERROR_RANGE */ ++ -EOPNOTSUPP, /* CXD2880_RESULT_ERROR_NOSUPPORT */ ++ -ECANCELED, /* CXD2880_RESULT_ERROR_CANCEL */ ++ -EPERM, /* CXD2880_RESULT_ERROR_OTHER */ ++ -EOVERFLOW, /* CXD2880_RESULT_ERROR_OVERFLOW */ ++ 0, /* CXD2880_RESULT_OK_CONFIRM */ ++}; ++ ++static enum cxd2880_ret cxd2880_pre_bit_err_t( ++ struct cxd2880_tnrdmd *tnrdmd, u32 *pre_bit_err, ++ u32 *pre_bit_count) ++{ ++ u8 rdata[2]; ++ ++ if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnrdmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x10) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x39, rdata, 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if ((rdata[0] & 0x01) == 0) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x22, rdata, 2) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ *pre_bit_err = (rdata[0] << 8) | rdata[1]; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x6F, rdata, 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnrdmd); ++ ++ *pre_bit_count = ((rdata[0] & 0x07) == 0) ? ++ 256 : (0x1000 << (rdata[0] & 0x07)); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret 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]; ++ ++ if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnrdmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x3C, data, sizeof(data)) ++ != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(data[0] & 0x01)) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ *pre_bit_err = ++ ((data[1] & 0x0F) << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0xA0, data, 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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); ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x20) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x6F, data, 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period_exp = data[0] & 0x0F; ++ ++ *pre_bit_count = (1U << period_exp) * n_ldpc; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret 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; ++ ++ if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x0D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x15, rdata, 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((rdata[0] & 0x40) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ *post_bit_err = ((rdata[0] & 0x3F) << 16) | (rdata[1] << 8) | rdata[2]; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x60, rdata, 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period_exp = (rdata[0] & 0x1F); ++ ++ if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (period_exp == 11) ++ *post_bit_count = 3342336; ++ else ++ *post_bit_count = (1U << period_exp) * 204 * 81; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ 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} ++ }; ++ ++ if (slvt_freeze_reg(tnrdmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x15, data, 3) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(data[0] & 0x40)) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ *post_bit_err = ++ ((data[0] & 0x3F) << 16) | (data[1] << 8) | data[2]; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x9D, data, 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ plp_code_rate = ++ (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07); ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0xA0, data, 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03); ++ ++ slvt_unfreeze_reg(tnrdmd); ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x20) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x72, data, 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period_exp = data[0] & 0x0F; ++ ++ if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) || ++ (plp_code_rate > CXD2880_DVBT2_R2_5)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate]; ++ } ++ ++ if (*post_bit_err > ((1U << period_exp) * n_bch)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ *post_bit_count = (1U << period_exp) * n_bch; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret cxd2880_read_block_err_t( ++ struct cxd2880_tnrdmd *tnrdmd, ++ u32 *block_err, ++ u32 *block_count) ++{ ++ u8 rdata[3]; ++ ++ if ((!tnrdmd) || (!block_err) || (!block_count)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x0D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x18, rdata, 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((rdata[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ *block_err = (rdata[1] << 8) | rdata[2]; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x5C, rdata, 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *block_count = 1U << (rdata[0] & 0x0F); ++ ++ if ((*block_count == 0) || (*block_err > *block_count)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret cxd2880_read_block_err_t2( ++ struct cxd2880_tnrdmd *tnrdmd, ++ u32 *block_err, ++ u32 *block_count) ++{ ++ if ((!tnrdmd) || (!block_err) || (!block_count)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 rdata[3]; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x18, rdata, 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((rdata[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ *block_err = (rdata[1] << 8) | rdata[2]; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x24) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0xDC, rdata, 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *block_count = 1U << (rdata[0] & 0x0F); ++ } ++ ++ if ((*block_count == 0) || (*block_err > *block_count)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static void cxd2880_release(struct dvb_frontend *fe) ++{ ++ struct cxd2880_priv *priv = NULL; ++ ++ if (!fe) { ++ pr_err("%s: invalid arg.\n", __func__); ++ return; ++ } ++ priv = (struct cxd2880_priv *)fe->demodulator_priv; ++ kfree(priv); ++} ++ ++static int cxd2880_init(struct dvb_frontend *fe) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_priv *priv = NULL; ++ struct cxd2880_tnrdmd_create_param create_param; ++ ++ if (!fe) { ++ pr_err("%s: invalid arg.\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 != CXD2880_RESULT_OK) { ++ mutex_unlock(priv->spi_mutex); ++ dev_info(&priv->spi->dev, ++ "%s: cxd2880 tnrdmd create failed %d\n", ++ __func__, ret); ++ return return_tbl[ret]; ++ } ++ } ++ ret = cxd2880_integ_init(&priv->tnrdmd); ++ if (ret != CXD2880_RESULT_OK) { ++ mutex_unlock(priv->spi_mutex); ++ dev_err(&priv->spi->dev, "%s: cxd2880 integ init failed %d\n", ++ __func__, ret); ++ return return_tbl[ret]; ++ } ++ mutex_unlock(priv->spi_mutex); ++ ++ dev_dbg(&priv->spi->dev, "%s: OK.\n", __func__); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_sleep(struct dvb_frontend *fe) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_priv *priv = NULL; ++ ++ if (!fe) { ++ pr_err("%s: inavlid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_priv *)fe->demodulator_priv; ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd); ++ mutex_unlock(priv->spi_mutex); ++ ++ dev_dbg(&priv->spi->dev, "%s: tnrdmd_sleep ret %d\n", ++ __func__, ret); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_read_signal_strength(struct dvb_frontend *fe, ++ u16 *strength) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_priv *priv = NULL; ++ struct dtv_frontend_properties *c = NULL; ++ int level = 0; ++ ++ if ((!fe) || (!strength)) { ++ pr_err("%s: inavlid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 { ++ dev_dbg(&priv->spi->dev, "%s: invalid system\n", __func__); ++ 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 != CXD2880_RESULT_OK) ++ dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ int snrvalue = 0; ++ struct cxd2880_priv *priv = NULL; ++ struct dtv_frontend_properties *c = NULL; ++ ++ if ((!fe) || (!snr)) { ++ pr_err("%s: inavlid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 { ++ dev_err(&priv->spi->dev, "%s: invalid system\n", __func__); ++ mutex_unlock(priv->spi_mutex); ++ return -EINVAL; ++ } ++ mutex_unlock(priv->spi_mutex); ++ ++ if (snrvalue < 0) ++ snrvalue = 0; ++ *snr = (u16)snrvalue; ++ ++ if (ret != CXD2880_RESULT_OK) ++ dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_priv *priv = NULL; ++ struct dtv_frontend_properties *c = NULL; ++ ++ if ((!fe) || (!ucblocks)) { ++ pr_err("%s: inavlid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 { ++ dev_err(&priv->spi->dev, "%s: invlaid system\n", __func__); ++ mutex_unlock(priv->spi_mutex); ++ return -EINVAL; ++ } ++ mutex_unlock(priv->spi_mutex); ++ ++ if (ret != CXD2880_RESULT_OK) ++ dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_priv *priv = NULL; ++ struct dtv_frontend_properties *c = NULL; ++ ++ if ((!fe) || (!ber)) { ++ pr_err("%s: inavlid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 { ++ dev_err(&priv->spi->dev, "%s: invlaid system\n", __func__); ++ mutex_unlock(priv->spi_mutex); ++ return -EINVAL; ++ } ++ mutex_unlock(priv->spi_mutex); ++ ++ if (ret != CXD2880_RESULT_OK) ++ dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_set_frontend(struct dvb_frontend *fe) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct dtv_frontend_properties *c; ++ struct cxd2880_priv *priv; ++ enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; ++ ++ if (!fe) { ++ pr_err("%s: inavlid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_priv *)fe->demodulator_priv; ++ c = &fe->dtv_property_cache; ++ ++ 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; ++ } ++ ++ dev_info(&priv->spi->dev, "%s: sys:%d freq:%d bw:%d\n", __func__, ++ 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); ++ } 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; ++ ret = cxd2880_integ_dvbt2_tune(&priv->tnrdmd, ++ &priv->dvbt2_tune_param); ++ } else { ++ dev_err(&priv->spi->dev, "%s: invalid system\n", __func__); ++ mutex_unlock(priv->spi_mutex); ++ return -EINVAL; ++ } ++ mutex_unlock(priv->spi_mutex); ++ dev_info(&priv->spi->dev, "%s: tune result %d\n", __func__, ret); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_read_status(struct dvb_frontend *fe, ++ enum fe_status *status) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 { ++ dev_err(&priv->spi->dev, ++ "%s: invlaid system", __func__); ++ mutex_unlock(priv->spi_mutex); ++ return -EINVAL; ++ } ++ ++ mutex_unlock(priv->spi_mutex); ++ if (ret != CXD2880_RESULT_OK) { ++ dev_err(&priv->spi->dev, "%s: failed. sys = %d\n", ++ __func__, priv->tnrdmd.sys); ++ return return_tbl[ret]; ++ } ++ ++ if (sync == 6) { ++ *status = FE_HAS_SIGNAL | ++ FE_HAS_CARRIER; ++ } ++ if (lock) ++ *status |= FE_HAS_VITERBI | ++ FE_HAS_SYNC | ++ FE_HAS_LOCK; ++ } ++ ++ dev_dbg(&priv->spi->dev, "%s: status %d result %d\n", __func__, ++ *status, ret); ++ ++ return return_tbl[CXD2880_RESULT_OK]; ++} ++ ++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("%s: invalid arg.", __func__); ++ return -EINVAL; ++ } ++ ++ if (retune) { ++ ret = cxd2880_set_frontend(fe); ++ if (ret) { ++ pr_err("%s: cxd2880_set_frontend failed %d\n", ++ __func__, 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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ int result = 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; ++ 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; ++ ++ if ((!fe) || (!c)) { ++ pr_err("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, "%s: get invalid mode %d\n", ++ __func__, 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; ++ dev_err(&priv->spi->dev, "%s: get invalid guard %d\n", ++ __func__, guard); ++ break; ++ } ++ } else { ++ c->transmission_mode = TRANSMISSION_MODE_2K; ++ c->guard_interval = GUARD_INTERVAL_1_32; ++ dev_dbg(&priv->spi->dev, ++ "%s: ModeGuard err %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, ++ "%s: TPSInfo hierarchy invalid %d\n", ++ __func__, 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; ++ dev_err(&priv->spi->dev, ++ "%s: TPSInfo rateHP invalid %d\n", ++ __func__, 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; ++ dev_err(&priv->spi->dev, ++ "%s: TPSInfo rateLP invalid %d\n", ++ __func__, 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; ++ dev_err(&priv->spi->dev, ++ "%s: TPSInfo constellation invalid %d\n", ++ __func__, tps.constellation); ++ break; ++ } ++ } else { ++ c->hierarchy = HIERARCHY_NONE; ++ c->code_rate_HP = FEC_NONE; ++ c->code_rate_LP = FEC_NONE; ++ c->modulation = QPSK; ++ dev_dbg(&priv->spi->dev, ++ "%s: TPS info err %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, ++ "%s: spectrum sense invalid %d\n", ++ __func__, sense); ++ break; ++ } ++ } else { ++ c->inversion = INVERSION_OFF; ++ dev_dbg(&priv->spi->dev, ++ "%s: spectrum_sense %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, "%s: mon_rf_lvl %d\n", ++ __func__, result); ++ } ++ ++ result = cxd2880_read_snr(fe, &snr); ++ if (!result) { ++ 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; ++ dev_dbg(&priv->spi->dev, "%s: read_snr %d\n", __func__, result); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_pre_bit_err_t(&priv->tnrdmd, &pre_bit_err, ++ &pre_bit_count); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: pre_bit_error_t failed %d\n", ++ __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_post_bit_err_t(&priv->tnrdmd, ++ &post_bit_err, &post_bit_count); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: post_bit_err_t %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_read_block_err_t(&priv->tnrdmd, ++ &block_err, &block_count); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: read_block_err_t %d\n", __func__, ret); ++ } ++ ++ return 0; ++} ++ ++static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, ++ struct dtv_frontend_properties *c) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ int result = 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; ++ 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; ++ ++ if ((!fe) || (!c)) { ++ pr_err("%s: invalid arg.\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, ++ "%s: L1Pre fft_mode invalid %d\n", ++ __func__, 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; ++ dev_err(&priv->spi->dev, ++ "%s: L1Pre gi invalid %d\n", ++ __func__, l1pre.gi); ++ break; ++ } ++ } else { ++ c->transmission_mode = TRANSMISSION_MODE_2K; ++ c->guard_interval = GUARD_INTERVAL_1_32; ++ dev_dbg(&priv->spi->dev, ++ "%s: L1Pre err %d\n", __func__, 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 == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, ++ "%s: CodeRate invalid %d\n", ++ __func__, coderate); ++ break; ++ } ++ } else { ++ c->fec_inner = FEC_NONE; ++ dev_dbg(&priv->spi->dev, "%s: CodeRate %d\n", __func__, 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 == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, ++ "%s: QAM invalid %d\n", ++ __func__, qam); ++ break; ++ } ++ } else { ++ c->modulation = QPSK; ++ dev_dbg(&priv->spi->dev, "%s: QAM %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, ++ "%s: spectrum sense invalid %d\n", ++ __func__, sense); ++ break; ++ } ++ } else { ++ c->inversion = INVERSION_OFF; ++ dev_dbg(&priv->spi->dev, ++ "%s: SpectrumSense %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: mon_rf_lvl %d\n", __func__, ret); ++ } ++ ++ result = cxd2880_read_snr(fe, &snr); ++ if (!result) { ++ 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; ++ dev_dbg(&priv->spi->dev, "%s: read_snr %d\n", __func__, result); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd, ++ &pre_bit_err, ++ &pre_bit_count); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: read_bit_err_t2 %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_post_bit_err_t2(&priv->tnrdmd, ++ &post_bit_err, &post_bit_count); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: post_bit_err_t2 %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_read_block_err_t2(&priv->tnrdmd, ++ &block_err, &block_count); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: read_block_err_t2 %d\n", __func__, ret); ++ } ++ ++ return 0; ++} ++ ++static int cxd2880_get_frontend(struct dvb_frontend *fe, ++ struct dtv_frontend_properties *props) ++{ ++ struct cxd2880_priv *priv = NULL; ++ int result = 0; ++ ++ if ((!fe) || (!props)) { ++ pr_err("%s: invalid arg.", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_priv *)fe->demodulator_priv; ++ ++ dev_dbg(&priv->spi->dev, "%s: system=%d\n", __func__, ++ fe->dtv_property_cache.delivery_system); ++ switch (fe->dtv_property_cache.delivery_system) { ++ case SYS_DVBT: ++ result = cxd2880_get_frontend_t(fe, props); ++ break; ++ case SYS_DVBT2: ++ result = cxd2880_get_frontend_t2(fe, props); ++ break; ++ default: ++ result = -EINVAL; ++ break; ++ } ++ ++ return result; ++} ++ ++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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ enum cxd2880_tnrdmd_chip_id chipid = ++ CXD2880_TNRDMD_CHIP_ID_UNKNOWN; ++ static struct cxd2880_priv *priv; ++ u8 data = 0; ++ ++ if (!fe) { ++ pr_err("%s: invalid arg.\n", __func__); ++ 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 != CXD2880_RESULT_OK) { ++ dev_err(&priv->spi->dev, ++ "%s: spi_device_initialize failed. %d\n", ++ __func__, ret); ++ kfree(priv); ++ return NULL; ++ } ++ ++ ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi, ++ &priv->spi_device); ++ if (ret != CXD2880_RESULT_OK) { ++ dev_err(&priv->spi->dev, ++ "%s: spi_device_create_spi failed. %d\n", ++ __func__, ret); ++ kfree(priv); ++ return NULL; ++ } ++ ++ ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0); ++ if (ret != CXD2880_RESULT_OK) { ++ dev_err(&priv->spi->dev, ++ "%s: io_spi_create failed. %d\n", __func__, ret); ++ kfree(priv); ++ return NULL; ++ } ++ if (priv->regio.write_reg(&priv->regio, CXD2880_IO_TGT_SYS, 0x00, 0x00) ++ != CXD2880_RESULT_OK) { ++ dev_err(&priv->spi->dev, ++ "%s: set bank to 0x00 failed.\n", __func__); ++ kfree(priv); ++ return NULL; ++ } ++ if (priv->regio.read_regs(&priv->regio, ++ CXD2880_IO_TGT_SYS, 0xFD, &data, 1) ++ != CXD2880_RESULT_OK) { ++ dev_err(&priv->spi->dev, ++ "%s: read chip id failed.\n", __func__); ++ 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)) { ++ dev_err(&priv->spi->dev, ++ "%s: chip id invalid.\n", __func__); ++ kfree(priv); ++ return NULL; ++ } ++ ++ fe->demodulator_priv = priv; ++ dev_info(&priv->spi->dev, ++ "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"); +diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig +index a21f5a39a440fe64a98f6bc04879fef65d753292..b07ac86fc53c782cf0980fc86f07d09bb5df0e40 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 +diff --git a/drivers/media/spi/Makefile b/drivers/media/spi/Makefile +index ea64013d16cc7eda7424ed6684240e99b685e2cb..40e0f88d9f6c84a6ca6cfbd23d30102eabefd4e1 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 +diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c +new file mode 100644 +index 0000000000000000000000000000000000000000..82e122349055be817eb74ed5bbcd7560485bc448 +--- /dev/null ++++ b/drivers/media/spi/cxd2880-spi.c +@@ -0,0 +1,728 @@ ++/* ++ * 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 . ++ */ ++ ++#include ++ ++#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("%s: invalid arg\n", __func__); ++ 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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ if (size > BURST_WRITE_MAX) { ++ pr_err("%s: data size > WRITE_MAX\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (subAddress + size > 0x100) { ++ pr_err("%s: out of range\n", __func__); ++ 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) { ++ dev_err(&spi->dev, "%s: write spi failed %d\n", ++ __func__, 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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ if (packet_num > 0xFFFF) { ++ dev_err(&spi->dev, "%s: packet num > 0xFFFF\n", __func__); ++ return -EINVAL; ++ } ++ ++ data[0] = 0x10; ++ data[1] = (u8)((packet_num >> 8) & 0xFF); ++ data[2] = (u8)(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) ++ dev_err(&spi->dev, "%s: spi_write_then_read failed\n", ++ __func__); ++ ++ 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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ ret = spi_write_then_read(spi, &send_data, 1, ++ recv_data, sizeof(recv_data)); ++ if (ret) ++ dev_err(&spi->dev, ++ "%s: spi_write_then_read failed\n", __func__); ++ ++ info->read_ready = (u8)((recv_data[0] & 0x80) ? 1 : 0); ++ info->almost_full = (u8)((recv_data[0] & 0x40) ? 1 : 0); ++ info->almost_empty = (u8)((recv_data[0] & 0x20) ? 1 : 0); ++ info->overflow = (u8)((recv_data[0] & 0x10) ? 1 : 0); ++ info->underflow = (u8)((recv_data[0] & 0x08) ? 1 : 0); ++ info->packet_num = (u16)(((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("%s: write spi failed\n", __func__); ++ ++ return ret; ++} ++ ++static int cxd2880_set_pid_filter(struct spi_device *spi, ++ struct cxd2880_pid_filter_config *cfg) ++{ ++ u8 data[65]; ++ ++ if (!spi) { ++ pr_err("%s: ivnalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ data[0] = 0x00; ++ if (cxd2880_write_reg(spi, 0x00, &data[0], 1) != 0) ++ return -EIO; ++ if (!cfg) { ++ data[0] = 0x02; ++ if (cxd2880_write_reg(spi, 0x50, &data[0], 1) != 0) ++ return -EIO; ++ } else { ++ data[0] = (u8)(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)] = ++ (u8)((u8)(pid >> 8) | 0x20); ++ data[2 + (i * 2)] = ++ (u8)(pid & 0xFF); ++ } else { ++ data[1 + (i * 2)] = 0x00; ++ data[2 + (i * 2)] = 0x00; ++ } ++ } ++ } ++ if (cxd2880_write_reg(spi, 0x50, data, 65) != 0) ++ return -EIO; ++ } ++ ++ 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("%s: invalid arg.\n", __func__); ++ 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) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: set_pid_filter failed\n", __func__); ++ } ++ ++ return ret; ++} ++ ++static int cxd2880_ts_read(void *arg) ++{ ++ struct cxd2880_dvb_spi *dvb_spi = NULL; ++ struct cxd2880_ts_buf_info info; ++ struct timespec ts; ++ long elapsed = 0; ++ long starttime = 0; ++ u32 i; ++ int ret; ++ ++ dvb_spi = (struct cxd2880_dvb_spi *)arg; ++ if (!dvb_spi) { ++ pr_err("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ ret = cxd2880_spi_clear_ts_buffer(dvb_spi->spi); ++ if (ret) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: set_clear_ts_buffer failed\n", __func__); ++ return ret; ++ } ++ ++ getnstimeofday(&ts); ++ starttime = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); ++ while (!kthread_should_stop()) { ++ getnstimeofday(&ts); ++ elapsed = ++ ((ts.tv_sec * 1000) + (ts.tv_nsec / 1000000)) ++ - starttime; ++ ret = cxd2880_spi_read_ts_buffer_info(dvb_spi->spi, ++ &info); ++ if (ret) { ++ pr_err("%s: spi_read_ts_buffer_info error\n", ++ __func__); ++ 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); ++ } ++ starttime = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); ++ } 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); ++ starttime = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); ++ } 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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ demux = feed->demux; ++ if (!demux) { ++ pr_err("%s: feed->demux is NULL\n", __func__); ++ return -EINVAL; ++ } ++ dvb_spi = (struct cxd2880_dvb_spi *)demux->priv; ++ ++ if (dvb_spi->feed_count == CXD2880_MAX_FILTER_SIZE) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: Exceeded maximum PID count (32).", __func__); ++ dev_err(&dvb_spi->spi->dev, ++ "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) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: update pid filter failed\n", ++ __func__); ++ return ret; ++ } ++ } ++ dvb_spi->all_pid_feed_count++; ++ ++ dev_dbg(&dvb_spi->spi->dev, ++ "%s: all PID feed (count = %d)\n", ++ __func__, 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; ++ dev_dbg(&dvb_spi->spi->dev, ++ "%s: store PID %d to #%d\n", ++ __func__, feed->pid, i); ++ break; ++ } ++ } ++ if (i == CXD2880_MAX_FILTER_SIZE) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: PID filter is full. Assumed bug.\n", ++ __func__); ++ 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(sizeof(u8) * MAX_TRANS_PACKET * 188, ++ GFP_KERNEL | GFP_DMA); ++ if (!dvb_spi->ts_buf) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: ts buffer allocate failed\n", __func__); ++ 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)) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: kthread_run failed/\n", ++ __func__); ++ 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++; ++ ++ dev_dbg(&dvb_spi->spi->dev, "%s: start feed (count %d)\n", ++ __func__, 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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ demux = feed->demux; ++ if (!demux) { ++ pr_err("%s: feed->demux is NULL\n", __func__); ++ return -EINVAL; ++ } ++ dvb_spi = (struct cxd2880_dvb_spi *)demux->priv; ++ ++ if (!dvb_spi->feed_count) { ++ dev_warn(&dvb_spi->spi->dev, ++ "%s: no feed is started\n", __func__); ++ 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) { ++ dev_warn(&dvb_spi->spi->dev, ++ "%s: PID %d not found.\n", ++ __func__, 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; ++ dev_dbg(&dvb_spi->spi->dev, ++ "%s: removed PID %d from #%d\n", ++ __func__, feed->pid, i); ++ break; ++ } ++ } ++ dvb_spi->filter_config = cfgtmp; ++ ++ if (i == CXD2880_MAX_FILTER_SIZE) { ++ dev_warn(&dvb_spi->spi->dev, "%s: PID %d not found\n", ++ __func__, 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) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: cxd2880_ts_read thread didn't terminate normally\n", ++ __func__); ++ ret = ret_stop; ++ } ++ kfree(dvb_spi->ts_buf); ++ dvb_spi->ts_buf = NULL; ++ } ++ ++ dev_dbg(&dvb_spi->spi->dev, "%s: stop feed ok.(count %d)\n", ++ __func__, 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("%s: invalid arg.\n", __func__); ++ 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) { ++ dev_err(&spi->dev, "%s: dvb_register_adapter() failed\n", ++ __func__); ++ goto fail_adapter; ++ } ++ ++ if (!dvb_attach(cxd2880_attach, &dvb_spi->dvb_fe, &config)) { ++ dev_err(&spi->dev, "%s: cxd2880_attach failed\n", __func__); ++ goto fail_attach; ++ } ++ ++ ret = dvb_register_frontend(&dvb_spi->adapter, ++ &dvb_spi->dvb_fe); ++ if (ret < 0) { ++ dev_err(&spi->dev, "%s: dvb_register_frontend() failed\n", ++ __func__); ++ 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) { ++ dev_err(&spi->dev, "%s: dvb_dmx_init() failed\n", __func__); ++ 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) { ++ dev_err(&spi->dev, "%s: dvb_dmxdev_init() failed\n", __func__); ++ 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) { ++ dev_err(&spi->dev, "%s: add_frontend() failed\n", __func__); ++ goto fail_dmx_fe; ++ } ++ ++ ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx, ++ &dvb_spi->dmx_fe); ++ if (ret < 0) { ++ dev_err(&spi->dev, "%s: dvb_register_frontend() failed\n", ++ __func__); ++ goto fail_fe_conn; ++ } ++ ++ dev_info(&spi->dev, "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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ dvb_spi = (struct cxd2880_dvb_spi *)dev_get_drvdata(&spi->dev); ++ ++ if (!dvb_spi) { ++ pr_err("%s: failed\n", __func__); ++ 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); ++ dev_info(&spi->dev, "%s: cxd2880_spi remove ok.\n", __func__); ++ ++ 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"); + +From cd562c1037bd813c368aa493b6b08a952a23b749 Mon Sep 17 00:00:00 2001 +From: Yasunari Takiguchi +Date: Thu, 22 Dec 2016 15:34:12 +0900 +Subject: [PATCH 225/229] BCM2708: Add Raspberry Pi TV HAT Device Tree Support + +This is an EXAMPLE CODE of Raspberry Pi TV HAT device tree overlay. +Although this is not a part of our release code, it has been used to verify +CXD2880 device driver with TV HAT. + +Add the following line to /boot/config.txt to enable TV HAT: + +dtoverlay=rpi-tv + +Reboot Raspberry Pi and check the existance of /proc/device-tree/soc/spi@7e204000/cxd2880@0. +If exists, the installation is successful. you should be able to find the following three files. +/dev/dvb/adapter0/frontend0 +/dev/dvb/adapter0/demux0 +/dev/dvb/adapter0/dvr0 + +Signed-off-by: Yasunari Takiguchi +Signed-off-by: Masayuki Yamamoto +Signed-off-by: Hideki Nozawa +Signed-off-by: Kota Yonezawa +Signed-off-by: Toshihiko Matsumoto +Signed-off-by: Satoshi Watanabe +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 6 ++++++ + arch/arm/boot/dts/overlays/rpi-tv-overlay.dts | 31 +++++++++++++++++++++++++++ + 3 files changed, 38 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/rpi-tv-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index b64dd7ac0630b2b525809a9f5221420f34a58ac9..e2f66a55dc5afe13d690c2c17827054ac94b7168 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -81,6 +81,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + rpi-ft5406.dtbo \ + rpi-proto.dtbo \ + rpi-sense.dtbo \ ++ rpi-tv.dtbo \ + rra-digidac1-wm8741-audio.dtbo \ + sc16is750-i2c.dtbo \ + sc16is752-spi1.dtbo \ +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 1377e5b8e8363c3e0ede318ce54bd784cb70d4c9..e2a803e5180cf78d67b6723cfd2f6d3b2b54e53b 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1142,6 +1142,12 @@ Load: dtoverlay=rpi-sense + Params: + + ++Name: rpi-tv ++Info: Raspberry Pi TV HAT ++Load: dtoverlay=rpi-tv ++Params: ++ ++ + Name: rra-digidac1-wm8741-audio + Info: Configures the Red Rocks Audio DigiDAC1 soundcard + Load: dtoverlay=rra-digidac1-wm8741-audio +diff --git a/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts b/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts +new file mode 100644 +index 0000000000000000000000000000000000000000..a68f6f793d8efd8b2e2adf9f2fb6426f61ff464a +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts +@@ -0,0 +1,31 @@ ++// rpi-tv HAT ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ ++ spidev@0 { ++ status = "disabled"; ++ }; ++ ++ cxd2880@0 { ++ compatible = "sony,cxd2880"; ++ reg = <0>; /* CE0 */ ++ spi-max-frequency = <50000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++}; + +From fca54639764bcd86afde246c8ac1985b491a1a2d Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 12 Apr 2017 17:52:56 -0700 +Subject: [PATCH 226/229] panel-raspberrypi-touchscreen: Fix NULL deref if + probe order goes wrong. + +If the i2c driver hadn't pobed before the panel driver probes, then +the client would be NULL but we were looking for an ERR_PTR in the +error case. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +index 7f315f04b109621ca7f3861fdd8acf956e752629..b57b7ad9aa4c5048186e98553af59ec912973096 100644 +--- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c ++++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +@@ -404,6 +404,9 @@ static struct i2c_client *rpi_touchscreen_get_i2c(struct device *dev, + + of_node_put(node); + ++ if (!client) ++ return ERR_PTR(-EPROBE_DEFER); ++ + return client; + } + + +From f26f9c061858b0badf738961cf0b934b31433f78 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Wed, 19 Apr 2017 09:59:21 -0700 +Subject: [PATCH 227/229] smsc75xx: use skb_cow_head() to deal with cloned skbs + +We need to ensure there is enough headroom to push extra header, +but we also need to check if we are allowed to change headers. + +skb_cow_head() is the proper helper to deal with this. + +Fixes: d0cad871703b ("smsc75xx: SMSC LAN75xx USB gigabit ethernet adapter driver") +Signed-off-by: Eric Dumazet +Cc: James Hughes +Signed-off-by: David S. Miller +--- + drivers/net/usb/smsc75xx.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c +index 9af9799935dbbd4baed06eb03402803e0ce8d9c8..4cb9b11a545a9572ab6d248742ec5abee00fa7e4 100644 +--- a/drivers/net/usb/smsc75xx.c ++++ b/drivers/net/usb/smsc75xx.c +@@ -2205,13 +2205,9 @@ static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev, + { + u32 tx_cmd_a, tx_cmd_b; + +- if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) { +- struct sk_buff *skb2 = +- skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags); ++ if (skb_cow_head(skb, SMSC75XX_TX_OVERHEAD)) { + dev_kfree_skb_any(skb); +- skb = skb2; +- if (!skb) +- return NULL; ++ return NULL; + } + + tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN) | TX_CMD_A_FCS; + +From 19b7bd935e3ef6f5bbd9429c5c487c07ce4593a1 Mon Sep 17 00:00:00 2001 +From: James Hughes +Date: Wed, 19 Apr 2017 11:13:40 +0100 +Subject: [PATCH 228/229] smsc95xx: Use skb_cow_head to deal with cloned skbs + +The driver was failing to check that the SKB wasn't cloned +before adding checksum data. +Replace existing handling to extend/copy the header buffer +with skb_cow_head. + +Signed-off-by: James Hughes +Acked-by: Eric Dumazet +Acked-by: Woojung Huh +Signed-off-by: David S. Miller +--- + drivers/net/usb/smsc95xx.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c +index df60c989fc229bf0aab3c27e95ccd45323367840..f6661e388f6e801c1b88e48a3b71407bd70cf56e 100644 +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -2067,13 +2067,13 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, + /* We do not advertise SG, so skbs should be already linearized */ + BUG_ON(skb_shinfo(skb)->nr_frags); + +- if (skb_headroom(skb) < overhead) { +- struct sk_buff *skb2 = skb_copy_expand(skb, +- overhead, 0, flags); ++ /* Make writable and expand header space by overhead if required */ ++ if (skb_cow_head(skb, overhead)) { ++ /* Must deallocate here as returning NULL to indicate error ++ * means the skb won't be deallocated in the caller. ++ */ + dev_kfree_skb_any(skb); +- skb = skb2; +- if (!skb) +- return NULL; ++ return NULL; + } + + if (csum) { + +From b629887de7c80ed000a78e290ca4daca5e7c312f Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 24 Apr 2017 18:26:52 +0100 +Subject: [PATCH 229/229] i2c-bcm2835: Ignore unexpected interrupt + +--- + drivers/i2c/busses/i2c-bcm2835.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c +index 8642f580ce41803bd22c76a0fa80d083d0747be1..47167f403cc8329bd811b47c7011c299b8ecafee 100644 +--- a/drivers/i2c/busses/i2c-bcm2835.c ++++ b/drivers/i2c/busses/i2c-bcm2835.c +@@ -279,7 +279,9 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) + } + + if (val & BCM2835_I2C_S_DONE) { +- if (i2c_dev->curr_msg->flags & I2C_M_RD) { ++ if (!i2c_dev->curr_msg) { ++ dev_err(i2c_dev->dev, "Got unexpected interrupt (from firmware?)\n"); ++ } else if (i2c_dev->curr_msg->flags & I2C_M_RD) { + bcm2835_drain_rxfifo(i2c_dev); + val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); + } diff --git a/projects/RPi2/linux/linux.arm.conf b/projects/RPi2/linux/linux.arm.conf index 6d71483c4c..353a1852a2 100644 --- a/projects/RPi2/linux/linux.arm.conf +++ b/projects/RPi2/linux/linux.arm.conf @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 4.9.20 Kernel Configuration +# Linux/arm 4.9.24 Kernel Configuration # CONFIG_ARM=y CONFIG_ARM_HAS_SG_CHAIN=y @@ -2566,6 +2566,11 @@ CONFIG_VIDEO_CX25840=m # # Sensors used on soc_camera driver # + +# +# Media SPI Adapters +# +CONFIG_CXD2880_SPI_DRV=m CONFIG_MEDIA_TUNER=m CONFIG_MEDIA_TUNER_SIMPLE=m CONFIG_MEDIA_TUNER_TDA8290=m diff --git a/projects/RPi2/patches/linux/linux-01-RPi_support.patch b/projects/RPi2/patches/linux/linux-01-RPi_support.patch index 4a8a74abea..3e05740020 100644 --- a/projects/RPi2/patches/linux/linux-01-RPi_support.patch +++ b/projects/RPi2/patches/linux/linux-01-RPi_support.patch @@ -1,7 +1,7 @@ -From ace6fd3ca18068ece94afeee6eddb8d190ea8c79 Mon Sep 17 00:00:00 2001 +From cb8066936db1d23446c81d21d6b4bb55056acc30 Mon Sep 17 00:00:00 2001 From: Steve Glendinning Date: Thu, 19 Feb 2015 18:47:12 +0000 -Subject: [PATCH 001/220] smsx95xx: fix crimes against truesize +Subject: [PATCH 001/229] smsx95xx: fix crimes against truesize smsc95xx is adjusting truesize when it shouldn't, and following a recent patch from Eric this is now triggering warnings. @@ -48,10 +48,10 @@ index 831aa33d078ae7d2dd57fdded5de71d1eb915f99..b77935bded8c0ff7808b00f170ff10e5 usbnet_skb_return(dev, ax_skb); } -From 77227dfd51d9f6cb24da1ee9fce7c29d8fdd26d8 Mon Sep 17 00:00:00 2001 +From 32919b70d04f9735170481b00f6ba04a12a40895 Mon Sep 17 00:00:00 2001 From: Sam Nazarko Date: Fri, 1 Apr 2016 17:27:21 +0100 -Subject: [PATCH 002/220] smsc95xx: Experimental: Enable turbo_mode and +Subject: [PATCH 002/229] smsc95xx: Experimental: Enable turbo_mode and packetsize=2560 by default See: http://forum.kodi.tv/showthread.php?tid=285288 @@ -94,10 +94,10 @@ index b77935bded8c0ff7808b00f170ff10e594300ad0..693f163684de921404738e33244881e0 netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n", -From bfcc45ab8ec29eddf9068f709e19a71c0750ca35 Mon Sep 17 00:00:00 2001 +From e4dd221bccc5aa86f27569bf87c623972e11df63 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 003/220] Allow mac address to be set in smsc95xx +Subject: [PATCH 003/229] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -193,10 +193,10 @@ index 693f163684de921404738e33244881e0aab92ec9..df60c989fc229bf0aab3c27e95ccd453 eth_hw_addr_random(dev->net); netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); -From 5c7af355f2985972bffc0c547818bc67bd9f2d47 Mon Sep 17 00:00:00 2001 +From b94bb3ddcf5368a84e9dc00864dd63dd8cae8b58 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 13 Mar 2015 12:43:36 +0000 -Subject: [PATCH 004/220] Protect __release_resource against resources without +Subject: [PATCH 004/229] Protect __release_resource against resources without parents Without this patch, removing a device tree overlay can crash here. @@ -224,10 +224,10 @@ index 9b5f04404152c296af3a96132f27cfc80ffa9af9..f8a9af6e6b915812be2ba2c1c2b40106 for (;;) { tmp = *p; -From 8b39431fedbaa4e15cc8187416649b679aa88517 Mon Sep 17 00:00:00 2001 +From 9269e1fb3edbbe45407f327ec8192095795e2894 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 18 Dec 2014 16:07:15 -0800 -Subject: [PATCH 005/220] mm: Remove the PFN busy warning +Subject: [PATCH 005/229] mm: Remove the PFN busy warning See commit dae803e165a11bc88ca8dbc07a11077caf97bbcb -- the warning is expected sometimes when using CMA. However, that commit still spams @@ -239,7 +239,7 @@ Signed-off-by: Eric Anholt 1 file changed, 2 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 1460e6ad5e141788edea4b4ea3a294352d788af1..69dc54cf662fbac6b67af7bdfb7b7a41deb78d06 100644 +index e5b159b88e3968857c2b02d4c6bb0589a83930b3..84271c72e2b98ab0135908776cb220c790a9cd4c 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -7323,8 +7323,6 @@ int alloc_contig_range(unsigned long start, unsigned long end, @@ -252,10 +252,10 @@ index 1460e6ad5e141788edea4b4ea3a294352d788af1..69dc54cf662fbac6b67af7bdfb7b7a41 goto done; } -From 73f0130d019611fe110d734bd94cb5384140f035 Mon Sep 17 00:00:00 2001 +From a3d0748addb1db79bf2938b2f73f2787c8142c0d Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 4 Dec 2015 17:41:50 +0000 -Subject: [PATCH 006/220] irq-bcm2836: Prevent spurious interrupts, and trap +Subject: [PATCH 006/229] irq-bcm2836: Prevent spurious interrupts, and trap them early The old arch-specific IRQ macros included a dsb to ensure the @@ -282,10 +282,10 @@ index d96b2c947e74e3edab3917551c64fbd1ced0f34c..93e3f7660c4230c9f1dd3b195958cb49 #endif } else if (stat) { -From 2ccd0c4c9b5fb75670cb506403c52b1b1fe38d9d Mon Sep 17 00:00:00 2001 +From ef009f2619a7cef201c14af374391cbe2bb804b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 12 Jun 2015 19:01:05 +0200 -Subject: [PATCH 007/220] irqchip: bcm2835: Add FIQ support +Subject: [PATCH 007/229] irqchip: bcm2835: Add FIQ support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -414,10 +414,10 @@ index 44d7c38dde479d771f3552e914bf8c1c1f5019f7..42ff5e6a8e0d532f5b60a1e7af7cc4d9 } -From 0e091203819ee3c24cb7d9ef27fda64160b0cee5 Mon Sep 17 00:00:00 2001 +From 62aaeef510e9438692129b3dddcbf42f0329736d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Oct 2015 16:26:55 +0200 -Subject: [PATCH 008/220] irqchip: irq-bcm2835: Add 2836 FIQ support +Subject: [PATCH 008/229] irqchip: irq-bcm2835: Add 2836 FIQ support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -516,10 +516,10 @@ index 42ff5e6a8e0d532f5b60a1e7af7cc4d941bd5008..eccf6ed025299cb480884f5bcbe77abf for (b = 0; b < NR_BANKS; b++) { for (i = 0; i < bank_irqs[b]; i++) { -From 1f36307a91673999b54a458708660828bbb57e87 Mon Sep 17 00:00:00 2001 +From 2cbc1ae91a761b3d13e536207025681a6f9b07aa Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 10:26:09 +0100 -Subject: [PATCH 009/220] spidev: Add "spidev" compatible string to silence +Subject: [PATCH 009/229] spidev: Add "spidev" compatible string to silence warning See: https://github.com/raspberrypi/linux/issues/1054 @@ -540,10 +540,10 @@ index 2e05046f866bd01bf87edcdeff0d5b76d4d0aea7..d780491b8013a4e97fa843958964454e }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); -From 098c16955ecffe714b0b9c8a1e71155a39be354c Mon Sep 17 00:00:00 2001 +From cbf8e59e110417902cc0a33d80846e92668d0959 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 30 Jun 2015 14:12:42 +0100 -Subject: [PATCH 010/220] serial: 8250: Don't crash when nr_uarts is 0 +Subject: [PATCH 010/229] serial: 8250: Don't crash when nr_uarts is 0 --- drivers/tty/serial/8250/8250_core.c | 2 ++ @@ -563,10 +563,10 @@ index e8819aa20415603c80547e382838a8fa3ce54792..cf9c7d2e3f95e1a19410247a89c2e49c for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; -From 4f351bb67f89906f34b83cc9fa32223e8e9e9887 Mon Sep 17 00:00:00 2001 +From cd51d76d165de45326a6dd1c2de3bfe7bf1cae3f Mon Sep 17 00:00:00 2001 From: notro Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 011/220] pinctrl-bcm2835: Set base to 0 give expected gpio +Subject: [PATCH 011/229] pinctrl-bcm2835: Set base to 0 give expected gpio numbering Signed-off-by: Noralf Tronnes @@ -588,10 +588,10 @@ index fa77165fab2c1348163979da507df17e7168c49b..d11e2e4ea189466e686d762cb6c6fef9 .can_sleep = false, }; -From f9b822f58271c75e81a9354f1167dc719f9a233d Mon Sep 17 00:00:00 2001 +From 3c9de5fca5b74c711b41abe6b6395b1f37c65892 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 24 Feb 2015 13:40:50 +0000 -Subject: [PATCH 012/220] pinctrl-bcm2835: Fix interrupt handling for GPIOs +Subject: [PATCH 012/229] pinctrl-bcm2835: Fix interrupt handling for GPIOs 28-31 and 46-53 Contrary to the documentation, the BCM2835 GPIO controller actually has @@ -737,10 +737,10 @@ index d11e2e4ea189466e686d762cb6c6fef9111ecf8e..107ad7d58de8f8a7f55e09c9cdcf7d66 }, }; -From d2dc0ee0513fbcdd90576a0765e061dc29b8067c Mon Sep 17 00:00:00 2001 +From feeffef9b6523e4435355de13920f47d01e0b4d8 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 26 Feb 2015 09:58:22 +0000 -Subject: [PATCH 013/220] pinctrl-bcm2835: Only request the interrupts listed +Subject: [PATCH 013/229] pinctrl-bcm2835: Only request the interrupts listed in the DTB Although the GPIO controller can generate three interrupts (four counting @@ -767,10 +767,10 @@ index 107ad7d58de8f8a7f55e09c9cdcf7d66fa7ab66b..644bdecbcfcb79d3b84a33769265fca5 pc->irq_data[i].irqgroup = i; -From e4d48693d7cf2b97fc189e4344ec3f09c333903d Mon Sep 17 00:00:00 2001 +From ff925faea8508f57604e78ee21a1025e748c47f0 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 May 2016 12:32:47 +0100 -Subject: [PATCH 014/220] pinctrl-bcm2835: Return pins to inputs when freed +Subject: [PATCH 014/229] pinctrl-bcm2835: Return pins to inputs when freed When dynamically unloading overlays, it is important that freed pins are restored to being inputs to prevent functions from being enabled in @@ -811,10 +811,10 @@ index 644bdecbcfcb79d3b84a33769265fca5d3d0c9e5..81a66cba2ab0f7e3ae179de7edd10122 .get_function_name = bcm2835_pmx_get_function_name, .get_function_groups = bcm2835_pmx_get_function_groups, -From ca1600077e78e1a5cde5e329aa2aaa8b4261453a Mon Sep 17 00:00:00 2001 +From 0f7a0e45617c0f98ed82c08971d26b95597b8988 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 24 Jun 2015 14:10:44 +0100 -Subject: [PATCH 015/220] spi-bcm2835: Support pin groups other than 7-11 +Subject: [PATCH 015/229] spi-bcm2835: Support pin groups other than 7-11 The spi-bcm2835 driver automatically uses GPIO chip-selects due to some unreliability of the native ones. In doing so it chooses the @@ -895,10 +895,10 @@ index f35cc10772f6670397ea923ad30158270dd68578..5dfe20ffc2866fa6789825016c585175 /* and set up the "mode" and level */ dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n", -From aa8c3ce9cad4a9c450f305b25bf6e099fc788102 Mon Sep 17 00:00:00 2001 +From ff0aa7f8e9c8f79130dc2f63b87156683b1b54b1 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 1 Jul 2016 22:09:24 +0100 -Subject: [PATCH 016/220] spi-bcm2835: Disable forced software CS +Subject: [PATCH 016/229] spi-bcm2835: Disable forced software CS Select software CS in bcm2708_common.dtsi, and disable the automatic conversion in the driver to allow hardware CS to be re-enabled with an @@ -932,10 +932,10 @@ index 5dfe20ffc2866fa6789825016c585175a29705b6..8493474d286f7a1ac6454a22c61c8c2c return 0; } -From d13a1d0c1b9ae58ff0cd262d8d79ce4c4ef342d2 Mon Sep 17 00:00:00 2001 +From 770219991e8e487d9eda05b0aff7d2977b4ba56b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 8 Nov 2016 21:35:38 +0000 -Subject: [PATCH 017/220] spi-bcm2835: Remove unused code +Subject: [PATCH 017/229] spi-bcm2835: Remove unused code --- drivers/spi/spi-bcm2835.c | 61 ----------------------------------------------- @@ -1023,10 +1023,10 @@ index 8493474d286f7a1ac6454a22c61c8c2cef9121bf..33d75ad38a7f77d085321ace9101900a } -From c893ea9baa610d6c6348d7628279c77679055d97 Mon Sep 17 00:00:00 2001 +From 6fab21d4b1999469dbf9d4a8428f38fffe98dea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 3 Jun 2015 12:26:13 +0200 -Subject: [PATCH 018/220] ARM: bcm2835: Set Serial number and Revision +Subject: [PATCH 018/229] ARM: bcm2835: Set Serial number and Revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -1079,10 +1079,10 @@ index 0c1edfc98696da0e0bb7f4a18cdfbcdd27a9795d..8f152266ba9b470df2eaaed9ebcf158e static const char * const bcm2835_compat[] = { -From e997f981519f0c1b0d922cf3b893fb799f7f4686 Mon Sep 17 00:00:00 2001 +From fae16613c032abcd4e39076a1ba35b1d5828a783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sat, 3 Oct 2015 22:22:55 +0200 -Subject: [PATCH 019/220] dmaengine: bcm2835: Load driver early and support +Subject: [PATCH 019/229] dmaengine: bcm2835: Load driver early and support legacy API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -1185,10 +1185,10 @@ index e18dc596cf2447fa9ef7e41b62d9396e29043426..80d35f760b4a4a51e60c355a84d538ba MODULE_ALIAS("platform:bcm2835-dma"); MODULE_DESCRIPTION("BCM2835 DMA engine driver"); -From a0a01cf3fd1469a6b94a16d21aa7cfb61d02d7cb Mon Sep 17 00:00:00 2001 +From bec04405036485dd65f6fc47e84348ae853562af Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 25 Jan 2016 17:25:12 +0000 -Subject: [PATCH 020/220] firmware: Updated mailbox header +Subject: [PATCH 020/229] firmware: Updated mailbox header --- include/soc/bcm2835/raspberrypi-firmware.h | 11 +++++++++++ @@ -1251,10 +1251,10 @@ index 3fb357193f09914fe21f8555a4b8613f74f22bc3..227a107214a02deadcca3db202da265e RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, -From c7b70d7bf562b9611f342862653ad7f68fa9e0c6 Mon Sep 17 00:00:00 2001 +From 82f922d58232d082f55ad3b710f82c3210b35683 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 9 May 2016 17:28:18 -0700 -Subject: [PATCH 021/220] clk: bcm2835: Mark GPIO clocks enabled at boot as +Subject: [PATCH 021/229] clk: bcm2835: Mark GPIO clocks enabled at boot as critical. These divide off of PLLD_PER and are used for the ethernet and wifi @@ -1292,10 +1292,10 @@ index 2acaa77ad482a99f28ea64ea43c891501125304c..d13cbbf5bbe06314bfdf103ff85d5cd7 init.ops = &bcm2835_vpu_clock_clk_ops; } else { -From 70bd41a7fa143e6083f8e6fda573ccc8b11d5de0 Mon Sep 17 00:00:00 2001 +From 5cd10e36b0a4b7a94c019db2595ca6a196c7e8ca Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 15 Jun 2016 16:48:41 +0100 -Subject: [PATCH 022/220] rtc: Add SPI alias for pcf2123 driver +Subject: [PATCH 022/229] rtc: Add SPI alias for pcf2123 driver Without this alias, Device Tree won't cause the driver to be loaded. @@ -1315,10 +1315,10 @@ index 8895f77726e8da5444afcd602dceff8f25a9b3fd..1833b8853ceb0e6147cceb93a00e558c MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:rtc-pcf2123"); -From ea7d87c6e8212f5559000d9471f9e87169797430 Mon Sep 17 00:00:00 2001 +From 441b7b516839ee78346d0fd9278e4b2ebdf8ae2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 7 Oct 2016 16:50:59 +0200 -Subject: [PATCH 023/220] watchdog: bcm2835: Support setting reboot partition +Subject: [PATCH 023/229] watchdog: bcm2835: Support setting reboot partition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -1442,10 +1442,10 @@ index 4dddd8298a227d64862f2e92954a465f2e44b3f6..1f545e024422f59280932713e6a1b051 register_restart_handler(&wdt->restart_handler); if (pm_power_off == NULL) -From 639060b6afee11534ce54ab416abeb0ed7fd6965 Mon Sep 17 00:00:00 2001 +From e15fd788eff11cf229e0049e075a6a3a956398a8 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 5 Apr 2016 19:40:12 +0100 -Subject: [PATCH 024/220] reboot: Use power off rather than busy spinning when +Subject: [PATCH 024/229] reboot: Use power off rather than busy spinning when halt is requested --- @@ -1468,10 +1468,10 @@ index 3fa867a2aae672755c6ce6448f4148c989dbf964..80dca8dcd6709034b643c6a3f35729e0 /* -From c020700a444e1e3ed5db75038f9b6c299b890e64 Mon Sep 17 00:00:00 2001 +From 6665032094afa9ac298d8f60d8b900169d545509 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 9 Nov 2016 13:02:52 +0000 -Subject: [PATCH 025/220] bcm: Make RASPBERRYPI_POWER depend on PM +Subject: [PATCH 025/229] bcm: Make RASPBERRYPI_POWER depend on PM --- drivers/soc/bcm/Kconfig | 1 + @@ -1490,10 +1490,10 @@ index a39b0d58ddd0fdf0ac1cc7295f8aafb12546e226..e037a6dd79d1881a09e3ca9115782709 help This enables support for the RPi power domains which can be enabled -From a2bda2acba829767aeead5be052c7b6eee905d97 Mon Sep 17 00:00:00 2001 +From 5151700add5effb47213ab307c1e67a0cdee9c0c Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Fri, 2 Sep 2016 16:45:27 +0100 -Subject: [PATCH 026/220] Register the clocks early during the boot process, so +Subject: [PATCH 026/229] Register the clocks early during the boot process, so that special/critical clocks can get enabled early on in the boot process avoiding the risk of disabling a clock, pll_divider or pll when a claiming driver fails to install propperly - maybe it needs to defer. @@ -1538,10 +1538,10 @@ index d13cbbf5bbe06314bfdf103ff85d5cd73cbf7f7a..a99ccf9f056d3a3e7c482339e08483f3 MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("BCM2835 clock driver"); -From f8fdbafbd1b8a67f07ae454be34e61e9e420998a Mon Sep 17 00:00:00 2001 +From 107b440406fad9cfec531d1c67921047d96bcb14 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 6 Dec 2016 17:05:39 +0000 -Subject: [PATCH 027/220] bcm2835-rng: Avoid initialising if already enabled +Subject: [PATCH 027/229] bcm2835-rng: Avoid initialising if already enabled Avoids the 0x40000 cycles of warmup again if firmware has already used it --- @@ -1567,10 +1567,10 @@ index 574211a495491d9d6021dcaefe4274a63ed02055..e66c0fca8c6090e32f72796c0877a1cf err = hwrng_register(&bcm2835_rng_ops); if (err) { -From d917a5b2280fe48ef807f0c67b23fa8f55fb7687 Mon Sep 17 00:00:00 2001 +From 878e5404accdb54a7dbdb04fca64fd388b519c27 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 24 Aug 2016 16:28:44 +0100 -Subject: [PATCH 028/220] kbuild: Ignore dtco targets when filtering symbols +Subject: [PATCH 028/229] kbuild: Ignore dtco targets when filtering symbols --- scripts/Kbuild.include | 2 +- @@ -1590,10 +1590,10 @@ index 179219845dfcdfbeb586d12c5ec1296095d9fbf4..e0743e44f84188667a0c322e8c3d36f1 esac | tr ";" "\n" | sed -rn 's/^.*=== __KSYM_(.*) ===.*$$/KSYM_\1/p' -From e668d477605548f3bda8ccaaa3d8cfde214ef748 Mon Sep 17 00:00:00 2001 +From 01111f91ba6ca8650464a2d63be3a5efbecc286b Mon Sep 17 00:00:00 2001 From: Robert Tiemann Date: Mon, 20 Jul 2015 11:01:25 +0200 -Subject: [PATCH 029/220] BCM2835_DT: Fix I2S register map +Subject: [PATCH 029/229] BCM2835_DT: Fix I2S register map --- Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt | 4 ++-- @@ -1631,10 +1631,10 @@ index 65783de0aedf3da79adc36fd077b7a89954ddb6b..a89fe4220fdc3f26f75ee66daf187554 dmas = <&dma 2>, <&dma 3>; -From 79b139ddbe668e2f2b05d54b3caa01ac837cc01f Mon Sep 17 00:00:00 2001 +From fc3efa2b58407f9120532a75a0eb31e3d946e324 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 030/220] Main bcm2708/bcm2709 linux port +Subject: [PATCH 030/229] Main bcm2708/bcm2709 linux port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -1841,10 +1841,10 @@ index cfb4b4496dd9f61362dea012176c146120fada07..d9c6c217c4d6a2408abe2665bf7f2700 MODULE_AUTHOR("Lubomir Rintel "); MODULE_DESCRIPTION("BCM2835 mailbox IPC driver"); -From 255056f5891a55df23e6bd9b6239022cb30c9806 Mon Sep 17 00:00:00 2001 +From e6b0c3acbc8ed89dec1a97037fda008a0d65c554 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 031/220] Add dwc_otg driver +Subject: [PATCH 031/229] Add dwc_otg driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -2546,10 +2546,10 @@ index 358ca8dd784fe43700ae070764fa783500a792fe..abaac7c7142d8887c1516957fc52162c return i; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index c28ccf1b5a1fe285044024fff3f70bf9ae7cc91f..0e65cb92d12eb9645ddc21b902cd8b141cafef47 100644 +index 35fb2bef0e45971568dbbafd2699fe0b1d3a4e5b..28d781209de161d4dd02ee9dcf2b86e43c8858a3 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c -@@ -5009,7 +5009,7 @@ static void port_event(struct usb_hub *hub, int port1) +@@ -5016,7 +5016,7 @@ static void port_event(struct usb_hub *hub, int port1) if (portchange & USB_PORT_STAT_C_OVERCURRENT) { u16 status = 0, unused; @@ -62901,10 +62901,10 @@ index 0000000000000000000000000000000000000000..cdc9963176e5a4a0d5250613b61e26c5 +test_main(); +0; -From e4ae0eb3bfe63196bb9577dda90d44b377fff72b Mon Sep 17 00:00:00 2001 +From 720b024065112322f1f8d8adad09e24d9b8b3a33 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 17:06:34 +0100 -Subject: [PATCH 032/220] bcm2708 framebuffer driver +Subject: [PATCH 032/229] bcm2708 framebuffer driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -66363,10 +66363,10 @@ index 3c14e43b82fefe1d32f591d1b2f61d2cd28d0fa8..7626beb6a5bb8df601ddf0f6e6909d1f +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 -From 1c2a6d9e3cfab206f4a7f9498a30bb38d39eb3d1 Mon Sep 17 00:00:00 2001 +From 5170d3020760803904fb33f948a08e3f2fe9c99a Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 033/220] dmaengine: Add support for BCM2708 +Subject: [PATCH 033/229] dmaengine: Add support for BCM2708 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -66997,10 +66997,10 @@ index 0000000000000000000000000000000000000000..c5bfff2765be4606077e6c8af73040ec + +#endif /* _PLAT_BCM2708_DMA_H */ -From fdc5c1e17bb8cdaa612dde04bbd1b6b3f5636686 Mon Sep 17 00:00:00 2001 +From 65050c0d8eee5ee8951136cf37ab79a16714a439 Mon Sep 17 00:00:00 2001 From: gellert Date: Fri, 15 Aug 2014 16:35:06 +0100 -Subject: [PATCH 034/220] MMC: added alternative MMC driver +Subject: [PATCH 034/229] MMC: added alternative MMC driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -68750,10 +68750,10 @@ index 0000000000000000000000000000000000000000..4fe8d1fe44578fbefcd48f8c327ba3d0 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gellert Weisz"); -From e47f0fe40ec129cab52f07ad0c315d37a2d57fe2 Mon Sep 17 00:00:00 2001 +From 11a2ec26cc0c9a4a901683bcc5db431495785c73 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 25 Mar 2015 17:49:47 +0000 -Subject: [PATCH 035/220] Adding bcm2835-sdhost driver, and an overlay to +Subject: [PATCH 035/229] Adding bcm2835-sdhost driver, and an overlay to enable it BCM2835 has two SD card interfaces. This driver uses the other one. @@ -71158,10 +71158,10 @@ index 0000000000000000000000000000000000000000..a9bc79bfdbb71807819dfe2d8f165144 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Phil Elwell"); -From 5fcecb8e60f05180c91e2a18b779d5c8461ab620 Mon Sep 17 00:00:00 2001 +From 2d193c7dae8a2303209a2fe91fda9ae8533c5f20 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 11 May 2016 12:50:33 +0100 -Subject: [PATCH 036/220] mmc: Add MMC_QUIRK_ERASE_BROKEN for some cards +Subject: [PATCH 036/229] mmc: Add MMC_QUIRK_ERASE_BROKEN for some cards Some SD cards have been found that corrupt data when small blocks are erased. Add a quirk to indicate that ERASE should not be used, @@ -71297,10 +71297,10 @@ index 73fad83acbcb6a157587180516f9ffe7c61eb7d7..e7c9d3098ac06e3c6554fa3373a311f9 unsigned int erase_shift; /* if erase unit is power 2 */ unsigned int pref_erase; /* in sectors */ -From f7c278edaa5dc994fb610ccf72ba33c340925972 Mon Sep 17 00:00:00 2001 +From bf2cb577cae2292835fa1b23d6a7bc4e6e57cd83 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 037/220] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 037/229] cma: Add vc_cma driver to enable use of CMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -71332,7 +71332,7 @@ Signed-off-by: Noralf Trønnes create mode 100644 include/linux/broadcom/vc_cma.h diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index dcc09739a54ef860343ac2fca5acf59724ca60e2..6d518c7635ae128f4554945dd3ffd351f9d325bf 100644 +index 8453a49471d72aee4f1c30c7cf7fd5d11e9975ba..5e5924a51ff56d314af315e0198bd61aece084f1 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -4,6 +4,8 @@ @@ -72636,10 +72636,10 @@ index 0000000000000000000000000000000000000000..be2819d5d41f9d5ed65daf8eedb94c9e + +#endif /* VC_CMA_H */ -From a38618ea5e2cc3f84de75fa11b46725b178f1810 Mon Sep 17 00:00:00 2001 +From 007cc2317a385a0ee577ad7c10ae670445961824 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 038/220] bcm2708: alsa sound driver +Subject: [PATCH 038/229] bcm2708: alsa sound driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -75374,10 +75374,10 @@ index 0000000000000000000000000000000000000000..af3e6eb690113fc32ce9e06bd2f0f294 + +#endif // _VC_AUDIO_DEFS_H_ -From cd2ed566ba3b675d81f8ba3cfd8bd4c116e391b7 Mon Sep 17 00:00:00 2001 +From d65ea31e609388eda13399b5d76fa78b83962c0a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 28 Oct 2016 15:36:43 +0100 -Subject: [PATCH 039/220] vc_mem: Add vc_mem driver for querying firmware +Subject: [PATCH 039/229] vc_mem: Add vc_mem driver for querying firmware memory addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -75901,10 +75901,10 @@ index 0000000000000000000000000000000000000000..20a475377eb3078ea1ecaef2b24efc35 + +#endif /* _VC_MEM_H */ -From 3bca045578853ff455fa5aa9ce3cb6625a72da10 Mon Sep 17 00:00:00 2001 +From 6ec4aeb958e0f4369097c42dee73a2e3ea56acd2 Mon Sep 17 00:00:00 2001 From: Tim Gover Date: Tue, 22 Jul 2014 15:41:04 +0100 -Subject: [PATCH 040/220] vcsm: VideoCore shared memory service for BCM2835 +Subject: [PATCH 040/229] vcsm: VideoCore shared memory service for BCM2835 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -80311,10 +80311,10 @@ index 0000000000000000000000000000000000000000..334f36d0d697b047df2922b5f2db67f3 + +#endif /* __VMCS_SM_IOCTL_H__INCLUDED__ */ -From 7e2f2a04538763e7af2b66b2ef6e301c9f402590 Mon Sep 17 00:00:00 2001 +From 50677b57028c716da928d1f37ee2660d7f047986 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Fri, 21 Aug 2015 23:14:48 +0100 -Subject: [PATCH 041/220] Add /dev/gpiomem device for rootless user GPIO access +Subject: [PATCH 041/229] Add /dev/gpiomem device for rootless user GPIO access Signed-off-by: Luke Wren @@ -80625,10 +80625,10 @@ index 0000000000000000000000000000000000000000..911f5b7393ed48ceed8751f06967ae64 +MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace"); +MODULE_AUTHOR("Luke Wren "); -From 372c91d3d0d0a137618fa4df8ad8d076bc7229f4 Mon Sep 17 00:00:00 2001 +From 37c315c77e0854a6f0d0cbd59e59b423b2dafbd5 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 5 Sep 2015 01:14:45 +0100 -Subject: [PATCH 042/220] Add SMI driver +Subject: [PATCH 042/229] Add SMI driver Signed-off-by: Luke Wren --- @@ -82579,10 +82579,10 @@ index 0000000000000000000000000000000000000000..ee3a75edfc033eeb0d90a687ffb68b10 + +#endif /* BCM2835_SMI_H */ -From f3f809a8023342dd2dd4bfb36c4a6b99e34aeb20 Mon Sep 17 00:00:00 2001 +From c45bdc33fcdc9b8fc27f73e5856a0cda534c6df1 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Tue, 26 Apr 2016 14:59:21 +0000 -Subject: [PATCH 043/220] MISC: bcm2835: smi: use clock manager and fix reload +Subject: [PATCH 043/229] MISC: bcm2835: smi: use clock manager and fix reload issues Use clock manager instead of self-made clockmanager. @@ -82752,10 +82752,10 @@ index 63a4ea08b9930a3a31a985f0a1d969b488ed49ec..1261540703127d1d63b9f3c87042c6e5 return 0; } -From f2bfd53319709e8d543eb7ae3dc4d59ae3908093 Mon Sep 17 00:00:00 2001 +From 04f085b20286938b2edbaee180d154792ed2c8b3 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 5 Sep 2015 01:16:10 +0100 -Subject: [PATCH 044/220] Add SMI NAND driver +Subject: [PATCH 044/229] Add SMI NAND driver Signed-off-by: Luke Wren --- @@ -83120,10 +83120,10 @@ index 0000000000000000000000000000000000000000..02adda6da18bd0ba9ab19a104975b79d + ("Driver for NAND chips using Broadcom Secondary Memory Interface"); +MODULE_AUTHOR("Luke Wren "); -From 30a6c2c5267914444f95d7c70b56318deca21efb Mon Sep 17 00:00:00 2001 +From 703a412e030de0a175b587b44bc0738354de2e4c Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 045/220] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 045/229] lirc: added support for RaspberryPi GPIO lirc_rpi: Use read_current_timer to determine transmitter delay. Thanks to jjmz and others See: https://github.com/raspberrypi/linux/issues/525 @@ -83986,10 +83986,10 @@ index 0000000000000000000000000000000000000000..fb69624ccef00ddbdccf8256d6baf1b1 + +#endif -From b74ad641f8868ca5d3c3aef7baea0ae1f03ec341 Mon Sep 17 00:00:00 2001 +From 3a261e33ae9c95d3772670611169ac85607b5be9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 046/220] Add cpufreq driver +Subject: [PATCH 046/229] Add cpufreq driver Signed-off-by: popcornmix --- @@ -84256,10 +84256,10 @@ index 0000000000000000000000000000000000000000..414fbdc10dfbfc6e4bb47870a7af3fd5 +module_init(bcm2835_cpufreq_module_init); +module_exit(bcm2835_cpufreq_module_exit); -From 20e4a967e3f3b88d63e3d7c46c8198afd6581bd2 Mon Sep 17 00:00:00 2001 +From c1737e0db817d17df8147e80d45eeb095e27a7a9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 047/220] Added hwmon/thermal driver for reporting core +Subject: [PATCH 047/229] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -84425,10 +84425,10 @@ index 0000000000000000000000000000000000000000..c63fb9f9d143e19612a18fe530c7b2b3 +MODULE_DESCRIPTION("Thermal driver for bcm2835 chip"); +MODULE_LICENSE("GPL"); -From e485d7218d11ef86bf03a948c3df1dd6e2264683 Mon Sep 17 00:00:00 2001 +From f73a86da3d30b9a334b262026ddfe87bfd9ae8c1 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 17 Jun 2015 15:44:08 +0100 -Subject: [PATCH 048/220] Add Chris Boot's i2c driver +Subject: [PATCH 048/229] Add Chris Boot's i2c driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -85093,10 +85093,10 @@ index 0000000000000000000000000000000000000000..962f2e5c7455d91bf32925d785f5f16b +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From a867b62a2fc6e866a52d3742894727045a15cc67 Mon Sep 17 00:00:00 2001 +From 1db902a5f1e80f377cf093db330ad9617375ea45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:27:06 +0200 -Subject: [PATCH 049/220] char: broadcom: Add vcio module +Subject: [PATCH 049/229] char: broadcom: Add vcio module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -85322,10 +85322,10 @@ index 0000000000000000000000000000000000000000..c19bc2075c77879563ef5e59038b5a14 +MODULE_DESCRIPTION("Mailbox userspace access"); +MODULE_LICENSE("GPL"); -From c3895f611eafd3c731d2964df1581f07fb2f9522 Mon Sep 17 00:00:00 2001 +From 53ce66f55753253f3e9adcec3d59640e1c797560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 26 Jun 2015 14:25:01 +0200 -Subject: [PATCH 050/220] firmware: bcm2835: Support ARCH_BCM270x +Subject: [PATCH 050/229] firmware: bcm2835: Support ARCH_BCM270x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -85408,10 +85408,10 @@ index dd506cd3a5b874f9e1acd07efb8cd151bb6145d1..3f070bd38a91511c986e3fb114b15bd4 MODULE_AUTHOR("Eric Anholt "); MODULE_DESCRIPTION("Raspberry Pi firmware driver"); -From 0bd5079a80dd6bc9c593e13e52b8e64ef9b79da5 Mon Sep 17 00:00:00 2001 +From 9ae97b240e6285f7a47b6d5aa1a13aa01609f3ad Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 051/220] bcm2835: add v4l2 camera device +Subject: [PATCH 051/229] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -93153,10 +93153,10 @@ index 0000000000000000000000000000000000000000..9d1d11e4a53e510c04a416d92d195a7d + +#endif /* MMAL_VCHIQ_H */ -From 201640f5760f1d84cf0b8a8a49d695809f78e365 Mon Sep 17 00:00:00 2001 +From a15ffe27fd20c8835a1404679e70e0a6f4c312a6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 11 May 2015 09:00:42 +0100 -Subject: [PATCH 052/220] scripts: Add mkknlimg and knlinfo scripts from tools +Subject: [PATCH 052/229] scripts: Add mkknlimg and knlinfo scripts from tools repo The Raspberry Pi firmware looks for a trailer on the kernel image to @@ -93676,10 +93676,10 @@ index 0000000000000000000000000000000000000000..60206de7fa9a49bd027c635306674a29 + return $trailer; +} -From 75eaa71803c4d693ae6a2c8e0b4e5510f036c1f2 Mon Sep 17 00:00:00 2001 +From 03ab2da6d25acf5c13aab3dba565e9ad498ef0b4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 10 Aug 2015 09:49:15 +0100 -Subject: [PATCH 053/220] scripts/dtc: Update to upstream version 1.4.1 +Subject: [PATCH 053/229] scripts/dtc: Update to upstream version 1.4.1 Includes the new localfixups format. @@ -96530,10 +96530,10 @@ index ad9b05ae698b0495ecbda42ffcf4743555313a27..2595dfda020fd9e03f0beff5006f229d -#define DTC_VERSION "DTC 1.4.1-g53bf130b" +#define DTC_VERSION "DTC 1.4.1-g25efc119" -From 7cea97bde2fb5a4958335b884aee20a5d5f03262 Mon Sep 17 00:00:00 2001 +From 8ade2c47ccf954e386bfec5ff051435975a669dc Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:46:08 +0200 -Subject: [PATCH 054/220] BCM2708: Add core Device Tree support +Subject: [PATCH 054/229] BCM2708: Add core Device Tree support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -106661,10 +106661,10 @@ index 0a07f9014944ed92a8e2e42983ae43be60b3e471..1967878a843461c3ff1f473b9a030eb0 # Bzip2 -From 2294dcf5e531118e721e9a4ff946aa7eaa1de06d Mon Sep 17 00:00:00 2001 +From a1262117d6c9ed2e113a57eb004ac3b0bbfb138c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 Feb 2015 13:50:57 +0000 -Subject: [PATCH 055/220] BCM270x_DT: Add pwr_led, and the required "input" +Subject: [PATCH 055/229] BCM270x_DT: Add pwr_led, and the required "input" trigger The "input" trigger makes the associated GPIO an input. This is to support @@ -106840,10 +106840,10 @@ index ddfcb2df3656cf0ab6aebd1fa3d624a6ec2e94e9..271563eb835f9018712e2076a88f341d /* Set LED brightness level * Must not sleep. Use brightness_set_blocking for drivers -From 2ba877036465a3cd0848a8bf576650e01575571f Mon Sep 17 00:00:00 2001 +From 71d39d01810797ce92e8f29cf824a64d2e8104d8 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 056/220] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 056/229] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -107095,10 +107095,10 @@ index fb795c3b3c178ad3cd7c9e9e4547ffd492bac181..703fa8a70574323abe2fb32599254582 __u32 dx; /* screen-relative */ __u32 dy; -From 051268acb9fcf7b4bbd5fa81a46af4989c419b27 Mon Sep 17 00:00:00 2001 +From d75614a783a4c69c60d7b19bcf141f8503bcfa22 Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 057/220] Speed up console framebuffer imageblit function +Subject: [PATCH 057/229] Speed up console framebuffer imageblit function Especially on platforms with a slower CPU but a relatively high framebuffer fill bandwidth, like current ARM devices, the existing @@ -107307,10 +107307,10 @@ index a2bb276a8b2463eee98eb237c4647bc00cd93601..436494fba15abecb400ef28688466faf start_index, pitch_index); } else -From aa6d09ed8941a36181549e9a273d5c2be4a3210e Mon Sep 17 00:00:00 2001 +From 5797ce2ede3c2df641c6a9e70d410b2f2b098911 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 058/220] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 058/229] enabling the realtime clock 1-wire chip DS1307 and 1-wire on GPIO4 (as a module) 1-wire: Add support for configuring pin for w1-gpio kernel module @@ -107560,10 +107560,10 @@ index d58594a3232492e33f1dd4babd3798b03e0f0203..feae94256256316fd9d850c3d83325af unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; -From 26d60ab559d4ea92afc001308765d4c3f07be640 Mon Sep 17 00:00:00 2001 +From cc604f99ccdffe1276d5031294f69a660b01c638 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 059/220] config: Enable CONFIG_MEMCG, but leave it disabled +Subject: [PATCH 059/229] config: Enable CONFIG_MEMCG, but leave it disabled (due to memory cost). Enable with cgroup_enable=memory. --- @@ -107571,10 +107571,10 @@ Subject: [PATCH 059/220] config: Enable CONFIG_MEMCG, but leave it disabled 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c -index 4e2f3de0e40bff4caef5ee9c587ea19140d07f85..4b687fba53c58e744e04608a9510f9b811f26343 100644 +index a3d2aad2443f3314396d25086d891eca22317cf8..45db7dee21858fc80e571f463717e51afce4262c 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c -@@ -5626,7 +5626,7 @@ int __init cgroup_init_early(void) +@@ -5627,7 +5627,7 @@ int __init cgroup_init_early(void) return 0; } @@ -107583,7 +107583,7 @@ index 4e2f3de0e40bff4caef5ee9c587ea19140d07f85..4b687fba53c58e744e04608a9510f9b8 /** * cgroup_init - cgroup initialization -@@ -6163,6 +6163,28 @@ static int __init cgroup_no_v1(char *str) +@@ -6164,6 +6164,28 @@ static int __init cgroup_no_v1(char *str) } __setup("cgroup_no_v1=", cgroup_no_v1); @@ -107613,10 +107613,10 @@ index 4e2f3de0e40bff4caef5ee9c587ea19140d07f85..4b687fba53c58e744e04608a9510f9b8 * css_tryget_online_from_dir - get corresponding css from a cgroup dentry * @dentry: directory dentry of interest -From 5d758fbf4aca0b7c1edf791f2592a6da5141b023 Mon Sep 17 00:00:00 2001 +From 4f6e576e8cafa2c4cef2bfd1298d8beff5f3d4ab Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 14 Jul 2014 22:02:09 +0100 -Subject: [PATCH 060/220] hid: Reduce default mouse polling interval to 60Hz +Subject: [PATCH 060/229] hid: Reduce default mouse polling interval to 60Hz Reduces overhead when using X --- @@ -107652,10 +107652,10 @@ index ae83af649a607f67239f1a64bf45dd4b5770cc7d..4a7af9d0b910f59d17421ce14138400d ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { -From 8c9b2d7d5038f9824f2de9194704680d99e1b982 Mon Sep 17 00:00:00 2001 +From 06a98a9947af50301d550e0d25b84b9638e670cb Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Tue, 12 May 2015 14:47:56 +0100 -Subject: [PATCH 061/220] rpi-ft5406: Add touchscreen driver for pi LCD display +Subject: [PATCH 061/229] rpi-ft5406: Add touchscreen driver for pi LCD display Fix driver detection failure Check that the buffer response is non-zero meaning the touchscreen was detected @@ -108013,10 +108013,10 @@ index 227a107214a02deadcca3db202da265eba1fdd21..b0f6e33bd30c35664ceee057f4c3ad32 RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f, -From efeb9051d9d8cc32d7bb6acdac458b7bf658a29e Mon Sep 17 00:00:00 2001 +From c989ab09b298d8f44d70d200e2f8daa693d6e080 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 28 Nov 2016 16:50:04 +0000 -Subject: [PATCH 062/220] Improve __copy_to_user and __copy_from_user +Subject: [PATCH 062/229] Improve __copy_to_user and __copy_from_user performance Provide a __copy_from_user that uses memcpy. On BCM2708, use @@ -109591,10 +109591,10 @@ index 333dc3c2e5ffbb2c5ab8fcfb6115b6162643cf20..46b787a6474ffa857da9b663948863ec bool "Broadcom BCM63xx DSL SoC" depends on ARCH_MULTI_V7 -From c3ae87038305b92e9180cb80fc55a181806702b2 Mon Sep 17 00:00:00 2001 +From 101ea4dcb4d6e197c8205c6ed768310a87a2ec06 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 25 Jun 2015 12:16:11 +0100 -Subject: [PATCH 063/220] gpio-poweroff: Allow it to work on Raspberry Pi +Subject: [PATCH 063/229] gpio-poweroff: Allow it to work on Raspberry Pi The Raspberry Pi firmware manages the power-down and reboot process. To do this it installs a pm_power_off handler, causing @@ -109629,10 +109629,10 @@ index be3d81ff51cc3f510d85e4eed7a52960e51e7bc1..a030ae9fb1fca325061c093696e82186 "%s: pm_power_off function already registered", __func__); -From d4819a37276f0ef6f3e2cdcd5eccfb0b011cff81 Mon Sep 17 00:00:00 2001 +From 9e3b24f5e14f4ee5e245273e438264cdaae253e5 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Jul 2015 14:32:47 +0100 -Subject: [PATCH 064/220] mfd: Add Raspberry Pi Sense HAT core driver +Subject: [PATCH 064/229] mfd: Add Raspberry Pi Sense HAT core driver --- drivers/input/joystick/Kconfig | 8 + @@ -110497,10 +110497,10 @@ index 0000000000000000000000000000000000000000..56196dc2af10e464a1e3f98b028dca1c + +#endif -From 9f6bdc019a388b1ea4b3a27e46ca8726118c9552 Mon Sep 17 00:00:00 2001 +From 855bc2c77914c65c0545e34ca8b616ce21a293ff Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 065/220] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 065/229] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -110675,10 +110675,10 @@ index 0000000000000000000000000000000000000000..45f2b770ad9e67728ca599a7445d6ae9 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); +MODULE_LICENSE("GPL v2"); -From d7f0d75af3c821a8c21b2d901e96e13a10e0fff0 Mon Sep 17 00:00:00 2001 +From bba1ca849bd063ca5222ff21b6c6d4111b519806 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Mon, 25 Jan 2016 15:48:59 +0000 -Subject: [PATCH 066/220] ASoC: Add support for Rpi-DAC +Subject: [PATCH 066/229] ASoC: Add support for Rpi-DAC --- sound/soc/bcm/Kconfig | 7 +++ @@ -110962,10 +110962,10 @@ index 0000000000000000000000000000000000000000..afe1b419582aa40c4b2729d242bb13cd +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From fe26ef9411dc01b92a3e34e3d2dbfcce78555ab4 Mon Sep 17 00:00:00 2001 +From 0f9b79e7c14e113edd3b333709c3a7bb0d06744f Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 067/220] ASoC: wm8804: Implement MCLK configuration options, +Subject: [PATCH 067/229] ASoC: wm8804: Implement MCLK configuration options, add 32bit support WM8804 can run with PLL frequencies of 256xfs and 128xfs for most sample rates. At 192kHz only 128xfs is supported. The existing driver selects 128xfs automatically for some lower samples rates. By using an @@ -111014,10 +111014,10 @@ index af95d648265b3e92e345101542b332aee35191d4..513f56ba132929662802d15cdc653af3 .component_driver = { .dapm_widgets = wm8804_dapm_widgets, -From d688169c6c2216690e615b8b539ec1886ac83eeb Mon Sep 17 00:00:00 2001 +From eafee11cda0f176ddb444c59ebf790344e5a5b03 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 068/220] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 068/229] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -111361,10 +111361,10 @@ index 0000000000000000000000000000000000000000..19dc953b7227ba86123fc7a2ba654499 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); +MODULE_LICENSE("GPL v2"); -From 9882b17f502ab6eba3e60ec3ec04744f669b6bfc Mon Sep 17 00:00:00 2001 +From b4e4db59ea48160171b6a01b003abef5ac6ed38d Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 069/220] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 069/229] Add IQaudIO Sound Card support for Raspberry Pi Set a limit of 0dB on Digital Volume Control @@ -111694,10 +111694,10 @@ index 0000000000000000000000000000000000000000..4e8e6dec14bcf4a1ff286c43742d4097 +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); -From 94eeca6a279f8e3c395d0048a4c24e0dbc4093f9 Mon Sep 17 00:00:00 2001 +From 9c16bec9bc7f8bc87099cf0130f44adfb0d27a01 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 25 Jul 2016 17:06:50 +0100 -Subject: [PATCH 070/220] iqaudio-dac: Compile fix - untested +Subject: [PATCH 070/229] iqaudio-dac: Compile fix - untested --- sound/soc/bcm/iqaudio-dac.c | 6 +++++- @@ -111721,10 +111721,10 @@ index 4e8e6dec14bcf4a1ff286c43742d4097249d6777..aa15bc4b49ca95edec905fddd8fd0a6d if (dapm->dev != codec_dai->dev) return 0; -From c3c66b676e27402aa8f6df477b14c3b25ab00e1f Mon Sep 17 00:00:00 2001 +From 0e74e8e4d9ac3510421ce91d095456d490bf33c2 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 10:06:56 +0200 -Subject: [PATCH 071/220] Added support for HiFiBerry DAC+ +Subject: [PATCH 071/229] Added support for HiFiBerry DAC+ The driver is based on the HiFiBerry DAC driver. However HiFiBerry DAC+ uses a different codec chip (PCM5122), therefore a new driver is necessary. @@ -112354,10 +112354,10 @@ index 72b19e62f6267698aea45d2410d616d91c1825cb..c6839ef6e16754ed9de2698507b8986a dev_err(dev, "No LRCLK?\n"); return -EINVAL; -From b32b2cfa080c1bb6689ccf00857896d57534682f Mon Sep 17 00:00:00 2001 +From ec92c2143d9505b6829cb4ff13ec33ff90f3adb0 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 11:09:58 +0200 -Subject: [PATCH 072/220] Added driver for HiFiBerry Amp amplifier add-on board +Subject: [PATCH 072/229] Added driver for HiFiBerry Amp amplifier add-on board The driver contains a low-level hardware driver for the TAS5713 and the drivers for the Raspberry Pi I2S subsystem. @@ -113197,10 +113197,10 @@ index 0000000000000000000000000000000000000000..8f019e04898754d2f87e9630137be9e8 + +#endif /* _TAS5713_H */ -From 6c6253ced927fd8a4a4bc7dbfd96cb934e3f2f85 Mon Sep 17 00:00:00 2001 +From 9f40f104f6893e8ba6d3eaf69bfdeb8c4dc5108f Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:25:49 -0700 -Subject: [PATCH 073/220] Update ds1307 driver for device-tree support +Subject: [PATCH 073/229] Update ds1307 driver for device-tree support Signed-off-by: Ryan Coe --- @@ -113227,10 +113227,10 @@ index 4e31036ee2596dec93accd26f627c5b95591ae9f..b92044cf03e750afa521a93519500e9d .driver = { .name = "rtc-ds1307", -From b6529d4aa9141d702f95c06227af481cffd823c3 Mon Sep 17 00:00:00 2001 +From 7fcc953a86eefbc84fa31a5f35396b3f7989aca1 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 25 Mar 2015 09:26:17 +0100 -Subject: [PATCH 074/220] Add driver for rpi-proto +Subject: [PATCH 074/229] Add driver for rpi-proto Forward port of 3.10.x driver from https://github.com/koalo We are using a custom board and would like to use rpi 3.18.x @@ -113446,10 +113446,10 @@ index 0000000000000000000000000000000000000000..9db678e885efd63d84d60a098a84ed67 +MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)"); +MODULE_LICENSE("GPL"); -From 477089266946852344ffa0af34aa55a5935140a5 Mon Sep 17 00:00:00 2001 +From eda93dadf2ff70fa40bc6e25cfbcf4c002d497b4 Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Mon, 24 Aug 2015 16:03:47 +0100 -Subject: [PATCH 075/220] RaspiDAC3 support +Subject: [PATCH 075/229] RaspiDAC3 support Signed-off-by: Jan Grulich @@ -113692,10 +113692,10 @@ index 0000000000000000000000000000000000000000..dd9eeea2af0382307f437e6db09d1546 +MODULE_DESCRIPTION("ASoC Driver for RaspiDAC Rev.3x"); +MODULE_LICENSE("GPL v2"); -From 21769c8cd7439b9e3e50e774d65ae484d388be8d Mon Sep 17 00:00:00 2001 +From 15aa080d980f651b5d97f4d6e481abf18fbe74f6 Mon Sep 17 00:00:00 2001 From: Aaron Shaw Date: Thu, 7 Apr 2016 21:26:21 +0100 -Subject: [PATCH 076/220] Add Support for JustBoom Audio boards +Subject: [PATCH 076/229] Add Support for JustBoom Audio boards justboom-dac: Adjust for ALSA API change @@ -114149,10 +114149,10 @@ index 0000000000000000000000000000000000000000..91acb666380faa3c0deb2230f8a0f8bb +MODULE_DESCRIPTION("ASoC Driver for JustBoom PI Digi HAT Sound Card"); +MODULE_LICENSE("GPL v2"); -From 8e16cb34280580accee4d4b246a2bf1f68898014 Mon Sep 17 00:00:00 2001 +From bf13321d80233017145d5fda5b01e34f8de9a166 Mon Sep 17 00:00:00 2001 From: Andrey Grodzovsky Date: Tue, 3 May 2016 22:10:59 -0400 -Subject: [PATCH 077/220] ARM: adau1977-adc: Add basic machine driver for +Subject: [PATCH 077/229] ARM: adau1977-adc: Add basic machine driver for adau1977 codec driver. This commit adds basic support for the codec usage including: Device tree overlay, @@ -114334,10 +114334,10 @@ index 0000000000000000000000000000000000000000..6e2ee027926ee63c89222f75ceb89e3d +MODULE_DESCRIPTION("ASoC Driver for ADAU1977 ADC"); +MODULE_LICENSE("GPL v2"); -From e2bb2f096bf36883b8e7b026f2fabb48d64e137a Mon Sep 17 00:00:00 2001 +From 661232aaff54122beaa4a9ad08b5d9e547a6a31f Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Mon, 16 May 2016 21:36:31 +1000 -Subject: [PATCH 078/220] New AudioInjector.net Pi soundcard with low jitter +Subject: [PATCH 078/229] New AudioInjector.net Pi soundcard with low jitter audio in and out. Contains the sound/soc/bcm ALSA machine driver and necessary alterations to the Kconfig and Makefile. @@ -114588,10 +114588,10 @@ index 0000000000000000000000000000000000000000..ef54e0f07ea03f59e9957b5d98f3e7fd +MODULE_ALIAS("platform:audioinjector-pi-soundcard"); + -From 8ad7c0ce666a8d9bf54dffcffe99230986e80683 Mon Sep 17 00:00:00 2001 +From 0de5e9aa69797bbadd19ab02752c87453ec79f91 Mon Sep 17 00:00:00 2001 From: DigitalDreamtime Date: Thu, 30 Jun 2016 18:38:42 +0100 -Subject: [PATCH 079/220] Add IQAudIO Digi WM8804 board support +Subject: [PATCH 079/229] Add IQAudIO Digi WM8804 board support Support IQAudIO Digi board with iqaudio_digi machine driver and iqaudio-digi-wm8804-audio overlay. @@ -114891,10 +114891,10 @@ index 0000000000000000000000000000000000000000..9b6e829bcb5b1762a853775e78163196 +MODULE_DESCRIPTION("ASoC Driver for IQAudIO WM8804 Digi"); +MODULE_LICENSE("GPL v2"); -From 9eddb99275e246c9fbc00591001b94250908445d Mon Sep 17 00:00:00 2001 +From a4095054f656362613c191ee300b9e65ba0bdc8b Mon Sep 17 00:00:00 2001 From: escalator2015 Date: Tue, 24 May 2016 16:20:09 +0100 -Subject: [PATCH 080/220] New driver for RRA DigiDAC1 soundcard using WM8741 + +Subject: [PATCH 080/229] New driver for RRA DigiDAC1 soundcard using WM8741 + WM8804 --- @@ -115367,10 +115367,10 @@ index 0000000000000000000000000000000000000000..446796e7e4c14a7d95b2f2a01211d9a0 +MODULE_DESCRIPTION("ASoC Driver for RRA DigiDAC1"); +MODULE_LICENSE("GPL v2"); -From ef311a15a728dd13d735f09f6214b89b8551ebd7 Mon Sep 17 00:00:00 2001 +From 3bf19276b1b847b1d96caee3c746c0d29d603e0e Mon Sep 17 00:00:00 2001 From: DigitalDreamtime Date: Sat, 2 Jul 2016 16:26:19 +0100 -Subject: [PATCH 081/220] Add support for Dion Audio LOCO DAC-AMP HAT +Subject: [PATCH 081/229] Add support for Dion Audio LOCO DAC-AMP HAT Using dedicated machine driver and pcm5102a codec driver. @@ -115543,10 +115543,10 @@ index 0000000000000000000000000000000000000000..89e65317512bc774453ac8d0d5b0ff98 +MODULE_DESCRIPTION("ASoC Driver for DionAudio LOCO"); +MODULE_LICENSE("GPL v2"); -From f0095d1c98b5bf40e328f7459b49793e68f45350 Mon Sep 17 00:00:00 2001 +From 12fe276699395b039afff7dea0ee0179a690f5f5 Mon Sep 17 00:00:00 2001 From: Clive Messer Date: Mon, 19 Sep 2016 14:01:04 +0100 -Subject: [PATCH 082/220] Allo Piano DAC boards: Initial 2 channel (stereo) +Subject: [PATCH 082/229] Allo Piano DAC boards: Initial 2 channel (stereo) support (#1645) Add initial 2 channel (stereo) support for Allo Piano DAC (2.0/2.1) boards, @@ -115753,10 +115753,10 @@ index 0000000000000000000000000000000000000000..8e8e62e5a36a279b425ed4655cfbac99 +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Piano DAC"); +MODULE_LICENSE("GPL v2"); -From 067375121b334db7e3ab4b09ceac310a0723d95a Mon Sep 17 00:00:00 2001 +From 3807cf287bc29c2a2fb95369349a7c6757bbc2b3 Mon Sep 17 00:00:00 2001 From: gtrainavicius Date: Sun, 23 Oct 2016 12:06:53 +0300 -Subject: [PATCH 083/220] Support for Blokas Labs pisound board +Subject: [PATCH 083/229] Support for Blokas Labs pisound board Pisound dynamic overlay (#1760) @@ -116933,10 +116933,10 @@ index 0000000000000000000000000000000000000000..4b8545487d06e4ea70073a5d063fb231 +MODULE_DESCRIPTION("ASoC Driver for pisound, http://blokas.io/pisound"); +MODULE_LICENSE("GPL v2"); -From 33ce233ed2584afe96636773ae8e160bf158c36f Mon Sep 17 00:00:00 2001 +From c375d01c52d73c3e83814310c5f9f21bc8b7a394 Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 21 Oct 2015 14:55:21 +0100 -Subject: [PATCH 084/220] rpi_display: add backlight driver and overlay +Subject: [PATCH 084/229] rpi_display: add backlight driver and overlay Add a mailbox-driven backlight controller for the Raspberry Pi DSI touchscreen display. Requires updated GPU firmware to recognise the @@ -117105,10 +117105,10 @@ index 0000000000000000000000000000000000000000..14a0d9b037395497c1fdae2961feccd5 +MODULE_DESCRIPTION("Raspberry Pi mailbox based Backlight Driver"); +MODULE_LICENSE("GPL"); -From 54e1dbaef697f6fc4546e0939a8deb77e3ad4033 Mon Sep 17 00:00:00 2001 +From 271dfcf951d3ac0ef459b1aa063b066b169d4786 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 23 Feb 2016 19:56:04 +0000 -Subject: [PATCH 085/220] bcm2835-virtgpio: Virtual GPIO driver +Subject: [PATCH 085/229] bcm2835-virtgpio: Virtual GPIO driver Add a virtual GPIO driver that uses the firmware mailbox interface to request that the VPU toggles LEDs. @@ -117382,10 +117382,10 @@ index b0f6e33bd30c35664ceee057f4c3ad32b914291d..e92278968b2b979db2a1f855f70e7aaf RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f, -From ac53d48c62fe76b1e1cc9efd499f24e98ebf4b72 Mon Sep 17 00:00:00 2001 +From 1e615d35b3a8ce4f3433174cf813e77cff0e3a00 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 23 Feb 2016 17:26:48 +0000 -Subject: [PATCH 086/220] amba_pl011: Don't use DT aliases for numbering +Subject: [PATCH 086/229] amba_pl011: Don't use DT aliases for numbering The pl011 driver looks for DT aliases of the form "serial", and if found uses as the device ID. This can cause @@ -117414,10 +117414,10 @@ index e2c33b9528d82ed7a2c27d083d7b1d222da68178..5a11ff833e1fd112ba04df3a427cd94b uap->old_cr = 0; uap->port.dev = dev; -From 9ba7fae58e91f74bb16cbbfb09d7144a39bc5035 Mon Sep 17 00:00:00 2001 +From 21e66cfc8bfc2195a7b769388fa98af584d8b58b Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Wed, 3 Dec 2014 13:23:28 +0200 -Subject: [PATCH 087/220] OF: DT-Overlay configfs interface +Subject: [PATCH 087/229] OF: DT-Overlay configfs interface This is a port of Pantelis Antoniou's v3 port that makes use of the new upstreamed configfs support for binary attributes. @@ -117849,10 +117849,10 @@ index 0000000000000000000000000000000000000000..0037e6868a6cda8706c88194c6a4454b +} +late_initcall(of_cfs_init); -From 3d1029a97572b0b870c97325b5ba6715f2893687 Mon Sep 17 00:00:00 2001 +From 66577977b62c8b1b9b2e30baf0f16435ec96ae35 Mon Sep 17 00:00:00 2001 From: Cheong2K Date: Fri, 26 Feb 2016 18:20:10 +0800 -Subject: [PATCH 088/220] brcm: adds support for BCM43341 wifi +Subject: [PATCH 088/229] brcm: adds support for BCM43341 wifi brcmfmac: Disable power management @@ -118015,10 +118015,10 @@ index d0407d9ad7827cd756b6311410ffe2d9a7cacc78..f1fb8a3c7a3211e8429585861f2f42e0 #define BRCM_CC_4335_CHIP_ID 0x4335 #define BRCM_CC_4339_CHIP_ID 0x4339 -From bee032889b6506b0860b46998f4e762fe0ad68f5 Mon Sep 17 00:00:00 2001 +From c9ca6019b268dd73f61430b0406d04b298219528 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 17 Dec 2015 13:37:07 +0000 -Subject: [PATCH 089/220] hci_h5: Don't send conf_req when ACTIVE +Subject: [PATCH 089/229] hci_h5: Don't send conf_req when ACTIVE Without this patch, a modem and kernel can continuously bombard each other with conf_req and conf_rsp messages, in a demented game of tag. @@ -118041,10 +118041,10 @@ index 0879d64b1caf58afb6e5d494c07d9ab7e7cdf983..5161ab30fd533d50f516bb93d5b9f402 if (H5_HDR_LEN(hdr) > 2) h5->tx_win = (data[2] & 0x07); -From 6ef0c0f087f212d6968ae96d957381cc683683a7 Mon Sep 17 00:00:00 2001 +From 80becbfb1eb526e8dc82520503c2f92d3120ab82 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 13 Apr 2015 17:16:29 +0100 -Subject: [PATCH 090/220] config: Add default configs +Subject: [PATCH 090/229] config: Add default configs --- arch/arm/configs/bcm2709_defconfig | 1297 +++++++++++++++++++++++++++++++++++ @@ -120671,10 +120671,10 @@ index 0000000000000000000000000000000000000000..8acee9f31202ec14f2933d92dd70831c +CONFIG_CRC_ITU_T=y +CONFIG_LIBCRC32C=y -From e5f988ef5fd9496bec35b230dfb4289b75f1cb71 Mon Sep 17 00:00:00 2001 +From d067fb0bd2225f5ca5cf5334ea20372dc32b3355 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Wed, 24 Aug 2016 03:35:56 -0700 -Subject: [PATCH 091/220] Add arm64 configuration and device tree differences. +Subject: [PATCH 091/229] Add arm64 configuration and device tree differences. Disable MMC_BCM2835_SDHOST and MMC_BCM2835 since these drivers are crashing at the moment. @@ -122089,10 +122089,10 @@ index 0000000000000000000000000000000000000000..d7406f5a4620151044b8f716b4d10bb8 +CONFIG_LIBCRC32C=y +CONFIG_BCM2708_VCHIQ=n -From ae5882f60d59db76fcb08c3bb7d26188ab5a0c9b Mon Sep 17 00:00:00 2001 +From 048ec555bde80f0d45a509590811cf06b8683a91 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 7 Mar 2016 15:05:11 +0000 -Subject: [PATCH 092/220] vchiq_arm: Tweak the logging output +Subject: [PATCH 092/229] vchiq_arm: Tweak the logging output Signed-off-by: Phil Elwell --- @@ -122167,10 +122167,10 @@ index 2c98da4307dff994a00dc246574ef0aaee05d5da..160db24aeea33a8296923501009c1f02 switch (type) { -From a2531fd0535770cad254ea80e8bd2a94c4ada2f4 Mon Sep 17 00:00:00 2001 +From 7d957ebc37354b5e062ab797d906fa1b3192c33e Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 23 Mar 2016 14:16:25 +0000 -Subject: [PATCH 093/220] vchiq_arm: Access the dequeue_pending flag locked +Subject: [PATCH 093/229] vchiq_arm: Access the dequeue_pending flag locked Reading through this code looking for another problem (now found in userland) the use of dequeue_pending outside a lock didn't seem safe. @@ -122228,10 +122228,10 @@ index 7b6cd4d80621e38ff6d47fcd87b45fbe9cd4259b..d8669fa7f39b077877eca1829ba9538b return add_completion(instance, reason, header, user_service, -From 0abf254dd70f7520670534959d9f24840ec0bef4 Mon Sep 17 00:00:00 2001 +From 37d9af85ed4cb135e3cc842eca5d3c21edbd3df8 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 23 Mar 2016 20:53:47 +0000 -Subject: [PATCH 094/220] vchiq_arm: Service callbacks must not fail +Subject: [PATCH 094/229] vchiq_arm: Service callbacks must not fail Service callbacks are not allowed to return an error. The internal callback that delivers events and messages to user tasks does not enqueue them if @@ -122257,10 +122257,10 @@ index d8669fa7f39b077877eca1829ba9538bf2e21a82..54552c6ce54f413c9781ba279b936f98 DEBUG_TRACE(SERVICE_CALLBACK_LINE); } -From 2644cc28982a3f59033c2b6ed5cd85327f7d08d9 Mon Sep 17 00:00:00 2001 +From 8901e803a85bdad7aed4ece564a972e1479d633a Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 21 Apr 2016 13:49:32 +0100 -Subject: [PATCH 095/220] vchiq_arm: Add completion records under the mutex +Subject: [PATCH 095/229] vchiq_arm: Add completion records under the mutex An issue was observed when flushing openmax components which generate a large number of messages returning @@ -122323,10 +122323,10 @@ index 54552c6ce54f413c9781ba279b936f98be4f47b0..bde8955b7d8505d73579b77b5b392154 return VCHIQ_SUCCESS; -From dde2a0205bb9cfde62ce87b495d0c7bd69930cb9 Mon Sep 17 00:00:00 2001 +From f7818783188ad1ca3dfa917eef8a7b1c44d00c24 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 20 Jun 2016 13:51:44 +0100 -Subject: [PATCH 096/220] vchiq_arm: Avoid use of mutex in add_completion +Subject: [PATCH 096/229] vchiq_arm: Avoid use of mutex in add_completion Claiming the completion_mutex within add_completion did prevent some messages appearing twice, but provokes a deadlock caused by vcsm using @@ -122520,10 +122520,10 @@ index 160db24aeea33a8296923501009c1f02bc41e599..71a3bedc55314f3b22dbff40c05dedf0 up(&state->slot_available_event); } -From 19689de74e1902269bcac64510b987ad657e8bb9 Mon Sep 17 00:00:00 2001 +From a3670b6bf343df0f90c9035aef4becb0397526d7 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Oct 2016 10:14:10 -0700 -Subject: [PATCH 097/220] staging/vchi: Convert to current get_user_pages() +Subject: [PATCH 097/229] staging/vchi: Convert to current get_user_pages() arguments. Signed-off-by: Eric Anholt @@ -122560,10 +122560,10 @@ index e5cdda12c7e5c35c69eb96991cfdb8326def167f..085d37588c59198b4e5f00b9249bb842 num_pages, /* len */ 0, /* gup_flags */ -From 227e5348ac80d55e144540cc52cb83fac71ebcae Mon Sep 17 00:00:00 2001 +From 5d2e4bf27aef87c693de1ed6e988b5624863b918 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Oct 2016 10:16:03 -0700 -Subject: [PATCH 098/220] staging/vchi: Update for rename of +Subject: [PATCH 098/229] staging/vchi: Update for rename of page_cache_release() to put_page(). Signed-off-by: Eric Anholt @@ -122608,10 +122608,10 @@ index 085d37588c59198b4e5f00b9249bb8421695854f..5a2b8fb459ebe086ec229f37b6381bdb kfree(pages); } -From a7e01ebd2ab71bf7fa6a180164553a43acb1d61a Mon Sep 17 00:00:00 2001 +From af0be25de2e646b6f55a8c407fc504277e7d21ee Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 3 Oct 2016 10:21:17 -0700 -Subject: [PATCH 099/220] drivers/vchi: Remove dependency on CONFIG_BROKEN. +Subject: [PATCH 099/229] drivers/vchi: Remove dependency on CONFIG_BROKEN. The driver builds now. @@ -122633,10 +122633,10 @@ index 9676fb29075a457109e4d4235f086987aec74868..db8e1beb89f9f8c48ea5964016c8285e help Kernel to VideoCore communication interface for the -From b3fd781539c0fc82d066dff19acb6678a6182547 Mon Sep 17 00:00:00 2001 +From 9db7c44044af7ca93638725180b277084f83284c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 14 Sep 2016 09:16:19 +0100 -Subject: [PATCH 100/220] raspberrypi-firmware: Export the general transaction +Subject: [PATCH 100/229] raspberrypi-firmware: Export the general transaction function. The vc4-firmware-kms module is going to be doing the MBOX FB call. @@ -122680,10 +122680,10 @@ index e92278968b2b979db2a1f855f70e7aafb224fa98..09e3d871d110eb0762ebdb5ea3293537 #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ -From acdb7331d3942780bc5391de89d9a2281646db42 Mon Sep 17 00:00:00 2001 +From 2e9d6b6d3d819ef8a26d61c260976e8af226f646 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 14 Sep 2016 09:18:09 +0100 -Subject: [PATCH 101/220] raspberrypi-firmware: Define the MBOX channel in the +Subject: [PATCH 101/229] raspberrypi-firmware: Define the MBOX channel in the header. Signed-off-by: Eric Anholt @@ -122705,10 +122705,10 @@ index 09e3d871d110eb0762ebdb5ea329353738d58661..2859db09e25bb945251e85edb39bc434 enum rpi_firmware_property_status { -From 388a0c696f392f9641658d6648d5ccf98c57ebfa Mon Sep 17 00:00:00 2001 +From e195fb27ffe8e99d6e5f975e963972e6173ad56e Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 14 Sep 2016 08:39:33 +0100 -Subject: [PATCH 102/220] drm/vc4: Add a mode for using the closed firmware for +Subject: [PATCH 102/229] drm/vc4: Add a mode for using the closed firmware for display. Signed-off-by: Eric Anholt @@ -122734,7 +122734,7 @@ index fb77db755e0a29d8589860da82186c7a1f394c72..c6dd06cca9830018c39b3b16afe4045e vc4_gem.o \ vc4_hdmi.o \ diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c -index 7aadce1f7e7a0e56b302bded53ad8c0d5977cc22..bdf32c572fc2c46932daca934dfb002d05493883 100644 +index c7e6c9839c9abfa5b4a9086024ebe3f854b13b38..c7e478f672e184974a33bb9ca72b8aa62d76e97e 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -162,6 +162,9 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, @@ -123475,103 +123475,10 @@ index 0000000000000000000000000000000000000000..d18a1dae51a2275846c9826b5bf1ba57 + }, +}; -From efa272fcf3b5d4feb8e970f5f3adaedbb52cff56 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= -Date: Sat, 17 Sep 2016 15:07:10 +0200 -Subject: [PATCH 103/220] i2c: bcm2835: Fix hang for writing messages larger - than 16 bytes -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Writing messages larger than the FIFO size results in a hang, rendering -the machine unusable. This is because the RXD status flag is set on the -first interrupt which results in bcm2835_drain_rxfifo() stealing bytes -from the buffer. The controller continues to trigger interrupts waiting -for the missing bytes, but bcm2835_fill_txfifo() has none to give. -In this situation wait_for_completion_timeout() apparently is unable to -stop the madness. - -The BCM2835 ARM Peripherals datasheet has this to say about the flags: - TXD: is set when the FIFO has space for at least one byte of data. - RXD: is set when the FIFO contains at least one byte of data. - TXW: is set during a write transfer and the FIFO is less than full. - RXR: is set during a read transfer and the FIFO is or more full. - -Implementing the logic from the downstream i2c-bcm2708 driver solved -the hang problem. - -Signed-off-by: Noralf Trønnes -Reviewed-by: Eric Anholt -Reviewed-by: Martin Sperl ---- - drivers/i2c/busses/i2c-bcm2835.c | 22 ++++++++++++++-------- - 1 file changed, 14 insertions(+), 8 deletions(-) - -diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c -index d4f3239b56865919e1b781b20a7c5ebcd76b4eb9..f283b714aa79e2e4685ed95b04b6b289f7e9eee7 100644 ---- a/drivers/i2c/busses/i2c-bcm2835.c -+++ b/drivers/i2c/busses/i2c-bcm2835.c -@@ -64,6 +64,7 @@ struct bcm2835_i2c_dev { - int irq; - struct i2c_adapter adapter; - struct completion completion; -+ struct i2c_msg *curr_msg; - u32 msg_err; - u8 *msg_buf; - size_t msg_buf_remaining; -@@ -126,14 +127,13 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) - return IRQ_HANDLED; - } - -- if (val & BCM2835_I2C_S_RXD) { -- bcm2835_drain_rxfifo(i2c_dev); -- if (!(val & BCM2835_I2C_S_DONE)) -- return IRQ_HANDLED; -- } -- - if (val & BCM2835_I2C_S_DONE) { -- if (i2c_dev->msg_buf_remaining) -+ if (i2c_dev->curr_msg->flags & I2C_M_RD) { -+ bcm2835_drain_rxfifo(i2c_dev); -+ val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); -+ } -+ -+ if ((val & BCM2835_I2C_S_RXD) || i2c_dev->msg_buf_remaining) - i2c_dev->msg_err = BCM2835_I2C_S_LEN; - else - i2c_dev->msg_err = 0; -@@ -141,11 +141,16 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) - return IRQ_HANDLED; - } - -- if (val & BCM2835_I2C_S_TXD) { -+ if (val & BCM2835_I2C_S_TXW) { - bcm2835_fill_txfifo(i2c_dev); - return IRQ_HANDLED; - } - -+ if (val & BCM2835_I2C_S_RXR) { -+ bcm2835_drain_rxfifo(i2c_dev); -+ return IRQ_HANDLED; -+ } -+ - return IRQ_NONE; - } - -@@ -155,6 +160,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, - u32 c; - unsigned long time_left; - -+ i2c_dev->curr_msg = msg; - i2c_dev->msg_buf = msg->buf; - i2c_dev->msg_buf_remaining = msg->len; - reinit_completion(&i2c_dev->completion); - -From 912ba8c7f00b0fcca8a476275730822209a876f2 Mon Sep 17 00:00:00 2001 +From c9e79874b1619a2f841c1dbde4a7aa3c39245e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Sep 2016 18:24:38 +0200 -Subject: [PATCH 104/220] i2c: bcm2835: Protect against unexpected TXW/RXR +Subject: [PATCH 103/229] i2c: bcm2835: Protect against unexpected TXW/RXR interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -123696,10 +123603,10 @@ index f283b714aa79e2e4685ed95b04b6b289f7e9eee7..d2ba1a4de36af512e8e3c97251bd3537 return -ETIMEDOUT; } -From 60c779f9cd724410a7f515ca7dd2c74b0d70ff19 Mon Sep 17 00:00:00 2001 +From 362aa18575e46d38641515073f377126be10bdae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Mon, 19 Sep 2016 17:19:41 +0200 -Subject: [PATCH 105/220] i2c: bcm2835: Use dev_dbg logging on transfer errors +Subject: [PATCH 104/229] i2c: bcm2835: Use dev_dbg logging on transfer errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -123731,10 +123638,10 @@ index d2ba1a4de36af512e8e3c97251bd3537ae61591a..54d510abd46a117c9238fc6d7edec840 if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) return -EREMOTEIO; -From d25a488c3d2cbe416f18eebda107beb959e0d1a1 Mon Sep 17 00:00:00 2001 +From 4052b875979e5a2a4512064121f28a83bd9b51f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Thu, 22 Sep 2016 22:05:50 +0200 -Subject: [PATCH 106/220] i2c: bcm2835: Can't support I2C_M_IGNORE_NAK +Subject: [PATCH 105/229] i2c: bcm2835: Can't support I2C_M_IGNORE_NAK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -123778,10 +123685,10 @@ index 54d510abd46a117c9238fc6d7edec84019d1f60d..565ef69ce61423544dc0558c85ef318b if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) -From db00e4a5449b4c07b42647cb7602d289a5f069dc Mon Sep 17 00:00:00 2001 +From e2621b15db86c88529b68dd09a74074b18340720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Sep 2016 04:54:27 +0200 -Subject: [PATCH 107/220] i2c: bcm2835: Add support for Repeated Start +Subject: [PATCH 106/229] i2c: bcm2835: Add support for Repeated Start Condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 @@ -123963,10 +123870,10 @@ index 565ef69ce61423544dc0558c85ef318b0ae9c324..241e08ae7c27cec23fad3c1bf3ebad3a static u32 bcm2835_i2c_func(struct i2c_adapter *adap) -From 8833865b9f400d0ed56a9d4d6145a937b9065f52 Mon Sep 17 00:00:00 2001 +From 4a6c08fa3e49a680330f7b1d37277b9bf7f2a146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Fri, 23 Sep 2016 04:57:17 +0200 -Subject: [PATCH 108/220] i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT +Subject: [PATCH 107/229] i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124003,10 +123910,10 @@ index 241e08ae7c27cec23fad3c1bf3ebad3a4d2a8e6f..d2085dd3742eabebc537621968088261 bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); -From 37473a5dc43a3906a40b10ea5fe01a707c0befdc Mon Sep 17 00:00:00 2001 +From 1cb94068391d98e357edf70e524fbf1aa0123554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 27 Sep 2016 01:00:08 +0200 -Subject: [PATCH 109/220] i2c: bcm2835: Add support for dynamic clock +Subject: [PATCH 108/229] i2c: bcm2835: Add support for dynamic clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124122,10 +124029,10 @@ index d2085dd3742eabebc537621968088261f8dc7ea8..c3436f627028477f7e21b47e079fd5ab irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq) { -From 1cff038969748df4e53086ff17b956d12832053a Mon Sep 17 00:00:00 2001 +From 9ff203ee6916687ccdc23059827981833668776d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Tue, 1 Nov 2016 15:15:41 +0100 -Subject: [PATCH 110/220] i2c: bcm2835: Add debug support +Subject: [PATCH 109/229] i2c: bcm2835: Add debug support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -124314,10 +124221,10 @@ index c3436f627028477f7e21b47e079fd5ab06ec188a..8642f580ce41803bd22c76a0fa80d083 if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) return -EREMOTEIO; -From 70aa7700bd80535743fb9beef96d0b637cebed3e Mon Sep 17 00:00:00 2001 +From ec8ddef211c52c295f2f8d9bfe6117fe71a13d7b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 31 Dec 2016 14:15:50 +0000 -Subject: [PATCH 111/220] arm64: Add CONFIG_ARCH_BCM2835 +Subject: [PATCH 110/229] arm64: Add CONFIG_ARCH_BCM2835 --- arch/arm64/configs/bcmrpi3_defconfig | 1 + @@ -124333,10 +124240,10 @@ index d7406f5a4620151044b8f716b4d10bb818648e06..53da5c7a33e5898a66e549fb0c39fe3d CONFIG_BCM2708_VCHIQ=n +CONFIG_ARCH_BCM2835=y -From 1413a4cbb0bee9ceaa67b42518b62b1f56e09934 Mon Sep 17 00:00:00 2001 +From 15f326747fc083b56f27d2d57554591439008b55 Mon Sep 17 00:00:00 2001 From: Alex Tucker Date: Tue, 13 Dec 2016 19:50:18 +0000 -Subject: [PATCH 112/220] Add support for Silicon Labs Si7013/20/21 +Subject: [PATCH 111/229] Add support for Silicon Labs Si7013/20/21 humidity/temperature sensor. --- @@ -124411,10 +124318,10 @@ index f6d134c095af2398fc55ae7d2b0e86456c30627c..31bda8da4cb6a56bfe493a81b9189009 }; }; -From f9e98bf01a071940ac897648f18a528a373e3b07 Mon Sep 17 00:00:00 2001 +From 001451767991156606435b6650a321fe5c4461aa Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 3 Jan 2017 21:27:46 +0000 -Subject: [PATCH 113/220] Document the si7020 option +Subject: [PATCH 112/229] Document the si7020 option --- arch/arm/boot/dts/overlays/README | 3 +++ @@ -124435,10 +124342,10 @@ index 81d991803be335e5a1bc3bb0a8c7a2c9f5c392bd..e8fa4ccb44c34a20485c4e6155467af9 Name: i2c0-bcm2708 Info: Enable the i2c_bcm2708 driver for the i2c0 bus. Not all pin combinations -From 89ebf453db75349f9b5b46f47925f3731b5e9eef Mon Sep 17 00:00:00 2001 +From 7491fd8defc166f29a912a340b2b3d3a7b0fbf20 Mon Sep 17 00:00:00 2001 From: Giedrius Trainavicius Date: Thu, 5 Jan 2017 02:38:16 +0200 -Subject: [PATCH 114/220] pisound improvements: +Subject: [PATCH 113/229] pisound improvements: * Added a writable sysfs object to enable scripts / user space software to blink MIDI activity LEDs for variable duration. @@ -124732,10 +124639,10 @@ index 4b8545487d06e4ea70073a5d063fb2310b3b94d0..ba70734b89e61a11201657406223f0b3 }; -From fd7556ce597c3332b4f5b342e7e2c7a38e2b6a27 Mon Sep 17 00:00:00 2001 +From fe0f2b309061b58f33bb4c5057f5b020c461c57e Mon Sep 17 00:00:00 2001 From: Aaron Shaw Date: Tue, 10 Jan 2017 16:05:41 +0000 -Subject: [PATCH 115/220] Add driver_name property +Subject: [PATCH 114/229] Add driver_name property Add driver name property for use with 5.1 passthrough audio in LibreElec and other Kodi based OSs --- @@ -124755,10 +124662,10 @@ index 8fd50dbe681508a2cfe8fdde1c9fedbe9a507fa7..05a224ec712d06b8b7587ab6b8bb562d .dai_link = snd_rpi_justboom_dac_dai, .num_links = ARRAY_SIZE(snd_rpi_justboom_dac_dai), -From f782f8effc0d78303a984ec66ac967939e9c4e20 Mon Sep 17 00:00:00 2001 +From 395fe72c974551ea765a21ac762f9477d59b242a Mon Sep 17 00:00:00 2001 From: Aaron Shaw Date: Tue, 10 Jan 2017 16:11:04 +0000 -Subject: [PATCH 116/220] Add driver_name paramater +Subject: [PATCH 115/229] Add driver_name paramater Add driver_name parameter for use with 5.1 passthrough audio in LibreElec and other Kodi OSs --- @@ -124778,10 +124685,10 @@ index 91acb666380faa3c0deb2230f8a0f8bbec59417b..abfdc5c4dd5811e6847bddda4921abe3 .dai_link = snd_rpi_justboom_digi_dai, .num_links = ARRAY_SIZE(snd_rpi_justboom_digi_dai), -From f407f07800ccbda10269c7d000a2cb518456efdf Mon Sep 17 00:00:00 2001 +From 11591b5b5b3a83c5537bd4085a0c0baa87d2a213 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 11 Jan 2017 13:01:21 +0000 -Subject: [PATCH 117/220] BCM270X_DT: Add pi3-disable-wifi overlay +Subject: [PATCH 116/229] BCM270X_DT: Add pi3-disable-wifi overlay pi3-disable-wifi is a minimal overlay to disable the onboard WiFi. @@ -124842,10 +124749,10 @@ index 0000000000000000000000000000000000000000..017199554bf2f4e381efcc7bb71e750c + }; +}; -From 5d44b8be50fa1b6bb4d5a06a2394b915e4560049 Mon Sep 17 00:00:00 2001 +From 5a54679ce859d2c34fb89ccd1142d79928fa95a5 Mon Sep 17 00:00:00 2001 From: Electron752 Date: Thu, 12 Jan 2017 07:07:08 -0800 -Subject: [PATCH 118/220] ARM64: Make it work again on 4.9 (#1790) +Subject: [PATCH 117/229] ARM64: Make it work again on 4.9 (#1790) * Invoke the dtc compiler with the same options used in arm mode. * ARM64 now uses the bcm2835 platform just like ARM32. @@ -125250,10 +125157,10 @@ index 53da5c7a33e5898a66e549fb0c39fe3da555ca87..c7e891d72969a388d9b135a36dbfc9c9 -CONFIG_BCM2708_VCHIQ=n -CONFIG_ARCH_BCM2835=y -From 230c1dc4e998e421082cbd988c60df28a07b80ac Mon Sep 17 00:00:00 2001 +From 9468c54af05cd96712b20ae0d6a45e73f7808cd9 Mon Sep 17 00:00:00 2001 From: Electron752 Date: Sat, 14 Jan 2017 02:54:26 -0800 -Subject: [PATCH 119/220] ARM64: Enable Kernel Address Space Randomization +Subject: [PATCH 118/229] ARM64: Enable Kernel Address Space Randomization (#1792) Randomization allows the mapping between virtual addresses and physical @@ -125285,10 +125192,10 @@ index c7e891d72969a388d9b135a36dbfc9c9cb609bf8..974d8889c0cf695eb88b57bbef11bc5a CONFIG_BINFMT_MISC=y CONFIG_COMPAT=y -From ff859e7f5700e9c44eeb4dcff97173f54fe1a30c Mon Sep 17 00:00:00 2001 +From a2905214f8f9a5d577544b3cf6267f7c3dc954ab Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sun, 15 Jan 2017 07:31:59 -0800 -Subject: [PATCH 120/220] ARM64: Enable RTL8187/RTL8192CU wifi in build config +Subject: [PATCH 119/229] ARM64: Enable RTL8187/RTL8192CU wifi in build config These drivers build now, so they can be enabled back in the build configuration just like they are for @@ -125313,10 +125220,10 @@ index 974d8889c0cf695eb88b57bbef11bc5aa556b635..4670a490dfb1e582ec24a3b39a3cb9b2 CONFIG_ZD1211RW=m CONFIG_MAC80211_HWSIM=m -From 7705397444fcbbac1c3f2a4847ffec6e8fcbf21b Mon Sep 17 00:00:00 2001 +From 428018a0e81e6f2b721175114d134cf30e71c1bf Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 16 Jan 2017 14:53:12 +0000 -Subject: [PATCH 121/220] BCM270X_DT: Add spi0-cs overlay +Subject: [PATCH 120/229] BCM270X_DT: Add spi0-cs overlay The spi0-cs overlay allows the software chip selectts to be modified using the cs0_pin and cs1_pin parameters. @@ -125404,10 +125311,10 @@ index 0000000000000000000000000000000000000000..7f79029d043c04d7496c7c3480450c69 + }; +}; -From 4c71408224f6f93f9ac9682321b1c147d45b1b67 Mon Sep 17 00:00:00 2001 +From aabd8a056966109f49e5d114861b5c16801ad4de Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 1 Jul 2016 22:09:24 +0100 -Subject: [PATCH 122/220] spi-bcm2835: Disable forced software CS +Subject: [PATCH 121/229] spi-bcm2835: Disable forced software CS Select software CS in bcm2708_common.dtsi, and disable the automatic conversion in the driver to allow hardware CS to be re-enabled with an @@ -125433,10 +125340,10 @@ index 74dd21b7373c7564ede01d84a4f63b93a6d52fa7..51cdefbf5eb265f49bd05e0aa91dfbee i2c0: i2c@7e205000 { -From 9ea5a212d20eaf9baf53b852460ed0179febc6b8 Mon Sep 17 00:00:00 2001 +From 139c8c6cff3ca80644fd2895ed23f7fa5434ea84 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 16 Jan 2017 16:33:54 +0000 -Subject: [PATCH 123/220] config: Add CONFIG_TCP_CONG_BBR See: +Subject: [PATCH 122/229] config: Add CONFIG_TCP_CONG_BBR See: https://github.com/raspberrypi/linux/issues/1784 --- @@ -125471,10 +125378,10 @@ index 8acee9f31202ec14f2933d92dd70831cda8d7b51..219f67051a2542329449b0099165ae28 CONFIG_IPV6_ROUTER_PREF=y CONFIG_INET6_AH=m -From b6703000e7089e86684fdcccd6da4f1fc8860acc Mon Sep 17 00:00:00 2001 +From 0f058832b94fba5bd5e602cb8bff12fb4131697f Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 17 Jan 2017 11:34:58 +0000 -Subject: [PATCH 124/220] BCM270X_DT: Enable UART0 on CM3 +Subject: [PATCH 123/229] BCM270X_DT: Enable UART0 on CM3 Signed-off-by: Phil Elwell --- @@ -125497,10 +125404,10 @@ index 41874c25a84226c0e4af92ec4059e0a571fe6123..3ba6e621856c288ae4694f758604619f sdhost_pins: sdhost_pins { brcm,pins = <48 49 50 51 52 53>; -From 21415f899907b9f02eca30a5ab4e411d5bec315c Mon Sep 17 00:00:00 2001 +From 9a984ea6c04c9c4c13c75b606ad85c9fd006aeda Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 17 Jan 2017 14:39:39 +0000 -Subject: [PATCH 125/220] config: Add CONFIG_MD_M25P80 and CONFIG_MD_SPI_NOR +Subject: [PATCH 124/229] config: Add CONFIG_MD_M25P80 and CONFIG_MD_SPI_NOR See: https://github.com/raspberrypi/linux/issues/1781 @@ -125539,10 +125446,10 @@ index 219f67051a2542329449b0099165ae2885022bec..c4898d63d74718097ec3a1d1fe60b230 CONFIG_OF_CONFIGFS=y CONFIG_ZRAM=m -From fc58c11e6fc82ca1c9d855135f56d953649ca366 Mon Sep 17 00:00:00 2001 +From db4243fd802325f324c91edf63b82c51fa037ef2 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:33:51 -0800 -Subject: [PATCH 126/220] ARM64/DWC_OTG: Port dwc_otg driver to ARM64 +Subject: [PATCH 125/229] ARM64/DWC_OTG: Port dwc_otg driver to ARM64 In ARM64, the FIQ mechanism used by this driver is not current implemented. As a workaround, reqular IRQ is used instead @@ -125885,10 +125792,10 @@ index 6b2c7d0c93f36a63863ff4b0ecc1f3eab77e058b..d7b700ff17821ad1944e36721fe6b2db /** The OS page size */ #define DWC_OS_PAGE_SIZE PAGE_SIZE -From 4167e54b9c6897a8a0eadb434d78a56860af0703 Mon Sep 17 00:00:00 2001 +From 9a4ec231ceb9d9ac814c4f8e9632e10d224c446f Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:43:57 -0800 -Subject: [PATCH 127/220] ARM64: Round-Robin dispatch IRQs between CPUs. +Subject: [PATCH 126/229] ARM64: Round-Robin dispatch IRQs between CPUs. IRQ-CPU mapping is round robined on ARM64 to increase concurrency and allow multiple interrupts to be serviced @@ -125962,10 +125869,10 @@ index 93e3f7660c4230c9f1dd3b195958cb498949b0ca..486bcbfb32305ee417f6b3be7e91a3ff .name = "bcm2836-gpu", .irq_mask = bcm2836_arm_irqchip_mask_gpu_irq, -From e18b3bd37e43924b0952b4c5bc225915e5af6ff8 Mon Sep 17 00:00:00 2001 +From 90ad4ba6d1d5d314626c74e5f1d383c1aaaf69ab Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:45:03 -0800 -Subject: [PATCH 128/220] ARM64: Enable DWC_OTG Driver In ARM64 Build +Subject: [PATCH 127/229] ARM64: Enable DWC_OTG Driver In ARM64 Build Config(bcmrpi3_defconfig) Signed-off-by: Michael Zoran @@ -125986,10 +125893,10 @@ index 4670a490dfb1e582ec24a3b39a3cb9b2488b1864..8c4392344eb4495689c220d5d176ee8c CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_REALTEK=m -From 0a46af1c0e5a2987d69cbab275f694a7c4153535 Mon Sep 17 00:00:00 2001 +From 97e3419592acaa360b86a6444bb67f946d919024 Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Sat, 14 Jan 2017 21:46:04 -0800 -Subject: [PATCH 129/220] ARM64: Use dwc_otg driver by default for USB. +Subject: [PATCH 128/229] ARM64: Use dwc_otg driver by default for USB. If it breaks on anybody, they can use the standard device tree overlays to switch back to the dwc2 driver. @@ -126015,10 +125922,10 @@ index f6def5d7e5d622cf09e8f87332c7374fe28da08b..3e134a1208610b90e2d0fc22f03c6e9f -}; -#endif -From 9ec14630d64986b52384438389772804c4b8bd56 Mon Sep 17 00:00:00 2001 +From c4cbd1b95c15f0e179ffd733ecd80bb868d3c29e Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 23 Jan 2017 17:36:50 +0000 -Subject: [PATCH 130/220] BCM270X_DT: Add reference to audio_pins to CM dtb +Subject: [PATCH 129/229] BCM270X_DT: Add reference to audio_pins to CM dtb The CM1 dtb contains an empty audio_pins node, but no reference to it. Adding the usual pinctrl reference from the audio node enables the @@ -126046,10 +125953,10 @@ index eb8662f0d222b4c0a9a2bcb8bccb13e86a0006b3..10be69972bd1440f574e35d515f3d6a0 hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; }; -From 61d7842d32cf765e132da3c91e292b372f969ea4 Mon Sep 17 00:00:00 2001 +From 64b84190e8f82dcbdb81a3c0780684168218f2dc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 25 Jan 2017 11:30:38 +0000 -Subject: [PATCH 131/220] config: Add additional network scheduling modules +Subject: [PATCH 130/229] config: Add additional network scheduling modules --- arch/arm/configs/bcm2709_defconfig | 4 ++++ @@ -126101,10 +126008,10 @@ index c4898d63d74718097ec3a1d1fe60b2307a6a3140..b448eaa866c200f48351819072c7fefc CONFIG_NET_SCH_PLUG=m CONFIG_NET_CLS_BASIC=m -From 1e02a58f4e9fcdf4df7bfa8f0a1a5847bd0533a6 Mon Sep 17 00:00:00 2001 +From 1a2d2836a996533ce62a30b4c7f420a4bee3eb0a Mon Sep 17 00:00:00 2001 From: chris johnson Date: Sun, 22 Jan 2017 03:27:31 +0000 -Subject: [PATCH 132/220] ASoC: A simple-card overlay for ADAU7002 +Subject: [PATCH 131/229] ASoC: A simple-card overlay for ADAU7002 Usage: `dtoverlay=adau7002-simple` --- @@ -126202,10 +126109,10 @@ index 0000000000000000000000000000000000000000..e67e6625d7967abc92cf00cb604d4c12 + }; +}; -From b68346a7aaf560a3c0f5bb0d8f3368fa0fe24902 Mon Sep 17 00:00:00 2001 +From 74920b1c374b91ce84e1985bc203f8aadc37df4f Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 25 Jan 2017 21:17:23 +0000 -Subject: [PATCH 133/220] config: Add SND_SOC_ADAU7002 codec module +Subject: [PATCH 132/229] config: Add SND_SOC_ADAU7002 codec module As there is now an overlay requiring it, build the codec module. @@ -126240,10 +126147,10 @@ index b448eaa866c200f48351819072c7fefcd8ad8132..5105a592c9bcfee1cc6a8b50fd1c6c32 CONFIG_SND_SOC_WM8804_I2C=m CONFIG_SND_SIMPLE_CARD=m -From dc9c7db126e9c43f02e274eba0a9642c2860e939 Mon Sep 17 00:00:00 2001 +From 44e8842d6af9cfe7c25872b24e635982da9d6a5e Mon Sep 17 00:00:00 2001 From: Scott Ellis Date: Fri, 27 Jan 2017 06:42:42 -0500 -Subject: [PATCH 134/220] Add overlay for mcp3008 adc (#1818) +Subject: [PATCH 133/229] Add overlay for mcp3008 adc (#1818) Some example usage: @@ -126529,10 +126436,10 @@ index 0000000000000000000000000000000000000000..06bf4264959c380d8a9f90f74e780397 + }; +}; -From 0ce341d5fba2be9d92ba7ab47cb3522c2adebcdc Mon Sep 17 00:00:00 2001 +From 04cb2b6d07495a43ef358d682335d50375a89c33 Mon Sep 17 00:00:00 2001 From: ED6E0F17 Date: Fri, 3 Feb 2017 14:52:42 +0000 -Subject: [PATCH 135/220] usb: dwc2: Avoid suspending if we're in gadget mode +Subject: [PATCH 134/229] usb: dwc2: Avoid suspending if we're in gadget mode (#1825) I've found when booting HiKey with the usb gadget cable attached @@ -126584,10 +126491,10 @@ index df5a065780054f21841ca9f08b8ab118922c530b..619ccfe1eafc4643b16970f8a1129ff9 goto skip_power_saving; -From 8693790f2fed00d8924d88a41c5acafdd04e547a Mon Sep 17 00:00:00 2001 +From 43e63a937e2502763d25f20ab86d02f9c50ed7c2 Mon Sep 17 00:00:00 2001 From: JamesH65 Date: Mon, 6 Feb 2017 15:24:47 +0000 -Subject: [PATCH 136/220] gpio_mem: Remove unnecessary dev_info output (#1830) +Subject: [PATCH 135/229] gpio_mem: Remove unnecessary dev_info output (#1830) The open function was spamming syslog every time called, so have removed call completely. @@ -126609,10 +126516,10 @@ index 911f5b7393ed48ceed8751f06967ae6463453f9c..f5e7f1ba8fb6f18dee77fad06a17480c dev_err(inst->dev, "Unknown minor device: %d", dev); ret = -ENXIO; -From 717a8a38685825e7aa32c98e0060d4c1c548fcc8 Mon Sep 17 00:00:00 2001 +From 485bcbae2ea29432fc86bc307d3857d3045ab1a3 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Sun, 22 Jan 2017 12:49:36 +0100 -Subject: [PATCH 137/220] config: Enable regulator support +Subject: [PATCH 136/229] config: Enable regulator support Signed-off-by: Matthias Reichl --- @@ -126647,10 +126554,10 @@ index 5105a592c9bcfee1cc6a8b50fd1c6c32f1381158..74bc0d81bcb4d7f6676368926cdcc10e CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_ANALOG_TV_SUPPORT=y -From defe868ac9c7aea28dfe3d674cca4ac237a42a28 Mon Sep 17 00:00:00 2001 +From 5d3a02f750e9eb547a6db6e9405154d0d4b36641 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Sun, 22 Jan 2017 12:49:36 +0100 -Subject: [PATCH 138/220] BCM270x DT: expose 3.3V and 5V system rails +Subject: [PATCH 137/229] BCM270x DT: expose 3.3V and 5V system rails Signed-off-by: Matthias Reichl --- @@ -126683,10 +126590,10 @@ index a46cb4a8b1419edd95e0e07c18b0f373222dc2bf..36d853715f2379e1952ce3d3be58dd67 + }; }; -From 628011120453bc609f27087fc87c9d919356bc7e Mon Sep 17 00:00:00 2001 +From 69311a52ed134f9cd20ee838b963415534d4c3fd Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Sun, 22 Jan 2017 12:49:36 +0100 -Subject: [PATCH 139/220] BCM270x DT: Consolidate audio card overlays +Subject: [PATCH 138/229] BCM270x DT: Consolidate audio card overlays Reference 3.3V / 5V system rails instead of instantiating local regulators. @@ -126981,10 +126888,10 @@ index 16b1247bfa618ff85936ddf78c3aea58075eaa67..f8d48233e28c7c18509b4a95692f6aff __overlay__ { compatible = "rra,digidac1-soundcard"; -From 95ca969b2e456bb562ed0566375eb7ae340c51f8 Mon Sep 17 00:00:00 2001 +From 03ce521ccd30fe64b294c85c44e4ace162911b93 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Sun, 22 Jan 2017 12:49:37 +0100 -Subject: [PATCH 140/220] ASoC: Add driver for Cirrus Logic Audio Card +Subject: [PATCH 139/229] ASoC: Add driver for Cirrus Logic Audio Card Note: due to problems with deferred probing of regulators the following softdep should be added to a modprobe.d file @@ -128234,10 +128141,10 @@ index 0000000000000000000000000000000000000000..ac8651ddff7bd3701dffe22c7fb88352 +MODULE_DESCRIPTION("ASoC driver for Cirrus Logic Audio Card"); +MODULE_LICENSE("GPL"); -From f44dfb33964a1c4605f4f9cf481c7bc0b9d2bff6 Mon Sep 17 00:00:00 2001 +From 64255853d68677b808a3180c98b7cd74e261d10f Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Sun, 22 Jan 2017 12:49:37 +0100 -Subject: [PATCH 141/220] config: enable Cirrus Logic Audio Card +Subject: [PATCH 140/229] config: enable Cirrus Logic Audio Card Signed-off-by: Matthias Reichl --- @@ -128286,10 +128193,10 @@ index 74bc0d81bcb4d7f6676368926cdcc10e581fbcae..f0b87d15e959d88eb26e5a11244365da CONFIG_SND_BCM2708_SOC_RPI_PROTO=m CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m -From 2c0b23c58a5b98e6e4ed872285009ab404a36327 Mon Sep 17 00:00:00 2001 +From 28979551fcf782d3fff4e62cfb33f70576689534 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 9 Feb 2017 14:33:30 +0000 -Subject: [PATCH 142/220] irq-bcm2836: Avoid "Invalid trigger warning" +Subject: [PATCH 141/229] irq-bcm2836: Avoid "Invalid trigger warning" Initialise the level for each IRQ to avoid a warning from the arm arch timer code. @@ -128313,10 +128220,10 @@ index 486bcbfb32305ee417f6b3be7e91a3ff069a586c..e10597c1a1e51e5e27aa574b6a26d871 static void -From eb17d3c8b7537d536f873e4a8cbceff01d52b4ab Mon Sep 17 00:00:00 2001 +From 4a26c514f3ceadc5fac1f60c20270094cd5683d6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 9 Feb 2017 14:36:44 +0000 -Subject: [PATCH 143/220] sound: Demote deferral errors to INFO level +Subject: [PATCH 142/229] sound: Demote deferral errors to INFO level At present there is no mechanism to specify driver load order, which can lead to deferrals and repeated retries until successful. @@ -128351,10 +128258,10 @@ index c0bbcd9032613a78aef551ce697cabc792880bad..a2504d8c83d74d7227e65be142a26cc9 goto _err_defer; } -From 63afb4ab766224a831fdf16e534250d60384edb4 Mon Sep 17 00:00:00 2001 +From dfaae9e11853b96a79aecc1ca7bf4cea2d12d2ca Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 9 Feb 2017 14:40:33 +0000 -Subject: [PATCH 144/220] sound: Suppress error message about deferrals +Subject: [PATCH 143/229] sound: Suppress error message about deferrals Since driver load deferrals are expected and will already have resulted in a kernel message, suppress an essentially @@ -128601,10 +128508,10 @@ index 9db678e885efd63d84d60a098a84ed6772b19a2d..fadbfade100228aaafabb0d3bdf35c01 return ret; } -From 5ae4f5002dd0d56ec5a5f0460dbc6f23e9a1d563 Mon Sep 17 00:00:00 2001 +From 70a5074730562de432cd1414e4f651769ff3611e Mon Sep 17 00:00:00 2001 From: Claggy3 Date: Sat, 11 Feb 2017 14:00:30 +0000 -Subject: [PATCH 145/220] Update vfpmodule.c +Subject: [PATCH 144/229] Update vfpmodule.c Christopher Alexander Tobias Schulze - May 2, 2015, 11:57 a.m. This patch fixes a problem with VFP state save and restore related @@ -128741,10 +128648,10 @@ index da0b33deba6d3c2906eef271f253ab7a30a92680..c6f1d6da808cda78a58f184e19e83522 /* * Save the userland NEON/VFP state. Under UP, -From 08cb651151531dc65340f990bdf8e592188a9395 Mon Sep 17 00:00:00 2001 +From dfd4e143cb7bdc1ccebe1d48f4e49fc6dd5a2f9a Mon Sep 17 00:00:00 2001 From: Martin Cerveny Date: Mon, 13 Feb 2017 17:23:47 +0100 -Subject: [PATCH 146/220] dwc_otg: fix summarize urb->actual_length for +Subject: [PATCH 145/229] dwc_otg: fix summarize urb->actual_length for isochronous transfers Kernel does not copy input data of ISO transfers to userspace @@ -128772,10 +128679,10 @@ index 162a656501988e56c9d780b7793d365fde09f801..992269d61ecf48126379a38e528f7190 dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i); } -From faf677a63e70517cd59a04f6aed3b11a8de295d7 Mon Sep 17 00:00:00 2001 +From 576b5c9de48614542ad32cb61c75d77281d7845f Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 1 Dec 2016 22:00:19 +0100 -Subject: [PATCH 147/220] clk: bcm: Support rate change propagation on bcm2835 +Subject: [PATCH 146/229] clk: bcm: Support rate change propagation on bcm2835 clocks Some peripheral clocks, like the VEC (Video EnCoder) clock need to be set @@ -128900,10 +128807,10 @@ index a99ccf9f056d3a3e7c482339e08483f3701ebc04..dafaa6b22724ab41dac1327cfa81de09 init.ops = &bcm2835_vpu_clock_clk_ops; } else { -From 3638f582dd0f8588d85467a6e1c0832807092dd4 Mon Sep 17 00:00:00 2001 +From e5efacb9b223f6ffd713e2e30769e4a4f3ed36dc Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 1 Dec 2016 22:00:20 +0100 -Subject: [PATCH 148/220] clk: bcm: Allow rate change propagation to PLLH_AUX +Subject: [PATCH 147/229] clk: bcm: Allow rate change propagation to PLLH_AUX on VEC clock The VEC clock requires needs to be set at exactly 108MHz. Allow rate @@ -128938,10 +128845,10 @@ index dafaa6b22724ab41dac1327cfa81de09908a4dfd..0453d7c6a63923370e4191db2c4d083b /* dsi clocks */ [BCM2835_CLOCK_DSI0E] = REGISTER_PER_CLK( -From 9060ca4581c44c6c5c5b4deae146cfcf44f9e10c Mon Sep 17 00:00:00 2001 +From 38e87f3c4f8869155fc0e158daf081477a30e8dc Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 12 Dec 2016 09:00:53 +0100 -Subject: [PATCH 149/220] clk: bcm: Fix 'maybe-uninitialized' warning in +Subject: [PATCH 148/229] clk: bcm: Fix 'maybe-uninitialized' warning in bcm2835_clock_choose_div_and_prate() best_rate is reported as potentially uninitialized by gcc. @@ -128970,10 +128877,10 @@ index 0453d7c6a63923370e4191db2c4d083b893b3b47..9d895726ebb24bc78a2014870dbdd7c7 struct clk_hw *parent; -From 5834187e64129c0e106d29bb872f81695b168815 Mon Sep 17 00:00:00 2001 +From 200123c63be7a15943470ac28ad36a833f7b230b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 18 Jan 2017 07:31:55 +1100 -Subject: [PATCH 150/220] clk: bcm2835: Don't rate change PLLs on behalf of DSI +Subject: [PATCH 149/229] clk: bcm2835: Don't rate change PLLs on behalf of DSI PLL dividers. Our core PLLs are intended to be configured once and left alone. With @@ -129145,10 +129052,10 @@ index 9d895726ebb24bc78a2014870dbdd7c779cd1cdf..b58cff2756581ba7e0be8a818cdbdf72 /* the clocks */ -From 2e8e35870b82fb5de73255fa7af66565f8fb50e5 Mon Sep 17 00:00:00 2001 +From 360fff2ec652b2f2e5ba70d7866bbca3e4de4340 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 18 Jan 2017 07:31:56 +1100 -Subject: [PATCH 151/220] clk: bcm2835: Register the DSI0/DSI1 pixel clocks. +Subject: [PATCH 150/229] clk: bcm2835: Register the DSI0/DSI1 pixel clocks. The DSI pixel clocks are muxed from clocks generated in the analog phy by the DSI driver. In order to set them as parents, we need to do the @@ -129390,10 +129297,10 @@ index 360e00cefd35679b49890234b5c369fb52b89e20..a0c812b0fa391d149b4f546db39bdc4b +#define BCM2835_CLOCK_DSI0P 49 +#define BCM2835_CLOCK_DSI1P 50 -From 61a75db41f54a9792d7e84647dacee8610247139 Mon Sep 17 00:00:00 2001 +From 9ff06b257d97ee933e6ce72895f8045fe3f796ac Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 18 Jan 2017 07:31:57 +1100 -Subject: [PATCH 152/220] clk: bcm2835: Add leaf clock measurement support, +Subject: [PATCH 151/229] clk: bcm2835: Add leaf clock measurement support, disabled by default This proved incredibly useful during debugging of the DSI driver, to @@ -129739,10 +129646,10 @@ index b2c277b378ee799a4f8e05ad076d1253e85cb392..136e5d28f9eaeaa10d45382a0f31da9f /* the gates */ -From 218ade97d646c5cb8e0570d3f48f505d9a93b844 Mon Sep 17 00:00:00 2001 +From edfb256b81b5759de8c1ae604a9207f32485bb90 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 26 Apr 2016 13:46:13 -0700 -Subject: [PATCH 153/220] drm/panel: Add support for the Raspberry Pi 7" +Subject: [PATCH 152/229] drm/panel: Add support for the Raspberry Pi 7" Touchscreen. This driver communicates with the Atmel microcontroller for sequencing @@ -130323,10 +130230,10 @@ index 0000000000000000000000000000000000000000..1a536fe4d040f5fafe324baee110a622 +MODULE_DESCRIPTION("Raspberry Pi 7-inch touchscreen driver"); +MODULE_LICENSE("GPL v2"); -From 63053a5639161cfd102eab240fc0ea17eb7ae2a9 Mon Sep 17 00:00:00 2001 +From 971722af64e67ce4d6b95334cb5ef9eb106de78c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 2 Jun 2016 12:29:45 -0700 -Subject: [PATCH 154/220] BCM270X: Add the DSI panel to the defconfig. +Subject: [PATCH 153/229] BCM270X: Add the DSI panel to the defconfig. Signed-off-by: Eric Anholt --- @@ -130375,10 +130282,10 @@ index 8c4392344eb4495689c220d5d176ee8c189079fd..301611d2283f5f8800339271cea59aed CONFIG_DRM_VC4=m CONFIG_FB=y -From 38cc16a87a73c268f0b2f8a48804c309f9c51b93 Mon Sep 17 00:00:00 2001 +From 43367ec7cb74fe771991888f2a32f91c128224b8 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 13 Dec 2016 15:15:10 -0800 -Subject: [PATCH 155/220] ARM: bcm2835: dt: Add the DSI module nodes and +Subject: [PATCH 154/229] ARM: bcm2835: dt: Add the DSI module nodes and clocks. The modules stay disabled by default, and if you want to enable DSI @@ -130482,10 +130389,10 @@ index 51cdefbf5eb265f49bd05e0aa91dfbeee3fbfdcc..41776b97b4b6b1c053d07fd357fac4ba compatible = "brcm,bcm2835-i2c"; reg = <0x7e804000 0x1000>; -From 83e93acdc1971583e26e5e5d073f38b0210ada55 Mon Sep 17 00:00:00 2001 +From 45e66e1dae71050403d0c54e3b5d12666fb86f83 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 2 Jun 2016 15:09:35 -0700 -Subject: [PATCH 156/220] BCM270X: Enable the DSI panel node in the VC4 +Subject: [PATCH 155/229] BCM270X: Enable the DSI panel node in the VC4 overlay. Signed-off-by: Eric Anholt @@ -130636,10 +130543,10 @@ index 4f1cc20f90dc6780f74e08ebee00e5a1a6062c85..f25cd9a3936861920b0d518ff2d773ee cma-256 = <0>,"+0-1-2-3-4"; cma-192 = <0>,"-0+1-2-3-4"; -From ee952b37b9f922003ee9585cfc2a42e2114352a6 Mon Sep 17 00:00:00 2001 +From 9e135ea40fb0e583455fc8050bf7ecdd9eab9275 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 3 Nov 2016 18:53:10 -0700 -Subject: [PATCH 157/220] drm/vc4: Add support for rendering with ETC1 +Subject: [PATCH 156/229] drm/vc4: Add support for rendering with ETC1 textures. The validation for it ends up being quite simple, but I hadn't got @@ -130699,10 +130606,10 @@ index ad7edc3edf7ca1d653a0bc025a5eda6692b74370..69caa21f0cb23c9439238f6239c0041b struct drm_vc4_get_param { __u32 param; -From 52b3d9cf40d631805d4024ed9e3c4a98417fae5e Mon Sep 17 00:00:00 2001 +From b19682fb87dd6393ae3685f081f6e154889ffa2d Mon Sep 17 00:00:00 2001 From: Jonas Pfeil Date: Tue, 8 Nov 2016 00:18:39 +0100 -Subject: [PATCH 158/220] drm/vc4: Add fragment shader threading support +Subject: [PATCH 157/229] drm/vc4: Add fragment shader threading support FS threading brings performance improvements of 0-20% in glmark2. @@ -130938,10 +130845,10 @@ index 69caa21f0cb23c9439238f6239c0041b178d5669..f07a090167261131076438960c1dec17 struct drm_vc4_get_param { __u32 param; -From 332076ec2c47807ce3a887b1d5f553cfe3726327 Mon Sep 17 00:00:00 2001 +From 14b543648ecaac69b9d2aa32c6d72a994812517c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 2 Dec 2016 14:48:09 +0100 -Subject: [PATCH 159/220] drm: Add TV connector states to drm_connector_state +Subject: [PATCH 158/229] drm: Add TV connector states to drm_connector_state Some generic TV connector properties are exposed in drm_mode_config, but they are currently handled independently in each DRM encoder driver. @@ -131091,10 +130998,10 @@ index ac9d7d8e0e43a807e9fc9a0b66de5f26b49d3348..2645e803857253ff98eb94aa1bacc825 /** -From a6b2130dbab5288f1b71bf07172db1d5fdd7fca0 Mon Sep 17 00:00:00 2001 +From 53806e85b0e28114d335f5f1e1cc44ac7f324965 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 2 Dec 2016 14:48:08 +0100 -Subject: [PATCH 160/220] drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into +Subject: [PATCH 159/229] drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum List of values like the DRM_MODE_SUBCONNECTOR_xx ones are better @@ -131141,10 +131048,10 @@ index df0e3504c349a950bf41540fbcd6cd944cf11d2f..970bfc0d7107451e5bc4e29c524a764c #define DRM_MODE_CONNECTOR_Unknown 0 #define DRM_MODE_CONNECTOR_VGA 1 -From e7d68f5b95e20acbfbb8cc5b511ef866567594c4 Mon Sep 17 00:00:00 2001 +From 23f61d053734a6ad483786b3efe9b9975ac7f732 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 2 Dec 2016 14:48:10 +0100 -Subject: [PATCH 161/220] drm/vc4: Add support for the VEC (Video Encoder) IP +Subject: [PATCH 160/229] drm/vc4: Add support for the VEC (Video Encoder) IP The VEC IP is a TV DAC, providing support for PAL and NTSC standards. @@ -131883,10 +131790,10 @@ index 0000000000000000000000000000000000000000..32bb8ef985fbc6f39f9e5f459846bb77 + }, +}; -From e94a14543823231f5ab650e1e9bc59be54b5a19b Mon Sep 17 00:00:00 2001 +From 966bbd4c2c379b753065dc168a690231cf1673dc Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 15 Sep 2016 15:25:23 +0100 -Subject: [PATCH 162/220] drm/vc4: Set up SCALER_DISPCTRL at boot. +Subject: [PATCH 161/229] drm/vc4: Set up SCALER_DISPCTRL at boot. We want the HVS on, obviously, and we also want DSP3 (PV1's source) to be muxed from HVS channel 2 like we expect in vc4_crtc.c. The @@ -131946,10 +131853,10 @@ index 39f6886b24100c43b590e47e0c7bc44846721d65..b3b297fba7097bc495fa8916292c5479 * SCALER_DISPSTAT_IRQDISP0. Note that short frame contributions are * always enabled. -From faac17bf8b9cb3632accb22b0c9145a8ea75960b Mon Sep 17 00:00:00 2001 +From 54721806cc59807aa15ca137bf38ee22bdc58132 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 10 Feb 2016 16:17:29 -0800 -Subject: [PATCH 163/220] drm/vc4: Add support for feeding DSI encoders from +Subject: [PATCH 162/229] drm/vc4: Add support for feeding DSI encoders from the pixel valve. We have to set a different pixel format, which tells the hardware to @@ -131963,7 +131870,7 @@ Signed-off-by: Eric Anholt 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c -index bdf32c572fc2c46932daca934dfb002d05493883..0a861158740586836d2d47cccae4109ad4ec968d 100644 +index c7e478f672e184974a33bb9ca72b8aa62d76e97e..a4937e261202748924a5a327995b6f700afd5a97 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -352,38 +352,40 @@ static u32 vc4_get_fifo_full_level(u32 format) @@ -132064,10 +131971,10 @@ index b3b297fba7097bc495fa8916292c547925720199..385405a2df05eb3dd86d4f687aa82053 # define PV_VCONTROL_VIDEN BIT(0) -From c7c932bf0e314be090c2f9563c4083d3f90e4ec5 Mon Sep 17 00:00:00 2001 +From ba6346905722f941f3ed1849bbcbeddeb3e3134c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 10 Feb 2016 11:42:32 -0800 -Subject: [PATCH 164/220] drm/vc4: Add DSI driver +Subject: [PATCH 163/229] drm/vc4: Add DSI driver The DSI0 and DSI1 blocks on the 2835 are related hardware blocks. Some registers move around, and the featureset is slightly different, @@ -133895,10 +133802,10 @@ index 0000000000000000000000000000000000000000..17fcac381dbb37cd9a5ff210ad8578f4 + }, +}; -From f989d336154383fb68900bdd474cd765f2422216 Mon Sep 17 00:00:00 2001 +From 40b37524ea6056707d4fa2ab232cab7132816a6e Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 2 Dec 2016 14:48:12 +0100 -Subject: [PATCH 165/220] ARM: dts: bcm283x: Add VEC node in bcm283x.dtsi +Subject: [PATCH 164/229] ARM: dts: bcm283x: Add VEC node in bcm283x.dtsi Add the VEC (Video EnCoder) node definition in bcm283x.dtsi. @@ -133929,10 +133836,10 @@ index 41776b97b4b6b1c053d07fd357fac4ba4787ac53..d3cc586661f903e67a840189c0446aa8 compatible = "brcm,bcm2835-pixelvalve2"; reg = <0x7e807000 0x100>; -From b912118cbba61496211f790134093433a9e13487 Mon Sep 17 00:00:00 2001 +From dc1d5236f122dd294d9333680bc4f19cc782f54c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 2 Dec 2016 14:48:13 +0100 -Subject: [PATCH 166/220] ARM: dts: bcm283x: Enable the VEC IP on all +Subject: [PATCH 165/229] ARM: dts: bcm283x: Enable the VEC IP on all RaspberryPi boards Enable the VEC IP on all RaspberryPi boards. @@ -133958,10 +133865,10 @@ index 365648898f3acc4f82dc6cb58e4bbebbe249be94..d4577a51e678cb600b475d3d3395ca4e + status = "okay"; +}; -From 1d878f349a231e3d6adaa38600eb138a8d5ae3f8 Mon Sep 17 00:00:00 2001 +From 74f587581a6e7ca01674619b38699d7588a6c230 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 23 Jan 2017 11:41:54 -0800 -Subject: [PATCH 167/220] BCM270X: Disable VEC unless vc4-kms-v3d is present. +Subject: [PATCH 166/229] BCM270X: Disable VEC unless vc4-kms-v3d is present. Signed-off-by: Eric Anholt --- @@ -134000,10 +133907,10 @@ index f25cd9a3936861920b0d518ff2d773ee467e2f49..a8ef8c9051668a7477dea30aa262568c cma-256 = <0>,"+0-1-2-3-4"; cma-192 = <0>,"-0+1-2-3-4"; -From 404c6a5d9c07a89b3c6c07c1ccac1222c31d27cf Mon Sep 17 00:00:00 2001 +From 7c0bed1aaed0e68b94d0e66610c180b36aaf221a Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 1 Feb 2017 17:09:18 -0800 -Subject: [PATCH 168/220] drm/vc4: Name the primary and cursor planes in fkms. +Subject: [PATCH 167/229] drm/vc4: Name the primary and cursor planes in fkms. This makes debugging nicer, compared to trying to remember what the IDs are. @@ -134027,10 +133934,10 @@ index d18a1dae51a2275846c9826b5bf1ba57ae97b55c..e49ce68b607a7ffc2329e3235362f3bc if (type == DRM_PLANE_TYPE_PRIMARY) { vc4_plane->fbinfo = -From c093ed979e0a69557ebfcbaa1f44bea1e232ba7f Mon Sep 17 00:00:00 2001 +From 6e27de8364a6cef10ca9e0ee71136c8e3e97387b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 1 Feb 2017 17:10:09 -0800 -Subject: [PATCH 169/220] drm/vc4: Add DRM_DEBUG_ATOMIC for the insides of +Subject: [PATCH 168/229] drm/vc4: Add DRM_DEBUG_ATOMIC for the insides of fkms. Trying to debug weston on fkms involved figuring out what calls I was @@ -134100,10 +134007,10 @@ index e49ce68b607a7ffc2329e3235362f3bc21ed5cbb..dbf065677202fbebf8e3a0cffbe880aa RPI_FIRMWARE_SET_CURSOR_STATE, &packet_state, -From 69298e6cd8f0b2e5c63d200dcb4728c151d51c8c Mon Sep 17 00:00:00 2001 +From 9603c092bb73984198d90990c206c4cdb2ca0d27 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 2 Feb 2017 09:42:18 -0800 -Subject: [PATCH 170/220] drm/vc4: Fix sending of page flip completion events +Subject: [PATCH 169/229] drm/vc4: Fix sending of page flip completion events in FKMS mode. In the rewrite of vc4_crtc.c for fkms, I dropped the part of the @@ -134145,10 +134052,10 @@ index dbf065677202fbebf8e3a0cffbe880aa42daef3f..da818a207bfa639b8cea48d94bcf4566 static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) -From ad245132fc0f2ebe6e367f8b3e42a9aa65bd7b4a Mon Sep 17 00:00:00 2001 +From 063fdbf198e68bf5acf896d170351c2021da0114 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 8 Feb 2017 15:00:54 -0800 -Subject: [PATCH 171/220] drm/vc4: Fulfill user BO creation requests from the +Subject: [PATCH 170/229] drm/vc4: Fulfill user BO creation requests from the kernel BO cache. The from_cache flag was actually "the BO is invisible to userspace", @@ -134201,10 +134108,10 @@ index 3f6704cf6608d7be47637c6aa585de087b7f74ee..5ec14f25625dde6fd61e10415092fa25 cma_obj = drm_gem_cma_create(dev, size); -From d38462637c46bfaf7e456a05c950c57a9d74a6bd Mon Sep 17 00:00:00 2001 +From e4042424a6af42f9f2b3450f091c600655aa27a4 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 9 Feb 2017 09:23:34 -0800 -Subject: [PATCH 172/220] drm/vc4: Fix OOPSes from trying to cache a partially +Subject: [PATCH 171/229] drm/vc4: Fix OOPSes from trying to cache a partially constructed BO. If a CMA allocation failed, the partially constructed BO would be @@ -134238,10 +134145,10 @@ index 5ec14f25625dde6fd61e10415092fa25527cc151..fd83a28076564b9ea5cf0f2ba29b884e if (!cache_list) { vc4_bo_destroy(bo); -From e8c7c517a4ec706104026119188765393a6b01c0 Mon Sep 17 00:00:00 2001 +From fe89695150b22bea927c6351ea8e0ed8ee2b780d Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 12 Oct 2015 08:58:08 -0700 -Subject: [PATCH 173/220] drm/vc4: Verify at boot that CMA doesn't cross a +Subject: [PATCH 172/229] drm/vc4: Verify at boot that CMA doesn't cross a 256MB boundary. I've seen lots of users cranking CMA up higher, so throw an error if @@ -134324,10 +134231,10 @@ index c960459eda7e640ea55be1d4ed80c6a9125a8877..b50245282a18bc790da0f901944c2e67 static unsigned long cma_bitmap_aligned_mask(const struct cma *cma, int align_order) -From f13fc1876a6218896b4ffa952dfcd9c6651ac542 Mon Sep 17 00:00:00 2001 +From 8bc34cf4015adcf7f81205122b9541398a596762 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 17 Feb 2017 09:47:11 +0000 -Subject: [PATCH 174/220] BCM270X_DT: Add SMSC ethernet controller to DT +Subject: [PATCH 173/229] BCM270X_DT: Add SMSC ethernet controller to DT With an ethernet node in the DT, a suitable firmware can populate the local-mac-address property, removing the need for a downstream patch @@ -134390,10 +134297,10 @@ index d29ba72de727fe26b5a586e0bd0a41181c68ae04..78101849441679baf3624cf67a0ff7a2 / { model = "Raspberry Pi 3 Model B"; -From 6582c676aee037189fc29847dd11a8558841d77f Mon Sep 17 00:00:00 2001 +From e1666ea2024adaa3745e1ddfd171e2e2f9b871f2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 17 Feb 2017 15:26:13 +0000 -Subject: [PATCH 175/220] brcmfmac: Mute expected startup 'errors' +Subject: [PATCH 174/229] brcmfmac: Mute expected startup 'errors' The brcmfmac WiFi driver always complains about the '00' country code and the firmware version is reported as an error. Modify the driver to @@ -134432,10 +134339,10 @@ index 4051780f64f44a5ce522babe6c371a1beb79a824..b081673abcb4aa72d70d8e0834b608f6 /* locate firmware version number for ethtool */ ptr = strrchr(buf, ' ') + 1; -From f2e36f81e3c8055950ceeab46639b9396386ba37 Mon Sep 17 00:00:00 2001 +From 77a9e71e9aa65d4b9037580f3e2454edb30fccc6 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Feb 2017 17:20:08 +0000 -Subject: [PATCH 176/220] clk-bcm2835: Mark used PLLs and dividers CRITICAL +Subject: [PATCH 175/229] clk-bcm2835: Mark used PLLs and dividers CRITICAL The VPU configures and relies on several PLLs and dividers. Mark all enabled dividers and their PLLs as CRITICAL to prevent the kernel from @@ -134463,10 +134370,10 @@ index 136e5d28f9eaeaa10d45382a0f31da9f4adb91ef..4192863778c8009aacfc9a49ee38ad1c divider->data = data; -From 75204fb0be1d1c4d3bfafc95ab4ce6f95be9f21d Mon Sep 17 00:00:00 2001 +From e34c5f1346b7125471e6bb6063f6f48055688738 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Feb 2017 17:20:08 +0000 -Subject: [PATCH 177/220] clk-bcm2835: Add claim-clocks property +Subject: [PATCH 176/229] clk-bcm2835: Add claim-clocks property The claim-clocks property can be used to prevent PLLs and dividers from being marked as critical. It contains a vector of clock IDs, @@ -134601,10 +134508,10 @@ index 4192863778c8009aacfc9a49ee38ad1ca62a01e4..6b245357e4e93c19a839eee92a82f95a sizeof(cprman_parent_names)); of_clk_parent_fill(dev->of_node, cprman->real_parent_names, -From ecd92075685f3d97757db3408223901af0a17475 Mon Sep 17 00:00:00 2001 +From be10b2ef524572ca6161a1d8b1dfaff7e8821166 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Mon, 20 Feb 2017 20:01:16 +0100 -Subject: [PATCH 178/220] dmaengine: bcm2835: Fix cyclic DMA period splitting +Subject: [PATCH 177/229] dmaengine: bcm2835: Fix cyclic DMA period splitting The code responsible for splitting periods into chunks that can be handled by the DMA controller missed to update total_len, @@ -134643,10 +134550,10 @@ index 80d35f760b4a4a51e60c355a84d538bac3892a4d..599c218dc8a73172dd4bd4a058fc8f95 /* calculate the length that remains to reach period_length */ control_block->length = period_len - *total_len; -From f292e0c479d6bc88781a77dc1626b31595bf9ac2 Mon Sep 17 00:00:00 2001 +From 96de3f8a9aedb7ee89be98e8f0f5c002d97f2446 Mon Sep 17 00:00:00 2001 From: Scott Ellis Date: Thu, 23 Feb 2017 11:56:20 -0500 -Subject: [PATCH 179/220] Add ads1015 driver to config +Subject: [PATCH 178/229] Add ads1015 driver to config --- arch/arm/configs/bcm2709_defconfig | 3 ++- @@ -134700,10 +134607,10 @@ index 9a9cd1cdcb2f76d4408568681ec80885293bae48..554fed3a4fbfd1940422b808046c6d2b CONFIG_FB=y CONFIG_FB_BCM2708=y -From 6689e68ab8efe29a3cafbe7398a4f26e55cc223e Mon Sep 17 00:00:00 2001 +From c208ea3209328063c8df1bf1b2046b0d0b72cdd5 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 27 Jan 2017 18:49:30 +0000 -Subject: [PATCH 180/220] config: add slcan kernel module +Subject: [PATCH 179/229] config: add slcan kernel module See: https://github.com/raspberrypi/linux/issues/1819 --- @@ -134736,10 +134643,10 @@ index 554fed3a4fbfd1940422b808046c6d2b1f508394..99888182259b280790a7506b248a8130 CONFIG_IRDA=m CONFIG_IRLAN=m -From 5476da49a0513f2782a6ccae1fedf2cc38201d80 Mon Sep 17 00:00:00 2001 +From 00d0301a093b7f79d4809fcc113b9839b5029e97 Mon Sep 17 00:00:00 2001 From: Miquel Date: Fri, 24 Feb 2017 20:51:06 +0100 -Subject: [PATCH 181/220] sound: Support for Dion Audio LOCO-V2 DAC-AMP HAT +Subject: [PATCH 180/229] sound: Support for Dion Audio LOCO-V2 DAC-AMP HAT Signed-off-by: Miquel Blauw --- @@ -135003,10 +134910,10 @@ index 0000000000000000000000000000000000000000..a009c49477972a9832175d86f201b035 +MODULE_DESCRIPTION("ASoC Driver for DionAudio LOCO-V2"); +MODULE_LICENSE("GPL v2"); -From 910ace3d10614d67b74540f5975740a6711b6709 Mon Sep 17 00:00:00 2001 +From 84f9e798ff7f63f2de7d5ce97b5fc9cc642cc995 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Sun, 26 Feb 2017 01:13:02 +0000 -Subject: [PATCH 182/220] SQUASH: Add LOCO-V2 overlay from last commit +Subject: [PATCH 181/229] SQUASH: Add LOCO-V2 overlay from last commit --- .../dts/overlays/dionaudio-loco-v2-overlay.dts | 49 ++++++++++++++++++++++ @@ -135069,10 +134976,10 @@ index 0000000000000000000000000000000000000000..a1af93de30119734e8d14cbd454589d3 + }; +}; -From aaa9491e3b03a685d8b336411ef75ecc29452ff6 Mon Sep 17 00:00:00 2001 +From 5532e4a2891e94cad11a2c9f5238e073ad98b2fd Mon Sep 17 00:00:00 2001 From: Fe-Pi Date: Wed, 1 Mar 2017 04:42:43 -0700 -Subject: [PATCH 183/220] Add support for Fe-Pi audio sound card. (#1867) +Subject: [PATCH 182/229] Add support for Fe-Pi audio sound card. (#1867) Fe-Pi Audio Sound Card is based on NXP SGTL5000 codec. Mechanical specification of the board is the same the Raspberry Pi Zero. @@ -135421,10 +135328,10 @@ index 0000000000000000000000000000000000000000..015b56fd73cc36be5b5eecd17548fd03 +MODULE_DESCRIPTION("ASoC Driver for Fe-Pi Audio"); +MODULE_LICENSE("GPL v2"); -From 07dc8de314890c5718b766ac02f5c889fc362abd Mon Sep 17 00:00:00 2001 +From 14a2bffb1f12e8f4fea74332aa3286c53d620502 Mon Sep 17 00:00:00 2001 From: Scott Ellis Date: Wed, 1 Mar 2017 07:22:24 -0500 -Subject: [PATCH 184/220] Add overlay for ads1115 ADCs (#1864) +Subject: [PATCH 183/229] Add overlay for ads1115 ADCs (#1864) --- arch/arm/boot/dts/overlays/Makefile | 1 + @@ -135588,10 +135495,10 @@ index 0000000000000000000000000000000000000000..7c16a1af3172d14e1a976b1776b9f167 + }; +}; -From 045d35e72184011869bdfccf740c5b0625d7917f Mon Sep 17 00:00:00 2001 +From cb3b58cca69fe52de364c33109e50471d5b13dda Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 1 Mar 2017 16:06:53 +0000 -Subject: [PATCH 185/220] clk-bcm2835: Correct the prediv logic +Subject: [PATCH 184/229] clk-bcm2835: Correct the prediv logic If a clock has the prediv flag set, both the integer and fractional parts must be scaled when calculating the resulting frequency. @@ -135618,10 +135525,10 @@ index 6b245357e4e93c19a839eee92a82f95aec996e4e..8ea29fbc8dc451b9cff502bc1a918ae6 return bcm2835_pll_rate_from_divisors(parent_rate, ndiv, fdiv, pdiv); } -From 9833d81be5ae7b8301cd846efdacddb9954a8331 Mon Sep 17 00:00:00 2001 +From 4d154d37fead1447c7221ca0d4b0b8dbcfc297cf Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 1 Mar 2017 16:07:39 +0000 -Subject: [PATCH 186/220] amba_pl011: Round input clock up +Subject: [PATCH 185/229] amba_pl011: Round input clock up The UART clock is initialised to be as close to the requested frequency as possible without exceeding it. Now that there is a @@ -135707,10 +135614,10 @@ index 5a11ff833e1fd112ba04df3a427cd94bf6793ec5..003a5b0c30295dbbcb94a28d0c64d124 /* unregisters the driver also if no more ports are left */ static void pl011_unregister_port(struct uart_amba_port *uap) -From 0f1383deac133e518b7c1e84e2f6cb6b0918b9f5 Mon Sep 17 00:00:00 2001 +From 30382da357246ac32d4d445c495b95bd57146e56 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 13 Feb 2017 11:10:50 +0000 -Subject: [PATCH 187/220] BCM2835-V4L2: Ensure H264 header bytes get a sensible +Subject: [PATCH 186/229] BCM2835-V4L2: Ensure H264 header bytes get a sensible timestamp H264 header come off VC with 0 timestamps, which means they get a @@ -135799,10 +135706,10 @@ index e6aeb7e7e381de65d6c6586205069a4c5cd33274..7f8a68916a67001bc9241bce2928519a struct vchiq_mmal_port *port; /* port being used for capture */ /* camera port being used for capture */ -From 568318dde09bbbaeb5c6ffe813d9885ca9cd0b1c Mon Sep 17 00:00:00 2001 +From e37b420844cab750b4b0ca1ed5eeb0aab65577c4 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 13 Feb 2017 13:11:41 +0000 -Subject: [PATCH 188/220] BCM2835-V4L2: Correctly denote key frames in encoded +Subject: [PATCH 187/229] BCM2835-V4L2: Correctly denote key frames in encoded data Forward MMAL key frame flags to the V4L2 buffers. @@ -135827,10 +135734,10 @@ index e69731320f4e59249933bc21843913deab4a1209..6bdec0806126044cf7146d53326e4da5 "Buffer has ts %llu", dev->capture.last_timestamp); -From 51ecb04f5852f54bdeeef4485f729f9e070ecc82 Mon Sep 17 00:00:00 2001 +From d798550b4fa22e6947eac75b9f626bd2d07ffc9d Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 20 Feb 2017 17:01:21 +0000 -Subject: [PATCH 189/220] bcm2835-gpio-exp: Driver for GPIO expander via +Subject: [PATCH 188/229] bcm2835-gpio-exp: Driver for GPIO expander via mailbox service Pi3 and Compute Module 3 have a GPIO expander that the @@ -136248,10 +136155,10 @@ index 2859db09e25bb945251e85edb39bc43430857168..56b3f0fe1ea3d22fcf207e6df90b640e /* Dispmanx TAGS */ RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001, -From 843d61b8346e9a2c49c2d4cbdef680175b503b2e Mon Sep 17 00:00:00 2001 +From 398c0b7dd08ce4698e8fa058a212293113d57741 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 24 May 2016 16:30:05 +0100 -Subject: [PATCH 190/220] BCM270X_DT: Add bcm2708-rpi-0-w.dts +Subject: [PATCH 189/229] BCM270X_DT: Add bcm2708-rpi-0-w.dts Add DT support for the Pi Zero W. N.B. It will not be loaded automatically without a corresponding change to the firmware. @@ -136479,10 +136386,10 @@ index 0000000000000000000000000000000000000000..db0f99ddf2f46e83827d56e21c4846dd + }; +}; -From d005b22695f92ac66e1a7405c98e6acff08e5e92 Mon Sep 17 00:00:00 2001 +From 67e2a753965b663de7de65220d47e3439b9bece3 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 6 Mar 2017 09:06:18 +0000 -Subject: [PATCH 191/220] clk-bcm2835: Read max core clock from firmware +Subject: [PATCH 190/229] clk-bcm2835: Read max core clock from firmware The VPU is responsible for managing the core clock, usually under direction from the bcm2835-cpufreq driver but not via the clk-bcm2835 @@ -136610,10 +136517,10 @@ index 8ea29fbc8dc451b9cff502bc1a918ae65fb1b306..fe3298b54cdfb96bd90fb4f39e13921d for (i = 0; !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks", -From e7f6dfb5b3ce261660cf5e67b1cfa9d984e9d5b7 Mon Sep 17 00:00:00 2001 +From 2d3684c4b3333b0f1270beac6343860f4f807862 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 7 Mar 2017 19:48:23 +0000 -Subject: [PATCH 192/220] config: Add CONFIG_CRYPTO_LZ4 +Subject: [PATCH 191/229] config: Add CONFIG_CRYPTO_LZ4 Enabling this options allows LZ4 memory compression. @@ -136650,10 +136557,10 @@ index 2c124bbfa343bf2c160250d055e1509678a80850..1748fcb84bdc3853ffccba93a41cd2dc # CONFIG_CRYPTO_HW is not set CONFIG_ARM_CRYPTO=y -From d60a07e2fc0abda4aafc9e029b125389d8a0f714 Mon Sep 17 00:00:00 2001 +From 9aa1e9e321bc7a9a0529baad81fb43f30a3dad0d Mon Sep 17 00:00:00 2001 From: Michael Zoran Date: Thu, 23 Feb 2017 17:54:31 -0800 -Subject: [PATCH 193/220] drm/vc4: Don't wait for vblank when updating the +Subject: [PATCH 192/229] drm/vc4: Don't wait for vblank when updating the cursor Commonly used desktop environments such as xfce4 and gnome @@ -136710,10 +136617,10 @@ index 881bf489478b01b34e9e4df6013fe608c42215ee..14d69bb4967dedcd3bbc475639a8c27e * expected change from the drm_mode_cursor_universal() * helper. -From dba84088915d1ecfb2d7fd4cc5f02d662c46b23f Mon Sep 17 00:00:00 2001 +From a9ba13528c4bf6f3c21f1c7ca98e7ff6cef48f02 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 6 Mar 2017 12:17:16 -0800 -Subject: [PATCH 194/220] panel-raspberrypi-touchscreen: Round up clk rate to +Subject: [PATCH 193/229] panel-raspberrypi-touchscreen: Round up clk rate to fix DSI panel. Commit 488f9bc8e3def93e0baef53cee2026c2cb0d8956 slightly increased the @@ -136748,10 +136655,10 @@ index 1a536fe4d040f5fafe324baee110a6225dd0be08..7f315f04b109621ca7f3861fdd8acf95 .hsync_start = HACT + HFP, .hsync_end = HACT + HFP + HSW, -From 90afefde8ad6549e102301761f790041182ec27b Mon Sep 17 00:00:00 2001 +From b69080b69bb9ed31405bb0ece685f908e29b8530 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Wed, 8 Mar 2017 20:04:13 +1100 -Subject: [PATCH 195/220] Add support for the AudioInjector.net Octo sound card +Subject: [PATCH 194/229] Add support for the AudioInjector.net Octo sound card --- arch/arm/boot/dts/overlays/Makefile | 1 + @@ -137222,10 +137129,10 @@ index 0000000000000000000000000000000000000000..9effea725798640887755dfa688da453 +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:audioinjector-octo-soundcard"); -From 8ffb640336c5094288c8c7876b76d9b0089bfaf0 Mon Sep 17 00:00:00 2001 +From d0cff46e369056e6b3c44cf5404e59c86d9e6014 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Wed, 8 Mar 2017 21:13:24 +1100 -Subject: [PATCH 196/220] ASoC: bcm2835_i2s.c: relax the ch2 register setting +Subject: [PATCH 195/229] ASoC: bcm2835_i2s.c: relax the ch2 register setting for 8 channels This patch allows ch2 registers to be set for 8 channels of audio. @@ -137254,10 +137161,10 @@ index 6ba20498202ed36906b52096893a88867a79269f..c8dd065aea8414b47aa2ea4fc04168b5 format |= BCM2835_I2S_CH1(BCM2835_I2S_CHPOS(ch1pos)); format |= BCM2835_I2S_CH2(BCM2835_I2S_CHPOS(ch2pos)); -From bb30772aa51c75e61e9e8187f22a3b46392da30a Mon Sep 17 00:00:00 2001 +From e1d1177a35fba39eb6bdcedba11870a64debf3f6 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 10 Mar 2017 14:43:15 +0000 -Subject: [PATCH 197/220] bcm2835-v4l2: Fix buffer overflow problem +Subject: [PATCH 196/229] bcm2835-v4l2: Fix buffer overflow problem https://github.com/raspberrypi/linux/issues/1447 port_parameter_get() failed to account for the header @@ -137293,10 +137200,10 @@ index 781322542d5a8295f3d7d5a3eaaf0cac29930c30..e4b243b33f58913f3d2952c97d2a2e3f * but report true size of parameter */ -From 27701c533dd68188ce983afa3a355db0d2418199 Mon Sep 17 00:00:00 2001 +From 59af39c8490b563fd9fe26b2881f20a7b90b8aa1 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Fri, 10 Feb 2017 17:57:08 -0800 -Subject: [PATCH 198/220] build/arm64: Add rules for .dtbo files for dts +Subject: [PATCH 197/229] build/arm64: Add rules for .dtbo files for dts overlays We now create overlays as .dtbo files. @@ -137321,10 +137228,10 @@ index 3635b8662724569d3338ebb620d603c644fe38b7..822fefeb1cd0aa2dc8398f885cf28e9b dtbs: prepare scripts -From 1419ba1eecbca87bb837bf10ea8f44ca48b9ee53 Mon Sep 17 00:00:00 2001 +From 44e344eece74eb129ebbe21352553d51e582bea3 Mon Sep 17 00:00:00 2001 From: John Greb Date: Wed, 8 Mar 2017 15:12:29 +0000 -Subject: [PATCH 199/220] Match dwc2 device-tree fifo sizes to the hardware +Subject: [PATCH 198/229] Match dwc2 device-tree fifo sizes to the hardware values. Since commit aa381a7259c3f53727bcaa8c5f9359e940a0e3fd was reverted with 3fa9538539ac737096c81f3315a14670b1609092 the g-tx-fifo-size array in the device-tree needs to match the preset values in the bcm2835. @@ -137355,10 +137262,10 @@ index 527abc9f0ddf71f4dc7d58336d87684c931cc2f3..265a16bab008453edba198cf2366c423 }; }; -From ec646318b5d58d3ce5037528470468100f157c33 Mon Sep 17 00:00:00 2001 +From c26228c832d36ee5578898c898005c4a8dd06e33 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 5 Mar 2017 11:46:41 +0000 -Subject: [PATCH 200/220] config: Add RTL8XXXU wifi module +Subject: [PATCH 199/229] config: Add RTL8XXXU wifi module --- arch/arm/configs/bcm2709_defconfig | 1 + @@ -137390,10 +137297,10 @@ index bf52db66afb2aa18d6f6f9fb9b64dcbd97e24521..4bc0f8b52b7f39f99d650cb9c4cdfdba CONFIG_ZD1211RW=m CONFIG_MAC80211_HWSIM=m -From d21416717bbf4df7a53962e72978c5307579f5f8 Mon Sep 17 00:00:00 2001 +From 6012d3a1b078d1a0a56088193ed58b6462792993 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 7 Mar 2017 12:18:20 +0000 -Subject: [PATCH 201/220] BCM270X_DT: Invert Pi3 power LED to match fw change +Subject: [PATCH 200/229] BCM270X_DT: Invert Pi3 power LED to match fw change Firmware expgpio driver reworked due to complaint over hotplug detect. @@ -137419,10 +137326,10 @@ index 173103aaca503833b5e29530ed94e14c7cab0444..b21d2866d204adc533b46d581028f290 }; -From e95d839d186dbffe488aefc930cadd28f18002a0 Mon Sep 17 00:00:00 2001 +From 94dc319b9e2a3da3acba4c0216906cb183c945e0 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 14 Mar 2017 09:10:05 +0000 -Subject: [PATCH 202/220] BCM270X_DT: Add lm75 to i2c-sensor overlay +Subject: [PATCH 201/229] BCM270X_DT: Add lm75 to i2c-sensor overlay See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=177236 @@ -137485,10 +137392,10 @@ index 31bda8da4cb6a56bfe493a81b918900995fb0589..606b2d5012abf2e85712be631c42ea40 }; }; -From 0ce5e90cdcdcb7f11e8efeb969762c15562ca5dd Mon Sep 17 00:00:00 2001 +From c8e0b6101fd2ecdeb76720a474785cf5c06d8254 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 14 Mar 2017 14:23:06 +0000 -Subject: [PATCH 203/220] bcm2835-gpio-exp: Copy/paste error adding base twice +Subject: [PATCH 202/229] bcm2835-gpio-exp: Copy/paste error adding base twice brcmexp_gpio_set was adding gpio->gc.base to the offset twice, so passing an invalid number to the mailbox service. @@ -137514,10 +137421,10 @@ index 681a91492d4c33bdfd42416e069218e8611cc4d9..d68adafaee4ad406f45f4ff0d6b7c1ad set.state = val; /* Output state */ -From 11ba49a5dcf9f5f5619e8c05f32306b430886e76 Mon Sep 17 00:00:00 2001 +From b7701d7e7f150854ad3ef0f1554022464557ea3e Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 15 Mar 2017 11:12:40 +0000 -Subject: [PATCH 204/220] bcm2835-camera: Correct port_parameter_get return +Subject: [PATCH 203/229] bcm2835-camera: Correct port_parameter_get return value The API for port_parameter_get() requires that the @@ -137575,10 +137482,10 @@ index e4b243b33f58913f3d2952c97d2a2e3fbbbd0ae8..ec2853ba9d4b1b0cd6e07a495a424e15 pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__, ret, port->component->handle, port->handle, parameter_id); -From b5c1fb2410ca88175189123afdbdc8e805f5af1c Mon Sep 17 00:00:00 2001 +From 42fba0cbde85f4fc2ece0f1491b4d3aa3f3489ea Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 17 Mar 2017 12:24:41 +0000 -Subject: [PATCH 205/220] config: Make spidev a loadable module +Subject: [PATCH 204/229] config: Make spidev a loadable module spidev isn't required early in the boot process, and not all users need it (spi_bcm2835 is a module), so make it a loadable module. @@ -137634,10 +137541,10 @@ index 4bc0f8b52b7f39f99d650cb9c4cdfdba6fac59dd..8d64ce4465f6f276b2d58ed1e2e45fb0 CONFIG_SND_SIMPLE_CARD=m CONFIG_SOUND_PRIME=m -From 1911ea02d3d4dd1563bb56307cc5aa952446e43a Mon Sep 17 00:00:00 2001 +From 57b8961f4b7371e51b9d75ca8e820d9b80b8b2d2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 23 Mar 2017 10:06:56 +0000 -Subject: [PATCH 206/220] ASoC: Add prompt for ICS43432 codec +Subject: [PATCH 205/229] ASoC: Add prompt for ICS43432 codec Without a prompt string, a config setting can't be included in a defconfig. Give CONFIG_SND_SOC_ICS43432 a prompt so that Pi soundcards @@ -137662,10 +137569,10 @@ index 9824cdd04b0c11c45b8cedd0187a0eba8f1dc2d4..c0b88d43df0de283c58ed6158680bc7e config SND_SOC_INNO_RK3036 tristate "Inno codec driver for RK3036 SoC" -From b15a4e9186b8f5ae89c254cc034450d8c87b2f25 Mon Sep 17 00:00:00 2001 +From c0ba2c5008f51ac66a7e9fddc41add243a94a867 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 23 Mar 2017 16:34:46 +0000 -Subject: [PATCH 207/220] bcm2835-aux: Add aux interrupt controller +Subject: [PATCH 206/229] bcm2835-aux: Add aux interrupt controller The AUX block has a shared interrupt line with a register indicating which devices have active IRQs. Expose this as a nested interrupt @@ -137829,10 +137736,10 @@ index bd750cf2238d61489811e7d7bd3b5f9950ed53c8..41e0702fae4692221980b0d02aed1ba6 BCM2835_AUX_CLOCK_COUNT, GFP_KERNEL); if (!onecell) -From 276b4a46685a5195d0c49d13900a342683ced706 Mon Sep 17 00:00:00 2001 +From 7d8f0b2bebc31971821a4c1d63f5fef7441fc197 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 23 Mar 2017 17:08:44 +0000 -Subject: [PATCH 208/220] BCM270X_DT: Enable AUX interrupt controller in DT +Subject: [PATCH 207/229] BCM270X_DT: Enable AUX interrupt controller in DT See: https://github.com/raspberrypi/linux/issues/1484 https://github.com/raspberrypi/linux/issues/1573 @@ -137885,10 +137792,10 @@ index d3cc586661f903e67a840189c0446aa80e16a44e..348c71bbc913644c04bab43fcb95abe9 #address-cells = <1>; #size-cells = <0>; -From f0d1516f1a0cd098dba3baa2884a3f8e197d0f82 Mon Sep 17 00:00:00 2001 +From 8899614857b2e3417d669450ac21e3010cdbb7dc Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Mon, 27 Mar 2017 22:26:49 +1100 -Subject: [PATCH 209/220] Audioinjector addons dts : add reset and regulators +Subject: [PATCH 208/229] Audioinjector addons dts : add reset and regulators for the Octo product. This patch adds a reset GPIO for the AudioInjector.net octo sound card. @@ -137955,10 +137862,10 @@ index dbf2f3cacc2e6bf5b7116fbadd97f2781580a79c..a36fa85a61f7eaab35ca481ed1dac621 codec = <&cs42448>; status = "okay"; -From 66cf592b878498381efad6ab14116e38b5d12462 Mon Sep 17 00:00:00 2001 +From 9b039f5cb19f7b5718c5c21d1dcc1d494c0a63bd Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Mon, 27 Mar 2017 22:27:26 +1100 -Subject: [PATCH 210/220] AudioInjector Octo : Consolidate sample rates and add +Subject: [PATCH 209/229] AudioInjector Octo : Consolidate sample rates and add a codec reset. This patch consolidates the sample rates which the audioinjector.net octo @@ -138098,10 +138005,10 @@ index 9effea725798640887755dfa688da45338718afc..1198c36c4563b8673e5d386d1dfa92d4 dai->cpu_dai_name = NULL; dai->cpu_of_node = i2s_node; -From cd90a81a5b257615b2d602ac794008c1f74d22c1 Mon Sep 17 00:00:00 2001 +From 6f3d9b375793a4e9fac48da15467a06aa795fdc5 Mon Sep 17 00:00:00 2001 From: Peter Malkin Date: Mon, 27 Mar 2017 16:38:21 -0700 -Subject: [PATCH 211/220] Driver support for Google voiceHAT soundcard. +Subject: [PATCH 210/229] Driver support for Google voiceHAT soundcard. --- arch/arm/boot/dts/overlays/Makefile | 1 + @@ -138606,10 +138513,10 @@ index 0000000000000000000000000000000000000000..225854b8e5298b3c3018f59a49404354 +MODULE_DESCRIPTION("ASoC Driver for Google voiceHAT SoundCard"); +MODULE_LICENSE("GPL v2"); -From bbc44acd1168da5c90ef281ee5c1c432254f94d9 Mon Sep 17 00:00:00 2001 +From bd26dc547a4151ff27c27a6e6d355acea71416d9 Mon Sep 17 00:00:00 2001 From: Raashid Muhammed Date: Mon, 27 Mar 2017 12:35:00 +0530 -Subject: [PATCH 212/220] Add support for Allo Piano DAC 2.1 plus add-on board +Subject: [PATCH 211/229] Add support for Allo Piano DAC 2.1 plus add-on board for Raspberry Pi. The Piano DAC 2.1 has support for 4 channels with subwoofer. @@ -139237,10 +139144,10 @@ index 0000000000000000000000000000000000000000..f66f42abadbd5f9d3fe000676e8297ed +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Piano DAC Plus"); +MODULE_LICENSE("GPL v2"); -From da12961a62933749b87d6e6ae1903e75d8501c3d Mon Sep 17 00:00:00 2001 +From 86ad0d5d97902245ab40a9465f9e1038efe77c04 Mon Sep 17 00:00:00 2001 From: BabuSubashChandar Date: Tue, 28 Mar 2017 20:04:42 +0530 -Subject: [PATCH 213/220] Add support for Allo Boss DAC add-on board for +Subject: [PATCH 212/229] Add support for Allo Boss DAC add-on board for Raspberry Pi. (#1924) Signed-off-by: Baswaraj K @@ -139970,10 +139877,10 @@ index 0000000000000000000000000000000000000000..c080e31065d99ab309ab3bdf41a44adf +MODULE_DESCRIPTION("ALSA ASoC Machine Driver for Allo Boss DAC"); +MODULE_LICENSE("GPL v2"); -From 8023e80635527d669f70ff9a6fcdaca2ad458818 Mon Sep 17 00:00:00 2001 +From 1d6787a5b15ae9978b894198fa3c9f6e40c5fa90 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 28 Mar 2017 14:22:20 +0100 -Subject: [PATCH 214/220] BCM270X_DT: Allow multiple instances of w1-gpio +Subject: [PATCH 213/229] BCM270X_DT: Allow multiple instances of w1-gpio overlays Upcoming firmware will modify the address portion of node names when @@ -140038,10 +139945,10 @@ index 66a98f6c9601f51483f27803995bec772bb3350e..ef8bfbcabdb31231075d5c281df3b38b <&w1_pins>,"brcm,pins:4"; pullup = <&w1>,"rpi,parasitic-power:0"; -From 0a07667778a5b2c5e556c15199c5be30a3887c60 Mon Sep 17 00:00:00 2001 +From 6b723831ce7f33feb5725649eeb4983b47bf448b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 28 Mar 2017 17:41:30 +0100 -Subject: [PATCH 215/220] leds-gpio: Remove stray assignment to brightness_set +Subject: [PATCH 214/229] leds-gpio: Remove stray assignment to brightness_set The brightness_set method is intended for use cases that must not block, and can only be used if the GPIO provider can never sleep. @@ -140067,10 +139974,10 @@ index 6a27a693034825de2897bb7b338b60cc10c9e59f..a6b352cb003ff5e6c87cf6d37d6502b6 if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP) { state = gpiod_get_value_cansleep(led_dat->gpiod); -From 1e448652dbc96e7d9ab2016536eac218f59af577 Mon Sep 17 00:00:00 2001 +From 611806fca5b173d987ade185fe31dc5f29525971 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Thu, 30 Mar 2017 11:43:57 +1100 -Subject: [PATCH 216/220] Audioinjector Octo : add extra sample rates, fix rst +Subject: [PATCH 215/229] Audioinjector Octo : add extra sample rates, fix rst and use bcm270x regs This patch adds new sample rates to the Audioinjector Octo sound card. The @@ -140232,10 +140139,10 @@ index 1198c36c4563b8673e5d386d1dfa92d43689e297..dcf403ab37639ba79e38278d7e4b1ade if (i2s_node && codec_node) { dai->cpu_dai_name = NULL; -From 51ab3c74bc14237229c4bdf6286969e3809bb53f Mon Sep 17 00:00:00 2001 +From 92635064cc8dd80ab824296a3b6800e29ca14f91 Mon Sep 17 00:00:00 2001 From: BabuSubashChandar C Date: Thu, 30 Mar 2017 20:17:27 +0530 -Subject: [PATCH 217/220] Add support for new clock rate and mute gpios. +Subject: [PATCH 216/229] Add support for new clock rate and mute gpios. Signed-off-by: Baswaraj K Reviewed-by: Deepak @@ -140888,10 +140795,10 @@ index c080e31065d99ab309ab3bdf41a44adfdd8f8039..203ab76c7045b081578e23bda1099dd1 } -From 30994f05cc060da85ff6546f5b4e4e7cef63c1b1 Mon Sep 17 00:00:00 2001 +From cfc68e1ea68c3fcf639133e3e2480b7e2888410f Mon Sep 17 00:00:00 2001 From: BabuSubashChandar Date: Sat, 1 Apr 2017 00:46:52 +0530 -Subject: [PATCH 218/220] Add clock changes and mute gpios (#1938) +Subject: [PATCH 217/229] Add clock changes and mute gpios (#1938) Also improve code style and adhere to ALSA coding conventions. @@ -141584,10 +141491,10 @@ index f66f42abadbd5f9d3fe000676e8297ed91630e47..56e43f98846b41e487b3089813f7edc3 } -From 9f610278ad940a5265ea3417913eb2f887391008 Mon Sep 17 00:00:00 2001 +From 04f11f2061e4ba6f51b54036c47c007e3eac9736 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Tue, 4 Apr 2017 19:20:59 +1000 -Subject: [PATCH 219/220] Audioinjector : make the octo and pi sound cards have +Subject: [PATCH 218/229] Audioinjector : make the octo and pi sound cards have different driver names This patch gives the audioinjector octo and pi soundcards different driver @@ -141624,10 +141531,10 @@ index ef54e0f07ea03f59e9957b5d98f3e7fdc998e469..491906bbf446826e55dd843f28e4860f .of_match_table = audioinjector_pi_soundcard_of_match, }, -From 107d4574cc3765ad8530e6d9cce70b560b0563fd Mon Sep 17 00:00:00 2001 +From 47250496327a7a8222723df2e3b6c585a17a0258 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Tue, 4 Apr 2017 19:23:04 +1000 -Subject: [PATCH 220/220] Audioinjector octo : Make the playback and capture +Subject: [PATCH 219/229] Audioinjector octo : Make the playback and capture symmetric This patch ensures that the sample rate and channel count of the audioinjector @@ -141649,3 +141556,17746 @@ index 49115c8e20ce1a2ba5a99feb8983a1cafb052ca2..5e79f4eff93a21ed3495c77a90f73525 }, }; + +From 6a9230f331e56feff0c3b16cbd83e9a448150169 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Tue, 7 Mar 2017 14:51:03 -0800 +Subject: [PATCH 220/229] drm/vc4: Allow using more than 256MB of CMA memory. + +Until now, we've had to limit Raspberry Pi to 256MB of CMA memory to +keep from triggering the hardware addressing bug between of the tile +binner of the tile alloc memory (where the top 4 bits come from the +tile state data array's address). + +To work around that and allow more memory to be reserved for graphics, +allocate a single BO to store tile state data arrays and tile +alloc/overflow memory while the GPU is active, and make sure that that +one BO doesn't happen to cross a 256MB boundary. With that in place, +we can allocate textures and shaders anywhere in system memory (still +contiguous, of course). + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/vc4/vc4_drv.h | 28 +++++-- + drivers/gpu/drm/vc4/vc4_gem.c | 12 ++- + drivers/gpu/drm/vc4/vc4_irq.c | 61 +++++++-------- + drivers/gpu/drm/vc4/vc4_render_cl.c | 3 +- + drivers/gpu/drm/vc4/vc4_v3d.c | 150 ++++++++++++++++++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_validate.c | 54 ++++++------- + 6 files changed, 234 insertions(+), 74 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h +index 44a8e6fda2b576fed63d93ef34e076cebf90d64c..9e50bc25b2be71079d52a861c25f3fe7c4db0830 100644 +--- a/drivers/gpu/drm/vc4/vc4_drv.h ++++ b/drivers/gpu/drm/vc4/vc4_drv.h +@@ -97,12 +97,23 @@ struct vc4_dev { + */ + struct list_head seqno_cb_list; + +- /* The binner overflow memory that's currently set up in +- * BPOA/BPOS registers. When overflow occurs and a new one is +- * allocated, the previous one will be moved to +- * vc4->current_exec's free list. ++ /* The memory used for storing binner tile alloc, tile state, ++ * and overflow memory allocations. This is freed when V3D ++ * powers down. + */ +- struct vc4_bo *overflow_mem; ++ struct vc4_bo *bin_bo; ++ ++ /* Size of blocks allocated within bin_bo. */ ++ uint32_t bin_alloc_size; ++ ++ /* Bitmask of the bin_alloc_size chunks in bin_bo that are ++ * used. ++ */ ++ uint32_t bin_alloc_used; ++ ++ /* Bitmask of the current bin_alloc used for overflow memory. */ ++ uint32_t bin_alloc_overflow; ++ + struct work_struct overflow_mem_work; + + int power_refcount; +@@ -295,8 +306,12 @@ struct vc4_exec_info { + bool found_increment_semaphore_packet; + bool found_flush; + uint8_t bin_tiles_x, bin_tiles_y; +- struct drm_gem_cma_object *tile_bo; ++ /* Physical address of the start of the tile alloc array ++ * (where each tile's binned CL will start) ++ */ + uint32_t tile_alloc_offset; ++ /* Bitmask of which binner slots are freed when this job completes. */ ++ uint32_t bin_slots; + + /** + * Computed addresses pointing into exec_bo where we start the +@@ -531,6 +546,7 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, + extern struct platform_driver vc4_v3d_driver; + int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused); + int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused); ++int vc4_v3d_get_bin_slot(struct vc4_dev *vc4); + + /* vc4_validate.c */ + int +diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c +index ab3016982466c3ca35ba479050ee107d26eb50ac..a5029ab49068bdbd69411cccbdb6f5111f387e38 100644 +--- a/drivers/gpu/drm/vc4/vc4_gem.c ++++ b/drivers/gpu/drm/vc4/vc4_gem.c +@@ -695,6 +695,7 @@ static void + vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) + { + struct vc4_dev *vc4 = to_vc4_dev(dev); ++ unsigned long irqflags; + unsigned i; + + if (exec->bo) { +@@ -710,6 +711,11 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) + drm_gem_object_unreference_unlocked(&bo->base.base); + } + ++ /* Free up the allocation of any bin slots we used. */ ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ vc4->bin_alloc_used &= ~exec->bin_slots; ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ + mutex_lock(&vc4->power_lock); + if (--vc4->power_refcount == 0) { + pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev); +@@ -951,9 +957,9 @@ vc4_gem_destroy(struct drm_device *dev) + /* V3D should already have disabled its interrupt and cleared + * the overflow allocation registers. Now free the object. + */ +- if (vc4->overflow_mem) { +- drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base); +- vc4->overflow_mem = NULL; ++ if (vc4->bin_bo) { ++ drm_gem_object_unreference_unlocked(&vc4->bin_bo->base.base); ++ vc4->bin_bo = NULL; + } + + if (vc4->hang_state) +diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c +index 094bc6a475c1773923dfe8225cba9886fc9e5026..c43ee1e646f6dd68fe19dacdbcf9322da13c4280 100644 +--- a/drivers/gpu/drm/vc4/vc4_irq.c ++++ b/drivers/gpu/drm/vc4/vc4_irq.c +@@ -58,50 +58,45 @@ vc4_overflow_mem_work(struct work_struct *work) + { + struct vc4_dev *vc4 = + container_of(work, struct vc4_dev, overflow_mem_work); +- struct drm_device *dev = vc4->dev; +- struct vc4_bo *bo; ++ struct vc4_bo *bo = vc4->bin_bo; ++ int bin_bo_slot; ++ struct vc4_exec_info *exec; ++ unsigned long irqflags; + +- bo = vc4_bo_create(dev, 256 * 1024, true); +- if (IS_ERR(bo)) { ++ bin_bo_slot = vc4_v3d_get_bin_slot(vc4); ++ if (bin_bo_slot < 0) { + DRM_ERROR("Couldn't allocate binner overflow mem\n"); + return; + } + +- /* If there's a job executing currently, then our previous +- * overflow allocation is getting used in that job and we need +- * to queue it to be released when the job is done. But if no +- * job is executing at all, then we can free the old overflow +- * object direcctly. +- * +- * No lock necessary for this pointer since we're the only +- * ones that update the pointer, and our workqueue won't +- * reenter. +- */ +- if (vc4->overflow_mem) { +- struct vc4_exec_info *current_exec; +- unsigned long irqflags; +- +- spin_lock_irqsave(&vc4->job_lock, irqflags); +- current_exec = vc4_first_bin_job(vc4); +- if (!current_exec) +- current_exec = vc4_last_render_job(vc4); +- if (current_exec) { +- vc4->overflow_mem->seqno = current_exec->seqno; +- list_add_tail(&vc4->overflow_mem->unref_head, +- ¤t_exec->unref_list); +- vc4->overflow_mem = NULL; ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ ++ if (vc4->bin_alloc_overflow) { ++ /* If we had overflow memory allocated previously, ++ * then that chunk will free when the current bin job ++ * is done. If we don't have a bin job running, then ++ * the chunk will be done whenever the list of render ++ * jobs has drained. ++ */ ++ exec = vc4_first_bin_job(vc4); ++ if (!exec) ++ exec = vc4_last_render_job(vc4); ++ if (exec) { ++ exec->bin_slots |= vc4->bin_alloc_overflow; ++ } else { ++ /* There's nothing queued in the hardware, so ++ * the old slot is free immediately. ++ */ ++ vc4->bin_alloc_used &= ~vc4->bin_alloc_overflow; + } +- spin_unlock_irqrestore(&vc4->job_lock, irqflags); + } ++ vc4->bin_alloc_overflow = BIT(bin_bo_slot); + +- if (vc4->overflow_mem) +- drm_gem_object_unreference_unlocked(&vc4->overflow_mem->base.base); +- vc4->overflow_mem = bo; +- +- V3D_WRITE(V3D_BPOA, bo->base.paddr); ++ V3D_WRITE(V3D_BPOA, bo->base.paddr + bin_bo_slot * vc4->bin_alloc_size); + V3D_WRITE(V3D_BPOS, bo->base.base.size); + V3D_WRITE(V3D_INTCTL, V3D_INT_OUTOMEM); + V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM); ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); + } + + static void +diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c +index 5cdd003605f57c99faf31832e3f3dd38a75b7402..6face6aa0890b59bc91d3740fa063a5c46f7cc21 100644 +--- a/drivers/gpu/drm/vc4/vc4_render_cl.c ++++ b/drivers/gpu/drm/vc4/vc4_render_cl.c +@@ -178,8 +178,7 @@ static void emit_tile(struct vc4_exec_info *exec, + + if (has_bin) { + rcl_u8(setup, VC4_PACKET_BRANCH_TO_SUB_LIST); +- rcl_u32(setup, (exec->tile_bo->paddr + +- exec->tile_alloc_offset + ++ rcl_u32(setup, (exec->tile_alloc_offset + + (y * exec->bin_tiles_x + x) * 32)); + } + +diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c +index 1d9e5a6edd22c29ce8b2990c9c35627aa1af2bd8..da79d8511dfb4f631fd3ad4c3680b312f44bd454 100644 +--- a/drivers/gpu/drm/vc4/vc4_v3d.c ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -159,6 +159,144 @@ static void vc4_v3d_init_hw(struct drm_device *dev) + V3D_WRITE(V3D_VPMBASE, 0); + } + ++int vc4_v3d_get_bin_slot(struct vc4_dev *vc4) ++{ ++ struct drm_device *dev = vc4->dev; ++ unsigned long irqflags; ++ int slot; ++ uint64_t seqno = 0; ++ struct vc4_exec_info *exec; ++ ++try_again: ++ spin_lock_irqsave(&vc4->job_lock, irqflags); ++ slot = ffs(~vc4->bin_alloc_used); ++ if (slot != 0) { ++ /* Switch from ffs() bit index to a 0-based index. */ ++ slot--; ++ vc4->bin_alloc_used |= BIT(slot); ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ return slot; ++ } ++ ++ /* Couldn't find an open slot. Wait for render to complete ++ * and try again. ++ */ ++ exec = vc4_last_render_job(vc4); ++ if (exec) ++ seqno = exec->seqno; ++ spin_unlock_irqrestore(&vc4->job_lock, irqflags); ++ ++ if (seqno) { ++ int ret = vc4_wait_for_seqno(dev, seqno, ~0ull, true); ++ ++ if (ret == 0) ++ goto try_again; ++ ++ return ret; ++ } ++ ++ return -ENOMEM; ++} ++ ++/** ++ * vc4_allocate_bin_bo() - allocates the memory that will be used for ++ * tile binning. ++ * ++ * The binner has a limitation that the addresses in the tile state ++ * buffer that point into the tile alloc buffer or binner overflow ++ * memory only have 28 bits (256MB), and the top 4 on the bus for ++ * tile alloc references end up coming from the tile state buffer's ++ * address. ++ * ++ * To work around this, we allocate a single large buffer while V3D is ++ * in use, make sure that it has the top 4 bits constant across its ++ * entire extent, and then put the tile state, tile alloc, and binner ++ * overflow memory inside that buffer. ++ * ++ * This creates a limitation where we may not be able to execute a job ++ * if it doesn't fit within the buffer that we allocated up front. ++ * However, it turns out that 16MB is "enough for anybody", and ++ * real-world applications run into allocation failures from the ++ * overall CMA pool before they make scenes complicated enough to run ++ * out of bin space. ++ */ ++int ++vc4_allocate_bin_bo(struct drm_device *drm) ++{ ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ struct vc4_v3d *v3d = vc4->v3d; ++ uint32_t size = 16 * 1024 * 1024; ++ int ret = 0; ++ struct list_head list; ++ ++ /* We may need to try allocating more than once to get a BO ++ * that doesn't cross 256MB. Track the ones we've allocated ++ * that failed so far, so that we can free them when we've got ++ * one that succeeded (if we freed them right away, our next ++ * allocation would probably be the same chunk of memory). ++ */ ++ INIT_LIST_HEAD(&list); ++ ++ while (true) { ++ struct vc4_bo *bo = vc4_bo_create(drm, size, true); ++ ++ if (IS_ERR(bo)) { ++ ret = PTR_ERR(bo); ++ ++ dev_err(&v3d->pdev->dev, ++ "Failed to allocate memory for tile binning: " ++ "%d. You may need to enable CMA or give it " ++ "more memory.", ++ ret); ++ break; ++ } ++ ++ /* Check if this BO won't trigger the addressing bug. */ ++ if ((bo->base.paddr & 0xf0000000) == ++ ((bo->base.paddr + bo->base.base.size - 1) & 0xf0000000)) { ++ vc4->bin_bo = bo; ++ ++ /* Set up for allocating 512KB chunks of ++ * binner memory. The biggest allocation we ++ * need to do is for the initial tile alloc + ++ * tile state buffer. We can render to a ++ * maximum of ((2048*2048) / (32*32) = 4096 ++ * tiles in a frame (until we do floating ++ * point rendering, at which point it would be ++ * 8192). Tile state is 48b/tile (rounded to ++ * a page), and tile alloc is 32b/tile ++ * (rounded to a page), plus a page of extra, ++ * for a total of 320kb for our worst-case. ++ * We choose 512kb so that it divides evenly ++ * into our 16MB, and the rest of the 512kb ++ * will be used as storage for the overflow ++ * from the initial 32b CL per bin. ++ */ ++ vc4->bin_alloc_size = 512 * 1024; ++ vc4->bin_alloc_used = 0; ++ vc4->bin_alloc_overflow = 0; ++ WARN_ON_ONCE(sizeof(vc4->bin_alloc_used) * 8 != ++ bo->base.base.size / vc4->bin_alloc_size); ++ ++ break; ++ } ++ ++ /* Put it on the list to free later, and try again. */ ++ list_add(&bo->unref_head, &list); ++ } ++ ++ /* Free all the BOs we allocated but didn't choose. */ ++ while (!list_empty(&list)) { ++ struct vc4_bo *bo = list_last_entry(&list, ++ struct vc4_bo, unref_head); ++ ++ list_del(&bo->unref_head); ++ drm_gem_object_unreference_unlocked(&bo->base.base); ++ } ++ ++ return ret; ++} ++ + #ifdef CONFIG_PM + static int vc4_v3d_runtime_suspend(struct device *dev) + { +@@ -167,6 +305,9 @@ static int vc4_v3d_runtime_suspend(struct device *dev) + + vc4_irq_uninstall(vc4->dev); + ++ drm_gem_object_unreference_unlocked(&vc4->bin_bo->base.base); ++ vc4->bin_bo = NULL; ++ + return 0; + } + +@@ -174,6 +315,11 @@ static int vc4_v3d_runtime_resume(struct device *dev) + { + struct vc4_v3d *v3d = dev_get_drvdata(dev); + struct vc4_dev *vc4 = v3d->vc4; ++ int ret; ++ ++ ret = vc4_allocate_bin_bo(vc4->dev); ++ if (ret) ++ return ret; + + vc4_v3d_init_hw(vc4->dev); + vc4_irq_postinstall(vc4->dev); +@@ -226,6 +372,10 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) + return -EINVAL; + } + ++ ret = vc4_allocate_bin_bo(drm); ++ if (ret) ++ return ret; ++ + /* Reset the binner overflow address/size at setup, to be sure + * we don't reuse an old one. + */ +diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c +index 9fd171c361c23b52a4d507919ec7e26fd1e87aac..59d808e2a6cc6f3173b1309cc4f491098886cf36 100644 +--- a/drivers/gpu/drm/vc4/vc4_validate.c ++++ b/drivers/gpu/drm/vc4/vc4_validate.c +@@ -340,10 +340,11 @@ static int + validate_tile_binning_config(VALIDATE_ARGS) + { + struct drm_device *dev = exec->exec_bo->base.dev; +- struct vc4_bo *tile_bo; ++ struct vc4_dev *vc4 = to_vc4_dev(dev); + uint8_t flags; +- uint32_t tile_state_size, tile_alloc_size; +- uint32_t tile_count; ++ uint32_t tile_state_size; ++ uint32_t tile_count, bin_addr; ++ int bin_slot; + + if (exec->found_tile_binning_mode_config_packet) { + DRM_ERROR("Duplicate VC4_PACKET_TILE_BINNING_MODE_CONFIG\n"); +@@ -369,13 +370,28 @@ validate_tile_binning_config(VALIDATE_ARGS) + return -EINVAL; + } + ++ bin_slot = vc4_v3d_get_bin_slot(vc4); ++ if (bin_slot < 0) { ++ if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS) { ++ DRM_ERROR("Failed to allocate binner memory: %d\n", ++ bin_slot); ++ } ++ return bin_slot; ++ } ++ ++ /* The slot we allocated will only be used by this job, and is ++ * free when the job completes rendering. ++ */ ++ exec->bin_slots |= BIT(bin_slot); ++ bin_addr = vc4->bin_bo->base.paddr + bin_slot * vc4->bin_alloc_size; ++ + /* The tile state data array is 48 bytes per tile, and we put it at + * the start of a BO containing both it and the tile alloc. + */ + tile_state_size = 48 * tile_count; + + /* Since the tile alloc array will follow us, align. */ +- exec->tile_alloc_offset = roundup(tile_state_size, 4096); ++ exec->tile_alloc_offset = bin_addr + roundup(tile_state_size, 4096); + + *(uint8_t *)(validated + 14) = + ((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK | +@@ -386,35 +402,13 @@ validate_tile_binning_config(VALIDATE_ARGS) + VC4_SET_FIELD(VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128, + VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE)); + +- /* Initial block size. */ +- tile_alloc_size = 32 * tile_count; +- +- /* +- * The initial allocation gets rounded to the next 256 bytes before +- * the hardware starts fulfilling further allocations. +- */ +- tile_alloc_size = roundup(tile_alloc_size, 256); +- +- /* Add space for the extra allocations. This is what gets used first, +- * before overflow memory. It must have at least 4096 bytes, but we +- * want to avoid overflow memory usage if possible. +- */ +- tile_alloc_size += 1024 * 1024; +- +- tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size, +- true); +- exec->tile_bo = &tile_bo->base; +- if (IS_ERR(exec->tile_bo)) +- return PTR_ERR(exec->tile_bo); +- list_add_tail(&tile_bo->unref_head, &exec->unref_list); +- + /* tile alloc address. */ +- *(uint32_t *)(validated + 0) = (exec->tile_bo->paddr + +- exec->tile_alloc_offset); ++ *(uint32_t *)(validated + 0) = exec->tile_alloc_offset; + /* tile alloc size. */ +- *(uint32_t *)(validated + 4) = tile_alloc_size; ++ *(uint32_t *)(validated + 4) = (bin_addr + vc4->bin_alloc_size - ++ exec->tile_alloc_offset); + /* tile state address. */ +- *(uint32_t *)(validated + 8) = exec->tile_bo->paddr; ++ *(uint32_t *)(validated + 8) = bin_addr; + + return 0; + } + +From c9198914d5f724e33f1b4e15a38acbd5439a50c5 Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Thu, 30 Mar 2017 10:23:27 -0700 +Subject: [PATCH 221/229] Revert "drm/vc4: Verify at boot that CMA doesn't + cross a 256MB boundary." + +This reverts commit 016c804fa69381bd23a1a13cba08a3c4557fcdff. The +restriction was lifted by the previous commit. +--- + drivers/base/dma-contiguous.c | 1 - + drivers/gpu/drm/vc4/vc4_v3d.c | 18 ------------------ + mm/cma.c | 2 -- + 3 files changed, 21 deletions(-) + +diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c +index 60f5c2591ccdb0202461458eab4035cfba731b8b..e167a1e1bccb062efef2595fcd5299301a97df80 100644 +--- a/drivers/base/dma-contiguous.c ++++ b/drivers/base/dma-contiguous.c +@@ -35,7 +35,6 @@ + #endif + + struct cma *dma_contiguous_default_area; +-EXPORT_SYMBOL(dma_contiguous_default_area); + + /* + * Default global CMA area size can be defined in kernel's .config. +diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c +index da79d8511dfb4f631fd3ad4c3680b312f44bd454..882ec06225f1d5caca71bdb5c69664188192c2e2 100644 +--- a/drivers/gpu/drm/vc4/vc4_v3d.c ++++ b/drivers/gpu/drm/vc4/vc4_v3d.c +@@ -16,10 +16,7 @@ + * this program. If not, see . + */ + +-#include "linux/init.h" +-#include "linux/cma.h" + #include "linux/component.h" +-#include "linux/dma-contiguous.h" + #include "linux/pm_runtime.h" + #include "vc4_drv.h" + #include "vc4_regs.h" +@@ -334,23 +331,8 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) + struct drm_device *drm = dev_get_drvdata(master); + struct vc4_dev *vc4 = to_vc4_dev(drm); + struct vc4_v3d *v3d = NULL; +- struct cma *cma; + int ret; + +- cma = dev_get_cma_area(dev); +- if (!cma) +- return -EINVAL; +- +- if ((cma_get_base(cma) & 0xf0000000) != +- ((cma_get_base(cma) + cma_get_size(cma) - 1) & 0xf0000000)) { +- DRM_ERROR("V3D requires that the CMA area (0x%08lx - 0x%08lx) " +- "not span a 256MB boundary, or memory corruption " +- "would happen.\n", +- (long)cma_get_base(cma), +- cma_get_base(cma) + cma_get_size(cma)); +- return -EINVAL; +- } +- + v3d = devm_kzalloc(&pdev->dev, sizeof(*v3d), GFP_KERNEL); + if (!v3d) + return -ENOMEM; +diff --git a/mm/cma.c b/mm/cma.c +index b50245282a18bc790da0f901944c2e670ffac2d2..c960459eda7e640ea55be1d4ed80c6a9125a8877 100644 +--- a/mm/cma.c ++++ b/mm/cma.c +@@ -47,13 +47,11 @@ phys_addr_t cma_get_base(const struct cma *cma) + { + return PFN_PHYS(cma->base_pfn); + } +-EXPORT_SYMBOL(cma_get_base); + + unsigned long cma_get_size(const struct cma *cma) + { + return cma->count << PAGE_SHIFT; + } +-EXPORT_SYMBOL(cma_get_size); + + static unsigned long cma_bitmap_aligned_mask(const struct cma *cma, + int align_order) + +From c22d272c517370c8e6f5a8a4850bca6219a1e34b Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Mon, 27 Feb 2017 12:28:02 -0800 +Subject: [PATCH 222/229] drm/vc4: Add HDMI audio support + +The HDMI encoder IP embeds all needed blocks to output audio, with a +custom DAI called MAI moving audio between the two parts of the HDMI +core. This driver now exposes a sound card to let users stream audio +to their display. + +Using the hdmi-codec driver has been considered here, but MAI meant +having to significantly rework hdmi-codec, and it would have left +little shared code with the I2S mode anyway. + +The encoder requires that the audio be SPDIF-formatted frames only, +which alsalib will format-convert for us. + +This patch is the combined work of Eric Anholt (initial register setup +with a separate dmaengine driver and using simple-audio-card) and +Boris Brezillon (moving it all into HDMI, massive debug to get it +actually working), and which Eric has the permission to release. + +v2: Drop "-audio" from sound card name, since that's already implied + (suggestion by Boris) + +Signed-off-by: Eric Anholt +Acked-by: Boris Brezillon +Link: http://patchwork.freedesktop.org/patch/msgid/20170227202803.12855-2-eric@anholt.net +--- + drivers/gpu/drm/vc4/Kconfig | 4 + + drivers/gpu/drm/vc4/vc4_hdmi.c | 494 ++++++++++++++++++++++++++++++++++++++++- + drivers/gpu/drm/vc4/vc4_regs.h | 107 ++++++++- + 3 files changed, 603 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig +index e1517d07cb7d22776ca164a5d2d9b87e55a5563a..973b4203c0b264115b7cd9d4a433b449bd0ec3b3 100644 +--- a/drivers/gpu/drm/vc4/Kconfig ++++ b/drivers/gpu/drm/vc4/Kconfig +@@ -2,11 +2,15 @@ config DRM_VC4 + tristate "Broadcom VC4 Graphics" + depends on ARCH_BCM2835 || COMPILE_TEST + depends on DRM ++ depends on SND && SND_SOC + depends on COMMON_CLK + select DRM_KMS_HELPER + select DRM_KMS_CMA_HELPER + select DRM_GEM_CMA_HELPER + select DRM_PANEL ++ select SND_PCM ++ select SND_PCM_ELD ++ select SND_SOC_GENERIC_DMAENGINE_PCM + select DRM_MIPI_DSI + help + Choose this option if you have a system that has a Broadcom +diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c +index c4cb2e26de32f06db0abf3fd94b3117c3292eed5..8db1016cad929438f30ea44c6974dcb340b74596 100644 +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -31,11 +31,27 @@ + #include "linux/clk.h" + #include "linux/component.h" + #include "linux/i2c.h" ++#include "linux/of_address.h" + #include "linux/of_gpio.h" + #include "linux/of_platform.h" ++#include "linux/rational.h" ++#include "sound/dmaengine_pcm.h" ++#include "sound/pcm_drm_eld.h" ++#include "sound/pcm_params.h" ++#include "sound/soc.h" + #include "vc4_drv.h" + #include "vc4_regs.h" + ++/* HDMI audio information */ ++struct vc4_hdmi_audio { ++ struct snd_soc_card card; ++ struct snd_soc_dai_link link; ++ int samplerate; ++ int channels; ++ struct snd_dmaengine_dai_dma_data dma_data; ++ struct snd_pcm_substream *substream; ++}; ++ + /* General HDMI hardware state. */ + struct vc4_hdmi { + struct platform_device *pdev; +@@ -43,6 +59,8 @@ struct vc4_hdmi { + struct drm_encoder *encoder; + struct drm_connector *connector; + ++ struct vc4_hdmi_audio audio; ++ + struct i2c_adapter *ddc; + void __iomem *hdmicore_regs; + void __iomem *hd_regs; +@@ -98,6 +116,10 @@ static const struct { + HDMI_REG(VC4_HDMI_SW_RESET_CONTROL), + HDMI_REG(VC4_HDMI_HOTPLUG_INT), + HDMI_REG(VC4_HDMI_HOTPLUG), ++ HDMI_REG(VC4_HDMI_MAI_CHANNEL_MAP), ++ HDMI_REG(VC4_HDMI_MAI_CONFIG), ++ HDMI_REG(VC4_HDMI_MAI_FORMAT), ++ HDMI_REG(VC4_HDMI_AUDIO_PACKET_CONFIG), + HDMI_REG(VC4_HDMI_RAM_PACKET_CONFIG), + HDMI_REG(VC4_HDMI_HORZA), + HDMI_REG(VC4_HDMI_HORZB), +@@ -108,6 +130,7 @@ static const struct { + HDMI_REG(VC4_HDMI_VERTB0), + HDMI_REG(VC4_HDMI_VERTB1), + HDMI_REG(VC4_HDMI_TX_PHY_RESET_CTL), ++ HDMI_REG(VC4_HDMI_TX_PHY_CTL0), + }; + + static const struct { +@@ -116,6 +139,9 @@ static const struct { + } hd_regs[] = { + HDMI_REG(VC4_HD_M_CTL), + HDMI_REG(VC4_HD_MAI_CTL), ++ HDMI_REG(VC4_HD_MAI_THR), ++ HDMI_REG(VC4_HD_MAI_FMT), ++ HDMI_REG(VC4_HD_MAI_SMP), + HDMI_REG(VC4_HD_VID_CTL), + HDMI_REG(VC4_HD_CSC_CTL), + HDMI_REG(VC4_HD_FRAME_COUNT), +@@ -215,6 +241,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) + + drm_mode_connector_update_edid_property(connector, edid); + ret = drm_add_edid_modes(connector, edid); ++ drm_edid_to_eld(connector, edid); + + return ret; + } +@@ -300,7 +327,7 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + u32 packet_id = frame->any.type - 0x80; +- u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id; ++ u32 packet_reg = VC4_HDMI_RAM_PACKET(packet_id); + uint8_t buffer[VC4_HDMI_PACKET_STRIDE]; + ssize_t len, i; + int ret; +@@ -385,6 +412,24 @@ static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder) + vc4_hdmi_write_infoframe(encoder, &frame); + } + ++static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder) ++{ ++ struct drm_device *drm = encoder->dev; ++ struct vc4_dev *vc4 = drm->dev_private; ++ struct vc4_hdmi *hdmi = vc4->hdmi; ++ union hdmi_infoframe frame; ++ int ret; ++ ++ ret = hdmi_audio_infoframe_init(&frame.audio); ++ ++ frame.audio.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; ++ frame.audio.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; ++ frame.audio.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; ++ frame.audio.channels = hdmi->audio.channels; ++ ++ vc4_hdmi_write_infoframe(encoder, &frame); ++} ++ + static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) + { + vc4_hdmi_set_avi_infoframe(encoder); +@@ -591,6 +636,447 @@ static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = { + .enable = vc4_hdmi_encoder_enable, + }; + ++/* HDMI audio codec callbacks */ ++static void vc4_hdmi_audio_set_mai_clock(struct vc4_hdmi *hdmi) ++{ ++ struct drm_device *drm = hdmi->encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ u32 hsm_clock = clk_get_rate(hdmi->hsm_clock); ++ unsigned long n, m; ++ ++ rational_best_approximation(hsm_clock, hdmi->audio.samplerate, ++ VC4_HD_MAI_SMP_N_MASK >> ++ VC4_HD_MAI_SMP_N_SHIFT, ++ (VC4_HD_MAI_SMP_M_MASK >> ++ VC4_HD_MAI_SMP_M_SHIFT) + 1, ++ &n, &m); ++ ++ HD_WRITE(VC4_HD_MAI_SMP, ++ VC4_SET_FIELD(n, VC4_HD_MAI_SMP_N) | ++ VC4_SET_FIELD(m - 1, VC4_HD_MAI_SMP_M)); ++} ++ ++static void vc4_hdmi_set_n_cts(struct vc4_hdmi *hdmi) ++{ ++ struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_crtc *crtc = encoder->crtc; ++ struct drm_device *drm = encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ const struct drm_display_mode *mode = &crtc->state->adjusted_mode; ++ u32 samplerate = hdmi->audio.samplerate; ++ u32 n, cts; ++ u64 tmp; ++ ++ n = 128 * samplerate / 1000; ++ tmp = (u64)(mode->clock * 1000) * n; ++ do_div(tmp, 128 * samplerate); ++ cts = tmp; ++ ++ HDMI_WRITE(VC4_HDMI_CRP_CFG, ++ VC4_HDMI_CRP_CFG_EXTERNAL_CTS_EN | ++ VC4_SET_FIELD(n, VC4_HDMI_CRP_CFG_N)); ++ ++ /* ++ * We could get slightly more accurate clocks in some cases by ++ * providing a CTS_1 value. The two CTS values are alternated ++ * between based on the period fields ++ */ ++ HDMI_WRITE(VC4_HDMI_CTS_0, cts); ++ HDMI_WRITE(VC4_HDMI_CTS_1, cts); ++} ++ ++static inline struct vc4_hdmi *dai_to_hdmi(struct snd_soc_dai *dai) ++{ ++ struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai); ++ ++ return snd_soc_card_get_drvdata(card); ++} ++ ++static int vc4_hdmi_audio_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct vc4_hdmi *hdmi = dai_to_hdmi(dai); ++ struct drm_encoder *encoder = hdmi->encoder; ++ struct vc4_dev *vc4 = to_vc4_dev(encoder->dev); ++ int ret; ++ ++ if (hdmi->audio.substream && hdmi->audio.substream != substream) ++ return -EINVAL; ++ ++ hdmi->audio.substream = substream; ++ ++ /* ++ * If the HDMI encoder hasn't probed, or the encoder is ++ * currently in DVI mode, treat the codec dai as missing. ++ */ ++ if (!encoder->crtc || !(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ++ VC4_HDMI_RAM_PACKET_ENABLE)) ++ return -ENODEV; ++ ++ ret = snd_pcm_hw_constraint_eld(substream->runtime, ++ hdmi->connector->eld); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int vc4_hdmi_audio_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++{ ++ return 0; ++} ++ ++static void vc4_hdmi_audio_reset(struct vc4_hdmi *hdmi) ++{ ++ struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_device *drm = encoder->dev; ++ struct device *dev = &hdmi->pdev->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ int ret; ++ ++ ret = vc4_hdmi_stop_packet(encoder, HDMI_INFOFRAME_TYPE_AUDIO); ++ if (ret) ++ dev_err(dev, "Failed to stop audio infoframe: %d\n", ret); ++ ++ HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_RESET); ++ HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_ERRORF); ++ HD_WRITE(VC4_HD_MAI_CTL, VC4_HD_MAI_CTL_FLUSH); ++} ++ ++static void vc4_hdmi_audio_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct vc4_hdmi *hdmi = dai_to_hdmi(dai); ++ ++ if (substream != hdmi->audio.substream) ++ return; ++ ++ vc4_hdmi_audio_reset(hdmi); ++ ++ hdmi->audio.substream = NULL; ++} ++ ++/* HDMI audio codec callbacks */ ++static int vc4_hdmi_audio_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct vc4_hdmi *hdmi = dai_to_hdmi(dai); ++ struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_device *drm = encoder->dev; ++ struct device *dev = &hdmi->pdev->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ u32 audio_packet_config, channel_mask; ++ u32 channel_map, i; ++ ++ if (substream != hdmi->audio.substream) ++ return -EINVAL; ++ ++ dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__, ++ params_rate(params), params_width(params), ++ params_channels(params)); ++ ++ hdmi->audio.channels = params_channels(params); ++ hdmi->audio.samplerate = params_rate(params); ++ ++ HD_WRITE(VC4_HD_MAI_CTL, ++ VC4_HD_MAI_CTL_RESET | ++ VC4_HD_MAI_CTL_FLUSH | ++ VC4_HD_MAI_CTL_DLATE | ++ VC4_HD_MAI_CTL_ERRORE | ++ VC4_HD_MAI_CTL_ERRORF); ++ ++ vc4_hdmi_audio_set_mai_clock(hdmi); ++ ++ audio_packet_config = ++ VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT | ++ VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS | ++ VC4_SET_FIELD(0xf, VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER); ++ ++ channel_mask = GENMASK(hdmi->audio.channels - 1, 0); ++ audio_packet_config |= VC4_SET_FIELD(channel_mask, ++ VC4_HDMI_AUDIO_PACKET_CEA_MASK); ++ ++ /* Set the MAI threshold. This logic mimics the firmware's. */ ++ if (hdmi->audio.samplerate > 96000) { ++ HD_WRITE(VC4_HD_MAI_THR, ++ VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQHIGH) | ++ VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW)); ++ } else if (hdmi->audio.samplerate > 48000) { ++ HD_WRITE(VC4_HD_MAI_THR, ++ VC4_SET_FIELD(0x14, VC4_HD_MAI_THR_DREQHIGH) | ++ VC4_SET_FIELD(0x12, VC4_HD_MAI_THR_DREQLOW)); ++ } else { ++ HD_WRITE(VC4_HD_MAI_THR, ++ VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) | ++ VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) | ++ VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQHIGH) | ++ VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQLOW)); ++ } ++ ++ HDMI_WRITE(VC4_HDMI_MAI_CONFIG, ++ VC4_HDMI_MAI_CONFIG_BIT_REVERSE | ++ VC4_SET_FIELD(channel_mask, VC4_HDMI_MAI_CHANNEL_MASK)); ++ ++ channel_map = 0; ++ for (i = 0; i < 8; i++) { ++ if (channel_mask & BIT(i)) ++ channel_map |= i << (3 * i); ++ } ++ ++ HDMI_WRITE(VC4_HDMI_MAI_CHANNEL_MAP, channel_map); ++ HDMI_WRITE(VC4_HDMI_AUDIO_PACKET_CONFIG, audio_packet_config); ++ vc4_hdmi_set_n_cts(hdmi); ++ ++ return 0; ++} ++ ++static int vc4_hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, ++ struct snd_soc_dai *dai) ++{ ++ struct vc4_hdmi *hdmi = dai_to_hdmi(dai); ++ struct drm_encoder *encoder = hdmi->encoder; ++ struct drm_device *drm = encoder->dev; ++ struct vc4_dev *vc4 = to_vc4_dev(drm); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ vc4_hdmi_set_audio_infoframe(encoder); ++ HDMI_WRITE(VC4_HDMI_TX_PHY_CTL0, ++ HDMI_READ(VC4_HDMI_TX_PHY_CTL0) & ++ ~VC4_HDMI_TX_PHY_RNG_PWRDN); ++ HD_WRITE(VC4_HD_MAI_CTL, ++ VC4_SET_FIELD(hdmi->audio.channels, ++ VC4_HD_MAI_CTL_CHNUM) | ++ VC4_HD_MAI_CTL_ENABLE); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ HD_WRITE(VC4_HD_MAI_CTL, ++ VC4_HD_MAI_CTL_DLATE | ++ VC4_HD_MAI_CTL_ERRORE | ++ VC4_HD_MAI_CTL_ERRORF); ++ HDMI_WRITE(VC4_HDMI_TX_PHY_CTL0, ++ HDMI_READ(VC4_HDMI_TX_PHY_CTL0) | ++ VC4_HDMI_TX_PHY_RNG_PWRDN); ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static inline struct vc4_hdmi * ++snd_component_to_hdmi(struct snd_soc_component *component) ++{ ++ struct snd_soc_card *card = snd_soc_component_get_drvdata(component); ++ ++ return snd_soc_card_get_drvdata(card); ++} ++ ++static int vc4_hdmi_audio_eld_ctl_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); ++ struct vc4_hdmi *hdmi = snd_component_to_hdmi(component); ++ ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; ++ uinfo->count = sizeof(hdmi->connector->eld); ++ ++ return 0; ++} ++ ++static int vc4_hdmi_audio_eld_ctl_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); ++ struct vc4_hdmi *hdmi = snd_component_to_hdmi(component); ++ ++ memcpy(ucontrol->value.bytes.data, hdmi->connector->eld, ++ sizeof(hdmi->connector->eld)); ++ ++ return 0; ++} ++ ++static const struct snd_kcontrol_new vc4_hdmi_audio_controls[] = { ++ { ++ .access = SNDRV_CTL_ELEM_ACCESS_READ | ++ SNDRV_CTL_ELEM_ACCESS_VOLATILE, ++ .iface = SNDRV_CTL_ELEM_IFACE_PCM, ++ .name = "ELD", ++ .info = vc4_hdmi_audio_eld_ctl_info, ++ .get = vc4_hdmi_audio_eld_ctl_get, ++ }, ++}; ++ ++static const struct snd_soc_dapm_widget vc4_hdmi_audio_widgets[] = { ++ SND_SOC_DAPM_OUTPUT("TX"), ++}; ++ ++static const struct snd_soc_dapm_route vc4_hdmi_audio_routes[] = { ++ { "TX", NULL, "Playback" }, ++}; ++ ++static const struct snd_soc_codec_driver vc4_hdmi_audio_codec_drv = { ++ .component_driver = { ++ .controls = vc4_hdmi_audio_controls, ++ .num_controls = ARRAY_SIZE(vc4_hdmi_audio_controls), ++ .dapm_widgets = vc4_hdmi_audio_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(vc4_hdmi_audio_widgets), ++ .dapm_routes = vc4_hdmi_audio_routes, ++ .num_dapm_routes = ARRAY_SIZE(vc4_hdmi_audio_routes), ++ }, ++}; ++ ++static const struct snd_soc_dai_ops vc4_hdmi_audio_dai_ops = { ++ .startup = vc4_hdmi_audio_startup, ++ .shutdown = vc4_hdmi_audio_shutdown, ++ .hw_params = vc4_hdmi_audio_hw_params, ++ .set_fmt = vc4_hdmi_audio_set_fmt, ++ .trigger = vc4_hdmi_audio_trigger, ++}; ++ ++static struct snd_soc_dai_driver vc4_hdmi_audio_codec_dai_drv = { ++ .name = "vc4-hdmi-hifi", ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 2, ++ .channels_max = 8, ++ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | ++ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | ++ SNDRV_PCM_RATE_192000, ++ .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, ++ }, ++}; ++ ++static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = { ++ .name = "vc4-hdmi-cpu-dai-component", ++}; ++ ++static int vc4_hdmi_audio_cpu_dai_probe(struct snd_soc_dai *dai) ++{ ++ struct vc4_hdmi *hdmi = dai_to_hdmi(dai); ++ ++ snd_soc_dai_init_dma_data(dai, &hdmi->audio.dma_data, NULL); ++ ++ return 0; ++} ++ ++static struct snd_soc_dai_driver vc4_hdmi_audio_cpu_dai_drv = { ++ .name = "vc4-hdmi-cpu-dai", ++ .probe = vc4_hdmi_audio_cpu_dai_probe, ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 1, ++ .channels_max = 8, ++ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | ++ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | ++ SNDRV_PCM_RATE_192000, ++ .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, ++ }, ++ .ops = &vc4_hdmi_audio_dai_ops, ++}; ++ ++static const struct snd_dmaengine_pcm_config pcm_conf = { ++ .chan_names[SNDRV_PCM_STREAM_PLAYBACK] = "audio-rx", ++ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, ++}; ++ ++static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi) ++{ ++ struct snd_soc_dai_link *dai_link = &hdmi->audio.link; ++ struct snd_soc_card *card = &hdmi->audio.card; ++ struct device *dev = &hdmi->pdev->dev; ++ const __be32 *addr; ++ int ret; ++ ++ if (!of_find_property(dev->of_node, "dmas", NULL)) { ++ dev_warn(dev, ++ "'dmas' DT property is missing, no HDMI audio\n"); ++ return 0; ++ } ++ ++ /* ++ * Get the physical address of VC4_HD_MAI_DATA. We need to retrieve ++ * the bus address specified in the DT, because the physical address ++ * (the one returned by platform_get_resource()) is not appropriate ++ * for DMA transfers. ++ * This VC/MMU should probably be exposed to avoid this kind of hacks. ++ */ ++ addr = of_get_address(dev->of_node, 1, NULL, NULL); ++ hdmi->audio.dma_data.addr = be32_to_cpup(addr) + VC4_HD_MAI_DATA; ++ hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ hdmi->audio.dma_data.maxburst = 2; ++ ++ ret = devm_snd_dmaengine_pcm_register(dev, &pcm_conf, 0); ++ if (ret) { ++ dev_err(dev, "Could not register PCM component: %d\n", ret); ++ return ret; ++ } ++ ++ ret = devm_snd_soc_register_component(dev, &vc4_hdmi_audio_cpu_dai_comp, ++ &vc4_hdmi_audio_cpu_dai_drv, 1); ++ if (ret) { ++ dev_err(dev, "Could not register CPU DAI: %d\n", ret); ++ return ret; ++ } ++ ++ /* register codec and codec dai */ ++ ret = snd_soc_register_codec(dev, &vc4_hdmi_audio_codec_drv, ++ &vc4_hdmi_audio_codec_dai_drv, 1); ++ if (ret) { ++ dev_err(dev, "Could not register codec: %d\n", ret); ++ return ret; ++ } ++ ++ dai_link->name = "MAI"; ++ dai_link->stream_name = "MAI PCM"; ++ dai_link->codec_dai_name = vc4_hdmi_audio_codec_dai_drv.name; ++ dai_link->cpu_dai_name = dev_name(dev); ++ dai_link->codec_name = dev_name(dev); ++ dai_link->platform_name = dev_name(dev); ++ ++ card->dai_link = dai_link; ++ card->num_links = 1; ++ card->name = "vc4-hdmi"; ++ card->dev = dev; ++ ++ /* ++ * Be careful, snd_soc_register_card() calls dev_set_drvdata() and ++ * stores a pointer to the snd card object in dev->driver_data. This ++ * means we cannot use it for something else. The hdmi back-pointer is ++ * now stored in card->drvdata and should be retrieved with ++ * snd_soc_card_get_drvdata() if needed. ++ */ ++ snd_soc_card_set_drvdata(card, hdmi); ++ ret = devm_snd_soc_register_card(dev, card); ++ if (ret) { ++ dev_err(dev, "Could not register sound card: %d\n", ret); ++ goto unregister_codec; ++ } ++ ++ return 0; ++ ++unregister_codec: ++ snd_soc_unregister_codec(dev); ++ ++ return ret; ++} ++ ++static void vc4_hdmi_audio_cleanup(struct vc4_hdmi *hdmi) ++{ ++ struct device *dev = &hdmi->pdev->dev; ++ ++ /* ++ * If drvdata is not set this means the audio card was not ++ * registered, just skip codec unregistration in this case. ++ */ ++ if (dev_get_drvdata(dev)) ++ snd_soc_unregister_codec(dev); ++} ++ + static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) + { + struct platform_device *pdev = to_platform_device(dev); +@@ -722,6 +1208,10 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) + goto err_destroy_encoder; + } + ++ ret = vc4_hdmi_audio_init(hdmi); ++ if (ret) ++ goto err_destroy_encoder; ++ + return 0; + + err_destroy_encoder: +@@ -743,6 +1233,8 @@ static void vc4_hdmi_unbind(struct device *dev, struct device *master, + struct vc4_dev *vc4 = drm->dev_private; + struct vc4_hdmi *hdmi = vc4->hdmi; + ++ vc4_hdmi_audio_cleanup(hdmi); ++ + vc4_hdmi_connector_destroy(hdmi->connector); + vc4_hdmi_encoder_destroy(hdmi->encoder); + +diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h +index 385405a2df05eb3dd86d4f687aa8205331bec3cc..932093936178674173a84002b33e07e9a37fdfe9 100644 +--- a/drivers/gpu/drm/vc4/vc4_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_regs.h +@@ -446,11 +446,62 @@ + #define VC4_HDMI_HOTPLUG 0x00c + # define VC4_HDMI_HOTPLUG_CONNECTED BIT(0) + ++/* 3 bits per field, where each field maps from that corresponding MAI ++ * bus channel to the given HDMI channel. ++ */ ++#define VC4_HDMI_MAI_CHANNEL_MAP 0x090 ++ ++#define VC4_HDMI_MAI_CONFIG 0x094 ++# define VC4_HDMI_MAI_CONFIG_FORMAT_REVERSE BIT(27) ++# define VC4_HDMI_MAI_CONFIG_BIT_REVERSE BIT(26) ++# define VC4_HDMI_MAI_CHANNEL_MASK_MASK VC4_MASK(15, 0) ++# define VC4_HDMI_MAI_CHANNEL_MASK_SHIFT 0 ++ ++/* Last received format word on the MAI bus. */ ++#define VC4_HDMI_MAI_FORMAT 0x098 ++ ++#define VC4_HDMI_AUDIO_PACKET_CONFIG 0x09c ++# define VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_SAMPLE_FLAT BIT(29) ++# define VC4_HDMI_AUDIO_PACKET_ZERO_DATA_ON_INACTIVE_CHANNELS BIT(24) ++# define VC4_HDMI_AUDIO_PACKET_FORCE_SAMPLE_PRESENT BIT(19) ++# define VC4_HDMI_AUDIO_PACKET_FORCE_B_FRAME BIT(18) ++# define VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER_MASK VC4_MASK(13, 10) ++# define VC4_HDMI_AUDIO_PACKET_B_FRAME_IDENTIFIER_SHIFT 10 ++/* If set, then multichannel, otherwise 2 channel. */ ++# define VC4_HDMI_AUDIO_PACKET_AUDIO_LAYOUT BIT(9) ++/* If set, then AUDIO_LAYOUT overrides audio_cea_mask */ ++# define VC4_HDMI_AUDIO_PACKET_FORCE_AUDIO_LAYOUT BIT(8) ++# define VC4_HDMI_AUDIO_PACKET_CEA_MASK_MASK VC4_MASK(7, 0) ++# define VC4_HDMI_AUDIO_PACKET_CEA_MASK_SHIFT 0 ++ + #define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 + # define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) + + #define VC4_HDMI_RAM_PACKET_STATUS 0x0a4 + ++#define VC4_HDMI_CRP_CFG 0x0a8 ++/* When set, the CTS_PERIOD counts based on MAI bus sync pulse instead ++ * of pixel clock. ++ */ ++# define VC4_HDMI_CRP_USE_MAI_BUS_SYNC_FOR_CTS BIT(26) ++/* When set, no CRP packets will be sent. */ ++# define VC4_HDMI_CRP_CFG_DISABLE BIT(25) ++/* If set, generates CTS values based on N, audio clock, and video ++ * clock. N must be divisible by 128. ++ */ ++# define VC4_HDMI_CRP_CFG_EXTERNAL_CTS_EN BIT(24) ++# define VC4_HDMI_CRP_CFG_N_MASK VC4_MASK(19, 0) ++# define VC4_HDMI_CRP_CFG_N_SHIFT 0 ++ ++/* 20-bit fields containing CTS values to be transmitted if !EXTERNAL_CTS_EN */ ++#define VC4_HDMI_CTS_0 0x0ac ++#define VC4_HDMI_CTS_1 0x0b0 ++/* 20-bit fields containing number of clocks to send CTS0/1 before ++ * switching to the other one. ++ */ ++#define VC4_HDMI_CTS_PERIOD_0 0x0b4 ++#define VC4_HDMI_CTS_PERIOD_1 0x0b8 ++ + #define VC4_HDMI_HORZA 0x0c4 + # define VC4_HDMI_HORZA_VPOS BIT(14) + # define VC4_HDMI_HORZA_HPOS BIT(13) +@@ -512,7 +563,11 @@ + + #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 + +-#define VC4_HDMI_GCP_0 0x400 ++#define VC4_HDMI_TX_PHY_CTL0 0x2c4 ++# define VC4_HDMI_TX_PHY_RNG_PWRDN BIT(25) ++ ++#define VC4_HDMI_GCP(x) (0x400 + ((x) * 0x4)) ++#define VC4_HDMI_RAM_PACKET(x) (0x400 + ((x) * 0x24)) + #define VC4_HDMI_PACKET_STRIDE 0x24 + + #define VC4_HD_M_CTL 0x00c +@@ -522,6 +577,56 @@ + # define VC4_HD_M_ENABLE BIT(0) + + #define VC4_HD_MAI_CTL 0x014 ++/* Set when audio stream is received at a slower rate than the ++ * sampling period, so MAI fifo goes empty. Write 1 to clear. ++ */ ++# define VC4_HD_MAI_CTL_DLATE BIT(15) ++# define VC4_HD_MAI_CTL_BUSY BIT(14) ++# define VC4_HD_MAI_CTL_CHALIGN BIT(13) ++# define VC4_HD_MAI_CTL_WHOLSMP BIT(12) ++# define VC4_HD_MAI_CTL_FULL BIT(11) ++# define VC4_HD_MAI_CTL_EMPTY BIT(10) ++# define VC4_HD_MAI_CTL_FLUSH BIT(9) ++/* If set, MAI bus generates SPDIF (bit 31) parity instead of passing ++ * through. ++ */ ++# define VC4_HD_MAI_CTL_PAREN BIT(8) ++# define VC4_HD_MAI_CTL_CHNUM_MASK VC4_MASK(7, 4) ++# define VC4_HD_MAI_CTL_CHNUM_SHIFT 4 ++# define VC4_HD_MAI_CTL_ENABLE BIT(3) ++/* Underflow error status bit, write 1 to clear. */ ++# define VC4_HD_MAI_CTL_ERRORE BIT(2) ++/* Overflow error status bit, write 1 to clear. */ ++# define VC4_HD_MAI_CTL_ERRORF BIT(1) ++/* Single-shot reset bit. Read value is undefined. */ ++# define VC4_HD_MAI_CTL_RESET BIT(0) ++ ++#define VC4_HD_MAI_THR 0x018 ++# define VC4_HD_MAI_THR_PANICHIGH_MASK VC4_MASK(29, 24) ++# define VC4_HD_MAI_THR_PANICHIGH_SHIFT 24 ++# define VC4_HD_MAI_THR_PANICLOW_MASK VC4_MASK(21, 16) ++# define VC4_HD_MAI_THR_PANICLOW_SHIFT 16 ++# define VC4_HD_MAI_THR_DREQHIGH_MASK VC4_MASK(13, 8) ++# define VC4_HD_MAI_THR_DREQHIGH_SHIFT 8 ++# define VC4_HD_MAI_THR_DREQLOW_MASK VC4_MASK(5, 0) ++# define VC4_HD_MAI_THR_DREQLOW_SHIFT 0 ++ ++/* Format header to be placed on the MAI data. Unused. */ ++#define VC4_HD_MAI_FMT 0x01c ++ ++/* Register for DMAing in audio data to be transported over the MAI ++ * bus to the Falcon core. ++ */ ++#define VC4_HD_MAI_DATA 0x020 ++ ++/* Divider from HDMI HSM clock to MAI serial clock. Sampling period ++ * converges to N / (M + 1) cycles. ++ */ ++#define VC4_HD_MAI_SMP 0x02c ++# define VC4_HD_MAI_SMP_N_MASK VC4_MASK(31, 8) ++# define VC4_HD_MAI_SMP_N_SHIFT 8 ++# define VC4_HD_MAI_SMP_M_MASK VC4_MASK(7, 0) ++# define VC4_HD_MAI_SMP_M_SHIFT 0 + + #define VC4_HD_VID_CTL 0x038 + # define VC4_HD_VID_CTL_ENABLE BIT(31) + +From b0e084829f6a7ad74dfcc469a0270b95e7c7abe7 Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Thu, 2 Feb 2017 11:37:36 +0100 +Subject: [PATCH 223/229] ARM: dts: bcm283x: Add HDMI audio related properties + +Add the dmas and dma-names properties to support HDMI audio. + +Signed-off-by: Boris Brezillon +Signed-off-by: Eric Anholt +(cherry picked from commit d46d2c6380c10e80e99f6af9067356128bffac6b) +--- + arch/arm/boot/dts/bcm283x.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi +index 348c71bbc913644c04bab43fcb95abe9b6c9c640..7d58cd79ac6bd99f0b47a909ac827c61aac642d9 100644 +--- a/arch/arm/boot/dts/bcm283x.dtsi ++++ b/arch/arm/boot/dts/bcm283x.dtsi +@@ -339,6 +339,8 @@ + clocks = <&clocks BCM2835_PLLH_PIX>, + <&clocks BCM2835_CLOCK_HSM>; + clock-names = "pixel", "hdmi"; ++ dmas = <&dma 17>; ++ dma-names = "audio-rx"; + status = "disabled"; + }; + + +From 4bb790470fe058b8a784ec7da6bd9366cca287da Mon Sep 17 00:00:00 2001 +From: Yasunari Takiguchi +Date: Fri, 14 Apr 2017 10:43:57 +0100 +Subject: [PATCH 224/229] This is the driver for Sony CXD2880 DVB-T2/T tuner + + demodulator. It includes the CXD2880 driver and the CXD2880 SPI adapter. The + current CXD2880 driver version is 1.4.1 - 1.0.1 released on April 13, 2017. + +Signed-off-by: Yasunari Takiguchi +Signed-off-by: Masayuki Yamamoto +Signed-off-by: Hideki Nozawa +Signed-off-by: Kota Yonezawa +Signed-off-by: Toshihiko Matsumoto +Signed-off-by: Satoshi Watanabe +--- + drivers/media/dvb-frontends/Kconfig | 2 + + drivers/media/dvb-frontends/Makefile | 1 + + drivers/media/dvb-frontends/cxd2880/Kconfig | 6 + + drivers/media/dvb-frontends/cxd2880/Makefile | 21 + + drivers/media/dvb-frontends/cxd2880/cxd2880.h | 46 + + .../media/dvb-frontends/cxd2880/cxd2880_common.c | 84 + + .../media/dvb-frontends/cxd2880/cxd2880_common.h | 86 + + .../dvb-frontends/cxd2880/cxd2880_devio_spi.c | 147 + + .../dvb-frontends/cxd2880/cxd2880_devio_spi.h | 40 + + drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h | 50 + + drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h | 91 + + .../media/dvb-frontends/cxd2880/cxd2880_dvbt2.h | 402 ++ + .../media/dvb-frontends/cxd2880/cxd2880_integ.c | 99 + + .../media/dvb-frontends/cxd2880/cxd2880_integ.h | 44 + + .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.c | 197 + + .../dvb-frontends/cxd2880/cxd2880_integ_dvbt.h | 58 + + .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c | 311 ++ + .../dvb-frontends/cxd2880/cxd2880_integ_dvbt2.h | 64 + + drivers/media/dvb-frontends/cxd2880/cxd2880_io.c | 68 + + drivers/media/dvb-frontends/cxd2880/cxd2880_io.h | 62 + + drivers/media/dvb-frontends/cxd2880/cxd2880_math.c | 89 + + drivers/media/dvb-frontends/cxd2880/cxd2880_math.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 | 45 + + .../media/dvb-frontends/cxd2880/cxd2880_stdlib.h | 35 + + .../dvb-frontends/cxd2880/cxd2880_stopwatch_port.c | 71 + + .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c | 3925 ++++++++++++++++++++ + .../media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h | 395 ++ + .../cxd2880/cxd2880_tnrdmd_driver_version.h | 29 + + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c | 1072 ++++++ + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.h | 62 + + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c | 1309 +++++++ + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.h | 82 + + .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.c | 2523 +++++++++++++ + .../cxd2880/cxd2880_tnrdmd_dvbt2_mon.h | 170 + + .../cxd2880/cxd2880_tnrdmd_dvbt_mon.c | 1190 ++++++ + .../cxd2880/cxd2880_tnrdmd_dvbt_mon.h | 106 + + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c | 207 ++ + .../dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h | 52 + + drivers/media/dvb-frontends/cxd2880/cxd2880_top.c | 1550 ++++++++ + drivers/media/spi/Kconfig | 14 + + drivers/media/spi/Makefile | 5 + + drivers/media/spi/cxd2880-spi.c | 728 ++++ + 44 files changed, 15759 insertions(+) + create mode 100644 drivers/media/dvb-frontends/cxd2880/Kconfig + create mode 100644 drivers/media/dvb-frontends/cxd2880/Makefile + 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_devio_spi.c + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.h + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.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_integ_dvbt.c + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.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_io.c + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_io.h + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_math.c + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_math.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_stdlib.h + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c + 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_dvbt.c + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.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_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/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_tnrdmd_mon.c + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.h + create mode 100644 drivers/media/dvb-frontends/cxd2880/cxd2880_top.c + create mode 100644 drivers/media/spi/cxd2880-spi.c + +diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig +index b71b747ee0baae22a68c081b24132bef5f05bf2a..4b59e4a8bdab149226d8d6ff8fc7678bf65ffaa3 100644 +--- a/drivers/media/dvb-frontends/Kconfig ++++ b/drivers/media/dvb-frontends/Kconfig +@@ -518,6 +518,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/Makefile b/drivers/media/dvb-frontends/Makefile +index 93921a4eaa275997a5ed4178de1acb1a54409430..5629631ffb2f044363fd1e1d820e4df75ec41c2b 100644 +--- a/drivers/media/dvb-frontends/Makefile ++++ b/drivers/media/dvb-frontends/Makefile +@@ -126,3 +126,4 @@ obj-$(CONFIG_DVB_TC90522) += tc90522.o + obj-$(CONFIG_DVB_HORUS3A) += horus3a.o + obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o + obj-$(CONFIG_DVB_HELENE) += helene.o ++obj-$(CONFIG_DVB_CXD2880) += cxd2880/ +diff --git a/drivers/media/dvb-frontends/cxd2880/Kconfig b/drivers/media/dvb-frontends/cxd2880/Kconfig +new file mode 100644 +index 0000000000000000000000000000000000000000..36b8b6f7c4f71d9b0b8539c2713e800a32913d8e +--- /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/dvb-frontends/cxd2880/Makefile b/drivers/media/dvb-frontends/cxd2880/Makefile +new file mode 100644 +index 0000000000000000000000000000000000000000..2672c4a3d65cf4ff65e9dc8d240ae88cdfa1eb19 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/Makefile +@@ -0,0 +1,21 @@ ++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_math.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/dvb-frontends/cxd2880/cxd2880.h b/drivers/media/dvb-frontends/cxd2880/cxd2880.h +new file mode 100644 +index 0000000000000000000000000000000000000000..281f9a784eb530355bcf94500609d17180b9f73c +--- /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 . ++ */ ++ ++#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 0000000000000000000000000000000000000000..850f3a76b2c79808fd080801507f8edcda5d4b4d +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.c +@@ -0,0 +1,84 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_common.h" ++ ++#define MASKUPPER(n) (((n) == 0) ? 0 : (0xFFFFFFFFU << (32 - (n)))) ++#define MASKLOWER(n) (((n) == 0) ? 0 : (0xFFFFFFFFU >> (32 - (n)))) ++ ++int cxd2880_convert2s_complement(u32 value, u32 bitlen) ++{ ++ if ((bitlen == 0) || (bitlen >= 32)) ++ return (int)value; ++ ++ if (value & (u32)(1 << (bitlen - 1))) ++ return (int)(MASKUPPER(32 - bitlen) | value); ++ else ++ return (int)(MASKLOWER(bitlen) & value); ++} ++ ++u32 cxd2880_bit_split_from_byte_array(u8 *array, u32 start_bit, u32 bit_num) ++{ ++ u32 value = 0; ++ u8 *array_read; ++ u8 bit_read; ++ u32 len_remain; ++ ++ if (!array) ++ return 0; ++ if ((bit_num == 0) || (bit_num > 32)) ++ return 0; ++ ++ array_read = array + (start_bit / 8); ++ bit_read = (u8)(start_bit % 8); ++ len_remain = bit_num; ++ ++ if (bit_read != 0) { ++ if (((int)len_remain) <= 8 - bit_read) { ++ value = (*array_read) >> ((8 - bit_read) - len_remain); ++ len_remain = 0; ++ } else { ++ value = *array_read++; ++ len_remain -= 8 - bit_read; ++ } ++ } ++ ++ while (len_remain > 0) { ++ if (len_remain < 8) { ++ value <<= len_remain; ++ value |= (*array_read++ >> (8 - len_remain)); ++ len_remain = 0; ++ } else { ++ value <<= 8; ++ value |= (u32)(*array_read++); ++ len_remain -= 8; ++ } ++ } ++ ++ value &= MASKLOWER(bit_num); ++ ++ return 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 0000000000000000000000000000000000000000..b1ecb44bca10f730b1dc6add663c469ade5784c9 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_common.h +@@ -0,0 +1,86 @@ ++/* ++ * 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 . ++ */ ++ ++#ifndef CXD2880_COMMON_H ++#define CXD2880_COMMON_H ++ ++#include ++ ++#ifndef NULL ++#ifdef __cplusplus ++#define NULL 0 ++#else ++#define NULL ((void *)0) ++#endif ++#endif ++ ++#include ++#define CXD2880_SLEEP(n) msleep(n) ++#ifndef CXD2880_SLEEP_IN_MON ++#define CXD2880_SLEEP_IN_MON(n, obj) CXD2880_SLEEP(n) ++#endif ++ ++#define CXD2880_ARG_UNUSED(arg) ((void)(arg)) ++ ++enum cxd2880_ret { ++ CXD2880_RESULT_OK, ++ CXD2880_RESULT_ERROR_ARG, ++ CXD2880_RESULT_ERROR_IO, ++ CXD2880_RESULT_ERROR_SW_STATE, ++ CXD2880_RESULT_ERROR_HW_STATE, ++ CXD2880_RESULT_ERROR_TIMEOUT, ++ CXD2880_RESULT_ERROR_UNLOCK, ++ CXD2880_RESULT_ERROR_RANGE, ++ CXD2880_RESULT_ERROR_NOSUPPORT, ++ CXD2880_RESULT_ERROR_CANCEL, ++ CXD2880_RESULT_ERROR_OTHER, ++ CXD2880_RESULT_ERROR_OVERFLOW, ++ CXD2880_RESULT_OK_CONFIRM ++}; ++ ++int cxd2880_convert2s_complement(u32 value, u32 bitlen); ++ ++u32 cxd2880_bit_split_from_byte_array(u8 *array, u32 start_bit, u32 bit_num); ++ ++struct cxd2880_atomic { ++ int counter; ++}; ++ ++#define cxd2880_atomic_set(a, i) ((a)->counter = i) ++#define cxd2880_atomic_read(a) ((a)->counter) ++ ++struct cxd2880_stopwatch { ++ u32 start_time; ++}; ++ ++enum cxd2880_ret cxd2880_stopwatch_start(struct cxd2880_stopwatch *stopwatch); ++ ++enum cxd2880_ret cxd2880_stopwatch_sleep(struct cxd2880_stopwatch *stopwatch, ++ u32 ms); ++ ++enum cxd2880_ret cxd2880_stopwatch_elapsed(struct cxd2880_stopwatch *stopwatch, ++ u32 *elapsed); ++ ++#endif +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 0000000000000000000000000000000000000000..516efade6bf586629f5df6a72e7cd0f81544ee90 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_devio_spi.c +@@ -0,0 +1,147 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_devio_spi.h" ++#include "cxd2880_stdlib.h" ++ ++#define BURST_WRITE_MAX 128 ++ ++static enum cxd2880_ret cxd2880_io_spi_read_reg(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, ++ u8 sub_address, u8 *data, ++ u32 size) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_spi *spi = NULL; ++ u8 send_data[6]; ++ u8 *read_data_top = data; ++ ++ if ((!io) || (!io->if_object) || (!data)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (sub_address + size > 0x100) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ spi = (struct cxd2880_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] = (u8)size; ++ ++ ret = ++ spi->write_read(spi, send_data, sizeof(send_data), ++ read_data_top, send_data[2]); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ sub_address += send_data[2]; ++ read_data_top += send_data[2]; ++ size -= send_data[2]; ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret cxd2880_io_spi_write_reg(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, ++ u8 sub_address, ++ const u8 *data, u32 size) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ if (size > BURST_WRITE_MAX) ++ return CXD2880_RESULT_ERROR_OVERFLOW; ++ ++ if (sub_address + size > 0x100) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ spi = (struct cxd2880_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] = (u8)size; ++ ++ cxd2880_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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ sub_address += send_data[2]; ++ write_data_top += send_data[2]; ++ size -= send_data[2]; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_io_spi_create(struct cxd2880_io *io, ++ struct cxd2880_spi *spi, u8 slave_select) ++{ ++ if ((!io) || (!spi)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ 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 CXD2880_RESULT_OK; ++} +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 0000000000000000000000000000000000000000..15934bf11935bb0da08996f3441891fb8710b15c +--- /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 . ++ */ ++ ++#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" ++ ++enum cxd2880_ret 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_dtv.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h +new file mode 100644 +index 0000000000000000000000000000000000000000..7de098d556fec6a90f7335328059de4c69d66df2 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_dtv.h +@@ -0,0 +1,50 @@ ++/* ++ * 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 . ++ */ ++ ++#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_ISDBT, ++ CXD2880_DTV_SYS_ISDBTSB, ++ CXD2880_DTV_SYS_ISDBTMM_A, ++ CXD2880_DTV_SYS_ISDBTMM_B, ++ 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_dvbt.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt.h +new file mode 100644 +index 0000000000000000000000000000000000000000..345c094760d28a48995aca91b61ff034fa475db0 +--- /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 . ++ */ ++ ++#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_dvbt2.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_dvbt2.h +new file mode 100644 +index 0000000000000000000000000000000000000000..1870398cba9da50143a0c0d0774763edd8a31e78 +--- /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 . ++ */ ++ ++#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_integ.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c +new file mode 100644 +index 0000000000000000000000000000000000000000..5ad6685e2a1d457c5a9b8d31a1d6f4aed526dd04 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ.c +@@ -0,0 +1,99 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd.h" ++#include "cxd2880_tnrdmd_mon.h" ++#include "cxd2880_integ.h" ++ ++enum cxd2880_ret cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_stopwatch timer; ++ u32 elapsed_time = 0; ++ u8 cpu_task_completed = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_init1(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = cxd2880_stopwatch_start(&timer); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ while (1) { ++ ret = cxd2880_stopwatch_elapsed(&timer, &elapsed_time); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, ++ &cpu_task_completed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (cpu_task_completed) ++ break; ++ ++ if (elapsed_time > CXD2880_TNRDMD_WAIT_INIT_TIMEOUT) ++ return CXD2880_RESULT_ERROR_TIMEOUT; ++ ret = ++ cxd2880_stopwatch_sleep(&timer, ++ CXD2880_TNRDMD_WAIT_INIT_INTVL); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = cxd2880_tnrdmd_init2(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ cxd2880_atomic_set(&tnr_dmd->cancel, 1); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd ++ *tnr_dmd) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (cxd2880_atomic_read(&tnr_dmd->cancel) != 0) ++ return CXD2880_RESULT_ERROR_CANCEL; ++ ++ return CXD2880_RESULT_OK; ++} +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 0000000000000000000000000000000000000000..9cfc52dbf9d4fc128506ee355461cd6ca9f9ab53 +--- /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 . ++ */ ++ ++#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 ++ ++enum cxd2880_ret cxd2880_integ_init(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_integ_cancel(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_integ_check_cancellation(struct cxd2880_tnrdmd ++ *tnr_dmd); ++ ++#endif +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 0000000000000000000000000000000000000000..43b7da69fc6d689c2246047d06473074f48f69e8 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt.c +@@ -0,0 +1,197 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd_dvbt.h" ++#include "cxd2880_integ_dvbt.h" ++ ++static enum cxd2880_ret dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt_tune_param ++ *tune_param) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!tune_param)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ cxd2880_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 CXD2880_RESULT_ERROR_NOSUPPORT; ++ } ++ ++ ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ CXD2880_SLEEP(CXD2880_TNRDMD_WAIT_AGC_STABLE); ++ ++ ret = cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt_wait_demod_lock(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ enum cxd2880_tnrdmd_lock_result lock = ++ CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; ++ struct cxd2880_stopwatch timer; ++ u8 continue_wait = 1; ++ u32 elapsed = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_stopwatch_start(&timer); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ for (;;) { ++ ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (elapsed >= CXD2880_DVBT_WAIT_TS_LOCK) ++ continue_wait = 0; ++ ++ ret = cxd2880_tnrdmd_dvbt_check_ts_lock(tnr_dmd, &lock); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ switch (lock) { ++ case CXD2880_TNRDMD_LOCK_RESULT_LOCKED: ++ return CXD2880_RESULT_OK; ++ ++ case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED: ++ return CXD2880_RESULT_ERROR_UNLOCK; ++ ++ default: ++ break; ++ } ++ ++ ret = cxd2880_integ_check_cancellation(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (continue_wait) { ++ ret = ++ cxd2880_stopwatch_sleep(&timer, ++ CXD2880_DVBT_WAIT_LOCK_INTVL); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } else { ++ ret = CXD2880_RESULT_ERROR_TIMEOUT; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret dvbt_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ enum cxd2880_tnrdmd_lock_result lock = ++ CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; ++ struct cxd2880_stopwatch timer; ++ u8 continue_wait = 1; ++ u32 elapsed = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_stopwatch_start(&timer); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ for (;;) { ++ ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (elapsed >= CXD2880_DVBT_WAIT_DMD_LOCK) ++ continue_wait = 0; ++ ++ ret = cxd2880_tnrdmd_dvbt_check_demod_lock(tnr_dmd, &lock); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ switch (lock) { ++ case CXD2880_TNRDMD_LOCK_RESULT_LOCKED: ++ return CXD2880_RESULT_OK; ++ ++ case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED: ++ return CXD2880_RESULT_ERROR_UNLOCK; ++ ++ default: ++ break; ++ } ++ ++ ret = cxd2880_integ_check_cancellation(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (continue_wait) { ++ ret = ++ cxd2880_stopwatch_sleep(&timer, ++ CXD2880_DVBT_WAIT_LOCK_INTVL); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } else { ++ ret = CXD2880_RESULT_ERROR_TIMEOUT; ++ 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 0000000000000000000000000000000000000000..41f35c07a15e5052d3c09a21f1cc5c2085158690 +--- /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 . ++ */ ++ ++#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; ++ enum cxd2880_ret tune_result; ++ struct cxd2880_dvbt_tune_param dvbt_tune_param; ++}; ++ ++enum cxd2880_ret cxd2880_integ_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt_tune_param ++ *tune_param); ++ ++enum cxd2880_ret cxd2880_integ_dvbt_wait_ts_lock(struct cxd2880_tnrdmd ++ *tnr_dmd); ++ ++#endif +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 0000000000000000000000000000000000000000..1d60b9c236d844df239e3adfa0da40192555c7ee +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_integ_dvbt2.c +@@ -0,0 +1,311 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd_dvbt2.h" ++#include "cxd2880_tnrdmd_dvbt2_mon.h" ++#include "cxd2880_integ_dvbt2.h" ++ ++static enum cxd2880_ret dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dvbt2_profile ++ profile); ++ ++static enum cxd2880_ret dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_tune_param ++ *tune_param) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!tune_param)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ cxd2880_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 CXD2880_RESULT_ERROR_NOSUPPORT; ++ } ++ ++ if ((tune_param->profile != CXD2880_DVBT2_PROFILE_BASE) && ++ (tune_param->profile != CXD2880_DVBT2_PROFILE_LITE)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ CXD2880_SLEEP(CXD2880_TNRDMD_WAIT_AGC_STABLE); ++ ++ ret = cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt2_wait_demod_lock(tnr_dmd, tune_param->profile); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = cxd2880_tnrdmd_dvbt2_diver_fef_setting(tnr_dmd); ++ if (ret == CXD2880_RESULT_ERROR_HW_STATE) ++ return CXD2880_RESULT_ERROR_UNLOCK; ++ else if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt2_wait_l1_post_lock(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ { ++ u8 plp_not_found; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_data_plp_error(tnr_dmd, ++ &plp_not_found); ++ if (ret == CXD2880_RESULT_ERROR_HW_STATE) ++ return CXD2880_RESULT_ERROR_UNLOCK; ++ else if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (plp_not_found) { ++ ret = CXD2880_RESULT_OK_CONFIRM; ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_integ_dvbt2_wait_ts_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_profile ++ profile) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ enum cxd2880_tnrdmd_lock_result lock = ++ CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; ++ u16 timeout = 0; ++ struct cxd2880_stopwatch timer; ++ u8 continue_wait = 1; ++ u32 elapsed = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_stopwatch_start(&timer); ++ if (ret != CXD2880_RESULT_OK) ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ for (;;) { ++ ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (elapsed >= timeout) ++ continue_wait = 0; ++ ++ ret = cxd2880_tnrdmd_dvbt2_check_ts_lock(tnr_dmd, &lock); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ switch (lock) { ++ case CXD2880_TNRDMD_LOCK_RESULT_LOCKED: ++ return CXD2880_RESULT_OK; ++ ++ case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED: ++ return CXD2880_RESULT_ERROR_UNLOCK; ++ ++ default: ++ break; ++ } ++ ++ ret = cxd2880_integ_check_cancellation(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (continue_wait) { ++ ret = ++ cxd2880_stopwatch_sleep(&timer, ++ CXD2880_DVBT2_WAIT_LOCK_INTVL); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } else { ++ ret = CXD2880_RESULT_ERROR_TIMEOUT; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret dvbt2_wait_demod_lock(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dvbt2_profile ++ profile) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ enum cxd2880_tnrdmd_lock_result lock = ++ CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; ++ u16 timeout = 0; ++ struct cxd2880_stopwatch timer; ++ u8 continue_wait = 1; ++ u32 elapsed = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_stopwatch_start(&timer); ++ if (ret != CXD2880_RESULT_OK) ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ ++ for (;;) { ++ ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (elapsed >= timeout) ++ continue_wait = 0; ++ ++ ret = cxd2880_tnrdmd_dvbt2_check_demod_lock(tnr_dmd, &lock); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ switch (lock) { ++ case CXD2880_TNRDMD_LOCK_RESULT_LOCKED: ++ return CXD2880_RESULT_OK; ++ ++ case CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED: ++ return CXD2880_RESULT_ERROR_UNLOCK; ++ ++ default: ++ break; ++ } ++ ++ ret = cxd2880_integ_check_cancellation(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (continue_wait) { ++ ret = ++ cxd2880_stopwatch_sleep(&timer, ++ CXD2880_DVBT2_WAIT_LOCK_INTVL); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } else { ++ ret = CXD2880_RESULT_ERROR_TIMEOUT; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret dvbt2_wait_l1_post_lock(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_stopwatch timer; ++ u8 continue_wait = 1; ++ u32 elapsed = 0; ++ u8 l1_post_valid; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_stopwatch_start(&timer); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ for (;;) { ++ ret = cxd2880_stopwatch_elapsed(&timer, &elapsed); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (l1_post_valid) ++ return CXD2880_RESULT_OK; ++ ++ ret = cxd2880_integ_check_cancellation(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (continue_wait) { ++ ret = ++ cxd2880_stopwatch_sleep(&timer, ++ CXD2880_DVBT2_WAIT_LOCK_INTVL); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } else { ++ ret = CXD2880_RESULT_ERROR_TIMEOUT; ++ 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 0000000000000000000000000000000000000000..bc72eb8188f2e5304cef7db687291b56eb728f8d +--- /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 . ++ */ ++ ++#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; ++ enum cxd2880_ret tune_result; ++ struct cxd2880_dvbt2_tune_param dvbt2_tune_param; ++}; ++ ++enum cxd2880_ret cxd2880_integ_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_tune_param ++ *tune_param); ++ ++enum cxd2880_ret 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_io.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_io.c +new file mode 100644 +index 0000000000000000000000000000000000000000..f0f82055a953337a3fed96feedc2ca5b8d961c4f +--- /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 . ++ */ ++ ++#include "cxd2880_io.h" ++ ++enum cxd2880_ret cxd2880_io_common_write_one_reg(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, ++ u8 sub_address, u8 data) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!io) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = io->write_regs(io, tgt, sub_address, &data, 1); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_io_set_reg_bits(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, ++ u8 sub_address, u8 data, u8 mask) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!io) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (mask == 0x00) ++ return CXD2880_RESULT_OK; ++ ++ if (mask != 0xFF) { ++ u8 rdata = 0x00; ++ ++ ret = io->read_regs(io, tgt, sub_address, &rdata, 1); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ data = (u8)((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 0000000000000000000000000000000000000000..4d6db13cf9109373eb1262218b853ef37283958b +--- /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 . ++ */ ++ ++#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 { ++ enum cxd2880_ret (*read_regs)(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, u8 sub_address, ++ u8 *data, u32 size); ++ enum cxd2880_ret (*write_regs)(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, u8 sub_address, ++ const u8 *data, u32 size); ++ enum cxd2880_ret (*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; ++}; ++ ++enum cxd2880_ret cxd2880_io_common_write_one_reg(struct cxd2880_io *io, ++ enum cxd2880_io_tgt tgt, ++ u8 sub_address, u8 data); ++ ++enum cxd2880_ret 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_math.c b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.c +new file mode 100644 +index 0000000000000000000000000000000000000000..434c827898ff5f4a44bcc013fa7df43c168cafc4 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.c +@@ -0,0 +1,89 @@ ++/* ++ * cxd2880_math.c ++ * Sony CXD2880 DVB-T2/T tuner + demodulator driver ++ * mathmatics 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 . ++ */ ++ ++#include "cxd2880_math.h" ++ ++#define MAX_BIT_PRECISION 5 ++#define FRAC_BITMASK 0x1F ++#define LOG2_10_100X 332 ++#define LOG2_E_100X 144 ++ ++static const u8 log2_look_up[] = { ++ 0, 4, ++ 9, 13, ++ 17, 21, ++ 25, 29, ++ 32, 36, ++ 39, 43, ++ 46, 49, ++ 52, 55, ++ 58, 61, ++ 64, 67, ++ 70, 73, ++ 75, 78, ++ 81, 83, ++ 86, 88, ++ 91, 93, ++ 95, 98 ++}; ++ ++u32 cxd2880_math_log2(u32 x) ++{ ++ u8 count = 0; ++ u8 index = 0; ++ u32 xval = x; ++ ++ for (x >>= 1; x > 0; x >>= 1) ++ count++; ++ ++ x = count * 100; ++ ++ if (count > 0) { ++ if (count <= MAX_BIT_PRECISION) { ++ index = ++ (u8)(xval << (MAX_BIT_PRECISION - count)) & ++ FRAC_BITMASK; ++ x += log2_look_up[index]; ++ } else { ++ index = ++ (u8)(xval >> (count - MAX_BIT_PRECISION)) & ++ FRAC_BITMASK; ++ x += log2_look_up[index]; ++ } ++ } ++ ++ return x; ++} ++ ++u32 cxd2880_math_log10(u32 x) ++{ ++ return ((100 * cxd2880_math_log2(x) + LOG2_10_100X / 2) / LOG2_10_100X); ++} ++ ++u32 cxd2880_math_log(u32 x) ++{ ++ return ((100 * cxd2880_math_log2(x) + LOG2_E_100X / 2) / LOG2_E_100X); ++} +diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_math.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.h +new file mode 100644 +index 0000000000000000000000000000000000000000..94211835a4adca74e4ddad3ea417f01d9f8eedef +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_math.h +@@ -0,0 +1,40 @@ ++/* ++ * cxd2880_math.h ++ * Sony CXD2880 DVB-T2/T tuner + demodulator driver ++ * mathmatics 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 . ++ */ ++ ++#ifndef CXD2880_MATH_H_ ++#define CXD2880_MATH_H_ ++ ++#include "cxd2880_common.h" ++ ++u32 cxd2880_math_log2(u32 x); ++u32 cxd2880_math_log10(u32 x); ++u32 cxd2880_math_log(u32 x); ++ ++#ifndef min ++#define min(a, b) (((a) < (b)) ? (a) : (b)) ++#endif ++ ++#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 0000000000000000000000000000000000000000..81e5be7479623e536f6b472a38ae8af785291506 +--- /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 . ++ */ ++ ++#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 { ++ enum cxd2880_ret (*read)(struct cxd2880_spi *spi, u8 *data, ++ u32 size); ++ enum cxd2880_ret (*write)(struct cxd2880_spi *spi, const u8 *data, ++ u32 size); ++ enum cxd2880_ret (*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 0000000000000000000000000000000000000000..af9ed40c900b09c0566748d56991573965233ab4 +--- /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 . ++ */ ++ ++#include ++ ++#include "cxd2880_spi_device.h" ++ ++static enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ spi_device = (struct cxd2880_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 CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ spi_device = (struct cxd2880_spi_device *)(spi->user); ++ ++ result = spi_write_then_read(spi_device->spi, tx_data, ++ tx_size, rx_data, rx_size); ++ if (result < 0) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret ++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 CXD2880_RESULT_ERROR_ARG; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, ++ struct cxd2880_spi_device *spi_device) ++{ ++ if ((!spi) || (!spi_device)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ 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 CXD2880_RESULT_OK; ++} +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 0000000000000000000000000000000000000000..343d9161d537b2eb5bcc61e5cbd4c9fa04f5f8fe +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_spi_device.h +@@ -0,0 +1,45 @@ ++/* ++ * 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 . ++ */ ++ ++#ifndef CXD2880_SPI_DEVICE_H ++#define CXD2880_SPI_DEVICE_H ++ ++#include "cxd2880_spi.h" ++ ++struct cxd2880_spi_device { ++ struct spi_device *spi; ++}; ++ ++enum cxd2880_ret ++cxd2880_spi_device_initialize(struct cxd2880_spi_device *spi_device, ++ enum cxd2880_spi_mode mode, ++ u32 speedHz); ++ ++enum cxd2880_ret ++cxd2880_spi_device_create_spi(struct cxd2880_spi *spi, ++ struct cxd2880_spi_device *spi_device); ++ ++#endif /* CXD2880_SPI_DEVICE_H */ +diff --git a/drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h b/drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h +new file mode 100644 +index 0000000000000000000000000000000000000000..b9ca1b9df1101b3a1cd78db593c9f36b08f67e01 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_stdlib.h +@@ -0,0 +1,35 @@ ++/* ++ * cxd2880_stdlib.h ++ * Sony CXD2880 DVB-T2/T tuner + demodulator driver ++ * standard lib function aliases ++ * ++ * 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 . ++ */ ++ ++#ifndef CXD2880_STDLIB_H ++#define CXD2880_STDLIB_H ++ ++#include ++ ++#define cxd2880_memcpy memcpy ++#define cxd2880_memset memset ++ ++#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 0000000000000000000000000000000000000000..14ad6aa6c4c0500c0e0ed59ab1c28f1dfe13f1d3 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_stopwatch_port.c +@@ -0,0 +1,71 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_common.h" ++ ++#include ++#include ++#include ++ ++static u32 get_time_count(void) ++{ ++ struct timespec tp; ++ ++ getnstimeofday(&tp); ++ ++ return (u32)((tp.tv_sec * 1000) + (tp.tv_nsec / 1000000)); ++} ++ ++enum cxd2880_ret cxd2880_stopwatch_start(struct cxd2880_stopwatch *stopwatch) ++{ ++ if (!stopwatch) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ stopwatch->start_time = get_time_count(); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_stopwatch_sleep(struct cxd2880_stopwatch *stopwatch, ++ u32 ms) ++{ ++ if (!stopwatch) ++ return CXD2880_RESULT_ERROR_ARG; ++ CXD2880_ARG_UNUSED(*stopwatch); ++ CXD2880_SLEEP(ms); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_stopwatch_elapsed(struct cxd2880_stopwatch *stopwatch, ++ u32 *elapsed) ++{ ++ if (!stopwatch || !elapsed) ++ return CXD2880_RESULT_ERROR_ARG; ++ *elapsed = get_time_count() - stopwatch->start_time; ++ ++ return CXD2880_RESULT_OK; ++} +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 0000000000000000000000000000000000000000..286384ae012443c432a232401ff35157c57ed0f5 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.c +@@ -0,0 +1,3925 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_common.h" ++#include "cxd2880_stdlib.h" ++#include "cxd2880_tnrdmd.h" ++#include "cxd2880_tnrdmd_mon.h" ++#include "cxd2880_tnrdmd_dvbt.h" ++#include "cxd2880_tnrdmd_dvbt2.h" ++ ++static enum cxd2880_ret p_init1(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x11, ++ 0x16) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_NOSUPPORT; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->create_param.en_internal_ldo) ++ data = 0x01; ++ else ++ data = 0x00; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x11, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x13, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x12, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_NOSUPPORT; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x69, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret p_init2(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data[6] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ data[4] = 0x06; ++ data[5] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x13, data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret p_init3(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data[2] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ ++ data[1] = 0x01; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x1F, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret rf_init1(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data[80] = { 0 }; ++ u8 addr = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x01; ++ data[1] = 0x00; ++ data[2] = 0x01; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x21, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x01; ++ data[1] = 0x01; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x17, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->create_param.stationary_use) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x1A, ++ 0x06) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x4F, ++ 0x18) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x61, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x71, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x9D, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x7D, ++ 0x02) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x8F, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x8B, ++ 0xC6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x9A, ++ 0x03) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x1C, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xB5, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xB9, ++ 0x07) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x33, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xC1, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xC4, ++ 0x1E) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xD9, data, ++ 8) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x6C; ++ data[1] = 0x10; ++ data[2] = 0xA6; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x44, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x16; ++ data[1] = 0xA8; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x50, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x22; ++ data[2] = 0x00; ++ data[3] = 0x88; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x62, data, ++ 4) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x74, ++ 0x75) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x05; ++ data[1] = 0x05; ++ data[2] = 0x05; ++ data[3] = 0x05; ++ data[4] = 0x05; ++ data[5] = 0x05; ++ data[6] = 0x05; ++ data[7] = 0x05; ++ data[8] = 0x05; ++ data[9] = 0x04; ++ data[10] = 0x04; ++ data[11] = 0x04; ++ data[12] = 0x03; ++ data[13] = 0x03; ++ data[14] = 0x03; ++ data[15] = 0x04; ++ data[16] = 0x04; ++ data[17] = 0x05; ++ data[18] = 0x05; ++ data[19] = 0x05; ++ data[20] = 0x02; ++ data[21] = 0x02; ++ data[22] = 0x02; ++ data[23] = 0x02; ++ data[24] = 0x02; ++ data[25] = 0x02; ++ data[26] = 0x02; ++ data[27] = 0x02; ++ data[28] = 0x02; ++ data[29] = 0x03; ++ data[30] = 0x02; ++ data[31] = 0x01; ++ data[32] = 0x01; ++ data[33] = 0x01; ++ data[34] = 0x02; ++ data[35] = 0x02; ++ data[36] = 0x03; ++ data[37] = 0x04; ++ data[38] = 0x04; ++ data[39] = 0x04; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x7F, data, ++ 40) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x16) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x71; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x23, ++ 0x89) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0xFF; ++ data[1] = 0x00; ++ data[2] = 0x00; ++ data[3] = 0x00; ++ data[4] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x00; ++ data[2] = 0x00; ++ data[3] = 0x00; ++ data[4] = 0x00; ++ data[5] = 0x01; ++ data[6] = 0x00; ++ data[7] = 0x01; ++ data[8] = 0x00; ++ data[9] = 0x02; ++ data[10] = 0x00; ++ data[11] = 0x63; ++ data[12] = 0x00; ++ data[13] = 0x00; ++ data[14] = 0x00; ++ data[15] = 0x03; ++ data[16] = 0x00; ++ data[17] = 0x04; ++ data[18] = 0x00; ++ data[19] = 0x04; ++ data[20] = 0x00; ++ data[21] = 0x06; ++ data[22] = 0x00; ++ data[23] = 0x06; ++ data[24] = 0x00; ++ data[25] = 0x08; ++ data[26] = 0x00; ++ data[27] = 0x09; ++ data[28] = 0x00; ++ data[29] = 0x0B; ++ data[30] = 0x00; ++ data[31] = 0x0B; ++ data[32] = 0x00; ++ data[33] = 0x0D; ++ data[34] = 0x00; ++ data[35] = 0x0D; ++ data[36] = 0x00; ++ data[37] = 0x0F; ++ data[38] = 0x00; ++ data[39] = 0x0F; ++ data[40] = 0x00; ++ data[41] = 0x0F; ++ data[42] = 0x00; ++ data[43] = 0x10; ++ data[44] = 0x00; ++ data[45] = 0x79; ++ data[46] = 0x00; ++ data[47] = 0x00; ++ data[48] = 0x00; ++ data[49] = 0x02; ++ data[50] = 0x00; ++ data[51] = 0x00; ++ data[52] = 0x00; ++ data[53] = 0x03; ++ data[54] = 0x00; ++ data[55] = 0x01; ++ data[56] = 0x00; ++ data[57] = 0x03; ++ data[58] = 0x00; ++ data[59] = 0x03; ++ data[60] = 0x00; ++ data[61] = 0x03; ++ data[62] = 0x00; ++ data[63] = 0x04; ++ data[64] = 0x00; ++ data[65] = 0x04; ++ data[66] = 0x00; ++ data[67] = 0x06; ++ data[68] = 0x00; ++ data[69] = 0x05; ++ data[70] = 0x00; ++ data[71] = 0x07; ++ data[72] = 0x00; ++ data[73] = 0x07; ++ data[74] = 0x00; ++ data[75] = 0x08; ++ data[76] = 0x00; ++ data[77] = 0x0A; ++ data[78] = 0x03; ++ data[79] = 0xE0; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x3A, data, ++ 80) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = 0x03; ++ data[1] = 0xE0; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xBC, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x51, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xC5, ++ 0x07) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x70, ++ 0xE9) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x76, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x78, ++ 0x32) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x7A, ++ 0x46) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x7C, ++ 0x86) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x7E, ++ 0xA4) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xE1, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x12) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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; ++ } ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, addr, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x13) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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; ++ } ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, addr, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x08; ++ data[1] = 0x09; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xBD, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x08; ++ data[1] = 0x09; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xC4, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x20; ++ data[1] = 0x20; ++ data[2] = 0x30; ++ data[3] = 0x41; ++ data[4] = 0x50; ++ data[5] = 0x5F; ++ data[6] = 0x6F; ++ data[7] = 0x80; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xC9, data, ++ 8) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x14) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x15; ++ data[1] = 0x18; ++ data[2] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x15, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x16) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x09; ++ data[2] = 0x00; ++ data[3] = 0x08; ++ data[4] = 0x00; ++ data[5] = 0x07; ++ data[6] = 0x00; ++ data[7] = 0x06; ++ data[8] = 0x00; ++ data[9] = 0x05; ++ data[10] = 0x00; ++ data[11] = 0x03; ++ data[12] = 0x00; ++ data[13] = 0x02; ++ data[14] = 0x00; ++ data[15] = 0x00; ++ data[16] = 0x00; ++ data[17] = 0x78; ++ data[18] = 0x00; ++ data[19] = 0x00; ++ data[20] = 0x00; ++ data[21] = 0x06; ++ data[22] = 0x00; ++ data[23] = 0x08; ++ data[24] = 0x00; ++ data[25] = 0x08; ++ data[26] = 0x00; ++ data[27] = 0x0C; ++ data[28] = 0x00; ++ data[29] = 0x0C; ++ data[30] = 0x00; ++ data[31] = 0x0D; ++ data[32] = 0x00; ++ data[33] = 0x0F; ++ data[34] = 0x00; ++ data[35] = 0x0E; ++ data[36] = 0x00; ++ data[37] = 0x0E; ++ data[38] = 0x00; ++ data[39] = 0x10; ++ data[40] = 0x00; ++ data[41] = 0x0F; ++ data[42] = 0x00; ++ data[43] = 0x0E; ++ data[44] = 0x00; ++ data[45] = 0x10; ++ data[46] = 0x00; ++ data[47] = 0x0F; ++ data[48] = 0x00; ++ data[49] = 0x0E; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x12, data, ++ 50) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0x00) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x25, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x11, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0x00) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x02, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x8F, ++ 0x16) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x67, ++ 0x60) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6A, ++ 0x0F) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6C, ++ 0x17) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0xFE; ++ data[2] = 0xEE; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6E, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0xA1; ++ data[1] = 0x8B; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x8D, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x08; ++ data[1] = 0x09; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x77, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->create_param.stationary_use) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x80, ++ 0xAA) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x41, ++ 0xA0) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ 0x68) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x25, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x1A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0x00) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x14, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x26, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret rf_init2(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data[5] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x40; ++ data[1] = 0x40; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xEA, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ 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; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x30, data, ++ 4) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x14) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x1B, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xD3, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret 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 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = 0x00; ++ data[1] = 0x00; ++ data[2] = 0x0E; ++ data[3] = 0x00; ++ data[4] = 0x03; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xE7, data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = 0x1F; ++ data[1] = 0x80; ++ data[2] = 0x18; ++ data[3] = 0x00; ++ data[4] = 0x07; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xE7, data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ 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: ++ case CXD2880_DTV_SYS_ISDBT: ++ case CXD2880_DTV_SYS_ISDBTSB: ++ case CXD2880_DTV_SYS_ISDBTMM_A: ++ case CXD2880_DTV_SYS_ISDBTMM_B: ++ data[2] = 0x94; ++ data[6] = 0x91; ++ break; ++ case CXD2880_DTV_SYS_DVBT2: ++ data[2] = 0x96; ++ data[6] = 0x93; ++ break; ++ default: ++ return CXD2880_RESULT_ERROR_ARG; ++ } ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x44, data, ++ 8) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x62, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x15) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x03; ++ data[1] = 0xE2; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x1E, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = (u8)(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 CXD2880_RESULT_ERROR_ARG; ++ } ++ ++ data[5] = 0x00; ++ ++ freq_khz += shift_frequency_khz; ++ ++ data[6] = (u8)((freq_khz >> 16) & 0x0F); ++ data[7] = (u8)((freq_khz >> 8) & 0xFF); ++ data[8] = (u8)(freq_khz & 0xFF); ++ data[9] = 0xFF; ++ data[10] = 0xFE; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x52, data, ++ 11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret 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 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = 0x01; ++ data[1] = 0x0E; ++ data[2] = 0x01; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2D, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x1A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x29, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2C, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x60, ++ data[0]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x62, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2D, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2F, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (shift_frequency_khz != 0) { ++ int shift_freq = 0; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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] = (u8)(((u32)shift_freq >> 8) & 0xFF); ++ data[1] = (u8)((u32)shift_freq & 0xFF); ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x69, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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] = (u8)((u32)shift_freq & 0xFF); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x69, ++ data[0]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->create_param.stationary_use) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x8A, ++ 0x87) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_tune3(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dtv_sys sys, ++ u8 en_fef_intmtnt_ctrl) ++{ ++ u8 data[6] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x41, ++ 0xA0) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xFE, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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; ++ } ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xEF, data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x2D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((sys == CXD2880_DTV_SYS_DVBT2) && en_fef_intmtnt_ctrl) ++ data[0] = 0x00; ++ else ++ data[0] = 0x01; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB1, ++ data[0]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_tune4(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data[2] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ { ++ if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != ++ CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x14; ++ data[1] = 0x00; ++ if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x55, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x0B; ++ data[1] = 0xFF; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x53, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x57, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x0B; ++ data[1] = 0xFF; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x55, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != ++ CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x14; ++ data[1] = 0x00; ++ if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x53, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x57, ++ 0x02) != ++ CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xFE, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_DMD, 0xFE, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_sleep1(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data[3] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x57, ++ 0x03) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x53, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ if (tnr_dmd->diver_sub->io->write_reg(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != ++ CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x1F; ++ data[1] = 0xFF; ++ data[2] = 0x03; ++ if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x55, ++ data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x00; ++ if (tnr_dmd->diver_sub->io->write_regs(tnr_dmd->diver_sub->io, ++ CXD2880_IO_TGT_SYS, 0x53, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x1F; ++ data[1] = 0xFF; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x55, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_sleep2(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 data = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x2D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB1, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB2, &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data & 0x01) == 0x00) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xF4, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xF3, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xF2, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xF1, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xF0, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xEF, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_sleep3(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xFD, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_sleep4(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0xE2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x41, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret spll_reset(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_tnrdmd_clockmode clockmode) ++{ ++ u8 data[4] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x29, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x28, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x26, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x22, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x30, ++ data[0]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x22, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(2); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x10, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0x00) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x00; ++ data[2] = 0x00; ++ data[3] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x26, data, ++ 4) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret t_power_x(struct cxd2880_tnrdmd *tnr_dmd, u8 on) ++{ ++ u8 data[3] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x29, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x28, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x25, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (on) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2B, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x12, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2A, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } else { ++ data[0] = 0x03; ++ data[1] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2A, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x13, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x25, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x11, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if ((data[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ data[0] = 0x00; ++ data[1] = 0x00; ++ data[2] = 0x00; ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x27, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++struct cxd2880_tnrdmd_ts_clk_cfg { ++ u8 srl_clk_mode; ++ u8 srl_duty_mode; ++ u8 ts_clk_period; ++}; ++ ++static enum cxd2880_ret set_ts_clk_mode_and_freq(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dtv_sys sys) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 ts_rate_ctrl_off = 0; ++ u8 ts_in_off = 0; ++ u8 ts_clk_manaul_on = 0; ++ ++ if ((sys == CXD2880_DTV_SYS_ISDBT) || ++ (sys == CXD2880_DTV_SYS_ISDBTSB) || ++ (sys == CXD2880_DTV_SYS_ISDBTMM_A) || ++ (sys == CXD2880_DTV_SYS_ISDBTMM_B)) { ++ backwards_compatible = 0; ++ ts_rate_ctrl_off = 1; ++ ts_in_off = 0; ++ } else 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD, ++ 0xDE, ts_in_off, 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_io_set_reg_bits(tnr_dmd->io, CXD2880_IO_TGT_DMD, ++ 0xDA, ts_clk_manaul_on, 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ts_clk_cfg = ++ srl_ts_clk_stgs[tnr_dmd->srl_ts_clk_mod_cnts] ++ [(u8)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 != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xD9, ++ ts_clk_cfg.ts_clk_period); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ { ++ u8 data = (u8)(backwards_compatible ? 0x00 : 0x01); ++ ++ if (sys == CXD2880_DTV_SYS_DVBT) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_io_set_reg_bits(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x66, ++ data, 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret pid_ftr_setting(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_tnrdmd_pid_ftr_cfg ++ *pid_ftr_cfg) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (!pid_ftr_cfg) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x50, ++ 0x02) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } else { ++ u8 data[65]; ++ ++ data[0] = (u8)(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)] = ++ (u8)((u8) ++ (pid_ftr_cfg->pid_cfg[i].pid ++ >> 8) | 0x20); ++ data[2 + (i * 2)] = ++ (u8)(pid_ftr_cfg->pid_cfg[i].pid ++ & 0xFF); ++ } else { ++ data[1 + (i * 2)] = 0x00; ++ data[2 + (i * 2)] = 0x00; ++ } ++ } ++ } ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x50, data, ++ 65) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret load_cfg_mem(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u8 i; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ 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 != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ 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 CXD2880_RESULT_ERROR_OVERFLOW; ++ } ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ cxd2880_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; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ cxd2880_memset(tnr_dmd_main, 0, sizeof(struct cxd2880_tnrdmd)); ++ cxd2880_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 CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ 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; ++ cxd2880_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; ++ cxd2880_atomic_set(&tnr_dmd->diver_sub->cancel, 0); ++ } ++ ++ ret = cxd2880_tnrdmd_chip_id(tnr_dmd, &tnr_dmd->chip_id); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->chip_id)) ++ return CXD2880_RESULT_ERROR_NOSUPPORT; ++ ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (!CXD2880_TNRDMD_CHIP_ID_VALID(tnr_dmd->diver_sub->chip_id)) ++ return CXD2880_RESULT_ERROR_NOSUPPORT; ++ } ++ ++ ret = p_init1(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = p_init1(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ CXD2880_SLEEP(1); ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = p_init2(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = p_init2(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ CXD2880_SLEEP(5); ++ ++ ret = p_init3(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = p_init3(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = rf_init1(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = rf_init1(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ { ++ u8 cpu_task_completed = 0; ++ ++ ret = ++ cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, ++ &cpu_task_completed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (!cpu_task_completed) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ ret = rf_init2(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = rf_init2(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = load_cfg_mem(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = load_cfg_mem(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *task_completed) ++{ ++ u16 cpu_status = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!task_completed)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd, &cpu_status); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (cpu_status == 0) ++ *task_completed = 1; ++ else ++ *task_completed = 0; ++ ++ return ret; ++} ++ ++enum cxd2880_ret 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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (frequency_khz < 4000) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = cxd2880_tnrdmd_sleep(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ { ++ u8 data = 0; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x2B, &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ switch (sys) { ++ case CXD2880_DTV_SYS_DVBT: ++ case CXD2880_DTV_SYS_ISDBT: ++ case CXD2880_DTV_SYS_ISDBTSB: ++ case CXD2880_DTV_SYS_ISDBTMM_A: ++ case CXD2880_DTV_SYS_ISDBTMM_B: ++ if (data == 0x00) { ++ ret = t_power_x(tnr_dmd, 1); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == ++ CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = t_power_x(tnr_dmd->diver_sub, 1); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ } ++ break; ++ ++ case CXD2880_DTV_SYS_DVBT2: ++ if (data == 0x01) { ++ ret = t_power_x(tnr_dmd, 0); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == ++ CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = t_power_x(tnr_dmd->diver_sub, 0); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ } ++ break; ++ ++ default: ++ return CXD2880_RESULT_ERROR_ARG; ++ } ++ } ++ ++ { ++ enum cxd2880_tnrdmd_clockmode new_clk_mode = ++ CXD2880_TNRDMD_CLOCKMODE_A; ++ ++ ret = spll_reset(tnr_dmd, new_clk_mode); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ tnr_dmd->diver_sub->clk_mode = new_clk_mode; ++ } ++ ++ ret = load_cfg_mem(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = load_cfg_mem(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ CXD2880_SLEEP(10); ++ ++ { ++ u8 cpu_task_completed = 0; ++ ++ ret = ++ cxd2880_tnrdmd_check_internal_cpu_status(tnr_dmd, ++ &cpu_task_completed); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (!cpu_task_completed) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ ret = ++ x_tune2(tnr_dmd, bandwidth, tnr_dmd->clk_mode, ++ shift_frequency_khz); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dtv_sys sys, ++ u8 en_fef_intmtnt_ctrl) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = x_tune3(tnr_dmd, sys, en_fef_intmtnt_ctrl); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_tune4(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = cxd2880_tnrdmd_set_ts_output(tnr_dmd, 1); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_sleep1(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = x_sleep2(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_sleep2(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ switch (tnr_dmd->sys) { ++ case CXD2880_DTV_SYS_DVBT: ++ ret = cxd2880_tnrdmd_dvbt_sleep_setting(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_DTV_SYS_DVBT2: ++ ret = cxd2880_tnrdmd_dvbt2_sleep_setting(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ default: ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ ret = x_sleep3(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_sleep3(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = x_sleep4(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_sleep4(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_tnrdmd_cfg_id id, ++ int value) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u8 data[2] = { 0 }; ++ u8 need_sub_setting = 0; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ switch (id) { ++ case CXD2880_TNRDMD_CFG_OUTPUT_SEL_MSB: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC4, ++ (u8)(value ? 0x00 : ++ 0x10), 0x10); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSVALID_ACTIVE_HI: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC5, ++ (u8)(value ? 0x00 : ++ 0x02), 0x02); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSSYNC_ACTIVE_HI: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC5, ++ (u8)(value ? 0x00 : ++ 0x04), 0x04); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSERR_ACTIVE_HI: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xCB, ++ (u8)(value ? 0x00 : ++ 0x01), 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_LATCH_ON_POSEDGE: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC5, ++ (u8)(value ? 0x01 : ++ 0x00), 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSCLK_CONT: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ tnr_dmd->srl_ts_clk_mod_cnts = (u8)(value ? 0x01 : 0x00); ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSCLK_MASK: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((value < 0) || (value > 0x1F)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC6, (u8)value, ++ 0x1F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSVALID_MASK: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((value < 0) || (value > 0x1F)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC8, (u8)value, ++ 0x1F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSERR_MASK: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((value < 0) || (value > 0x1F)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xC9, (u8)value, ++ 0x1F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSERR_VALID_DIS: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x91, ++ (u8)(value ? 0x01 : ++ 0x00), 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSPIN_CURRENT: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x51, (u8)value, ++ 0x3F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSPIN_PULLUP_MANUAL: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x50, ++ (u8)(value ? 0x80 : ++ 0x00), 0x80); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSPIN_PULLUP: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x50, (u8)value, ++ 0x3F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TSCLK_FREQ: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((value < 0) || (value > 1)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((value < 0) || (value > 0xFF)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ tnr_dmd->ts_byte_clk_manual_setting = (u8)value; ++ ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TS_PACKET_GAP: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((value < 0) || (value > 7)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0xD6, (u8)value, ++ 0x07); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TS_BACKWARDS_COMPATIBLE: ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ tnr_dmd->is_ts_backwards_compatible_mode = (u8)(value ? 1 : 0); ++ ++ break; ++ ++ case CXD2880_TNRDMD_CFG_PWM_VALUE: ++ if ((value < 0) || (value > 0x1000)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x22, ++ (u8)(value ? 0x01 : ++ 0x00), 0x01); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ { ++ u8 data[2]; ++ ++ data[0] = (u8)(((u16)value >> 8) & 0x1F); ++ data[1] = (u8)((u16)value & 0xFF); ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x23, ++ data[0], 0x1F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x24, ++ data[1], 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ break; ++ ++ case CXD2880_TNRDMD_CFG_INTERRUPT: ++ data[0] = (u8)((value >> 8) & 0xFF); ++ data[1] = (u8)(value & 0xFF); ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x48, data[0], ++ 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x49, data[1], ++ 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_INTERRUPT_LOCK_SEL: ++ data[0] = (u8)(value & 0x07); ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x4A, data[0], ++ 0x07); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_INTERRUPT_INV_LOCK_SEL: ++ data[0] = (u8)((value & 0x07) << 3); ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_SYS, ++ 0x00, 0x4A, data[0], ++ 0x38); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_FIXED_CLOCKMODE: ++ if ((value < (int)CXD2880_TNRDMD_CLOCKMODE_UNKNOWN) || ++ (value > (int)CXD2880_TNRDMD_CLOCKMODE_C)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ tnr_dmd->fixed_clk_mode = (enum cxd2880_tnrdmd_clockmode)value; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_CABLE_INPUT: ++ tnr_dmd->is_cable_input = (u8)(value ? 1 : 0); ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_BASE: ++ tnr_dmd->en_fef_intmtnt_base = (u8)(value ? 1 : 0); ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT2_FEF_INTERMITTENT_LITE: ++ tnr_dmd->en_fef_intmtnt_lite = (u8)(value ? 1 : 0); ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_EMPTY_THRS: ++ data[0] = (u8)((value >> 8) & 0x07); ++ data[1] = (u8)(value & 0xFF); ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x99, data[0], ++ 0x07); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x9A, data[1], ++ 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TS_BUF_ALMOST_FULL_THRS: ++ data[0] = (u8)((value >> 8) & 0x07); ++ data[1] = (u8)(value & 0xFF); ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x9B, data[0], ++ 0x07); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x9C, data[1], ++ 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_TS_BUF_RRDY_THRS: ++ data[0] = (u8)((value >> 8) & 0x07); ++ data[1] = (u8)(value & 0xFF); ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x9D, data[0], ++ 0x07); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x00, 0x9E, data[1], ++ 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_BLINDTUNE_DVBT2_FIRST: ++ tnr_dmd->blind_tune_dvbt2_first = (u8)(value ? 1 : 0); ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD: ++ if ((value < 0) || (value > 31)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x10, 0x60, ++ (u8)(value & 0x1F), ++ 0x1F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD: ++ if ((value < 0) || (value > 7)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x10, 0x6F, ++ (u8)(value & 0x07), ++ 0x07); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT2_BBER_MES: ++ if ((value < 0) || (value > 15)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x20, 0x72, ++ (u8)(value & 0x0F), ++ 0x0F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT2_LBER_MES: ++ if ((value < 0) || (value > 15)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x20, 0x6F, ++ (u8)(value & 0x0F), ++ 0x0F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT_PER_MES: ++ if ((value < 0) || (value > 15)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x10, 0x5C, ++ (u8)(value & 0x0F), ++ 0x0F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_DVBT2_PER_MES: ++ if ((value < 0) || (value > 15)) ++ return CXD2880_RESULT_ERROR_RANGE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x24, 0xDC, ++ (u8)(value & 0x0F), ++ 0x0F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ break; ++ ++ case CXD2880_TNRDMD_CFG_ISDBT_BERPER_PERIOD: ++ { ++ u8 data[2]; ++ ++ data[0] = (u8)((value & 0x00007F00) >> 8); ++ data[1] = (u8)(value & 0x000000FF); ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x60, 0x5B, ++ data[0], 0x7F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, ++ CXD2880_IO_TGT_DMD, ++ 0x60, 0x5C, ++ data[1], 0xFF); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ break; ++ ++ default: ++ return CXD2880_RESULT_ERROR_ARG; ++ } ++ ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (id > 2) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (mode > CXD2880_TNRDMD_GPIO_MODE_EEW) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, ++ 0x00, 0x40 + id, (u8)mode, ++ 0x0F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, ++ 0x00, 0x43, ++ (u8)(open_drain ? (1 << id) : ++ 0), (u8)(1 << id)); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, ++ 0x00, 0x44, ++ (u8)(invert ? (1 << id) : 0), ++ (u8)(1 << id)); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, ++ 0x00, 0x45, ++ (u8)(en ? 0 : (1 << id)), ++ (u8)(1 << id)); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_gpio_set_cfg(tnr_dmd->diver_sub, id, en, mode, ++ open_drain, invert); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 *value) ++{ ++ u8 data = 0; ++ ++ if ((!tnr_dmd) || (!value)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (id > 2) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x20, &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *value = (u8)((data >> id) & 0x01); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 *value) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_gpio_read(tnr_dmd->diver_sub, id, value); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 value) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (id > 2) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_set_and_save_reg_bits(tnr_dmd, CXD2880_IO_TGT_SYS, ++ 0x00, 0x46, ++ (u8)(value ? (1 << id) : 0), ++ (u8)(1 << id)); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 value) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_gpio_write(tnr_dmd->diver_sub, id, value); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd, ++ u16 *value) ++{ ++ u8 data[2] = { 0 }; ++ ++ if ((!tnr_dmd) || (!value)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x15, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *value = (u16)(((u16)data[0] << 8) | (data[1])); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd, ++ u16 value) ++{ ++ u8 data[2] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = (u8)((value >> 8) & 0xFF); ++ data[1] = (u8)(value & 0xFF); ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x3C, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 clear_overflow_flag, ++ u8 clear_underflow_flag, ++ u8 clear_buf) ++{ ++ u8 data[2] = { 0 }; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ data[0] = (u8)(clear_overflow_flag ? 0x02 : 0x00); ++ data[0] |= (u8)(clear_underflow_flag ? 0x01 : 0x00); ++ data[1] = (u8)(clear_buf ? 0x01 : 0x00); ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x9F, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_tnrdmd_chip_id *chip_id) ++{ ++ u8 data = 0; ++ ++ if ((!tnr_dmd) || (!chip_id)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0xFD, &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *chip_id = (enum cxd2880_tnrdmd_chip_id)data; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ tgt, 0x00, bank) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (cxd2880_io_set_reg_bits(tnr_dmd->io, tgt, address, value, bit_mask) ++ != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = set_cfg_mem(tnr_dmd, tgt, bank, address, value, bit_mask); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dtv_sys sys, ++ u8 scan_mode_end) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ CXD2880_ARG_UNUSED(sys); ++ ++ tnr_dmd->scan_mode = scan_mode_end; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ ret = ++ cxd2880_tnrdmd_set_scan_mode(tnr_dmd->diver_sub, sys, ++ scan_mode_end); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_tnrdmd_pid_ftr_cfg ++ *pid_ftr_cfg) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->create_param.ts_output_if == CXD2880_TNRDMD_TSOUT_IF_TS) ++ return CXD2880_RESULT_ERROR_NOSUPPORT; ++ ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_ret(*rf_lvl_cmpstn) ++ (struct cxd2880_tnrdmd *, ++ int *)) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ tnr_dmd->rf_lvl_cmpstn = rf_lvl_cmpstn; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_ret ++ (*rf_lvl_cmpstn)(struct ++ cxd2880_tnrdmd ++ *, ++ int *)) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_set_rf_lvl_cmpstn(tnr_dmd->diver_sub, rf_lvl_cmpstn); ++ ++ return ret; ++} ++ ++enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ tnr_dmd->lna_thrs_tbl_air = tbl_air; ++ tnr_dmd->lna_thrs_tbl_cable = tbl_cable; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_set_lna_thrs(tnr_dmd->diver_sub, tbl_air, tbl_cable); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 en, u8 value) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->create_param.ts_output_if != CXD2880_TNRDMD_TSOUT_IF_TS) ++ return CXD2880_RESULT_ERROR_NOSUPPORT; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (en) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x50, ++ ((value & 0x1F) | 0x80)) != ++ CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x52, ++ (value & 0x1F)) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } else { ++ ret = tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x50, 0x3F); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x52, ++ 0x1F) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = load_cfg_mem(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 en) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ switch (tnr_dmd->create_param.ts_output_if) { ++ case CXD2880_TNRDMD_TSOUT_IF_TS: ++ if (en) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x52, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xC3, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } else { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xC3, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x52, ++ 0x1F) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ break; ++ ++ case CXD2880_TNRDMD_TSOUT_IF_SPI: ++ break; ++ ++ case CXD2880_TNRDMD_TSOUT_IF_SDIO: ++ break; ++ ++ default: ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret slvt_freeze_reg(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ switch (tnr_dmd->create_param.ts_output_if) { ++ case CXD2880_TNRDMD_TSOUT_IF_SPI: ++ case CXD2880_TNRDMD_TSOUT_IF_SDIO: ++ { ++ u8 data = 0; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ break; ++ case CXD2880_TNRDMD_TSOUT_IF_TS: ++ default: ++ break; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x01, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 0000000000000000000000000000000000000000..26e29b3b9f6bdba32a181595e8298cda3325112c +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd.h +@@ -0,0 +1,395 @@ ++/* ++ * 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 . ++ */ ++ ++#ifndef CXD2880_TNRDMD_H ++#define CXD2880_TNRDMD_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, ++ CXD2880_TNRDMD_CFG_ISDBT_BERPER_PERIOD ++}; ++ ++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; ++ enum cxd2880_ret (*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; ++ struct cxd2880_atomic cancel; ++}; ++ ++enum cxd2880_ret cxd2880_tnrdmd_create(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_io *io, ++ struct cxd2880_tnrdmd_create_param ++ *create_param); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret cxd2880_tnrdmd_init1(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_init2(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_check_internal_cpu_status(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *task_completed); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret cxd2880_tnrdmd_common_tune_setting2(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dtv_sys sys, ++ u8 en_fef_intmtnt_ctrl); ++ ++enum cxd2880_ret cxd2880_tnrdmd_sleep(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_cfg(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_tnrdmd_cfg_id id, ++ int value); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_read(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 *value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_read_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 *value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_write(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_gpio_write_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 id, u8 value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_interrupt_read(struct cxd2880_tnrdmd *tnr_dmd, ++ u16 *value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_interrupt_clear(struct cxd2880_tnrdmd *tnr_dmd, ++ u16 value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_ts_buf_clear(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 clear_overflow_flag, ++ u8 clear_underflow_flag, ++ u8 clear_buf); ++ ++enum cxd2880_ret cxd2880_tnrdmd_chip_id(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_tnrdmd_chip_id *chip_id); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_scan_mode(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dtv_sys sys, ++ u8 scan_mode_end); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_pid_ftr(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_tnrdmd_pid_ftr_cfg ++ *pid_ftr_cfg); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_ret(*rf_lvl_cmpstn) ++ (struct cxd2880_tnrdmd *, ++ int *)); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_rf_lvl_cmpstn_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_ret ++ (*rf_lvl_cmpstn)(struct ++ cxd2880_tnrdmd ++ *, ++ int *)); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_ts_pin_high_low(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 en, u8 value); ++ ++enum cxd2880_ret cxd2880_tnrdmd_set_ts_output(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 en); ++ ++enum cxd2880_ret 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 0000000000000000000000000000000000000000..68fb3af04bd41719d407f333314635622cd982b0 +--- /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 . ++ */ ++ ++#define CXD2880_TNRDMD_DRIVER_VERSION "1.4.1 - 1.0.1" ++ ++#define CXD2880_TNRDMD_DRIVER_RELEASE_DATE "2017-04-13" +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 0000000000000000000000000000000000000000..f36cf533ec1795bf033531b0a347b60d917fe35f +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c +@@ -0,0 +1,1072 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd_dvbt.h" ++#include "cxd2880_tnrdmd_dvbt_mon.h" ++ ++static enum cxd2880_ret x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dtv_bandwidth ++ bandwidth, ++ enum cxd2880_tnrdmd_clockmode ++ clk_mode) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x31, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data_a[2] = { 0x52, 0x49 }; ++ u8 data_b[2] = { 0x5D, 0x55 }; ++ u8 data_c[2] = { 0x60, 0x00 }; ++ u8 *data = NULL; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x65, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x5D, ++ 0x07) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { ++ u8 data[2] = { 0x01, 0x01 }; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xCE, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x5C, ++ 0xFB) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xA4, ++ 0x03) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x14) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB0, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x25) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2] = { 0x01, 0xF0 }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xF0, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) || ++ (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x12) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x44, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x87, ++ 0xD2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x68, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, ++ data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x7D, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x71, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x51, ++ &data[2], ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[4] = { 0xB3, 0x00, 0x01, 0x02 }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x72, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6B, ++ &data[2], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, ++ data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x02) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x7D, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x71, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x51, ++ &data[2], ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[4] = { 0xB8, 0x00, 0x00, 0x03 }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x72, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6B, ++ &data[2], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, ++ data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x7D, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x71, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x51, ++ &data[2], ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[4] = { 0xBE, 0xAB, 0x00, 0x03 }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x72, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6B, ++ &data[2], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, ++ data, ++ 5) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x06) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x7D, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x71, ++ data) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x51, ++ &data[2], ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[4] = { 0xC8, 0x01, 0x00, 0x03 }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x72, ++ &data[0], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6B, ++ &data[2], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ break; ++ ++ default: ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xFD, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd ++ *tnr_dmd) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x5C, ++ 0xD8) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xA4, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x11) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x87, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dvbt_profile profile) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x67, ++ (profile == ++ CXD2880_DVBT_PROFILE_HP) ? 0x00 : 0x01) != ++ CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt_tune_param ++ *tune_param) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!tune_param)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT, ++ tune_param->center_freq_khz, ++ tune_param->bandwidth, 0, 0); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth, ++ tnr_dmd->clk_mode); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = dvbt_set_profile(tnr_dmd, tune_param->profile); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt_tune_param ++ *tune_param) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!tune_param)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT, ++ 0); ++ if (ret != CXD2880_RESULT_OK) ++ 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 CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd ++ *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = x_sleep_dvbt_demod_setting(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ u8 sync_stat = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ u8 unlock_detected_sub = 0; ++ ++ if ((!tnr_dmd) || (!lock)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ u8 sync_stat = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ u8 unlock_detected_sub = 0; ++ ++ if ((!tnr_dmd) || (!lock)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ 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 0000000000000000000000000000000000000000..de394d8e27f323a9ccfacbe3e56a3d6f40b6babe +--- /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 . ++ */ ++ ++#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; ++}; ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt_tune_param ++ *tune_param); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt_tune_param ++ *tune_param); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd ++ *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock); ++ ++#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 0000000000000000000000000000000000000000..bdad65b7298ab0ad131a6e6579e304fb279359a5 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2.c +@@ -0,0 +1,1309 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd_dvbt2.h" ++#include "cxd2880_tnrdmd_dvbt2_mon.h" ++ ++static enum cxd2880_ret x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dtv_bandwidth ++ bandwidth, ++ enum cxd2880_tnrdmd_clockmode ++ clk_mode) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x31, ++ 0x02) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x5D, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { ++ u8 data[2] = { 0x01, 0x01 }; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xCE, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[14] = { 0x07, 0x06, 0x01, 0xF0, ++ 0x00, 0x00, 0x04, 0xB0, 0x00, 0x00, 0x09, 0x9C, 0x0E, ++ 0x4C ++ }; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x20) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x8A, ++ data[0]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x90, ++ data[1]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x25) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xF0, &data[2], ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x2A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xDC, ++ data[4]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xDE, ++ data[5]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x2D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x73, &data[6], ++ 4) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x8F, &data[10], ++ 4) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1D, ++ &data_1[0], 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x22, ++ data_1[3]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x24, ++ data_1[4]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x26, ++ data_1[5]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x29, ++ &data_1[6], 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x2D, ++ data_1[8]) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) { ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x2E, ++ &data_2[0], ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x35, ++ &data_2[6], ++ 7) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x3C, ++ &data_3[0], 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x56, ++ &data_3[2], 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x19, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ data, ++ 9) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x02) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2] = { 0x3F, 0xFF }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x19, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ data, ++ 9) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2] = { 0x3F, 0xFF }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x19, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ data, ++ 9) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x06) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2] = { 0x3F, 0xFF }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x19, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ data, ++ 9) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ data, ++ 6) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4A, ++ 0x03) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2] = { 0x3F, 0xFF }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x19, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, ++ data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x4B, ++ data, ++ 9) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ break; ++ ++ default: ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xFD, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd ++ *tnr_dmd) ++{ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ u8 data[] = { 0, 1, 0, 2, ++ 0, 4, 0, 8, 0, 16, 0, 32 ++ }; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x1D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x47, data, ++ 12) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dvbt2_profile profile) ++{ ++ u8 t2_mode_tune_mode = 0; ++ u8 seq_not2_dtime = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x2E) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ t2_mode_tune_mode) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x2C, ++ seq_not2_dtime) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_tune_param ++ *tune_param) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!tune_param)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if ((tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) && ++ (tune_param->profile == CXD2880_DVBT2_PROFILE_ANY)) ++ return CXD2880_RESULT_ERROR_NOSUPPORT; ++ ++ ret = ++ cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2, ++ tune_param->center_freq_khz, ++ tune_param->bandwidth, 0, 0); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth, ++ tnr_dmd->clk_mode); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ ret = dvbt2_set_profile(tnr_dmd, tune_param->profile); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = ++ dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } else { ++ ret = ++ cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0, ++ (u8)(tune_param->data_plp_id)); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_tune_param ++ *tune_param) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!tune_param)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ 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 CXD2880_RESULT_ERROR_ARG; ++ } ++ ++ ret = ++ cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, ++ CXD2880_DTV_SYS_DVBT2, ++ en_fef_intmtnt_ctrl); ++ if (ret != CXD2880_RESULT_OK) ++ 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 CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd ++ *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = x_sleep_dvbt2_demod_setting(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) { ++ ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ u8 sync_stat = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ u8 unlock_detected_sub = 0; ++ ++ if ((!tnr_dmd) || (!lock)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ u8 sync_stat = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ u8 unlock_detected_sub = 0; ++ ++ if ((!tnr_dmd) || (!lock)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (unlock_detected && unlock_detected_sub) ++ *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED; ++ else ++ *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 auto_plp, ++ u8 plp_id) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x23) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (!auto_plp) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xAF, ++ plp_id) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xAD, ++ auto_plp ? 0x00 : 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd ++ *tnr_dmd) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) ++ return CXD2880_RESULT_OK; ++ ++ { ++ struct cxd2880_dvbt2_ofdm ofdm; ++ ++ ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (!ofdm.mixed) ++ return CXD2880_RESULT_OK; ++ } ++ ++ { ++ u8 data[] = { 0, 8, 0, 16, ++ 0, 32, 0, 64, 0, 128, 1, 0 ++ }; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x1D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x47, data, ++ 12) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *l1_post_valid) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ u8 data; ++ ++ if ((!tnr_dmd) || (!l1_post_valid)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *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 0000000000000000000000000000000000000000..8735280f0143ec5a7304dbeca39a510e346a0071 +--- /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 . ++ */ ++ ++#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 ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_tune_param ++ *tune_param); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_tune_param ++ *tune_param); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd ++ *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_lock_result ++ *lock); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 auto_plp, ++ u8 plp_id); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd ++ *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *l1_post_valid); ++ ++#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 0000000000000000000000000000000000000000..235db16f4a08faf05db3aea737251fa5f82f143e +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c +@@ -0,0 +1,2523 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd_mon.h" ++#include "cxd2880_tnrdmd_dvbt2.h" ++#include "cxd2880_tnrdmd_dvbt2_mon.h" ++#include "cxd2880_math.h" ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *sync_stat, ++ u8 *ts_lock_stat, ++ u8 *unlock_detected) ++{ ++ if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, &data, ++ sizeof(data)) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *sync_stat = data & 0x07; ++ *ts_lock_stat = ((data & 0x20) ? 1 : 0); ++ *unlock_detected = ((data & 0x10) ? 1 : 0); ++ } ++ ++ if (*sync_stat == 0x07) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *sync_stat, ++ u8 *unlock_detected) ++{ ++ u8 ts_lock_stat = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub, sync_stat, ++ &ts_lock_stat, unlock_detected); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *offset) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!offset)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[4]; ++ u32 ctl_val = 0; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (sync_state != 6) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x30, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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) * (u8)tnr_dmd->bandwidth / 940); ++ break; ++ default: ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *offset) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!offset)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub, offset); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_l1pre ++ *l1_pre) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!l1_pre)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[37]; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ u8 version = 0; ++ enum cxd2880_dvbt2_profile profile; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ 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 != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (sync_state < 5) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } else { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x61, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ 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 CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } 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 CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } else { ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ l1_pre->mixed = l1_pre->s2 & 0x01; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_version ++ *ver) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u8 version = 0; ++ ++ if ((!tnr_dmd) || (!ver)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[2]; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (sync_state < 5) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } else { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x80, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ version = ((data[0] & 0x03) << 2); ++ version |= ((data[1] & 0xC0) >> 6); ++ *ver = (enum cxd2880_dvbt2_version)version; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_ofdm *ofdm) ++{ ++ if ((!tnr_dmd) || (!ofdm)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[5]; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (sync_state != 6) { ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ ret = CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->diver_mode == ++ CXD2880_TNRDMD_DIVERMODE_MAIN) ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_ofdm( ++ tnr_dmd->diver_sub, ofdm); ++ ++ return ret; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1D, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *plp_ids, ++ u8 *num_plps) ++{ ++ if ((!tnr_dmd) || (!num_plps)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 l1_post_ok = 0; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, ++ &l1_post_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(l1_post_ok & 0x01)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xC1, num_plps, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (*num_plps == 0) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_OTHER; ++ } ++ ++ if (!plp_ids) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_OK; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xC2, plp_ids, ++ ((*num_plps > ++ 62) ? 62 : *num_plps)) != ++ CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (*num_plps > 62) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0C) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ plp_ids + 62, ++ *num_plps - 62) != ++ CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ } ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[20]; ++ u8 addr = 0; ++ u8 index = 0; ++ u8 l1_post_ok = 0; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, ++ &l1_post_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!l1_post_ok) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) ++ addr = 0xA9; ++ else ++ addr = 0x96; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, addr, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ if ((type == CXD2880_DVBT2_PLP_COMMON) && (data[13] == 0)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ 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 = (u16)((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 = ++ (u8)((plp_info->rsvd & 0x8000) >> 15); ++ plp_info->plp_mode = ++ (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000C) >> ++ 2); ++ plp_info->static_flag = (u8)((plp_info->rsvd & 0x0002) >> 1); ++ plp_info->static_padding_flag = (u8)(plp_info->rsvd & 0x0001); ++ plp_info->rsvd = (u16)((plp_info->rsvd & 0x7FF0) >> 4); ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *plp_error) ++{ ++ if ((!tnr_dmd) || (!plp_error)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if ((data & 0x01) == 0x00) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xC0, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *plp_error = data & 0x01; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *l1_change) ++{ ++ if ((!tnr_dmd) || (!l1_change)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (sync_state < 5) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } else { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x5F, &data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ *l1_change = data & 0x01; ++ if (*l1_change) { ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x22) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x16, ++ 0x01) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ } ++ slvt_unfreeze_reg(tnr_dmd); ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ struct cxd2880_dvbt2_l1post ++ *l1_post) ++{ ++ if ((!tnr_dmd) || (!l1_post)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[16]; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, data, ++ sizeof(data)) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (!(data[0] & 0x01)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ 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 CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_plp_btype ++ type, ++ struct cxd2880_dvbt2_bbheader ++ *bbheader) ++{ ++ if ((!tnr_dmd) || (!bbheader)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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 != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (!ts_lock) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) { ++ u8 l1_post_ok; ++ u8 data; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, ++ &l1_post_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(l1_post_ok & 0x01)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB6, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (data == 0) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ { ++ u8 data[14]; ++ u8 addr = 0; ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) ++ addr = 0x51; ++ else ++ addr = 0x42; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, addr, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ bbheader->stream_input = ++ (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03); ++ bbheader->is_single_input_stream = (u8)((data[0] >> 5) & 0x01); ++ bbheader->is_constant_coding_modulation = ++ (u8)((data[0] >> 4) & 0x01); ++ bbheader->issy_indicator = (u8)((data[0] >> 3) & 0x01); ++ bbheader->null_packet_deletion = (u8)((data[0] >> 2) & 0x01); ++ bbheader->ext = (u8)(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 = (u16)((data[4] << 8) | data[5]); ++ ++ if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) { ++ bbheader->user_packet_length = ++ (u16)((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 = ++ (u32)((data[11] << 16) | (data[12] << 8) | ++ data[13]); ++ } ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_dvbt2_plp_btype ++ type, ++ u32 *ts_rate_bps) ++{ ++ if ((!tnr_dmd) || (!ts_rate_bps)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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 != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (!ts_lock) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 l1_post_ok = 0; ++ u8 addr = 0; ++ u8 data = 0; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, ++ &l1_post_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(l1_post_ok & 0x01)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) ++ addr = 0xBA; ++ else ++ addr = 0xA7; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, addr, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if ((data & 0x80) == 0x00) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x25) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[4]; ++ u8 addr = 0; ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) ++ addr = 0xA6; ++ else ++ addr = 0xAA; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, addr, &data[0], ++ 4) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ *ts_rate_bps = ++ (u32)(((data[0] & 0x07) << 24) | (data[1] << 16) | ++ (data[2] << 8) | data[3]); ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_spectrum_sense ++ *sense) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 early_unlock = 0; ++ ++ if ((!tnr_dmd) || (!sense)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock, ++ &early_unlock); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (sync_state != 6) { ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ ret = CXD2880_RESULT_ERROR_HW_STATE; ++ ++ 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; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x2F, &data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *sense = ++ (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV : ++ CXD2880_TNRDMD_SPECTRUM_NORMAL; ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, ++ u16 *reg_value) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!reg_value)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ { ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ u8 data[2]; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (sync_state != 6) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x13, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *reg_value = (data[0] << 8) | data[1]; ++ } ++ ++ return ret; ++} ++ ++static enum cxd2880_ret dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, ++ u32 reg_value, int *snr) ++{ ++ if ((!tnr_dmd) || (!snr)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (reg_value == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (reg_value > 10876) ++ reg_value = 10876; ++ ++ *snr = ++ 10 * 10 * ((int)cxd2880_math_log10(reg_value) - ++ (int)cxd2880_math_log10(12600 - reg_value)); ++ *snr += 32000; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, ++ int *snr) ++{ ++ u16 reg_value = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!snr)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ *snr = -1000 * 1000; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { ++ ret = dvbt2_read_snr_reg(tnr_dmd, ®_value); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret 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; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ *snr = -1000 * 1000; ++ *snr_main = -1000 * 1000; ++ *snr_sub = -1000 * 1000; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = dvbt2_read_snr_reg(tnr_dmd, ®_value); ++ if (ret == CXD2880_RESULT_OK) { ++ ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main); ++ if (ret != CXD2880_RESULT_OK) ++ reg_value = 0; ++ } else if (ret == CXD2880_RESULT_ERROR_HW_STATE) { ++ reg_value = 0; ++ } else { ++ return ret; ++ } ++ ++ reg_value_sum += reg_value; ++ ++ ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, ®_value); ++ if (ret == CXD2880_RESULT_OK) { ++ ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub); ++ if (ret != CXD2880_RESULT_OK) ++ reg_value = 0; ++ } else if (ret == CXD2880_RESULT_ERROR_HW_STATE) { ++ reg_value = 0; ++ } else { ++ return ret; ++ } ++ ++ reg_value_sum += reg_value; ++ ++ ret = dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u32 bit_error = 0; ++ u32 period_exp = 0; ++ u32 n_ldpc = 0; ++ ++ if ((!tnr_dmd) || (!ber)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ { ++ u8 data[5]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x3C, data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(data[0] & 0x01)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ bit_error = ++ ((data[1] & 0x0F) << 24) | (data[2] << 16) | (data[3] << 8) ++ | data[4]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xA0, data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x20) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6F, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period_exp = data[0] & 0x0F; ++ } ++ ++ if (bit_error > ((1U << period_exp) * n_ldpc)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *fer) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u32 fec_error = 0; ++ u32 period = 0; ++ ++ if ((!tnr_dmd) || (!fer)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (!(data[0] & 0x80)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ fec_error = ((data[0] & 0x7F) << 8) | (data[1]); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x20) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x72, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period = (1 << (data[0] & 0x0F)); ++ } ++ ++ if ((period == 0) || (fec_error > period)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u32 bit_error = 0; ++ u32 period_exp = 0; ++ u32 n_bch = 0; ++ ++ if ((!tnr_dmd) || (!ber)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ 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} ++ }; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x15, data, ++ 3) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(data[0] & 0x40)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ bit_error = ((data[0] & 0x3F) << 16) | (data[1] << 8) | data[2]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x9D, data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ plp_cr = (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07); ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xA0, data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03); ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x20) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x72, data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period_exp = data[0] & 0x0F; ++ ++ if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) || ++ (plp_cr > CXD2880_DVBT2_R2_5)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ n_bch = n_bch_bits_lookup[plp_fec_type][plp_cr]; ++ } ++ ++ if (bit_error > ((1U << period_exp) * n_bch)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ u32 *pen) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ u8 data[3]; ++ ++ if ((!tnr_dmd) || (!pen)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x39, data, ++ sizeof(data)) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (!(data[0] & 0x01)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ *pen = ((data[1] << 8) | data[2]); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *ppm) ++{ ++ if ((!tnr_dmd) || (!ppm)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 ctl_val_reg[5]; ++ u8 nominal_rate_reg[5]; ++ u32 trl_ctl_val = 0; ++ u32 trcg_nominal_rate = 0; ++ int num; ++ int den; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ s8 diff_upper = 0; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (sync_state != 6) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x34, ++ ctl_val_reg, ++ sizeof(ctl_val_reg)) != ++ CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ nominal_rate_reg, ++ sizeof(nominal_rate_reg)) != ++ CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_HW_STATE; ++ ++ 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 CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *ppm) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ppm)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub, ppm); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *quality) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_tnrdmd_dvbt2_mon_pre_bchber(tnr_dmd, &ber); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = cxd2880_tnrdmd_dvbt2_mon_snr(tnr_dmd, &snr); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA, ++ &code_rate); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256)) ++ return CXD2880_RESULT_ERROR_OTHER; ++ ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ts_rate_kbps) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 data[12]; ++ u8 sync_state = 0; ++ u8 ts_lock = 0; ++ u8 unlock_detected = 0; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, ++ &ts_lock, ++ &unlock_detected); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!ts_lock) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x23, data, ++ 12) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ rd_smooth_dp = (u32)((data[0] & 0x1F) << 24); ++ rd_smooth_dp |= (u32)(data[1] << 16); ++ rd_smooth_dp |= (u32)(data[2] << 8); ++ rd_smooth_dp |= (u32)data[3]; ++ ++ if (rd_smooth_dp < 214958) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ ep_ck_nume = (u32)((data[4] & 0x3F) << 24); ++ ep_ck_nume |= (u32)(data[5] << 16); ++ ep_ck_nume |= (u32)(data[6] << 8); ++ ep_ck_nume |= (u32)data[7]; ++ ++ ep_ck_deno = (u32)((data[8] & 0x3F) << 24); ++ ep_ck_deno |= (u32)(data[9] << 16); ++ ep_ck_deno |= (u32)(data[10] << 8); ++ ep_ck_deno |= (u32)data[11]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x41, data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ { ++ 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 CXD2880_RESULT_ERROR_SW_STATE; ++ } ++ ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd, ++ u32 *per) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ u32 packet_error = 0; ++ u32 period = 0; ++ ++ if (!tnr_dmd || !per) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 rdata[3]; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x18, rdata, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((rdata[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ packet_error = (rdata[1] << 8) | rdata[2]; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x24) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xDC, rdata, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period = 1U << (rdata[0] & 0x0F); ++ } ++ ++ if ((period == 0) || (packet_error > period)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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; ++} ++ ++enum cxd2880_ret 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; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!qam)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, &l1_post_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(l1_post_ok & 0x01)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) { ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB6, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (data == 0) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB1, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ } else { ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x9E, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07); ++ ++ return ret; ++} ++ ++enum cxd2880_ret 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; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!code_rate)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x86, &l1_post_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(l1_post_ok & 0x01)) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (type == CXD2880_DVBT2_PLP_COMMON) { ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB6, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (data == 0) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xB0, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ } else { ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x9D, &data, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_profile ++ *profile) ++{ ++ if ((!tnr_dmd) || (!profile)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x22, &data, ++ sizeof(data)) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (data & 0x02) { ++ if (data & 0x01) ++ *profile = CXD2880_DVBT2_PROFILE_LITE; ++ else ++ *profile = CXD2880_DVBT2_PROFILE_BASE; ++ } else { ++ enum cxd2880_ret ret = CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (tnr_dmd->diver_mode == ++ CXD2880_TNRDMD_DIVERMODE_MAIN) ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_profile( ++ tnr_dmd->diver_sub, profile); ++ ++ return ret; ++ } ++ } ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret dvbt2_calc_sdi(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; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA, ++ &code_rate); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if ((code_rate > CXD2880_DVBT2_R2_5) || (qam > CXD2880_DVBT2_QAM256)) ++ return CXD2880_RESULT_ERROR_OTHER; ++ ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *ssi) ++{ ++ int rf_lvl = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ssi)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt2_calc_sdi(tnr_dmd, rf_lvl, ssi); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *ssi) ++{ ++ int rf_lvl = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ssi)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt2_calc_sdi(tnr_dmd, rf_lvl, ssi); ++ if (ret != CXD2880_RESULT_OK) ++ 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 0000000000000000000000000000000000000000..784ad2844d1b06af8594c25f1f6f6b67ded9dc71 +--- /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 . ++ */ ++ ++#ifndef CXD2880_TNRDMD_DVBT2_MON_H ++#define CXD2880_TNRDMD_DVBT2_MON_H ++ ++#include "cxd2880_tnrdmd.h" ++#include "cxd2880_dvbt2.h" ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *sync_stat, ++ u8 *ts_lock_stat, ++ u8 *unlock_detected); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *sync_stat, ++ u8 *unlock_detected); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *offset); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *offset); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_l1pre ++ *l1_pre); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_version ++ *ver); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd, ++ struct cxd2880_dvbt2_ofdm *ofdm); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *plp_ids, ++ u8 *num_plps); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_dvbt2_plp_btype ++ type, ++ struct cxd2880_dvbt2_plp ++ *plp_info); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ u8 *plp_error); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *l1_change); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ struct cxd2880_dvbt2_l1post ++ *l1_post); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_plp_btype ++ type, ++ struct cxd2880_dvbt2_bbheader ++ *bbheader); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_dvbt2_plp_btype ++ type, ++ u32 *ts_rate_bps); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_spectrum_sense ++ *sense); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, ++ int *snr); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd ++ *tnr_dmd, int *snr, ++ int *snr_main, ++ int *snr_sub); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_ldpcber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_post_bchfer(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *fer); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_pre_bchber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ u32 *pen); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *ppm); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *ppm); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ts_rate(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ts_rate_kbps); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_quality(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *quality); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_per(struct cxd2880_tnrdmd *tnr_dmd, ++ u32 *per); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd, ++ enum cxd2880_dvbt2_plp_btype type, ++ enum cxd2880_dvbt2_plp_constell ++ *qam); ++ ++enum cxd2880_ret 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); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt2_profile ++ *profile); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *ssi); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *ssi); ++ ++#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 0000000000000000000000000000000000000000..d890081b6424b51ddce4fc770a8ed94af14e153e +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c +@@ -0,0 +1,1190 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_tnrdmd_mon.h" ++#include "cxd2880_tnrdmd_dvbt.h" ++#include "cxd2880_tnrdmd_dvbt_mon.h" ++#include "cxd2880_math.h" ++ ++static enum cxd2880_ret is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *sync_stat, ++ u8 *ts_lock_stat, ++ u8 *unlock_detected) ++{ ++ u8 rdata = 0x00; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!sync_stat) || (!ts_lock_stat) || (!unlock_detected)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, &rdata, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *unlock_detected = (u8)((rdata & 0x10) ? 1 : 0); ++ *sync_stat = (u8)(rdata & 0x07); ++ *ts_lock_stat = (u8)((rdata & 0x20) ? 1 : 0); ++ ++ if (*sync_stat == 0x07) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *sync_stat, ++ u8 *unlock_detected) ++{ ++ u8 ts_lock_stat = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!sync_stat) || (!unlock_detected)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub, sync_stat, ++ &ts_lock_stat, unlock_detected); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt_mode ++ *mode, ++ enum cxd2880_dvbt_guard ++ *guard) ++{ ++ u8 rdata = 0x00; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!mode) || (!guard)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = is_tps_locked(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) { ++ 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; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1B, &rdata, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03); ++ *guard = (enum cxd2880_dvbt_guard)(rdata & 0x03); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *offset) ++{ ++ u8 rdata[4]; ++ u32 ctl_val = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!offset)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = is_tps_locked(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1D, rdata, ++ 4) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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) * (u8)tnr_dmd->bandwidth / 235); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *offset) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!offset)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub, offset); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber) ++{ ++ u8 rdata[2]; ++ u32 bit_error = 0; ++ u32 period = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ber)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x39, rdata, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if ((rdata[0] & 0x01) == 0) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x22, rdata, ++ 2) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ bit_error = (rdata[0] << 8) | rdata[1]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x6F, rdata, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ period = ((rdata[0] & 0x07) == 0) ? 256 : (0x1000 << (rdata[0] & 0x07)); ++ ++ if ((period == 0) || (bit_error > period)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber) ++{ ++ u8 rdata[3]; ++ u32 bit_error = 0; ++ u32 period_exp = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ber)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x15, rdata, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((rdata[0] & 0x40) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ bit_error = ((rdata[0] & 0x3F) << 16) | (rdata[1] << 8) | rdata[2]; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, rdata, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period_exp = (rdata[0] & 0x1F); ++ ++ if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ struct cxd2880_dvbt_tpsinfo ++ *info) ++{ ++ u8 rdata[7]; ++ u8 cell_id_ok = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!info)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = is_tps_locked(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) { ++ 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; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x29, rdata, ++ 7) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x11) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0xD5, &cell_id_ok, ++ 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 = (u16)((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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ u32 *pen) ++{ ++ u8 rdata[3]; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!pen)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x26, rdata, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (!(rdata[0] & 0x01)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ *pen = (rdata[1] << 8) | rdata[2]; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_spectrum_sense ++ *sense) ++{ ++ u8 data = 0; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!sense)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = is_tps_locked(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) { ++ 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; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x1C, &data, ++ sizeof(data)) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *sense = ++ (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV : ++ CXD2880_TNRDMD_SPECTRUM_NORMAL; ++ ++ return ret; ++} ++ ++static enum cxd2880_ret dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd, ++ u16 *reg_value) ++{ ++ u8 rdata[2]; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!reg_value)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = is_tps_locked(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x13, rdata, ++ 2) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnr_dmd); ++ ++ *reg_value = (rdata[0] << 8) | rdata[1]; ++ ++ return ret; ++} ++ ++static enum cxd2880_ret dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd, ++ u32 reg_value, int *snr) ++{ ++ if ((!tnr_dmd) || (!snr)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (reg_value == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (reg_value > 4996) ++ reg_value = 4996; ++ ++ *snr = ++ 10 * 10 * ((int)cxd2880_math_log10(reg_value) - ++ (int)cxd2880_math_log10(5350 - reg_value)); ++ *snr += 28500; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, ++ int *snr) ++{ ++ u16 reg_value = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!snr)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ *snr = -1000 * 1000; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) { ++ ret = dvbt_read_snr_reg(tnr_dmd, ®_value); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt_calc_snr(tnr_dmd, reg_value, snr); ++ if (ret != CXD2880_RESULT_OK) ++ 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 != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret 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; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!snr) || (!snr_main) || (!snr_sub)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ *snr = -1000 * 1000; ++ *snr_main = -1000 * 1000; ++ *snr_sub = -1000 * 1000; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = dvbt_read_snr_reg(tnr_dmd, ®_value); ++ if (ret == CXD2880_RESULT_OK) { ++ ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main); ++ if (ret != CXD2880_RESULT_OK) ++ reg_value = 0; ++ } else if (ret == CXD2880_RESULT_ERROR_HW_STATE) { ++ reg_value = 0; ++ } else { ++ return ret; ++ } ++ ++ reg_value_sum += reg_value; ++ ++ ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, ®_value); ++ if (ret == CXD2880_RESULT_OK) { ++ ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub); ++ if (ret != CXD2880_RESULT_OK) ++ reg_value = 0; ++ } else if (ret == CXD2880_RESULT_ERROR_HW_STATE) { ++ reg_value = 0; ++ } else { ++ return ret; ++ } ++ ++ reg_value_sum += reg_value; ++ ++ ret = dvbt_calc_snr(tnr_dmd, reg_value_sum, snr); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *ppm) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ppm)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ 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; ++ ++ if (slvt_freeze_reg(tnr_dmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ ret = is_tps_locked(tnr_dmd); ++ if (ret != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return ret; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x21, ++ ctl_val_reg, ++ sizeof(ctl_val_reg)) != ++ CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x04) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x60, ++ nominal_rate_reg, ++ sizeof(nominal_rate_reg)) != ++ CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnr_dmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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 CXD2880_RESULT_ERROR_HW_STATE; ++ ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, int *ppm) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ppm)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm); ++ ++ return ret; ++} ++ ++enum cxd2880_ret 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} ++ } ++ }; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!quality)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) { ++ u8 data = 0; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x67, &data, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ profile = ++ ((data & 0x01) == ++ 0x01) ? CXD2880_DVBT_PROFILE_LP : CXD2880_DVBT_PROFILE_HP; ++ } ++ ++ ret = cxd2880_tnrdmd_dvbt_mon_pre_rsber(tnr_dmd, &ber); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = cxd2880_tnrdmd_dvbt_mon_snr(tnr_dmd, &sn); ++ if (ret != CXD2880_RESULT_OK) ++ 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 CXD2880_RESULT_ERROR_OTHER; ++ } ++ ++ if ((tps.hierarchy != CXD2880_DVBT_HIERARCHY_NON) && ++ (tps.constellation == CXD2880_DVBT_CONSTELLATION_QPSK)) ++ return CXD2880_RESULT_ERROR_OTHER; ++ ++ 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[(int)tps.hierarchy - ++ 1][(int)tps.constellation - ++ 1][tps.rate_lp]; ++ else ++ sn_rel = ++ sn - nordig_hier_hp_dvbt_db_1000[(int)tps.hierarchy - ++ 1][(int)tps.constellation - ++ 1][tps.rate_hp]; ++ ++ if (ber > 10000) { ++ ber_sqi = 0; ++ } else if (ber > 1) { ++ ber_sqi = (int)(10 * cxd2880_math_log10(ber)); ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd, ++ u32 *per) ++{ ++ u32 packet_error = 0; ++ u32 period = 0; ++ u8 rdata[3]; ++ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!per)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x18, rdata, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((rdata[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ packet_error = (rdata[1] << 8) | rdata[2]; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x5C, rdata, ++ 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period = 1U << (rdata[0] & 0x0F); ++ ++ if ((period == 0) || (packet_error > period)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ { ++ 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 enum cxd2880_ret dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd, ++ int rf_lvl, u8 *ssi) ++{ ++ struct cxd2880_dvbt_tpsinfo tps; ++ int prel; ++ int temp_ssi = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ 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 CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if ((tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3) || ++ (tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5)) ++ return CXD2880_RESULT_ERROR_OTHER; ++ ++ 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; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *ssi) ++{ ++ int rf_lvl = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ssi)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *ssi) ++{ ++ int rf_lvl = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!ssi)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ ret = dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ return ret; ++} ++ ++static enum cxd2880_ret is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd) ++{ ++ u8 sync = 0; ++ u8 tslock = 0; ++ u8 early_unlock = 0; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if (!tnr_dmd) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock, ++ &early_unlock); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ ++ if (sync != 6) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ return CXD2880_RESULT_OK; ++} +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 0000000000000000000000000000000000000000..486fc466272e762cd0f647296e2d818c8b28702c +--- /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 . ++ */ ++ ++#ifndef CXD2880_TNRDMD_DVBT_MON_H ++#define CXD2880_TNRDMD_DVBT_MON_H ++ ++#include "cxd2880_tnrdmd.h" ++#include "cxd2880_dvbt.h" ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *sync_stat, ++ u8 *ts_lock_stat, ++ u8 *unlock_detected); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd ++ *tnr_dmd, u8 *sync_stat, ++ u8 *unlock_detected); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum cxd2880_dvbt_mode ++ *mode, ++ enum cxd2880_dvbt_guard ++ *guard); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *offset); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *offset); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_viterbiber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_pre_rsber(struct cxd2880_tnrdmd ++ *tnr_dmd, u32 *ber); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ struct cxd2880_dvbt_tpsinfo ++ *info); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ u32 *pen); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd ++ *tnr_dmd, ++ enum ++ cxd2880_tnrdmd_spectrum_sense ++ *sense); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd, ++ int *snr); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd ++ *tnr_dmd, int *snr, ++ int *snr_main, int *snr_sub); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd ++ *tnr_dmd, int *ppm); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ int *ppm); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_quality(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *quality); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_per(struct cxd2880_tnrdmd *tnr_dmd, ++ u32 *per); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *ssi); ++ ++enum cxd2880_ret cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ u8 *ssi); ++ ++#endif +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 0000000000000000000000000000000000000000..0ac5b9bf3be803d5ea99c1aca67052142cfabff1 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_mon.c +@@ -0,0 +1,207 @@ ++/* ++ * 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 . ++ */ ++ ++#include "cxd2880_common.h" ++#include "cxd2880_tnrdmd_mon.h" ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd, ++ int *rf_lvl_db) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!rf_lvl_db)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x01) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2] = { 0x80, 0x00 }; ++ ++ if (tnr_dmd->io->write_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x5B, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ CXD2880_SLEEP_IN_MON(2, tnr_dmd); ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x1A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ { ++ u8 data[2]; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x15, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((data[0] != 0) || (data[1] != 0)) ++ return CXD2880_RESULT_ERROR_OTHER; ++ ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x11, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *rf_lvl_db = ++ cxd2880_convert2s_complement((data[0] << 3) | ++ ((data[1] & 0xE0) >> 5), 11); ++ } ++ ++ *rf_lvl_db *= 125; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x10, ++ 0x00) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnr_dmd->rf_lvl_cmpstn) { ++ ret = tnr_dmd->rf_lvl_cmpstn(tnr_dmd, rf_lvl_db); ++ if (ret != CXD2880_RESULT_OK) ++ return ret; ++ } ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ int *rf_lvl_db) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!rf_lvl_db)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, rf_lvl_db); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd ++ *tnr_dmd, u16 *status) ++{ ++ u8 data[2] = { 0 }; ++ ++ if ((!tnr_dmd) || (!status)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x00, ++ 0x1A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_SYS, 0x15, data, ++ 2) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *status = (u16)(((u16)data[0] << 8) | data[1]); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ u16 *status) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!status)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ ret = ++ cxd2880_tnrdmd_mon_internal_cpu_status(tnr_dmd->diver_sub, status); ++ ++ return ret; ++} ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd, ++ struct ++ cxd2880_tnrdmd_ts_buf_info ++ *info) ++{ ++ u8 data[3] = { 0 }; ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ ++ if ((!tnr_dmd) || (!info)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if ((tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP) && ++ (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnr_dmd->io->write_reg(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x00, ++ 0x0A) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ if (tnr_dmd->io->read_regs(tnr_dmd->io, ++ CXD2880_IO_TGT_DMD, 0x50, data, ++ 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ info->read_ready = (u8)((data[0] & 0x10) ? 0x01 : 0x00); ++ info->almost_full = (u8)((data[0] & 0x08) ? 0x01 : 0x00); ++ info->almost_empty = (u8)((data[0] & 0x04) ? 0x01 : 0x00); ++ info->overflow = (u8)((data[0] & 0x02) ? 0x01 : 0x00); ++ info->underflow = (u8)((data[0] & 0x01) ? 0x01 : 0x00); ++ ++ info->packet_num = (u16)(((u32)(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 0000000000000000000000000000000000000000..506bd559668ff39fb9ca14a3a423569df3239ad1 +--- /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 . ++ */ ++ ++#ifndef CXD2880_TNRDMD_MON_H ++#define CXD2880_TNRDMD_MON_H ++ ++#include "cxd2880_common.h" ++#include "cxd2880_tnrdmd.h" ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl(struct cxd2880_tnrdmd *tnr_dmd, ++ int *rf_lvl_db); ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_rf_lvl_sub(struct cxd2880_tnrdmd *tnr_dmd, ++ int *rf_lvl_db); ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status(struct cxd2880_tnrdmd ++ *tnr_dmd, u16 *status); ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_internal_cpu_status_sub(struct ++ cxd2880_tnrdmd ++ *tnr_dmd, ++ u16 *status); ++ ++enum cxd2880_ret cxd2880_tnrdmd_mon_ts_buf_info(struct cxd2880_tnrdmd *tnr_dmd, ++ struct ++ cxd2880_tnrdmd_ts_buf_info ++ *info); ++ ++#endif +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 0000000000000000000000000000000000000000..66d78fb93a13264f60f6e34904704644133ffd59 +--- /dev/null ++++ b/drivers/media/dvb-frontends/cxd2880/cxd2880_top.c +@@ -0,0 +1,1550 @@ ++/* ++ * 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 . ++ */ ++ ++#include ++ ++#include "dvb_frontend.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 */ ++}; ++ ++/* ++ * return value conversion table ++ */ ++static int return_tbl[] = { ++ 0, /* CXD2880_RESULT_OK */ ++ -EINVAL, /* CXD2880_RESULT_ERROR_ARG*/ ++ -EIO, /* CXD2880_RESULT_ERROR_IO */ ++ -EPERM, /* CXD2880_RESULT_ERROR_SW_STATE */ ++ -EBUSY, /* CXD2880_RESULT_ERROR_HW_STATE */ ++ -ETIME, /* CXD2880_RESULT_ERROR_TIMEOUT */ ++ -EAGAIN, /* CXD2880_RESULT_ERROR_UNLOCK */ ++ -ERANGE, /* CXD2880_RESULT_ERROR_RANGE */ ++ -EOPNOTSUPP, /* CXD2880_RESULT_ERROR_NOSUPPORT */ ++ -ECANCELED, /* CXD2880_RESULT_ERROR_CANCEL */ ++ -EPERM, /* CXD2880_RESULT_ERROR_OTHER */ ++ -EOVERFLOW, /* CXD2880_RESULT_ERROR_OVERFLOW */ ++ 0, /* CXD2880_RESULT_OK_CONFIRM */ ++}; ++ ++static enum cxd2880_ret cxd2880_pre_bit_err_t( ++ struct cxd2880_tnrdmd *tnrdmd, u32 *pre_bit_err, ++ u32 *pre_bit_count) ++{ ++ u8 rdata[2]; ++ ++ if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnrdmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x10) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x39, rdata, 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if ((rdata[0] & 0x01) == 0) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x22, rdata, 2) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ *pre_bit_err = (rdata[0] << 8) | rdata[1]; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x6F, rdata, 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ slvt_unfreeze_reg(tnrdmd); ++ ++ *pre_bit_count = ((rdata[0] & 0x07) == 0) ? ++ 256 : (0x1000 << (rdata[0] & 0x07)); ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret 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]; ++ ++ if ((!tnrdmd) || (!pre_bit_err) || (!pre_bit_count)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (slvt_freeze_reg(tnrdmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x3C, data, sizeof(data)) ++ != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(data[0] & 0x01)) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ *pre_bit_err = ++ ((data[1] & 0x0F) << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0xA0, data, 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ 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); ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x20) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x6F, data, 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period_exp = data[0] & 0x0F; ++ ++ *pre_bit_count = (1U << period_exp) * n_ldpc; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret 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; ++ ++ if ((!tnrdmd) || (!post_bit_err) || (!post_bit_count)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x0D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x15, rdata, 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((rdata[0] & 0x40) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ *post_bit_err = ((rdata[0] & 0x3F) << 16) | (rdata[1] << 8) | rdata[2]; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x60, rdata, 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period_exp = (rdata[0] & 0x1F); ++ ++ if ((period_exp <= 11) && (bit_error > (1U << period_exp) * 204 * 8)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ if (period_exp == 11) ++ *post_bit_count = 3342336; ++ else ++ *post_bit_count = (1U << period_exp) * 204 * 81; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret 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 CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ 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} ++ }; ++ ++ if (slvt_freeze_reg(tnrdmd) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x0B) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x15, data, 3) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ if (!(data[0] & 0x40)) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ } ++ ++ *post_bit_err = ++ ((data[0] & 0x3F) << 16) | (data[1] << 8) | data[2]; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x9D, data, 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ plp_code_rate = ++ (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07); ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0xA0, data, 1) != CXD2880_RESULT_OK) { ++ slvt_unfreeze_reg(tnrdmd); ++ return CXD2880_RESULT_ERROR_IO; ++ } ++ ++ plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03); ++ ++ slvt_unfreeze_reg(tnrdmd); ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x20) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x72, data, 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ period_exp = data[0] & 0x0F; ++ ++ if ((plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K) || ++ (plp_code_rate > CXD2880_DVBT2_R2_5)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate]; ++ } ++ ++ if (*post_bit_err > ((1U << period_exp) * n_bch)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ *post_bit_count = (1U << period_exp) * n_bch; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret cxd2880_read_block_err_t( ++ struct cxd2880_tnrdmd *tnrdmd, ++ u32 *block_err, ++ u32 *block_count) ++{ ++ u8 rdata[3]; ++ ++ if ((!tnrdmd) || (!block_err) || (!block_count)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x0D) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x18, rdata, 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((rdata[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ *block_err = (rdata[1] << 8) | rdata[2]; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x10) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x5C, rdata, 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *block_count = 1U << (rdata[0] & 0x0F); ++ ++ if ((*block_count == 0) || (*block_err > *block_count)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static enum cxd2880_ret cxd2880_read_block_err_t2( ++ struct cxd2880_tnrdmd *tnrdmd, ++ u32 *block_err, ++ u32 *block_count) ++{ ++ if ((!tnrdmd) || (!block_err) || (!block_count)) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) ++ return CXD2880_RESULT_ERROR_ARG; ++ ++ if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) ++ return CXD2880_RESULT_ERROR_SW_STATE; ++ ++ { ++ u8 rdata[3]; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x0B) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x18, rdata, 3) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if ((rdata[0] & 0x01) == 0) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ *block_err = (rdata[1] << 8) | rdata[2]; ++ ++ if (tnrdmd->io->write_reg(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0x00, 0x24) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ if (tnrdmd->io->read_regs(tnrdmd->io, CXD2880_IO_TGT_DMD, ++ 0xDC, rdata, 1) != CXD2880_RESULT_OK) ++ return CXD2880_RESULT_ERROR_IO; ++ ++ *block_count = 1U << (rdata[0] & 0x0F); ++ } ++ ++ if ((*block_count == 0) || (*block_err > *block_count)) ++ return CXD2880_RESULT_ERROR_HW_STATE; ++ ++ return CXD2880_RESULT_OK; ++} ++ ++static void cxd2880_release(struct dvb_frontend *fe) ++{ ++ struct cxd2880_priv *priv = NULL; ++ ++ if (!fe) { ++ pr_err("%s: invalid arg.\n", __func__); ++ return; ++ } ++ priv = (struct cxd2880_priv *)fe->demodulator_priv; ++ kfree(priv); ++} ++ ++static int cxd2880_init(struct dvb_frontend *fe) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_priv *priv = NULL; ++ struct cxd2880_tnrdmd_create_param create_param; ++ ++ if (!fe) { ++ pr_err("%s: invalid arg.\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 != CXD2880_RESULT_OK) { ++ mutex_unlock(priv->spi_mutex); ++ dev_info(&priv->spi->dev, ++ "%s: cxd2880 tnrdmd create failed %d\n", ++ __func__, ret); ++ return return_tbl[ret]; ++ } ++ } ++ ret = cxd2880_integ_init(&priv->tnrdmd); ++ if (ret != CXD2880_RESULT_OK) { ++ mutex_unlock(priv->spi_mutex); ++ dev_err(&priv->spi->dev, "%s: cxd2880 integ init failed %d\n", ++ __func__, ret); ++ return return_tbl[ret]; ++ } ++ mutex_unlock(priv->spi_mutex); ++ ++ dev_dbg(&priv->spi->dev, "%s: OK.\n", __func__); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_sleep(struct dvb_frontend *fe) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_priv *priv = NULL; ++ ++ if (!fe) { ++ pr_err("%s: inavlid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_priv *)fe->demodulator_priv; ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_tnrdmd_sleep(&priv->tnrdmd); ++ mutex_unlock(priv->spi_mutex); ++ ++ dev_dbg(&priv->spi->dev, "%s: tnrdmd_sleep ret %d\n", ++ __func__, ret); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_read_signal_strength(struct dvb_frontend *fe, ++ u16 *strength) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_priv *priv = NULL; ++ struct dtv_frontend_properties *c = NULL; ++ int level = 0; ++ ++ if ((!fe) || (!strength)) { ++ pr_err("%s: inavlid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 { ++ dev_dbg(&priv->spi->dev, "%s: invalid system\n", __func__); ++ 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 != CXD2880_RESULT_OK) ++ dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ int snrvalue = 0; ++ struct cxd2880_priv *priv = NULL; ++ struct dtv_frontend_properties *c = NULL; ++ ++ if ((!fe) || (!snr)) { ++ pr_err("%s: inavlid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 { ++ dev_err(&priv->spi->dev, "%s: invalid system\n", __func__); ++ mutex_unlock(priv->spi_mutex); ++ return -EINVAL; ++ } ++ mutex_unlock(priv->spi_mutex); ++ ++ if (snrvalue < 0) ++ snrvalue = 0; ++ *snr = (u16)snrvalue; ++ ++ if (ret != CXD2880_RESULT_OK) ++ dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_priv *priv = NULL; ++ struct dtv_frontend_properties *c = NULL; ++ ++ if ((!fe) || (!ucblocks)) { ++ pr_err("%s: inavlid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 { ++ dev_err(&priv->spi->dev, "%s: invlaid system\n", __func__); ++ mutex_unlock(priv->spi_mutex); ++ return -EINVAL; ++ } ++ mutex_unlock(priv->spi_mutex); ++ ++ if (ret != CXD2880_RESULT_OK) ++ dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct cxd2880_priv *priv = NULL; ++ struct dtv_frontend_properties *c = NULL; ++ ++ if ((!fe) || (!ber)) { ++ pr_err("%s: inavlid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 { ++ dev_err(&priv->spi->dev, "%s: invlaid system\n", __func__); ++ mutex_unlock(priv->spi_mutex); ++ return -EINVAL; ++ } ++ mutex_unlock(priv->spi_mutex); ++ ++ if (ret != CXD2880_RESULT_OK) ++ dev_dbg(&priv->spi->dev, "%s: ret = %d\n", __func__, ret); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_set_frontend(struct dvb_frontend *fe) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ struct dtv_frontend_properties *c; ++ struct cxd2880_priv *priv; ++ enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; ++ ++ if (!fe) { ++ pr_err("%s: inavlid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_priv *)fe->demodulator_priv; ++ c = &fe->dtv_property_cache; ++ ++ 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; ++ } ++ ++ dev_info(&priv->spi->dev, "%s: sys:%d freq:%d bw:%d\n", __func__, ++ 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); ++ } 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; ++ ret = cxd2880_integ_dvbt2_tune(&priv->tnrdmd, ++ &priv->dvbt2_tune_param); ++ } else { ++ dev_err(&priv->spi->dev, "%s: invalid system\n", __func__); ++ mutex_unlock(priv->spi_mutex); ++ return -EINVAL; ++ } ++ mutex_unlock(priv->spi_mutex); ++ dev_info(&priv->spi->dev, "%s: tune result %d\n", __func__, ret); ++ ++ return return_tbl[ret]; ++} ++ ++static int cxd2880_read_status(struct dvb_frontend *fe, ++ enum fe_status *status) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ 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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 { ++ dev_err(&priv->spi->dev, ++ "%s: invlaid system", __func__); ++ mutex_unlock(priv->spi_mutex); ++ return -EINVAL; ++ } ++ ++ mutex_unlock(priv->spi_mutex); ++ if (ret != CXD2880_RESULT_OK) { ++ dev_err(&priv->spi->dev, "%s: failed. sys = %d\n", ++ __func__, priv->tnrdmd.sys); ++ return return_tbl[ret]; ++ } ++ ++ if (sync == 6) { ++ *status = FE_HAS_SIGNAL | ++ FE_HAS_CARRIER; ++ } ++ if (lock) ++ *status |= FE_HAS_VITERBI | ++ FE_HAS_SYNC | ++ FE_HAS_LOCK; ++ } ++ ++ dev_dbg(&priv->spi->dev, "%s: status %d result %d\n", __func__, ++ *status, ret); ++ ++ return return_tbl[CXD2880_RESULT_OK]; ++} ++ ++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("%s: invalid arg.", __func__); ++ return -EINVAL; ++ } ++ ++ if (retune) { ++ ret = cxd2880_set_frontend(fe); ++ if (ret) { ++ pr_err("%s: cxd2880_set_frontend failed %d\n", ++ __func__, 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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ int result = 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; ++ 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; ++ ++ if ((!fe) || (!c)) { ++ pr_err("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, "%s: get invalid mode %d\n", ++ __func__, 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; ++ dev_err(&priv->spi->dev, "%s: get invalid guard %d\n", ++ __func__, guard); ++ break; ++ } ++ } else { ++ c->transmission_mode = TRANSMISSION_MODE_2K; ++ c->guard_interval = GUARD_INTERVAL_1_32; ++ dev_dbg(&priv->spi->dev, ++ "%s: ModeGuard err %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_tnrdmd_dvbt_mon_tps_info(&priv->tnrdmd, &tps); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, ++ "%s: TPSInfo hierarchy invalid %d\n", ++ __func__, 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; ++ dev_err(&priv->spi->dev, ++ "%s: TPSInfo rateHP invalid %d\n", ++ __func__, 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; ++ dev_err(&priv->spi->dev, ++ "%s: TPSInfo rateLP invalid %d\n", ++ __func__, 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; ++ dev_err(&priv->spi->dev, ++ "%s: TPSInfo constellation invalid %d\n", ++ __func__, tps.constellation); ++ break; ++ } ++ } else { ++ c->hierarchy = HIERARCHY_NONE; ++ c->code_rate_HP = FEC_NONE; ++ c->code_rate_LP = FEC_NONE; ++ c->modulation = QPSK; ++ dev_dbg(&priv->spi->dev, ++ "%s: TPS info err %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(&priv->tnrdmd, &sense); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, ++ "%s: spectrum sense invalid %d\n", ++ __func__, sense); ++ break; ++ } ++ } else { ++ c->inversion = INVERSION_OFF; ++ dev_dbg(&priv->spi->dev, ++ "%s: spectrum_sense %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, "%s: mon_rf_lvl %d\n", ++ __func__, result); ++ } ++ ++ result = cxd2880_read_snr(fe, &snr); ++ if (!result) { ++ 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; ++ dev_dbg(&priv->spi->dev, "%s: read_snr %d\n", __func__, result); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_pre_bit_err_t(&priv->tnrdmd, &pre_bit_err, ++ &pre_bit_count); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: pre_bit_error_t failed %d\n", ++ __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_post_bit_err_t(&priv->tnrdmd, ++ &post_bit_err, &post_bit_count); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: post_bit_err_t %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_read_block_err_t(&priv->tnrdmd, ++ &block_err, &block_count); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: read_block_err_t %d\n", __func__, ret); ++ } ++ ++ return 0; ++} ++ ++static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, ++ struct dtv_frontend_properties *c) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ int result = 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; ++ 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; ++ ++ if ((!fe) || (!c)) { ++ pr_err("%s: invalid arg.\n", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_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 == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, ++ "%s: L1Pre fft_mode invalid %d\n", ++ __func__, 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; ++ dev_err(&priv->spi->dev, ++ "%s: L1Pre gi invalid %d\n", ++ __func__, l1pre.gi); ++ break; ++ } ++ } else { ++ c->transmission_mode = TRANSMISSION_MODE_2K; ++ c->guard_interval = GUARD_INTERVAL_1_32; ++ dev_dbg(&priv->spi->dev, ++ "%s: L1Pre err %d\n", __func__, 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 == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, ++ "%s: CodeRate invalid %d\n", ++ __func__, coderate); ++ break; ++ } ++ } else { ++ c->fec_inner = FEC_NONE; ++ dev_dbg(&priv->spi->dev, "%s: CodeRate %d\n", __func__, 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 == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, ++ "%s: QAM invalid %d\n", ++ __func__, qam); ++ break; ++ } ++ } else { ++ c->modulation = QPSK; ++ dev_dbg(&priv->spi->dev, "%s: QAM %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(&priv->tnrdmd, &sense); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_err(&priv->spi->dev, ++ "%s: spectrum sense invalid %d\n", ++ __func__, sense); ++ break; ++ } ++ } else { ++ c->inversion = INVERSION_OFF; ++ dev_dbg(&priv->spi->dev, ++ "%s: SpectrumSense %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_tnrdmd_mon_rf_lvl(&priv->tnrdmd, &strength); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: mon_rf_lvl %d\n", __func__, ret); ++ } ++ ++ result = cxd2880_read_snr(fe, &snr); ++ if (!result) { ++ 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; ++ dev_dbg(&priv->spi->dev, "%s: read_snr %d\n", __func__, result); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_pre_bit_err_t2(&priv->tnrdmd, ++ &pre_bit_err, ++ &pre_bit_count); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: read_bit_err_t2 %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_post_bit_err_t2(&priv->tnrdmd, ++ &post_bit_err, &post_bit_count); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: post_bit_err_t2 %d\n", __func__, ret); ++ } ++ ++ mutex_lock(priv->spi_mutex); ++ ret = cxd2880_read_block_err_t2(&priv->tnrdmd, ++ &block_err, &block_count); ++ mutex_unlock(priv->spi_mutex); ++ if (ret == CXD2880_RESULT_OK) { ++ 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; ++ dev_dbg(&priv->spi->dev, ++ "%s: read_block_err_t2 %d\n", __func__, ret); ++ } ++ ++ return 0; ++} ++ ++static int cxd2880_get_frontend(struct dvb_frontend *fe, ++ struct dtv_frontend_properties *props) ++{ ++ struct cxd2880_priv *priv = NULL; ++ int result = 0; ++ ++ if ((!fe) || (!props)) { ++ pr_err("%s: invalid arg.", __func__); ++ return -EINVAL; ++ } ++ ++ priv = (struct cxd2880_priv *)fe->demodulator_priv; ++ ++ dev_dbg(&priv->spi->dev, "%s: system=%d\n", __func__, ++ fe->dtv_property_cache.delivery_system); ++ switch (fe->dtv_property_cache.delivery_system) { ++ case SYS_DVBT: ++ result = cxd2880_get_frontend_t(fe, props); ++ break; ++ case SYS_DVBT2: ++ result = cxd2880_get_frontend_t2(fe, props); ++ break; ++ default: ++ result = -EINVAL; ++ break; ++ } ++ ++ return result; ++} ++ ++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) ++{ ++ enum cxd2880_ret ret = CXD2880_RESULT_OK; ++ enum cxd2880_tnrdmd_chip_id chipid = ++ CXD2880_TNRDMD_CHIP_ID_UNKNOWN; ++ static struct cxd2880_priv *priv; ++ u8 data = 0; ++ ++ if (!fe) { ++ pr_err("%s: invalid arg.\n", __func__); ++ 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 != CXD2880_RESULT_OK) { ++ dev_err(&priv->spi->dev, ++ "%s: spi_device_initialize failed. %d\n", ++ __func__, ret); ++ kfree(priv); ++ return NULL; ++ } ++ ++ ret = cxd2880_spi_device_create_spi(&priv->cxd2880_spi, ++ &priv->spi_device); ++ if (ret != CXD2880_RESULT_OK) { ++ dev_err(&priv->spi->dev, ++ "%s: spi_device_create_spi failed. %d\n", ++ __func__, ret); ++ kfree(priv); ++ return NULL; ++ } ++ ++ ret = cxd2880_io_spi_create(&priv->regio, &priv->cxd2880_spi, 0); ++ if (ret != CXD2880_RESULT_OK) { ++ dev_err(&priv->spi->dev, ++ "%s: io_spi_create failed. %d\n", __func__, ret); ++ kfree(priv); ++ return NULL; ++ } ++ if (priv->regio.write_reg(&priv->regio, CXD2880_IO_TGT_SYS, 0x00, 0x00) ++ != CXD2880_RESULT_OK) { ++ dev_err(&priv->spi->dev, ++ "%s: set bank to 0x00 failed.\n", __func__); ++ kfree(priv); ++ return NULL; ++ } ++ if (priv->regio.read_regs(&priv->regio, ++ CXD2880_IO_TGT_SYS, 0xFD, &data, 1) ++ != CXD2880_RESULT_OK) { ++ dev_err(&priv->spi->dev, ++ "%s: read chip id failed.\n", __func__); ++ 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)) { ++ dev_err(&priv->spi->dev, ++ "%s: chip id invalid.\n", __func__); ++ kfree(priv); ++ return NULL; ++ } ++ ++ fe->demodulator_priv = priv; ++ dev_info(&priv->spi->dev, ++ "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"); +diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig +index a21f5a39a440fe64a98f6bc04879fef65d753292..b07ac86fc53c782cf0980fc86f07d09bb5df0e40 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 +diff --git a/drivers/media/spi/Makefile b/drivers/media/spi/Makefile +index ea64013d16cc7eda7424ed6684240e99b685e2cb..40e0f88d9f6c84a6ca6cfbd23d30102eabefd4e1 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 +diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c +new file mode 100644 +index 0000000000000000000000000000000000000000..82e122349055be817eb74ed5bbcd7560485bc448 +--- /dev/null ++++ b/drivers/media/spi/cxd2880-spi.c +@@ -0,0 +1,728 @@ ++/* ++ * 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 . ++ */ ++ ++#include ++ ++#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("%s: invalid arg\n", __func__); ++ 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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ if (size > BURST_WRITE_MAX) { ++ pr_err("%s: data size > WRITE_MAX\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (subAddress + size > 0x100) { ++ pr_err("%s: out of range\n", __func__); ++ 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) { ++ dev_err(&spi->dev, "%s: write spi failed %d\n", ++ __func__, 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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ if (packet_num > 0xFFFF) { ++ dev_err(&spi->dev, "%s: packet num > 0xFFFF\n", __func__); ++ return -EINVAL; ++ } ++ ++ data[0] = 0x10; ++ data[1] = (u8)((packet_num >> 8) & 0xFF); ++ data[2] = (u8)(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) ++ dev_err(&spi->dev, "%s: spi_write_then_read failed\n", ++ __func__); ++ ++ 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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ ret = spi_write_then_read(spi, &send_data, 1, ++ recv_data, sizeof(recv_data)); ++ if (ret) ++ dev_err(&spi->dev, ++ "%s: spi_write_then_read failed\n", __func__); ++ ++ info->read_ready = (u8)((recv_data[0] & 0x80) ? 1 : 0); ++ info->almost_full = (u8)((recv_data[0] & 0x40) ? 1 : 0); ++ info->almost_empty = (u8)((recv_data[0] & 0x20) ? 1 : 0); ++ info->overflow = (u8)((recv_data[0] & 0x10) ? 1 : 0); ++ info->underflow = (u8)((recv_data[0] & 0x08) ? 1 : 0); ++ info->packet_num = (u16)(((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("%s: write spi failed\n", __func__); ++ ++ return ret; ++} ++ ++static int cxd2880_set_pid_filter(struct spi_device *spi, ++ struct cxd2880_pid_filter_config *cfg) ++{ ++ u8 data[65]; ++ ++ if (!spi) { ++ pr_err("%s: ivnalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ data[0] = 0x00; ++ if (cxd2880_write_reg(spi, 0x00, &data[0], 1) != 0) ++ return -EIO; ++ if (!cfg) { ++ data[0] = 0x02; ++ if (cxd2880_write_reg(spi, 0x50, &data[0], 1) != 0) ++ return -EIO; ++ } else { ++ data[0] = (u8)(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)] = ++ (u8)((u8)(pid >> 8) | 0x20); ++ data[2 + (i * 2)] = ++ (u8)(pid & 0xFF); ++ } else { ++ data[1 + (i * 2)] = 0x00; ++ data[2 + (i * 2)] = 0x00; ++ } ++ } ++ } ++ if (cxd2880_write_reg(spi, 0x50, data, 65) != 0) ++ return -EIO; ++ } ++ ++ 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("%s: invalid arg.\n", __func__); ++ 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) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: set_pid_filter failed\n", __func__); ++ } ++ ++ return ret; ++} ++ ++static int cxd2880_ts_read(void *arg) ++{ ++ struct cxd2880_dvb_spi *dvb_spi = NULL; ++ struct cxd2880_ts_buf_info info; ++ struct timespec ts; ++ long elapsed = 0; ++ long starttime = 0; ++ u32 i; ++ int ret; ++ ++ dvb_spi = (struct cxd2880_dvb_spi *)arg; ++ if (!dvb_spi) { ++ pr_err("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ ret = cxd2880_spi_clear_ts_buffer(dvb_spi->spi); ++ if (ret) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: set_clear_ts_buffer failed\n", __func__); ++ return ret; ++ } ++ ++ getnstimeofday(&ts); ++ starttime = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); ++ while (!kthread_should_stop()) { ++ getnstimeofday(&ts); ++ elapsed = ++ ((ts.tv_sec * 1000) + (ts.tv_nsec / 1000000)) ++ - starttime; ++ ret = cxd2880_spi_read_ts_buffer_info(dvb_spi->spi, ++ &info); ++ if (ret) { ++ pr_err("%s: spi_read_ts_buffer_info error\n", ++ __func__); ++ 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); ++ } ++ starttime = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); ++ } 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); ++ starttime = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); ++ } 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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ demux = feed->demux; ++ if (!demux) { ++ pr_err("%s: feed->demux is NULL\n", __func__); ++ return -EINVAL; ++ } ++ dvb_spi = (struct cxd2880_dvb_spi *)demux->priv; ++ ++ if (dvb_spi->feed_count == CXD2880_MAX_FILTER_SIZE) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: Exceeded maximum PID count (32).", __func__); ++ dev_err(&dvb_spi->spi->dev, ++ "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) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: update pid filter failed\n", ++ __func__); ++ return ret; ++ } ++ } ++ dvb_spi->all_pid_feed_count++; ++ ++ dev_dbg(&dvb_spi->spi->dev, ++ "%s: all PID feed (count = %d)\n", ++ __func__, 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; ++ dev_dbg(&dvb_spi->spi->dev, ++ "%s: store PID %d to #%d\n", ++ __func__, feed->pid, i); ++ break; ++ } ++ } ++ if (i == CXD2880_MAX_FILTER_SIZE) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: PID filter is full. Assumed bug.\n", ++ __func__); ++ 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(sizeof(u8) * MAX_TRANS_PACKET * 188, ++ GFP_KERNEL | GFP_DMA); ++ if (!dvb_spi->ts_buf) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: ts buffer allocate failed\n", __func__); ++ 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)) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: kthread_run failed/\n", ++ __func__); ++ 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++; ++ ++ dev_dbg(&dvb_spi->spi->dev, "%s: start feed (count %d)\n", ++ __func__, 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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ demux = feed->demux; ++ if (!demux) { ++ pr_err("%s: feed->demux is NULL\n", __func__); ++ return -EINVAL; ++ } ++ dvb_spi = (struct cxd2880_dvb_spi *)demux->priv; ++ ++ if (!dvb_spi->feed_count) { ++ dev_warn(&dvb_spi->spi->dev, ++ "%s: no feed is started\n", __func__); ++ 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) { ++ dev_warn(&dvb_spi->spi->dev, ++ "%s: PID %d not found.\n", ++ __func__, 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; ++ dev_dbg(&dvb_spi->spi->dev, ++ "%s: removed PID %d from #%d\n", ++ __func__, feed->pid, i); ++ break; ++ } ++ } ++ dvb_spi->filter_config = cfgtmp; ++ ++ if (i == CXD2880_MAX_FILTER_SIZE) { ++ dev_warn(&dvb_spi->spi->dev, "%s: PID %d not found\n", ++ __func__, 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) { ++ dev_err(&dvb_spi->spi->dev, ++ "%s: cxd2880_ts_read thread didn't terminate normally\n", ++ __func__); ++ ret = ret_stop; ++ } ++ kfree(dvb_spi->ts_buf); ++ dvb_spi->ts_buf = NULL; ++ } ++ ++ dev_dbg(&dvb_spi->spi->dev, "%s: stop feed ok.(count %d)\n", ++ __func__, 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("%s: invalid arg.\n", __func__); ++ 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) { ++ dev_err(&spi->dev, "%s: dvb_register_adapter() failed\n", ++ __func__); ++ goto fail_adapter; ++ } ++ ++ if (!dvb_attach(cxd2880_attach, &dvb_spi->dvb_fe, &config)) { ++ dev_err(&spi->dev, "%s: cxd2880_attach failed\n", __func__); ++ goto fail_attach; ++ } ++ ++ ret = dvb_register_frontend(&dvb_spi->adapter, ++ &dvb_spi->dvb_fe); ++ if (ret < 0) { ++ dev_err(&spi->dev, "%s: dvb_register_frontend() failed\n", ++ __func__); ++ 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) { ++ dev_err(&spi->dev, "%s: dvb_dmx_init() failed\n", __func__); ++ 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) { ++ dev_err(&spi->dev, "%s: dvb_dmxdev_init() failed\n", __func__); ++ 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) { ++ dev_err(&spi->dev, "%s: add_frontend() failed\n", __func__); ++ goto fail_dmx_fe; ++ } ++ ++ ret = dvb_spi->demux.dmx.connect_frontend(&dvb_spi->demux.dmx, ++ &dvb_spi->dmx_fe); ++ if (ret < 0) { ++ dev_err(&spi->dev, "%s: dvb_register_frontend() failed\n", ++ __func__); ++ goto fail_fe_conn; ++ } ++ ++ dev_info(&spi->dev, "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("%s: invalid arg\n", __func__); ++ return -EINVAL; ++ } ++ ++ dvb_spi = (struct cxd2880_dvb_spi *)dev_get_drvdata(&spi->dev); ++ ++ if (!dvb_spi) { ++ pr_err("%s: failed\n", __func__); ++ 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); ++ dev_info(&spi->dev, "%s: cxd2880_spi remove ok.\n", __func__); ++ ++ 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"); + +From cd562c1037bd813c368aa493b6b08a952a23b749 Mon Sep 17 00:00:00 2001 +From: Yasunari Takiguchi +Date: Thu, 22 Dec 2016 15:34:12 +0900 +Subject: [PATCH 225/229] BCM2708: Add Raspberry Pi TV HAT Device Tree Support + +This is an EXAMPLE CODE of Raspberry Pi TV HAT device tree overlay. +Although this is not a part of our release code, it has been used to verify +CXD2880 device driver with TV HAT. + +Add the following line to /boot/config.txt to enable TV HAT: + +dtoverlay=rpi-tv + +Reboot Raspberry Pi and check the existance of /proc/device-tree/soc/spi@7e204000/cxd2880@0. +If exists, the installation is successful. you should be able to find the following three files. +/dev/dvb/adapter0/frontend0 +/dev/dvb/adapter0/demux0 +/dev/dvb/adapter0/dvr0 + +Signed-off-by: Yasunari Takiguchi +Signed-off-by: Masayuki Yamamoto +Signed-off-by: Hideki Nozawa +Signed-off-by: Kota Yonezawa +Signed-off-by: Toshihiko Matsumoto +Signed-off-by: Satoshi Watanabe +--- + arch/arm/boot/dts/overlays/Makefile | 1 + + arch/arm/boot/dts/overlays/README | 6 ++++++ + arch/arm/boot/dts/overlays/rpi-tv-overlay.dts | 31 +++++++++++++++++++++++++++ + 3 files changed, 38 insertions(+) + create mode 100644 arch/arm/boot/dts/overlays/rpi-tv-overlay.dts + +diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile +index b64dd7ac0630b2b525809a9f5221420f34a58ac9..e2f66a55dc5afe13d690c2c17827054ac94b7168 100644 +--- a/arch/arm/boot/dts/overlays/Makefile ++++ b/arch/arm/boot/dts/overlays/Makefile +@@ -81,6 +81,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ + rpi-ft5406.dtbo \ + rpi-proto.dtbo \ + rpi-sense.dtbo \ ++ rpi-tv.dtbo \ + rra-digidac1-wm8741-audio.dtbo \ + sc16is750-i2c.dtbo \ + sc16is752-spi1.dtbo \ +diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README +index 1377e5b8e8363c3e0ede318ce54bd784cb70d4c9..e2a803e5180cf78d67b6723cfd2f6d3b2b54e53b 100644 +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -1142,6 +1142,12 @@ Load: dtoverlay=rpi-sense + Params: + + ++Name: rpi-tv ++Info: Raspberry Pi TV HAT ++Load: dtoverlay=rpi-tv ++Params: ++ ++ + Name: rra-digidac1-wm8741-audio + Info: Configures the Red Rocks Audio DigiDAC1 soundcard + Load: dtoverlay=rra-digidac1-wm8741-audio +diff --git a/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts b/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts +new file mode 100644 +index 0000000000000000000000000000000000000000..a68f6f793d8efd8b2e2adf9f2fb6426f61ff464a +--- /dev/null ++++ b/arch/arm/boot/dts/overlays/rpi-tv-overlay.dts +@@ -0,0 +1,31 @@ ++// rpi-tv HAT ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ ++ spidev@0 { ++ status = "disabled"; ++ }; ++ ++ cxd2880@0 { ++ compatible = "sony,cxd2880"; ++ reg = <0>; /* CE0 */ ++ spi-max-frequency = <50000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++}; + +From fca54639764bcd86afde246c8ac1985b491a1a2d Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Wed, 12 Apr 2017 17:52:56 -0700 +Subject: [PATCH 226/229] panel-raspberrypi-touchscreen: Fix NULL deref if + probe order goes wrong. + +If the i2c driver hadn't pobed before the panel driver probes, then +the client would be NULL but we were looking for an ERR_PTR in the +error case. + +Signed-off-by: Eric Anholt +--- + drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +index 7f315f04b109621ca7f3861fdd8acf956e752629..b57b7ad9aa4c5048186e98553af59ec912973096 100644 +--- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c ++++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c +@@ -404,6 +404,9 @@ static struct i2c_client *rpi_touchscreen_get_i2c(struct device *dev, + + of_node_put(node); + ++ if (!client) ++ return ERR_PTR(-EPROBE_DEFER); ++ + return client; + } + + +From f26f9c061858b0badf738961cf0b934b31433f78 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Wed, 19 Apr 2017 09:59:21 -0700 +Subject: [PATCH 227/229] smsc75xx: use skb_cow_head() to deal with cloned skbs + +We need to ensure there is enough headroom to push extra header, +but we also need to check if we are allowed to change headers. + +skb_cow_head() is the proper helper to deal with this. + +Fixes: d0cad871703b ("smsc75xx: SMSC LAN75xx USB gigabit ethernet adapter driver") +Signed-off-by: Eric Dumazet +Cc: James Hughes +Signed-off-by: David S. Miller +--- + drivers/net/usb/smsc75xx.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c +index 9af9799935dbbd4baed06eb03402803e0ce8d9c8..4cb9b11a545a9572ab6d248742ec5abee00fa7e4 100644 +--- a/drivers/net/usb/smsc75xx.c ++++ b/drivers/net/usb/smsc75xx.c +@@ -2205,13 +2205,9 @@ static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev, + { + u32 tx_cmd_a, tx_cmd_b; + +- if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) { +- struct sk_buff *skb2 = +- skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags); ++ if (skb_cow_head(skb, SMSC75XX_TX_OVERHEAD)) { + dev_kfree_skb_any(skb); +- skb = skb2; +- if (!skb) +- return NULL; ++ return NULL; + } + + tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN) | TX_CMD_A_FCS; + +From 19b7bd935e3ef6f5bbd9429c5c487c07ce4593a1 Mon Sep 17 00:00:00 2001 +From: James Hughes +Date: Wed, 19 Apr 2017 11:13:40 +0100 +Subject: [PATCH 228/229] smsc95xx: Use skb_cow_head to deal with cloned skbs + +The driver was failing to check that the SKB wasn't cloned +before adding checksum data. +Replace existing handling to extend/copy the header buffer +with skb_cow_head. + +Signed-off-by: James Hughes +Acked-by: Eric Dumazet +Acked-by: Woojung Huh +Signed-off-by: David S. Miller +--- + drivers/net/usb/smsc95xx.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c +index df60c989fc229bf0aab3c27e95ccd45323367840..f6661e388f6e801c1b88e48a3b71407bd70cf56e 100644 +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -2067,13 +2067,13 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, + /* We do not advertise SG, so skbs should be already linearized */ + BUG_ON(skb_shinfo(skb)->nr_frags); + +- if (skb_headroom(skb) < overhead) { +- struct sk_buff *skb2 = skb_copy_expand(skb, +- overhead, 0, flags); ++ /* Make writable and expand header space by overhead if required */ ++ if (skb_cow_head(skb, overhead)) { ++ /* Must deallocate here as returning NULL to indicate error ++ * means the skb won't be deallocated in the caller. ++ */ + dev_kfree_skb_any(skb); +- skb = skb2; +- if (!skb) +- return NULL; ++ return NULL; + } + + if (csum) { + +From b629887de7c80ed000a78e290ca4daca5e7c312f Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 24 Apr 2017 18:26:52 +0100 +Subject: [PATCH 229/229] i2c-bcm2835: Ignore unexpected interrupt + +--- + drivers/i2c/busses/i2c-bcm2835.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c +index 8642f580ce41803bd22c76a0fa80d083d0747be1..47167f403cc8329bd811b47c7011c299b8ecafee 100644 +--- a/drivers/i2c/busses/i2c-bcm2835.c ++++ b/drivers/i2c/busses/i2c-bcm2835.c +@@ -279,7 +279,9 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) + } + + if (val & BCM2835_I2C_S_DONE) { +- if (i2c_dev->curr_msg->flags & I2C_M_RD) { ++ if (!i2c_dev->curr_msg) { ++ dev_err(i2c_dev->dev, "Got unexpected interrupt (from firmware?)\n"); ++ } else if (i2c_dev->curr_msg->flags & I2C_M_RD) { + bcm2835_drain_rxfifo(i2c_dev); + val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); + }