diff --git a/projects/RPi2/linux/linux.arm.conf b/projects/RPi2/linux/linux.arm.conf index cc170548d1..19367c20eb 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 3.18.8 Kernel Configuration +# Linux/arm 3.18.9 Kernel Configuration # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -2202,7 +2202,6 @@ CONFIG_DVB_EC100=m CONFIG_DVB_CXD2820R=m CONFIG_DVB_RTL2830=m CONFIG_DVB_RTL2832=m -CONFIG_DVB_SP2=m CONFIG_DVB_SI2168=m CONFIG_DVB_AS102_FE=m @@ -2248,6 +2247,7 @@ CONFIG_DVB_LNBP22=m CONFIG_DVB_ISL6421=m CONFIG_DVB_ISL6423=m CONFIG_DVB_A8293=m +CONFIG_DVB_SP2=m CONFIG_DVB_LGS8GXX=m CONFIG_DVB_ATBM8830=m CONFIG_DVB_IX2505V=m @@ -2960,6 +2960,7 @@ CONFIG_LIRC_XBOX=m # CONFIG_LUSTRE_FS is not set # CONFIG_DGAP is not set # CONFIG_GS_FPGABOOT is not set +# CONFIG_FB_TFT is not set # # SOC (System On Chip) specific Drivers diff --git a/projects/RPi2/patches/linux/linux-01-RPi_support.patch b/projects/RPi2/patches/linux/linux-01-RPi_support.patch index 73bb883e88..36c9673ecd 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 aca2e72ca1b6ad03c3fa678cb0a0df73cccb9c28 Mon Sep 17 00:00:00 2001 +From 56c4547ca5523de7597fc21a4679d78b9232b3cd Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 001/118] Main bcm2708 linux port +Subject: [PATCH 001/178] Main bcm2708 linux port Signed-off-by: popcornmix --- @@ -2167,7 +2167,7 @@ index 0000000..51d147a +MODULE_PARM_DESC(dmachans, "Bitmap of DMA channels available to the ARM"); diff --git a/arch/arm/mach-bcm2708/include/mach/arm_control.h b/arch/arm/mach-bcm2708/include/mach/arm_control.h new file mode 100644 -index 0000000..a82bb92 +index 0000000..a82bb92b --- /dev/null +++ b/arch/arm/mach-bcm2708/include/mach/arm_control.h @@ -0,0 +1,419 @@ @@ -5121,10 +5121,10 @@ index dba793e..9300f87 100644 unsigned int version; /* SDHCI spec. version */ -From daf2ee2a20e883160ae2dd258e94783d7782458f Mon Sep 17 00:00:00 2001 +From d870bedee3fa655a2d321485a1fd20bf65fb5e69 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 Oct 2014 18:50:05 +0100 -Subject: [PATCH 002/118] Add bcm2708_gpio driver +Subject: [PATCH 002/178] Add bcm2708_gpio driver Signed-off-by: popcornmix @@ -5728,10 +5728,10 @@ index 0000000..fb69624 + +#endif -From a3d9dea6a2533b1e32176b4aa08742032d9c7bc9 Mon Sep 17 00:00:00 2001 +From 730bb0ef278ac90a79298c5a553b51e4b6490a83 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 7 May 2013 22:20:24 +0100 -Subject: [PATCH 003/118] Add quick config. +Subject: [PATCH 003/178] Add quick config. This is designed for quick compiling when developing. No modules are needed and it includes all Pi specific drivers @@ -5944,10 +5944,10 @@ index 0000000..e5efe75 +CONFIG_CRC_ITU_T=y +CONFIG_LIBCRC32C=y -From 9997d90fcf6e9a653a2607d813dc6c77ef16e00c Mon Sep 17 00:00:00 2001 +From f22b16e26046072a0f77739b18d641afb7d22bff Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 004/118] Add dwc_otg driver +Subject: [PATCH 004/178] Add dwc_otg driver Signed-off-by: popcornmix @@ -6108,10 +6108,10 @@ index 358ca8d..abaac7c 100644 return i; } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c -index f7b7713..5423d18 100644 +index f368d20..2f6e3fe 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c -@@ -1889,6 +1889,85 @@ int usb_set_configuration(struct usb_device *dev, int configuration) +@@ -1872,6 +1872,85 @@ int usb_set_configuration(struct usb_device *dev, int configuration) if (cp->string == NULL && !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) cp->string = usb_cache_string(dev, cp->desc.iConfiguration); @@ -63000,10 +63000,10 @@ index 0000000..cdc9963 +test_main(); +0; -From e63b217fe67e3ccf3958109037c91aaea50e2d8c Mon Sep 17 00:00:00 2001 +From 733e95a5fde1d06faa3264634873005be4f6a5d6 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:54:32 +0100 -Subject: [PATCH 005/118] bcm2708 watchdog driver +Subject: [PATCH 005/178] bcm2708 watchdog driver Signed-off-by: popcornmix --- @@ -63431,11 +63431,10 @@ index 0000000..8a27d68 +MODULE_ALIAS_MISCDEV(TEMP_MINOR); +MODULE_LICENSE("GPL"); - -From 0ac2e35f7d1e39ee2d3f393b6ee1a8196a3c043a Mon Sep 17 00:00:00 2001 +From 0513ef2f5971d8149c7dd5e702baad09881f457f Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 007/118] Speed up console framebuffer imageblit function +Subject: [PATCH 007/178] 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 @@ -63644,10 +63643,10 @@ index a2bb276..436494f 100644 start_index, pitch_index); } else -From 4326e79caa1d0a891961bcd27f06457bcc5beb2b Mon Sep 17 00:00:00 2001 +From 4bb465b46a72c08477abca49c826249981864d6a Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 008/118] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 008/178] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -63740,10 +63739,10 @@ index fb795c3..fa72af0 100644 #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ #define FB_TYPE_PLANES 1 /* Non interleaved planes */ -From 37e686f87dafb75e66723083dbb961c3f62c74cf Mon Sep 17 00:00:00 2001 +From d4134ca971869d4ab333d0d3d6b53c6b084ae053 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:55:09 +0100 -Subject: [PATCH 009/118] bcm2708 framebuffer driver +Subject: [PATCH 009/178] bcm2708 framebuffer driver Signed-off-by: popcornmix @@ -67186,10 +67185,10 @@ index 3c14e43..7626beb6a 100644 +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 3f80ee657c0aab35e88ab93d688a6199d14aaa3c Mon Sep 17 00:00:00 2001 +From 872456cd9e1e200307d9a8a90ca3386ae524344e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 2 Jul 2013 23:42:01 +0100 -Subject: [PATCH 010/118] bcm2708 vchiq driver +Subject: [PATCH 010/178] bcm2708 vchiq driver Signed-off-by: popcornmix @@ -80138,10 +80137,10 @@ index 0000000..b6bfa21 + return vchiq_build_time; +} -From fe192815f71471794df82b6ed96341c0a646ef7b Mon Sep 17 00:00:00 2001 +From ad5bc172e3705e203a37f905a078c398d54f5677 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 12 May 2014 15:12:02 +0100 -Subject: [PATCH 011/118] vchiq: Avoid high load when blocked and unkillable +Subject: [PATCH 011/178] vchiq: Avoid high load when blocked and unkillable vchiq: Include SIGSTOP and SIGCONT in list of signals not-masked by vchiq to allow gdb to work --- @@ -80303,10 +80302,10 @@ index c2eefef..05e7979 100644 static inline int is_pow2(int i) { -From dea80401902622e4a94e2a37b753bf497c56c1e6 Mon Sep 17 00:00:00 2001 +From d267dad2d891450731f0c1772ade5acab23cefd2 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 012/118] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 012/178] cma: Add vc_cma driver to enable use of CMA Signed-off-by: popcornmix --- @@ -81593,10 +81592,10 @@ index 0000000..5325832 + +#endif /* VC_CMA_H */ -From 77570a64671592488505521f1c885ef79e23c931 Mon Sep 17 00:00:00 2001 +From 9b6b1ad40fa4f7491d6f92105e7b05bc70e1c4b1 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 013/118] bcm2708: alsa sound driver +Subject: [PATCH 013/178] bcm2708: alsa sound driver Signed-off-by: popcornmix @@ -84359,10 +84358,10 @@ index 0000000..af3e6eb + +#endif // _VC_AUDIO_DEFS_H_ -From 3c57d750d996eda5cf50ac210fb0181d82f0d031 Mon Sep 17 00:00:00 2001 +From 4262c63721dc8423b5ab8b75b6184038f04bdb44 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:51:55 +0100 -Subject: [PATCH 014/118] Add hwrng (hardware random number generator) driver +Subject: [PATCH 014/178] Add hwrng (hardware random number generator) driver --- drivers/char/hw_random/Kconfig | 11 ++++ @@ -84529,10 +84528,10 @@ index 0000000..340f004 +MODULE_DESCRIPTION("BCM2708 H/W Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL and additional rights"); -From d5ac09a62f26dae93c30586be44a3a909ab74594 Mon Sep 17 00:00:00 2001 +From fe1e9cb352700051d4a761c505b754cea6c6a886 Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 015/118] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 015/178] 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 @@ -85264,10 +85263,10 @@ index 0000000..c688364 +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -From 709b621cc5e85dd90a1154a07600675b56c31ee2 Mon Sep 17 00:00:00 2001 +From 0afa8dfab501f31ad240aadce1d5b7afd528b6fd Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 016/118] Add cpufreq driver +Subject: [PATCH 016/178] Add cpufreq driver --- arch/arm/Kconfig | 1 + @@ -85551,10 +85550,10 @@ index 0000000..447ca09 +module_init(bcm2835_cpufreq_module_init); +module_exit(bcm2835_cpufreq_module_exit); -From 3abbb2a220b0be9338dfcf5a5e71fc2c4a779c1b Mon Sep 17 00:00:00 2001 +From e4d62671d5f8515e4b8960f7265b88e034706cb3 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 017/118] Added hwmon/thermal driver for reporting core +Subject: [PATCH 017/178] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian --- @@ -86076,10 +86075,10 @@ index 0000000..85fceb5 + +module_platform_driver(bcm2835_thermal_driver); -From b274d5703e257194a174448a364b5dc3f2a5da0c Mon Sep 17 00:00:00 2001 +From e1bd7f7b1f8849c634eb64df8b70f01804c4c189 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 018/118] Allow mac address to be set in smsc95xx +Subject: [PATCH 018/178] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -86170,10 +86169,10 @@ index d07bf4c..5ae60ab 100644 if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, dev->net->dev_addr) == 0) { -From 144ffa9ea38c07b79b7b168dca257d7eb3d9ed6f Mon Sep 17 00:00:00 2001 +From b5a365e88fb0e46af6a3989fada577e135767ac7 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 4 Nov 2013 18:56:10 +0000 -Subject: [PATCH 019/118] Add Chris Boot's i2c and spi drivers. +Subject: [PATCH 019/178] Add Chris Boot's i2c and spi drivers. i2c-bcm2708: fixed baudrate @@ -87520,10 +87519,10 @@ index 0000000..b04a57d +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From 1bb03aaa05391d1b251d9d31a7b6a20422f57efd Mon Sep 17 00:00:00 2001 +From 19ad7bb3fecd3186a2b32c790464939ab39e77dc Mon Sep 17 00:00:00 2001 From: cbeytas Date: Mon, 24 Jun 2013 00:05:40 -0400 -Subject: [PATCH 020/118] Perform I2C combined transactions when possible +Subject: [PATCH 020/178] Perform I2C combined transactions when possible Perform I2C combined transactions whenever possible, within the restrictions of the Broadcomm Serial Controller. @@ -87595,10 +87594,10 @@ index 09203c0..7d385a3 100644 } -From 039c613ee1655b337a7b301fa8a844c1f19de088 Mon Sep 17 00:00:00 2001 +From 70d6f535caf640960b2b514d16b3a49156329c1b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 021/118] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 021/178] 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 @@ -87870,10 +87869,10 @@ index 2820924..fd0550f 100644 } } -From decee9a130dc67cdef670b428c83c2aa08a464ec Mon Sep 17 00:00:00 2001 +From b147d342aa86d4fb00b2934000a34de66414721e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 12 Apr 2013 23:58:47 +0100 -Subject: [PATCH 023/118] config: add missing options from 3.6.y kernel +Subject: [PATCH 023/178] config: add missing options from 3.6.y kernel --- arch/arm/configs/bcmrpi_defconfig | 658 ++++++++++++++++++++++++++++++++++++-- @@ -88807,10 +88806,10 @@ index 6d2eae1..e2da9da 100644 # CONFIG_CRYPTO_HW is not set CONFIG_CRC_ITU_T=y -From 26d6b8a8c55249e2ba73c8e0aafe923f9509a71a Mon Sep 17 00:00:00 2001 +From 251aba9353b12acd3870bc812fcd4cdf55ffeef5 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 024/118] config: Enable CONFIG_MEMCG, but leave it disabled +Subject: [PATCH 024/178] config: Enable CONFIG_MEMCG, but leave it disabled (due to memory cost). Enable with cgroup_enable=memory. --- @@ -88878,10 +88877,10 @@ index d72bdc3..f5ca101 100644 #ifdef CONFIG_MEMCG_SWAP -From c3c933ed04505ef9931412f3edd78daa8ccdb396 Mon Sep 17 00:00:00 2001 +From dd263a4786735c23aa1eb7614aaa90762b96a4a4 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:46:42 +0100 -Subject: [PATCH 025/118] Add FIQ patch to dwc_otg driver. Enable with +Subject: [PATCH 025/178] Add FIQ patch to dwc_otg driver. Enable with dwc_otg.fiq_fix_enable=1. Should give about 10% more ARM performance. Thanks to Gordon and Costas @@ -92174,10 +92173,10 @@ index 1b1f83c..c8590b5 100644 if (status.b.sr) { -From bb3a9c9021f9ab2eb551b9d35a4aa16e33c96d46 Mon Sep 17 00:00:00 2001 +From 2553d2ac21b1dcef8bef5c2e009a2165dab65d91 Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 19 Mar 2014 12:58:23 +0000 -Subject: [PATCH 026/118] dwc_otg: fiq_fsm: Base commit for driver rewrite +Subject: [PATCH 026/178] dwc_otg: fiq_fsm: Base commit for driver rewrite This commit removes the previous FIQ fixes entirely and adds fiq_fsm. @@ -97072,10 +97071,10 @@ index 5d310df..4b32941 100644 return -EBUSY; } -From 8d9c9ba2ad0878ca44a99b26be729017dc329c01 Mon Sep 17 00:00:00 2001 +From da6385b8e1ad2ba49ef064242e578ef6600efdb6 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 027/118] bcm2835: add v4l2 camera device +Subject: [PATCH 027/178] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -97187,10 +97186,10 @@ index 0000000..c585a8f + +$ v4l2-ctl --list-formats diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index 3aac88f..9bc18aa 100644 +index 7362772..c40b8ae 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig -@@ -126,6 +126,7 @@ config VIDEO_S3C_CAMIF +@@ -124,6 +124,7 @@ config VIDEO_S3C_CAMIF source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" @@ -103057,10 +103056,10 @@ index 0000000..9d1d11e + +#endif /* MMAL_VCHIQ_H */ -From bba19070cc6b8f30946801c583f532799fd4c243 Mon Sep 17 00:00:00 2001 +From 726de5d7ab1c667c2f5f7db93c0005c5a7e9bd01 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 10:58:01 +0000 -Subject: [PATCH 028/118] V4L2: Fixes from 6by9 +Subject: [PATCH 028/178] V4L2: Fixes from 6by9 V4L2: Fix EV values. Add manual shutter speed control @@ -105472,10 +105471,10 @@ index a06fb44..76f249e 100644 release_msg: -From 3648a355f4bd36b9c8c7328ddc5a8466d53dbcab Mon Sep 17 00:00:00 2001 +From 04b8d2ddde3e5b54ce5413cf88a21d8110e37d1e Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 029/118] dmaengine: Add support for BCM2708 +Subject: [PATCH 029/178] dmaengine: Add support for BCM2708 Add support for DMA controller of BCM2708 as used in the Raspberry Pi. Currently it only supports cyclic DMA. @@ -106614,10 +106613,10 @@ index 0000000..10463db +MODULE_AUTHOR("Gellert Weisz "); +MODULE_LICENSE("GPL v2"); -From e25acbdd7d1a4e017616f7f334d5ba0fbb83e971 Mon Sep 17 00:00:00 2001 +From f2bd46e2441b7467b290e5934c31579a69f87a38 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:33:38 +0100 -Subject: [PATCH 030/118] ASoC: Add support for BCM2708 +Subject: [PATCH 030/178] ASoC: Add support for BCM2708 This driver adds support for digital audio (I2S) for the BCM2708 SoC that is used by the @@ -107749,10 +107748,10 @@ index 0000000..6fdcbc1 + +#endif -From 2f8aae960762512d5b705a2a70ee159d5f236bb9 Mon Sep 17 00:00:00 2001 +From 657becbc1afd7795432cc8c38f6af81c66c99e14 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:59:51 +0100 -Subject: [PATCH 031/118] ASoC: Add support for PCM5102A codec +Subject: [PATCH 031/178] ASoC: Add support for PCM5102A codec Some definitions to support the PCM5102A codec by Texas Instruments. @@ -107877,10 +107876,10 @@ index 0000000..126f1e9 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From 48a6b3d8b1d5d812ef4b2be426ab23a887a4b42a Mon Sep 17 00:00:00 2001 +From f7ad1224dc9fe74e3f527adb1721b3f180a5756e Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:04:54 +0100 -Subject: [PATCH 032/118] BCM2708: Add I2S support to board file +Subject: [PATCH 032/178] BCM2708: Add I2S support to board file Adds the required initializations for I2S to the board file of mach-bcm2708. @@ -107935,10 +107934,10 @@ index a740344..dca28ad 100644 struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); -From 01fa110fc4fda05b5a4378013920b073a28d1e25 Mon Sep 17 00:00:00 2001 +From 2f4ed18d39152153e86968c514d7e2fc8484d7ba Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 033/118] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 033/178] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -108087,10 +108086,10 @@ index 0000000..4b70b45 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); +MODULE_LICENSE("GPL v2"); -From 026b8407f88bca1b92525494b48e6d7eccda4eed Mon Sep 17 00:00:00 2001 +From cf362d5ffe0ed77f985e865fa7321fad69265e7f Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:21:34 +0100 -Subject: [PATCH 034/118] BCM2708: Add HifiBerry DAC to board file +Subject: [PATCH 034/178] BCM2708: Add HifiBerry DAC to board file This adds the initalization of the HifiBerry DAC to the mach-bcm2708 board file. @@ -108138,10 +108137,10 @@ index dca28ad..50d4991 100644 struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); -From 263026baaed37ff82f9a4ab3f1e20188a59ef2eb Mon Sep 17 00:00:00 2001 +From e239c52b9461ad8edc7a98bb9821bfe5dedd3a20 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Mon, 2 Dec 2013 20:28:22 +0100 -Subject: [PATCH 035/118] BCM2708: Add I2S and DMA support to default config +Subject: [PATCH 035/178] BCM2708: Add I2S and DMA support to default config This commit adds several modules that are needed for I2S support for the Raspberry Pi to the defconfig. @@ -108176,10 +108175,10 @@ index 3f99687..dfd98df 100644 CONFIG_UIO_PDRV_GENIRQ=m CONFIG_STAGING=y -From 57616aa4ecad145cacb1468c0eb89e02d9c10593 Mon Sep 17 00:00:00 2001 +From c4870cd9209463810e77ed7fd0a81417a6ce5aec Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 6 Dec 2013 20:50:28 +0100 -Subject: [PATCH 036/118] ASoC: BCM2708: Add support for RPi-DAC +Subject: [PATCH 036/178] ASoC: BCM2708: Add support for RPi-DAC This adds a machine driver for the RPi-DAC. @@ -108487,10 +108486,10 @@ index 0000000..b4eaa44 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From e59d15fa37adf8ad4f7d42d7e179a87a86b65d7f Mon Sep 17 00:00:00 2001 +From bba7b1cb221dd4a362810513d531af92a81f00fc Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 037/118] ASoC: wm8804: Implement MCLK configuration options, +Subject: [PATCH 037/178] 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 @@ -108530,10 +108529,10 @@ index 3addc5f..d060b23 100644 #define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ -From 862968c193b69c070cc28e5db4575107471eede4 Mon Sep 17 00:00:00 2001 +From d1f0698e2a3a38051931ff7bed689ad30dd4a577 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 038/118] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 038/178] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -108736,10 +108735,10 @@ index 0000000..e4f769d +MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); +MODULE_LICENSE("GPL v2"); -From 03397c6ea43eda25ddfd78c908fa2152c9fa7e8d Mon Sep 17 00:00:00 2001 +From b09084f6badfdf5f18536a18561794ac8a6e21d8 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:26:08 +0100 -Subject: [PATCH 039/118] BCM2708: Added support for HiFiBerry Digi board Board +Subject: [PATCH 039/178] BCM2708: Added support for HiFiBerry Digi board Board initalization by I2C Signed-off-by: Daniel Matuschek @@ -108786,10 +108785,10 @@ index 100c223..a57cb85 100644 bcm_register_device(&snd_rpi_dac_device); bcm_register_device(&snd_pcm1794a_codec_device); -From f7122ca88ec110b880bec3f3785e8f596aced34b Mon Sep 17 00:00:00 2001 +From 954dc35f7e529de82d15e8f303fe2a73d0d0d788 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:27:28 +0100 -Subject: [PATCH 040/118] BCM2708: Added HiFiBerry Digi configuration option It +Subject: [PATCH 040/178] BCM2708: Added HiFiBerry Digi configuration option It will be compiled as a module by default. This also includes the WM8804 driver. @@ -108811,10 +108810,10 @@ index f688da5..c9d3fac 100644 CONFIG_SND_SIMPLE_CARD=m CONFIG_SOUND_PRIME=m -From 7efd594ca5e103927d2bf0c19c6bff361179add6 Mon Sep 17 00:00:00 2001 +From 2b091c9c22b9a1cc01aa3979e3025d25a2a13353 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:36:35 +0100 -Subject: [PATCH 041/118] ASoC: wm8804: Set idle_bias_off to false Idle bias +Subject: [PATCH 041/178] ASoC: wm8804: Set idle_bias_off to false Idle bias has been change to remove warning on driver startup Signed-off-by: Daniel Matuschek @@ -108836,10 +108835,10 @@ index d060b23..d486a9d 100644 .controls = wm8804_snd_controls, .num_controls = ARRAY_SIZE(wm8804_snd_controls), -From 852c2141123d6f54a0db703f5b7c7472b64fd04b Mon Sep 17 00:00:00 2001 +From 6a048ee53b365d5bb142dff0430fa157c66e8221 Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 042/118] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 042/178] Add IQaudIO Sound Card support for Raspberry Pi --- arch/arm/configs/bcmrpi_defconfig | 1 + @@ -109049,10 +109048,10 @@ index 0000000..8d0e2ae +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); -From 4861016e7fc78b6c451241697da27b309cbdd405 Mon Sep 17 00:00:00 2001 +From 05f333305025682c7cb5f70b29f165c2a7fe7c71 Mon Sep 17 00:00:00 2001 From: Howard Mitchell Date: Fri, 28 Mar 2014 16:40:31 +0000 -Subject: [PATCH 043/118] pcm512x: Use a range macro for Volume and rename to +Subject: [PATCH 043/178] pcm512x: Use a range macro for Volume and rename to PCM. This allows limiting the output gain to avoid clipping in the @@ -109077,10 +109076,10 @@ index 640c991..b405719 100644 PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, -From b71befc2d6878ab64369272d7a91a1339a2ae004 Mon Sep 17 00:00:00 2001 +From e6d58c0582457b39b0cc47306974aeca36b85c93 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Jun 2014 13:42:01 +0100 -Subject: [PATCH 044/118] vmstat: Workaround for issue where dirty page count +Subject: [PATCH 044/178] vmstat: Workaround for issue where dirty page count goes negative See: @@ -109107,10 +109106,10 @@ index 82e7db7..f87d16d 100644 static inline void __inc_zone_page_state(struct page *page, -From 7777b35ffa6f98bcf34e29c9246a9aa0cc30898b Mon Sep 17 00:00:00 2001 +From b0e540fa161ae0e4264441754b84a064b3bc2a8d Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 20 Jun 2014 16:03:12 +0100 -Subject: [PATCH 045/118] dwc_otg: Fix various issues with root port and +Subject: [PATCH 045/178] dwc_otg: Fix various issues with root port and transaction errors Process the host port interrupts correctly (and don't trample them). @@ -109180,10 +109179,10 @@ index 4195ff2..a5566bc 100644 fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "RESET "); } -From 8078dc7763e9a514fe277bdfb9daba3490ab2b9b Mon Sep 17 00:00:00 2001 +From f3960ea24733a8e97390ca9ef8b502322037dd8f Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 20 Jun 2014 17:23:20 +0100 -Subject: [PATCH 046/118] fiq_fsm: Implement hack for Split Interrupt +Subject: [PATCH 046/178] fiq_fsm: Implement hack for Split Interrupt transactions Hubs aren't too picky about which endpoint we send Control type split @@ -109269,10 +109268,10 @@ index 130096b..68d4f3b 100644 break; } -From 59a31a7cf05f497b9e1f66fdd7bdb9a2a9ac665c Mon Sep 17 00:00:00 2001 +From 19874370022f7a8ed89305f8cf390fc12b2b7aff Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 6 Jul 2014 12:07:25 +0200 -Subject: [PATCH 047/118] spi-bcm2708: Prepare for Common Clock Framework +Subject: [PATCH 047/178] spi-bcm2708: Prepare for Common Clock Framework migration As part of migrating to use the Common Clock Framework, replace clk_enable() @@ -109317,10 +109316,10 @@ index b04a57d..349d21f 100644 free_irq(bs->irq, master); iounmap(bs->base); -From 0ffe14b3c16bb989c47f4831cca4868c0f6b4396 Mon Sep 17 00:00:00 2001 +From 053678d02351666c7649e552e41c66f72969f2a9 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 6 Jul 2014 12:09:30 +0200 -Subject: [PATCH 048/118] BCM2708: Migrate to the Common Clock Framework +Subject: [PATCH 048/178] BCM2708: Migrate to the Common Clock Framework As part of moving towards using Device Tree, the Common Clock Framework has to be used instead of the BCM2708 clock implementation. @@ -109590,10 +109589,10 @@ index 5f9d725..0000000 - unsigned long rate; -}; -From 8d4f9a3868d1e49061755e92826181d23570192a Mon Sep 17 00:00:00 2001 +From 3fb74416dce89c2d1cca6c8b02e7281f60549b19 Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:46:08 +0200 -Subject: [PATCH 049/118] BCM2708: Add core Device Tree support +Subject: [PATCH 049/178] BCM2708: Add core Device Tree support Add the bare minimum needed to boot BCM2708 from a Device Tree. @@ -109758,10 +109757,10 @@ index ef12cb8..747e27a 100644 module_param(boardrev, uint, 0644); -From 34692845b55c6cd655d66159bf39d94b54ca87f1 Mon Sep 17 00:00:00 2001 +From 1cb0ba6051288c359bcafcbd4f312cf1effa19d3 Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:47:48 +0200 -Subject: [PATCH 050/118] BCM2708: armctrl: Add IRQ Device Tree support +Subject: [PATCH 050/178] BCM2708: armctrl: Add IRQ Device Tree support Add Device Tree IRQ support for BCM2708. Usage is the same as for irq-bcm2835. @@ -109931,10 +109930,10 @@ index 96fa9b9..74bacb3 100644 return 0; } -From 1910732621efa349be125249e6c1a9c1cea26e87 Mon Sep 17 00:00:00 2001 +From f7cd15f44919db0ae1efb41d99aa98e54cfe8ddf Mon Sep 17 00:00:00 2001 From: notro Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 051/118] BCM2708: use pinctrl-bcm2835 +Subject: [PATCH 051/178] BCM2708: use pinctrl-bcm2835 Use pinctrl-bcm2835 instead of the pinctrl-bcm2708 and bcm2708_gpio combination. @@ -110011,10 +110010,10 @@ index eabba02..962e180 100644 .can_sleep = false, }; -From 289b6d5cd1ab056ca1765522d43787bb12a03144 Mon Sep 17 00:00:00 2001 +From a82c4f26a4d4a9d57e5d9e0c14283f18f36c34df Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 27 Jul 2014 20:12:58 +0200 -Subject: [PATCH 052/118] spi: bcm2708: add device tree support +Subject: [PATCH 052/178] spi: bcm2708: add device tree support Add DT support to driver and add to .dtsi file. Setup pins and spidev in .dts file. @@ -110221,10 +110220,10 @@ index 349d21f..041b5e2 100644 .probe = bcm2708_spi_probe, .remove = bcm2708_spi_remove, -From 9073e39c042cec64040e4a6616812c7b2479902d Mon Sep 17 00:00:00 2001 +From ccfcdf167873ce85e5a2605822c44213978c1e55 Mon Sep 17 00:00:00 2001 From: notro Date: Tue, 29 Jul 2014 11:04:49 +0200 -Subject: [PATCH 053/118] i2c: bcm2708: add device tree support +Subject: [PATCH 053/178] i2c: bcm2708: add device tree support Add DT support to driver and add to .dtsi file. Setup pins in .dts file. @@ -110448,10 +110447,10 @@ index 7d385a3..526129b 100644 .probe = bcm2708_i2c_probe, .remove = bcm2708_i2c_remove, -From 1adbf82d623f07899915a785cdb07da688187d82 Mon Sep 17 00:00:00 2001 +From b96bbdf88da786449ac3aeded78fcf1b8e3f746d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 14 Jul 2014 22:02:09 +0100 -Subject: [PATCH 054/118] hid: Reduce default mouse polling interval to 60Hz +Subject: [PATCH 054/178] hid: Reduce default mouse polling interval to 60Hz Reduces overhead when using X --- @@ -110487,10 +110486,10 @@ index ca6849a..4671921 100644 ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { -From a997b0ef0cdeb60899028abc06aae5b48ca928b1 Mon Sep 17 00:00:00 2001 +From f9c1949bdbc1356fc1e4780263e9e458bbfbd08f Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 24 Jul 2014 21:24:03 +0100 -Subject: [PATCH 055/118] usb: core: make overcurrent messages more prominent +Subject: [PATCH 055/178] usb: core: make overcurrent messages more prominent Hub overcurrent messages are more serious than "debug". Increase loglevel. --- @@ -110498,7 +110497,7 @@ Hub overcurrent messages are more serious than "debug". Increase loglevel. 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index b649fef..5f8d914 100644 +index 2246954..505a8d9 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4923,7 +4923,7 @@ static void port_event(struct usb_hub *hub, int port1) @@ -110511,10 +110510,10 @@ index b649fef..5f8d914 100644 USB_PORT_FEAT_C_OVER_CURRENT); msleep(100); /* Cool down */ -From a5b0d739eb6f93286969029cfa3ee33bb279c104 Mon Sep 17 00:00:00 2001 +From 96d531fdb8a4d49e4a655bfc2c268ce63c4318c6 Mon Sep 17 00:00:00 2001 From: Tim Gover Date: Tue, 22 Jul 2014 15:41:04 +0100 -Subject: [PATCH 056/118] vcsm: VideoCore shared memory service for BCM2835 +Subject: [PATCH 056/178] vcsm: VideoCore shared memory service for BCM2835 Add experimental support for the VideoCore shared memory service. This allows user processes to allocate memory from VideoCore's @@ -114848,10 +114847,10 @@ index 0000000..da1c523 +MODULE_DESCRIPTION("VideoCore SharedMemory Driver"); +MODULE_LICENSE("GPL v2"); -From 6c5861cbdfaf5127acf152713d7415af678428fd Mon Sep 17 00:00:00 2001 +From bb94b9d2326ee2c1839388d6dad813a130a305d2 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 7 Aug 2014 02:03:50 +0100 -Subject: [PATCH 057/118] Revert "ARM: dma: Use dma_pfn_offset for dma address +Subject: [PATCH 057/178] Revert "ARM: dma: Use dma_pfn_offset for dma address translation" This reverts commit 6ce0d20016925d031f1e24d64302e4c976d7cec6. @@ -114903,10 +114902,10 @@ index 85738b2..9477f09 100644 } -From b049a2290076030bcd5c9315b9f87304cd94642f Mon Sep 17 00:00:00 2001 +From b183715643cdaf45fa421d536b1c9986de2a3c24 Mon Sep 17 00:00:00 2001 From: gellert Date: Fri, 15 Aug 2014 16:35:06 +0100 -Subject: [PATCH 058/118] MMC: added alternative MMC driver +Subject: [PATCH 058/178] MMC: added alternative MMC driver --- arch/arm/configs/bcmrpi_defconfig | 2 + @@ -116613,10 +116612,10 @@ index 0000000..cefba7c +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gellert Weisz"); -From d64338c3c1c4ef960e5b31b9faeab7a7b5689cd5 Mon Sep 17 00:00:00 2001 +From 3b503ee1590687e2c5dc1d7c4d4b22a27467b707 Mon Sep 17 00:00:00 2001 From: P33M Date: Tue, 13 Jan 2015 17:12:18 +0000 -Subject: [PATCH 059/118] mmc: Disable CMD23 transfers on all cards +Subject: [PATCH 059/178] mmc: Disable CMD23 transfers on all cards Pending wire-level investigation of these types of transfers and associated errors on bcm2835-mmc, disable for now. Fallback of @@ -116642,10 +116641,10 @@ index dd1d1e0..f472082 100644 } EXPORT_SYMBOL(mmc_fixup_device); -From 3b320ff2a31672e78cb7aeeecac7137880ea7c97 Mon Sep 17 00:00:00 2001 +From ae644d83c20542d3bd0010bc75ae1f92b2847373 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 10:06:56 +0200 -Subject: [PATCH 060/118] Added support for HiFiBerry DAC+ +Subject: [PATCH 060/178] 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. @@ -116869,10 +116868,10 @@ index 0000000..c63387b +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+"); +MODULE_LICENSE("GPL v2"); -From 0f179127af3243c0b9530af0bea9ae0a0de17523 Mon Sep 17 00:00:00 2001 +From 551c3589adf01796e00547a52110eb041df5402c Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 11:09:58 +0200 -Subject: [PATCH 061/118] Added driver for HiFiBerry Amp amplifier add-on board +Subject: [PATCH 061/178] 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. @@ -117716,10 +117715,10 @@ index 0000000..8f019e0 + +#endif /* _TAS5713_H */ -From 5e11969b25049c118f95485a8b99e5295e07d594 Mon Sep 17 00:00:00 2001 +From ca454ce78774f9aafbb7dff1678fbb583a015193 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Oct 2014 11:47:53 +0100 -Subject: [PATCH 062/118] Improve __copy_to_user and __copy_from_user +Subject: [PATCH 062/178] Improve __copy_to_user and __copy_from_user performance Provide a __copy_from_user that uses memcpy. On BCM2708, use @@ -119243,10 +119242,10 @@ index 3e58d71..0622891 100644 static unsigned long noinline __clear_user_memset(void __user *addr, unsigned long n) -From ec3b66e514690a10b787219d09594daf80eb0d8a Mon Sep 17 00:00:00 2001 +From 4d936397f5e4afccd95e1f8ccd244a67a76c12de Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 1 Sep 2014 16:35:56 +0100 -Subject: [PATCH 063/118] bcm2708: Allow option card devices to be configured +Subject: [PATCH 063/178] bcm2708: Allow option card devices to be configured via DT If the kernel is built with Device Tree support, and if a DT blob @@ -119702,10 +119701,10 @@ index 2685fe4..e2c61d1 100644 static struct platform_driver bcm2835_i2s_driver = { .probe = bcm2835_i2s_probe, -From 2ec07a6d9a5407b0d368d0bb5fd2e000a86f6b89 Mon Sep 17 00:00:00 2001 +From 2259e35d7fce68051f8878bb56ebd6618ad563ee Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 12 Nov 2014 17:07:02 +0000 -Subject: [PATCH 064/118] Adding Device Tree support for some RPi audio cards +Subject: [PATCH 064/178] Adding Device Tree support for some RPi audio cards --- arch/arm/boot/dts/Makefile | 2 + @@ -120330,10 +120329,10 @@ index 126f1e9..7c6598e 100644 }; -From d03006701455ee50431b69a8b10127e86da34de5 Mon Sep 17 00:00:00 2001 +From 535a90f3b07d3e83835b9278ec3f0dec286d481b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 5 Dec 2014 17:26:26 +0000 -Subject: [PATCH 065/118] fdt: Add support for the CONFIG_CMDLINE_EXTEND option +Subject: [PATCH 065/178] fdt: Add support for the CONFIG_CMDLINE_EXTEND option --- drivers/of/fdt.c | 29 ++++++++++++++++++++++++----- @@ -120388,10 +120387,10 @@ index 2e2b6d0..badc6a3 100644 pr_debug("Command line is: %s\n", (char*)data); -From 285e7f92a730afa3b98b0675ee9b516f47a2be29 Mon Sep 17 00:00:00 2001 +From 12cba1e54b4bbf66b611ca38e8c9c7bcdd6d1a9f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 25 Nov 2014 13:39:03 +0000 -Subject: [PATCH 066/118] config: Enable device tree +Subject: [PATCH 066/178] config: Enable device tree --- arch/arm/configs/bcmrpi_defconfig | 1 + @@ -120410,10 +120409,10 @@ index 997e1f3..2cd8227 100644 CONFIG_AEABI=y CONFIG_CLEANCACHE=y -From 77da52386846b07153310362885d60732f071f12 Mon Sep 17 00:00:00 2001 +From bd79b3cae7f3752a409f50bda1c779aa28ad7770 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 16 Dec 2014 10:23:48 +0000 -Subject: [PATCH 067/118] DT: Add overrides to enable i2c0, i2c1, spi and i2s +Subject: [PATCH 067/178] DT: Add overrides to enable i2c0, i2c1, spi and i2s --- arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 10 ++++++++++ @@ -120457,10 +120456,10 @@ index d8c6d15..167b22b 100644 + }; +}; -From ac3c1ae15c81ebb4ec2387a2c0b84aa0848fb033 Mon Sep 17 00:00:00 2001 +From 67684bf7c56ac4aca5f82e857d7028fab8440a4a Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 18 Dec 2014 16:48:32 +0000 -Subject: [PATCH 068/118] lirc-rpi: Add device tree support, and a suitable +Subject: [PATCH 068/178] lirc-rpi: Add device tree support, and a suitable overlay The overlay supports DT parameters that match the old module @@ -120754,10 +120753,10 @@ index c688364..cd66ca2 100644 if (result < 0) goto exit_rpi; -From 6744225dec56543dd78ab8f4fcf65b176eb3d0b0 Mon Sep 17 00:00:00 2001 +From 9b45a42487c04bb7aa9e5706e5ae0c2e1846cca9 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 6 Jan 2015 12:06:55 +0000 -Subject: [PATCH 069/118] Fix the activity LED in DT mode +Subject: [PATCH 069/178] Fix the activity LED in DT mode Add a "leds" node to the base DTBs, and a subnode for the activity LED. You can change the LED function like this: @@ -120889,10 +120888,10 @@ index 6b36128..1b56cb5 100644 clocks { -From db4b8009f599a835105d18d34bb881beb44b1672 Mon Sep 17 00:00:00 2001 +From 85cda0001958195912f4d549961bddb38f49c476 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 15 Jan 2015 10:39:06 +0000 -Subject: [PATCH 070/118] Adding w1-gpio device tree overlays +Subject: [PATCH 070/178] Adding w1-gpio device tree overlays N.B. Requires firmware supporting multi-target overrides @@ -121002,10 +121001,10 @@ index 0000000..b3e97c2 + }; +}; -From 8dcd89fdfd239b288d8b3e060c2e3916dc57b12c Mon Sep 17 00:00:00 2001 +From 4720975144d14e7bb0e1677df39ef70c23406066 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 21 Jan 2015 22:46:02 +0000 -Subject: [PATCH 071/118] config: Enable CONFIG_PPS +Subject: [PATCH 071/178] config: Enable CONFIG_PPS --- arch/arm/configs/bcmrpi_defconfig | 3 +++ @@ -121026,10 +121025,10 @@ index 2cd8227..36aca2b 100644 CONFIG_GPIO_ARIZONA=m CONFIG_W1=m -From 572bc22d988b1a30ab3c73dfa1e7e8a949ee5e6d Mon Sep 17 00:00:00 2001 +From d1ef5c83ab7f3b068badf10b71c96675711a2d4c Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 21 Jan 2015 23:47:33 +0000 -Subject: [PATCH 072/118] config: Add CONFIG_IP_NF options +Subject: [PATCH 072/178] config: Add CONFIG_IP_NF options --- arch/arm/configs/bcmrpi_defconfig | 9 +++++++-- @@ -121076,10 +121075,10 @@ index 36aca2b..665b01e4 100644 CONFIG_BRIDGE_EBT_BROUTE=m CONFIG_BRIDGE_EBT_T_FILTER=m -From 0d1115692bc818a35c80a55306e8effa7cf8d003 Mon Sep 17 00:00:00 2001 +From 34280711120a023e5838fc3ca136648f8b0a9af9 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 12:04:59 +0000 -Subject: [PATCH 073/118] config: Restore some missing options +Subject: [PATCH 073/178] config: Restore some missing options --- arch/arm/configs/bcmrpi_defconfig | 18 ++++++++++++++++-- @@ -121164,10 +121163,10 @@ index 665b01e4..41b90b4 100644 CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_TGR192=m -From 584da5c2c92bb51d9f5385748bbd4d5f4771a5bc Mon Sep 17 00:00:00 2001 +From 5cd5f0891ef04975d173ddd983bae639e86e0032 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Fri, 23 Jan 2015 16:41:17 +0100 -Subject: [PATCH 074/118] TAS5713: return error if initialisation fails +Subject: [PATCH 074/178] TAS5713: return error if initialisation fails Existing TAS5713 driver logs errors during initialisation, but does not return an error code. Therefore even if initialisation fails, the driver will still be @@ -121234,10 +121233,10 @@ index a24c1da..9b27138 100644 return 0; } -From a7fb5ef1974a31d3c7c3bf4c91f3c260eebfd886 Mon Sep 17 00:00:00 2001 +From 1282aa10123544cfa0138a1c291e7ccb8d1f3ebb Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 14:48:55 +0000 -Subject: [PATCH 075/118] scripts/dtc: Update to upstream version with overlay +Subject: [PATCH 075/178] scripts/dtc: Update to upstream version with overlay patches --- @@ -126450,10 +126449,10 @@ index 54d4e904..d644002 100644 -#define DTC_VERSION "DTC 1.4.0-dirty" +#define DTC_VERSION "DTC 1.4.1-g36c70742" -From 4ea94c936b62e2a76d208282078ae0bfde3395d7 Mon Sep 17 00:00:00 2001 +From 235823174ef6855009c94d274e4102bc42443b5c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 15:18:03 +0000 -Subject: [PATCH 076/118] BCM2708_DT: Build the overlays as well +Subject: [PATCH 076/178] BCM2708_DT: Build the overlays as well --- arch/arm/boot/dts/Makefile | 13 +++++++++++++ @@ -126491,10 +126490,10 @@ index adaebbb..3c7f539 100644 # old build results so people don't accidentally use them. dtbs: $(addprefix $(obj)/, $(dtb-y)) -From 0e205cc53bb545c7283ac871c3b5d6b1a72af8e9 Mon Sep 17 00:00:00 2001 +From ddc5480fd84ca83d204a423d85efd2c3c2917de0 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Sun, 25 Jan 2015 19:41:06 +0100 -Subject: [PATCH 077/118] Add device tree overlay for HiFiBerry Amp/Amp+ +Subject: [PATCH 077/178] Add device tree overlay for HiFiBerry Amp/Amp+ This patch add the missing device tree file for the HiFiBerry Amp and Amp+ boards. --- @@ -126561,10 +126560,10 @@ index 0000000..2c81448 + }; +}; -From 77d636077702cd065a509c5d5b59c0c5d19e7a97 Mon Sep 17 00:00:00 2001 +From 0f7c70d27087881384cd782f91c124d568f3404b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 26 Jan 2015 09:18:24 +0000 -Subject: [PATCH 078/118] Add pps-gpio DT overlay +Subject: [PATCH 078/178] Add pps-gpio DT overlay Parameters: gpiopin= // Default 18 @@ -126627,10 +126626,10 @@ index 0000000..40bf0e1 + }; +}; -From a04646189c8eac899999e1a501d3e2393c679d05 Mon Sep 17 00:00:00 2001 +From f7e84137511d8292f3348ec46449df75f57670bc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Jan 2015 14:32:18 +0000 -Subject: [PATCH 079/118] config: Remove STRICT_DEVMEM +Subject: [PATCH 079/178] config: Remove STRICT_DEVMEM --- arch/arm/configs/bcmrpi_defconfig | 1 - @@ -126649,10 +126648,10 @@ index 41b90b4..fd7c022 100644 CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_CRYPTD=m -From 788316ba620b084e03d5ac172ff1412cd99d624e Mon Sep 17 00:00:00 2001 +From c7b1992e537ba515483e104887b8d22d4fb80f4d Mon Sep 17 00:00:00 2001 From: Serge Schneider Date: Wed, 3 Sep 2014 14:44:22 +0100 -Subject: [PATCH 080/118] I2C: Only register the I2C device for the current +Subject: [PATCH 080/178] I2C: Only register the I2C device for the current board revision --- @@ -126696,10 +126695,10 @@ index 2c6a29d..b36037b 100644 +module_param(vc_i2c_override, bool, 0644); +MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral."); -From 76c23596602a84c76afb40609496f2a6ce0c2e83 Mon Sep 17 00:00:00 2001 +From 4cf81b0a2ccbcc69b074bc27f046a1dd232c3a98 Mon Sep 17 00:00:00 2001 From: Timo Kokkonen Date: Wed, 29 Oct 2014 23:30:30 -0700 -Subject: [PATCH 081/118] Added support to reserve/enable a GPIO pin to be used +Subject: [PATCH 081/178] Added support to reserve/enable a GPIO pin to be used from pps-gpio module (LinuxPPS). Enable PPS modules in default config for RPi. @@ -126773,10 +126772,10 @@ index b36037b..762e17c 100644 module_param(vc_i2c_override, bool, 0644); MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral."); -From f06da99b103f8335d550b653728e4c9855b8e2bc Mon Sep 17 00:00:00 2001 +From 86ec5ea3f83c19428ab6c3258215b58d9f92e757 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 26 Jan 2015 15:26:10 +0000 -Subject: [PATCH 082/118] BCM2708_DT: Correct length of the peripheral space +Subject: [PATCH 082/178] BCM2708_DT: Correct length of the peripheral space --- arch/arm/boot/dts/bcm2708.dtsi | 2 +- @@ -126796,10 +126795,10 @@ index 1b56cb5..d879316 100644 intc: interrupt-controller { compatible = "brcm,bcm2708-armctrl-ic"; -From 56c9fd8b8af24b859ecedf39ed1dcbe0f35c2476 Mon Sep 17 00:00:00 2001 +From 181a7548ede06cbbc7a129c05ca4dbf5d331e95b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 28 Jan 2015 16:22:04 +0000 -Subject: [PATCH 083/118] BCM2708_DT: Add pcf8523-rtc overlay +Subject: [PATCH 083/178] BCM2708_DT: Add pcf8523-rtc overlay --- arch/arm/boot/dts/Makefile | 1 + @@ -126848,10 +126847,10 @@ index 0000000..0071f62 + }; +}; -From 7d13e3b5b6cf3dbc85925f8a09197f16c78bacb6 Mon Sep 17 00:00:00 2001 +From f1e261cb3e10f5f868384f5ce236b04f7dadb321 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Sat, 31 Jan 2015 16:07:56 +0100 -Subject: [PATCH 084/118] Add a parameter to turn off SPDIF output if no audio +Subject: [PATCH 084/178] Add a parameter to turn off SPDIF output if no audio is playing This patch adds the paramater auto_shutdown_output to the kernel module. @@ -126923,10 +126922,10 @@ index 76af8a6..b0e3d28 100644 static struct snd_soc_dai_link snd_rpi_hifiberry_digi_dai[] = { -From 62ea15f457f01c3e1a5ef7517d04da0531ec159a Mon Sep 17 00:00:00 2001 +From f94ae6c75ef2220fbdcc071ee7383cc3d90f9ec6 Mon Sep 17 00:00:00 2001 From: Joerg Hohensohn Date: Sun, 1 Feb 2015 22:08:03 +0100 -Subject: [PATCH 085/118] bugfix for 32kHz sample rate, was missing +Subject: [PATCH 085/178] bugfix for 32kHz sample rate, was missing --- sound/soc/bcm/hifiberry_digi.c | 1 + @@ -126945,10 +126944,10 @@ index b0e3d28..133d51b 100644 case 48000: case 88200: -From ee472ca7d2f42fcc59a1836b5596f04dd7f5c3f0 Mon Sep 17 00:00:00 2001 +From 01cd25824eb91095290a51b62e03929bf35aeabc Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:25:49 -0700 -Subject: [PATCH 086/118] Update ds1307 driver for device-tree support +Subject: [PATCH 086/178] Update ds1307 driver for device-tree support Signed-off-by: Ryan Coe --- @@ -126975,10 +126974,10 @@ index bb43cf7..dadd4fb 100644 .driver = { .name = "rtc-ds1307", -From b794ae3eb9d58f1c3c012858eec79ec51d62c1fc Mon Sep 17 00:00:00 2001 +From fe6a1ee3642bc7533c201c18a9e2368db2ab5b5e Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:26:03 -0700 -Subject: [PATCH 087/118] Add device-tree overlay for ds1307 +Subject: [PATCH 087/178] Add device-tree overlay for ds1307 Signed-off-by: Ryan Coe --- @@ -127028,10 +127027,10 @@ index 0000000..7d27044 + }; +}; -From 93f6cbc1cd6f0f62778809797034b495c96dec7a Mon Sep 17 00:00:00 2001 +From a6bd90dca81764d1a2c4418941da74a6da6e5812 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 1 Feb 2015 12:10:25 +0000 -Subject: [PATCH 088/118] config: Add DVB_USB_DVBSKY +Subject: [PATCH 088/178] config: Add DVB_USB_DVBSKY --- arch/arm/configs/bcmrpi_defconfig | 1 + @@ -127050,10 +127049,10 @@ index fd7c022..0453a38 100644 CONFIG_DVB_B2C2_FLEXCOP_USB=m CONFIG_DVB_AS102=m -From f7c438c6e71ea13ac879d5da1d24f61d0d519515 Mon Sep 17 00:00:00 2001 +From e629cfce47781b2f5c4413f90e9f4d65373a8025 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 7 May 2013 14:32:27 +0100 -Subject: [PATCH 089/118] Add 2709 platform for Raspberry Pi 2 +Subject: [PATCH 089/178] Add 2709 platform for Raspberry Pi 2 --- arch/arm/Kconfig | 21 + @@ -136698,10 +136697,10 @@ index a562ddf..40d27c1 100644 select SND_SOC_DMAENGINE_PCM select SND_SOC_GENERIC_DMAENGINE_PCM -From a6e7623e29c52da79b6e12cda2932362ddcb53c5 Mon Sep 17 00:00:00 2001 +From 1a8cabc097e49877216ff23673af126913df6fe9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 20 Jun 2014 17:19:27 +0100 -Subject: [PATCH 090/118] bcm2709: Simplify and strip down IRQ handler +Subject: [PATCH 090/178] bcm2709: Simplify and strip down IRQ handler --- arch/arm/include/asm/entry-macro-multi.S | 2 + @@ -136918,10 +136917,10 @@ index d08591b..101d9f1 100644 +1: get_irqnr_and_base r0, r2, r6, lr + .endm -From 84b9417dd3aa0f7d79e255dd67838522120b7ae5 Mon Sep 17 00:00:00 2001 +From dc0e06154990ac14fba037f57e8110441f3ae273 Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 24 Sep 2014 11:57:51 +0100 -Subject: [PATCH 091/118] dwc_otg: FIQ support on SMP. Set up FIQ stack and +Subject: [PATCH 091/178] dwc_otg: FIQ support on SMP. Set up FIQ stack and handler on Core 0 only. --- @@ -137051,10 +137050,10 @@ index 98e1dc5..4d8dd95 100644 otg_dev->hcd->otg_dev = otg_dev; -From 39f557623e8e34bef7ed7c7d65a4eb9d6917064a Mon Sep 17 00:00:00 2001 +From fa7bc5fafccca649beafb3a91962a677c912d720 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 26 Sep 2014 11:32:09 +0100 -Subject: [PATCH 092/118] dwc_otg: introduce fiq_fsm_spin(un|)lock() +Subject: [PATCH 092/178] dwc_otg: introduce fiq_fsm_spin(un|)lock() SMP safety for the FIQ relies on register read-modify write cycles being completed in the correct order. Several places in the DWC code modify @@ -137371,10 +137370,10 @@ index a5566bc..ee35196 100644 } -From 06a71c21fe9cd857714063cb4a3de705906b7815 Mon Sep 17 00:00:00 2001 +From 0b347edf0085491f459f21cafcd875686d166c0e Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 22 Jan 2015 11:59:41 +0000 -Subject: [PATCH 093/118] fiq_fsm: fix build on bcm2708 and bcm2709 platforms +Subject: [PATCH 093/178] fiq_fsm: fix build on bcm2708 and bcm2709 platforms --- drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 8 ++++++++ @@ -137417,10 +137416,10 @@ index 84618a5..0d2b04e 100644 /** * fiq_fsm_restart_channel() - Poke channel enable bit for a split transaction -From 0658efdd52780c380d5304e41ac2e5758710eda1 Mon Sep 17 00:00:00 2001 +From 2d3ac996d16d11d3970e623c01806bc6241ea624 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 22 Jan 2015 17:49:23 +0000 -Subject: [PATCH 094/118] dwc_otg: put some barriers back where they should be +Subject: [PATCH 094/178] dwc_otg: put some barriers back where they should be for UP --- @@ -137460,10 +137459,10 @@ index 124ac16..ac70f1d 100644 local_fiq_enable(); return 0; -From 961c437b9a119bea0dd2777b22f266a456749d4b Mon Sep 17 00:00:00 2001 +From 96a5b7b5116449a0b15165194e80bd0e9740a315 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 22 Jan 2015 18:02:44 +0000 -Subject: [PATCH 095/118] mach_bcm2709: Add Mailbox resources to USB driver +Subject: [PATCH 095/178] mach_bcm2709: Add Mailbox resources to USB driver --- arch/arm/mach-bcm2709/bcm2709.c | 10 ++++++++++ @@ -137491,10 +137490,10 @@ index a1058ad..5d73b73 100644 -From b8f0397ee613e004741de965ece808acd399cc14 Mon Sep 17 00:00:00 2001 +From 319e3d3a1df0aa0ee2201c7dcdecd9ff24abf858 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 22 Jan 2015 18:45:23 +0000 -Subject: [PATCH 096/118] bcm2709/dwc_otg: Setup FIQ on core 1 if >1 core +Subject: [PATCH 096/178] bcm2709/dwc_otg: Setup FIQ on core 1 if >1 core active --- @@ -137557,10 +137556,10 @@ index 4d8dd95..1d28459 100644 otg_dev->hcd->otg_dev = otg_dev; hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd); -From 57da2f0f4aeb02cc6ac3af4e69a5d333e06ff121 Mon Sep 17 00:00:00 2001 +From 8f79b718b6e7e84acc529f28fc590dc15bb7a7bb Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 26 Jan 2015 17:40:22 +0000 -Subject: [PATCH 097/118] bcm2709: Port pps-gpio and i2c patches +Subject: [PATCH 097/178] bcm2709: Port pps-gpio and i2c patches --- arch/arm/mach-bcm2709/bcm2709.c | 41 +++++++++++++++++++++++++++++++++++++++-- @@ -137651,10 +137650,10 @@ index 5d73b73..f009aeb 100644 +module_param(vc_i2c_override, bool, 0644); +MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral."); -From 3d8ea1f8c634e9837d65b2cc5478b423f67275cb Mon Sep 17 00:00:00 2001 +From 4b69688192fd7760cd59bc19113865d5702922bc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 28 Jan 2015 17:57:23 +0000 -Subject: [PATCH 098/118] bcm2709: Also accept the 2708 machine ID +Subject: [PATCH 098/178] bcm2709: Also accept the 2708 machine ID --- arch/arm/mach-bcm2709/bcm2709.c | 13 +++++++++++++ @@ -137685,10 +137684,10 @@ index f009aeb..7e3affd 100644 module_param(serial, uint, 0644); module_param(uart_clock, uint, 0644); -From 1c927de4d2e49c5040d541cc260d96ed2087e940 Mon Sep 17 00:00:00 2001 +From 564bd7d5fc4e93139fdcb174e29a6082be731b69 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 2 Feb 2015 12:45:07 +0000 -Subject: [PATCH 099/118] BCM2709_DT: Fix bad merge +Subject: [PATCH 099/178] BCM2709_DT: Fix bad merge --- arch/arm/boot/dts/Makefile | 25 +++++++++++++------------ @@ -137731,10 +137730,10 @@ index 605ed38..8f76444 100644 dtb-$(CONFIG_ARCH_BCM_5301X) += bcm4708-netgear-r6250.dtb -From dc541a13732815e5b93c474f1a77eb283a80011d Mon Sep 17 00:00:00 2001 +From 63866d6c47b36556ecba2d22ec7aec86f4725e75 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Tue, 3 Feb 2015 07:15:19 +0100 -Subject: [PATCH 100/118] HiFiBerry Amp: fix device-tree problems +Subject: [PATCH 100/178] HiFiBerry Amp: fix device-tree problems Some code to load the driver based on device-tree-overlays was missing. This is added by this patch. --- @@ -137788,10 +137787,10 @@ index 1e87ee0..5903915 100644 .probe = snd_rpi_hifiberry_amp_probe, .remove = snd_rpi_hifiberry_amp_remove, -From 90e80ea7a2c6d0d4a2fd28bcbddb2a1ada3e315b Mon Sep 17 00:00:00 2001 +From 54b112c667b0e762a3c345e3f73004f2d0ce6b1e Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 3 Feb 2015 11:41:38 +0000 -Subject: [PATCH 101/118] BCM270x_DT: Add i2c0_baudrate and i2c1_baudrate +Subject: [PATCH 101/178] BCM270x_DT: Add i2c0_baudrate and i2c1_baudrate parameters --- @@ -137840,10 +137839,10 @@ index 0cdff31..63d3da4 100644 act_led_gpio = <&act_led>,"gpios:4"; act_led_activelow = <&act_led>,"gpios:8"; -From 06c7f1fb387c0905749bb3e53bdad25fca2418d5 Mon Sep 17 00:00:00 2001 +From 15ebab0ec79a1c839463d2281830d80f92ad5f2a Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 4 Feb 2015 10:02:24 +0000 -Subject: [PATCH 102/118] pinctrl-bcm2835: bcm2835_gpio_direction_output must +Subject: [PATCH 102/178] pinctrl-bcm2835: bcm2835_gpio_direction_output must set the value --- @@ -137871,10 +137870,10 @@ index 962e180..42a4fd5 100644 static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -From e326bc4b7f77b47002032078c31d386bbb5d8067 Mon Sep 17 00:00:00 2001 +From b970b5a159a9bd4d74d51404a00352c4ec018f1b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 4 Feb 2015 12:59:36 +0000 -Subject: [PATCH 103/118] w1-gpio: Sort out the pullup/parasitic power tangle +Subject: [PATCH 103/178] w1-gpio: Sort out the pullup/parasitic power tangle --- arch/arm/boot/dts/w1-gpio-overlay.dts | 4 +++- @@ -138047,10 +138046,10 @@ index d58594a..feae942 100644 unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; -From 263ce080f1c8ad56a6f1ead1db42c4b33c37dc3b Mon Sep 17 00:00:00 2001 +From e4d09ecf5f1a0673652ea451a7df471e1c8a14b4 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 4 Feb 2015 20:35:02 +0000 -Subject: [PATCH 104/118] config: Add USBIP +Subject: [PATCH 104/178] config: Add USBIP --- arch/arm/configs/bcm2709_defconfig | 4 ++++ @@ -138094,10 +138093,10 @@ index 0453a38..81c4387 100644 CONFIG_USB_SERIAL_GENERIC=y CONFIG_USB_SERIAL_AIRCABLE=m -From ddd9c99196e26e2f844cdc1ab0c1c3cc7fe8d62b Mon Sep 17 00:00:00 2001 +From 820ee7680dfddcfc297ae4e27a20536756225f5a Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 4 Feb 2015 12:16:50 +0000 -Subject: [PATCH 105/118] dwc_otg: fixup read-modify-write in critical paths +Subject: [PATCH 105/178] dwc_otg: fixup read-modify-write in critical paths Be more careful about read-modify-write on registers that the FIQ also touches. @@ -138227,10 +138226,10 @@ index 17d3030..acd0dd7 100644 } } -From 2b8ff76e2295fb644f2af2a2035c060faef95857 Mon Sep 17 00:00:00 2001 +From 4b9a5ac7ca8558595f54f5f5a1b5a8fc87597afb Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 5 Feb 2015 14:05:35 +0000 -Subject: [PATCH 106/118] BCM2709_DT: Set the "always-on" flag for the timer to +Subject: [PATCH 106/178] BCM2709_DT: Set the "always-on" flag for the timer to enable high res mode --- @@ -138250,10 +138249,10 @@ index c7e975c..220866e 100644 cpus: cpus { -From d4f28ea0d00fa433d0381a00eb1004cd7443b9aa Mon Sep 17 00:00:00 2001 +From f3c0f47504874d981b6da3d9ae0157cac7644538 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 5 Feb 2015 16:01:44 +0000 -Subject: [PATCH 107/118] i2c_bcm2708: Fix clock reference counting +Subject: [PATCH 107/178] i2c_bcm2708: Fix clock reference counting --- drivers/i2c/busses/i2c-bcm2708.c | 12 ++++++++++-- @@ -138301,10 +138300,10 @@ index 526129b..fda59ba 100644 kfree(bi); -From 76e8732707af010574a877b3168bcc6576c9dcbc Mon Sep 17 00:00:00 2001 +From 17a04965be465e75c95706c05bc86aa361e53ab7 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 Feb 2015 09:06:55 +0000 -Subject: [PATCH 108/118] BCM270x_DT: Rename the activity LED back to the +Subject: [PATCH 108/178] BCM270x_DT: Rename the activity LED back to the prosaic "led0" --- @@ -138339,10 +138338,10 @@ index 220866e..fee2053 100644 }; }; -From 058847567ff07b66610274a7203748b994fc3220 Mon Sep 17 00:00:00 2001 +From 8759a1bd1b7560f9e1aa2b91d2f56eb4031e19b8 Mon Sep 17 00:00:00 2001 From: Byron Bradley Date: Fri, 6 Feb 2015 14:19:41 +0000 -Subject: [PATCH 109/118] Add device-tree overlay for pcf2127 +Subject: [PATCH 109/178] Add device-tree overlay for pcf2127 Signed-off-by: Byron Bradley --- @@ -138392,10 +138391,10 @@ index 0000000..01fc81d + }; +}; -From e9545fffdfb122a5903137082454be921c78ca7c Mon Sep 17 00:00:00 2001 +From 4879ab3075c11c66c7833d175370935d4a509db4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 Feb 2015 13:50:57 +0000 -Subject: [PATCH 110/118] BCM270x_DT: Add pwr_led, and the required "input" +Subject: [PATCH 110/178] BCM270x_DT: Add pwr_led, and the required "input" trigger The "input" trigger makes the associated GPIO an input. This is to support @@ -138658,10 +138657,10 @@ index 0000000..2ca2b98 +MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\""); +MODULE_LICENSE("GPL"); -From 9915602a4592d25aadd17ad8d228f8a62bb3ddfd Mon Sep 17 00:00:00 2001 +From f68d615ac864c091412ce0aac483795669239733 Mon Sep 17 00:00:00 2001 From: android Date: Mon, 25 Aug 2014 13:18:21 +0100 -Subject: [PATCH 111/118] BCM2708_VCIO : Add automatic creation of device node +Subject: [PATCH 111/178] BCM2708_VCIO : Add automatic creation of device node --- arch/arm/mach-bcm2708/vcio.c | 12 +++++++++++- @@ -138743,10 +138742,10 @@ index 5e43e85..700bff4 100644 } -From ff835fe6472dcfc8206ef3bec91f7bf270baa29f Mon Sep 17 00:00:00 2001 +From d99bf4819d11c1dc97c975a9a11c1915a6d415b3 Mon Sep 17 00:00:00 2001 From: jeanleflambeur Date: Sun, 1 Feb 2015 12:35:38 +0100 -Subject: [PATCH 112/118] Fix grabbing lock from atomic context in i2c driver +Subject: [PATCH 112/178] Fix grabbing lock from atomic context in i2c driver 2 main changes: - check for timeouts in the bcm2708_bsc_setup function as indicated by this comment: @@ -138965,10 +138964,10 @@ index fda59ba..81e9374 100644 dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n", pdev->id, (unsigned long)regs->start, irq, baudrate); -From 84dee9c2f466e4c379371723f34ff8a9bf7cbc51 Mon Sep 17 00:00:00 2001 +From 0ffa7e36f244c46958f85f5e63e31826747ec4d2 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 8 Feb 2015 11:30:07 +0000 -Subject: [PATCH 113/118] config: Add ENC28J60 SPI ethernet module +Subject: [PATCH 113/178] config: Add ENC28J60 SPI ethernet module --- arch/arm/configs/bcm2709_defconfig | 1 + @@ -139000,10 +138999,10 @@ index 3b09de9..9303cfb 100644 CONFIG_PPP=m CONFIG_PPP_BSDCOMP=m -From 8a270a4b0035dc23b93fec16b46ae702b5e18eb2 Mon Sep 17 00:00:00 2001 +From 7bbc2246f034d0dbd8b96509067b24b26670e711 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 8 Feb 2015 15:02:47 +0000 -Subject: [PATCH 114/118] config: Enable IP_NF_TARGET_CLUSTERIP +Subject: [PATCH 114/178] config: Enable IP_NF_TARGET_CLUSTERIP --- arch/arm/configs/bcm2709_defconfig | 1 + @@ -139035,10 +139034,10 @@ index 9303cfb..13d0461 100644 CONFIG_IP_NF_TARGET_TTL=m CONFIG_IP_NF_RAW=m -From e8b3758e9e77f1fb24fd8e1cc2e03aa07d0467f2 Mon Sep 17 00:00:00 2001 +From 3fa9b8db3e88af0bc64fe7e8f4848b044c0b833b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 8 Feb 2015 17:16:15 +0000 -Subject: [PATCH 115/118] config: Add VIDEO_EM28XX_V4L2 +Subject: [PATCH 115/178] config: Add VIDEO_EM28XX_V4L2 --- arch/arm/configs/bcm2709_defconfig | 1 + @@ -139070,37 +139069,10 @@ index 13d0461..898ebd2 100644 CONFIG_VIDEO_EM28XX_DVB=m CONFIG_V4L_PLATFORM_DRIVERS=y -From 1361a58ed67435a95171a0046ba90b708bdb44b1 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 8 Feb 2015 13:17:00 +0000 -Subject: [PATCH 116/118] ntp: Patch to fix false positives on 32bit systems - -See: https://bugzilla.kernel.org/show_bug.cgi?id=92481 ---- - kernel/time/ntp.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c -index 28bf91c..242774d 100644 ---- a/kernel/time/ntp.c -+++ b/kernel/time/ntp.c -@@ -634,9 +634,9 @@ int ntp_validate_timex(struct timex *txc) - return -EPERM; - - if (txc->modes & ADJ_FREQUENCY) { -- if (LONG_MIN / PPM_SCALE > txc->freq) -+ if (LLONG_MIN / PPM_SCALE > txc->freq) - return -EINVAL; -- if (LONG_MAX / PPM_SCALE < txc->freq) -+ if (LLONG_MAX / PPM_SCALE < txc->freq) - return -EINVAL; - } - - -From 086127cc3f5fa6818a993965f9c753ede3a569da Mon Sep 17 00:00:00 2001 +From 75dc915aadd0a9101ec9e0d847fd5abe6d7e4ea9 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 12 Feb 2015 11:20:00 +0000 -Subject: [PATCH 118/118] fiq_fsm: Falling out of the state machine isn't fatal +Subject: [PATCH 117/178] fiq_fsm: Falling out of the state machine isn't fatal This edge case can be hit if the port is disabled while the FIQ is in the middle of a transaction. Make the effects less severe. @@ -139169,3 +139141,14793 @@ index 6266661..8a31562 100644 } /** Handles interrupt for a specific Host Channel */ + +From db6838433d9f142e5fdefe276bc56685067b0536 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 25 Feb 2015 17:14:57 +0000 +Subject: [PATCH 118/178] perf: Add support for performance counter interrupt + and enable in DT + +--- + arch/arm/boot/dts/bcm2708.dtsi | 4 ++++ + arch/arm/boot/dts/bcm2709.dtsi | 5 +++++ + arch/arm/mach-bcm2709/armctrl.c | 6 +++++- + 3 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/bcm2708.dtsi b/arch/arm/boot/dts/bcm2708.dtsi +index aeeabae..0713a1ed 100644 +--- a/arch/arm/boot/dts/bcm2708.dtsi ++++ b/arch/arm/boot/dts/bcm2708.dtsi +@@ -80,6 +80,10 @@ + leds: leds { + compatible = "gpio-leds"; + }; ++ ++ arm-pmu { ++ compatible = "arm,arm1176-pmu"; ++ }; + }; + + clocks { +diff --git a/arch/arm/boot/dts/bcm2709.dtsi b/arch/arm/boot/dts/bcm2709.dtsi +index 6986455..34d2226 100644 +--- a/arch/arm/boot/dts/bcm2709.dtsi ++++ b/arch/arm/boot/dts/bcm2709.dtsi +@@ -80,6 +80,11 @@ + leds: leds { + compatible = "gpio-leds"; + }; ++ ++ arm-pmu { ++ compatible = "arm,cortex-a7-pmu"; ++ interrupts = <3 9>; ++ }; + }; + + clocks { +diff --git a/arch/arm/mach-bcm2709/armctrl.c b/arch/arm/mach-bcm2709/armctrl.c +index 6e3f0f2ff..fc6cb8b 100644 +--- a/arch/arm/mach-bcm2709/armctrl.c ++++ b/arch/arm/mach-bcm2709/armctrl.c +@@ -76,6 +76,8 @@ static void armctrl_mask_irq(struct irq_data *d) + } else if (d->irq >= ARM_IRQ1_BASE && d->irq < ARM_IRQ_LOCAL_BASE) { + unsigned int data = (unsigned int)irq_get_chip_data(d->irq); + writel(1 << (data & 0x1f), __io_address(disables[(data >> 5) & 0x3])); ++ } else if (d->irq == INTERRUPT_ARM_LOCAL_PMU_FAST) { ++ writel(0xf, __io_address(ARM_LOCAL_PM_ROUTING_CLR)); + } else { printk("%s: %d\n", __func__, d->irq); BUG(); } + } + +@@ -119,6 +121,8 @@ static void armctrl_unmask_irq(struct irq_data *d) + } else if (d->irq >= ARM_IRQ1_BASE && d->irq < ARM_IRQ_LOCAL_BASE) { + unsigned int data = (unsigned int)irq_get_chip_data(d->irq); + writel(1 << (data & 0x1f), __io_address(enables[(data >> 5) & 0x3])); ++ } else if (d->irq == INTERRUPT_ARM_LOCAL_PMU_FAST) { ++ writel(0xf, __io_address(ARM_LOCAL_PM_ROUTING_SET)); + } else { printk("%s: %d\n", __func__, d->irq); BUG(); } + } + +@@ -145,7 +149,7 @@ static int armctrl_xlate(struct irq_domain *d, struct device_node *ctrlr, + if (WARN_ON(intspec[0] == 0 && intspec[1] >= NR_IRQS_BANK0)) + return -EINVAL; + +- if (WARN_ON(intspec[0] == 3 && intspec[1] > 3 && intspec[1] != 5)) ++ if (WARN_ON(intspec[0] == 3 && intspec[1] > 3 && intspec[1] != 5 && intspec[1] != 9)) + return -EINVAL; + + if (intspec[0] == 0) + +From 86f8202fe3e53996cd888dc2f2d0bf4820dc2170 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Thu, 5 Mar 2015 18:08:05 +0000 +Subject: [PATCH 119/178] bcm2709: Increase the spare/free IRQs to match + bcm2708 + +--- + arch/arm/mach-bcm2709/include/mach/irqs.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/mach-bcm2709/include/mach/irqs.h b/arch/arm/mach-bcm2709/include/mach/irqs.h +index 3a883d2..d301f06c 100644 +--- a/arch/arm/mach-bcm2709/include/mach/irqs.h ++++ b/arch/arm/mach-bcm2709/include/mach/irqs.h +@@ -217,9 +217,9 @@ + #define FIQ_IRQS (128) + #define GPIO_IRQ_START (HARD_IRQS + FIQ_IRQS) + #define GPIO_IRQS (32*5) +-#define SPARE_ALLOC_IRQS 32 ++#define SPARE_ALLOC_IRQS 64 + #define BCM2708_ALLOC_IRQS (HARD_IRQS+FIQ_IRQS+GPIO_IRQS+SPARE_ALLOC_IRQS) +-#define FREE_IRQS 32 ++#define FREE_IRQS 128 + #define NR_IRQS (BCM2708_ALLOC_IRQS+FREE_IRQS) + + #endif /* _BCM2708_IRQS_H_ */ + +From 7e6686b0b8cbd9fe1a9904c0bb98e4b9fb320ad3 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 18 Feb 2015 10:40:28 +0000 +Subject: [PATCH 120/178] vc_cma: Make the vc_cma area the default contiguous + DMA area + +--- + drivers/char/broadcom/vc_cma/vc_cma.c | 98 ++++++++++++++++++++++++++--------- + 1 file changed, 73 insertions(+), 25 deletions(-) + +diff --git a/drivers/char/broadcom/vc_cma/vc_cma.c b/drivers/char/broadcom/vc_cma/vc_cma.c +index a635f9f..bd64317 100644 +--- a/drivers/char/broadcom/vc_cma/vc_cma.c ++++ b/drivers/char/broadcom/vc_cma/vc_cma.c +@@ -58,6 +58,8 @@ + #define LOG_DBG(fmt, ...) \ + if (vc_cma_debug) \ + printk(KERN_INFO fmt "\n", ##__VA_ARGS__) ++#define LOG_INFO(fmt, ...) \ ++ printk(KERN_INFO fmt "\n", ##__VA_ARGS__) + #define LOG_ERR(fmt, ...) \ + printk(KERN_ERR fmt "\n", ##__VA_ARGS__) + +@@ -120,6 +122,10 @@ unsigned int vc_cma_chunks; + unsigned int vc_cma_chunks_used; + unsigned int vc_cma_chunks_reserved; + ++ ++void *vc_cma_dma_alloc; ++unsigned int vc_cma_dma_size; ++ + static int in_loud_error; + + unsigned int vc_cma_reserve_total; +@@ -198,8 +204,17 @@ void vc_cma_reserve(void) + * size from the end of memory + */ + if (vc_cma_size) { +- if (dma_declare_contiguous(NULL /*&vc_cma_device.dev*/, vc_cma_size, ++ if (dma_declare_contiguous(&vc_cma_device.dev, vc_cma_size, + vc_cma_base, 0) == 0) { ++ if (!dev_get_cma_area(NULL)) { ++ /* There is no default CMA area - make this ++ the default */ ++ struct cma *vc_cma_area = dev_get_cma_area( ++ &vc_cma_device.dev); ++ dma_contiguous_set_default(vc_cma_area); ++ LOG_INFO("vc_cma_reserve - using vc_cma as " ++ "the default contiguous DMA area"); ++ } + } else { + LOG_ERR("vc_cma: dma_declare_contiguous(%x,%x) failed", + vc_cma_size, (unsigned int)vc_cma_base); +@@ -309,6 +324,9 @@ static int vc_cma_show_info(struct seq_file *m, void *v) + seq_printf(m, " PID %5d: %d bytes\n", user->pid, + user->reserve); + } ++ seq_printf(m, " dma_alloc : %p (%d pages)\n", ++ vc_cma_dma_alloc ? page_address(vc_cma_dma_alloc) : 0, ++ vc_cma_dma_size); + + seq_printf(m, "\n"); + +@@ -348,31 +366,33 @@ static int vc_cma_proc_write(struct file *file, + #define FREE_STR "free" + #define DEBUG_STR "debug" + #define RESERVE_STR "reserve" ++#define DMA_ALLOC_STR "dma_alloc" ++#define DMA_FREE_STR "dma_free" + if (strncmp(input_str, ALLOC_STR, strlen(ALLOC_STR)) == 0) { +- int size; ++ int alloc_size; + char *p = input_str + strlen(ALLOC_STR); + + while (*p == ' ') + p++; +- size = memparse(p, NULL); +- LOG_ERR("/proc/vc-cma: alloc %d", size); +- if (size) ++ alloc_size = memparse(p, NULL); ++ LOG_INFO("/proc/vc-cma: alloc %d", alloc_size); ++ if (alloc_size) + send_vc_msg(VC_CMA_MSG_REQUEST_FREE, +- size / VC_CMA_CHUNK_SIZE, 0); ++ alloc_size / VC_CMA_CHUNK_SIZE, 0); + else + LOG_ERR("invalid size '%s'", p); + rc = size; + } else if (strncmp(input_str, FREE_STR, strlen(FREE_STR)) == 0) { +- int size; ++ int alloc_size; + char *p = input_str + strlen(FREE_STR); + + while (*p == ' ') + p++; +- size = memparse(p, NULL); +- LOG_ERR("/proc/vc-cma: free %d", size); +- if (size) ++ alloc_size = memparse(p, NULL); ++ LOG_INFO("/proc/vc-cma: free %d", alloc_size); ++ if (alloc_size) + send_vc_msg(VC_CMA_MSG_REQUEST_ALLOC, +- size / VC_CMA_CHUNK_SIZE, 0); ++ alloc_size / VC_CMA_CHUNK_SIZE, 0); + else + LOG_ERR("invalid size '%s'", p); + rc = size; +@@ -384,18 +404,46 @@ static int vc_cma_proc_write(struct file *file, + vc_cma_debug = 1; + else if ((strcmp(p, "off") == 0) || (strcmp(p, "0") == 0)) + vc_cma_debug = 0; +- LOG_ERR("/proc/vc-cma: debug %s", vc_cma_debug ? "on" : "off"); ++ LOG_INFO("/proc/vc-cma: debug %s", vc_cma_debug ? "on" : "off"); + rc = size; + } else if (strncmp(input_str, RESERVE_STR, strlen(RESERVE_STR)) == 0) { +- int size; ++ int alloc_size; + int reserved; + char *p = input_str + strlen(RESERVE_STR); + while (*p == ' ') + p++; +- size = memparse(p, NULL); ++ alloc_size = memparse(p, NULL); + +- reserved = vc_cma_set_reserve(size, current->tgid); ++ reserved = vc_cma_set_reserve(alloc_size, current->tgid); + rc = (reserved >= 0) ? size : reserved; ++ } else if (strncmp(input_str, DMA_ALLOC_STR, strlen(DMA_ALLOC_STR)) == 0) { ++ int alloc_size; ++ char *p = input_str + strlen(DMA_ALLOC_STR); ++ while (*p == ' ') ++ p++; ++ alloc_size = memparse(p, NULL); ++ ++ if (vc_cma_dma_alloc) { ++ dma_release_from_contiguous(NULL, vc_cma_dma_alloc, ++ vc_cma_dma_size); ++ vc_cma_dma_alloc = NULL; ++ vc_cma_dma_size = 0; ++ } ++ vc_cma_dma_alloc = dma_alloc_from_contiguous(NULL, alloc_size, 0); ++ vc_cma_dma_size = (vc_cma_dma_alloc ? alloc_size : 0); ++ if (vc_cma_dma_alloc) ++ LOG_INFO("dma_alloc(%d pages) -> %p", alloc_size, page_address(vc_cma_dma_alloc)); ++ else ++ LOG_ERR("dma_alloc(%d pages) failed", alloc_size); ++ rc = size; ++ } else if (strncmp(input_str, DMA_FREE_STR, strlen(DMA_FREE_STR)) == 0) { ++ if (vc_cma_dma_alloc) { ++ dma_release_from_contiguous(NULL, vc_cma_dma_alloc, ++ vc_cma_dma_size); ++ vc_cma_dma_alloc = NULL; ++ vc_cma_dma_size = 0; ++ } ++ rc = size; + } + + out: +@@ -526,7 +574,7 @@ static int vc_cma_alloc_chunks(int num_chunks, struct cma_msg *reply) + uint8_t *chunk_addr; + size_t chunk_size = PAGES_PER_CHUNK << PAGE_SHIFT; + +- chunk = dma_alloc_from_contiguous(NULL /*&vc_cma_device.dev*/, ++ chunk = dma_alloc_from_contiguous(&vc_cma_device.dev, + PAGES_PER_CHUNK, + VC_CMA_CHUNK_ORDER); + if (!chunk) +@@ -548,7 +596,7 @@ static int vc_cma_alloc_chunks(int num_chunks, struct cma_msg *reply) + "bad SPARSEMEM configuration?", + __func__, (unsigned int)page_to_phys(chunk), + vc_cma_base, vc_cma_base + vc_cma_size - 1); +- LOG_ERR("%s: dev->cma_area = %p\n", __func__, ++ LOG_ERR("%s: dev->cma_area = %p", __func__, + (void*)0/*vc_cma_device.dev.cma_area*/); + LOG_ERR("%s: ===============================", + __func__); +@@ -672,7 +720,7 @@ static int cma_worker_proc(void *param) + } + + if (!dma_release_from_contiguous +- (NULL /*&vc_cma_device.dev*/, page, ++ (&vc_cma_device.dev, page, + PAGES_PER_CHUNK)) { + LOG_ERR + ("CMA_MSG_FREE - failed to " +@@ -1023,12 +1071,12 @@ static int vc_cma_init(void) + if (!check_cma_config()) + goto out_release; + +- printk(KERN_INFO "vc-cma: Videocore CMA driver\n"); +- printk(KERN_INFO "vc-cma: vc_cma_base = 0x%08x\n", vc_cma_base); +- printk(KERN_INFO "vc-cma: vc_cma_size = 0x%08x (%u MiB)\n", +- vc_cma_size, vc_cma_size / (1024 * 1024)); +- printk(KERN_INFO "vc-cma: vc_cma_initial = 0x%08x (%u MiB)\n", +- vc_cma_initial, vc_cma_initial / (1024 * 1024)); ++ LOG_INFO("vc-cma: Videocore CMA driver"); ++ LOG_INFO("vc-cma: vc_cma_base = 0x%08x", vc_cma_base); ++ LOG_INFO("vc-cma: vc_cma_size = 0x%08x (%u MiB)", ++ vc_cma_size, vc_cma_size / (1024 * 1024)); ++ LOG_INFO("vc-cma: vc_cma_initial = 0x%08x (%u MiB)", ++ vc_cma_initial, vc_cma_initial / (1024 * 1024)); + + vc_cma_base_page = phys_to_page(vc_cma_base); + +@@ -1038,7 +1086,7 @@ static int vc_cma_init(void) + for (vc_cma_chunks_used = 0; + vc_cma_chunks_used < chunks_needed; vc_cma_chunks_used++) { + struct page *chunk; +- chunk = dma_alloc_from_contiguous(NULL /*&vc_cma_device.dev*/, ++ chunk = dma_alloc_from_contiguous(&vc_cma_device.dev, + PAGES_PER_CHUNK, + VC_CMA_CHUNK_ORDER); + if (!chunk) + +From 050710dbbb4f2a024afeee40c3d92d40c6f97a74 Mon Sep 17 00:00:00 2001 +From: "Yann E. MORIN" +Date: Wed, 18 Feb 2015 12:46:07 +0100 +Subject: [PATCH 121/178] char/vc_cma: fix build with LPAE enabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +LPAE is required for virtualisation on ARM. However, enabling LPAE +results in an unbuildable configuration, due to improper formats +used in vc_cma: + + CC drivers/char/broadcom/vc_cma/vc_cma.o + drivers/char/broadcom/vc_cma/vc_cma.c: In function ‘vc_cma_alloc_chunks’: + drivers/char/broadcom/vc_cma/vc_cma.c:547:4: error: format ‘%x’ expects argument + of type ‘unsigned int’, but argument 4 has type ‘phys_addr_t’ [-Werror=format=] + LOG_ERR("%s: chunk phys %x, vc_cma %x-%x - " + ^ + drivers/char/broadcom/vc_cma/vc_cma.c:547:4: error: format ‘%x’ expects argument + of type ‘unsigned int’, but argument 5 has type ‘phys_addr_t’ [-Werror=format=] + drivers/char/broadcom/vc_cma/vc_cma.c: In function ‘cma_worker_proc’: + drivers/char/broadcom/vc_cma/vc_cma.c:677:7: error: format ‘%x’ expects argument + of type ‘unsigned int’, but argument 3 has type ‘long long unsigned int’ [-Werror=format=] + LOG_ERR + ^ + drivers/char/broadcom/vc_cma/vc_cma.c: In function ‘vc_cma_init’: + drivers/char/broadcom/vc_cma/vc_cma.c:1027:2: error: format ‘%x’ expects argument + of type ‘unsigned int’, but argument 2 has type ‘phys_addr_t’ [-Werror=format=] + printk(KERN_INFO "vc-cma: vc_cma_base = 0x%08x\n", vc_cma_base); + ^ + cc1: all warnings being treated as errors + make[6]: *** [drivers/char/broadcom/vc_cma/vc_cma.o] Error 1 + +As explained in Documentation/printk-formats.txt, printing a physical +address phys_addr_t should be done using the %pa[p] format, which +expects a "reference" to the value. + +Even if virtualisation is currently not possible (due to the bootloader +starting the kernel in SVC, not HYP, mode), fix the printk formats +nonetheless, it will anyway give better-looking code! ;-) + +Signed-off-by: "Yann E. MORIN" +--- + drivers/char/broadcom/vc_cma/vc_cma.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/char/broadcom/vc_cma/vc_cma.c b/drivers/char/broadcom/vc_cma/vc_cma.c +index bd64317..07b31a7 100644 +--- a/drivers/char/broadcom/vc_cma/vc_cma.c ++++ b/drivers/char/broadcom/vc_cma/vc_cma.c +@@ -590,12 +590,13 @@ static int vc_cma_alloc_chunks(int num_chunks, struct cma_msg *reply) + BUG_ON(((page_to_phys(chunk) - vc_cma_base) % + VC_CMA_CHUNK_SIZE) != 0); + if (chunk_num >= vc_cma_chunks) { ++ phys_addr_t _pa = vc_cma_base + vc_cma_size - 1; + LOG_ERR("%s: ===============================", + __func__); +- LOG_ERR("%s: chunk phys %x, vc_cma %x-%x - " ++ LOG_ERR("%s: chunk phys %x, vc_cma %pa-%pa - " + "bad SPARSEMEM configuration?", + __func__, (unsigned int)page_to_phys(chunk), +- vc_cma_base, vc_cma_base + vc_cma_size - 1); ++ &vc_cma_base, &_pa); + LOG_ERR("%s: dev->cma_area = %p", __func__, + (void*)0/*vc_cma_device.dev.cma_area*/); + LOG_ERR("%s: ===============================", +@@ -722,11 +723,12 @@ static int cma_worker_proc(void *param) + if (!dma_release_from_contiguous + (&vc_cma_device.dev, page, + PAGES_PER_CHUNK)) { ++ phys_addr_t _pa = page_to_phys(page); + LOG_ERR + ("CMA_MSG_FREE - failed to " +- "release chunk %d (phys %x, " ++ "release chunk %d (phys %pa, " + "page %x)", chunk_num, +- page_to_phys(page), ++ &_pa, + (unsigned int)page); + } + vc_cma_chunks_used--; +@@ -1072,7 +1074,7 @@ static int vc_cma_init(void) + goto out_release; + + LOG_INFO("vc-cma: Videocore CMA driver"); +- LOG_INFO("vc-cma: vc_cma_base = 0x%08x", vc_cma_base); ++ LOG_INFO("vc-cma: vc_cma_base = %pa", &vc_cma_base); + LOG_INFO("vc-cma: vc_cma_size = 0x%08x (%u MiB)", + vc_cma_size, vc_cma_size / (1024 * 1024)); + LOG_INFO("vc-cma: vc_cma_initial = 0x%08x (%u MiB)", + +From 27077929db850cd975095571650a5dd9d3e2ec44 Mon Sep 17 00:00:00 2001 +From: Dave Stevenson <6by9@users.noreply.github.com> +Date: Thu, 26 Feb 2015 20:51:03 +0000 +Subject: [PATCH 122/178] BCM2835-V4L2: Fix compliance test failures + +VIDIOC_TRY_FMT and VIDIOC_S_FMT tests were faling due +to reporting V4L2_COLORSPACE_JPEG when the colour +format wasn't V4L2_PIX_FMT_JPEG. +Now reports V4L2_COLORSPACE_SMPTE170M for YUV formats. +--- + drivers/media/platform/bcm2835/bcm2835-camera.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/platform/bcm2835/bcm2835-camera.c b/drivers/media/platform/bcm2835/bcm2835-camera.c +index e5a0010..eb4d831 100644 +--- a/drivers/media/platform/bcm2835/bcm2835-camera.c ++++ b/drivers/media/platform/bcm2835/bcm2835-camera.c +@@ -774,7 +774,7 @@ static int vidioc_g_fbuf(struct file *file, void *fh, + a->fmt.bytesperline = (preview_port->es.video.width * 3)>>1; + a->fmt.sizeimage = (preview_port->es.video.width * + preview_port->es.video.height * 3)>>1; +- a->fmt.colorspace = V4L2_COLORSPACE_JPEG; ++ a->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; + + return 0; + } +@@ -860,8 +860,10 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + + if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_RGB24) + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; +- else ++ else if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_JPEG) + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; ++ else ++ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.priv = 0; + + v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix, +@@ -904,10 +906,12 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + f->fmt.pix.sizeimage < MIN_BUFFER_SIZE) + f->fmt.pix.sizeimage = MIN_BUFFER_SIZE; + +- if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_RGB24) ++ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; +- else ++ else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG) + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; ++ else ++ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.priv = 0; + + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, + +From 1dd62cd51cf212c70252ad10cb81a9e97b388b3b Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 24 Feb 2015 13:40:50 +0000 +Subject: [PATCH 123/178] pinctrl-bcm2835: Fix interrupt handling for GPIOs + 28-31 and 46-53 + +Contrary to the documentation, the BCM2835 GPIO controller actually has +four interrupt lines - one each for the three IRQ groups and one common. Rather +confusingly, the GPIO interrupt groups don't correspond directly with the GPIO +control banks. Instead, GPIOs 0-27 generate IRQ GPIO0, 28-45 GPIO1 and +46-53 GPIO2. + +Awkwardly, the GPIOS for IRQ GPIO1 straddle two 32-entry GPIO banks, so it is +cleaner to split out a function to process the interrupts for a single GPIO +bank. + +This bug has only just been observed because GPIOs above 27 can only be +accessed on an old Raspberry Pi with the optional P5 header fitted, where +the pins are often used for I2S instead. +--- + drivers/pinctrl/pinctrl-bcm2835.c | 50 +++++++++++++++++++++++++++++---------- + 1 file changed, 38 insertions(+), 12 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c +index 42a4fd5..ae68710 100644 +--- a/drivers/pinctrl/pinctrl-bcm2835.c ++++ b/drivers/pinctrl/pinctrl-bcm2835.c +@@ -47,6 +47,7 @@ + #define MODULE_NAME "pinctrl-bcm2835" + #define BCM2835_NUM_GPIOS 54 + #define BCM2835_NUM_BANKS 2 ++#define BCM2835_NUM_IRQS 3 + + #define BCM2835_PIN_BITMAP_SZ \ + DIV_ROUND_UP(BCM2835_NUM_GPIOS, sizeof(unsigned long) * 8) +@@ -88,13 +89,13 @@ enum bcm2835_pinconf_pull { + + struct bcm2835_gpio_irqdata { + struct bcm2835_pinctrl *pc; +- int bank; ++ int irqgroup; + }; + + struct bcm2835_pinctrl { + struct device *dev; + void __iomem *base; +- int irq[BCM2835_NUM_BANKS]; ++ int irq[BCM2835_NUM_IRQS]; + + /* note: locking assumes each bank will have its own unsigned long */ + unsigned long enabled_irq_map[BCM2835_NUM_BANKS]; +@@ -105,7 +106,7 @@ struct bcm2835_pinctrl { + struct gpio_chip gpio_chip; + struct pinctrl_gpio_range gpio_range; + +- struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_BANKS]; ++ struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_IRQS]; + spinlock_t irq_lock[BCM2835_NUM_BANKS]; + }; + +@@ -394,17 +395,16 @@ static struct gpio_chip bcm2835_gpio_chip = { + .can_sleep = false, + }; + +-static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id) ++static int bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc, ++ unsigned int bank, u32 mask) + { +- struct bcm2835_gpio_irqdata *irqdata = dev_id; +- struct bcm2835_pinctrl *pc = irqdata->pc; +- int bank = irqdata->bank; + unsigned long events; + unsigned offset; + unsigned gpio; + unsigned int type; + + events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4); ++ events &= mask; + events &= pc->enabled_irq_map[bank]; + for_each_set_bit(offset, &events, 32) { + gpio = (32 * bank) + offset; +@@ -420,7 +420,30 @@ static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id) + if (type & IRQ_TYPE_LEVEL_MASK) + bcm2835_gpio_set_bit(pc, GPEDS0, gpio); + } +- return events ? IRQ_HANDLED : IRQ_NONE; ++ ++ return (events != 0); ++} ++ ++static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id) ++{ ++ struct bcm2835_gpio_irqdata *irqdata = dev_id; ++ struct bcm2835_pinctrl *pc = irqdata->pc; ++ int handled = 0; ++ ++ switch (irqdata->irqgroup) { ++ case 0: /* IRQ0 covers GPIOs 0-27 */ ++ handled = bcm2835_gpio_irq_handle_bank(pc, 0, 0x0fffffff); ++ break; ++ case 1: /* IRQ1 covers GPIOs 28-45 */ ++ handled = bcm2835_gpio_irq_handle_bank(pc, 0, 0xf0000000) | ++ bcm2835_gpio_irq_handle_bank(pc, 1, 0x00003fff); ++ break; ++ case 2: /* IRQ2 covers GPIOs 46-53 */ ++ handled = bcm2835_gpio_irq_handle_bank(pc, 1, 0x003fc000); ++ break; ++ } ++ ++ return handled ? IRQ_HANDLED : IRQ_NONE; + } + + static inline void __bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc, +@@ -992,8 +1015,6 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) + for (i = 0; i < BCM2835_NUM_BANKS; i++) { + unsigned long events; + unsigned offset; +- int len; +- char *name; + + /* clear event detection flags */ + bcm2835_gpio_wr(pc, GPREN0 + i * 4, 0); +@@ -1008,10 +1029,15 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) + for_each_set_bit(offset, &events, 32) + bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset)); + ++ spin_lock_init(&pc->irq_lock[i]); ++ } ++ ++ for (i = 0; i < BCM2835_NUM_IRQS; i++) { ++ int len; ++ char *name; + pc->irq[i] = irq_of_parse_and_map(np, i); + pc->irq_data[i].pc = pc; +- pc->irq_data[i].bank = i; +- spin_lock_init(&pc->irq_lock[i]); ++ pc->irq_data[i].irqgroup = i; + + len = strlen(dev_name(pc->dev)) + 16; + name = devm_kzalloc(pc->dev, len, GFP_KERNEL); + +From 6c4cbee9fcfd71039eaf6a10d0ff423ae1f77be4 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 26 Feb 2015 09:58:22 +0000 +Subject: [PATCH 124/178] pinctrl-bcm2835: Only request the interrupts listed + in the DTB + +Although the GPIO controller can generate three interrupts (four counting +the common one), the device tree files currently only specify two. In the +absence of the third, simply don't register that interrupt (as opposed to +registering 0), which has the effect of making it impossible to generate +interrupts for GPIOs 46-53 which, since they share pins with the SD card +interface, is unlikely to be a problem. +--- + drivers/pinctrl/pinctrl-bcm2835.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c +index ae68710..87b7a4a 100644 +--- a/drivers/pinctrl/pinctrl-bcm2835.c ++++ b/drivers/pinctrl/pinctrl-bcm2835.c +@@ -1036,6 +1036,8 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) + int len; + char *name; + pc->irq[i] = irq_of_parse_and_map(np, i); ++ if (pc->irq[i] == 0) ++ break; + pc->irq_data[i].pc = pc; + pc->irq_data[i].irqgroup = i; + + +From a5d81b0f08bbaba1ed2837a1494b4d24e43c1144 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:09 +0100 +Subject: [PATCH 125/178] staging: fbtft: core support + +This commit adds the core fbtft framework from +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/Kconfig | 2 + + drivers/staging/Makefile | 1 + + drivers/staging/fbtft/Kconfig | 9 + + drivers/staging/fbtft/Makefile | 3 + + drivers/staging/fbtft/README | 32 + + drivers/staging/fbtft/fbtft-bus.c | 256 ++++++ + drivers/staging/fbtft/fbtft-core.c | 1516 +++++++++++++++++++++++++++++++++++ + drivers/staging/fbtft/fbtft-io.c | 409 ++++++++++ + drivers/staging/fbtft/fbtft-sysfs.c | 222 +++++ + drivers/staging/fbtft/fbtft.h | 447 +++++++++++ + 10 files changed, 2897 insertions(+) + create mode 100644 drivers/staging/fbtft/Kconfig + create mode 100644 drivers/staging/fbtft/Makefile + create mode 100644 drivers/staging/fbtft/README + create mode 100644 drivers/staging/fbtft/fbtft-bus.c + create mode 100644 drivers/staging/fbtft/fbtft-core.c + create mode 100644 drivers/staging/fbtft/fbtft-io.c + create mode 100644 drivers/staging/fbtft/fbtft-sysfs.c + create mode 100644 drivers/staging/fbtft/fbtft.h + +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 4690ae9..fbe9889 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -108,4 +108,6 @@ source "drivers/staging/skein/Kconfig" + + source "drivers/staging/unisys/Kconfig" + ++source "drivers/staging/fbtft/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index c780a0e..8140e78 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -46,3 +46,4 @@ obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/ + obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/ + obj-$(CONFIG_CRYPTO_SKEIN) += skein/ + obj-$(CONFIG_UNISYSSPAR) += unisys/ ++obj-$(CONFIG_FB_TFT) += fbtft/ +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +new file mode 100644 +index 0000000..3d6598b +--- /dev/null ++++ b/drivers/staging/fbtft/Kconfig +@@ -0,0 +1,9 @@ ++menuconfig FB_TFT ++ tristate "Support for small TFT LCD display modules" ++ depends on FB && SPI && GPIOLIB ++ select FB_SYS_FILLRECT ++ select FB_SYS_COPYAREA ++ select FB_SYS_IMAGEBLIT ++ select FB_SYS_FOPS ++ select FB_DEFERRED_IO ++ select FB_BACKLIGHT +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +new file mode 100644 +index 0000000..9132dde +--- /dev/null ++++ b/drivers/staging/fbtft/Makefile +@@ -0,0 +1,3 @@ ++# Core module ++obj-$(CONFIG_FB_TFT) += fbtft.o ++fbtft-y += fbtft-core.o fbtft-sysfs.o fbtft-bus.o fbtft-io.o +diff --git a/drivers/staging/fbtft/README b/drivers/staging/fbtft/README +new file mode 100644 +index 0000000..ba4c74c +--- /dev/null ++++ b/drivers/staging/fbtft/README +@@ -0,0 +1,32 @@ ++ FBTFT ++========= ++ ++Linux Framebuffer drivers for small TFT LCD display modules. ++The module 'fbtft' makes writing drivers for some of these displays very easy. ++ ++Development is done on a Raspberry Pi running the Raspbian "wheezy" distribution. ++ ++INSTALLATION ++ Download kernel sources ++ ++ From Linux 3.15 ++ cd drivers/video/fbdev/fbtft ++ git clone https://github.com/notro/fbtft.git ++ ++ Add to drivers/video/fbdev/Kconfig: source "drivers/video/fbdev/fbtft/Kconfig" ++ Add to drivers/video/fbdev/Makefile: obj-y += fbtft/ ++ ++ Before Linux 3.15 ++ cd drivers/video ++ git clone https://github.com/notro/fbtft.git ++ ++ Add to drivers/video/Kconfig: source "drivers/video/fbtft/Kconfig" ++ Add to drivers/video/Makefile: obj-y += fbtft/ ++ ++ Enable driver(s) in menuconfig and build the kernel ++ ++ ++See wiki for more information: https://github.com/notro/fbtft/wiki ++ ++ ++Source: https://github.com/notro/fbtft/ +diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c +new file mode 100644 +index 0000000..b3cddb0 +--- /dev/null ++++ b/drivers/staging/fbtft/fbtft-bus.c +@@ -0,0 +1,256 @@ ++#include ++#include ++#include ++#include ++#include "fbtft.h" ++ ++ ++ ++ ++/***************************************************************************** ++ * ++ * void (*write_reg)(struct fbtft_par *par, int len, ...); ++ * ++ *****************************************************************************/ ++ ++#define define_fbtft_write_reg(func, type, modifier) \ ++void func(struct fbtft_par *par, int len, ...) \ ++{ \ ++ va_list args; \ ++ int i, ret; \ ++ int offset = 0; \ ++ type *buf = (type *)par->buf; \ ++ \ ++ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { \ ++ va_start(args, len); \ ++ for (i = 0; i < len; i++) { \ ++ buf[i] = (type)va_arg(args, unsigned int); \ ++ } \ ++ va_end(args); \ ++ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, type, buf, len, "%s: ", __func__); \ ++ } \ ++ \ ++ va_start(args, len); \ ++ \ ++ if (par->startbyte) { \ ++ *(u8 *)par->buf = par->startbyte; \ ++ buf = (type *)(par->buf + 1); \ ++ offset = 1; \ ++ } \ ++ \ ++ *buf = modifier((type)va_arg(args, unsigned int)); \ ++ if (par->gpio.dc != -1) \ ++ gpio_set_value(par->gpio.dc, 0); \ ++ ret = par->fbtftops.write(par, par->buf, sizeof(type)+offset); \ ++ if (ret < 0) { \ ++ va_end(args); \ ++ dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); \ ++ return; \ ++ } \ ++ len--; \ ++ \ ++ if (par->startbyte) \ ++ *(u8 *)par->buf = par->startbyte | 0x2; \ ++ \ ++ if (len) { \ ++ i = len; \ ++ while (i--) { \ ++ *buf++ = modifier((type)va_arg(args, unsigned int)); \ ++ } \ ++ if (par->gpio.dc != -1) \ ++ gpio_set_value(par->gpio.dc, 1); \ ++ ret = par->fbtftops.write(par, par->buf, len * (sizeof(type)+offset)); \ ++ if (ret < 0) { \ ++ va_end(args); \ ++ dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); \ ++ return; \ ++ } \ ++ } \ ++ va_end(args); \ ++} \ ++EXPORT_SYMBOL(func); ++ ++define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, ) ++define_fbtft_write_reg(fbtft_write_reg16_bus8, u16, cpu_to_be16) ++define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, ) ++ ++void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...) ++{ ++ va_list args; ++ int i, ret; ++ int pad = 0; ++ u16 *buf = (u16 *)par->buf; ++ ++ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { ++ va_start(args, len); ++ for (i = 0; i < len; i++) ++ *(((u8 *)buf) + i) = (u8)va_arg(args, unsigned int); ++ va_end(args); ++ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, ++ par->info->device, u8, buf, len, "%s: ", __func__); ++ } ++ if (len <= 0) ++ return; ++ ++ if (par->spi && (par->spi->bits_per_word == 8)) { ++ /* we're emulating 9-bit, pad start of buffer with no-ops ++ (assuming here that zero is a no-op) */ ++ pad = (len % 4) ? 4 - (len % 4) : 0; ++ for (i = 0; i < pad; i++) ++ *buf++ = 0x000; ++ } ++ ++ va_start(args, len); ++ *buf++ = (u8)va_arg(args, unsigned int); ++ i = len - 1; ++ while (i--) { ++ *buf = (u8)va_arg(args, unsigned int); ++ *buf++ |= 0x100; /* dc=1 */ ++ } ++ va_end(args); ++ ret = par->fbtftops.write(par, par->buf, (len + pad) * sizeof(u16)); ++ if (ret < 0) { ++ dev_err(par->info->device, ++ "%s: write() failed and returned %d\n", __func__, ret); ++ return; ++ } ++} ++EXPORT_SYMBOL(fbtft_write_reg8_bus9); ++ ++ ++ ++ ++/***************************************************************************** ++ * ++ * int (*write_vmem)(struct fbtft_par *par); ++ * ++ *****************************************************************************/ ++ ++/* 16 bit pixel over 8-bit databus */ ++int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16; ++ u16 *txbuf16 = (u16 *)par->txbuf.buf; ++ size_t remain; ++ size_t to_copy; ++ size_t tx_array_size; ++ int i; ++ int ret = 0; ++ size_t startbyte_size = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", ++ __func__, offset, len); ++ ++ remain = len / 2; ++ vmem16 = (u16 *)(par->info->screen_base + offset); ++ ++ if (par->gpio.dc != -1) ++ gpio_set_value(par->gpio.dc, 1); ++ ++ /* non buffered write */ ++ if (!par->txbuf.buf) ++ return par->fbtftops.write(par, vmem16, len); ++ ++ /* buffered write */ ++ tx_array_size = par->txbuf.len / 2; ++ ++ if (par->startbyte) { ++ txbuf16 = (u16 *)(par->txbuf.buf + 1); ++ tx_array_size -= 2; ++ *(u8 *)(par->txbuf.buf) = par->startbyte | 0x2; ++ startbyte_size = 1; ++ } ++ ++ while (remain) { ++ to_copy = remain > tx_array_size ? tx_array_size : remain; ++ dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n", ++ to_copy, remain - to_copy); ++ ++ for (i = 0; i < to_copy; i++) ++ txbuf16[i] = cpu_to_be16(vmem16[i]); ++ ++ vmem16 = vmem16 + to_copy; ++ ret = par->fbtftops.write(par, par->txbuf.buf, ++ startbyte_size + to_copy * 2); ++ if (ret < 0) ++ return ret; ++ remain -= to_copy; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(fbtft_write_vmem16_bus8); ++ ++/* 16 bit pixel over 9-bit SPI bus: dc + high byte, dc + low byte */ ++int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u8 *vmem8; ++ u16 *txbuf16 = par->txbuf.buf; ++ size_t remain; ++ size_t to_copy; ++ size_t tx_array_size; ++ int i; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", ++ __func__, offset, len); ++ ++ if (!par->txbuf.buf) { ++ dev_err(par->info->device, "%s: txbuf.buf is NULL\n", __func__); ++ return -1; ++ } ++ ++ remain = len; ++ vmem8 = par->info->screen_base + offset; ++ ++ tx_array_size = par->txbuf.len / 2; ++ ++ while (remain) { ++ to_copy = remain > tx_array_size ? tx_array_size : remain; ++ dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n", ++ to_copy, remain - to_copy); ++ ++#ifdef __LITTLE_ENDIAN ++ for (i = 0; i < to_copy; i += 2) { ++ txbuf16[i] = 0x0100 | vmem8[i+1]; ++ txbuf16[i+1] = 0x0100 | vmem8[i]; ++ } ++#else ++ for (i = 0; i < to_copy; i++) ++ txbuf16[i] = 0x0100 | vmem8[i]; ++#endif ++ vmem8 = vmem8 + to_copy; ++ ret = par->fbtftops.write(par, par->txbuf.buf, to_copy*2); ++ if (ret < 0) ++ return ret; ++ remain -= to_copy; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(fbtft_write_vmem16_bus9); ++ ++int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ dev_err(par->info->device, "%s: function not implemented\n", __func__); ++ return -1; ++} ++EXPORT_SYMBOL(fbtft_write_vmem8_bus8); ++ ++/* 16 bit pixel over 16-bit databus */ ++int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", ++ __func__, offset, len); ++ ++ vmem16 = (u16 *)(par->info->screen_base + offset); ++ ++ if (par->gpio.dc != -1) ++ gpio_set_value(par->gpio.dc, 1); ++ ++ /* no need for buffered write with 16-bit bus */ ++ return par->fbtftops.write(par, vmem16, len); ++} ++EXPORT_SYMBOL(fbtft_write_vmem16_bus16); +diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c +new file mode 100644 +index 0000000..873e2c7 +--- /dev/null ++++ b/drivers/staging/fbtft/fbtft-core.c +@@ -0,0 +1,1516 @@ ++/* ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * This driver is inspired by: ++ * st7735fb.c, Copyright (C) 2011, Matt Porter ++ * broadsheetfb.c, Copyright (C) 2008, Jaya Kumar ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++extern void fbtft_sysfs_init(struct fbtft_par *par); ++extern void fbtft_sysfs_exit(struct fbtft_par *par); ++extern void fbtft_expand_debug_value(unsigned long *debug); ++extern int fbtft_gamma_parse_str(struct fbtft_par *par, unsigned long *curves, ++ const char *str, int size); ++ ++static unsigned long debug; ++module_param(debug, ulong , 0); ++MODULE_PARM_DESC(debug, "override device debug level"); ++ ++static bool dma = true; ++module_param(dma, bool, 0); ++MODULE_PARM_DESC(dma, "Use DMA buffer"); ++ ++ ++void fbtft_dbg_hex(const struct device *dev, int groupsize, ++ void *buf, size_t len, const char *fmt, ...) ++{ ++ va_list args; ++ static char textbuf[512]; ++ char *text = textbuf; ++ size_t text_len; ++ ++ va_start(args, fmt); ++ text_len = vscnprintf(text, sizeof(textbuf), fmt, args); ++ va_end(args); ++ ++ hex_dump_to_buffer(buf, len, 32, groupsize, text + text_len, ++ 512 - text_len, false); ++ ++ if (len > 32) ++ dev_info(dev, "%s ...\n", text); ++ else ++ dev_info(dev, "%s\n", text); ++} ++EXPORT_SYMBOL(fbtft_dbg_hex); ++ ++unsigned long fbtft_request_gpios_match(struct fbtft_par *par, ++ const struct fbtft_gpio *gpio) ++{ ++ int ret; ++ long val; ++ ++ fbtft_par_dbg(DEBUG_REQUEST_GPIOS_MATCH, par, "%s('%s')\n", ++ __func__, gpio->name); ++ ++ if (strcasecmp(gpio->name, "reset") == 0) { ++ par->gpio.reset = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } else if (strcasecmp(gpio->name, "dc") == 0) { ++ par->gpio.dc = gpio->gpio; ++ return GPIOF_OUT_INIT_LOW; ++ } else if (strcasecmp(gpio->name, "cs") == 0) { ++ par->gpio.cs = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } else if (strcasecmp(gpio->name, "wr") == 0) { ++ par->gpio.wr = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } else if (strcasecmp(gpio->name, "rd") == 0) { ++ par->gpio.rd = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } else if (strcasecmp(gpio->name, "latch") == 0) { ++ par->gpio.latch = gpio->gpio; ++ return GPIOF_OUT_INIT_LOW; ++ } else if (gpio->name[0] == 'd' && gpio->name[1] == 'b') { ++ ret = kstrtol(&gpio->name[2], 10, &val); ++ if (ret == 0 && val < 16) { ++ par->gpio.db[val] = gpio->gpio; ++ return GPIOF_OUT_INIT_LOW; ++ } ++ } else if (strcasecmp(gpio->name, "led") == 0) { ++ par->gpio.led[0] = gpio->gpio; ++ return GPIOF_OUT_INIT_LOW; ++ } else if (strcasecmp(gpio->name, "led_") == 0) { ++ par->gpio.led[0] = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } ++ ++ return FBTFT_GPIO_NO_MATCH; ++} ++ ++int fbtft_request_gpios(struct fbtft_par *par) ++{ ++ struct fbtft_platform_data *pdata = par->pdata; ++ const struct fbtft_gpio *gpio; ++ unsigned long flags; ++ int ret; ++ ++ if (pdata && pdata->gpios) { ++ gpio = pdata->gpios; ++ while (gpio->name[0]) { ++ flags = FBTFT_GPIO_NO_MATCH; ++ /* if driver provides match function, try it first, ++ if no match use our own */ ++ if (par->fbtftops.request_gpios_match) ++ flags = par->fbtftops.request_gpios_match(par, gpio); ++ if (flags == FBTFT_GPIO_NO_MATCH) ++ flags = fbtft_request_gpios_match(par, gpio); ++ if (flags != FBTFT_GPIO_NO_MATCH) { ++ ret = devm_gpio_request_one(par->info->device, ++ gpio->gpio, flags, ++ par->info->device->driver->name); ++ if (ret < 0) { ++ dev_err(par->info->device, ++ "%s: gpio_request_one('%s'=%d) failed with %d\n", ++ __func__, gpio->name, ++ gpio->gpio, ret); ++ return ret; ++ } ++ fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, ++ "%s: '%s' = GPIO%d\n", ++ __func__, gpio->name, gpio->gpio); ++ } ++ gpio++; ++ } ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++static int fbtft_request_one_gpio(struct fbtft_par *par, ++ const char *name, int index, int *gpiop) ++{ ++ struct device *dev = par->info->device; ++ struct device_node *node = dev->of_node; ++ int gpio, flags, ret = 0; ++ enum of_gpio_flags of_flags; ++ ++ if (of_find_property(node, name, NULL)) { ++ gpio = of_get_named_gpio_flags(node, name, index, &of_flags); ++ if (gpio == -ENOENT) ++ return 0; ++ if (gpio == -EPROBE_DEFER) ++ return gpio; ++ if (gpio < 0) { ++ dev_err(dev, ++ "failed to get '%s' from DT\n", name); ++ return gpio; ++ } ++ ++ /* active low translates to initially low */ ++ flags = (of_flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_LOW : ++ GPIOF_OUT_INIT_HIGH; ++ ret = devm_gpio_request_one(dev, gpio, flags, ++ dev->driver->name); ++ if (ret) { ++ dev_err(dev, ++ "gpio_request_one('%s'=%d) failed with %d\n", ++ name, gpio, ret); ++ return ret; ++ } ++ if (gpiop) ++ *gpiop = gpio; ++ fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d\n", ++ __func__, name, gpio); ++ } ++ ++ return ret; ++} ++ ++static int fbtft_request_gpios_dt(struct fbtft_par *par) ++{ ++ int i; ++ int ret; ++ ++ if (!par->info->device->of_node) ++ return -EINVAL; ++ ++ ret = fbtft_request_one_gpio(par, "reset-gpios", 0, &par->gpio.reset); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "dc-gpios", 0, &par->gpio.dc); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "rd-gpios", 0, &par->gpio.rd); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "wr-gpios", 0, &par->gpio.wr); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "cs-gpios", 0, &par->gpio.cs); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "latch-gpios", 0, &par->gpio.latch); ++ if (ret) ++ return ret; ++ for (i = 0; i < 16; i++) { ++ ret = fbtft_request_one_gpio(par, "db-gpios", i, ++ &par->gpio.db[i]); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "led-gpios", i, ++ &par->gpio.led[i]); ++ if (ret) ++ return ret; ++ ret = fbtft_request_one_gpio(par, "aux-gpios", i, ++ &par->gpio.aux[i]); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_FB_BACKLIGHT ++int fbtft_backlight_update_status(struct backlight_device *bd) ++{ ++ struct fbtft_par *par = bl_get_data(bd); ++ bool polarity = !!(bd->props.state & BL_CORE_DRIVER1); ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, ++ "%s: polarity=%d, power=%d, fb_blank=%d\n", ++ __func__, polarity, bd->props.power, bd->props.fb_blank); ++ ++ if ((bd->props.power == FB_BLANK_UNBLANK) && (bd->props.fb_blank == FB_BLANK_UNBLANK)) ++ gpio_set_value(par->gpio.led[0], polarity); ++ else ++ gpio_set_value(par->gpio.led[0], !polarity); ++ ++ return 0; ++} ++ ++int fbtft_backlight_get_brightness(struct backlight_device *bd) ++{ ++ return bd->props.brightness; ++} ++ ++void fbtft_unregister_backlight(struct fbtft_par *par) ++{ ++ const struct backlight_ops *bl_ops; ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__); ++ ++ if (par->info->bl_dev) { ++ par->info->bl_dev->props.power = FB_BLANK_POWERDOWN; ++ backlight_update_status(par->info->bl_dev); ++ bl_ops = par->info->bl_dev->ops; ++ backlight_device_unregister(par->info->bl_dev); ++ par->info->bl_dev = NULL; ++ } ++} ++ ++void fbtft_register_backlight(struct fbtft_par *par) ++{ ++ struct backlight_device *bd; ++ struct backlight_properties bl_props = { 0, }; ++ struct backlight_ops *bl_ops; ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__); ++ ++ if (par->gpio.led[0] == -1) { ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, ++ "%s(): led pin not set, exiting.\n", __func__); ++ return; ++ } ++ ++ bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops), ++ GFP_KERNEL); ++ if (!bl_ops) { ++ dev_err(par->info->device, ++ "%s: could not allocate memeory for backlight operations.\n", ++ __func__); ++ return; ++ } ++ ++ bl_ops->get_brightness = fbtft_backlight_get_brightness; ++ bl_ops->update_status = fbtft_backlight_update_status; ++ bl_props.type = BACKLIGHT_RAW; ++ /* Assume backlight is off, get polarity from current state of pin */ ++ bl_props.power = FB_BLANK_POWERDOWN; ++ if (!gpio_get_value(par->gpio.led[0])) ++ bl_props.state |= BL_CORE_DRIVER1; ++ ++ bd = backlight_device_register(dev_driver_string(par->info->device), ++ par->info->device, par, bl_ops, &bl_props); ++ if (IS_ERR(bd)) { ++ dev_err(par->info->device, ++ "cannot register backlight device (%ld)\n", ++ PTR_ERR(bd)); ++ return; ++ } ++ par->info->bl_dev = bd; ++ ++ if (!par->fbtftops.unregister_backlight) ++ par->fbtftops.unregister_backlight = fbtft_unregister_backlight; ++} ++#else ++void fbtft_register_backlight(struct fbtft_par *par) { }; ++void fbtft_unregister_backlight(struct fbtft_par *par) { }; ++#endif ++EXPORT_SYMBOL(fbtft_register_backlight); ++EXPORT_SYMBOL(fbtft_unregister_backlight); ++ ++void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address set */ ++ write_reg(par, 0x2A, ++ (xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF); ++ ++ /* Row adress set */ ++ write_reg(par, 0x2B, ++ (ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++ ++void fbtft_reset(struct fbtft_par *par) ++{ ++ if (par->gpio.reset == -1) ++ return; ++ fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__); ++ gpio_set_value(par->gpio.reset, 0); ++ udelay(20); ++ gpio_set_value(par->gpio.reset, 1); ++ mdelay(120); ++} ++ ++ ++void fbtft_update_display(struct fbtft_par *par, unsigned start_line, unsigned end_line) ++{ ++ size_t offset, len; ++ struct timespec ts_start, ts_end, ts_fps, ts_duration; ++ long fps_ms, fps_us, duration_ms, duration_us; ++ long fps, throughput; ++ bool timeit = false; ++ int ret = 0; ++ ++ if (unlikely(par->debug & (DEBUG_TIME_FIRST_UPDATE | DEBUG_TIME_EACH_UPDATE))) { ++ if ((par->debug & DEBUG_TIME_EACH_UPDATE) || \ ++ ((par->debug & DEBUG_TIME_FIRST_UPDATE) && !par->first_update_done)) { ++ getnstimeofday(&ts_start); ++ timeit = true; ++ } ++ } ++ ++ /* Sanity checks */ ++ if (start_line > end_line) { ++ dev_warn(par->info->device, ++ "%s: start_line=%u is larger than end_line=%u. Shouldn't happen, will do full display update\n", ++ __func__, start_line, end_line); ++ start_line = 0; ++ end_line = par->info->var.yres - 1; ++ } ++ if (start_line > par->info->var.yres - 1 || end_line > par->info->var.yres - 1) { ++ dev_warn(par->info->device, ++ "%s: start_line=%u or end_line=%u is larger than max=%d. Shouldn't happen, will do full display update\n", ++ __func__, start_line, end_line, par->info->var.yres - 1); ++ start_line = 0; ++ end_line = par->info->var.yres - 1; ++ } ++ ++ fbtft_par_dbg(DEBUG_UPDATE_DISPLAY, par, "%s(start_line=%u, end_line=%u)\n", ++ __func__, start_line, end_line); ++ ++ if (par->fbtftops.set_addr_win) ++ par->fbtftops.set_addr_win(par, 0, start_line, ++ par->info->var.xres-1, end_line); ++ ++ offset = start_line * par->info->fix.line_length; ++ len = (end_line - start_line + 1) * par->info->fix.line_length; ++ ret = par->fbtftops.write_vmem(par, offset, len); ++ if (ret < 0) ++ dev_err(par->info->device, ++ "%s: write_vmem failed to update display buffer\n", ++ __func__); ++ ++ if (unlikely(timeit)) { ++ getnstimeofday(&ts_end); ++ if (par->update_time.tv_nsec == 0 && par->update_time.tv_sec == 0) { ++ par->update_time.tv_sec = ts_start.tv_sec; ++ par->update_time.tv_nsec = ts_start.tv_nsec; ++ } ++ ts_fps = timespec_sub(ts_start, par->update_time); ++ par->update_time.tv_sec = ts_start.tv_sec; ++ par->update_time.tv_nsec = ts_start.tv_nsec; ++ fps_ms = (ts_fps.tv_sec * 1000) + ((ts_fps.tv_nsec / 1000000) % 1000); ++ fps_us = (ts_fps.tv_nsec / 1000) % 1000; ++ fps = fps_ms * 1000 + fps_us; ++ fps = fps ? 1000000 / fps : 0; ++ ++ ts_duration = timespec_sub(ts_end, ts_start); ++ duration_ms = (ts_duration.tv_sec * 1000) + ((ts_duration.tv_nsec / 1000000) % 1000); ++ duration_us = (ts_duration.tv_nsec / 1000) % 1000; ++ throughput = duration_ms * 1000 + duration_us; ++ throughput = throughput ? (len * 1000) / throughput : 0; ++ throughput = throughput * 1000 / 1024; ++ ++ dev_info(par->info->device, ++ "Display update: %ld kB/s (%ld.%.3ld ms), fps=%ld (%ld.%.3ld ms)\n", ++ throughput, duration_ms, duration_us, ++ fps, fps_ms, fps_us); ++ par->first_update_done = true; ++ } ++} ++ ++ ++void fbtft_mkdirty(struct fb_info *info, int y, int height) ++{ ++ struct fbtft_par *par = info->par; ++ struct fb_deferred_io *fbdefio = info->fbdefio; ++ ++ /* special case, needed ? */ ++ if (y == -1) { ++ y = 0; ++ height = info->var.yres - 1; ++ } ++ ++ /* Mark display lines/area as dirty */ ++ spin_lock(&par->dirty_lock); ++ if (y < par->dirty_lines_start) ++ par->dirty_lines_start = y; ++ if (y + height - 1 > par->dirty_lines_end) ++ par->dirty_lines_end = y + height - 1; ++ spin_unlock(&par->dirty_lock); ++ ++ /* Schedule deferred_io to update display (no-op if already on queue)*/ ++ schedule_delayed_work(&info->deferred_work, fbdefio->delay); ++} ++ ++void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) ++{ ++ struct fbtft_par *par = info->par; ++ unsigned dirty_lines_start, dirty_lines_end; ++ struct page *page; ++ unsigned long index; ++ unsigned y_low = 0, y_high = 0; ++ int count = 0; ++ ++ spin_lock(&par->dirty_lock); ++ dirty_lines_start = par->dirty_lines_start; ++ dirty_lines_end = par->dirty_lines_end; ++ /* set display line markers as clean */ ++ par->dirty_lines_start = par->info->var.yres - 1; ++ par->dirty_lines_end = 0; ++ spin_unlock(&par->dirty_lock); ++ ++ /* Mark display lines as dirty */ ++ list_for_each_entry(page, pagelist, lru) { ++ count++; ++ index = page->index << PAGE_SHIFT; ++ y_low = index / info->fix.line_length; ++ y_high = (index + PAGE_SIZE - 1) / info->fix.line_length; ++ fbtft_dev_dbg(DEBUG_DEFERRED_IO, par, info->device, ++ "page->index=%lu y_low=%d y_high=%d\n", ++ page->index, y_low, y_high); ++ if (y_high > info->var.yres - 1) ++ y_high = info->var.yres - 1; ++ if (y_low < dirty_lines_start) ++ dirty_lines_start = y_low; ++ if (y_high > dirty_lines_end) ++ dirty_lines_end = y_high; ++ } ++ ++ par->fbtftops.update_display(info->par, ++ dirty_lines_start, dirty_lines_end); ++} ++ ++ ++void fbtft_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ++{ ++ struct fbtft_par *par = info->par; ++ ++ fbtft_dev_dbg(DEBUG_FB_FILLRECT, par, info->dev, ++ "%s: dx=%d, dy=%d, width=%d, height=%d\n", ++ __func__, rect->dx, rect->dy, rect->width, rect->height); ++ sys_fillrect(info, rect); ++ ++ par->fbtftops.mkdirty(info, rect->dy, rect->height); ++} ++ ++void fbtft_fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) ++{ ++ struct fbtft_par *par = info->par; ++ ++ fbtft_dev_dbg(DEBUG_FB_COPYAREA, par, info->dev, ++ "%s: dx=%d, dy=%d, width=%d, height=%d\n", ++ __func__, area->dx, area->dy, area->width, area->height); ++ sys_copyarea(info, area); ++ ++ par->fbtftops.mkdirty(info, area->dy, area->height); ++} ++ ++void fbtft_fb_imageblit(struct fb_info *info, const struct fb_image *image) ++{ ++ struct fbtft_par *par = info->par; ++ ++ fbtft_dev_dbg(DEBUG_FB_IMAGEBLIT, par, info->dev, ++ "%s: dx=%d, dy=%d, width=%d, height=%d\n", ++ __func__, image->dx, image->dy, image->width, image->height); ++ sys_imageblit(info, image); ++ ++ par->fbtftops.mkdirty(info, image->dy, image->height); ++} ++ ++ssize_t fbtft_fb_write(struct fb_info *info, ++ const char __user *buf, size_t count, loff_t *ppos) ++{ ++ struct fbtft_par *par = info->par; ++ ssize_t res; ++ ++ fbtft_dev_dbg(DEBUG_FB_WRITE, par, info->dev, ++ "%s: count=%zd, ppos=%llu\n", __func__, count, *ppos); ++ res = fb_sys_write(info, buf, count, ppos); ++ ++ /* TODO: only mark changed area ++ update all for now */ ++ par->fbtftops.mkdirty(info, -1, 0); ++ ++ return res; ++} ++ ++/* from pxafb.c */ ++unsigned int chan_to_field(unsigned chan, struct fb_bitfield *bf) ++{ ++ chan &= 0xffff; ++ chan >>= 16 - bf->length; ++ return chan << bf->offset; ++} ++ ++int fbtft_fb_setcolreg(unsigned regno, ++ unsigned red, unsigned green, unsigned blue, ++ unsigned transp, struct fb_info *info) ++{ ++ struct fbtft_par *par = info->par; ++ unsigned val; ++ int ret = 1; ++ ++ fbtft_dev_dbg(DEBUG_FB_SETCOLREG, par, info->dev, ++ "%s(regno=%u, red=0x%X, green=0x%X, blue=0x%X, trans=0x%X)\n", ++ __func__, regno, red, green, blue, transp); ++ ++ switch (info->fix.visual) { ++ case FB_VISUAL_TRUECOLOR: ++ if (regno < 16) { ++ u32 *pal = info->pseudo_palette; ++ ++ val = chan_to_field(red, &info->var.red); ++ val |= chan_to_field(green, &info->var.green); ++ val |= chan_to_field(blue, &info->var.blue); ++ ++ pal[regno] = val; ++ ret = 0; ++ } ++ break; ++ ++ } ++ return ret; ++} ++ ++int fbtft_fb_blank(int blank, struct fb_info *info) ++{ ++ struct fbtft_par *par = info->par; ++ int ret = -EINVAL; ++ ++ fbtft_dev_dbg(DEBUG_FB_BLANK, par, info->dev, "%s(blank=%d)\n", ++ __func__, blank); ++ ++ if (!par->fbtftops.blank) ++ return ret; ++ ++ switch (blank) { ++ case FB_BLANK_POWERDOWN: ++ case FB_BLANK_VSYNC_SUSPEND: ++ case FB_BLANK_HSYNC_SUSPEND: ++ case FB_BLANK_NORMAL: ++ ret = par->fbtftops.blank(par, true); ++ break; ++ case FB_BLANK_UNBLANK: ++ ret = par->fbtftops.blank(par, false); ++ break; ++ } ++ return ret; ++} ++ ++void fbtft_merge_fbtftops(struct fbtft_ops *dst, struct fbtft_ops *src) ++{ ++ if (src->write) ++ dst->write = src->write; ++ if (src->read) ++ dst->read = src->read; ++ if (src->write_vmem) ++ dst->write_vmem = src->write_vmem; ++ if (src->write_register) ++ dst->write_register = src->write_register; ++ if (src->set_addr_win) ++ dst->set_addr_win = src->set_addr_win; ++ if (src->reset) ++ dst->reset = src->reset; ++ if (src->mkdirty) ++ dst->mkdirty = src->mkdirty; ++ if (src->update_display) ++ dst->update_display = src->update_display; ++ if (src->init_display) ++ dst->init_display = src->init_display; ++ if (src->blank) ++ dst->blank = src->blank; ++ if (src->request_gpios_match) ++ dst->request_gpios_match = src->request_gpios_match; ++ if (src->request_gpios) ++ dst->request_gpios = src->request_gpios; ++ if (src->verify_gpios) ++ dst->verify_gpios = src->verify_gpios; ++ if (src->register_backlight) ++ dst->register_backlight = src->register_backlight; ++ if (src->unregister_backlight) ++ dst->unregister_backlight = src->unregister_backlight; ++ if (src->set_var) ++ dst->set_var = src->set_var; ++ if (src->set_gamma) ++ dst->set_gamma = src->set_gamma; ++} ++ ++/** ++ * fbtft_framebuffer_alloc - creates a new frame buffer info structure ++ * ++ * @display: pointer to structure describing the display ++ * @dev: pointer to the device for this fb, this can be NULL ++ * ++ * Creates a new frame buffer info structure. ++ * ++ * Also creates and populates the following structures: ++ * info->fbops ++ * info->fbdefio ++ * info->pseudo_palette ++ * par->fbtftops ++ * par->txbuf ++ * ++ * Returns the new structure, or NULL if an error occurred. ++ * ++ */ ++struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, ++ struct device *dev) ++{ ++ struct fb_info *info; ++ struct fbtft_par *par; ++ struct fb_ops *fbops = NULL; ++ struct fb_deferred_io *fbdefio = NULL; ++ struct fbtft_platform_data *pdata = dev->platform_data; ++ u8 *vmem = NULL; ++ void *txbuf = NULL; ++ void *buf = NULL; ++ unsigned width; ++ unsigned height; ++ int txbuflen = display->txbuflen; ++ unsigned bpp = display->bpp; ++ unsigned fps = display->fps; ++ int vmem_size, i; ++ int *init_sequence = display->init_sequence; ++ char *gamma = display->gamma; ++ unsigned long *gamma_curves = NULL; ++ ++ /* sanity check */ ++ if (display->gamma_num * display->gamma_len > FBTFT_GAMMA_MAX_VALUES_TOTAL) { ++ dev_err(dev, ++ "%s: FBTFT_GAMMA_MAX_VALUES_TOTAL=%d is exceeded\n", ++ __func__, FBTFT_GAMMA_MAX_VALUES_TOTAL); ++ return NULL; ++ } ++ ++ /* defaults */ ++ if (!fps) ++ fps = 20; ++ if (!bpp) ++ bpp = 16; ++ ++ if (!pdata) { ++ dev_err(dev, "platform data is missing\n"); ++ return NULL; ++ } ++ ++ /* override driver values? */ ++ if (pdata->fps) ++ fps = pdata->fps; ++ if (pdata->txbuflen) ++ txbuflen = pdata->txbuflen; ++ if (pdata->display.init_sequence) ++ init_sequence = pdata->display.init_sequence; ++ if (pdata->gamma) ++ gamma = pdata->gamma; ++ if (pdata->display.debug) ++ display->debug = pdata->display.debug; ++ if (pdata->display.backlight) ++ display->backlight = pdata->display.backlight; ++ if (pdata->display.width) ++ display->width = pdata->display.width; ++ if (pdata->display.height) ++ display->height = pdata->display.height; ++ if (pdata->display.buswidth) ++ display->buswidth = pdata->display.buswidth; ++ if (pdata->display.regwidth) ++ display->regwidth = pdata->display.regwidth; ++ ++ display->debug |= debug; ++ fbtft_expand_debug_value(&display->debug); ++ ++ switch (pdata->rotate) { ++ case 90: ++ case 270: ++ width = display->height; ++ height = display->width; ++ break; ++ default: ++ width = display->width; ++ height = display->height; ++ } ++ ++ vmem_size = display->width * display->height * bpp / 8; ++ vmem = vzalloc(vmem_size); ++ if (!vmem) ++ goto alloc_fail; ++ ++ fbops = devm_kzalloc(dev, sizeof(struct fb_ops), GFP_KERNEL); ++ if (!fbops) ++ goto alloc_fail; ++ ++ fbdefio = devm_kzalloc(dev, sizeof(struct fb_deferred_io), GFP_KERNEL); ++ if (!fbdefio) ++ goto alloc_fail; ++ ++ buf = devm_kzalloc(dev, 128, GFP_KERNEL); ++ if (!buf) ++ goto alloc_fail; ++ ++ if (display->gamma_num && display->gamma_len) { ++ gamma_curves = devm_kzalloc(dev, display->gamma_num * display->gamma_len * sizeof(gamma_curves[0]), ++ GFP_KERNEL); ++ if (!gamma_curves) ++ goto alloc_fail; ++ } ++ ++ info = framebuffer_alloc(sizeof(struct fbtft_par), dev); ++ if (!info) ++ goto alloc_fail; ++ ++ info->screen_base = (u8 __force __iomem *)vmem; ++ info->fbops = fbops; ++ info->fbdefio = fbdefio; ++ ++ fbops->owner = dev->driver->owner; ++ fbops->fb_read = fb_sys_read; ++ fbops->fb_write = fbtft_fb_write; ++ fbops->fb_fillrect = fbtft_fb_fillrect; ++ fbops->fb_copyarea = fbtft_fb_copyarea; ++ fbops->fb_imageblit = fbtft_fb_imageblit; ++ fbops->fb_setcolreg = fbtft_fb_setcolreg; ++ fbops->fb_blank = fbtft_fb_blank; ++ ++ fbdefio->delay = HZ/fps; ++ fbdefio->deferred_io = fbtft_deferred_io; ++ fb_deferred_io_init(info); ++ ++ strncpy(info->fix.id, dev->driver->name, 16); ++ info->fix.type = FB_TYPE_PACKED_PIXELS; ++ info->fix.visual = FB_VISUAL_TRUECOLOR; ++ info->fix.xpanstep = 0; ++ info->fix.ypanstep = 0; ++ info->fix.ywrapstep = 0; ++ info->fix.line_length = width*bpp/8; ++ info->fix.accel = FB_ACCEL_NONE; ++ info->fix.smem_len = vmem_size; ++ ++ info->var.rotate = pdata->rotate; ++ info->var.xres = width; ++ info->var.yres = height; ++ info->var.xres_virtual = info->var.xres; ++ info->var.yres_virtual = info->var.yres; ++ info->var.bits_per_pixel = bpp; ++ info->var.nonstd = 1; ++ ++ /* RGB565 */ ++ info->var.red.offset = 11; ++ info->var.red.length = 5; ++ info->var.green.offset = 5; ++ info->var.green.length = 6; ++ info->var.blue.offset = 0; ++ info->var.blue.length = 5; ++ info->var.transp.offset = 0; ++ info->var.transp.length = 0; ++ ++ info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; ++ ++ par = info->par; ++ par->info = info; ++ par->pdata = dev->platform_data; ++ par->debug = display->debug; ++ par->buf = buf; ++ spin_lock_init(&par->dirty_lock); ++ par->bgr = pdata->bgr; ++ par->startbyte = pdata->startbyte; ++ par->init_sequence = init_sequence; ++ par->gamma.curves = gamma_curves; ++ par->gamma.num_curves = display->gamma_num; ++ par->gamma.num_values = display->gamma_len; ++ mutex_init(&par->gamma.lock); ++ info->pseudo_palette = par->pseudo_palette; ++ ++ if (par->gamma.curves && gamma) { ++ if (fbtft_gamma_parse_str(par, ++ par->gamma.curves, gamma, strlen(gamma))) ++ goto alloc_fail; ++ } ++ ++ /* Transmit buffer */ ++ if (txbuflen == -1) ++ txbuflen = vmem_size + 2; /* add in case startbyte is used */ ++ ++#ifdef __LITTLE_ENDIAN ++ if ((!txbuflen) && (bpp > 8)) ++ txbuflen = PAGE_SIZE; /* need buffer for byteswapping */ ++#endif ++ ++ if (txbuflen > 0) { ++ if (dma) { ++ dev->coherent_dma_mask = ~0; ++ txbuf = dmam_alloc_coherent(dev, txbuflen, &par->txbuf.dma, GFP_DMA); ++ } else { ++ txbuf = devm_kzalloc(par->info->device, txbuflen, GFP_KERNEL); ++ } ++ if (!txbuf) ++ goto alloc_fail; ++ par->txbuf.buf = txbuf; ++ par->txbuf.len = txbuflen; ++ } ++ ++ /* Initialize gpios to disabled */ ++ par->gpio.reset = -1; ++ par->gpio.dc = -1; ++ par->gpio.rd = -1; ++ par->gpio.wr = -1; ++ par->gpio.cs = -1; ++ par->gpio.latch = -1; ++ for (i = 0; i < 16; i++) { ++ par->gpio.db[i] = -1; ++ par->gpio.led[i] = -1; ++ par->gpio.aux[i] = -1; ++ } ++ ++ /* default fbtft operations */ ++ par->fbtftops.write = fbtft_write_spi; ++ par->fbtftops.read = fbtft_read_spi; ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus8; ++ par->fbtftops.write_register = fbtft_write_reg8_bus8; ++ par->fbtftops.set_addr_win = fbtft_set_addr_win; ++ par->fbtftops.reset = fbtft_reset; ++ par->fbtftops.mkdirty = fbtft_mkdirty; ++ par->fbtftops.update_display = fbtft_update_display; ++ par->fbtftops.request_gpios = fbtft_request_gpios; ++ if (display->backlight) ++ par->fbtftops.register_backlight = fbtft_register_backlight; ++ ++ /* use driver provided functions */ ++ fbtft_merge_fbtftops(&par->fbtftops, &display->fbtftops); ++ ++ return info; ++ ++alloc_fail: ++ vfree(vmem); ++ ++ return NULL; ++} ++EXPORT_SYMBOL(fbtft_framebuffer_alloc); ++ ++/** ++ * fbtft_framebuffer_release - frees up all memory used by the framebuffer ++ * ++ * @info: frame buffer info structure ++ * ++ */ ++void fbtft_framebuffer_release(struct fb_info *info) ++{ ++ fb_deferred_io_cleanup(info); ++ vfree(info->screen_base); ++ framebuffer_release(info); ++} ++EXPORT_SYMBOL(fbtft_framebuffer_release); ++ ++/** ++ * fbtft_register_framebuffer - registers a tft frame buffer device ++ * @fb_info: frame buffer info structure ++ * ++ * Sets SPI driverdata if needed ++ * Requests needed gpios. ++ * Initializes display ++ * Updates display. ++ * Registers a frame buffer device @fb_info. ++ * ++ * Returns negative errno on error, or zero for success. ++ * ++ */ ++int fbtft_register_framebuffer(struct fb_info *fb_info) ++{ ++ int ret; ++ char text1[50] = ""; ++ char text2[50] = ""; ++ struct fbtft_par *par = fb_info->par; ++ struct spi_device *spi = par->spi; ++ ++ /* sanity checks */ ++ if (!par->fbtftops.init_display) { ++ dev_err(fb_info->device, "missing fbtftops.init_display()\n"); ++ return -EINVAL; ++ } ++ ++ if (spi) ++ spi_set_drvdata(spi, fb_info); ++ if (par->pdev) ++ platform_set_drvdata(par->pdev, fb_info); ++ ++ ret = par->fbtftops.request_gpios(par); ++ if (ret < 0) ++ goto reg_fail; ++ ++ if (par->fbtftops.verify_gpios) { ++ ret = par->fbtftops.verify_gpios(par); ++ if (ret < 0) ++ goto reg_fail; ++ } ++ ++ ret = par->fbtftops.init_display(par); ++ if (ret < 0) ++ goto reg_fail; ++ if (par->fbtftops.set_var) { ++ ret = par->fbtftops.set_var(par); ++ if (ret < 0) ++ goto reg_fail; ++ } ++ ++ /* update the entire display */ ++ par->fbtftops.update_display(par, 0, par->info->var.yres - 1); ++ ++ if (par->fbtftops.set_gamma && par->gamma.curves) { ++ ret = par->fbtftops.set_gamma(par, par->gamma.curves); ++ if (ret) ++ goto reg_fail; ++ } ++ ++ if (par->fbtftops.register_backlight) ++ par->fbtftops.register_backlight(par); ++ ++ ret = register_framebuffer(fb_info); ++ if (ret < 0) ++ goto reg_fail; ++ ++ fbtft_sysfs_init(par); ++ ++ if (par->txbuf.buf) ++ sprintf(text1, ", %d KiB %sbuffer memory", ++ par->txbuf.len >> 10, par->txbuf.dma ? "DMA " : ""); ++ if (spi) ++ sprintf(text2, ", spi%d.%d at %d MHz", spi->master->bus_num, ++ spi->chip_select, spi->max_speed_hz/1000000); ++ dev_info(fb_info->dev, ++ "%s frame buffer, %dx%d, %d KiB video memory%s, fps=%lu%s\n", ++ fb_info->fix.id, fb_info->var.xres, fb_info->var.yres, ++ fb_info->fix.smem_len >> 10, text1, ++ HZ/fb_info->fbdefio->delay, text2); ++ ++#ifdef CONFIG_FB_BACKLIGHT ++ /* Turn on backlight if available */ ++ if (fb_info->bl_dev) { ++ fb_info->bl_dev->props.power = FB_BLANK_UNBLANK; ++ fb_info->bl_dev->ops->update_status(fb_info->bl_dev); ++ } ++#endif ++ ++ return 0; ++ ++reg_fail: ++ if (par->fbtftops.unregister_backlight) ++ par->fbtftops.unregister_backlight(par); ++ if (spi) ++ spi_set_drvdata(spi, NULL); ++ if (par->pdev) ++ platform_set_drvdata(par->pdev, NULL); ++ ++ return ret; ++} ++EXPORT_SYMBOL(fbtft_register_framebuffer); ++ ++/** ++ * fbtft_unregister_framebuffer - releases a tft frame buffer device ++ * @fb_info: frame buffer info structure ++ * ++ * Frees SPI driverdata if needed ++ * Frees gpios. ++ * Unregisters frame buffer device. ++ * ++ */ ++int fbtft_unregister_framebuffer(struct fb_info *fb_info) ++{ ++ struct fbtft_par *par = fb_info->par; ++ struct spi_device *spi = par->spi; ++ int ret; ++ ++ if (spi) ++ spi_set_drvdata(spi, NULL); ++ if (par->pdev) ++ platform_set_drvdata(par->pdev, NULL); ++ if (par->fbtftops.unregister_backlight) ++ par->fbtftops.unregister_backlight(par); ++ fbtft_sysfs_exit(par); ++ ret = unregister_framebuffer(fb_info); ++ return ret; ++} ++EXPORT_SYMBOL(fbtft_unregister_framebuffer); ++ ++#ifdef CONFIG_OF ++/** ++ * fbtft_init_display_dt() - Device Tree init_display() function ++ * @par: Driver data ++ * ++ * Return: 0 if successful, negative if error ++ */ ++static int fbtft_init_display_dt(struct fbtft_par *par) ++{ ++ struct device_node *node = par->info->device->of_node; ++ struct property *prop; ++ const __be32 *p; ++ u32 val; ++ int buf[64], i, j; ++ char msg[128]; ++ char str[16]; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ if (!node) ++ return -EINVAL; ++ ++ prop = of_find_property(node, "init", NULL); ++ p = of_prop_next_u32(prop, NULL, &val); ++ if (!p) ++ return -EINVAL; ++ while (p) { ++ if (val & FBTFT_OF_INIT_CMD) { ++ val &= 0xFFFF; ++ i = 0; ++ while (p && !(val & 0xFFFF0000)) { ++ if (i > 63) { ++ dev_err(par->info->device, ++ "%s: Maximum register values exceeded\n", ++ __func__); ++ return -EINVAL; ++ } ++ buf[i++] = val; ++ p = of_prop_next_u32(prop, p, &val); ++ } ++ /* make debug message */ ++ msg[0] = '\0'; ++ for (j = 0; j < i; j++) { ++ snprintf(str, 128, " %02X", buf[j]); ++ strcat(msg, str); ++ } ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "init: write_register:%s\n", msg); ++ ++ par->fbtftops.write_register(par, i, ++ buf[0], buf[1], buf[2], buf[3], ++ buf[4], buf[5], buf[6], buf[7], ++ buf[8], buf[9], buf[10], buf[11], ++ buf[12], buf[13], buf[14], buf[15], ++ buf[16], buf[17], buf[18], buf[19], ++ buf[20], buf[21], buf[22], buf[23], ++ buf[24], buf[25], buf[26], buf[27], ++ buf[28], buf[29], buf[30], buf[31], ++ buf[32], buf[33], buf[34], buf[35], ++ buf[36], buf[37], buf[38], buf[39], ++ buf[40], buf[41], buf[42], buf[43], ++ buf[44], buf[45], buf[46], buf[47], ++ buf[48], buf[49], buf[50], buf[51], ++ buf[52], buf[53], buf[54], buf[55], ++ buf[56], buf[57], buf[58], buf[59], ++ buf[60], buf[61], buf[62], buf[63]); ++ } else if (val & FBTFT_OF_INIT_DELAY) { ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "init: msleep(%u)\n", val & 0xFFFF); ++ msleep(val & 0xFFFF); ++ p = of_prop_next_u32(prop, p, &val); ++ } else { ++ dev_err(par->info->device, "illegal init value 0x%X\n", ++ val); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++/** ++ * fbtft_init_display() - Generic init_display() function ++ * @par: Driver data ++ * ++ * Uses par->init_sequence to do the initialization ++ * ++ * Return: 0 if successful, negative if error ++ */ ++int fbtft_init_display(struct fbtft_par *par) ++{ ++ int buf[64]; ++ char msg[128]; ++ char str[16]; ++ int i = 0; ++ int j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* sanity check */ ++ if (!par->init_sequence) { ++ dev_err(par->info->device, ++ "error: init_sequence is not set\n"); ++ return -EINVAL; ++ } ++ ++ /* make sure stop marker exists */ ++ for (i = 0; i < FBTFT_MAX_INIT_SEQUENCE; i++) ++ if (par->init_sequence[i] == -3) ++ break; ++ if (i == FBTFT_MAX_INIT_SEQUENCE) { ++ dev_err(par->info->device, ++ "missing stop marker at end of init sequence\n"); ++ return -EINVAL; ++ } ++ ++ par->fbtftops.reset(par); ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ ++ i = 0; ++ while (i < FBTFT_MAX_INIT_SEQUENCE) { ++ if (par->init_sequence[i] == -3) { ++ /* done */ ++ return 0; ++ } ++ if (par->init_sequence[i] >= 0) { ++ dev_err(par->info->device, ++ "missing delimiter at position %d\n", i); ++ return -EINVAL; ++ } ++ if (par->init_sequence[i+1] < 0) { ++ dev_err(par->info->device, ++ "missing value after delimiter %d at position %d\n", ++ par->init_sequence[i], i); ++ return -EINVAL; ++ } ++ switch (par->init_sequence[i]) { ++ case -1: ++ i++; ++ /* make debug message */ ++ strcpy(msg, ""); ++ j = i + 1; ++ while (par->init_sequence[j] >= 0) { ++ sprintf(str, "0x%02X ", par->init_sequence[j]); ++ strcat(msg, str); ++ j++; ++ } ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "init: write(0x%02X) %s\n", ++ par->init_sequence[i], msg); ++ ++ /* Write */ ++ j = 0; ++ while (par->init_sequence[i] >= 0) { ++ if (j > 63) { ++ dev_err(par->info->device, ++ "%s: Maximum register values exceeded\n", ++ __func__); ++ return -EINVAL; ++ } ++ buf[j++] = par->init_sequence[i++]; ++ } ++ par->fbtftops.write_register(par, j, ++ buf[0], buf[1], buf[2], buf[3], ++ buf[4], buf[5], buf[6], buf[7], ++ buf[8], buf[9], buf[10], buf[11], ++ buf[12], buf[13], buf[14], buf[15], ++ buf[16], buf[17], buf[18], buf[19], ++ buf[20], buf[21], buf[22], buf[23], ++ buf[24], buf[25], buf[26], buf[27], ++ buf[28], buf[29], buf[30], buf[31], ++ buf[32], buf[33], buf[34], buf[35], ++ buf[36], buf[37], buf[38], buf[39], ++ buf[40], buf[41], buf[42], buf[43], ++ buf[44], buf[45], buf[46], buf[47], ++ buf[48], buf[49], buf[50], buf[51], ++ buf[52], buf[53], buf[54], buf[55], ++ buf[56], buf[57], buf[58], buf[59], ++ buf[60], buf[61], buf[62], buf[63]); ++ break; ++ case -2: ++ i++; ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "init: mdelay(%d)\n", par->init_sequence[i]); ++ mdelay(par->init_sequence[i++]); ++ break; ++ default: ++ dev_err(par->info->device, ++ "unknown delimiter %d at position %d\n", ++ par->init_sequence[i], i); ++ return -EINVAL; ++ } ++ } ++ ++ dev_err(par->info->device, ++ "%s: something is wrong. Shouldn't get here.\n", __func__); ++ return -EINVAL; ++} ++EXPORT_SYMBOL(fbtft_init_display); ++ ++/** ++ * fbtft_verify_gpios() - Generic verify_gpios() function ++ * @par: Driver data ++ * ++ * Uses @spi, @pdev and @buswidth to determine which GPIOs is needed ++ * ++ * Return: 0 if successful, negative if error ++ */ ++int fbtft_verify_gpios(struct fbtft_par *par) ++{ ++ struct fbtft_platform_data *pdata; ++ int i; ++ ++ fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__); ++ ++ pdata = par->info->device->platform_data; ++ if (pdata->display.buswidth != 9 && par->startbyte == 0 && \ ++ par->gpio.dc < 0) { ++ dev_err(par->info->device, ++ "Missing info about 'dc' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ ++ if (!par->pdev) ++ return 0; ++ ++ if (par->gpio.wr < 0) { ++ dev_err(par->info->device, "Missing 'wr' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ for (i = 0; i < pdata->display.buswidth; i++) { ++ if (par->gpio.db[i] < 0) { ++ dev_err(par->info->device, ++ "Missing 'db%02d' gpio. Aborting.\n", i); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_OF ++/* returns 0 if the property is not present */ ++static u32 fbtft_of_value(struct device_node *node, const char *propname) ++{ ++ int ret; ++ u32 val = 0; ++ ++ ret = of_property_read_u32(node, propname, &val); ++ if (ret == 0) ++ pr_info("%s: %s = %u\n", __func__, propname, val); ++ ++ return val; ++} ++ ++static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev) ++{ ++ struct device_node *node = dev->of_node; ++ struct fbtft_platform_data *pdata; ++ ++ if (!node) { ++ dev_err(dev, "Missing platform data or DT\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) ++ return ERR_PTR(-ENOMEM); ++ ++ pdata->display.width = fbtft_of_value(node, "width"); ++ pdata->display.height = fbtft_of_value(node, "height"); ++ pdata->display.regwidth = fbtft_of_value(node, "regwidth"); ++ pdata->display.buswidth = fbtft_of_value(node, "buswidth"); ++ pdata->display.backlight = fbtft_of_value(node, "backlight"); ++ pdata->display.bpp = fbtft_of_value(node, "bpp"); ++ pdata->display.debug = fbtft_of_value(node, "debug"); ++ pdata->rotate = fbtft_of_value(node, "rotate"); ++ pdata->bgr = of_property_read_bool(node, "bgr"); ++ pdata->fps = fbtft_of_value(node, "fps"); ++ pdata->txbuflen = fbtft_of_value(node, "txbuflen"); ++ pdata->startbyte = fbtft_of_value(node, "startbyte"); ++ of_property_read_string(node, "gamma", (const char **)&pdata->gamma); ++ ++ if (of_find_property(node, "led-gpios", NULL)) ++ pdata->display.backlight = 1; ++ if (of_find_property(node, "init", NULL)) ++ pdata->display.fbtftops.init_display = fbtft_init_display_dt; ++ pdata->display.fbtftops.request_gpios = fbtft_request_gpios_dt; ++ ++ return pdata; ++} ++#else ++static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev) ++{ ++ dev_err(dev, "Missing platform data\n"); ++ return ERR_PTR(-EINVAL); ++} ++#endif ++ ++/** ++ * fbtft_probe_common() - Generic device probe() helper function ++ * @display: Display properties ++ * @sdev: SPI device ++ * @pdev: Platform device ++ * ++ * Allocates, initializes and registers a framebuffer ++ * ++ * Either @sdev or @pdev should be NULL ++ * ++ * Return: 0 if successful, negative if error ++ */ ++int fbtft_probe_common(struct fbtft_display *display, ++ struct spi_device *sdev, struct platform_device *pdev) ++{ ++ struct device *dev; ++ struct fb_info *info; ++ struct fbtft_par *par; ++ struct fbtft_platform_data *pdata; ++ int ret; ++ ++ if (sdev) ++ dev = &sdev->dev; ++ else ++ dev = &pdev->dev; ++ ++ if (unlikely(display->debug & DEBUG_DRIVER_INIT_FUNCTIONS)) ++ dev_info(dev, "%s()\n", __func__); ++ ++ pdata = dev->platform_data; ++ if (!pdata) { ++ pdata = fbtft_probe_dt(dev); ++ if (IS_ERR(pdata)) ++ return PTR_ERR(pdata); ++ dev->platform_data = pdata; ++ } ++ ++ info = fbtft_framebuffer_alloc(display, dev); ++ if (!info) ++ return -ENOMEM; ++ ++ par = info->par; ++ par->spi = sdev; ++ par->pdev = pdev; ++ ++ if (display->buswidth == 0) { ++ dev_err(dev, "buswidth is not set\n"); ++ return -EINVAL; ++ } ++ ++ /* write register functions */ ++ if (display->regwidth == 8 && display->buswidth == 8) { ++ par->fbtftops.write_register = fbtft_write_reg8_bus8; ++ } else ++ if (display->regwidth == 8 && display->buswidth == 9 && par->spi) { ++ par->fbtftops.write_register = fbtft_write_reg8_bus9; ++ } else if (display->regwidth == 16 && display->buswidth == 8) { ++ par->fbtftops.write_register = fbtft_write_reg16_bus8; ++ } else if (display->regwidth == 16 && display->buswidth == 16) { ++ par->fbtftops.write_register = fbtft_write_reg16_bus16; ++ } else { ++ dev_warn(dev, ++ "no default functions for regwidth=%d and buswidth=%d\n", ++ display->regwidth, display->buswidth); ++ } ++ ++ /* write_vmem() functions */ ++ if (display->buswidth == 8) ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus8; ++ else if (display->buswidth == 9) ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus9; ++ else if (display->buswidth == 16) ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus16; ++ ++ /* GPIO write() functions */ ++ if (par->pdev) { ++ if (display->buswidth == 8) ++ par->fbtftops.write = fbtft_write_gpio8_wr; ++ else if (display->buswidth == 16) ++ par->fbtftops.write = fbtft_write_gpio16_wr; ++ } ++ ++ /* 9-bit SPI setup */ ++ if (par->spi && display->buswidth == 9) { ++ par->spi->bits_per_word = 9; ++ ret = par->spi->master->setup(par->spi); ++ if (ret) { ++ dev_warn(&par->spi->dev, ++ "9-bit SPI not available, emulating using 8-bit.\n"); ++ par->spi->bits_per_word = 8; ++ ret = par->spi->master->setup(par->spi); ++ if (ret) ++ goto out_release; ++ /* allocate buffer with room for dc bits */ ++ par->extra = devm_kzalloc(par->info->device, ++ par->txbuf.len + (par->txbuf.len / 8) + 8, ++ GFP_KERNEL); ++ if (!par->extra) { ++ ret = -ENOMEM; ++ goto out_release; ++ } ++ par->fbtftops.write = fbtft_write_spi_emulate_9; ++ } ++ } ++ ++ if (!par->fbtftops.verify_gpios) ++ par->fbtftops.verify_gpios = fbtft_verify_gpios; ++ ++ /* make sure we still use the driver provided functions */ ++ fbtft_merge_fbtftops(&par->fbtftops, &display->fbtftops); ++ ++ /* use init_sequence if provided */ ++ if (par->init_sequence) ++ par->fbtftops.init_display = fbtft_init_display; ++ ++ /* use platform_data provided functions above all */ ++ fbtft_merge_fbtftops(&par->fbtftops, &pdata->display.fbtftops); ++ ++ ret = fbtft_register_framebuffer(info); ++ if (ret < 0) ++ goto out_release; ++ ++ return 0; ++ ++out_release: ++ fbtft_framebuffer_release(info); ++ ++ return ret; ++} ++EXPORT_SYMBOL(fbtft_probe_common); ++ ++/** ++ * fbtft_remove_common() - Generic device remove() helper function ++ * @dev: Device ++ * @info: Framebuffer ++ * ++ * Unregisters and releases the framebuffer ++ * ++ * Return: 0 if successful, negative if error ++ */ ++int fbtft_remove_common(struct device *dev, struct fb_info *info) ++{ ++ struct fbtft_par *par; ++ ++ if (!info) ++ return -EINVAL; ++ par = info->par; ++ if (par) ++ fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par, ++ "%s()\n", __func__); ++ fbtft_unregister_framebuffer(info); ++ fbtft_framebuffer_release(info); ++ ++ return 0; ++} ++EXPORT_SYMBOL(fbtft_remove_common); ++ ++MODULE_LICENSE("GPL"); +diff --git a/drivers/staging/fbtft/fbtft-io.c b/drivers/staging/fbtft/fbtft-io.c +new file mode 100644 +index 0000000..dfa2c46 +--- /dev/null ++++ b/drivers/staging/fbtft/fbtft-io.c +@@ -0,0 +1,409 @@ ++#include ++#include ++#include ++#include ++#ifdef CONFIG_ARCH_BCM2708 ++#include ++#endif ++#include "fbtft.h" ++ ++int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len) ++{ ++ struct spi_transfer t = { ++ .tx_buf = buf, ++ .len = len, ++ }; ++ struct spi_message m; ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ if (!par->spi) { ++ dev_err(par->info->device, ++ "%s: par->spi is unexpectedly NULL\n", __func__); ++ return -1; ++ } ++ ++ spi_message_init(&m); ++ if (par->txbuf.dma && buf == par->txbuf.buf) { ++ t.tx_dma = par->txbuf.dma; ++ m.is_dma_mapped = 1; ++ } ++ spi_message_add_tail(&t, &m); ++ return spi_sync(par->spi, &m); ++} ++EXPORT_SYMBOL(fbtft_write_spi); ++ ++/** ++ * fbtft_write_spi_emulate_9() - write SPI emulating 9-bit ++ * @par: Driver data ++ * @buf: Buffer to write ++ * @len: Length of buffer (must be divisible by 8) ++ * ++ * When 9-bit SPI is not available, this function can be used to emulate that. ++ * par->extra must hold a transformation buffer used for transfer. ++ */ ++int fbtft_write_spi_emulate_9(struct fbtft_par *par, void *buf, size_t len) ++{ ++ u16 *src = buf; ++ u8 *dst = par->extra; ++ size_t size = len / 2; ++ size_t added = 0; ++ int bits, i, j; ++ u64 val, dc, tmp; ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ if (!par->extra) { ++ dev_err(par->info->device, "%s: error: par->extra is NULL\n", ++ __func__); ++ return -EINVAL; ++ } ++ if ((len % 8) != 0) { ++ dev_err(par->info->device, ++ "%s: error: len=%d must be divisible by 8\n", ++ __func__, len); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < size; i += 8) { ++ tmp = 0; ++ bits = 63; ++ for (j = 0; j < 7; j++) { ++ dc = (*src & 0x0100) ? 1 : 0; ++ val = *src & 0x00FF; ++ tmp |= dc << bits; ++ bits -= 8; ++ tmp |= val << bits--; ++ src++; ++ } ++ tmp |= ((*src & 0x0100) ? 1 : 0); ++ *(u64 *)dst = cpu_to_be64(tmp); ++ dst += 8; ++ *dst++ = (u8)(*src++ & 0x00FF); ++ added++; ++ } ++ ++ return spi_write(par->spi, par->extra, size + added); ++} ++EXPORT_SYMBOL(fbtft_write_spi_emulate_9); ++ ++int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len) ++{ ++ int ret; ++ u8 txbuf[32] = { 0, }; ++ struct spi_transfer t = { ++ .speed_hz = 2000000, ++ .rx_buf = buf, ++ .len = len, ++ }; ++ struct spi_message m; ++ ++ if (!par->spi) { ++ dev_err(par->info->device, ++ "%s: par->spi is unexpectedly NULL\n", __func__); ++ return -ENODEV; ++ } ++ ++ if (par->startbyte) { ++ if (len > 32) { ++ dev_err(par->info->device, ++ "%s: len=%d can't be larger than 32 when using 'startbyte'\n", ++ __func__, len); ++ return -EINVAL; ++ } ++ txbuf[0] = par->startbyte | 0x3; ++ t.tx_buf = txbuf; ++ fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, ++ txbuf, len, "%s(len=%d) txbuf => ", __func__, len); ++ } ++ ++ spi_message_init(&m); ++ spi_message_add_tail(&t, &m); ++ ret = spi_sync(par->spi, &m); ++ fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len, ++ "%s(len=%d) buf <= ", __func__, len); ++ ++ return ret; ++} ++EXPORT_SYMBOL(fbtft_read_spi); ++ ++ ++#ifdef CONFIG_ARCH_BCM2708 ++ ++/* ++ * Raspberry Pi ++ * - writing directly to the registers is 40-50% faster than ++ * optimized use of gpiolib ++ */ ++ ++#define GPIOSET(no, ishigh) \ ++do { \ ++ if (ishigh) \ ++ set |= (1 << (no)); \ ++ else \ ++ reset |= (1 << (no)); \ ++} while (0) ++ ++int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len) ++{ ++ unsigned int set = 0; ++ unsigned int reset = 0; ++ u8 data; ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ while (len--) { ++ data = *(u8 *) buf; ++ buf++; ++ ++ /* Set data */ ++ GPIOSET(par->gpio.db[0], (data&0x01)); ++ GPIOSET(par->gpio.db[1], (data&0x02)); ++ GPIOSET(par->gpio.db[2], (data&0x04)); ++ GPIOSET(par->gpio.db[3], (data&0x08)); ++ GPIOSET(par->gpio.db[4], (data&0x10)); ++ GPIOSET(par->gpio.db[5], (data&0x20)); ++ GPIOSET(par->gpio.db[6], (data&0x40)); ++ GPIOSET(par->gpio.db[7], (data&0x80)); ++ writel(set, __io_address(GPIO_BASE+0x1C)); ++ writel(reset, __io_address(GPIO_BASE+0x28)); ++ ++ /* Pulse /WR low */ ++ writel((1<gpio.wr), __io_address(GPIO_BASE+0x28)); ++ writel(0, __io_address(GPIO_BASE+0x28)); /* used as a delay */ ++ writel((1<gpio.wr), __io_address(GPIO_BASE+0x1C)); ++ ++ set = 0; ++ reset = 0; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(fbtft_write_gpio8_wr); ++ ++int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len) ++{ ++ unsigned int set = 0; ++ unsigned int reset = 0; ++ u16 data; ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ while (len) { ++ len -= 2; ++ data = *(u16 *) buf; ++ buf += 2; ++ ++ /* Start writing by pulling down /WR */ ++ gpio_set_value(par->gpio.wr, 0); ++ ++ /* Set data */ ++ GPIOSET(par->gpio.db[0], (data&0x0001)); ++ GPIOSET(par->gpio.db[1], (data&0x0002)); ++ GPIOSET(par->gpio.db[2], (data&0x0004)); ++ GPIOSET(par->gpio.db[3], (data&0x0008)); ++ GPIOSET(par->gpio.db[4], (data&0x0010)); ++ GPIOSET(par->gpio.db[5], (data&0x0020)); ++ GPIOSET(par->gpio.db[6], (data&0x0040)); ++ GPIOSET(par->gpio.db[7], (data&0x0080)); ++ ++ GPIOSET(par->gpio.db[8], (data&0x0100)); ++ GPIOSET(par->gpio.db[9], (data&0x0200)); ++ GPIOSET(par->gpio.db[10], (data&0x0400)); ++ GPIOSET(par->gpio.db[11], (data&0x0800)); ++ GPIOSET(par->gpio.db[12], (data&0x1000)); ++ GPIOSET(par->gpio.db[13], (data&0x2000)); ++ GPIOSET(par->gpio.db[14], (data&0x4000)); ++ GPIOSET(par->gpio.db[15], (data&0x8000)); ++ ++ writel(set, __io_address(GPIO_BASE+0x1C)); ++ writel(reset, __io_address(GPIO_BASE+0x28)); ++ ++ /* Pullup /WR */ ++ gpio_set_value(par->gpio.wr, 1); ++ ++ set = 0; ++ reset = 0; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(fbtft_write_gpio16_wr); ++ ++int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len) ++{ ++ unsigned int set = 0; ++ unsigned int reset = 0; ++ u16 data; ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ while (len) { ++ len -= 2; ++ data = *(u16 *) buf; ++ buf += 2; ++ ++ /* Start writing by pulling down /WR */ ++ gpio_set_value(par->gpio.wr, 0); ++ ++ /* Low byte */ ++ GPIOSET(par->gpio.db[0], (data&0x0001)); ++ GPIOSET(par->gpio.db[1], (data&0x0002)); ++ GPIOSET(par->gpio.db[2], (data&0x0004)); ++ GPIOSET(par->gpio.db[3], (data&0x0008)); ++ GPIOSET(par->gpio.db[4], (data&0x0010)); ++ GPIOSET(par->gpio.db[5], (data&0x0020)); ++ GPIOSET(par->gpio.db[6], (data&0x0040)); ++ GPIOSET(par->gpio.db[7], (data&0x0080)); ++ writel(set, __io_address(GPIO_BASE+0x1C)); ++ writel(reset, __io_address(GPIO_BASE+0x28)); ++ ++ /* Pulse 'latch' high */ ++ gpio_set_value(par->gpio.latch, 1); ++ gpio_set_value(par->gpio.latch, 0); ++ ++ /* High byte */ ++ GPIOSET(par->gpio.db[0], (data&0x0100)); ++ GPIOSET(par->gpio.db[1], (data&0x0200)); ++ GPIOSET(par->gpio.db[2], (data&0x0400)); ++ GPIOSET(par->gpio.db[3], (data&0x0800)); ++ GPIOSET(par->gpio.db[4], (data&0x1000)); ++ GPIOSET(par->gpio.db[5], (data&0x2000)); ++ GPIOSET(par->gpio.db[6], (data&0x4000)); ++ GPIOSET(par->gpio.db[7], (data&0x8000)); ++ writel(set, __io_address(GPIO_BASE+0x1C)); ++ writel(reset, __io_address(GPIO_BASE+0x28)); ++ ++ /* Pullup /WR */ ++ gpio_set_value(par->gpio.wr, 1); ++ ++ set = 0; ++ reset = 0; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched); ++ ++#undef GPIOSET ++ ++#else ++ ++/* ++ * Optimized use of gpiolib is twice as fast as no optimization ++ * only one driver can use the optimized version at a time ++ */ ++int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len) ++{ ++ u8 data; ++ int i; ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ static u8 prev_data; ++#endif ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ while (len--) { ++ data = *(u8 *) buf; ++ ++ /* Start writing by pulling down /WR */ ++ gpio_set_value(par->gpio.wr, 0); ++ ++ /* Set data */ ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ if (data == prev_data) { ++ gpio_set_value(par->gpio.wr, 0); /* used as delay */ ++ } else { ++ for (i = 0; i < 8; i++) { ++ if ((data & 1) != (prev_data & 1)) ++ gpio_set_value(par->gpio.db[i], ++ (data & 1)); ++ data >>= 1; ++ prev_data >>= 1; ++ } ++ } ++#else ++ for (i = 0; i < 8; i++) { ++ gpio_set_value(par->gpio.db[i], (data & 1)); ++ data >>= 1; ++ } ++#endif ++ ++ /* Pullup /WR */ ++ gpio_set_value(par->gpio.wr, 1); ++ ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ prev_data = *(u8 *) buf; ++#endif ++ buf++; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(fbtft_write_gpio8_wr); ++ ++int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len) ++{ ++ u16 data; ++ int i; ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ static u16 prev_data; ++#endif ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ while (len) { ++ data = *(u16 *) buf; ++ ++ /* Start writing by pulling down /WR */ ++ gpio_set_value(par->gpio.wr, 0); ++ ++ /* Set data */ ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ if (data == prev_data) { ++ gpio_set_value(par->gpio.wr, 0); /* used as delay */ ++ } else { ++ for (i = 0; i < 16; i++) { ++ if ((data & 1) != (prev_data & 1)) ++ gpio_set_value(par->gpio.db[i], ++ (data & 1)); ++ data >>= 1; ++ prev_data >>= 1; ++ } ++ } ++#else ++ for (i = 0; i < 16; i++) { ++ gpio_set_value(par->gpio.db[i], (data & 1)); ++ data >>= 1; ++ } ++#endif ++ ++ /* Pullup /WR */ ++ gpio_set_value(par->gpio.wr, 1); ++ ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ prev_data = *(u16 *) buf; ++#endif ++ buf += 2; ++ len -= 2; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(fbtft_write_gpio16_wr); ++ ++int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len) ++{ ++ dev_err(par->info->device, "%s: function not implemented\n", __func__); ++ return -1; ++} ++EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched); ++ ++#endif /* CONFIG_ARCH_BCM2708 */ +diff --git a/drivers/staging/fbtft/fbtft-sysfs.c b/drivers/staging/fbtft/fbtft-sysfs.c +new file mode 100644 +index 0000000..45f8de3 +--- /dev/null ++++ b/drivers/staging/fbtft/fbtft-sysfs.c +@@ -0,0 +1,222 @@ ++#include "fbtft.h" ++ ++ ++static int get_next_ulong(char **str_p, unsigned long *val, char *sep, int base) ++{ ++ char *p_val; ++ int ret; ++ ++ if (!str_p || !(*str_p)) ++ return -EINVAL; ++ ++ p_val = strsep(str_p, sep); ++ ++ if (!p_val) ++ return -EINVAL; ++ ++ ret = kstrtoul(p_val, base, val); ++ if (ret) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++int fbtft_gamma_parse_str(struct fbtft_par *par, unsigned long *curves, ++ const char *str, int size) ++{ ++ char *str_p, *curve_p = NULL; ++ char *tmp; ++ unsigned long val = 0; ++ int ret = 0; ++ int curve_counter, value_counter; ++ ++ fbtft_par_dbg(DEBUG_SYSFS, par, "%s() str=\n", __func__); ++ ++ if (!str || !curves) ++ return -EINVAL; ++ ++ fbtft_par_dbg(DEBUG_SYSFS, par, "%s\n", str); ++ ++ tmp = kmalloc(size+1, GFP_KERNEL); ++ if (!tmp) ++ return -ENOMEM; ++ memcpy(tmp, str, size+1); ++ ++ /* replace optional separators */ ++ str_p = tmp; ++ while (*str_p) { ++ if (*str_p == ',') ++ *str_p = ' '; ++ if (*str_p == ';') ++ *str_p = '\n'; ++ str_p++; ++ } ++ ++ str_p = strim(tmp); ++ ++ curve_counter = 0; ++ while (str_p) { ++ if (curve_counter == par->gamma.num_curves) { ++ dev_err(par->info->device, "Gamma: Too many curves\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ curve_p = strsep(&str_p, "\n"); ++ value_counter = 0; ++ while (curve_p) { ++ if (value_counter == par->gamma.num_values) { ++ dev_err(par->info->device, ++ "Gamma: Too many values\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ret = get_next_ulong(&curve_p, &val, " ", 16); ++ if (ret) ++ goto out; ++ curves[curve_counter * par->gamma.num_values + value_counter] = val; ++ value_counter++; ++ } ++ if (value_counter != par->gamma.num_values) { ++ dev_err(par->info->device, "Gamma: Too few values\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ curve_counter++; ++ } ++ if (curve_counter != par->gamma.num_curves) { ++ dev_err(par->info->device, "Gamma: Too few curves\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++out: ++ kfree(tmp); ++ return ret; ++} ++ ++static ssize_t ++sprintf_gamma(struct fbtft_par *par, unsigned long *curves, char *buf) ++{ ++ ssize_t len = 0; ++ unsigned int i, j; ++ ++ mutex_lock(&par->gamma.lock); ++ for (i = 0; i < par->gamma.num_curves; i++) { ++ for (j = 0; j < par->gamma.num_values; j++) ++ len += scnprintf(&buf[len], PAGE_SIZE, ++ "%04lx ", curves[i*par->gamma.num_values + j]); ++ buf[len-1] = '\n'; ++ } ++ mutex_unlock(&par->gamma.lock); ++ ++ return len; ++} ++ ++static ssize_t store_gamma_curve(struct device *device, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct fb_info *fb_info = dev_get_drvdata(device); ++ struct fbtft_par *par = fb_info->par; ++ unsigned long tmp_curves[FBTFT_GAMMA_MAX_VALUES_TOTAL]; ++ int ret; ++ ++ ret = fbtft_gamma_parse_str(par, tmp_curves, buf, count); ++ if (ret) ++ return ret; ++ ++ ret = par->fbtftops.set_gamma(par, tmp_curves); ++ if (ret) ++ return ret; ++ ++ mutex_lock(&par->gamma.lock); ++ memcpy(par->gamma.curves, tmp_curves, ++ par->gamma.num_curves * par->gamma.num_values * sizeof(tmp_curves[0])); ++ mutex_unlock(&par->gamma.lock); ++ ++ return count; ++} ++ ++static ssize_t show_gamma_curve(struct device *device, ++ struct device_attribute *attr, char *buf) ++{ ++ struct fb_info *fb_info = dev_get_drvdata(device); ++ struct fbtft_par *par = fb_info->par; ++ ++ return sprintf_gamma(par, par->gamma.curves, buf); ++} ++ ++static struct device_attribute gamma_device_attrs[] = { ++ __ATTR(gamma, 0660, show_gamma_curve, store_gamma_curve), ++}; ++ ++ ++void fbtft_expand_debug_value(unsigned long *debug) ++{ ++ switch (*debug & 0b111) { ++ case 1: ++ *debug |= DEBUG_LEVEL_1; ++ break; ++ case 2: ++ *debug |= DEBUG_LEVEL_2; ++ break; ++ case 3: ++ *debug |= DEBUG_LEVEL_3; ++ break; ++ case 4: ++ *debug |= DEBUG_LEVEL_4; ++ break; ++ case 5: ++ *debug |= DEBUG_LEVEL_5; ++ break; ++ case 6: ++ *debug |= DEBUG_LEVEL_6; ++ break; ++ case 7: ++ *debug = 0xFFFFFFFF; ++ break; ++ } ++} ++ ++static ssize_t store_debug(struct device *device, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct fb_info *fb_info = dev_get_drvdata(device); ++ struct fbtft_par *par = fb_info->par; ++ int ret; ++ ++ ret = kstrtoul(buf, 10, &par->debug); ++ if (ret) ++ return ret; ++ fbtft_expand_debug_value(&par->debug); ++ ++ return count; ++} ++ ++static ssize_t show_debug(struct device *device, ++ struct device_attribute *attr, char *buf) ++{ ++ struct fb_info *fb_info = dev_get_drvdata(device); ++ struct fbtft_par *par = fb_info->par; ++ ++ return snprintf(buf, PAGE_SIZE, "%lu\n", par->debug); ++} ++ ++static struct device_attribute debug_device_attr = \ ++ __ATTR(debug, 0660, show_debug, store_debug); ++ ++ ++void fbtft_sysfs_init(struct fbtft_par *par) ++{ ++ device_create_file(par->info->dev, &debug_device_attr); ++ if (par->gamma.curves && par->fbtftops.set_gamma) ++ device_create_file(par->info->dev, &gamma_device_attrs[0]); ++} ++ ++void fbtft_sysfs_exit(struct fbtft_par *par) ++{ ++ device_remove_file(par->info->dev, &debug_device_attr); ++ if (par->gamma.curves && par->fbtftops.set_gamma) ++ device_remove_file(par->info->dev, &gamma_device_attrs[0]); ++} +diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h +new file mode 100644 +index 0000000..0dbf3f9 +--- /dev/null ++++ b/drivers/staging/fbtft/fbtft.h +@@ -0,0 +1,447 @@ ++/* ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifndef __LINUX_FBTFT_H ++#define __LINUX_FBTFT_H ++ ++#include ++#include ++#include ++#include ++ ++ ++#define FBTFT_NOP 0x00 ++#define FBTFT_SWRESET 0x01 ++#define FBTFT_RDDID 0x04 ++#define FBTFT_RDDST 0x09 ++#define FBTFT_CASET 0x2A ++#define FBTFT_RASET 0x2B ++#define FBTFT_RAMWR 0x2C ++ ++#define FBTFT_ONBOARD_BACKLIGHT 2 ++ ++#define FBTFT_GPIO_NO_MATCH 0xFFFF ++#define FBTFT_GPIO_NAME_SIZE 32 ++#define FBTFT_MAX_INIT_SEQUENCE 512 ++#define FBTFT_GAMMA_MAX_VALUES_TOTAL 128 ++ ++#define FBTFT_OF_INIT_CMD BIT(24) ++#define FBTFT_OF_INIT_DELAY BIT(25) ++ ++/** ++ * struct fbtft_gpio - Structure that holds one pinname to gpio mapping ++ * @name: pinname (reset, dc, etc.) ++ * @gpio: GPIO number ++ * ++ */ ++struct fbtft_gpio { ++ char name[FBTFT_GPIO_NAME_SIZE]; ++ unsigned gpio; ++}; ++ ++struct fbtft_par; ++ ++/** ++ * struct fbtft_ops - FBTFT operations structure ++ * @write: Writes to interface bus ++ * @read: Reads from interface bus ++ * @write_vmem: Writes video memory to display ++ * @write_reg: Writes to controller register ++ * @set_addr_win: Set the GRAM update window ++ * @reset: Reset the LCD controller ++ * @mkdirty: Marks display lines for update ++ * @update_display: Updates the display ++ * @init_display: Initializes the display ++ * @blank: Blank the display (optional) ++ * @request_gpios_match: Do pinname to gpio matching ++ * @request_gpios: Request gpios from the kernel ++ * @free_gpios: Free previously requested gpios ++ * @verify_gpios: Verify that necessary gpios is present (optional) ++ * @register_backlight: Used to register backlight device (optional) ++ * @unregister_backlight: Unregister backlight device (optional) ++ * @set_var: Configure LCD with values from variables like @rotate and @bgr ++ * (optional) ++ * @set_gamma: Set Gamma curve (optional) ++ * ++ * Most of these operations have default functions assigned to them in ++ * fbtft_framebuffer_alloc() ++ */ ++struct fbtft_ops { ++ int (*write)(struct fbtft_par *par, void *buf, size_t len); ++ int (*read)(struct fbtft_par *par, void *buf, size_t len); ++ int (*write_vmem)(struct fbtft_par *par, size_t offset, size_t len); ++ void (*write_register)(struct fbtft_par *par, int len, ...); ++ ++ void (*set_addr_win)(struct fbtft_par *par, ++ int xs, int ys, int xe, int ye); ++ void (*reset)(struct fbtft_par *par); ++ void (*mkdirty)(struct fb_info *info, int from, int to); ++ void (*update_display)(struct fbtft_par *par, ++ unsigned start_line, unsigned end_line); ++ int (*init_display)(struct fbtft_par *par); ++ int (*blank)(struct fbtft_par *par, bool on); ++ ++ unsigned long (*request_gpios_match)(struct fbtft_par *par, ++ const struct fbtft_gpio *gpio); ++ int (*request_gpios)(struct fbtft_par *par); ++ int (*verify_gpios)(struct fbtft_par *par); ++ ++ void (*register_backlight)(struct fbtft_par *par); ++ void (*unregister_backlight)(struct fbtft_par *par); ++ ++ int (*set_var)(struct fbtft_par *par); ++ int (*set_gamma)(struct fbtft_par *par, unsigned long *curves); ++}; ++ ++/** ++ * struct fbtft_display - Describes the display properties ++ * @width: Width of display in pixels ++ * @height: Height of display in pixels ++ * @regwidth: LCD Controller Register width in bits ++ * @buswidth: Display interface bus width in bits ++ * @backlight: Backlight type. ++ * @fbtftops: FBTFT operations provided by driver or device (platform_data) ++ * @bpp: Bits per pixel ++ * @fps: Frames per second ++ * @txbuflen: Size of transmit buffer ++ * @init_sequence: Pointer to LCD initialization array ++ * @gamma: String representation of Gamma curve(s) ++ * @gamma_num: Number of Gamma curves ++ * @gamma_len: Number of values per Gamma curve ++ * @debug: Initial debug value ++ * ++ * This structure is not stored by FBTFT except for init_sequence. ++ */ ++struct fbtft_display { ++ unsigned width; ++ unsigned height; ++ unsigned regwidth; ++ unsigned buswidth; ++ unsigned backlight; ++ struct fbtft_ops fbtftops; ++ unsigned bpp; ++ unsigned fps; ++ int txbuflen; ++ int *init_sequence; ++ char *gamma; ++ int gamma_num; ++ int gamma_len; ++ unsigned long debug; ++}; ++ ++/** ++ * struct fbtft_platform_data - Passes display specific data to the driver ++ * @display: Display properties ++ * @gpios: Pointer to an array of piname to gpio mappings ++ * @rotate: Display rotation angle ++ * @bgr: LCD Controller BGR bit ++ * @fps: Frames per second (this will go away, use @fps in @fbtft_display) ++ * @txbuflen: Size of transmit buffer ++ * @startbyte: When set, enables use of Startbyte in transfers ++ * @gamma: String representation of Gamma curve(s) ++ * @extra: A way to pass extra info ++ */ ++struct fbtft_platform_data { ++ struct fbtft_display display; ++ const struct fbtft_gpio *gpios; ++ unsigned rotate; ++ bool bgr; ++ unsigned fps; ++ int txbuflen; ++ u8 startbyte; ++ char *gamma; ++ void *extra; ++}; ++ ++/** ++ * struct fbtft_par - Main FBTFT data structure ++ * ++ * This structure holds all relevant data to operate the display ++ * ++ * See sourcefile for documentation since nested structs is not ++ * supported by kernel-doc. ++ * ++ */ ++/* @spi: Set if it is a SPI device ++ * @pdev: Set if it is a platform device ++ * @info: Pointer to framebuffer fb_info structure ++ * @pdata: Pointer to platform data ++ * @ssbuf: Not used ++ * @pseudo_palette: Used by fb_set_colreg() ++ * @txbuf.buf: Transmit buffer ++ * @txbuf.len: Transmit buffer length ++ * @buf: Small buffer used when writing init data over SPI ++ * @startbyte: Used by some controllers when in SPI mode. ++ * Format: 6 bit Device id + RS bit + RW bit ++ * @fbtftops: FBTFT operations provided by driver or device (platform_data) ++ * @dirty_lock: Protects dirty_lines_start and dirty_lines_end ++ * @dirty_lines_start: Where to begin updating display ++ * @dirty_lines_end: Where to end updating display ++ * @gpio.reset: GPIO used to reset display ++ * @gpio.dc: Data/Command signal, also known as RS ++ * @gpio.rd: Read latching signal ++ * @gpio.wr: Write latching signal ++ * @gpio.latch: Bus latch signal, eg. 16->8 bit bus latch ++ * @gpio.cs: LCD Chip Select with parallel interface bus ++ * @gpio.db[16]: Parallel databus ++ * @gpio.led[16]: Led control signals ++ * @gpio.aux[16]: Auxillary signals, not used by core ++ * @init_sequence: Pointer to LCD initialization array ++ * @gamma.lock: Mutex for Gamma curve locking ++ * @gamma.curves: Pointer to Gamma curve array ++ * @gamma.num_values: Number of values per Gamma curve ++ * @gamma.num_curves: Number of Gamma curves ++ * @debug: Pointer to debug value ++ * @current_debug: ++ * @first_update_done: Used to only time the first display update ++ * @update_time: Used to calculate 'fps' in debug output ++ * @bgr: BGR mode/\n ++ * @extra: Extra info needed by driver ++ */ ++struct fbtft_par { ++ struct spi_device *spi; ++ struct platform_device *pdev; ++ struct fb_info *info; ++ struct fbtft_platform_data *pdata; ++ u16 *ssbuf; ++ u32 pseudo_palette[16]; ++ struct { ++ void *buf; ++ dma_addr_t dma; ++ size_t len; ++ } txbuf; ++ u8 *buf; ++ u8 startbyte; ++ struct fbtft_ops fbtftops; ++ spinlock_t dirty_lock; ++ unsigned dirty_lines_start; ++ unsigned dirty_lines_end; ++ struct { ++ int reset; ++ int dc; ++ int rd; ++ int wr; ++ int latch; ++ int cs; ++ int db[16]; ++ int led[16]; ++ int aux[16]; ++ } gpio; ++ int *init_sequence; ++ struct { ++ struct mutex lock; ++ unsigned long *curves; ++ int num_values; ++ int num_curves; ++ } gamma; ++ unsigned long debug; ++ bool first_update_done; ++ struct timespec update_time; ++ bool bgr; ++ void *extra; ++}; ++ ++#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int)) ++ ++#define write_reg(par, ...) \ ++do { \ ++ par->fbtftops.write_register(par, NUMARGS(__VA_ARGS__), __VA_ARGS__); \ ++} while (0) ++ ++/* fbtft-core.c */ ++extern void fbtft_dbg_hex(const struct device *dev, ++ int groupsize, void *buf, size_t len, const char *fmt, ...); ++extern struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, ++ struct device *dev); ++extern void fbtft_framebuffer_release(struct fb_info *info); ++extern int fbtft_register_framebuffer(struct fb_info *fb_info); ++extern int fbtft_unregister_framebuffer(struct fb_info *fb_info); ++extern void fbtft_register_backlight(struct fbtft_par *par); ++extern void fbtft_unregister_backlight(struct fbtft_par *par); ++extern int fbtft_init_display(struct fbtft_par *par); ++extern int fbtft_probe_common(struct fbtft_display *display, ++ struct spi_device *sdev, struct platform_device *pdev); ++extern int fbtft_remove_common(struct device *dev, struct fb_info *info); ++ ++/* fbtft-io.c */ ++extern int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len); ++extern int fbtft_write_spi_emulate_9(struct fbtft_par *par, ++ void *buf, size_t len); ++extern int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len); ++extern int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len); ++extern int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len); ++extern int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, ++ void *buf, size_t len); ++ ++/* fbtft-bus.c */ ++extern int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len); ++extern int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len); ++extern int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len); ++extern int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len); ++extern void fbtft_write_reg8_bus8(struct fbtft_par *par, int len, ...); ++extern void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...); ++extern void fbtft_write_reg16_bus8(struct fbtft_par *par, int len, ...); ++extern void fbtft_write_reg16_bus16(struct fbtft_par *par, int len, ...); ++ ++ ++#define FBTFT_REGISTER_DRIVER(_name, _compatible, _display) \ ++ \ ++static int fbtft_driver_probe_spi(struct spi_device *spi) \ ++{ \ ++ return fbtft_probe_common(_display, spi, NULL); \ ++} \ ++ \ ++static int fbtft_driver_remove_spi(struct spi_device *spi) \ ++{ \ ++ struct fb_info *info = spi_get_drvdata(spi); \ ++ \ ++ return fbtft_remove_common(&spi->dev, info); \ ++} \ ++ \ ++static int fbtft_driver_probe_pdev(struct platform_device *pdev) \ ++{ \ ++ return fbtft_probe_common(_display, NULL, pdev); \ ++} \ ++ \ ++static int fbtft_driver_remove_pdev(struct platform_device *pdev) \ ++{ \ ++ struct fb_info *info = platform_get_drvdata(pdev); \ ++ \ ++ return fbtft_remove_common(&pdev->dev, info); \ ++} \ ++ \ ++static const struct of_device_id dt_ids[] = { \ ++ { .compatible = _compatible }, \ ++ {}, \ ++}; \ ++ \ ++MODULE_DEVICE_TABLE(of, dt_ids); \ ++ \ ++ \ ++static struct spi_driver fbtft_driver_spi_driver = { \ ++ .driver = { \ ++ .name = _name, \ ++ .owner = THIS_MODULE, \ ++ .of_match_table = of_match_ptr(dt_ids), \ ++ }, \ ++ .probe = fbtft_driver_probe_spi, \ ++ .remove = fbtft_driver_remove_spi, \ ++}; \ ++ \ ++static struct platform_driver fbtft_driver_platform_driver = { \ ++ .driver = { \ ++ .name = _name, \ ++ .owner = THIS_MODULE, \ ++ .of_match_table = of_match_ptr(dt_ids), \ ++ }, \ ++ .probe = fbtft_driver_probe_pdev, \ ++ .remove = fbtft_driver_remove_pdev, \ ++}; \ ++ \ ++static int __init fbtft_driver_module_init(void) \ ++{ \ ++ int ret; \ ++ \ ++ ret = spi_register_driver(&fbtft_driver_spi_driver); \ ++ if (ret < 0) \ ++ return ret; \ ++ return platform_driver_register(&fbtft_driver_platform_driver); \ ++} \ ++ \ ++static void __exit fbtft_driver_module_exit(void) \ ++{ \ ++ spi_unregister_driver(&fbtft_driver_spi_driver); \ ++ platform_driver_unregister(&fbtft_driver_platform_driver); \ ++} \ ++ \ ++module_init(fbtft_driver_module_init); \ ++module_exit(fbtft_driver_module_exit); ++ ++ ++/* Debug macros */ ++ ++/* shorthand debug levels */ ++#define DEBUG_LEVEL_1 DEBUG_REQUEST_GPIOS ++#define DEBUG_LEVEL_2 (DEBUG_LEVEL_1 | DEBUG_DRIVER_INIT_FUNCTIONS | DEBUG_TIME_FIRST_UPDATE) ++#define DEBUG_LEVEL_3 (DEBUG_LEVEL_2 | DEBUG_RESET | DEBUG_INIT_DISPLAY | DEBUG_BLANK | DEBUG_REQUEST_GPIOS | DEBUG_FREE_GPIOS | DEBUG_VERIFY_GPIOS | DEBUG_BACKLIGHT | DEBUG_SYSFS) ++#define DEBUG_LEVEL_4 (DEBUG_LEVEL_2 | DEBUG_FB_READ | DEBUG_FB_WRITE | DEBUG_FB_FILLRECT | DEBUG_FB_COPYAREA | DEBUG_FB_IMAGEBLIT | DEBUG_FB_BLANK) ++#define DEBUG_LEVEL_5 (DEBUG_LEVEL_3 | DEBUG_UPDATE_DISPLAY) ++#define DEBUG_LEVEL_6 (DEBUG_LEVEL_4 | DEBUG_LEVEL_5) ++#define DEBUG_LEVEL_7 0xFFFFFFFF ++ ++#define DEBUG_DRIVER_INIT_FUNCTIONS (1<<3) ++#define DEBUG_TIME_FIRST_UPDATE (1<<4) ++#define DEBUG_TIME_EACH_UPDATE (1<<5) ++#define DEBUG_DEFERRED_IO (1<<6) ++#define DEBUG_FBTFT_INIT_FUNCTIONS (1<<7) ++ ++/* fbops */ ++#define DEBUG_FB_READ (1<<8) ++#define DEBUG_FB_WRITE (1<<9) ++#define DEBUG_FB_FILLRECT (1<<10) ++#define DEBUG_FB_COPYAREA (1<<11) ++#define DEBUG_FB_IMAGEBLIT (1<<12) ++#define DEBUG_FB_SETCOLREG (1<<13) ++#define DEBUG_FB_BLANK (1<<14) ++ ++#define DEBUG_SYSFS (1<<16) ++ ++/* fbtftops */ ++#define DEBUG_BACKLIGHT (1<<17) ++#define DEBUG_READ (1<<18) ++#define DEBUG_WRITE (1<<19) ++#define DEBUG_WRITE_VMEM (1<<20) ++#define DEBUG_WRITE_REGISTER (1<<21) ++#define DEBUG_SET_ADDR_WIN (1<<22) ++#define DEBUG_RESET (1<<23) ++#define DEBUG_MKDIRTY (1<<24) ++#define DEBUG_UPDATE_DISPLAY (1<<25) ++#define DEBUG_INIT_DISPLAY (1<<26) ++#define DEBUG_BLANK (1<<27) ++#define DEBUG_REQUEST_GPIOS (1<<28) ++#define DEBUG_FREE_GPIOS (1<<29) ++#define DEBUG_REQUEST_GPIOS_MATCH (1<<30) ++#define DEBUG_VERIFY_GPIOS (1<<31) ++ ++ ++#define fbtft_init_dbg(dev, format, arg...) \ ++do { \ ++ if (unlikely((dev)->platform_data && \ ++ (((struct fbtft_platform_data *)(dev)->platform_data)->display.debug & DEBUG_DRIVER_INIT_FUNCTIONS))) \ ++ dev_info(dev, format, ##arg); \ ++} while (0) ++ ++#define fbtft_par_dbg(level, par, format, arg...) \ ++do { \ ++ if (unlikely(par->debug & level)) \ ++ dev_info(par->info->device, format, ##arg); \ ++} while (0) ++ ++#define fbtft_dev_dbg(level, par, dev, format, arg...) \ ++do { \ ++ if (unlikely(par->debug & level)) \ ++ dev_info(dev, format, ##arg); \ ++} while (0) ++ ++#define fbtft_par_dbg_hex(level, par, dev, type, buf, num, format, arg...) \ ++do { \ ++ if (unlikely(par->debug & level)) \ ++ fbtft_dbg_hex(dev, sizeof(type), buf, num * sizeof(type), format, ##arg); \ ++} while (0) ++ ++#endif /* __LINUX_FBTFT_H */ + +From 1903bbb366ab84fead8c671849cc4815777ea0fb Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:10 +0100 +Subject: [PATCH 126/178] staging: fbtft: add fb_agm1264k-fl driver + +This commit adds the fb_agm1264k-fl driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 + + drivers/staging/fbtft/Makefile | 3 + + drivers/staging/fbtft/fb_agm1264k-fl.c | 462 +++++++++++++++++++++++++++++++++ + 3 files changed, 471 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_agm1264k-fl.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 3d6598b..d552af6 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -7,3 +7,9 @@ menuconfig FB_TFT + select FB_SYS_FOPS + select FB_DEFERRED_IO + select FB_BACKLIGHT ++ ++config FB_TFT_AGM1264K_FL ++ tristate "FB driver for the AGM1264K-FL LCD display" ++ depends on FB_TFT ++ help ++ Framebuffer support for the AGM1264K-FL LCD display (two Samsung KS0108 compatable chips) +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 9132dde..eb13cc5 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -1,3 +1,6 @@ + # Core module + obj-$(CONFIG_FB_TFT) += fbtft.o + fbtft-y += fbtft-core.o fbtft-sysfs.o fbtft-bus.o fbtft-io.o ++ ++# drivers ++obj-$(CONFIG_FB_TFT_AGM1264K_FL) += fb_agm1264k-fl.o +diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c +new file mode 100644 +index 0000000..7fe4fa0 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_agm1264k-fl.c +@@ -0,0 +1,462 @@ ++/* ++ * FB driver for Two KS0108 LCD controllers in AGM1264K-FL display ++ * ++ * Copyright (C) 2014 ololoshka2871 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++/* Uncomment text line to use negative image on display */ ++/*#define NEGATIVE*/ ++ ++#define WHITE 0xff ++#define BLACK 0 ++ ++#define DRVNAME "fb_agm1264k-fl" ++#define WIDTH 64 ++#define HEIGHT 64 ++#define TOTALWIDTH (WIDTH * 2) /* because 2 x ks0108 in one display */ ++#define FPS 20 ++ ++#define EPIN gpio.wr ++#define RS gpio.dc ++#define RW gpio.aux[2] ++#define CS0 gpio.aux[0] ++#define CS1 gpio.aux[1] ++ ++ ++/* diffusing error (“Floyd-Steinberg”) */ ++#define DIFFUSING_MATRIX_WIDTH 2 ++#define DIFFUSING_MATRIX_HEIGHT 2 ++ ++static const signed char ++diffusing_matrix[DIFFUSING_MATRIX_WIDTH][DIFFUSING_MATRIX_HEIGHT] = { ++ {-1, 3}, ++ {3, 2}, ++}; ++ ++static const unsigned char gamma_correction_table[] = { ++0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, ++1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, ++6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, ++13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, ++22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, ++33, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 43, 44, 45, ++46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, ++62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 81, ++82, 83, 84, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 98, 99, 100, 102, ++103, 105, 106, 107, 109, 110, 111, 113, 114, 116, 117, 119, 120, 121, ++123, 124, 126, 127, 129, 130, 132, 133, 135, 137, 138, 140, 141, 143, ++145, 146, 148, 149, 151, 153, 154, 156, 158, 159, 161, 163, 165, 166, ++168, 170, 172, 173, 175, 177, 179, 181, 182, 184, 186, 188, 190, 192, ++194, 196, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, ++221, 223, 225, 227, 229, 231, 234, 236, 238, 240, 242, 244, 246, 248, ++251, 253, 255 ++}; ++ ++static int init_display(struct fbtft_par *par) ++{ ++ u8 i; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ for (i = 0; i < 2; ++i) { ++ write_reg(par, i, 0x3f); /* display on */ ++ write_reg(par, i, 0x40); /* set x to 0 */ ++ write_reg(par, i, 0xb0); /* set page to 0 */ ++ write_reg(par, i, 0xc0); /* set start line to 0 */ ++ } ++ ++ return 0; ++} ++ ++void reset(struct fbtft_par *par) ++{ ++ if (par->gpio.reset == -1) ++ return; ++ ++ fbtft_dev_dbg(DEBUG_RESET, par, par->info->device, "%s()\n", __func__); ++ ++ gpio_set_value(par->gpio.reset, 0); ++ udelay(20); ++ gpio_set_value(par->gpio.reset, 1); ++ mdelay(120); ++} ++ ++/* Check if all necessary GPIOS defined */ ++static int verify_gpios(struct fbtft_par *par) ++{ ++ int i; ++ ++ fbtft_dev_dbg(DEBUG_VERIFY_GPIOS, par, par->info->device, ++ "%s()\n", __func__); ++ ++ if (par->EPIN < 0) { ++ dev_err(par->info->device, ++ "Missing info about 'wr' (aka E) gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ for (i = 0; i < 8; ++i) { ++ if (par->gpio.db[i] < 0) { ++ dev_err(par->info->device, ++ "Missing info about 'db[%i]' gpio. Aborting.\n", ++ i); ++ return -EINVAL; ++ } ++ } ++ if (par->CS0 < 0) { ++ dev_err(par->info->device, ++ "Missing info about 'cs0' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ if (par->CS1 < 0) { ++ dev_err(par->info->device, ++ "Missing info about 'cs1' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ if (par->RW < 0) { ++ dev_err(par->info->device, ++ "Missing info about 'rw' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static unsigned long ++request_gpios_match(struct fbtft_par *par, const struct fbtft_gpio *gpio) ++{ ++ fbtft_dev_dbg(DEBUG_REQUEST_GPIOS_MATCH, par, par->info->device, ++ "%s('%s')\n", __func__, gpio->name); ++ ++ if (strcasecmp(gpio->name, "wr") == 0) { ++ /* left ks0108 E pin */ ++ par->EPIN = gpio->gpio; ++ return GPIOF_OUT_INIT_LOW; ++ } else if (strcasecmp(gpio->name, "cs0") == 0) { ++ /* left ks0108 controller pin */ ++ par->CS0 = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } else if (strcasecmp(gpio->name, "cs1") == 0) { ++ /* right ks0108 controller pin */ ++ par->CS1 = gpio->gpio; ++ return GPIOF_OUT_INIT_HIGH; ++ } ++ ++ /* if write (rw = 0) e(1->0) perform write */ ++ /* if read (rw = 1) e(0->1) set data on D0-7*/ ++ else if (strcasecmp(gpio->name, "rw") == 0) { ++ par->RW = gpio->gpio; ++ return GPIOF_OUT_INIT_LOW; ++ } ++ ++ return FBTFT_GPIO_NO_MATCH; ++} ++ ++/* This function oses to enter commands ++ * first byte - destination controller 0 or 1 ++ * folowing - commands ++ */ ++static void write_reg8_bus8(struct fbtft_par *par, int len, ...) ++{ ++ va_list args; ++ int i, ret; ++ u8 *buf = (u8 *)par->buf; ++ ++ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { ++ va_start(args, len); ++ for (i = 0; i < len; i++) ++ buf[i] = (u8)va_arg(args, unsigned int); ++ ++ va_end(args); ++ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, ++ par->info->device, u8, buf, len, "%s: ", __func__); ++ } ++ ++ va_start(args, len); ++ ++ *buf = (u8)va_arg(args, unsigned int); ++ ++ if (*buf > 1) { ++ va_end(args); ++ dev_err(par->info->device, "%s: Incorrect chip sellect request (%d)\n", ++ __func__, *buf); ++ return; ++ } ++ ++ /* select chip */ ++ if (*buf) { ++ /* cs1 */ ++ gpio_set_value(par->CS0, 1); ++ gpio_set_value(par->CS1, 0); ++ } else { ++ /* cs0 */ ++ gpio_set_value(par->CS0, 0); ++ gpio_set_value(par->CS1, 1); ++ } ++ ++ gpio_set_value(par->RS, 0); /* RS->0 (command mode) */ ++ len--; ++ ++ if (len) { ++ i = len; ++ while (i--) ++ *buf++ = (u8)va_arg(args, unsigned int); ++ ret = par->fbtftops.write(par, par->buf, len * (sizeof(u8))); ++ if (ret < 0) { ++ va_end(args); ++ dev_err(par->info->device, "%s: write() failed and returned %d\n", ++ __func__, ret); ++ return; ++ } ++ } ++ ++ va_end(args); ++} ++ ++static struct ++{ ++ int xs, ys_page, xe, ye_page; ++} addr_win; ++ ++/* save display writing zone */ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ addr_win.xs = xs; ++ addr_win.ys_page = ys / 8; ++ addr_win.xe = xe; ++ addr_win.ye_page = ye / 8; ++ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys_page=%d, xe=%d, ye_page=%d)\n", __func__, ++ addr_win.xs, addr_win.ys_page, addr_win.xe, addr_win.ye_page); ++} ++ ++static void ++construct_line_bitmap(struct fbtft_par *par, u8 *dest, signed short *src, ++ int xs, int xe, int y) ++{ ++ int x, i; ++ ++ for (x = xs; x < xe; ++x) { ++ u8 res = 0; ++ ++ for (i = 0; i < 8; i++) ++ if (src[(y * 8 + i) * par->info->var.xres + x]) ++ res |= 1 << i; ++#ifdef NEGATIVE ++ *dest++ = res; ++#else ++ *dest++ = ~res; ++#endif ++ } ++} ++ ++static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16 = (u16 *)par->info->screen_base; ++ u8 *buf = par->txbuf.buf; ++ int x, y; ++ int ret = 0; ++ ++ /* buffer to convert RGB565 -> grayscale16 -> Ditherd image 1bpp */ ++ signed short *convert_buf = kmalloc(par->info->var.xres * ++ par->info->var.yres * sizeof(signed short), GFP_NOIO); ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ /* converting to grayscale16 */ ++ for (x = 0; x < par->info->var.xres; ++x) ++ for (y = 0; y < par->info->var.yres; ++y) { ++ u16 pixel = vmem16[y * par->info->var.xres + x]; ++ u16 b = pixel & 0x1f; ++ u16 g = (pixel & (0x3f << 5)) >> 5; ++ u16 r = (pixel & (0x1f << (5 + 6))) >> (5 + 6); ++ ++ pixel = (299 * r + 587 * g + 114 * b) / 200; ++ if (pixel > 255) ++ pixel = 255; ++ ++ /* gamma-correction by table */ ++ convert_buf[y * par->info->var.xres + x] = ++ (signed short)gamma_correction_table[pixel]; ++ } ++ ++ /* Image Dithering */ ++ for (x = 0; x < par->info->var.xres; ++x) ++ for (y = 0; y < par->info->var.yres; ++y) { ++ signed short pixel = ++ convert_buf[y * par->info->var.xres + x]; ++ signed short error_b = pixel - BLACK; ++ signed short error_w = pixel - WHITE; ++ signed short error; ++ u16 i, j; ++ ++ /* what color close? */ ++ if (abs(error_b) >= abs(error_w)) { ++ /* white */ ++ error = error_w; ++ pixel = 0xff; ++ } else { ++ /* black */ ++ error = error_b; ++ pixel = 0; ++ } ++ ++ error /= 8; ++ ++ /* diffusion matrix row */ ++ for (i = 0; i < DIFFUSING_MATRIX_WIDTH; ++i) ++ /* diffusion matrix column */ ++ for (j = 0; j < DIFFUSING_MATRIX_HEIGHT; ++j) { ++ signed short *write_pos; ++ signed char coeff; ++ ++ /* skip pixels out of zone */ ++ if (x + i < 0 || ++ x + i >= par->info->var.xres ++ || y + j >= par->info->var.yres) ++ continue; ++ write_pos = &convert_buf[ ++ (y + j) * par->info->var.xres + ++ x + i]; ++ coeff = diffusing_matrix[i][j]; ++ if (coeff == -1) ++ /* pixel itself */ ++ *write_pos = pixel; ++ else { ++ signed short p = *write_pos + ++ error * coeff; ++ ++ if (p > WHITE) ++ p = WHITE; ++ if (p < BLACK) ++ p = BLACK; ++ *write_pos = p; ++ } ++ } ++ } ++ ++ /* 1 string = 2 pages */ ++ for (y = addr_win.ys_page; y <= addr_win.ye_page; ++y) { ++ /* left half of display */ ++ if (addr_win.xs < par->info->var.xres / 2) { ++ construct_line_bitmap(par, buf, convert_buf, ++ addr_win.xs, par->info->var.xres / 2, y); ++ ++ len = par->info->var.xres / 2 - addr_win.xs; ++ ++ /* select left side (sc0) ++ * set addr ++ */ ++ write_reg(par, 0x00, (1 << 6) | (u8)addr_win.xs); ++ write_reg(par, 0x00, (0x17 << 3) | (u8)y); ++ ++ /* write bitmap */ ++ gpio_set_value(par->RS, 1); /* RS->1 (data mode) */ ++ ret = par->fbtftops.write(par, buf, len); ++ if (ret < 0) ++ dev_err(par->info->device, ++ "%s: write failed and returned: %d\n", ++ __func__, ret); ++ } ++ /* right half of display */ ++ if (addr_win.xe >= par->info->var.xres / 2) { ++ construct_line_bitmap(par, buf, ++ convert_buf, par->info->var.xres / 2, ++ addr_win.xe + 1, y); ++ ++ len = addr_win.xe + 1 - par->info->var.xres / 2; ++ ++ /* select right side (sc1) ++ * set addr ++ */ ++ write_reg(par, 0x01, (1 << 6)); ++ write_reg(par, 0x01, (0x17 << 3) | (u8)y); ++ ++ /* write bitmap */ ++ gpio_set_value(par->RS, 1); /* RS->1 (data mode) */ ++ par->fbtftops.write(par, buf, len); ++ if (ret < 0) ++ dev_err(par->info->device, ++ "%s: write failed and returned: %d\n", ++ __func__, ret); ++ } ++ } ++ kfree(convert_buf); ++ ++ gpio_set_value(par->CS0, 1); ++ gpio_set_value(par->CS1, 1); ++ ++ return ret; ++} ++ ++static int write(struct fbtft_par *par, void *buf, size_t len) ++{ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ gpio_set_value(par->RW, 0); /* set write mode */ ++ ++ ++ while (len--) { ++ u8 i, data; ++ ++ data = *(u8 *) buf++; ++ ++ /* set data bus */ ++ for (i = 0; i < 8; ++i) ++ gpio_set_value(par->gpio.db[i], data & (1 << i)); ++ /* set E */ ++ gpio_set_value(par->EPIN, 1); ++ udelay(5); ++ /* unset E - write */ ++ gpio_set_value(par->EPIN, 0); ++ udelay(1); ++ } ++ ++ return 0; ++} ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = TOTALWIDTH, ++ .height = HEIGHT, ++ .fps = FPS, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .verify_gpios = verify_gpios, ++ .request_gpios_match = request_gpios_match, ++ .reset = reset, ++ .write = write, ++ .write_register = write_reg8_bus8, ++ .write_vmem = write_vmem, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "displaytronic,fb_agm1264k-fl", &display); ++ ++MODULE_ALIAS("platform:" DRVNAME); ++ ++MODULE_DESCRIPTION("Two KS0108 LCD controllers in AGM1264K-FL display"); ++MODULE_AUTHOR("ololoshka2871"); ++MODULE_LICENSE("GPL"); + +From e9ec02ed846b1b53478a0d4e83d133165f53a5a6 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:11 +0100 +Subject: [PATCH 127/178] staging: fbtft: add fb_bd663474 driver + +This commit adds the fb_bd663474 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_bd663474.c | 193 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 200 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_bd663474.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index d552af6..400492a 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -13,3 +13,9 @@ config FB_TFT_AGM1264K_FL + depends on FB_TFT + help + Framebuffer support for the AGM1264K-FL LCD display (two Samsung KS0108 compatable chips) ++ ++config FB_TFT_BD663474 ++ tristate "FB driver for the BD663474 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for BD663474 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index eb13cc5..9f80a6e 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -4,3 +4,4 @@ fbtft-y += fbtft-core.o fbtft-sysfs.o fbtft-bus.o fbtft + + # drivers + obj-$(CONFIG_FB_TFT_AGM1264K_FL) += fb_agm1264k-fl.o ++obj-$(CONFIG_FB_TFT_BD663474) += fb_bd663474.o +diff --git a/drivers/staging/fbtft/fb_bd663474.c b/drivers/staging/fbtft/fb_bd663474.c +new file mode 100644 +index 0000000..7e00c60 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_bd663474.c +@@ -0,0 +1,193 @@ ++/* ++ * FB driver for the uPD161704 LCD Controller ++ * ++ * Copyright (C) 2014 Seong-Woo Kim ++ * ++ * Based on fb_ili9325.c by Noralf Tronnes ++ * Based on ili9325.c by Jeroen Domburg ++ * Init code from UTFT library by Henning Karlsen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_bd663474" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define BPP 16 ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ ++ par->fbtftops.reset(par); ++ ++ /* Initialization sequence from Lib_UTFT */ ++ ++ /* oscillator start */ ++ write_reg(par, 0x000,0x0001); /*oscillator 0: stop, 1: operation */ ++ mdelay(10); ++ ++ /* Power settings */ ++ write_reg(par, 0x100, 0x0000 ); /* power supply setup */ ++ write_reg(par, 0x101, 0x0000 ); ++ write_reg(par, 0x102, 0x3110 ); ++ write_reg(par, 0x103, 0xe200 ); ++ write_reg(par, 0x110, 0x009d ); ++ write_reg(par, 0x111, 0x0022 ); ++ write_reg(par, 0x100, 0x0120 ); ++ mdelay( 20 ); ++ ++ write_reg(par, 0x100, 0x3120 ); ++ mdelay( 80 ); ++ /* Display control */ ++ write_reg(par, 0x001, 0x0100 ); ++ write_reg(par, 0x002, 0x0000 ); ++ write_reg(par, 0x003, 0x1230 ); ++ write_reg(par, 0x006, 0x0000 ); ++ write_reg(par, 0x007, 0x0101 ); ++ write_reg(par, 0x008, 0x0808 ); ++ write_reg(par, 0x009, 0x0000 ); ++ write_reg(par, 0x00b, 0x0000 ); ++ write_reg(par, 0x00c, 0x0000 ); ++ write_reg(par, 0x00d, 0x0018 ); ++ /* LTPS control settings */ ++ write_reg(par, 0x012, 0x0000 ); ++ write_reg(par, 0x013, 0x0000 ); ++ write_reg(par, 0x018, 0x0000 ); ++ write_reg(par, 0x019, 0x0000 ); ++ ++ write_reg(par, 0x203, 0x0000 ); ++ write_reg(par, 0x204, 0x0000 ); ++ ++ write_reg(par, 0x210, 0x0000 ); ++ write_reg(par, 0x211, 0x00ef ); ++ write_reg(par, 0x212, 0x0000 ); ++ write_reg(par, 0x213, 0x013f ); ++ write_reg(par, 0x214, 0x0000 ); ++ write_reg(par, 0x215, 0x0000 ); ++ write_reg(par, 0x216, 0x0000 ); ++ write_reg(par, 0x217, 0x0000 ); ++ ++ /* Gray scale settings */ ++ write_reg(par, 0x300, 0x5343); ++ write_reg(par, 0x301, 0x1021); ++ write_reg(par, 0x302, 0x0003); ++ write_reg(par, 0x303, 0x0011); ++ write_reg(par, 0x304, 0x050a); ++ write_reg(par, 0x305, 0x4342); ++ write_reg(par, 0x306, 0x1100); ++ write_reg(par, 0x307, 0x0003); ++ write_reg(par, 0x308, 0x1201); ++ write_reg(par, 0x309, 0x050a); ++ ++ /* RAM access settings */ ++ write_reg(par, 0x400, 0x4027 ); ++ write_reg(par, 0x401, 0x0000 ); ++ write_reg(par, 0x402, 0x0000 ); /* First screen drive position (1) */ ++ write_reg(par, 0x403, 0x013f ); /* First screen drive position (2) */ ++ write_reg(par, 0x404, 0x0000 ); ++ ++ write_reg(par, 0x200, 0x0000 ); ++ write_reg(par, 0x201, 0x0000 ); ++ write_reg(par, 0x100, 0x7120 ); ++ write_reg(par, 0x007, 0x0103 ); ++ mdelay( 10 ); ++ write_reg(par, 0x007, 0x0113 ); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ switch (par->info->var.rotate) { ++ /* R200h = Horizontal GRAM Start Address */ ++ /* R201h = Vertical GRAM Start Address */ ++ case 0: ++ write_reg(par, 0x0200, xs); ++ write_reg(par, 0x0201, ys); ++ break; ++ case 180: ++ write_reg(par, 0x0200, WIDTH - 1 - xs); ++ write_reg(par, 0x0201, HEIGHT - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x0200, WIDTH - 1 - ys); ++ write_reg(par, 0x0201, xs); ++ break; ++ case 90: ++ write_reg(par, 0x0200, ys); ++ write_reg(par, 0x0201, HEIGHT - 1 - xs); ++ break; ++ } ++ write_reg(par, 0x202); /* Write Data to GRAM */ ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ /* AM: GRAM update direction */ ++ case 0: ++ write_reg(par, 0x003, 0x1230); ++ break; ++ case 180: ++ write_reg(par, 0x003, 0x1200); ++ break; ++ case 270: ++ write_reg(par, 0x003, 0x1228); ++ break; ++ case 90: ++ write_reg(par, 0x003, 0x1218); ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct fbtft_display display = { ++ .regwidth = 16, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .bpp = BPP, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "hitachi,bd663474", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:bd663474"); ++MODULE_ALIAS("platform:bd663474"); ++ ++MODULE_DESCRIPTION("FB driver for the uPD161704 LCD Controller"); ++MODULE_AUTHOR("Seong-Woo Kim"); ++MODULE_LICENSE("GPL"); + +From b554a0b37bf476fadf7ff1e9211899c960dd9729 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:12 +0100 +Subject: [PATCH 128/178] staging: fbtft: add fb_hx8340bn driver + +This commit adds the fb_hx8340bn driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 + + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_hx8340bn.c | 229 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 236 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_hx8340bn.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 400492a..e6c23d5e 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -19,3 +19,9 @@ config FB_TFT_BD663474 + depends on FB_TFT + help + Generic Framebuffer support for BD663474 ++ ++config FB_TFT_HX8340BN ++ tristate "FB driver for the HX8340BN LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for HX8340BN +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 9f80a6e..7d89af7 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -5,3 +5,4 @@ fbtft-y += fbtft-core.o fbtft-sysfs.o fbtft-bus.o fbtft + # drivers + obj-$(CONFIG_FB_TFT_AGM1264K_FL) += fb_agm1264k-fl.o + obj-$(CONFIG_FB_TFT_BD663474) += fb_bd663474.o ++obj-$(CONFIG_FB_TFT_HX8340BN) += fb_hx8340bn.o +diff --git a/drivers/staging/fbtft/fb_hx8340bn.c b/drivers/staging/fbtft/fb_hx8340bn.c +new file mode 100644 +index 0000000..3939502f +--- /dev/null ++++ b/drivers/staging/fbtft/fb_hx8340bn.c +@@ -0,0 +1,229 @@ ++/* ++ * FB driver for the HX8340BN LCD Controller ++ * ++ * This display uses 9-bit SPI: Data/Command bit + 8 data bits ++ * For platforms that doesn't support 9-bit, the driver is capable ++ * of emulating this using 8-bit transfer. ++ * This is done by transfering eight 9-bit words in 9 bytes. ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_hx8340bn" ++#define WIDTH 176 ++#define HEIGHT 220 ++#define TXBUFLEN (4 * PAGE_SIZE) ++#define DEFAULT_GAMMA "1 3 0E 5 0 2 09 0 6 1 7 1 0 2 2\n" \ ++ "3 3 17 8 4 7 05 7 6 0 3 1 6 0 0 " ++ ++ ++static bool emulate; ++module_param(emulate, bool, 0); ++MODULE_PARM_DESC(emulate, "Force emulation in 9-bit mode"); ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ /* BTL221722-276L startup sequence, from datasheet */ ++ ++ /* SETEXTCOM: Set extended command set (C1h) ++ This command is used to set extended command set access enable. ++ Enable: After command (C1h), must write: ffh,83h,40h */ ++ write_reg(par, 0xC1, 0xFF, 0x83, 0x40); ++ ++ /* Sleep out ++ This command turns off sleep mode. ++ In this mode the DC/DC converter is enabled, Internal oscillator ++ is started, and panel scanning is started. */ ++ write_reg(par, 0x11); ++ mdelay(150); ++ ++ /* Undoc'd register? */ ++ write_reg(par, 0xCA, 0x70, 0x00, 0xD9); ++ ++ /* SETOSC: Set Internal Oscillator (B0h) ++ This command is used to set internal oscillator related settings */ ++ /* OSC_EN: Enable internal oscillator */ ++ /* Internal oscillator frequency: 125% x 2.52MHz */ ++ write_reg(par, 0xB0, 0x01, 0x11); ++ ++ /* Drive ability setting */ ++ write_reg(par, 0xC9, 0x90, 0x49, 0x10, 0x28, 0x28, 0x10, 0x00, 0x06); ++ mdelay(20); ++ ++ /* SETPWCTR5: Set Power Control 5(B5h) ++ This command is used to set VCOM Low and VCOM High Voltage */ ++ /* VCOMH 0110101 : 3.925 */ ++ /* VCOML 0100000 : -1.700 */ ++ /* 45h=69 VCOMH: "VMH" + 5d VCOML: "VMH" + 5d */ ++ write_reg(par, 0xB5, 0x35, 0x20, 0x45); ++ ++ /* SETPWCTR4: Set Power Control 4(B4h) ++ VRH[4:0]: Specify the VREG1 voltage adjusting. ++ VREG1 voltage is for gamma voltage setting. ++ BT[2:0]: Switch the output factor of step-up circuit 2 ++ for VGH and VGL voltage generation. */ ++ write_reg(par, 0xB4, 0x33, 0x25, 0x4C); ++ mdelay(10); ++ ++ /* Interface Pixel Format (3Ah) ++ This command is used to define the format of RGB picture data, ++ which is to be transfer via the system and RGB interface. */ ++ /* RGB interface: 16 Bit/Pixel */ ++ write_reg(par, 0x3A, 0x05); ++ ++ /* Display on (29h) ++ This command is used to recover from DISPLAY OFF mode. ++ Output from the Frame Memory is enabled. */ ++ write_reg(par, 0x29); ++ mdelay(10); ++ ++ return 0; ++} ++ ++void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ write_reg(par, FBTFT_CASET, 0x00, xs, 0x00, xe); ++ write_reg(par, FBTFT_RASET, 0x00, ys, 0x00, ye); ++ write_reg(par, FBTFT_RAMWR); ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* MADCTL - Memory data access control */ ++ /* RGB/BGR can be set with H/W pin SRGB and MADCTL BGR bit */ ++#define MY (1 << 7) ++#define MX (1 << 6) ++#define MV (1 << 5) ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x36, (par->bgr << 3)); ++ break; ++ case 270: ++ write_reg(par, 0x36, MX | MV | (par->bgr << 3)); ++ break; ++ case 180: ++ write_reg(par, 0x36, MX | MY | (par->bgr << 3)); ++ break; ++ case 90: ++ write_reg(par, 0x36, MY | MV | (par->bgr << 3)); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Gamma Curve selection, GC (only GC0 can be customized): ++ 0 = 2.2, 1 = 1.8, 2 = 2.5, 3 = 1.0 ++ Gamma string format: ++ OP0 OP1 CP0 CP1 CP2 CP3 CP4 MP0 MP1 MP2 MP3 MP4 MP5 CGM0 CGM1 ++ ON0 ON1 CN0 CN1 CN2 CN3 CN4 MN0 MN1 MN2 MN3 MN4 MN5 XXXX GC ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long mask[] = { ++ 0b1111, 0b1111, 0b11111, 0b1111, 0b1111, 0b1111, 0b11111, ++ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b11, 0b11, ++ 0b1111, 0b1111, 0b11111, 0b1111, 0b1111, 0b1111, 0b11111, ++ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b0, 0b0 }; ++ int i, j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < par->gamma.num_curves; i++) ++ for (j = 0; j < par->gamma.num_values; j++) ++ CURVE(i, j) &= mask[i * par->gamma.num_values + j]; ++ ++ write_reg(par, 0x26, 1 << CURVE(1, 14)); /* Gamma Set (26h) */ ++ ++ if (CURVE(1, 14)) ++ return 0; /* only GC0 can be customized */ ++ ++ write_reg(par, 0xC2, ++ (CURVE(0, 8) << 4) | CURVE(0, 7), ++ (CURVE(0, 10) << 4) | CURVE(0, 9), ++ (CURVE(0, 12) << 4) | CURVE(0, 11), ++ CURVE(0, 2), ++ (CURVE(0, 4) << 4) | CURVE(0, 3), ++ CURVE(0, 5), ++ CURVE(0, 6), ++ (CURVE(0, 1) << 4) | CURVE(0, 0), ++ (CURVE(0, 14) << 2) | CURVE(0, 13)); ++ ++ write_reg(par, 0xC3, ++ (CURVE(1, 8) << 4) | CURVE(1, 7), ++ (CURVE(1, 10) << 4) | CURVE(1, 9), ++ (CURVE(1, 12) << 4) | CURVE(1, 11), ++ CURVE(1, 2), ++ (CURVE(1, 4) << 4) | CURVE(1, 3), ++ CURVE(1, 5), ++ CURVE(1, 6), ++ (CURVE(1, 1) << 4) | CURVE(1, 0)); ++ ++ mdelay(10); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .txbuflen = TXBUFLEN, ++ .gamma_num = 2, ++ .gamma_len = 15, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8340bn", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:hx8340bn"); ++MODULE_ALIAS("platform:hx8340bn"); ++ ++MODULE_DESCRIPTION("FB driver for the HX8340BN LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From 44e8767644da0ee3d811b0d69efd72719676ef1a Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:13 +0100 +Subject: [PATCH 129/178] staging: fbtft: add fb_hx8347d driver + +This commit adds the fb_hx8347d driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_hx8347d.c | 181 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 188 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_hx8347d.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index e6c23d5e..9bb6e7b 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -25,3 +25,9 @@ config FB_TFT_HX8340BN + depends on FB_TFT + help + Generic Framebuffer support for HX8340BN ++ ++config FB_TFT_HX8347D ++ tristate "FB driver for the HX8347D LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for HX8347D +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 7d89af7..de68bf8 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -6,3 +6,4 @@ fbtft-y += fbtft-core.o fbtft-sysfs.o fbtft-bus.o fbtft + obj-$(CONFIG_FB_TFT_AGM1264K_FL) += fb_agm1264k-fl.o + obj-$(CONFIG_FB_TFT_BD663474) += fb_bd663474.o + obj-$(CONFIG_FB_TFT_HX8340BN) += fb_hx8340bn.o ++obj-$(CONFIG_FB_TFT_HX8347D) += fb_hx8347d.o +diff --git a/drivers/staging/fbtft/fb_hx8347d.c b/drivers/staging/fbtft/fb_hx8347d.c +new file mode 100644 +index 0000000..8139a8f +--- /dev/null ++++ b/drivers/staging/fbtft/fb_hx8347d.c +@@ -0,0 +1,181 @@ ++/* ++ * FB driver for the HX8347D LCD Controller ++ * ++ * Copyright (C) 2013 Christian Vogelgsang ++ * ++ * Based on driver code found here: https://github.com/watterott/r61505u-Adapter ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_hx8347d" ++#define WIDTH 320 ++#define HEIGHT 240 ++#define DEFAULT_GAMMA "0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" \ ++ "0 0 0 0 0 0 0 0 0 0 0 0 0 0" ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ /* driving ability */ ++ write_reg(par, 0xEA, 0x00); ++ write_reg(par, 0xEB, 0x20); ++ write_reg(par, 0xEC, 0x0C); ++ write_reg(par, 0xED, 0xC4); ++ write_reg(par, 0xE8, 0x40); ++ write_reg(par, 0xE9, 0x38); ++ write_reg(par, 0xF1, 0x01); ++ write_reg(par, 0xF2, 0x10); ++ write_reg(par, 0x27, 0xA3); ++ ++ /* power voltage */ ++ write_reg(par, 0x1B, 0x1B); ++ write_reg(par, 0x1A, 0x01); ++ write_reg(par, 0x24, 0x2F); ++ write_reg(par, 0x25, 0x57); ++ ++ /* VCOM offset */ ++ write_reg(par, 0x23, 0x8D); /* for flicker adjust */ ++ ++ /* power on */ ++ write_reg(par, 0x18, 0x36); ++ write_reg(par, 0x19, 0x01); /* start osc */ ++ write_reg(par, 0x01, 0x00); /* wakeup */ ++ write_reg(par, 0x1F, 0x88); ++ mdelay(5); ++ write_reg(par, 0x1F, 0x80); ++ mdelay(5); ++ write_reg(par, 0x1F, 0x90); ++ mdelay(5); ++ write_reg(par, 0x1F, 0xD0); ++ mdelay(5); ++ ++ /* color selection */ ++ write_reg(par, 0x17, 0x05); /* 65k */ ++ ++ /*panel characteristic */ ++ write_reg(par, 0x36, 0x00); ++ ++ /*display on */ ++ write_reg(par, 0x28, 0x38); ++ mdelay(40); ++ write_reg(par, 0x28, 0x3C); ++ ++ /* orientation */ ++ write_reg(par, 0x16, 0x60 | (par->bgr << 3)); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ write_reg(par, 0x02, (xs >> 8) & 0xFF); ++ write_reg(par, 0x03, xs & 0xFF); ++ write_reg(par, 0x04, (xe >> 8) & 0xFF); ++ write_reg(par, 0x05, xe & 0xFF); ++ write_reg(par, 0x06, (ys >> 8) & 0xFF); ++ write_reg(par, 0x07, ys & 0xFF); ++ write_reg(par, 0x08, (ye >> 8) & 0xFF); ++ write_reg(par, 0x09, ye & 0xFF); ++ write_reg(par, 0x22); ++} ++ ++/* ++ Gamma string format: ++ VRP0 VRP1 VRP2 VRP3 VRP4 VRP5 PRP0 PRP1 PKP0 PKP1 PKP2 PKP3 PKP4 CGM ++ VRN0 VRN1 VRN2 VRN3 VRN4 VRN5 PRN0 PRN1 PKN0 PKN1 PKN2 PKN3 PKN4 CGM ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long mask[] = { ++ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, ++ 0b1111111, 0b1111111, ++ 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, ++ 0b1111}; ++ int i, j; ++ int acc = 0; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < par->gamma.num_curves; i++) ++ for (j = 0; j < par->gamma.num_values; j++) { ++ acc += CURVE(i, j); ++ CURVE(i, j) &= mask[j]; ++ } ++ ++ if (acc == 0) /* skip if all values are zero */ ++ return 0; ++ ++ for (i = 0; i < par->gamma.num_curves; i++) { ++ write_reg(par, 0x40 + (i * 0x10), CURVE(i, 0)); ++ write_reg(par, 0x41 + (i * 0x10), CURVE(i, 1)); ++ write_reg(par, 0x42 + (i * 0x10), CURVE(i, 2)); ++ write_reg(par, 0x43 + (i * 0x10), CURVE(i, 3)); ++ write_reg(par, 0x44 + (i * 0x10), CURVE(i, 4)); ++ write_reg(par, 0x45 + (i * 0x10), CURVE(i, 5)); ++ write_reg(par, 0x46 + (i * 0x10), CURVE(i, 6)); ++ write_reg(par, 0x47 + (i * 0x10), CURVE(i, 7)); ++ write_reg(par, 0x48 + (i * 0x10), CURVE(i, 8)); ++ write_reg(par, 0x49 + (i * 0x10), CURVE(i, 9)); ++ write_reg(par, 0x4A + (i * 0x10), CURVE(i, 10)); ++ write_reg(par, 0x4B + (i * 0x10), CURVE(i, 11)); ++ write_reg(par, 0x4C + (i * 0x10), CURVE(i, 12)); ++ } ++ write_reg(par, 0x5D, (CURVE(1, 0) << 4) | CURVE(0, 0)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .gamma_num = 2, ++ .gamma_len = 14, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8347d", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:hx8347d"); ++MODULE_ALIAS("platform:hx8347d"); ++ ++MODULE_DESCRIPTION("FB driver for the HX8347D LCD Controller"); ++MODULE_AUTHOR("Christian Vogelgsang"); ++MODULE_LICENSE("GPL"); + +From 4bc239a8f7d5ba4add22dbc623d1d128474887b5 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:14 +0100 +Subject: [PATCH 130/178] staging: fbtft: add fb_hx8353d driver + +This commit adds the fb_hx8353d driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_hx8353d.c | 166 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 173 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_hx8353d.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 9bb6e7b..015429b 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -31,3 +31,9 @@ config FB_TFT_HX8347D + depends on FB_TFT + help + Generic Framebuffer support for HX8347D ++ ++config FB_TFT_HX8353D ++ tristate "FB driver for the HX8353D LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for HX8353D +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index de68bf8..766e285 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -7,3 +7,4 @@ obj-$(CONFIG_FB_TFT_AGM1264K_FL) += fb_agm1264k-fl.o + obj-$(CONFIG_FB_TFT_BD663474) += fb_bd663474.o + obj-$(CONFIG_FB_TFT_HX8340BN) += fb_hx8340bn.o + obj-$(CONFIG_FB_TFT_HX8347D) += fb_hx8347d.o ++obj-$(CONFIG_FB_TFT_HX8353D) += fb_hx8353d.o +diff --git a/drivers/staging/fbtft/fb_hx8353d.c b/drivers/staging/fbtft/fb_hx8353d.c +new file mode 100644 +index 0000000..c9512dc +--- /dev/null ++++ b/drivers/staging/fbtft/fb_hx8353d.c +@@ -0,0 +1,166 @@ ++/* ++ * FB driver for the HX8353D LCD Controller ++ * ++ * Copyright (c) 2014 Petr Olivka ++ * Copyright (c) 2013 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_hx8353d" ++#define DEFAULT_GAMMA "50 77 40 08 BF 00 03 0F 00 01 73 00 72 03 B0 0F 08 00 0F" ++ ++static int init_display(struct fbtft_par *par) ++{ ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ mdelay(150); ++ ++ /* SETEXTC */ ++ write_reg(par, 0xB9, 0xFF, 0x83, 0x53); ++ ++ /* RADJ */ ++ write_reg(par, 0xB0, 0x3C, 0x01); ++ ++ /* VCOM */ ++ write_reg(par, 0xB6, 0x94, 0x6C, 0x50); ++ ++ /* PWR */ ++ write_reg(par, 0xB1, 0x00, 0x01, 0x1B, 0x03, 0x01, 0x08, 0x77, 0x89); ++ ++ /* COLMOD */ ++ write_reg(par, 0x3A, 0x05); ++ ++ /* MEM ACCESS */ ++ write_reg(par, 0x36, 0xC0); ++ ++ /* SLPOUT - Sleep out & booster on */ ++ write_reg(par, 0x11); ++ mdelay(150); ++ ++ /* DISPON - Display On */ ++ write_reg(par, 0x29); ++ ++ /* RGBSET */ ++ write_reg(par, 0x2D, ++ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, ++ 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, ++ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ++ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, ++ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, ++ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, ++ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, ++ 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62); ++ ++ return 0; ++}; ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* column address */ ++ write_reg(par, 0x2a, xs >> 8, xs & 0xff, xe >> 8, xe & 0xff); ++ ++ /* row adress */ ++ write_reg(par, 0x2b, ys >> 8, ys & 0xff, ye >> 8, ye & 0xff); ++ ++ /* memory write */ ++ write_reg(par, 0x2c); ++} ++ ++#define my (1 << 7) ++#define mx (1 << 6) ++#define mv (1 << 5) ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* madctl - memory data access control ++ rgb/bgr: ++ 1. mode selection pin srgb ++ rgb h/w pin for color filter setting: 0=rgb, 1=bgr ++ 2. madctl rgb bit ++ rgb-bgr order color filter panel: 0=rgb, 1=bgr */ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x36, mx | my | (par->bgr << 3)); ++ break; ++ case 270: ++ write_reg(par, 0x36, my | mv | (par->bgr << 3)); ++ break; ++ case 180: ++ write_reg(par, 0x36, (par->bgr << 3)); ++ break; ++ case 90: ++ write_reg(par, 0x36, mx | mv | (par->bgr << 3)); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ gamma string format: ++*/ ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ write_reg(par, 0xE0, ++ curves[0], curves[1], curves[2], curves[3], ++ curves[4], curves[5], curves[6], curves[7], ++ curves[8], curves[9], curves[10], curves[11], ++ curves[12], curves[13], curves[14], curves[15], ++ curves[16], curves[17], curves[18]); ++ ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = 128, ++ .height = 160, ++ .gamma_num = 1, ++ .gamma_len = 19, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8353d", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:hx8353d"); ++MODULE_ALIAS("platform:hx8353d"); ++ ++MODULE_DESCRIPTION("FB driver for the HX8353D LCD Controller"); ++MODULE_AUTHOR("Petr Olivka"); ++MODULE_LICENSE("GPL"); + +From 68326151d0a48dce8c8235ca9b1a3deebd11c905 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:15 +0100 +Subject: [PATCH 131/178] staging: fbtft: add fb_ili9320 driver + +This commit adds the fb_ili9320 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 + + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_ili9320.c | 234 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 241 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_ili9320.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 015429b..eb57f19 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -37,3 +37,9 @@ config FB_TFT_HX8353D + depends on FB_TFT + help + Generic Framebuffer support for HX8353D ++ ++config FB_TFT_ILI9320 ++ tristate "FB driver for the ILI9320 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ILI9320 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 766e285..e101cb6 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -8,3 +8,4 @@ obj-$(CONFIG_FB_TFT_BD663474) += fb_bd663474.o + obj-$(CONFIG_FB_TFT_HX8340BN) += fb_hx8340bn.o + obj-$(CONFIG_FB_TFT_HX8347D) += fb_hx8347d.o + obj-$(CONFIG_FB_TFT_HX8353D) += fb_hx8353d.o ++obj-$(CONFIG_FB_TFT_ILI9320) += fb_ili9320.o +diff --git a/drivers/staging/fbtft/fb_ili9320.c b/drivers/staging/fbtft/fb_ili9320.c +new file mode 100644 +index 0000000..b26d893 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_ili9320.c +@@ -0,0 +1,234 @@ ++/* ++ * FB driver for the ILI9320 LCD Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ili9320" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define DEFAULT_GAMMA "07 07 6 0 0 0 5 5 4 0\n" \ ++ "07 08 4 7 5 1 2 0 7 7" ++ ++ ++static unsigned read_devicecode(struct fbtft_par *par) ++{ ++ int ret; ++ u8 rxbuf[8] = {0, }; ++ ++ write_reg(par, 0x0000); ++ ret = par->fbtftops.read(par, rxbuf, 4); ++ return (rxbuf[2] << 8) | rxbuf[3]; ++} ++ ++static int init_display(struct fbtft_par *par) ++{ ++ unsigned devcode; ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ devcode = read_devicecode(par); ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "Device code: 0x%04X\n", ++ devcode); ++ if ((devcode != 0x0000) && (devcode != 0x9320)) ++ dev_warn(par->info->device, ++ "Unrecognized Device code: 0x%04X (expected 0x9320)\n", ++ devcode); ++ ++ /* Initialization sequence from ILI9320 Application Notes */ ++ ++ /* *********** Start Initial Sequence ********* */ ++ write_reg(par, 0x00E5, 0x8000); /* Set the Vcore voltage and this setting is must. */ ++ write_reg(par, 0x0000, 0x0001); /* Start internal OSC. */ ++ write_reg(par, 0x0001, 0x0100); /* set SS and SM bit */ ++ write_reg(par, 0x0002, 0x0700); /* set 1 line inversion */ ++ write_reg(par, 0x0004, 0x0000); /* Resize register */ ++ write_reg(par, 0x0008, 0x0202); /* set the back and front porch */ ++ write_reg(par, 0x0009, 0x0000); /* set non-display area refresh cycle */ ++ write_reg(par, 0x000A, 0x0000); /* FMARK function */ ++ write_reg(par, 0x000C, 0x0000); /* RGB interface setting */ ++ write_reg(par, 0x000D, 0x0000); /* Frame marker Position */ ++ write_reg(par, 0x000F, 0x0000); /* RGB interface polarity */ ++ ++ /* ***********Power On sequence *************** */ ++ write_reg(par, 0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ ++ write_reg(par, 0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */ ++ write_reg(par, 0x0012, 0x0000); /* VREG1OUT voltage */ ++ write_reg(par, 0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ ++ mdelay(200); /* Dis-charge capacitor power voltage */ ++ write_reg(par, 0x0010, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ ++ write_reg(par, 0x0011, 0x0031); /* R11h=0x0031 at VCI=3.3V DC1[2:0], DC0[2:0], VC[2:0] */ ++ mdelay(50); ++ write_reg(par, 0x0012, 0x0138); /* R12h=0x0138 at VCI=3.3V VREG1OUT voltage */ ++ mdelay(50); ++ write_reg(par, 0x0013, 0x1800); /* R13h=0x1800 at VCI=3.3V VDV[4:0] for VCOM amplitude */ ++ write_reg(par, 0x0029, 0x0008); /* R29h=0x0008 at VCI=3.3V VCM[4:0] for VCOMH */ ++ mdelay(50); ++ write_reg(par, 0x0020, 0x0000); /* GRAM horizontal Address */ ++ write_reg(par, 0x0021, 0x0000); /* GRAM Vertical Address */ ++ ++ /* ------------------ Set GRAM area --------------- */ ++ write_reg(par, 0x0050, 0x0000); /* Horizontal GRAM Start Address */ ++ write_reg(par, 0x0051, 0x00EF); /* Horizontal GRAM End Address */ ++ write_reg(par, 0x0052, 0x0000); /* Vertical GRAM Start Address */ ++ write_reg(par, 0x0053, 0x013F); /* Vertical GRAM Start Address */ ++ write_reg(par, 0x0060, 0x2700); /* Gate Scan Line */ ++ write_reg(par, 0x0061, 0x0001); /* NDL,VLE, REV */ ++ write_reg(par, 0x006A, 0x0000); /* set scrolling line */ ++ ++ /* -------------- Partial Display Control --------- */ ++ write_reg(par, 0x0080, 0x0000); ++ write_reg(par, 0x0081, 0x0000); ++ write_reg(par, 0x0082, 0x0000); ++ write_reg(par, 0x0083, 0x0000); ++ write_reg(par, 0x0084, 0x0000); ++ write_reg(par, 0x0085, 0x0000); ++ ++ /* -------------- Panel Control ------------------- */ ++ write_reg(par, 0x0090, 0x0010); ++ write_reg(par, 0x0092, 0x0000); ++ write_reg(par, 0x0093, 0x0003); ++ write_reg(par, 0x0095, 0x0110); ++ write_reg(par, 0x0097, 0x0000); ++ write_reg(par, 0x0098, 0x0000); ++ write_reg(par, 0x0007, 0x0173); /* 262K color and display ON */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ switch (par->info->var.rotate) { ++ /* R20h = Horizontal GRAM Start Address */ ++ /* R21h = Vertical GRAM Start Address */ ++ case 0: ++ write_reg(par, 0x0020, xs); ++ write_reg(par, 0x0021, ys); ++ break; ++ case 180: ++ write_reg(par, 0x0020, WIDTH - 1 - xs); ++ write_reg(par, 0x0021, HEIGHT - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x0020, WIDTH - 1 - ys); ++ write_reg(par, 0x0021, xs); ++ break; ++ case 90: ++ write_reg(par, 0x0020, ys); ++ write_reg(par, 0x0021, HEIGHT - 1 - xs); ++ break; ++ } ++ write_reg(par, 0x0022); /* Write Data to GRAM */ ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x3, (par->bgr << 12) | 0x30); ++ break; ++ case 270: ++ write_reg(par, 0x3, (par->bgr << 12) | 0x28); ++ break; ++ case 180: ++ write_reg(par, 0x3, (par->bgr << 12) | 0x00); ++ break; ++ case 90: ++ write_reg(par, 0x3, (par->bgr << 12) | 0x18); ++ break; ++ } ++ return 0; ++} ++ ++/* ++ Gamma string format: ++ VRP0 VRP1 RP0 RP1 KP0 KP1 KP2 KP3 KP4 KP5 ++ VRN0 VRN1 RN0 RN1 KN0 KN1 KN2 KN3 KN4 KN5 ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long mask[] = { ++ 0b11111, 0b11111, 0b111, 0b111, 0b111, ++ 0b111, 0b111, 0b111, 0b111, 0b111, ++ 0b11111, 0b11111, 0b111, 0b111, 0b111, ++ 0b111, 0b111, 0b111, 0b111, 0b111 }; ++ int i, j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < 10; j++) ++ CURVE(i, j) &= mask[i*par->gamma.num_values + j]; ++ ++ write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4)); ++ write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6)); ++ write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8)); ++ write_reg(par, 0x0035, CURVE(0, 3) << 8 | CURVE(0, 2)); ++ write_reg(par, 0x0036, CURVE(0, 1) << 8 | CURVE(0, 0)); ++ ++ write_reg(par, 0x0037, CURVE(1, 5) << 8 | CURVE(1, 4)); ++ write_reg(par, 0x0038, CURVE(1, 7) << 8 | CURVE(1, 6)); ++ write_reg(par, 0x0039, CURVE(1, 9) << 8 | CURVE(1, 8)); ++ write_reg(par, 0x003C, CURVE(1, 3) << 8 | CURVE(1, 2)); ++ write_reg(par, 0x003D, CURVE(1, 1) << 8 | CURVE(1, 0)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 16, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .gamma_num = 2, ++ .gamma_len = 10, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9320", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ili9320"); ++MODULE_ALIAS("platform:ili9320"); ++ ++MODULE_DESCRIPTION("FB driver for the ILI9320 LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From eb23b240f57d1fea8c0555b121bf81b02c89ac99 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:16 +0100 +Subject: [PATCH 132/178] staging: fbtft: add fb_ili9325 driver + +This commit adds the fb_ili9325 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 + + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_ili9325.c | 291 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 298 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_ili9325.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index eb57f19..24b9d91 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -43,3 +43,9 @@ config FB_TFT_ILI9320 + depends on FB_TFT + help + Generic Framebuffer support for ILI9320 ++ ++config FB_TFT_ILI9325 ++ tristate "FB driver for the ILI9325 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ILI9325 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index e101cb6..09d4697 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -9,3 +9,4 @@ obj-$(CONFIG_FB_TFT_HX8340BN) += fb_hx8340bn.o + obj-$(CONFIG_FB_TFT_HX8347D) += fb_hx8347d.o + obj-$(CONFIG_FB_TFT_HX8353D) += fb_hx8353d.o + obj-$(CONFIG_FB_TFT_ILI9320) += fb_ili9320.o ++obj-$(CONFIG_FB_TFT_ILI9325) += fb_ili9325.o +diff --git a/drivers/staging/fbtft/fb_ili9325.c b/drivers/staging/fbtft/fb_ili9325.c +new file mode 100644 +index 0000000..5f88145 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_ili9325.c +@@ -0,0 +1,291 @@ ++/* ++ * FB driver for the ILI9325 LCD Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * Based on ili9325.c by Jeroen Domburg ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ili9325" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define BPP 16 ++#define FPS 20 ++#define DEFAULT_GAMMA "0F 00 7 2 0 0 6 5 4 1\n" \ ++ "04 16 2 7 6 3 2 1 7 7" ++ ++ ++static unsigned bt = 6; /* VGL=Vci*4 , VGH=Vci*4 */ ++module_param(bt, uint, 0); ++MODULE_PARM_DESC(bt, "Sets the factor used in the step-up circuits"); ++ ++static unsigned vc = 0b011; /* Vci1=Vci*0.80 */ ++module_param(vc, uint, 0); ++MODULE_PARM_DESC(vc, ++"Sets the ratio factor of Vci to generate the reference voltages Vci1"); ++ ++static unsigned vrh = 0b1101; /* VREG1OUT=Vci*1.85 */ ++module_param(vrh, uint, 0); ++MODULE_PARM_DESC(vrh, ++"Set the amplifying rate (1.6 ~ 1.9) of Vci applied to output the VREG1OUT"); ++ ++static unsigned vdv = 0b10010; /* VCOMH amplitude=VREG1OUT*0.98 */ ++module_param(vdv, uint, 0); ++MODULE_PARM_DESC(vdv, ++"Select the factor of VREG1OUT to set the amplitude of Vcom"); ++ ++static unsigned vcm = 0b001010; /* VCOMH=VREG1OUT*0.735 */ ++module_param(vcm, uint, 0); ++MODULE_PARM_DESC(vcm, "Set the internal VcomH voltage"); ++ ++ ++/* ++Verify that this configuration is within the Voltage limits ++ ++Display module configuration: Vcc = IOVcc = Vci = 3.3V ++ ++ Voltages ++---------- ++Vci = 3.3 ++Vci1 = Vci * 0.80 = 2.64 ++DDVDH = Vci1 * 2 = 5.28 ++VCL = -Vci1 = -2.64 ++VREG1OUT = Vci * 1.85 = 4.88 ++VCOMH = VREG1OUT * 0.735 = 3.59 ++VCOM amplitude = VREG1OUT * 0.98 = 4.79 ++VGH = Vci * 4 = 13.2 ++VGL = -Vci * 4 = -13.2 ++ ++ Limits ++-------- ++Power supplies ++1.65 < IOVcc < 3.30 => 1.65 < 3.3 < 3.30 ++2.40 < Vcc < 3.30 => 2.40 < 3.3 < 3.30 ++2.50 < Vci < 3.30 => 2.50 < 3.3 < 3.30 ++ ++Source/VCOM power supply voltage ++ 4.50 < DDVDH < 6.0 => 4.50 < 5.28 < 6.0 ++-3.0 < VCL < -2.0 => -3.0 < -2.64 < -2.0 ++VCI - VCL < 6.0 => 5.94 < 6.0 ++ ++Gate driver output voltage ++ 10 < VGH < 20 => 10 < 13.2 < 20 ++-15 < VGL < -5 => -15 < -13.2 < -5 ++VGH - VGL < 32 => 26.4 < 32 ++ ++VCOM driver output voltage ++VCOMH - VCOML < 6.0 => 4.79 < 6.0 ++*/ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ ++ bt &= 0b111; ++ vc &= 0b111; ++ vrh &= 0b1111; ++ vdv &= 0b11111; ++ vcm &= 0b111111; ++ ++ /* Initialization sequence from ILI9325 Application Notes */ ++ ++ /* ----------- Start Initial Sequence ----------- */ ++ write_reg(par, 0x00E3, 0x3008); /* Set internal timing */ ++ write_reg(par, 0x00E7, 0x0012); /* Set internal timing */ ++ write_reg(par, 0x00EF, 0x1231); /* Set internal timing */ ++ write_reg(par, 0x0001, 0x0100); /* set SS and SM bit */ ++ write_reg(par, 0x0002, 0x0700); /* set 1 line inversion */ ++ write_reg(par, 0x0004, 0x0000); /* Resize register */ ++ write_reg(par, 0x0008, 0x0207); /* set the back porch and front porch */ ++ write_reg(par, 0x0009, 0x0000); /* set non-display area refresh cycle */ ++ write_reg(par, 0x000A, 0x0000); /* FMARK function */ ++ write_reg(par, 0x000C, 0x0000); /* RGB interface setting */ ++ write_reg(par, 0x000D, 0x0000); /* Frame marker Position */ ++ write_reg(par, 0x000F, 0x0000); /* RGB interface polarity */ ++ ++ /* ----------- Power On sequence ----------- */ ++ write_reg(par, 0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ ++ write_reg(par, 0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */ ++ write_reg(par, 0x0012, 0x0000); /* VREG1OUT voltage */ ++ write_reg(par, 0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ ++ mdelay(200); /* Dis-charge capacitor power voltage */ ++ write_reg(par, 0x0010, /* SAP, BT[3:0], AP, DSTB, SLP, STB */ ++ (1 << 12) | (bt << 8) | (1 << 7) | (0b001 << 4)); ++ write_reg(par, 0x0011, 0x220 | vc); /* DC1[2:0], DC0[2:0], VC[2:0] */ ++ mdelay(50); /* Delay 50ms */ ++ write_reg(par, 0x0012, vrh); /* Internal reference voltage= Vci; */ ++ mdelay(50); /* Delay 50ms */ ++ write_reg(par, 0x0013, vdv << 8); /* Set VDV[4:0] for VCOM amplitude */ ++ write_reg(par, 0x0029, vcm); /* Set VCM[5:0] for VCOMH */ ++ write_reg(par, 0x002B, 0x000C); /* Set Frame Rate */ ++ mdelay(50); /* Delay 50ms */ ++ write_reg(par, 0x0020, 0x0000); /* GRAM horizontal Address */ ++ write_reg(par, 0x0021, 0x0000); /* GRAM Vertical Address */ ++ ++ /*------------------ Set GRAM area --------------- */ ++ write_reg(par, 0x0050, 0x0000); /* Horizontal GRAM Start Address */ ++ write_reg(par, 0x0051, 0x00EF); /* Horizontal GRAM End Address */ ++ write_reg(par, 0x0052, 0x0000); /* Vertical GRAM Start Address */ ++ write_reg(par, 0x0053, 0x013F); /* Vertical GRAM Start Address */ ++ write_reg(par, 0x0060, 0xA700); /* Gate Scan Line */ ++ write_reg(par, 0x0061, 0x0001); /* NDL,VLE, REV */ ++ write_reg(par, 0x006A, 0x0000); /* set scrolling line */ ++ ++ /*-------------- Partial Display Control --------- */ ++ write_reg(par, 0x0080, 0x0000); ++ write_reg(par, 0x0081, 0x0000); ++ write_reg(par, 0x0082, 0x0000); ++ write_reg(par, 0x0083, 0x0000); ++ write_reg(par, 0x0084, 0x0000); ++ write_reg(par, 0x0085, 0x0000); ++ ++ /*-------------- Panel Control ------------------- */ ++ write_reg(par, 0x0090, 0x0010); ++ write_reg(par, 0x0092, 0x0600); ++ write_reg(par, 0x0007, 0x0133); /* 262K color and display ON */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ switch (par->info->var.rotate) { ++ /* R20h = Horizontal GRAM Start Address */ ++ /* R21h = Vertical GRAM Start Address */ ++ case 0: ++ write_reg(par, 0x0020, xs); ++ write_reg(par, 0x0021, ys); ++ break; ++ case 180: ++ write_reg(par, 0x0020, WIDTH - 1 - xs); ++ write_reg(par, 0x0021, HEIGHT - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x0020, WIDTH - 1 - ys); ++ write_reg(par, 0x0021, xs); ++ break; ++ case 90: ++ write_reg(par, 0x0020, ys); ++ write_reg(par, 0x0021, HEIGHT - 1 - xs); ++ break; ++ } ++ write_reg(par, 0x0022); /* Write Data to GRAM */ ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ /* AM: GRAM update direction */ ++ case 0: ++ write_reg(par, 0x03, 0x0030 | (par->bgr << 12)); ++ break; ++ case 180: ++ write_reg(par, 0x03, 0x0000 | (par->bgr << 12)); ++ break; ++ case 270: ++ write_reg(par, 0x03, 0x0028 | (par->bgr << 12)); ++ break; ++ case 90: ++ write_reg(par, 0x03, 0x0018 | (par->bgr << 12)); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Gamma string format: ++ VRP0 VRP1 RP0 RP1 KP0 KP1 KP2 KP3 KP4 KP5 ++ VRN0 VRN1 RN0 RN1 KN0 KN1 KN2 KN3 KN4 KN5 ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long mask[] = { ++ 0b11111, 0b11111, 0b111, 0b111, 0b111, ++ 0b111, 0b111, 0b111, 0b111, 0b111, ++ 0b11111, 0b11111, 0b111, 0b111, 0b111, ++ 0b111, 0b111, 0b111, 0b111, 0b111 }; ++ int i, j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < 10; j++) ++ CURVE(i, j) &= mask[i*par->gamma.num_values + j]; ++ ++ write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4)); ++ write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6)); ++ write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8)); ++ write_reg(par, 0x0035, CURVE(0, 3) << 8 | CURVE(0, 2)); ++ write_reg(par, 0x0036, CURVE(0, 1) << 8 | CURVE(0, 0)); ++ ++ write_reg(par, 0x0037, CURVE(1, 5) << 8 | CURVE(1, 4)); ++ write_reg(par, 0x0038, CURVE(1, 7) << 8 | CURVE(1, 6)); ++ write_reg(par, 0x0039, CURVE(1, 9) << 8 | CURVE(1, 8)); ++ write_reg(par, 0x003C, CURVE(1, 3) << 8 | CURVE(1, 2)); ++ write_reg(par, 0x003D, CURVE(1, 1) << 8 | CURVE(1, 0)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 16, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .bpp = BPP, ++ .fps = FPS, ++ .gamma_num = 2, ++ .gamma_len = 10, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9325", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ili9325"); ++MODULE_ALIAS("platform:ili9325"); ++ ++MODULE_DESCRIPTION("FB driver for the ILI9325 LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From 9a7782c69bcdc280dc57b203895864dfd58a5d14 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:17 +0100 +Subject: [PATCH 133/178] staging: fbtft: add fb_ili9340 driver + +This commit adds the fb_ili9340 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_ili9340.c | 163 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 170 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_ili9340.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 24b9d91..6295acf 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -49,3 +49,9 @@ config FB_TFT_ILI9325 + depends on FB_TFT + help + Generic Framebuffer support for ILI9325 ++ ++config FB_TFT_ILI9340 ++ tristate "FB driver for the ILI9340 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ILI9340 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 09d4697..aa65da8 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -10,3 +10,4 @@ obj-$(CONFIG_FB_TFT_HX8347D) += fb_hx8347d.o + obj-$(CONFIG_FB_TFT_HX8353D) += fb_hx8353d.o + obj-$(CONFIG_FB_TFT_ILI9320) += fb_ili9320.o + obj-$(CONFIG_FB_TFT_ILI9325) += fb_ili9325.o ++obj-$(CONFIG_FB_TFT_ILI9340) += fb_ili9340.o +diff --git a/drivers/staging/fbtft/fb_ili9340.c b/drivers/staging/fbtft/fb_ili9340.c +new file mode 100644 +index 0000000..985687d +--- /dev/null ++++ b/drivers/staging/fbtft/fb_ili9340.c +@@ -0,0 +1,163 @@ ++/* ++ * FB driver for the ILI9340 LCD Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ili9340" ++#define WIDTH 240 ++#define HEIGHT 320 ++ ++ ++/* Init sequence taken from: Arduino Library for the Adafruit 2.2" display */ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ write_reg(par, 0xEF, 0x03, 0x80, 0x02); ++ write_reg(par, 0xCF, 0x00 , 0XC1 , 0X30); ++ write_reg(par, 0xED, 0x64 , 0x03 , 0X12 , 0X81); ++ write_reg(par, 0xE8, 0x85 , 0x00 , 0x78); ++ write_reg(par, 0xCB, 0x39 , 0x2C , 0x00 , 0x34 , 0x02); ++ write_reg(par, 0xF7, 0x20); ++ write_reg(par, 0xEA, 0x00 , 0x00); ++ ++ /* Power Control 1 */ ++ write_reg(par, 0xC0, 0x23); ++ ++ /* Power Control 2 */ ++ write_reg(par, 0xC1, 0x10); ++ ++ /* VCOM Control 1 */ ++ write_reg(par, 0xC5, 0x3e, 0x28); ++ ++ /* VCOM Control 2 */ ++ write_reg(par, 0xC7, 0x86); ++ ++ /* COLMOD: Pixel Format Set */ ++ /* 16 bits/pixel */ ++ write_reg(par, 0x3A, 0x55); ++ ++ /* Frame Rate Control */ ++ /* Division ratio = fosc, Frame Rate = 79Hz */ ++ write_reg(par, 0xB1, 0x00, 0x18); ++ ++ /* Display Function Control */ ++ write_reg(par, 0xB6, 0x08, 0x82, 0x27); ++ ++ /* Gamma Function Disable */ ++ write_reg(par, 0xF2, 0x00); ++ ++ /* Gamma curve selected */ ++ write_reg(par, 0x26, 0x01); ++ ++ /* Positive Gamma Correction */ ++ write_reg(par, 0xE0, ++ 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, ++ 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00); ++ ++ /* Negative Gamma Correction */ ++ write_reg(par, 0xE1, ++ 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, ++ 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F); ++ ++ /* Sleep OUT */ ++ write_reg(par, 0x11); ++ ++ mdelay(120); ++ ++ /* Display ON */ ++ write_reg(par, 0x29); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address */ ++ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); ++ ++ /* Row adress */ ++ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++#define ILI9340_MADCTL_MV 0x20 ++#define ILI9340_MADCTL_MX 0x40 ++#define ILI9340_MADCTL_MY 0x80 ++static int set_var(struct fbtft_par *par) ++{ ++ u8 val; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ case 270: ++ val = ILI9340_MADCTL_MV; ++ break; ++ case 180: ++ val = ILI9340_MADCTL_MY; ++ break; ++ case 90: ++ val = ILI9340_MADCTL_MV | ILI9340_MADCTL_MY | ILI9340_MADCTL_MX; ++ break; ++ default: ++ val = ILI9340_MADCTL_MX; ++ break; ++ } ++ /* Memory Access Control */ ++ write_reg(par, 0x36, val | (par->bgr << 3)); ++ ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9340", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ili9340"); ++MODULE_ALIAS("platform:ili9340"); ++ ++MODULE_DESCRIPTION("FB driver for the ILI9340 LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From 70a6aa9948626a034b02baf1b9fbac5ba6b0ea69 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:18 +0100 +Subject: [PATCH 134/178] staging: fbtft: add fb_ili9341 driver + +This commit adds the fb_ili9341 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_ili9341.c | 179 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 186 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_ili9341.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 6295acf..ee09e9d 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -55,3 +55,9 @@ config FB_TFT_ILI9340 + depends on FB_TFT + help + Generic Framebuffer support for ILI9340 ++ ++config FB_TFT_ILI9341 ++ tristate "FB driver for the ILI9341 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ILI9341 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index aa65da8..a83a685 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -11,3 +11,4 @@ obj-$(CONFIG_FB_TFT_HX8353D) += fb_hx8353d.o + obj-$(CONFIG_FB_TFT_ILI9320) += fb_ili9320.o + obj-$(CONFIG_FB_TFT_ILI9325) += fb_ili9325.o + obj-$(CONFIG_FB_TFT_ILI9340) += fb_ili9340.o ++obj-$(CONFIG_FB_TFT_ILI9341) += fb_ili9341.o +diff --git a/drivers/staging/fbtft/fb_ili9341.c b/drivers/staging/fbtft/fb_ili9341.c +new file mode 100644 +index 0000000..225b2d8 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_ili9341.c +@@ -0,0 +1,179 @@ ++/* ++ * FB driver for the ILI9341 LCD display controller ++ * ++ * This display uses 9-bit SPI: Data/Command bit + 8 data bits ++ * For platforms that doesn't support 9-bit, the driver is capable ++ * of emulating this using 8-bit transfer. ++ * This is done by transfering eight 9-bit words in 9 bytes. ++ * ++ * Copyright (C) 2013 Christian Vogelgsang ++ * Based on adafruit22fb.c by Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ili9341" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define TXBUFLEN (4 * PAGE_SIZE) ++#define DEFAULT_GAMMA "1F 1A 18 0A 0F 06 45 87 32 0A 07 02 07 05 00\n" \ ++ "00 25 27 05 10 09 3A 78 4D 05 18 0D 38 3A 1F" ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ /* startup sequence for MI0283QT-9A */ ++ write_reg(par, 0x01); /* software reset */ ++ mdelay(5); ++ write_reg(par, 0x28); /* display off */ ++ /* --------------------------------------------------------- */ ++ write_reg(par, 0xCF, 0x00, 0x83, 0x30); ++ write_reg(par, 0xED, 0x64, 0x03, 0x12, 0x81); ++ write_reg(par, 0xE8, 0x85, 0x01, 0x79); ++ write_reg(par, 0xCB, 0x39, 0X2C, 0x00, 0x34, 0x02); ++ write_reg(par, 0xF7, 0x20); ++ write_reg(par, 0xEA, 0x00, 0x00); ++ /* ------------power control-------------------------------- */ ++ write_reg(par, 0xC0, 0x26); ++ write_reg(par, 0xC1, 0x11); ++ /* ------------VCOM --------- */ ++ write_reg(par, 0xC5, 0x35, 0x3E); ++ write_reg(par, 0xC7, 0xBE); ++ /* ------------memory access control------------------------ */ ++ write_reg(par, 0x3A, 0x55); /* 16bit pixel */ ++ /* ------------frame rate----------------------------------- */ ++ write_reg(par, 0xB1, 0x00, 0x1B); ++ /* ------------Gamma---------------------------------------- */ ++ /* write_reg(par, 0xF2, 0x08); */ /* Gamma Function Disable */ ++ write_reg(par, 0x26, 0x01); ++ /* ------------display-------------------------------------- */ ++ write_reg(par, 0xB7, 0x07); /* entry mode set */ ++ write_reg(par, 0xB6, 0x0A, 0x82, 0x27, 0x00); ++ write_reg(par, 0x11); /* sleep out */ ++ mdelay(100); ++ write_reg(par, 0x29); /* display on */ ++ mdelay(20); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address set */ ++ write_reg(par, 0x2A, ++ (xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF); ++ ++ /* Row adress set */ ++ write_reg(par, 0x2B, ++ (ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++#define MEM_Y (7) /* MY row address order */ ++#define MEM_X (6) /* MX column address order */ ++#define MEM_V (5) /* MV row / column exchange */ ++#define MEM_L (4) /* ML vertical refresh order */ ++#define MEM_H (2) /* MH horizontal refresh order */ ++#define MEM_BGR (3) /* RGB-BGR Order */ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x36, (1 << MEM_X) | (par->bgr << MEM_BGR)); ++ break; ++ case 270: ++ write_reg(par, 0x36, ++ (1<bgr << MEM_BGR)); ++ break; ++ case 180: ++ write_reg(par, 0x36, (1 << MEM_Y) | (par->bgr << MEM_BGR)); ++ break; ++ case 90: ++ write_reg(par, 0x36, (1 << MEM_Y) | (1 << MEM_X) | ++ (1 << MEM_V) | (par->bgr << MEM_BGR)); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Gamma string format: ++ Positive: Par1 Par2 [...] Par15 ++ Negative: Par1 Par2 [...] Par15 ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ int i; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ for (i = 0; i < par->gamma.num_curves; i++) ++ write_reg(par, 0xE0 + i, ++ CURVE(i, 0), CURVE(i, 1), CURVE(i, 2), ++ CURVE(i, 3), CURVE(i, 4), CURVE(i, 5), ++ CURVE(i, 6), CURVE(i, 7), CURVE(i, 8), ++ CURVE(i, 9), CURVE(i, 10), CURVE(i, 11), ++ CURVE(i, 12), CURVE(i, 13), CURVE(i, 14)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .txbuflen = TXBUFLEN, ++ .gamma_num = 2, ++ .gamma_len = 15, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9341", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ili9341"); ++MODULE_ALIAS("platform:ili9341"); ++ ++MODULE_DESCRIPTION("FB driver for the ILI9341 LCD display controller"); ++MODULE_AUTHOR("Christian Vogelgsang"); ++MODULE_LICENSE("GPL"); + +From 0d728778b879b7d05aab1efbedc620f47fbd0660 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:19 +0100 +Subject: [PATCH 135/178] staging: fbtft: add fb_ili9481 driver + +This commit adds the fb_ili9481 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_ili9481.c | 117 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 124 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_ili9481.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index ee09e9d..86a1bee 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -61,3 +61,9 @@ config FB_TFT_ILI9341 + depends on FB_TFT + help + Generic Framebuffer support for ILI9341 ++ ++config FB_TFT_ILI9481 ++ tristate "FB driver for the ILI9481 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ILI9481 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index a83a685..0740641 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -12,3 +12,4 @@ obj-$(CONFIG_FB_TFT_ILI9320) += fb_ili9320.o + obj-$(CONFIG_FB_TFT_ILI9325) += fb_ili9325.o + obj-$(CONFIG_FB_TFT_ILI9340) += fb_ili9340.o + obj-$(CONFIG_FB_TFT_ILI9341) += fb_ili9341.o ++obj-$(CONFIG_FB_TFT_ILI9481) += fb_ili9481.o +diff --git a/drivers/staging/fbtft/fb_ili9481.c b/drivers/staging/fbtft/fb_ili9481.c +new file mode 100644 +index 0000000..725157a +--- /dev/null ++++ b/drivers/staging/fbtft/fb_ili9481.c +@@ -0,0 +1,117 @@ ++/* ++ * FB driver for the ILI9481 LCD Controller ++ * ++ * Copyright (c) 2014 Petr Olivka ++ * Copyright (c) 2013 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ili9481" ++#define WIDTH 320 ++#define HEIGHT 480 ++ ++static int default_init_sequence[] = { ++ ++ /* SLP_OUT - Sleep out */ ++ -1, 0x11, ++ -2, 50, ++ /* Power setting */ ++ -1, 0xD0, 0x07, 0x42, 0x18, ++ /* VCOM */ ++ -1, 0xD1, 0x00, 0x07, 0x10, ++ /* Power setting for norm. mode */ ++ -1, 0xD2, 0x01, 0x02, ++ /* Panel driving setting */ ++ -1, 0xC0, 0x10, 0x3B, 0x00, 0x02, 0x11, ++ /* Frame rate & inv. */ ++ -1, 0xC5, 0x03, ++ /* Pixel format */ ++ -1, 0x3A, 0x55, ++ /* Gamma */ ++ -1, 0xC8, 0x00, 0x32, 0x36, 0x45, 0x06, 0x16, ++ 0x37, 0x75, 0x77, 0x54, 0x0C, 0x00, ++ /* DISP_ON */ ++ -1, 0x29, ++ -3 ++}; ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* column address */ ++ write_reg(par, 0x2a, xs >> 8, xs & 0xff, xe >> 8, xe & 0xff); ++ ++ /* row adress */ ++ write_reg(par, 0x2b, ys >> 8, ys & 0xff, ye >> 8, ye & 0xff); ++ ++ /* memory write */ ++ write_reg(par, 0x2c); ++} ++ ++#define HFLIP 0x01 ++#define VFLIP 0x02 ++#define ROWxCOL 0x20 ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ case 270: ++ write_reg(par, 0x36, ROWxCOL | HFLIP | VFLIP | (par->bgr << 3)); ++ break; ++ case 180: ++ write_reg(par, 0x36, VFLIP | (par->bgr << 3)); ++ break; ++ case 90: ++ write_reg(par, 0x36, ROWxCOL | (par->bgr << 3)); ++ break; ++ default: ++ write_reg(par, 0x36, HFLIP | (par->bgr << 3)); ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .init_sequence = default_init_sequence, ++ .fbtftops = { ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9481", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ili9481"); ++MODULE_ALIAS("platform:ili9481"); ++ ++MODULE_DESCRIPTION("FB driver for the ILI9481 LCD Controller"); ++MODULE_AUTHOR("Petr Olivka"); ++MODULE_LICENSE("GPL"); + +From dcc5dddbc8532350ef90cdbd615708132ae0971f Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:20 +0100 +Subject: [PATCH 136/178] staging: fbtft: add fb_ili9486 driver + +This commit adds the fb_ili9486 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_ili9486.c | 121 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 128 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_ili9486.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 86a1bee..ca73537 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -67,3 +67,9 @@ config FB_TFT_ILI9481 + depends on FB_TFT + help + Generic Framebuffer support for ILI9481 ++ ++config FB_TFT_ILI9486 ++ tristate "FB driver for the ILI9486 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ILI9486 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 0740641..8e633cf 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -13,3 +13,4 @@ obj-$(CONFIG_FB_TFT_ILI9325) += fb_ili9325.o + obj-$(CONFIG_FB_TFT_ILI9340) += fb_ili9340.o + obj-$(CONFIG_FB_TFT_ILI9341) += fb_ili9341.o + obj-$(CONFIG_FB_TFT_ILI9481) += fb_ili9481.o ++obj-$(CONFIG_FB_TFT_ILI9486) += fb_ili9486.o +diff --git a/drivers/staging/fbtft/fb_ili9486.c b/drivers/staging/fbtft/fb_ili9486.c +new file mode 100644 +index 0000000..95b8999 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_ili9486.c +@@ -0,0 +1,121 @@ ++/* ++ * FB driver for the ILI9486 LCD Controller ++ * ++ * Copyright (C) 2014 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ili9486" ++#define WIDTH 320 ++#define HEIGHT 480 ++ ++ ++/* this init sequence matches PiScreen */ ++static int default_init_sequence[] = { ++ /* Interface Mode Control */ ++ -1, 0xb0, 0x0, ++ /* Sleep OUT */ ++ -1, 0x11, ++ -2, 250, ++ /* Interface Pixel Format */ ++ -1, 0x3A, 0x55, ++ /* Power Control 3 */ ++ -1, 0xC2, 0x44, ++ /* VCOM Control 1 */ ++ -1, 0xC5, 0x00, 0x00, 0x00, 0x00, ++ /* PGAMCTRL(Positive Gamma Control) */ ++ -1, 0xE0, 0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98, ++ 0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x00, ++ /* NGAMCTRL(Negative Gamma Control) */ ++ -1, 0xE1, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, ++ 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00, ++ /* Digital Gamma Control 1 */ ++ -1, 0xE2, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, ++ 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00, ++ /* Sleep OUT */ ++ -1, 0x11, ++ /* Display ON */ ++ -1, 0x29, ++ /* end marker */ ++ -3 ++}; ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address */ ++ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); ++ ++ /* Row adress */ ++ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x36, 0x80 | (par->bgr << 3)); ++ break; ++ case 90: ++ write_reg(par, 0x36, 0x20 | (par->bgr << 3)); ++ break; ++ case 180: ++ write_reg(par, 0x36, 0x40 | (par->bgr << 3)); ++ break; ++ case 270: ++ write_reg(par, 0x36, 0xE0 | (par->bgr << 3)); ++ break; ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .init_sequence = default_init_sequence, ++ .fbtftops = { ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9486", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ili9486"); ++MODULE_ALIAS("platform:ili9486"); ++ ++MODULE_DESCRIPTION("FB driver for the ILI9486 LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From 5acd3b750126f227dc5c9d3ac16a658bcfc87124 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:21 +0100 +Subject: [PATCH 137/178] staging: fbtft: add fb_pcd8544 driver + +This commit adds the fb_pcd8544 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_pcd8544.c | 177 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 184 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_pcd8544.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index ca73537..fc1c76a 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -73,3 +73,9 @@ config FB_TFT_ILI9486 + depends on FB_TFT + help + Generic Framebuffer support for ILI9486 ++ ++config FB_TFT_PCD8544 ++ tristate "FB driver for the PCD8544 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for PCD8544 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 8e633cf..d7b9409 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -14,3 +14,4 @@ obj-$(CONFIG_FB_TFT_ILI9340) += fb_ili9340.o + obj-$(CONFIG_FB_TFT_ILI9341) += fb_ili9341.o + obj-$(CONFIG_FB_TFT_ILI9481) += fb_ili9481.o + obj-$(CONFIG_FB_TFT_ILI9486) += fb_ili9486.o ++obj-$(CONFIG_FB_TFT_PCD8544) += fb_pcd8544.o +diff --git a/drivers/staging/fbtft/fb_pcd8544.c b/drivers/staging/fbtft/fb_pcd8544.c +new file mode 100644 +index 0000000..c4f2a5b +--- /dev/null ++++ b/drivers/staging/fbtft/fb_pcd8544.c +@@ -0,0 +1,177 @@ ++/* ++ * FB driver for the PCD8544 LCD Controller ++ * ++ * The display is monochrome and the video memory is RGB565. ++ * Any pixel value except 0 turns the pixel on. ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_pcd8544" ++#define WIDTH 84 ++#define HEIGHT 48 ++#define TXBUFLEN 84*6 ++#define DEFAULT_GAMMA "40" /* gamma is used to control contrast in this driver */ ++ ++static unsigned tc = 0; ++module_param(tc, uint, 0); ++MODULE_PARM_DESC(tc, "TC[1:0] Temperature coefficient: 0-3 (default: 0)"); ++ ++static unsigned bs = 4; ++module_param(bs, uint, 0); ++MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)"); ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ /* Function set */ ++ write_reg(par, 0x21); /* 5:1 1 ++ 2:0 PD - Powerdown control: chip is active ++ 1:0 V - Entry mode: horizontal addressing ++ 0:1 H - Extended instruction set control: extended ++ */ ++ ++ /* H=1 Temperature control */ ++ write_reg(par, 0x04 | (tc & 0x3)); /* ++ 2:1 1 ++ 1:x TC1 - Temperature Coefficient: 0x10 ++ 0:x TC0 ++ */ ++ ++ /* H=1 Bias system */ ++ write_reg(par, 0x10 | (bs & 0x7)); /* ++ 4:1 1 ++ 3:0 0 ++ 2:x BS2 - Bias System ++ 1:x BS1 ++ 0:x BS0 ++ */ ++ ++ /* Function set */ ++ write_reg(par, 0x22); /* 5:1 1 ++ 2:0 PD - Powerdown control: chip is active ++ 1:1 V - Entry mode: vertical addressing ++ 0:0 H - Extended instruction set control: basic ++ */ ++ ++ /* H=0 Display control */ ++ write_reg(par, 0x08 | 4); /* ++ 3:1 1 ++ 2:1 D - DE: 10=normal mode ++ 1:0 0 ++ 0:0 E ++ */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* H=0 Set X address of RAM */ ++ write_reg(par, 0x80); /* 7:1 1 ++ 6-0: X[6:0] - 0x00 ++ */ ++ ++ /* H=0 Set Y address of RAM */ ++ write_reg(par, 0x40); /* 7:0 0 ++ 6:1 1 ++ 2-0: Y[2:0] - 0x0 ++ */ ++} ++ ++static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16 = (u16 *)par->info->screen_base; ++ u8 *buf = par->txbuf.buf; ++ int x, y, i; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ for (x=0;x<84;x++) { ++ for (y=0;y<6;y++) { ++ *buf = 0x00; ++ for (i=0;i<8;i++) { ++ *buf |= (vmem16[(y*8+i)*84+x] ? 1 : 0) << i; ++ } ++ buf++; ++ } ++ } ++ ++ /* Write data */ ++ gpio_set_value(par->gpio.dc, 1); ++ ret = par->fbtftops.write(par, par->txbuf.buf, 6*84); ++ if (ret < 0) ++ dev_err(par->info->device, "%s: write failed and returned: %d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ curves[0] &= 0x7F; ++ ++ write_reg(par, 0x23); /* turn on extended instruction set */ ++ write_reg(par, 0x80 | curves[0]); ++ write_reg(par, 0x22); /* turn off extended instruction set */ ++ ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .txbuflen = TXBUFLEN, ++ .gamma_num = 1, ++ .gamma_len = 1, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .write_vmem = write_vmem, ++ .set_gamma = set_gamma, ++ }, ++ .backlight = 1, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "philips,pdc8544", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("spi:pdc8544"); ++ ++MODULE_DESCRIPTION("FB driver for the PCD8544 LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From 46310158fbe40bc211bec03e2df7551953236f99 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:22 +0100 +Subject: [PATCH 138/178] staging: fbtft: add fb_ra8875 driver + +This commit adds the fb_ra8875 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 + + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_ra8875.c | 331 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 338 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_ra8875.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index fc1c76a..d66281e 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -79,3 +79,9 @@ config FB_TFT_PCD8544 + depends on FB_TFT + help + Generic Framebuffer support for PCD8544 ++ ++config FB_TFT_RA8875 ++ tristate "FB driver for the RA8875 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for RA8875 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index d7b9409..d9aa2b3 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -15,3 +15,4 @@ obj-$(CONFIG_FB_TFT_ILI9341) += fb_ili9341.o + obj-$(CONFIG_FB_TFT_ILI9481) += fb_ili9481.o + obj-$(CONFIG_FB_TFT_ILI9486) += fb_ili9486.o + obj-$(CONFIG_FB_TFT_PCD8544) += fb_pcd8544.o ++obj-$(CONFIG_FB_TFT_RA8875) += fb_ra8875.o +diff --git a/drivers/staging/fbtft/fb_ra8875.c b/drivers/staging/fbtft/fb_ra8875.c +new file mode 100644 +index 0000000..c323c06 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_ra8875.c +@@ -0,0 +1,331 @@ ++/****************************************************************************** ++ ++ ProjectName: FBTFT driver ***** ***** ++ for the RA8875 LCD Controller * * ************ ++ * ** ** * * ++ Copyright © by Pf@nne & NOTRO * * * * * **** * ++ * * * * * * * ++ Last modification by: * * * * **** * ++ - Pf@nne (pf@nne-mail.de) * * ***** * ++ * * * ******* ++ ***** * * ++ Date : 10.06.2014 * * ++ Version : V1.13 ***** ++ Revison : 5 ++ ++******************************************************************************* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ra8875" ++ ++static int write_spi(struct fbtft_par *par, void *buf, size_t len) ++{ ++ struct spi_transfer t = { ++ .tx_buf = buf, ++ .len = len, ++ .speed_hz = 1000000, ++ }; ++ struct spi_message m; ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ if (!par->spi) { ++ dev_err(par->info->device, ++ "%s: par->spi is unexpectedly NULL\n", __func__); ++ return -1; ++ } ++ ++ spi_message_init(&m); ++ if (par->txbuf.dma && buf == par->txbuf.buf) { ++ t.tx_dma = par->txbuf.dma; ++ m.is_dma_mapped = 1; ++ } ++ spi_message_add_tail(&t, &m); ++ return spi_sync(par->spi, &m); ++} ++ ++static int init_display(struct fbtft_par *par) ++{ ++ gpio_set_value(par->gpio.dc, 1); ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "%s()\n", __func__); ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "display size %dx%d\n", par->info->var.xres, par->info->var.yres); ++ ++ par->fbtftops.reset(par); ++ ++ if ((par->info->var.xres == 320) && (par->info->var.yres == 240)) { ++ /* PLL clock frequency */ ++ write_reg(par, 0x88 , 0x0A); ++ write_reg(par, 0x89 , 0x02); ++ mdelay(10); ++ /* color deep / MCU Interface */ ++ write_reg(par, 0x10 , 0x0C); ++ /* pixel clock period */ ++ write_reg(par, 0x04 , 0x03); ++ mdelay(1); ++ /* horizontal settings */ ++ write_reg(par, 0x14 , 0x27); ++ write_reg(par, 0x15 , 0x00); ++ write_reg(par, 0x16 , 0x05); ++ write_reg(par, 0x17 , 0x04); ++ write_reg(par, 0x18 , 0x03); ++ /* vertical settings */ ++ write_reg(par, 0x19 , 0xEF); ++ write_reg(par, 0x1A , 0x00); ++ write_reg(par, 0x1B , 0x05); ++ write_reg(par, 0x1C , 0x00); ++ write_reg(par, 0x1D , 0x0E); ++ write_reg(par, 0x1E , 0x00); ++ write_reg(par, 0x1F , 0x02); ++ } else if ((par->info->var.xres == 480) && (par->info->var.yres == 272)) { ++ /* PLL clock frequency */ ++ write_reg(par, 0x88 , 0x0A); ++ write_reg(par, 0x89 , 0x02); ++ mdelay(10); ++ /* color deep / MCU Interface */ ++ write_reg(par, 0x10 , 0x0C); ++ /* pixel clock period */ ++ write_reg(par, 0x04 , 0x82); ++ mdelay(1); ++ /* horizontal settings */ ++ write_reg(par, 0x14 , 0x3B); ++ write_reg(par, 0x15 , 0x00); ++ write_reg(par, 0x16 , 0x01); ++ write_reg(par, 0x17 , 0x00); ++ write_reg(par, 0x18 , 0x05); ++ /* vertical settings */ ++ write_reg(par, 0x19 , 0x0F); ++ write_reg(par, 0x1A , 0x01); ++ write_reg(par, 0x1B , 0x02); ++ write_reg(par, 0x1C , 0x00); ++ write_reg(par, 0x1D , 0x07); ++ write_reg(par, 0x1E , 0x00); ++ write_reg(par, 0x1F , 0x09); ++ } else if ((par->info->var.xres == 640) && (par->info->var.yres == 480)) { ++ /* PLL clock frequency */ ++ write_reg(par, 0x88 , 0x0B); ++ write_reg(par, 0x89 , 0x02); ++ mdelay(10); ++ /* color deep / MCU Interface */ ++ write_reg(par, 0x10 , 0x0C); ++ /* pixel clock period */ ++ write_reg(par, 0x04 , 0x01); ++ mdelay(1); ++ /* horizontal settings */ ++ write_reg(par, 0x14 , 0x4F); ++ write_reg(par, 0x15 , 0x05); ++ write_reg(par, 0x16 , 0x0F); ++ write_reg(par, 0x17 , 0x01); ++ write_reg(par, 0x18 , 0x00); ++ /* vertical settings */ ++ write_reg(par, 0x19 , 0xDF); ++ write_reg(par, 0x1A , 0x01); ++ write_reg(par, 0x1B , 0x0A); ++ write_reg(par, 0x1C , 0x00); ++ write_reg(par, 0x1D , 0x0E); ++ write_reg(par, 0x1E , 0x00); ++ write_reg(par, 0x1F , 0x01); ++ } else if ((par->info->var.xres == 800) && (par->info->var.yres == 480)) { ++ /* PLL clock frequency */ ++ write_reg(par, 0x88 , 0x0B); ++ write_reg(par, 0x89 , 0x02); ++ mdelay(10); ++ /* color deep / MCU Interface */ ++ write_reg(par, 0x10 , 0x0C); ++ /* pixel clock period */ ++ write_reg(par, 0x04 , 0x81); ++ mdelay(1); ++ /* horizontal settings */ ++ write_reg(par, 0x14 , 0x63); ++ write_reg(par, 0x15 , 0x03); ++ write_reg(par, 0x16 , 0x03); ++ write_reg(par, 0x17 , 0x02); ++ write_reg(par, 0x18 , 0x00); ++ /* vertical settings */ ++ write_reg(par, 0x19 , 0xDF); ++ write_reg(par, 0x1A , 0x01); ++ write_reg(par, 0x1B , 0x14); ++ write_reg(par, 0x1C , 0x00); ++ write_reg(par, 0x1D , 0x06); ++ write_reg(par, 0x1E , 0x00); ++ write_reg(par, 0x1F , 0x01); ++ } else { ++ dev_err(par->info->device, "display size is not supported!!"); ++ return -1; ++ } ++ ++ /* PWM clock */ ++ write_reg(par, 0x8a , 0x81); ++ write_reg(par, 0x8b , 0xFF); ++ mdelay(10); ++ ++ /* Display ON */ ++ write_reg(par, 0x01 , 0x80); ++ mdelay(10); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Set_Active_Window */ ++ write_reg(par, 0x30 , xs & 0x00FF); ++ write_reg(par, 0x31 , (xs & 0xFF00) >> 8); ++ write_reg(par, 0x32 , ys & 0x00FF); ++ write_reg(par, 0x33 , (ys & 0xFF00) >> 8); ++ write_reg(par, 0x34 , (xs+xe) & 0x00FF); ++ write_reg(par, 0x35 , ((xs+xe) & 0xFF00) >> 8); ++ write_reg(par, 0x36 , (ys+ye) & 0x00FF); ++ write_reg(par, 0x37 , ((ys+ye) & 0xFF00) >> 8); ++ ++ /* Set_Memory_Write_Cursor */ ++ write_reg(par, 0x46, xs & 0xff); ++ write_reg(par, 0x47, (xs >> 8) & 0x03); ++ write_reg(par, 0x48, ys & 0xff); ++ write_reg(par, 0x49, (ys >> 8) & 0x01); ++ ++ write_reg(par, 0x02); ++} ++ ++static void write_reg8_bus8(struct fbtft_par *par, int len, ...) ++{ ++ va_list args; ++ int i, ret; ++ u8 *buf = (u8 *)par->buf; ++ ++ /* slow down spi-speed for writing registers */ ++ par->fbtftops.write = write_spi; ++ ++ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { ++ va_start(args, len); ++ for (i = 0; i < len; i++) ++ buf[i] = (u8)va_arg(args, unsigned int); ++ va_end(args); ++ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, ++ u8, buf, len, "%s: ", __func__); ++ } ++ ++ va_start(args, len); ++ *buf++ = 0x80; ++ *buf = (u8)va_arg(args, unsigned int); ++ ret = par->fbtftops.write(par, par->buf, 2); ++ if (ret < 0) { ++ va_end(args); ++ dev_err(par->info->device, "%s: write() failed and returned %dn", ++ __func__, ret); ++ return; ++ } ++ len--; ++ ++ udelay(100); ++ ++ if (len) { ++ buf = (u8 *)par->buf; ++ *buf++ = 0x00; ++ i = len; ++ while (i--) ++ *buf++ = (u8)va_arg(args, unsigned int); ++ ++ ret = par->fbtftops.write(par, par->buf, len + 1); ++ if (ret < 0) { ++ va_end(args); ++ dev_err(par->info->device, "%s: write() failed and returned %dn", ++ __func__, ret); ++ return; ++ } ++ } ++ va_end(args); ++ ++ /* restore user spi-speed */ ++ par->fbtftops.write = fbtft_write_spi; ++ udelay(100); ++} ++ ++static int write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16; ++ u16 *txbuf16 = (u16 *)par->txbuf.buf; ++ size_t remain; ++ size_t to_copy; ++ size_t tx_array_size; ++ int i; ++ int ret = 0; ++ size_t startbyte_size = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", ++ __func__, offset, len); ++ ++ remain = len / 2; ++ vmem16 = (u16 *)(par->info->screen_base + offset); ++ tx_array_size = par->txbuf.len / 2; ++ txbuf16 = (u16 *)(par->txbuf.buf + 1); ++ tx_array_size -= 2; ++ *(u8 *)(par->txbuf.buf) = 0x00; ++ startbyte_size = 1; ++ ++ while (remain) { ++ to_copy = remain > tx_array_size ? tx_array_size : remain; ++ dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n", ++ to_copy, remain - to_copy); ++ ++ for (i = 0; i < to_copy; i++) ++ txbuf16[i] = cpu_to_be16(vmem16[i]); ++ ++ vmem16 = vmem16 + to_copy; ++ ret = par->fbtftops.write(par, par->txbuf.buf, ++ startbyte_size + to_copy * 2); ++ if (ret < 0) ++ return ret; ++ remain -= to_copy; ++ } ++ ++ return ret; ++} ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .write_register = write_reg8_bus8, ++ .write_vmem = write_vmem16_bus8, ++ .write = write_spi, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "raio,ra8875", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ra8875"); ++MODULE_ALIAS("platform:ra8875"); ++ ++MODULE_DESCRIPTION("FB driver for the RA8875 LCD Controller"); ++MODULE_AUTHOR("Pf@nne"); ++MODULE_LICENSE("GPL"); + +From e974e74080054820d5eb9400be70b395601657a3 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:23 +0100 +Subject: [PATCH 139/178] staging: fbtft: add fb_s6d02a1 driver + +This commit adds the fb_s6d02a1 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_s6d02a1.c | 168 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 175 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_s6d02a1.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index d66281e..34676db 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -85,3 +85,9 @@ config FB_TFT_RA8875 + depends on FB_TFT + help + Generic Framebuffer support for RA8875 ++ ++config FB_TFT_S6D02A1 ++ tristate "FB driver for the S6D02A1 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for S6D02A1 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index d9aa2b3..e349e7f 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -16,3 +16,4 @@ obj-$(CONFIG_FB_TFT_ILI9481) += fb_ili9481.o + obj-$(CONFIG_FB_TFT_ILI9486) += fb_ili9486.o + obj-$(CONFIG_FB_TFT_PCD8544) += fb_pcd8544.o + obj-$(CONFIG_FB_TFT_RA8875) += fb_ra8875.o ++obj-$(CONFIG_FB_TFT_S6D02A1) += fb_s6d02a1.o +diff --git a/drivers/staging/fbtft/fb_s6d02a1.c b/drivers/staging/fbtft/fb_s6d02a1.c +new file mode 100644 +index 0000000..e412a42 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_s6d02a1.c +@@ -0,0 +1,168 @@ ++/* ++ * FB driver for the S6D02A1 LCD Controller ++ * ++ * Based on fb_st7735r.c by Noralf Tronnes ++ * Init code from UTFT library by Henning Karlsen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_s6d02a1" ++ ++static int default_init_sequence[] = { ++ ++ -1, 0xf0, 0x5a, 0x5a, ++ ++ -1, 0xfc, 0x5a, 0x5a, ++ ++ -1, 0xfa, 0x02, 0x1f, 0x00, 0x10, 0x22, 0x30, 0x38, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3d, 0x02, 0x01, ++ ++ -1, 0xfb, 0x21, 0x00, 0x02, 0x04, 0x07, 0x0a, 0x0b, 0x0c, 0x0c, 0x16, 0x1e, 0x30, 0x3f, 0x01, 0x02, ++ ++ /* power setting sequence */ ++ -1, 0xfd, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x01, 0x01, 0x00, 0x1f, 0x1f, ++ ++ -1, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, ++ ++ -1, 0xf5, 0x00, 0x70, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x66, 0x06, ++ ++ -1, 0xf6, 0x02, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x01, 0x00, ++ ++ -1, 0xf2, 0x00, 0x01, 0x03, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x08, 0x08, ++ ++ -1, 0xf8, 0x11, ++ ++ -1, 0xf7, 0xc8, 0x20, 0x00, 0x00, ++ ++ -1, 0xf3, 0x00, 0x00, ++ ++ -1, 0x11, ++ -2, 50, ++ ++ -1, 0xf3, 0x00, 0x01, ++ -2, 50, ++ -1, 0xf3, 0x00, 0x03, ++ -2, 50, ++ -1, 0xf3, 0x00, 0x07, ++ -2, 50, ++ -1, 0xf3, 0x00, 0x0f, ++ -2, 50, ++ ++ -1, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, ++ -2, 50, ++ ++ -1, 0xf3, 0x00, 0x1f, ++ -2, 50, ++ -1, 0xf3, 0x00, 0x7f, ++ -2, 50, ++ ++ -1, 0xf3, 0x00, 0xff, ++ -2, 50, ++ ++ -1, 0xfd, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x01, 0x00, 0x16, 0x16, ++ ++ -1, 0xf4, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, ++ ++ /* initializing sequence */ ++ ++ -1, 0x36, 0x08, ++ ++ -1, 0x35, 0x00, ++ ++ -1, 0x3a, 0x05, ++ ++ /* gamma setting sequence */ ++ -1, 0x26, 0x01, /* preset gamma curves, possible values 0x01, 0x02, 0x04, 0x08 */ ++ ++ -2, 150, ++ -1, 0x29, ++ -1, 0x2c, ++ /* end marker */ ++ -3 ++ ++}; ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address */ ++ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); ++ ++ /* Row adress */ ++ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++#define MY (1 << 7) ++#define MX (1 << 6) ++#define MV (1 << 5) ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* MADCTL - Memory data access control ++ RGB/BGR: ++ 1. Mode selection pin SRGB ++ RGB H/W pin for color filter setting: 0=RGB, 1=BGR ++ 2. MADCTL RGB bit ++ RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR */ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x36, MX | MY | (par->bgr << 3)); ++ break; ++ case 270: ++ write_reg(par, 0x36, MY | MV | (par->bgr << 3)); ++ break; ++ case 180: ++ write_reg(par, 0x36, (par->bgr << 3)); ++ break; ++ case 90: ++ write_reg(par, 0x36, MX | MV | (par->bgr << 3)); ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = 128, ++ .height = 160, ++ .init_sequence = default_init_sequence, ++ .fbtftops = { ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d02a1", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:s6d02a1"); ++MODULE_ALIAS("platform:s6d02a1"); ++ ++MODULE_DESCRIPTION("FB driver for the S6D02A1 LCD Controller"); ++MODULE_AUTHOR("WOLFGANG BUENING"); ++MODULE_LICENSE("GPL"); + +From ebff20f60858c7b44de27d06c785f87958df1cfc Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:24 +0100 +Subject: [PATCH 140/178] staging: fbtft: add fb_s6d1121 driver + +This commit adds the fb_s6d1121 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_s6d1121.c | 208 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 215 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_s6d1121.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 34676db..4fd9cfd 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -91,3 +91,9 @@ config FB_TFT_S6D02A1 + depends on FB_TFT + help + Generic Framebuffer support for S6D02A1 ++ ++config FB_TFT_S6D1121 ++ tristate "FB driver for the S6D1211 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for S6D1121 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index e349e7f..48b3ce1 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -17,3 +17,4 @@ obj-$(CONFIG_FB_TFT_ILI9486) += fb_ili9486.o + obj-$(CONFIG_FB_TFT_PCD8544) += fb_pcd8544.o + obj-$(CONFIG_FB_TFT_RA8875) += fb_ra8875.o + obj-$(CONFIG_FB_TFT_S6D02A1) += fb_s6d02a1.o ++obj-$(CONFIG_FB_TFT_S6D1121) += fb_s6d1121.o +diff --git a/drivers/staging/fbtft/fb_s6d1121.c b/drivers/staging/fbtft/fb_s6d1121.c +new file mode 100644 +index 0000000..7bbb21b +--- /dev/null ++++ b/drivers/staging/fbtft/fb_s6d1121.c +@@ -0,0 +1,208 @@ ++/* ++ * FB driver for the S6D1121 LCD Controller ++ * ++ * Copyright (C) 2013 Roman Rolinsky ++ * ++ * Based on fb_ili9325.c by Noralf Tronnes ++ * Based on ili9325.c by Jeroen Domburg ++ * Init code from UTFT library by Henning Karlsen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_s6d1121" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define BPP 16 ++#define FPS 20 ++#define DEFAULT_GAMMA "26 09 24 2C 1F 23 24 25 22 26 25 23 0D 00\n" \ ++ "1C 1A 13 1D 0B 11 12 10 13 15 36 19 00 0D" ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ ++ /* Initialization sequence from Lib_UTFT */ ++ ++ write_reg(par, 0x0011, 0x2004); ++ write_reg(par, 0x0013, 0xCC00); ++ write_reg(par, 0x0015, 0x2600); ++ write_reg(par, 0x0014, 0x252A); ++ write_reg(par, 0x0012, 0x0033); ++ write_reg(par, 0x0013, 0xCC04); ++ write_reg(par, 0x0013, 0xCC06); ++ write_reg(par, 0x0013, 0xCC4F); ++ write_reg(par, 0x0013, 0x674F); ++ write_reg(par, 0x0011, 0x2003); ++ write_reg(par, 0x0016, 0x0007); ++ write_reg(par, 0x0002, 0x0013); ++ write_reg(par, 0x0003, 0x0003); ++ write_reg(par, 0x0001, 0x0127); ++ write_reg(par, 0x0008, 0x0303); ++ write_reg(par, 0x000A, 0x000B); ++ write_reg(par, 0x000B, 0x0003); ++ write_reg(par, 0x000C, 0x0000); ++ write_reg(par, 0x0041, 0x0000); ++ write_reg(par, 0x0050, 0x0000); ++ write_reg(par, 0x0060, 0x0005); ++ write_reg(par, 0x0070, 0x000B); ++ write_reg(par, 0x0071, 0x0000); ++ write_reg(par, 0x0078, 0x0000); ++ write_reg(par, 0x007A, 0x0000); ++ write_reg(par, 0x0079, 0x0007); ++ write_reg(par, 0x0007, 0x0051); ++ write_reg(par, 0x0007, 0x0053); ++ write_reg(par, 0x0079, 0x0000); ++ ++ write_reg(par, 0x0022); /* Write Data to GRAM */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ switch (par->info->var.rotate) { ++ /* R20h = Horizontal GRAM Start Address */ ++ /* R21h = Vertical GRAM Start Address */ ++ case 0: ++ write_reg(par, 0x0020, xs); ++ write_reg(par, 0x0021, ys); ++ break; ++ case 180: ++ write_reg(par, 0x0020, WIDTH - 1 - xs); ++ write_reg(par, 0x0021, HEIGHT - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x0020, WIDTH - 1 - ys); ++ write_reg(par, 0x0021, xs); ++ break; ++ case 90: ++ write_reg(par, 0x0020, ys); ++ write_reg(par, 0x0021, HEIGHT - 1 - xs); ++ break; ++ } ++ write_reg(par, 0x0022); /* Write Data to GRAM */ ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ /* AM: GRAM update direction */ ++ case 0: ++ write_reg(par, 0x03, 0x0003 | (par->bgr << 12)); ++ break; ++ case 180: ++ write_reg(par, 0x03, 0x0000 | (par->bgr << 12)); ++ break; ++ case 270: ++ write_reg(par, 0x03, 0x000A | (par->bgr << 12)); ++ break; ++ case 90: ++ write_reg(par, 0x03, 0x0009 | (par->bgr << 12)); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Gamma string format: ++ PKP0 PKP1 PKP2 PKP3 PKP4 PKP5 PKP6 PKP7 PKP8 PKP9 PKP10 PKP11 VRP0 VRP1 ++ PKN0 PKN1 PKN2 PKN3 PKN4 PKN5 PKN6 PKN7 PRN8 PRN9 PRN10 PRN11 VRN0 VRN1 ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long mask[] = { ++ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, ++ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, ++ 0b11111, 0b11111, ++ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, ++ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, ++ 0b11111, 0b11111 }; ++ int i, j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < 14; j++) ++ CURVE(i, j) &= mask[i*par->gamma.num_values + j]; ++ ++ write_reg(par, 0x0030, CURVE(0, 1) << 8 | CURVE(0, 0)); ++ write_reg(par, 0x0031, CURVE(0, 3) << 8 | CURVE(0, 2)); ++ write_reg(par, 0x0032, CURVE(0, 5) << 8 | CURVE(0, 3)); ++ write_reg(par, 0x0033, CURVE(0, 7) << 8 | CURVE(0, 6)); ++ write_reg(par, 0x0034, CURVE(0, 9) << 8 | CURVE(0, 8)); ++ write_reg(par, 0x0035, CURVE(0, 11) << 8 | CURVE(0, 10)); ++ ++ write_reg(par, 0x0036, CURVE(1, 1) << 8 | CURVE(1, 0)); ++ write_reg(par, 0x0037, CURVE(1, 3) << 8 | CURVE(1, 2)); ++ write_reg(par, 0x0038, CURVE(1, 5) << 8 | CURVE(1, 4)); ++ write_reg(par, 0x0039, CURVE(1, 7) << 8 | CURVE(1, 6)); ++ write_reg(par, 0x003A, CURVE(1, 9) << 8 | CURVE(1, 8)); ++ write_reg(par, 0x003B, CURVE(1, 11) << 8 | CURVE(1, 10)); ++ ++ write_reg(par, 0x003C, CURVE(0, 13) << 8 | CURVE(0, 12)); ++ write_reg(par, 0x003D, CURVE(1, 13) << 8 | CURVE(1, 12)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 16, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .bpp = BPP, ++ .fps = FPS, ++ .gamma_num = 2, ++ .gamma_len = 14, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d1121", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:s6d1121"); ++MODULE_ALIAS("platform:s6d1121"); ++ ++MODULE_DESCRIPTION("FB driver for the S6D1121 LCD Controller"); ++MODULE_AUTHOR("Roman Rolinsky"); ++MODULE_LICENSE("GPL"); + +From cf0d08299526c255d9505b81782eb7212689852c Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:25 +0100 +Subject: [PATCH 141/178] staging: fbtft: add fb_ssd1289 driver + +This commit adds the fb_ssd1289 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_ssd1289.c | 206 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 213 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_ssd1289.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 4fd9cfd..05e8571 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -97,3 +97,9 @@ config FB_TFT_S6D1121 + depends on FB_TFT + help + Generic Framebuffer support for S6D1121 ++ ++config FB_TFT_SSD1289 ++ tristate "FB driver for the SSD1289 LCD Controller" ++ depends on FB_TFT ++ help ++ Framebuffer support for SSD1289 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 48b3ce1..ea5fa1e 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -18,3 +18,4 @@ obj-$(CONFIG_FB_TFT_PCD8544) += fb_pcd8544.o + obj-$(CONFIG_FB_TFT_RA8875) += fb_ra8875.o + obj-$(CONFIG_FB_TFT_S6D02A1) += fb_s6d02a1.o + obj-$(CONFIG_FB_TFT_S6D1121) += fb_s6d1121.o ++obj-$(CONFIG_FB_TFT_SSD1289) += fb_ssd1289.o +diff --git a/drivers/staging/fbtft/fb_ssd1289.c b/drivers/staging/fbtft/fb_ssd1289.c +new file mode 100644 +index 0000000..ef46fbc +--- /dev/null ++++ b/drivers/staging/fbtft/fb_ssd1289.c +@@ -0,0 +1,206 @@ ++/* ++ * FB driver for the SSD1289 LCD Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * Init sequence taken from ITDB02_Graph16.cpp - (C)2010-2011 Henning Karlsen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ssd1289" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define DEFAULT_GAMMA "02 03 2 5 7 7 4 2 4 2\n" \ ++ "02 03 2 5 7 5 4 2 4 2" ++ ++static unsigned reg11 = 0x6040; ++module_param(reg11, uint, 0); ++MODULE_PARM_DESC(reg11, "Register 11h value"); ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ ++ write_reg(par, 0x00, 0x0001); ++ write_reg(par, 0x03, 0xA8A4); ++ write_reg(par, 0x0C, 0x0000); ++ write_reg(par, 0x0D, 0x080C); ++ write_reg(par, 0x0E, 0x2B00); ++ write_reg(par, 0x1E, 0x00B7); ++ write_reg(par, 0x01, ++ (1 << 13) | (par->bgr << 11) | (1 << 9) | (HEIGHT - 1)); ++ write_reg(par, 0x02, 0x0600); ++ write_reg(par, 0x10, 0x0000); ++ write_reg(par, 0x05, 0x0000); ++ write_reg(par, 0x06, 0x0000); ++ write_reg(par, 0x16, 0xEF1C); ++ write_reg(par, 0x17, 0x0003); ++ write_reg(par, 0x07, 0x0233); ++ write_reg(par, 0x0B, 0x0000); ++ write_reg(par, 0x0F, 0x0000); ++ write_reg(par, 0x41, 0x0000); ++ write_reg(par, 0x42, 0x0000); ++ write_reg(par, 0x48, 0x0000); ++ write_reg(par, 0x49, 0x013F); ++ write_reg(par, 0x4A, 0x0000); ++ write_reg(par, 0x4B, 0x0000); ++ write_reg(par, 0x44, 0xEF00); ++ write_reg(par, 0x45, 0x0000); ++ write_reg(par, 0x46, 0x013F); ++ write_reg(par, 0x23, 0x0000); ++ write_reg(par, 0x24, 0x0000); ++ write_reg(par, 0x25, 0x8000); ++ write_reg(par, 0x4f, 0x0000); ++ write_reg(par, 0x4e, 0x0000); ++ write_reg(par, 0x22); ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ switch (par->info->var.rotate) { ++ /* R4Eh - Set GDDRAM X address counter */ ++ /* R4Fh - Set GDDRAM Y address counter */ ++ case 0: ++ write_reg(par, 0x4e, xs); ++ write_reg(par, 0x4f, ys); ++ break; ++ case 180: ++ write_reg(par, 0x4e, par->info->var.xres - 1 - xs); ++ write_reg(par, 0x4f, par->info->var.yres - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x4e, par->info->var.yres - 1 - ys); ++ write_reg(par, 0x4f, xs); ++ break; ++ case 90: ++ write_reg(par, 0x4e, ys); ++ write_reg(par, 0x4f, par->info->var.xres - 1 - xs); ++ break; ++ } ++ ++ /* R22h - RAM data write */ ++ write_reg(par, 0x22); ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ if (par->fbtftops.init_display != init_display) { ++ /* don't risk messing up register 11h */ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "%s: skipping since custom init_display() is used\n", ++ __func__); ++ return 0; ++ } ++ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x11, reg11 | 0b110000); ++ break; ++ case 270: ++ write_reg(par, 0x11, reg11 | 0b101000); ++ break; ++ case 180: ++ write_reg(par, 0x11, reg11 | 0b000000); ++ break; ++ case 90: ++ write_reg(par, 0x11, reg11 | 0b011000); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Gamma string format: ++ VRP0 VRP1 PRP0 PRP1 PKP0 PKP1 PKP2 PKP3 PKP4 PKP5 ++ VRN0 VRN1 PRN0 PRN1 PKN0 PKN1 PKN2 PKN3 PKN4 PKN5 ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long mask[] = { ++ 0b11111, 0b11111, 0b111, 0b111, 0b111, ++ 0b111, 0b111, 0b111, 0b111, 0b111, ++ 0b11111, 0b11111, 0b111, 0b111, 0b111, ++ 0b111, 0b111, 0b111, 0b111, 0b111 }; ++ int i, j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < 10; j++) ++ CURVE(i, j) &= mask[i*par->gamma.num_values + j]; ++ ++ write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4)); ++ write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6)); ++ write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8)); ++ write_reg(par, 0x0033, CURVE(0, 3) << 8 | CURVE(0, 2)); ++ write_reg(par, 0x0034, CURVE(1, 5) << 8 | CURVE(1, 4)); ++ write_reg(par, 0x0035, CURVE(1, 7) << 8 | CURVE(1, 6)); ++ write_reg(par, 0x0036, CURVE(1, 9) << 8 | CURVE(1, 8)); ++ write_reg(par, 0x0037, CURVE(1, 3) << 8 | CURVE(1, 2)); ++ write_reg(par, 0x003A, CURVE(0, 1) << 8 | CURVE(0, 0)); ++ write_reg(par, 0x003B, CURVE(1, 1) << 8 | CURVE(1, 0)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 16, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .gamma_num = 2, ++ .gamma_len = 10, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1289", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ssd1289"); ++MODULE_ALIAS("platform:ssd1289"); ++ ++MODULE_DESCRIPTION("FB driver for the SSD1289 LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From 0ea05ce08f869e95b5c0262c56d29ecb6d6473b6 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:26 +0100 +Subject: [PATCH 142/178] staging: fbtft: add fb_ssd1306 driver + +This commit adds the fb_ssd1306 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 + + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_ssd1306.c | 229 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 236 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_ssd1306.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 05e8571..3ae8259 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -103,3 +103,9 @@ config FB_TFT_SSD1289 + depends on FB_TFT + help + Framebuffer support for SSD1289 ++ ++config FB_TFT_SSD1306 ++ tristate "FB driver for the SSD1306 OLED Controller" ++ depends on FB_TFT ++ help ++ Framebuffer support for SSD1306 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index ea5fa1e..b612a4d 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -19,3 +19,4 @@ obj-$(CONFIG_FB_TFT_RA8875) += fb_ra8875.o + obj-$(CONFIG_FB_TFT_S6D02A1) += fb_s6d02a1.o + obj-$(CONFIG_FB_TFT_S6D1121) += fb_s6d1121.o + obj-$(CONFIG_FB_TFT_SSD1289) += fb_ssd1289.o ++obj-$(CONFIG_FB_TFT_SSD1306) += fb_ssd1306.o +diff --git a/drivers/staging/fbtft/fb_ssd1306.c b/drivers/staging/fbtft/fb_ssd1306.c +new file mode 100644 +index 0000000..5ea195b +--- /dev/null ++++ b/drivers/staging/fbtft/fb_ssd1306.c +@@ -0,0 +1,229 @@ ++/* ++ * FB driver for the SSD1306 OLED Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ssd1306" ++#define WIDTH 128 ++#define HEIGHT 64 ++ ++ ++/* ++ write_reg() caveat: ++ ++ This doesn't work because D/C has to be LOW for both values: ++ write_reg(par, val1, val2); ++ ++ Do it like this: ++ write_reg(par, val1); ++ write_reg(par, val2); ++*/ ++ ++/* Init sequence taken from the Adafruit SSD1306 Arduino library */ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ if (par->gamma.curves[0] == 0) { ++ mutex_lock(&par->gamma.lock); ++ if (par->info->var.yres == 64) ++ par->gamma.curves[0] = 0xCF; ++ else ++ par->gamma.curves[0] = 0x8F; ++ mutex_unlock(&par->gamma.lock); ++ } ++ ++ /* Set Display OFF */ ++ write_reg(par, 0xAE); ++ ++ /* Set Display Clock Divide Ratio/ Oscillator Frequency */ ++ write_reg(par, 0xD5); ++ write_reg(par, 0x80); ++ ++ /* Set Multiplex Ratio */ ++ write_reg(par, 0xA8); ++ if (par->info->var.yres == 64) ++ write_reg(par, 0x3F); ++ else ++ write_reg(par, 0x1F); ++ ++ /* Set Display Offset */ ++ write_reg(par, 0xD3); ++ write_reg(par, 0x0); ++ ++ /* Set Display Start Line */ ++ write_reg(par, 0x40 | 0x0); ++ ++ /* Charge Pump Setting */ ++ write_reg(par, 0x8D); ++ /* A[2] = 1b, Enable charge pump during display on */ ++ write_reg(par, 0x14); ++ ++ /* Set Memory Addressing Mode */ ++ write_reg(par, 0x20); ++ /* Vertical addressing mode */ ++ write_reg(par, 0x01); ++ ++ /*Set Segment Re-map */ ++ /* column address 127 is mapped to SEG0 */ ++ write_reg(par, 0xA0 | 0x1); ++ ++ /* Set COM Output Scan Direction */ ++ /* remapped mode. Scan from COM[N-1] to COM0 */ ++ write_reg(par, 0xC8); ++ ++ /* Set COM Pins Hardware Configuration */ ++ write_reg(par, 0xDA); ++ if (par->info->var.yres == 64) ++ /* A[4]=1b, Alternative COM pin configuration */ ++ write_reg(par, 0x12); ++ else ++ /* A[4]=0b, Sequential COM pin configuration */ ++ write_reg(par, 0x02); ++ ++ /* Set Pre-charge Period */ ++ write_reg(par, 0xD9); ++ write_reg(par, 0xF1); ++ ++ /* Set VCOMH Deselect Level */ ++ write_reg(par, 0xDB); ++ /* according to the datasheet, this value is out of bounds */ ++ write_reg(par, 0x40); ++ ++ /* Entire Display ON */ ++ /* Resume to RAM content display. Output follows RAM content */ ++ write_reg(par, 0xA4); ++ ++ /* Set Normal Display ++ 0 in RAM: OFF in display panel ++ 1 in RAM: ON in display panel */ ++ write_reg(par, 0xA6); ++ ++ /* Set Display ON */ ++ write_reg(par, 0xAF); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Set Lower Column Start Address for Page Addressing Mode */ ++ write_reg(par, 0x00 | 0x0); ++ /* Set Higher Column Start Address for Page Addressing Mode */ ++ write_reg(par, 0x10 | 0x0); ++ /* Set Display Start Line */ ++ write_reg(par, 0x40 | 0x0); ++} ++ ++static int blank(struct fbtft_par *par, bool on) ++{ ++ fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", ++ __func__, on ? "true" : "false"); ++ ++ if (on) ++ write_reg(par, 0xAE); ++ else ++ write_reg(par, 0xAF); ++ return 0; ++} ++ ++/* Gamma is used to control Contrast */ ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ curves[0] &= 0xFF; ++ ++ /* Set Contrast Control for BANK0 */ ++ write_reg(par, 0x81); ++ write_reg(par, curves[0]); ++ ++ return 0; ++} ++ ++static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16 = (u16 *)par->info->screen_base; ++ u8 *buf = par->txbuf.buf; ++ int x, y, i; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ for (x = 0; x < par->info->var.xres; x++) { ++ for (y = 0; y < par->info->var.yres/8; y++) { ++ *buf = 0x00; ++ for (i = 0; i < 8; i++) ++ *buf |= (vmem16[(y*8+i)*par->info->var.xres+x] ? 1 : 0) << i; ++ buf++; ++ } ++ } ++ ++ /* Write data */ ++ gpio_set_value(par->gpio.dc, 1); ++ ret = par->fbtftops.write(par, par->txbuf.buf, ++ par->info->var.xres*par->info->var.yres/8); ++ if (ret < 0) ++ dev_err(par->info->device, ++ "%s: write failed and returned: %d\n", __func__, ret); ++ ++ return ret; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .gamma_num = 1, ++ .gamma_len = 1, ++ .gamma = "00", ++ .fbtftops = { ++ .write_vmem = write_vmem, ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .blank = blank, ++ .set_gamma = set_gamma, ++ }, ++}; ++ ++ ++FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1306", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ssd1306"); ++MODULE_ALIAS("platform:ssd1306"); ++ ++MODULE_DESCRIPTION("SSD1306 OLED Driver"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From 015b84143d5394eb0ecf9b790a04f62f9b9f67c7 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:27 +0100 +Subject: [PATCH 143/178] staging: fbtft: add fb_ssd1331 driver + +This commit adds the fb_ssd1331 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_ssd1331.c | 205 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 212 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_ssd1331.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 3ae8259..f1e4832 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -109,3 +109,9 @@ config FB_TFT_SSD1306 + depends on FB_TFT + help + Framebuffer support for SSD1306 ++ ++config FB_TFT_SSD1331 ++ tristate "FB driver for the SSD1331 LCD Controller" ++ depends on FB_TFT ++ help ++ Framebuffer support for SSD1331 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index b612a4d..8dffb75 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -20,3 +20,4 @@ obj-$(CONFIG_FB_TFT_S6D02A1) += fb_s6d02a1.o + obj-$(CONFIG_FB_TFT_S6D1121) += fb_s6d1121.o + obj-$(CONFIG_FB_TFT_SSD1289) += fb_ssd1289.o + obj-$(CONFIG_FB_TFT_SSD1306) += fb_ssd1306.o ++obj-$(CONFIG_FB_TFT_SSD1331) += fb_ssd1331.o +diff --git a/drivers/staging/fbtft/fb_ssd1331.c b/drivers/staging/fbtft/fb_ssd1331.c +new file mode 100644 +index 0000000..da7464f +--- /dev/null ++++ b/drivers/staging/fbtft/fb_ssd1331.c +@@ -0,0 +1,205 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ssd1331" ++#define WIDTH 96 ++#define HEIGHT 64 ++#define GAMMA_NUM 1 ++#define GAMMA_LEN 63 ++#define DEFAULT_GAMMA "0 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2" \ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ write_reg(par, 0xae); /* Display Off */ ++ write_reg(par, 0xa0, 0x70 | (par->bgr << 2)); /* Set Colour Depth */ ++ write_reg(par, 0x72); // RGB colour ++ write_reg(par, 0xa1, 0x00); /* Set Display Start Line */ ++ write_reg(par, 0xa2, 0x00); /* Set Display Offset */ ++ write_reg(par, 0xa4); /* NORMALDISPLAY */ ++ write_reg(par, 0xa8, 0x3f); // Set multiplex ++ write_reg(par, 0xad, 0x8e); // Set master ++ // write_reg(par, 0xb0, 0x0b); // Set power mode ++ write_reg(par, 0xb1, 0x31); // Precharge ++ write_reg(par, 0xb3, 0xf0); // Clock div ++ write_reg(par, 0x8a, 0x64); // Precharge A ++ write_reg(par, 0x8b, 0x78); // Precharge B ++ write_reg(par, 0x8c, 0x64); // Precharge C ++ write_reg(par, 0xbb, 0x3a); // Precharge level ++ write_reg(par, 0xbe, 0x3e); // vcomh ++ write_reg(par, 0x87, 0x06); // Master current ++ write_reg(par, 0x81, 0x91); // Contrast A ++ write_reg(par, 0x82, 0x50); // Contrast B ++ write_reg(par, 0x83, 0x7d); // Contrast C ++ write_reg(par, 0xaf); /* Set Sleep Mode Display On */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ write_reg(par, 0x15, xs, xe); ++ write_reg(par, 0x75, ys, ye); ++} ++ ++static void write_reg8_bus8(struct fbtft_par *par, int len, ...) ++{ ++ va_list args; ++ int i, ret; ++ u8 *buf = (u8 *)par->buf; ++ ++ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { ++ va_start(args, len); ++ for (i = 0; i < len; i++) { ++ buf[i] = (u8)va_arg(args, unsigned int); ++ } ++ va_end(args); ++ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, u8, buf, len, "%s: ", __func__); ++ } ++ ++ va_start(args, len); ++ ++ *buf = (u8)va_arg(args, unsigned int); ++ if (par->gpio.dc != -1) ++ gpio_set_value(par->gpio.dc, 0); ++ ret = par->fbtftops.write(par, par->buf, sizeof(u8)); ++ if (ret < 0) { ++ va_end(args); ++ dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); ++ return; ++ } ++ len--; ++ ++ if (len) { ++ i = len; ++ while (i--) { ++ *buf++ = (u8)va_arg(args, unsigned int); ++ } ++ ret = par->fbtftops.write(par, par->buf, len * (sizeof(u8))); ++ if (ret < 0) { ++ va_end(args); ++ dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); ++ return; ++ } ++ } ++ if (par->gpio.dc != -1) ++ gpio_set_value(par->gpio.dc, 1); ++ va_end(args); ++} ++ ++/* ++ Grayscale Lookup Table ++ GS1 - GS63 ++ The driver Gamma curve contains the relative values between the entries ++ in the Lookup table. ++ ++ From datasheet: ++ 8.8 Gray Scale Decoder ++ ++ there are total 180 Gamma Settings (Setting 0 to Setting 180) ++ available for the Gray Scale table. ++ ++ The gray scale is defined in incremental way, with reference ++ to the length of previous table entry: ++ Setting of GS1 has to be >= 0 ++ Setting of GS2 has to be > Setting of GS1 +1 ++ Setting of GS3 has to be > Setting of GS2 +1 ++ : ++ Setting of GS63 has to be > Setting of GS62 +1 ++ ++ ++*/ ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long tmp[GAMMA_NUM * GAMMA_LEN]; ++ int i, acc = 0; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ for (i = 0; i < 63; i++) { ++ if (i > 0 && curves[i] < 2) { ++ dev_err(par->info->device, ++ "Illegal value in Grayscale Lookup Table at index %d. " \ ++ "Must be greater than 1\n", i); ++ return -EINVAL; ++ } ++ acc += curves[i]; ++ tmp[i] = acc; ++ if (acc > 180) { ++ dev_err(par->info->device, ++ "Illegal value(s) in Grayscale Lookup Table. " \ ++ "At index=%d, the accumulated value has exceeded 180\n", i); ++ return -EINVAL; ++ } ++ } ++ ++ write_reg(par, 0xB8, ++ tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], ++ tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15], ++ tmp[16], tmp[17], tmp[18], tmp[19], tmp[20], tmp[21], tmp[22], tmp[23], ++ tmp[24], tmp[25], tmp[26], tmp[27], tmp[28], tmp[29], tmp[30], tmp[31], ++ tmp[32], tmp[33], tmp[34], tmp[35], tmp[36], tmp[37], tmp[38], tmp[39], ++ tmp[40], tmp[41], tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47], ++ tmp[48], tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55], ++ tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61], tmp[62]); ++ ++ return 0; ++} ++ ++static int blank(struct fbtft_par *par, bool on) ++{ ++ fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", ++ __func__, on ? "true" : "false"); ++ if (on) ++ write_reg(par, 0xAE); ++ else ++ write_reg(par, 0xAF); ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .gamma_num = GAMMA_NUM, ++ .gamma_len = GAMMA_LEN, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .write_register = write_reg8_bus8, ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_gamma = set_gamma, ++ .blank = blank, ++ }, ++}; ++ ++FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1331", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ssd1331"); ++MODULE_ALIAS("platform:ssd1331"); ++ ++MODULE_DESCRIPTION("SSD1331 OLED Driver"); ++MODULE_AUTHOR("Alec Smecher (adapted from SSD1351 by James Davies)"); ++MODULE_LICENSE("GPL"); + +From 9e7236d5847bf3c92b96e16584579e4adb11ab56 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:28 +0100 +Subject: [PATCH 144/178] staging: fbtft: add fb_ssd1351 driver + +This commit adds the fb_ssd1351 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 + + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_ssd1351.c | 258 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 265 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_ssd1351.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index f1e4832..2ba8ef7 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -115,3 +115,9 @@ config FB_TFT_SSD1331 + depends on FB_TFT + help + Framebuffer support for SSD1331 ++ ++config FB_TFT_SSD1351 ++ tristate "FB driver for the SSD1351 LCD Controller" ++ depends on FB_TFT ++ help ++ Framebuffer support for SSD1351 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 8dffb75..7481e34 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -21,3 +21,4 @@ obj-$(CONFIG_FB_TFT_S6D1121) += fb_s6d1121.o + obj-$(CONFIG_FB_TFT_SSD1289) += fb_ssd1289.o + obj-$(CONFIG_FB_TFT_SSD1306) += fb_ssd1306.o + obj-$(CONFIG_FB_TFT_SSD1331) += fb_ssd1331.o ++obj-$(CONFIG_FB_TFT_SSD1351) += fb_ssd1351.o +diff --git a/drivers/staging/fbtft/fb_ssd1351.c b/drivers/staging/fbtft/fb_ssd1351.c +new file mode 100644 +index 0000000..062d986 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_ssd1351.c +@@ -0,0 +1,258 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_ssd1351" ++#define WIDTH 128 ++#define HEIGHT 128 ++#define GAMMA_NUM 1 ++#define GAMMA_LEN 63 ++#define DEFAULT_GAMMA "0 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2" \ ++ ++static void register_onboard_backlight(struct fbtft_par *par); ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ if (par->pdata ++ && par->pdata->display.backlight == FBTFT_ONBOARD_BACKLIGHT) { ++ /* module uses onboard GPIO for panel power */ ++ par->fbtftops.register_backlight = register_onboard_backlight; ++ } ++ ++ par->fbtftops.reset(par); ++ ++ write_reg(par, 0xfd, 0x12); /* Command Lock */ ++ write_reg(par, 0xfd, 0xb1); /* Command Lock */ ++ write_reg(par, 0xae); /* Display Off */ ++ write_reg(par, 0xb3, 0xf1); /* Front Clock Div */ ++ write_reg(par, 0xca, 0x7f); /* Set Mux Ratio */ ++ write_reg(par, 0x15, 0x00, 0x7f); /* Set Column Address */ ++ write_reg(par, 0x75, 0x00, 0x7f); /* Set Row Address */ ++ write_reg(par, 0xa1, 0x00); /* Set Display Start Line */ ++ write_reg(par, 0xa2, 0x00); /* Set Display Offset */ ++ write_reg(par, 0xb5, 0x00); /* Set GPIO */ ++ write_reg(par, 0xab, 0x01); /* Set Function Selection */ ++ write_reg(par, 0xb1, 0x32); /* Set Phase Length */ ++ write_reg(par, 0xb4, 0xa0, 0xb5, 0x55); /* Set Segment Low Voltage */ ++ write_reg(par, 0xbb, 0x17); /* Set Precharge Voltage */ ++ write_reg(par, 0xbe, 0x05); /* Set VComH Voltage */ ++ write_reg(par, 0xc1, 0xc8, 0x80, 0xc8); /* Set Contrast */ ++ write_reg(par, 0xc7, 0x0f); /* Set Master Contrast */ ++ write_reg(par, 0xb6, 0x01); /* Set Second Precharge Period */ ++ write_reg(par, 0xa6); /* Set Display Mode Reset */ ++ write_reg(par, 0xaf); /* Set Sleep Mode Display On */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ write_reg(par, 0x15, xs, xe); ++ write_reg(par, 0x75, ys, ye); ++ write_reg(par, 0x5c); ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ unsigned remap; ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ if (par->fbtftops.init_display != init_display) { ++ /* don't risk messing up register A0h */ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, ++ "%s: skipping since custom init_display() is used\n", ++ __func__); ++ return 0; ++ } ++ ++ remap = 0x60 | (par->bgr << 2); /* Set Colour Depth */ ++ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0xA0, remap | 0b00 | 1<<4); ++ break; ++ case 270: ++ write_reg(par, 0xA0, remap | 0b11 | 1<<4); ++ break; ++ case 180: ++ write_reg(par, 0xA0, remap | 0b10); ++ break; ++ case 90: ++ write_reg(par, 0xA0, remap | 0b01); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Grayscale Lookup Table ++ GS1 - GS63 ++ The driver Gamma curve contains the relative values between the entries ++ in the Lookup table. ++ ++ From datasheet: ++ 8.8 Gray Scale Decoder ++ ++ there are total 180 Gamma Settings (Setting 0 to Setting 180) ++ available for the Gray Scale table. ++ ++ The gray scale is defined in incremental way, with reference ++ to the length of previous table entry: ++ Setting of GS1 has to be >= 0 ++ Setting of GS2 has to be > Setting of GS1 +1 ++ Setting of GS3 has to be > Setting of GS2 +1 ++ : ++ Setting of GS63 has to be > Setting of GS62 +1 ++ ++ ++*/ ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ unsigned long tmp[GAMMA_NUM * GAMMA_LEN]; ++ int i, acc = 0; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ for (i = 0; i < 63; i++) { ++ if (i > 0 && curves[i] < 2) { ++ dev_err(par->info->device, ++ "Illegal value in Grayscale Lookup Table at index %d. " \ ++ "Must be greater than 1\n", i); ++ return -EINVAL; ++ } ++ acc += curves[i]; ++ tmp[i] = acc; ++ if (acc > 180) { ++ dev_err(par->info->device, ++ "Illegal value(s) in Grayscale Lookup Table. " \ ++ "At index=%d, the accumulated value has exceeded 180\n", i); ++ return -EINVAL; ++ } ++ } ++ ++ write_reg(par, 0xB8, ++ tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], ++ tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15], ++ tmp[16], tmp[17], tmp[18], tmp[19], tmp[20], tmp[21], tmp[22], tmp[23], ++ tmp[24], tmp[25], tmp[26], tmp[27], tmp[28], tmp[29], tmp[30], tmp[31], ++ tmp[32], tmp[33], tmp[34], tmp[35], tmp[36], tmp[37], tmp[38], tmp[39], ++ tmp[40], tmp[41], tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47], ++ tmp[48], tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55], ++ tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61], tmp[62]); ++ ++ return 0; ++} ++ ++static int blank(struct fbtft_par *par, bool on) ++{ ++ fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", ++ __func__, on ? "true" : "false"); ++ if (on) ++ write_reg(par, 0xAE); ++ else ++ write_reg(par, 0xAF); ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .gamma_num = GAMMA_NUM, ++ .gamma_len = GAMMA_LEN, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ .blank = blank, ++ }, ++}; ++ ++#ifdef CONFIG_FB_BACKLIGHT ++static int update_onboard_backlight(struct backlight_device *bd) ++{ ++ struct fbtft_par *par = bl_get_data(bd); ++ bool on; ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, ++ "%s: power=%d, fb_blank=%d\n", ++ __func__, bd->props.power, bd->props.fb_blank); ++ ++ on = (bd->props.power == FB_BLANK_UNBLANK) ++ && (bd->props.fb_blank == FB_BLANK_UNBLANK); ++ /* Onboard backlight connected to GPIO0 on SSD1351, GPIO1 unused */ ++ write_reg(par, 0xB5, on ? 0x03 : 0x02); ++ ++ return 0; ++} ++ ++static void register_onboard_backlight(struct fbtft_par *par) ++{ ++ struct backlight_device *bd; ++ struct backlight_properties bl_props = { 0, }; ++ struct backlight_ops *bl_ops; ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__); ++ ++ bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops), ++ GFP_KERNEL); ++ if (!bl_ops) { ++ dev_err(par->info->device, ++ "%s: could not allocate memory for backlight operations.\n", ++ __func__); ++ return; ++ } ++ ++ bl_ops->update_status = update_onboard_backlight; ++ bl_props.type = BACKLIGHT_RAW; ++ bl_props.power = FB_BLANK_POWERDOWN; ++ ++ bd = backlight_device_register(dev_driver_string(par->info->device), ++ par->info->device, par, bl_ops, &bl_props); ++ if (IS_ERR(bd)) { ++ dev_err(par->info->device, ++ "cannot register backlight device (%ld)\n", ++ PTR_ERR(bd)); ++ return; ++ } ++ par->info->bl_dev = bd; ++ ++ if (!par->fbtftops.unregister_backlight) ++ par->fbtftops.unregister_backlight = fbtft_unregister_backlight; ++} ++#else ++static void register_onboard_backlight(struct fbtft_par *par) { }; ++#endif ++ ++ ++FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1351", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:ssd1351"); ++MODULE_ALIAS("platform:ssd1351"); ++ ++MODULE_DESCRIPTION("SSD1351 OLED Driver"); ++MODULE_AUTHOR("James Davies"); ++MODULE_LICENSE("GPL"); + +From 113d538bde66bc0987ce4153e89ef1708cb48f3b Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:29 +0100 +Subject: [PATCH 145/178] staging: fbtft: add fb_st7735r driver + +This commit adds the fb_st7735r driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_st7735r.c | 195 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 202 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_st7735r.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 2ba8ef7..6bc2121 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -121,3 +121,9 @@ config FB_TFT_SSD1351 + depends on FB_TFT + help + Framebuffer support for SSD1351 ++ ++config FB_TFT_ST7735R ++ tristate "FB driver for the ST7735R LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for ST7735R +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 7481e34..2771e60 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -22,3 +22,4 @@ obj-$(CONFIG_FB_TFT_SSD1289) += fb_ssd1289.o + obj-$(CONFIG_FB_TFT_SSD1306) += fb_ssd1306.o + obj-$(CONFIG_FB_TFT_SSD1331) += fb_ssd1331.o + obj-$(CONFIG_FB_TFT_SSD1351) += fb_ssd1351.o ++obj-$(CONFIG_FB_TFT_ST7735R) += fb_st7735r.o +diff --git a/drivers/staging/fbtft/fb_st7735r.c b/drivers/staging/fbtft/fb_st7735r.c +new file mode 100644 +index 0000000..ea8f2b0 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_st7735r.c +@@ -0,0 +1,195 @@ ++/* ++ * FB driver for the ST7735R LCD Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_st7735r" ++#define DEFAULT_GAMMA "0F 1A 0F 18 2F 28 20 22 1F 1B 23 37 00 07 02 10\n" \ ++ "0F 1B 0F 17 33 2C 29 2E 30 30 39 3F 00 07 03 10" ++ ++ ++static int default_init_sequence[] = { ++ /* SWRESET - Software reset */ ++ -1, 0x01, ++ -2, 150, /* delay */ ++ ++ /* SLPOUT - Sleep out & booster on */ ++ -1, 0x11, ++ -2, 500, /* delay */ ++ ++ /* FRMCTR1 - frame rate control: normal mode ++ frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D) */ ++ -1, 0xB1, 0x01, 0x2C, 0x2D, ++ ++ /* FRMCTR2 - frame rate control: idle mode ++ frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D) */ ++ -1, 0xB2, 0x01, 0x2C, 0x2D, ++ ++ /* FRMCTR3 - frame rate control - partial mode ++ dot inversion mode, line inversion mode */ ++ -1, 0xB3, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D, ++ ++ /* INVCTR - display inversion control ++ no inversion */ ++ -1, 0xB4, 0x07, ++ ++ /* PWCTR1 - Power Control ++ -4.6V, AUTO mode */ ++ -1, 0xC0, 0xA2, 0x02, 0x84, ++ ++ /* PWCTR2 - Power Control ++ VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD */ ++ -1, 0xC1, 0xC5, ++ ++ /* PWCTR3 - Power Control ++ Opamp current small, Boost frequency */ ++ -1, 0xC2, 0x0A, 0x00, ++ ++ /* PWCTR4 - Power Control ++ BCLK/2, Opamp current small & Medium low */ ++ -1, 0xC3,0x8A,0x2A, ++ ++ /* PWCTR5 - Power Control */ ++ -1, 0xC4, 0x8A, 0xEE, ++ ++ /* VMCTR1 - Power Control */ ++ -1, 0xC5, 0x0E, ++ ++ /* INVOFF - Display inversion off */ ++ -1, 0x20, ++ ++ /* COLMOD - Interface pixel format */ ++ -1, 0x3A, 0x05, ++ ++ /* DISPON - Display On */ ++ -1, 0x29, ++ -2, 100, /* delay */ ++ ++ /* NORON - Partial off (Normal) */ ++ -1, 0x13, ++ -2, 10, /* delay */ ++ ++ /* end marker */ ++ -3 ++}; ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address */ ++ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); ++ ++ /* Row adress */ ++ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++#define MY (1 << 7) ++#define MX (1 << 6) ++#define MV (1 << 5) ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* MADCTL - Memory data access control ++ RGB/BGR: ++ 1. Mode selection pin SRGB ++ RGB H/W pin for color filter setting: 0=RGB, 1=BGR ++ 2. MADCTL RGB bit ++ RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR */ ++ switch (par->info->var.rotate) { ++ case 0: ++ write_reg(par, 0x36, MX | MY | (par->bgr << 3)); ++ break; ++ case 270: ++ write_reg(par, 0x36, MY | MV | (par->bgr << 3)); ++ break; ++ case 180: ++ write_reg(par, 0x36, (par->bgr << 3)); ++ break; ++ case 90: ++ write_reg(par, 0x36, MX | MV | (par->bgr << 3)); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ Gamma string format: ++ VRF0P VOS0P PK0P PK1P PK2P PK3P PK4P PK5P PK6P PK7P PK8P PK9P SELV0P SELV1P SELV62P SELV63P ++ VRF0N VOS0N PK0N PK1N PK2N PK3N PK4N PK5N PK6N PK7N PK8N PK9N SELV0N SELV1N SELV62N SELV63N ++*/ ++#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ int i,j; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ for (i = 0; i < par->gamma.num_curves; i++) ++ for (j = 0; j < par->gamma.num_values; j++) ++ CURVE(i,j) &= 0b111111; ++ ++ for (i = 0; i < par->gamma.num_curves; i++) ++ write_reg(par, 0xE0 + i, ++ CURVE(i, 0), CURVE(i, 1), CURVE(i, 2), CURVE(i, 3), ++ CURVE(i, 4), CURVE(i, 5), CURVE(i, 6), CURVE(i, 7), ++ CURVE(i, 8), CURVE(i, 9), CURVE(i, 10), CURVE(i, 11), ++ CURVE(i, 12), CURVE(i, 13), CURVE(i, 14), CURVE(i,15)); ++ ++ return 0; ++} ++#undef CURVE ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = 128, ++ .height = 160, ++ .init_sequence = default_init_sequence, ++ .gamma_num = 2, ++ .gamma_len = 16, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .set_gamma = set_gamma, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7735r", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:st7735r"); ++MODULE_ALIAS("platform:st7735r"); ++ ++MODULE_DESCRIPTION("FB driver for the ST7735R LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From f32722f8fb2533655104f2e066e5f08c5e485d5f Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:30 +0100 +Subject: [PATCH 146/178] staging: fbtft: add fb_tinylcd driver + +This commit adds the fb_tinylcd driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_tinylcd.c | 124 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 131 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_tinylcd.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 6bc2121..dd740bfb 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -127,3 +127,9 @@ config FB_TFT_ST7735R + depends on FB_TFT + help + Generic Framebuffer support for ST7735R ++ ++config FB_TFT_TINYLCD ++ tristate "FB driver for tinylcd.com display" ++ depends on FB_TFT ++ help ++ Custom Framebuffer support for tinylcd.com display +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 2771e60..a5c2d15 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -23,3 +23,4 @@ obj-$(CONFIG_FB_TFT_SSD1306) += fb_ssd1306.o + obj-$(CONFIG_FB_TFT_SSD1331) += fb_ssd1331.o + obj-$(CONFIG_FB_TFT_SSD1351) += fb_ssd1351.o + obj-$(CONFIG_FB_TFT_ST7735R) += fb_st7735r.o ++obj-$(CONFIG_FB_TFT_TINYLCD) += fb_tinylcd.o +diff --git a/drivers/staging/fbtft/fb_tinylcd.c b/drivers/staging/fbtft/fb_tinylcd.c +new file mode 100644 +index 0000000..ca98bfb +--- /dev/null ++++ b/drivers/staging/fbtft/fb_tinylcd.c +@@ -0,0 +1,124 @@ ++/* ++ * Custom FB driver for tinylcd.com display ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_tinylcd" ++#define WIDTH 320 ++#define HEIGHT 480 ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ write_reg(par, 0xB0, 0x80); ++ write_reg(par, 0xC0, 0x0A, 0x0A); ++ write_reg(par, 0xC1, 0x45, 0x07); ++ write_reg(par, 0xC2, 0x33); ++ write_reg(par, 0xC5, 0x00, 0x42, 0x80); ++ write_reg(par, 0xB1, 0xD0, 0x11); ++ write_reg(par, 0xB4, 0x02); ++ write_reg(par, 0xB6, 0x00, 0x22, 0x3B); ++ write_reg(par, 0xB7, 0x07); ++ write_reg(par, 0x36, 0x58); ++ write_reg(par, 0xF0, 0x36, 0xA5, 0xD3); ++ write_reg(par, 0xE5, 0x80); ++ write_reg(par, 0xE5, 0x01); ++ write_reg(par, 0xB3, 0x00); ++ write_reg(par, 0xE5, 0x00); ++ write_reg(par, 0xF0, 0x36, 0xA5, 0x53); ++ write_reg(par, 0xE0, 0x00, 0x35, 0x33, 0x00, 0x00, 0x00, ++ 0x00, 0x35, 0x33, 0x00, 0x00, 0x00); ++ write_reg(par, 0x3A, 0x55); ++ write_reg(par, 0x11); ++ udelay(250); ++ write_reg(par, 0x29); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* Column address */ ++ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); ++ ++ /* Row adress */ ++ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); ++ ++ /* Memory write */ ++ write_reg(par, 0x2C); ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ case 270: ++ write_reg(par, 0xB6, 0x00, 0x02, 0x3B); ++ write_reg(par, 0x36, 0x28); ++ break; ++ case 180: ++ write_reg(par, 0xB6, 0x00, 0x22, 0x3B); ++ write_reg(par, 0x36, 0x58); ++ break; ++ case 90: ++ write_reg(par, 0xB6, 0x00, 0x22, 0x3B); ++ write_reg(par, 0x36, 0x38); ++ break; ++ default: ++ write_reg(par, 0xB6, 0x00, 0x22, 0x3B); ++ write_reg(par, 0x36, 0x08); ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "neosec,tinylcd", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("spi:tinylcd"); ++ ++MODULE_DESCRIPTION("Custom FB driver for tinylcd.com display"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From 53ab604b2f4eadacc5020685e8de8478fc3149c8 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:31 +0100 +Subject: [PATCH 147/178] staging: fbtft: add fb_tls8204 driver + +This commit adds the fb_tls8204 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_tls8204.c | 176 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 183 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_tls8204.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index dd740bfb..73c181c 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -133,3 +133,9 @@ config FB_TFT_TINYLCD + depends on FB_TFT + help + Custom Framebuffer support for tinylcd.com display ++ ++config FB_TFT_TLS8204 ++ tristate "FB driver for the TLS8204 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for TLS8204 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index a5c2d15..5fa20f0 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -24,3 +24,4 @@ obj-$(CONFIG_FB_TFT_SSD1331) += fb_ssd1331.o + obj-$(CONFIG_FB_TFT_SSD1351) += fb_ssd1351.o + obj-$(CONFIG_FB_TFT_ST7735R) += fb_st7735r.o + obj-$(CONFIG_FB_TFT_TINYLCD) += fb_tinylcd.o ++obj-$(CONFIG_FB_TFT_TLS8204) += fb_tls8204.o +diff --git a/drivers/staging/fbtft/fb_tls8204.c b/drivers/staging/fbtft/fb_tls8204.c +new file mode 100644 +index 0000000..8738c7a +--- /dev/null ++++ b/drivers/staging/fbtft/fb_tls8204.c +@@ -0,0 +1,176 @@ ++/* ++ * FB driver for the TLS8204 LCD Controller ++ * ++ * The display is monochrome and the video memory is RGB565. ++ * Any pixel value except 0 turns the pixel on. ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * Copyright (C) 2014 Michael Hope (adapted for the TLS8204) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_tls8204" ++#define WIDTH 84 ++#define HEIGHT 48 ++#define TXBUFLEN WIDTH ++#define DEFAULT_GAMMA "40" /* gamma is used to control contrast in this driver */ ++ ++static unsigned bs = 4; ++module_param(bs, uint, 0); ++MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)"); ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ /* Enter extended command mode */ ++ write_reg(par, 0x21); /* 5:1 1 ++ 2:0 PD - Powerdown control: chip is active ++ 1:0 V - Entry mode: horizontal addressing ++ 0:1 H - Extended instruction set control: extended ++ */ ++ ++ /* H=1 Bias system */ ++ write_reg(par, 0x10 | (bs & 0x7)); /* ++ 4:1 1 ++ 3:0 0 ++ 2:x BS2 - Bias System ++ 1:x BS1 ++ 0:x BS0 ++ */ ++ ++ /* Set the address of the first display line. */ ++ write_reg(par, 0x04 | (64 >> 6)); ++ write_reg(par, 0x40 | (64 & 0x3F)); ++ ++ /* Enter H=0 standard command mode */ ++ write_reg(par, 0x20); ++ ++ /* H=0 Display control */ ++ write_reg(par, 0x08 | 4); /* ++ 3:1 1 ++ 2:1 D - DE: 10=normal mode ++ 1:0 0 ++ 0:0 E ++ */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* H=0 Set X address of RAM */ ++ write_reg(par, 0x80); /* 7:1 1 ++ 6-0: X[6:0] - 0x00 ++ */ ++ ++ /* H=0 Set Y address of RAM */ ++ write_reg(par, 0x40); /* 7:0 0 ++ 6:1 1 ++ 2-0: Y[2:0] - 0x0 ++ */ ++} ++ ++static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16 = (u16 *)par->info->screen_base; ++ int x, y, i; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ for (y = 0; y < HEIGHT/8; y++) { ++ u8 *buf = par->txbuf.buf; ++ /* The display is 102x68 but the LCD is 84x48. Set ++ the write pointer at the start of each row. */ ++ gpio_set_value(par->gpio.dc, 0); ++ write_reg(par, 0x80 | 0); ++ write_reg(par, 0x40 | y); ++ ++ for (x = 0; x < WIDTH; x++) { ++ u8 ch = 0; ++ for (i = 0; i < 8*WIDTH; i += WIDTH) { ++ ch >>= 1; ++ if (vmem16[(y*8*WIDTH)+i+x]) ++ ch |= 0x80; ++ } ++ *buf++ = ch; ++ } ++ /* Write the row */ ++ gpio_set_value(par->gpio.dc, 1); ++ ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH); ++ if (ret < 0) { ++ dev_err(par->info->device, ++ "%s: write failed and returned: %d\n", __func__, ret); ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++static int set_gamma(struct fbtft_par *par, unsigned long *curves) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* apply mask */ ++ curves[0] &= 0x7F; ++ ++ write_reg(par, 0x21); /* turn on extended instruction set */ ++ write_reg(par, 0x80 | curves[0]); ++ write_reg(par, 0x20); /* turn off extended instruction set */ ++ ++ return 0; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .txbuflen = TXBUFLEN, ++ .gamma_num = 1, ++ .gamma_len = 1, ++ .gamma = DEFAULT_GAMMA, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .write_vmem = write_vmem, ++ .set_gamma = set_gamma, ++ }, ++ .backlight = 1, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "teralane,tls8204", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("spi:tls8204"); ++ ++MODULE_DESCRIPTION("FB driver for the TLS8204 LCD Controller"); ++MODULE_AUTHOR("Michael Hope"); ++MODULE_LICENSE("GPL"); + +From ea4a91f4431edcd197d8b9ee68d8dc771216582f Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:32 +0100 +Subject: [PATCH 148/178] staging: fbtft: add fb_uc1701 driver + +This commit adds the fb_uc1701 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 ++ + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_uc1701.c | 210 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 217 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_uc1701.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 73c181c..fb3f4df 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -139,3 +139,9 @@ config FB_TFT_TLS8204 + depends on FB_TFT + help + Generic Framebuffer support for TLS8204 ++ ++config FB_TFT_UC1701 ++ tristate "FB driver for the UC1701 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for UC1701 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 5fa20f0..732b219 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -25,3 +25,4 @@ obj-$(CONFIG_FB_TFT_SSD1351) += fb_ssd1351.o + obj-$(CONFIG_FB_TFT_ST7735R) += fb_st7735r.o + obj-$(CONFIG_FB_TFT_TINYLCD) += fb_tinylcd.o + obj-$(CONFIG_FB_TFT_TLS8204) += fb_tls8204.o ++obj-$(CONFIG_FB_TFT_UC1701) += fb_uc1701.o +diff --git a/drivers/staging/fbtft/fb_uc1701.c b/drivers/staging/fbtft/fb_uc1701.c +new file mode 100644 +index 0000000..d70ac52 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_uc1701.c +@@ -0,0 +1,210 @@ ++/* ++ * FB driver for the UC1701 LCD Controller ++ * ++ * The display is monochrome and the video memory is RGB565. ++ * Any pixel value except 0 turns the pixel on. ++ * ++ * Copyright (C) 2014 Juergen Holzmann ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_uc1701" ++#define WIDTH 102 ++#define HEIGHT 64 ++#define PAGES (HEIGHT/8) ++ ++/* 1: Display on/off */ ++#define LCD_DISPLAY_ENABLE 0xAE ++/* 2: display start line set */ ++#define LCD_START_LINE 0x40 ++/* 3: Page address set (lower 4 bits select one of the pages) */ ++#define LCD_PAGE_ADDRESS 0xB0 ++/* 4: column address */ ++#define LCD_COL_ADDRESS 0x10 ++/* 8: select orientation */ ++#define LCD_BOTTOMVIEW 0xA0 ++/* 9: inverted display */ ++#define LCD_DISPLAY_INVERT 0xA6 ++/* 10: show memory content or switch all pixels on */ ++#define LCD_ALL_PIXEL 0xA4 ++/* 11: lcd bias set */ ++#define LCD_BIAS 0xA2 ++/* 14: Reset Controller */ ++#define LCD_RESET_CMD 0xE2 ++/* 15: output mode select (turns display upside-down) */ ++#define LCD_SCAN_DIR 0xC0 ++/* 16: power control set */ ++#define LCD_POWER_CONTROL 0x28 ++/* 17: voltage regulator resistor ratio set */ ++#define LCD_VOLTAGE 0x20 ++/* 18: Volume mode set */ ++#define LCD_VOLUME_MODE 0x81 ++/* 22: NOP command */ ++#define LCD_NO_OP 0xE3 ++/* 25: advanced program control */ ++#define LCD_ADV_PROG_CTRL 0xFA ++/* 25: advanced program control2 */ ++#define LCD_ADV_PROG_CTRL2 0x10 ++#define LCD_TEMPCOMP_HIGH 0x80 ++/* column offset for normal orientation */ ++#define SHIFT_ADDR_NORMAL 0 ++/* column offset for bottom view orientation */ ++#define SHIFT_ADDR_TOPVIEW 30 ++ ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ /* softreset of LCD */ ++ write_reg(par, LCD_RESET_CMD); ++ mdelay(10); ++ ++ /* set startpoint */ ++ /* LCD_START_LINE | (pos & 0x3F) */ ++ write_reg(par, LCD_START_LINE); ++ ++ /* select orientation BOTTOMVIEW */ ++ write_reg(par, LCD_BOTTOMVIEW | 1); ++ /* output mode select (turns display upside-down) */ ++ write_reg(par, LCD_SCAN_DIR | 0x00); ++ ++ /* Normal Pixel mode */ ++ write_reg(par, LCD_ALL_PIXEL | 0); ++ ++ /* positive display */ ++ write_reg(par, LCD_DISPLAY_INVERT | 0); ++ ++ /* bias 1/9 */ ++ write_reg(par, LCD_BIAS | 0); ++ ++ /* power control mode: all features on */ ++ /* LCD_POWER_CONTROL | (val&0x07) */ ++ write_reg(par, LCD_POWER_CONTROL | 0x07); ++ ++ /* set voltage regulator R/R */ ++ /* LCD_VOLTAGE | (val&0x07) */ ++ write_reg(par, LCD_VOLTAGE | 0x07); ++ ++ /* volume mode set */ ++ /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */ ++ write_reg(par, LCD_VOLUME_MODE); ++ /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */ ++ write_reg(par, 0x09); ++ /* ???? */ ++ /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */ ++ write_reg(par, LCD_NO_OP); ++ ++ /* advanced program control */ ++ write_reg(par, LCD_ADV_PROG_CTRL); ++ write_reg(par, LCD_ADV_PROG_CTRL2|LCD_TEMPCOMP_HIGH); ++ ++ /* enable display */ ++ write_reg(par, LCD_DISPLAY_ENABLE | 1); ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ /* goto address */ ++ /* LCD_PAGE_ADDRESS | ((page) & 0x1F), ++ (((col)+SHIFT_ADDR_NORMAL) & 0x0F), ++ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ ++ write_reg(par, LCD_PAGE_ADDRESS); ++ /* LCD_PAGE_ADDRESS | ((page) & 0x1F), ++ (((col)+SHIFT_ADDR_NORMAL) & 0x0F), ++ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ ++ write_reg(par, 0x00); ++ /* LCD_PAGE_ADDRESS | ((page) & 0x1F), ++ (((col)+SHIFT_ADDR_NORMAL) & 0x0F), ++ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ ++ write_reg(par, LCD_COL_ADDRESS); ++} ++ ++static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ u16 *vmem16 = (u16 *)par->info->screen_base; ++ u8 *buf = par->txbuf.buf; ++ int x, y, i; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ for (y = 0; y < PAGES; y++) { ++ buf = par->txbuf.buf; ++ for (x = 0; x < WIDTH; x++) { ++ *buf = 0x00; ++ for (i = 0; i < 8; i++) ++ *buf |= (vmem16[((y*8*WIDTH)+(i*WIDTH))+x] ? 1 : 0) << i; ++ buf++; ++ } ++ /* LCD_PAGE_ADDRESS | ((page) & 0x1F), ++ (((col)+SHIFT_ADDR_NORMAL) & 0x0F), ++ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ ++ write_reg(par, LCD_PAGE_ADDRESS|(u8)y); ++ /* LCD_PAGE_ADDRESS | ((page) & 0x1F), ++ (((col)+SHIFT_ADDR_NORMAL) & 0x0F), ++ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ ++ write_reg(par, 0x00); ++ /* LCD_PAGE_ADDRESS | ((page) & 0x1F), ++ (((col)+SHIFT_ADDR_NORMAL) & 0x0F), ++ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ ++ write_reg(par, LCD_COL_ADDRESS); ++ gpio_set_value(par->gpio.dc, 1); ++ ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH); ++ gpio_set_value(par->gpio.dc, 0); ++ } ++ ++ if (ret < 0) ++ dev_err(par->info->device, "%s: write failed and returned: %d\n", __func__, ret); ++ ++ return ret; ++} ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .write_vmem = write_vmem, ++ }, ++ .backlight = 1, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "UltraChip,uc1701", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("spi:uc1701"); ++ ++MODULE_DESCRIPTION("FB driver for the UC1701 LCD Controller"); ++MODULE_AUTHOR("Juergen Holzmann"); ++MODULE_LICENSE("GPL"); + +From e3a62d477914b251ba09d1ac5fdf6be3ad85e473 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:33 +0100 +Subject: [PATCH 149/178] staging: fbtft: add fb_upd161704 driver + +This commit adds the fb_upd161704 driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 + + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_upd161704.c | 206 +++++++++++++++++++++++++++++++++++ + 3 files changed, 213 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_upd161704.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index fb3f4df..886a48c 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -145,3 +145,9 @@ config FB_TFT_UC1701 + depends on FB_TFT + help + Generic Framebuffer support for UC1701 ++ ++config FB_TFT_UPD161704 ++ tristate "FB driver for the uPD161704 LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for uPD161704 +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 732b219..dca2a45 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -26,3 +26,4 @@ obj-$(CONFIG_FB_TFT_ST7735R) += fb_st7735r.o + obj-$(CONFIG_FB_TFT_TINYLCD) += fb_tinylcd.o + obj-$(CONFIG_FB_TFT_TLS8204) += fb_tls8204.o + obj-$(CONFIG_FB_TFT_UC1701) += fb_uc1701.o ++obj-$(CONFIG_FB_TFT_UPD161704) += fb_upd161704.o +diff --git a/drivers/staging/fbtft/fb_upd161704.c b/drivers/staging/fbtft/fb_upd161704.c +new file mode 100644 +index 0000000..8d7794e +--- /dev/null ++++ b/drivers/staging/fbtft/fb_upd161704.c +@@ -0,0 +1,206 @@ ++/* ++ * FB driver for the uPD161704 LCD Controller ++ * ++ * Copyright (C) 2014 Seong-Woo Kim ++ * ++ * Based on fb_ili9325.c by Noralf Tronnes ++ * Based on ili9325.c by Jeroen Domburg ++ * Init code from UTFT library by Henning Karlsen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_upd161704" ++#define WIDTH 240 ++#define HEIGHT 320 ++#define BPP 16 ++ ++static int init_display(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ par->fbtftops.reset(par); ++ ++ if (par->gpio.cs != -1) ++ gpio_set_value(par->gpio.cs, 0); /* Activate chip */ ++ ++ /* Initialization sequence from Lib_UTFT */ ++ ++ /* register reset */ ++ write_reg(par, 0x0003,0x0001); /* Soft reset */ ++ ++ /* oscillator start */ ++ write_reg(par, 0x003A,0x0001); /*Oscillator 0: stop, 1: operation */ ++ udelay(100); ++ ++ /* y-setting */ ++ write_reg(par, 0x0024,0x007B); /* amplitude setting */ ++ udelay(10); ++ write_reg(par, 0x0025,0x003B); /* amplitude setting */ ++ write_reg(par, 0x0026,0x0034); /* amplitude setting */ ++ udelay(10); ++ write_reg(par, 0x0027,0x0004); /* amplitude setting */ ++ write_reg(par, 0x0052,0x0025); /* circuit setting 1 */ ++ udelay(10); ++ write_reg(par, 0x0053,0x0033); /* circuit setting 2 */ ++ write_reg(par, 0x0061,0x001C); /* adjustment V10 positive polarity */ ++ udelay(10); ++ write_reg(par, 0x0062,0x002C); /* adjustment V9 negative polarity */ ++ write_reg(par, 0x0063,0x0022); /* adjustment V34 positive polarity */ ++ udelay(10); ++ write_reg(par, 0x0064,0x0027); /* adjustment V31 negative polarity */ ++ udelay(10); ++ write_reg(par, 0x0065,0x0014); /* adjustment V61 negative polarity */ ++ udelay(10); ++ write_reg(par, 0x0066,0x0010); /* adjustment V61 negative polarity */ ++ ++ /* Basical clock for 1 line (BASECOUNT[7:0]) number specified */ ++ write_reg(par, 0x002E,0x002D); ++ ++ /* Power supply setting */ ++ write_reg(par, 0x0019,0x0000); /* DC/DC output setting */ ++ udelay(200); ++ write_reg(par, 0x001A,0x1000); /* DC/DC frequency setting */ ++ write_reg(par, 0x001B,0x0023); /* DC/DC rising setting */ ++ write_reg(par, 0x001C,0x0C01); /* Regulator voltage setting */ ++ write_reg(par, 0x001D,0x0000); /* Regulator current setting */ ++ write_reg(par, 0x001E,0x0009); /* VCOM output setting */ ++ write_reg(par, 0x001F,0x0035); /* VCOM amplitude setting */ ++ write_reg(par, 0x0020,0x0015); /* VCOMM cencter setting */ ++ write_reg(par, 0x0018,0x1E7B); /* DC/DC operation setting */ ++ ++ /* windows setting */ ++ write_reg(par, 0x0008,0x0000); /* Minimum X address */ ++ write_reg(par, 0x0009,0x00EF); /* Maximum X address */ ++ write_reg(par, 0x000a,0x0000); /* Minimum Y address */ ++ write_reg(par, 0x000b,0x013F); /* Maximum Y address */ ++ ++ /* LCD display area setting */ ++ write_reg(par, 0x0029,0x0000); /* [LCDSIZE] X MIN. size set */ ++ write_reg(par, 0x002A,0x0000); /* [LCDSIZE] Y MIN. size set */ ++ write_reg(par, 0x002B,0x00EF); /* [LCDSIZE] X MAX. size set */ ++ write_reg(par, 0x002C,0x013F); /* [LCDSIZE] Y MAX. size set */ ++ ++ /* Gate scan setting */ ++ write_reg(par, 0x0032,0x0002); ++ ++ /* n line inversion line number */ ++ write_reg(par, 0x0033,0x0000); ++ ++ /* Line inversion/frame inversion/interlace setting */ ++ write_reg(par, 0x0037,0x0000); ++ ++ /* Gate scan operation setting register */ ++ write_reg(par, 0x003B,0x0001); ++ ++ /* Color mode */ ++ /*GS = 0: 260-k color (64 gray scale), GS = 1: 8 color (2 gray scale) */ ++ write_reg(par, 0x0004,0x0000); ++ ++ /* RAM control register */ ++ write_reg(par, 0x0005,0x0000); /*Window access 00:Normal, 10:Window */ ++ ++ /* Display setting register 2 */ ++ write_reg(par, 0x0001,0x0000); ++ ++ /* display setting */ ++ write_reg(par, 0x0000,0x0000); /* display on */ ++ ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ switch (par->info->var.rotate) { ++ /* R20h = Horizontal GRAM Start Address */ ++ /* R21h = Vertical GRAM Start Address */ ++ case 0: ++ write_reg(par, 0x0006, xs); ++ write_reg(par, 0x0007, ys); ++ break; ++ case 180: ++ write_reg(par, 0x0006, WIDTH - 1 - xs); ++ write_reg(par, 0x0007, HEIGHT - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x0006, WIDTH - 1 - ys); ++ write_reg(par, 0x0007, xs); ++ break; ++ case 90: ++ write_reg(par, 0x0006, ys); ++ write_reg(par, 0x0007, HEIGHT - 1 - xs); ++ break; ++ } ++ ++ write_reg(par, 0x0e); /* Write Data to GRAM */ ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ switch (par->info->var.rotate) { ++ /* AM: GRAM update direction */ ++ case 0: ++ write_reg(par, 0x01, 0x0000); ++ write_reg(par, 0x05, 0x0000); ++ break; ++ case 180: ++ write_reg(par, 0x01, 0x00C0); ++ write_reg(par, 0x05, 0x0000); ++ break; ++ case 270: ++ write_reg(par, 0x01, 0x0080); ++ write_reg(par, 0x05, 0x0001); ++ break; ++ case 90: ++ write_reg(par, 0x01, 0x0040); ++ write_reg(par, 0x05, 0x0001); ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct fbtft_display display = { ++ .regwidth = 16, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .fbtftops = { ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "nec,upd161704", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++MODULE_ALIAS("platform:" DRVNAME); ++MODULE_ALIAS("spi:upd161704"); ++MODULE_ALIAS("platform:upd161704"); ++ ++MODULE_DESCRIPTION("FB driver for the uPD161704 LCD Controller"); ++MODULE_AUTHOR("Seong-Woo Kim"); ++MODULE_LICENSE("GPL"); + +From 287214c19eb6be32eabcb5e79fad95265043f5d6 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:34 +0100 +Subject: [PATCH 150/178] staging: fbtft: add fb_watterott driver + +This commit adds the fb_watterott driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 + + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/fb_watterott.c | 324 +++++++++++++++++++++++++++++++++++ + 3 files changed, 331 insertions(+) + create mode 100644 drivers/staging/fbtft/fb_watterott.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 886a48c..8edec90 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -151,3 +151,9 @@ config FB_TFT_UPD161704 + depends on FB_TFT + help + Generic Framebuffer support for uPD161704 ++ ++config FB_TFT_WATTEROTT ++ tristate "FB driver for the WATTEROTT LCD Controller" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for WATTEROTT +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index dca2a45..78008c3 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -27,3 +27,4 @@ obj-$(CONFIG_FB_TFT_TINYLCD) += fb_tinylcd.o + obj-$(CONFIG_FB_TFT_TLS8204) += fb_tls8204.o + obj-$(CONFIG_FB_TFT_UC1701) += fb_uc1701.o + obj-$(CONFIG_FB_TFT_UPD161704) += fb_upd161704.o ++obj-$(CONFIG_FB_TFT_WATTEROTT) += fb_watterott.o +diff --git a/drivers/staging/fbtft/fb_watterott.c b/drivers/staging/fbtft/fb_watterott.c +new file mode 100644 +index 0000000..975b579 +--- /dev/null ++++ b/drivers/staging/fbtft/fb_watterott.c +@@ -0,0 +1,324 @@ ++/* ++ * FB driver for the Watterott LCD Controller ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fb_watterott" ++#define WIDTH 320 ++#define HEIGHT 240 ++#define FPS 5 ++#define TXBUFLEN 1024 ++#define DEFAULT_BRIGHTNESS 50 ++ ++#define CMD_VERSION 0x01 ++#define CMD_LCD_LED 0x10 ++#define CMD_LCD_RESET 0x11 ++#define CMD_LCD_ORIENTATION 0x20 ++#define CMD_LCD_DRAWIMAGE 0x27 ++#define COLOR_RGB323 8 ++#define COLOR_RGB332 9 ++#define COLOR_RGB233 10 ++#define COLOR_RGB565 16 ++ ++ ++static short mode = 565; ++module_param(mode, short, 0); ++MODULE_PARM_DESC(mode, "RGB color transfer mode: 332, 565 (default)"); ++ ++static void write_reg8_bus8(struct fbtft_par *par, int len, ...) ++{ ++ va_list args; ++ int i, ret; ++ u8 *buf = par->buf; ++ ++ va_start(args, len); ++ for (i = 0; i < len; i++) ++ *buf++ = (u8)va_arg(args, unsigned int); ++ va_end(args); ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, ++ par->info->device, u8, par->buf, len, "%s: ", __func__); ++ ++ ret = par->fbtftops.write(par, par->buf, len); ++ if (ret < 0) { ++ dev_err(par->info->device, ++ "%s: write() failed and returned %d\n", __func__, ret); ++ return; ++ } ++} ++ ++static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ unsigned start_line, end_line; ++ u16 *vmem16 = (u16 *)(par->info->screen_base + offset); ++ u16 *pos = par->txbuf.buf + 1; ++ u16 *buf16 = par->txbuf.buf + 10; ++ int i, j; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ start_line = offset / par->info->fix.line_length; ++ end_line = start_line + (len / par->info->fix.line_length) - 1; ++ ++ /* Set command header. pos: x, y, w, h */ ++ ((u8 *)par->txbuf.buf)[0] = CMD_LCD_DRAWIMAGE; ++ pos[0] = 0; ++ pos[2] = cpu_to_be16(par->info->var.xres); ++ pos[3] = cpu_to_be16(1); ++ ((u8 *)par->txbuf.buf)[9] = COLOR_RGB565; ++ ++ for (i = start_line; i <= end_line; i++) { ++ pos[1] = cpu_to_be16(i); ++ for (j = 0; j < par->info->var.xres; j++) ++ buf16[j] = cpu_to_be16(*vmem16++); ++ ret = par->fbtftops.write(par, ++ par->txbuf.buf, 10 + par->info->fix.line_length); ++ if (ret < 0) ++ return ret; ++ udelay(300); ++ } ++ ++ return 0; ++} ++ ++#define RGB565toRGB323(c) (((c&0xE000)>>8) | ((c&0600)>>6) | ((c&0x001C)>>2)) ++#define RGB565toRGB332(c) (((c&0xE000)>>8) | ((c&0700)>>6) | ((c&0x0018)>>3)) ++#define RGB565toRGB233(c) (((c&0xC000)>>8) | ((c&0700)>>5) | ((c&0x001C)>>2)) ++ ++static int write_vmem_8bit(struct fbtft_par *par, size_t offset, size_t len) ++{ ++ unsigned start_line, end_line; ++ u16 *vmem16 = (u16 *)(par->info->screen_base + offset); ++ u16 *pos = par->txbuf.buf + 1; ++ u8 *buf8 = par->txbuf.buf + 10; ++ int i, j; ++ int ret = 0; ++ ++ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); ++ ++ start_line = offset / par->info->fix.line_length; ++ end_line = start_line + (len / par->info->fix.line_length) - 1; ++ ++ /* Set command header. pos: x, y, w, h */ ++ ((u8 *)par->txbuf.buf)[0] = CMD_LCD_DRAWIMAGE; ++ pos[0] = 0; ++ pos[2] = cpu_to_be16(par->info->var.xres); ++ pos[3] = cpu_to_be16(1); ++ ((u8 *)par->txbuf.buf)[9] = COLOR_RGB332; ++ ++ for (i = start_line; i <= end_line; i++) { ++ pos[1] = cpu_to_be16(i); ++ for (j = 0; j < par->info->var.xres; j++) { ++ buf8[j] = RGB565toRGB332(*vmem16); ++ vmem16++; ++ } ++ ret = par->fbtftops.write(par, ++ par->txbuf.buf, 10 + par->info->var.xres); ++ if (ret < 0) ++ return ret; ++ udelay(700); ++ } ++ ++ return 0; ++} ++ ++static unsigned firmware_version(struct fbtft_par *par) ++{ ++ u8 rxbuf[4] = {0, }; ++ ++ write_reg(par, CMD_VERSION); ++ par->fbtftops.read(par, rxbuf, 4); ++ if (rxbuf[1] != '.') ++ return 0; ++ ++ return (rxbuf[0] - '0') << 8 | (rxbuf[2] - '0') << 4 | (rxbuf[3] - '0'); ++} ++ ++static int init_display(struct fbtft_par *par) ++{ ++ int ret; ++ unsigned version; ++ u8 save_mode; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* enable SPI interface by having CS and MOSI low during reset */ ++ save_mode = par->spi->mode; ++ par->spi->mode |= SPI_CS_HIGH; ++ ret = par->spi->master->setup(par->spi); /* set CS inactive low */ ++ if (ret) { ++ dev_err(par->info->device, "Could not set SPI_CS_HIGH\n"); ++ return ret; ++ } ++ write_reg(par, 0x00); /* make sure mode is set */ ++ ++ mdelay(50); ++ par->fbtftops.reset(par); ++ mdelay(1000); ++ par->spi->mode = save_mode; ++ ret = par->spi->master->setup(par->spi); ++ if (ret) { ++ dev_err(par->info->device, "Could not restore SPI mode\n"); ++ return ret; ++ } ++ write_reg(par, 0x00); ++ ++ version = firmware_version(par); ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "Firmware version: %x.%02x\n", ++ version >> 8, version & 0xFF); ++ ++ if (mode == 332) ++ par->fbtftops.write_vmem = write_vmem_8bit; ++ return 0; ++} ++ ++static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ /* not used on this controller */ ++} ++ ++static int set_var(struct fbtft_par *par) ++{ ++ u8 rotate; ++ ++ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); ++ ++ /* this controller rotates clock wise */ ++ switch (par->info->var.rotate) { ++ case 90: ++ rotate = 27; ++ break; ++ case 180: ++ rotate = 18; ++ break; ++ case 270: ++ rotate = 9; ++ break; ++ default: ++ rotate = 0; ++ } ++ write_reg(par, CMD_LCD_ORIENTATION, rotate); ++ ++ return 0; ++} ++ ++static int verify_gpios(struct fbtft_par *par) ++{ ++ if (par->gpio.reset < 0) { ++ dev_err(par->info->device, "Missing 'reset' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_FB_BACKLIGHT ++static int backlight_chip_update_status(struct backlight_device *bd) ++{ ++ struct fbtft_par *par = bl_get_data(bd); ++ int brightness = bd->props.brightness; ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, ++ "%s: brightness=%d, power=%d, fb_blank=%d\n", ++ __func__, bd->props.brightness, bd->props.power, ++ bd->props.fb_blank); ++ ++ if (bd->props.power != FB_BLANK_UNBLANK) ++ brightness = 0; ++ ++ if (bd->props.fb_blank != FB_BLANK_UNBLANK) ++ brightness = 0; ++ ++ write_reg(par, CMD_LCD_LED, brightness); ++ ++ return 0; ++} ++ ++static void register_chip_backlight(struct fbtft_par *par) ++{ ++ struct backlight_device *bd; ++ struct backlight_properties bl_props = { 0, }; ++ struct backlight_ops *bl_ops; ++ ++ fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__); ++ ++ bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops), ++ GFP_KERNEL); ++ if (!bl_ops) { ++ dev_err(par->info->device, ++ "%s: could not allocate memory for backlight operations.\n", ++ __func__); ++ return; ++ } ++ ++ bl_ops->update_status = backlight_chip_update_status; ++ bl_props.type = BACKLIGHT_RAW; ++ bl_props.power = FB_BLANK_POWERDOWN; ++ bl_props.max_brightness = 100; ++ bl_props.brightness = DEFAULT_BRIGHTNESS; ++ ++ bd = backlight_device_register(dev_driver_string(par->info->device), ++ par->info->device, par, bl_ops, &bl_props); ++ if (IS_ERR(bd)) { ++ dev_err(par->info->device, ++ "cannot register backlight device (%ld)\n", ++ PTR_ERR(bd)); ++ return; ++ } ++ par->info->bl_dev = bd; ++ ++ if (!par->fbtftops.unregister_backlight) ++ par->fbtftops.unregister_backlight = fbtft_unregister_backlight; ++} ++#else ++#define register_chip_backlight NULL ++#endif ++ ++ ++static struct fbtft_display display = { ++ .regwidth = 8, ++ .buswidth = 8, ++ .width = WIDTH, ++ .height = HEIGHT, ++ .fps = FPS, ++ .txbuflen = TXBUFLEN, ++ .fbtftops = { ++ .write_register = write_reg8_bus8, ++ .write_vmem = write_vmem, ++ .init_display = init_display, ++ .set_addr_win = set_addr_win, ++ .set_var = set_var, ++ .verify_gpios = verify_gpios, ++ .register_backlight = register_chip_backlight, ++ }, ++}; ++FBTFT_REGISTER_DRIVER(DRVNAME, "watterott,openlcd", &display); ++ ++MODULE_ALIAS("spi:" DRVNAME); ++ ++MODULE_DESCRIPTION("FB driver for the Watterott LCD Controller"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From aabdc53bcddead0fe715b2e583086cb235e45940 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:35 +0100 +Subject: [PATCH 151/178] staging: fbtft: add flexfb driver + +This commit adds the flexfb driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 6 + + drivers/staging/fbtft/Makefile | 1 + + drivers/staging/fbtft/flexfb.c | 593 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 600 insertions(+) + create mode 100644 drivers/staging/fbtft/flexfb.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index 8edec90..d7ddd6e 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -157,3 +157,9 @@ config FB_TFT_WATTEROTT + depends on FB_TFT + help + Generic Framebuffer support for WATTEROTT ++ ++config FB_FLEX ++ tristate "Generic FB driver for TFT LCD displays" ++ depends on FB_TFT ++ help ++ Generic Framebuffer support for TFT LCD displays. +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 78008c3..5b3254a 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -28,3 +28,4 @@ obj-$(CONFIG_FB_TFT_TLS8204) += fb_tls8204.o + obj-$(CONFIG_FB_TFT_UC1701) += fb_uc1701.o + obj-$(CONFIG_FB_TFT_UPD161704) += fb_upd161704.o + obj-$(CONFIG_FB_TFT_WATTEROTT) += fb_watterott.o ++obj-$(CONFIG_FB_FLEX) += flexfb.o +diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c +new file mode 100644 +index 0000000..45574a0 +--- /dev/null ++++ b/drivers/staging/fbtft/flexfb.c +@@ -0,0 +1,593 @@ ++/* ++ * Generic FB driver for TFT LCD displays ++ * ++ * Copyright (C) 2013 Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "flexfb" ++ ++ ++static char *chip = NULL; ++module_param(chip, charp, 0); ++MODULE_PARM_DESC(chip, "LCD controller"); ++ ++static unsigned int width = 0; ++module_param(width, uint, 0); ++MODULE_PARM_DESC(width, "Display width"); ++ ++static unsigned int height = 0; ++module_param(height, uint, 0); ++MODULE_PARM_DESC(height, "Display height"); ++ ++static int init[512]; ++static int init_num = 0; ++module_param_array(init, int, &init_num, 0); ++MODULE_PARM_DESC(init, "Init sequence"); ++ ++static unsigned int setaddrwin = 0; ++module_param(setaddrwin, uint, 0); ++MODULE_PARM_DESC(setaddrwin, "Which set_addr_win() implementation to use"); ++ ++static unsigned int buswidth = 8; ++module_param(buswidth, uint, 0); ++MODULE_PARM_DESC(buswidth, "Width of databus (default: 8)"); ++ ++static unsigned int regwidth = 8; ++module_param(regwidth, uint, 0); ++MODULE_PARM_DESC(regwidth, "Width of controller register (default: 8)"); ++ ++static bool nobacklight = false; ++module_param(nobacklight, bool, 0); ++MODULE_PARM_DESC(nobacklight, "Turn off backlight functionality."); ++ ++static bool latched = false; ++module_param(latched, bool, 0); ++MODULE_PARM_DESC(latched, "Use with latched 16-bit databus"); ++ ++ ++static int *initp = NULL; ++static int initp_num = 0; ++ ++/* default init sequences */ ++static int st7735r_init[] = { \ ++-1,0x01,-2,150,-1,0x11,-2,500,-1,0xB1,0x01,0x2C,0x2D,-1,0xB2,0x01,0x2C,0x2D,-1,0xB3,0x01,0x2C,0x2D,0x01,0x2C,0x2D, \ ++-1,0xB4,0x07,-1,0xC0,0xA2,0x02,0x84,-1,0xC1,0xC5,-1,0xC2,0x0A,0x00,-1,0xC3,0x8A,0x2A,-1,0xC4,0x8A,0xEE,-1,0xC5,0x0E, \ ++-1,0x20,-1,0x36,0xC0,-1,0x3A,0x05,-1,0xE0,0x0f,0x1a,0x0f,0x18,0x2f,0x28,0x20,0x22,0x1f,0x1b,0x23,0x37,0x00,0x07,0x02,0x10, \ ++-1,0xE1,0x0f,0x1b,0x0f,0x17,0x33,0x2c,0x29,0x2e,0x30,0x30,0x39,0x3f,0x00,0x07,0x03,0x10,-1,0x29,-2,100,-1,0x13,-2,10,-3 }; ++ ++static int ssd1289_init[] = { \ ++-1,0x00,0x0001,-1,0x03,0xA8A4,-1,0x0C,0x0000,-1,0x0D,0x080C,-1,0x0E,0x2B00,-1,0x1E,0x00B7,-1,0x01,0x2B3F,-1,0x02,0x0600, \ ++-1,0x10,0x0000,-1,0x11,0x6070,-1,0x05,0x0000,-1,0x06,0x0000,-1,0x16,0xEF1C,-1,0x17,0x0003,-1,0x07,0x0233,-1,0x0B,0x0000, \ ++-1,0x0F,0x0000,-1,0x41,0x0000,-1,0x42,0x0000,-1,0x48,0x0000,-1,0x49,0x013F,-1,0x4A,0x0000,-1,0x4B,0x0000,-1,0x44,0xEF00, \ ++-1,0x45,0x0000,-1,0x46,0x013F,-1,0x30,0x0707,-1,0x31,0x0204,-1,0x32,0x0204,-1,0x33,0x0502,-1,0x34,0x0507,-1,0x35,0x0204, \ ++-1,0x36,0x0204,-1,0x37,0x0502,-1,0x3A,0x0302,-1,0x3B,0x0302,-1,0x23,0x0000,-1,0x24,0x0000,-1,0x25,0x8000,-1,0x4f,0x0000, \ ++-1,0x4e,0x0000,-1,0x22,-3 }; ++ ++static int hx8340bn_init[] = { \ ++-1,0xC1,0xFF,0x83,0x40,-1,0x11,-2,150,-1,0xCA,0x70,0x00,0xD9,-1,0xB0,0x01,0x11, \ ++-1,0xC9,0x90,0x49,0x10,0x28,0x28,0x10,0x00,0x06,-2,20,-1,0xC2,0x60,0x71,0x01,0x0E,0x05,0x02,0x09,0x31,0x0A, \ ++-1,0xC3,0x67,0x30,0x61,0x17,0x48,0x07,0x05,0x33,-2,10,-1,0xB5,0x35,0x20,0x45,-1,0xB4,0x33,0x25,0x4C,-2,10, \ ++-1,0x3A,0x05,-1,0x29,-2,10,-3 }; ++ ++static int ili9225_init[] = { \ ++-1,0x0001,0x011C,-1,0x0002,0x0100,-1,0x0003,0x1030,-1,0x0008,0x0808,-1,0x000C,0x0000,-1,0x000F,0x0A01,-1,0x0020,0x0000, \ ++-1,0x0021,0x0000,-2,50,-1,0x0010,0x0A00,-1,0x0011,0x1038,-2,50,-1,0x0012,0x1121,-1,0x0013,0x004E,-1,0x0014,0x676F, \ ++-1,0x0030,0x0000,-1,0x0031,0x00DB,-1,0x0032,0x0000,-1,0x0033,0x0000,-1,0x0034,0x00DB,-1,0x0035,0x0000,-1,0x0036,0x00AF, \ ++-1,0x0037,0x0000,-1,0x0038,0x00DB,-1,0x0039,0x0000,-1,0x0050,0x0000,-1,0x0051,0x060A,-1,0x0052,0x0D0A,-1,0x0053,0x0303, \ ++-1,0x0054,0x0A0D,-1,0x0055,0x0A06,-1,0x0056,0x0000,-1,0x0057,0x0303,-1,0x0058,0x0000,-1,0x0059,0x0000,-2,50, \ ++-1,0x0007,0x1017,-2,50,-3 }; ++ ++static int ili9320_init[] = { \ ++-1,0x00E5,0x8000,-1,0x0000,0x0001,-1,0x0001,0x0100,-1,0x0002,0x0700,-1,0x0003,0x1030,-1,0x0004,0x0000,-1,0x0008,0x0202, \ ++-1,0x0009,0x0000,-1,0x000A,0x0000,-1,0x000C,0x0000,-1,0x000D,0x0000,-1,0x000F,0x0000,-1,0x0010,0x0000,-1,0x0011,0x0007, \ ++-1,0x0012,0x0000,-1,0x0013,0x0000,-2,200,-1,0x0010,0x17B0,-1,0x0011,0x0031,-2,50,-1,0x0012,0x0138,-2,50,-1,0x0013,0x1800, \ ++-1,0x0029,0x0008,-2,50,-1,0x0020,0x0000,-1,0x0021,0x0000,-1,0x0030,0x0000,-1,0x0031,0x0505,-1,0x0032,0x0004, \ ++-1,0x0035,0x0006,-1,0x0036,0x0707,-1,0x0037,0x0105,-1,0x0038,0x0002,-1,0x0039,0x0707,-1,0x003C,0x0704,-1,0x003D,0x0807, \ ++-1,0x0050,0x0000,-1,0x0051,0x00EF,-1,0x0052,0x0000,-1,0x0053,0x013F,-1,0x0060,0x2700,-1,0x0061,0x0001,-1,0x006A,0x0000, \ ++-1,0x0080,0x0000,-1,0x0081,0x0000,-1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000,-1,0x0085,0x0000,-1,0x0090,0x0010, \ ++-1,0x0092,0x0000,-1,0x0093,0x0003,-1,0x0095,0x0110,-1,0x0097,0x0000,-1,0x0098,0x0000,-1,0x0007,0x0173,-3 }; ++ ++static int ili9325_init[] = { \ ++-1,0x00E3,0x3008,-1,0x00E7,0x0012,-1,0x00EF,0x1231,-1,0x0001,0x0100,-1,0x0002,0x0700,-1,0x0003,0x1030,-1,0x0004,0x0000, \ ++-1,0x0008,0x0207,-1,0x0009,0x0000,-1,0x000A,0x0000,-1,0x000C,0x0000,-1,0x000D,0x0000,-1,0x000F,0x0000,-1,0x0010,0x0000, \ ++-1,0x0011,0x0007,-1,0x0012,0x0000,-1,0x0013,0x0000,-2,200,-1,0x0010,0x1690,-1,0x0011,0x0223,-2,50,-1,0x0012,0x000D,-2,50, \ ++-1,0x0013,0x1200,-1,0x0029,0x000A,-1,0x002B,0x000C,-2,50,-1,0x0020,0x0000,-1,0x0021,0x0000,-1,0x0030,0x0000, \ ++-1,0x0031,0x0506,-1,0x0032,0x0104,-1,0x0035,0x0207,-1,0x0036,0x000F,-1,0x0037,0x0306,-1,0x0038,0x0102,-1,0x0039,0x0707, \ ++-1,0x003C,0x0702,-1,0x003D,0x1604,-1,0x0050,0x0000,-1,0x0051,0x00EF,-1,0x0052,0x0000,-1,0x0053,0x013F,-1,0x0060,0xA700, \ ++-1,0x0061,0x0001,-1,0x006A,0x0000,-1,0x0080,0x0000,-1,0x0081,0x0000,-1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000, \ ++-1,0x0085,0x0000,-1,0x0090,0x0010,-1,0x0092,0x0600,-1,0x0007,0x0133,-3 }; ++ ++static int ili9341_init[] = { \ ++-1,0x28,-2,20,-1,0xCF,0x00,0x83,0x30,-1,0xED,0x64,0x03,0x12,0x81,-1,0xE8,0x85,0x01,0x79, \ ++-1,0xCB,0x39,0x2c,0x00,0x34,0x02,-1,0xF7,0x20,-1,0xEA,0x00,0x00,-1,0xC0,0x26,-1,0xC1,0x11, \ ++-1,0xC5,0x35,0x3E,-1,0xC7,0xBE,-1,0xB1,0x00,0x1B,-1,0xB6,0x0a,0x82,0x27,0x00,-1,0xB7,0x07, \ ++-1,0x3A,0x55,-1,0x36,0x48,-1,0x11,-2,120,-1,0x29,-2,20,-3 }; ++ ++static int ssd1351_init[] = { -1,0xfd,0x12,-1,0xfd,0xb1,-1,0xae,-1,0xb3,0xf1,-1,0xca,0x7f,-1,0xa0,0x74, \ ++ -1,0x15,0x00,0x7f,-1,0x75,0x00,0x7f,-1,0xa1,0x00,-1,0xa2,0x00,-1,0xb5,0x00, \ ++ -1,0xab,0x01,-1,0xb1,0x32,-1,0xb4,0xa0,0xb5,0x55,-1,0xbb,0x17,-1,0xbe,0x05, \ ++ -1,0xc1,0xc8,0x80,0xc8,-1,0xc7,0x0f,-1,0xb6,0x01,-1,0xa6,-1,0xaf,-3 }; ++ ++ ++/* ili9320, ili9325 */ ++static void flexfb_set_addr_win_1(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ switch (par->info->var.rotate) { ++ /* R20h = Horizontal GRAM Start Address */ ++ /* R21h = Vertical GRAM Start Address */ ++ case 0: ++ write_reg(par, 0x0020, xs); ++ write_reg(par, 0x0021, ys); ++ break; ++ case 180: ++ write_reg(par, 0x0020, width - 1 - xs); ++ write_reg(par, 0x0021, height - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x0020, width - 1 - ys); ++ write_reg(par, 0x0021, xs); ++ break; ++ case 90: ++ write_reg(par, 0x0020, ys); ++ write_reg(par, 0x0021, height - 1 - xs); ++ break; ++ } ++ write_reg(par, 0x0022); /* Write Data to GRAM */ ++} ++ ++/* ssd1289 */ ++static void flexfb_set_addr_win_2(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ switch (par->info->var.rotate) { ++ /* R4Eh - Set GDDRAM X address counter */ ++ /* R4Fh - Set GDDRAM Y address counter */ ++ case 0: ++ write_reg(par, 0x4e, xs); ++ write_reg(par, 0x4f, ys); ++ break; ++ case 180: ++ write_reg(par, 0x4e, par->info->var.xres - 1 - xs); ++ write_reg(par, 0x4f, par->info->var.yres - 1 - ys); ++ break; ++ case 270: ++ write_reg(par, 0x4e, par->info->var.yres - 1 - ys); ++ write_reg(par, 0x4f, xs); ++ break; ++ case 90: ++ write_reg(par, 0x4e, ys); ++ write_reg(par, 0x4f, par->info->var.xres - 1 - xs); ++ break; ++ } ++ ++ /* R22h - RAM data write */ ++ write_reg(par, 0x22, 0); ++} ++ ++/* ssd1351 */ ++static void set_addr_win_3(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ ++ write_reg(par, 0x15, xs, xe); ++ write_reg(par, 0x75, ys, ye); ++ write_reg(par, 0x5C); ++} ++ ++static int flexfb_verify_gpios_dc(struct fbtft_par *par) ++{ ++ fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__); ++ ++ if (par->gpio.dc < 0) { ++ dev_err(par->info->device, "Missing info about 'dc' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int flexfb_verify_gpios_db(struct fbtft_par *par) ++{ ++ int i; ++ int num_db = buswidth; ++ ++ fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__); ++ ++ if (par->gpio.dc < 0) { ++ dev_err(par->info->device, "Missing info about 'dc' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ if (par->gpio.wr < 0) { ++ dev_err(par->info->device, "Missing info about 'wr' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ if (latched && (par->gpio.latch < 0)) { ++ dev_err(par->info->device, "Missing info about 'latch' gpio. Aborting.\n"); ++ return -EINVAL; ++ } ++ if (latched) ++ num_db=buswidth/2; ++ for (i=0;i < num_db;i++) { ++ if (par->gpio.db[i] < 0) { ++ dev_err(par->info->device, "Missing info about 'db%02d' gpio. Aborting.\n", i); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct fbtft_display flex_display = { }; ++ ++static int flexfb_probe_common(struct spi_device *sdev, struct platform_device *pdev) ++{ ++ struct device *dev; ++ struct fb_info *info; ++ struct fbtft_par *par; ++ int ret; ++ ++ initp = init; ++ initp_num = init_num; ++ ++ if (sdev) ++ dev = &sdev->dev; ++ else ++ dev = &pdev->dev; ++ ++ fbtft_init_dbg(dev, "%s(%s)\n", __func__, sdev ? "'SPI device'" : "'Platform device'"); ++ ++ if (chip) { ++ ++ if (!strcmp(chip, "st7735r")) { ++ if (!width) ++ width = 128; ++ if (!height) ++ height = 160; ++ if (init_num == 0) { ++ initp = st7735r_init; ++ initp_num = ARRAY_SIZE(st7735r_init); ++ } ++ ++ ++ } else if (!strcmp(chip, "hx8340bn")) { ++ if (!width) ++ width = 176; ++ if (!height) ++ height = 220; ++ setaddrwin = 0; ++ if (init_num == 0) { ++ initp = hx8340bn_init; ++ initp_num = ARRAY_SIZE(hx8340bn_init); ++ } ++ ++ ++ } else if (!strcmp(chip, "ili9225")) { ++ if (!width) ++ width = 176; ++ if (!height) ++ height = 220; ++ setaddrwin = 0; ++ regwidth = 16; ++ if (init_num == 0) { ++ initp = ili9225_init; ++ initp_num = ARRAY_SIZE(ili9225_init); ++ } ++ ++ ++ ++ } else if (!strcmp(chip, "ili9320")) { ++ if (!width) ++ width = 240; ++ if (!height) ++ height = 320; ++ setaddrwin = 1; ++ regwidth = 16; ++ if (init_num == 0) { ++ initp = ili9320_init; ++ initp_num = ARRAY_SIZE(ili9320_init); ++ } ++ ++ ++ } else if (!strcmp(chip, "ili9325")) { ++ if (!width) ++ width = 240; ++ if (!height) ++ height = 320; ++ setaddrwin = 1; ++ regwidth = 16; ++ if (init_num == 0) { ++ initp = ili9325_init; ++ initp_num = ARRAY_SIZE(ili9325_init); ++ } ++ ++ } else if (!strcmp(chip, "ili9341")) { ++ if (!width) ++ width = 240; ++ if (!height) ++ height = 320; ++ setaddrwin = 0; ++ regwidth = 8; ++ if (init_num == 0) { ++ initp = ili9341_init; ++ initp_num = ARRAY_SIZE(ili9341_init); ++ } ++ ++ ++ } else if (!strcmp(chip, "ssd1289")) { ++ if (!width) ++ width = 240; ++ if (!height) ++ height = 320; ++ setaddrwin = 2; ++ regwidth = 16; ++ if (init_num == 0) { ++ initp = ssd1289_init; ++ initp_num = ARRAY_SIZE(ssd1289_init); ++ } ++ ++ ++ ++ } else if (!strcmp(chip, "ssd1351")) { ++ if (!width) ++ width = 128; ++ if (!height) ++ height = 128; ++ setaddrwin = 3; ++ if (init_num == 0) { ++ initp = ssd1351_init; ++ initp_num = ARRAY_SIZE(ssd1351_init); ++ } ++ } else { ++ dev_err(dev, "chip=%s is not supported\n", chip); ++ return -EINVAL; ++ } ++ } ++ ++ if (width == 0 || height == 0) { ++ dev_err(dev, "argument(s) missing: width and height has to be set.\n"); ++ return -EINVAL; ++ } ++ flex_display.width = width; ++ flex_display.height = height; ++ fbtft_init_dbg(dev, "Display resolution: %dx%d\n", width, height); ++ fbtft_init_dbg(dev, "chip = %s\n", chip ? chip : "not set"); ++ fbtft_init_dbg(dev, "setaddrwin = %d\n", setaddrwin); ++ fbtft_init_dbg(dev, "regwidth = %d\n", regwidth); ++ fbtft_init_dbg(dev, "buswidth = %d\n", buswidth); ++ ++ info = fbtft_framebuffer_alloc(&flex_display, dev); ++ if (!info) ++ return -ENOMEM; ++ ++ par = info->par; ++ if (sdev) ++ par->spi = sdev; ++ else ++ par->pdev = pdev; ++ if (!par->init_sequence) ++ par->init_sequence = initp; ++ par->fbtftops.init_display = fbtft_init_display; ++ ++ /* registerwrite functions */ ++ switch (regwidth) { ++ case 8: ++ par->fbtftops.write_register = fbtft_write_reg8_bus8; ++ break; ++ case 16: ++ par->fbtftops.write_register = fbtft_write_reg16_bus8; ++ break; ++ default: ++ dev_err(dev, "argument 'regwidth': %d is not supported.\n", regwidth); ++ return -EINVAL; ++ } ++ ++ /* bus functions */ ++ if (sdev) { ++ par->fbtftops.write = fbtft_write_spi; ++ switch (buswidth) { ++ case 8: ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus8; ++ if (!par->startbyte) ++ par->fbtftops.verify_gpios = flexfb_verify_gpios_dc; ++ break; ++ case 9: ++ if (regwidth == 16) { ++ dev_err(dev, "argument 'regwidth': %d is not supported with buswidth=%d and SPI.\n", regwidth, buswidth); ++ return -EINVAL; ++ } ++ par->fbtftops.write_register = fbtft_write_reg8_bus9; ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus9; ++ sdev->bits_per_word=9; ++ ret = sdev->master->setup(sdev); ++ if (ret) { ++ dev_warn(dev, ++ "9-bit SPI not available, emulating using 8-bit.\n"); ++ sdev->bits_per_word = 8; ++ ret = sdev->master->setup(sdev); ++ if (ret) ++ goto out_release; ++ /* allocate buffer with room for dc bits */ ++ par->extra = devm_kzalloc(par->info->device, ++ par->txbuf.len + (par->txbuf.len / 8) + 8, ++ GFP_KERNEL); ++ if (!par->extra) { ++ ret = -ENOMEM; ++ goto out_release; ++ } ++ par->fbtftops.write = fbtft_write_spi_emulate_9; ++ } ++ break; ++ default: ++ dev_err(dev, "argument 'buswidth': %d is not supported with SPI.\n", buswidth); ++ return -EINVAL; ++ } ++ } else { ++ par->fbtftops.verify_gpios = flexfb_verify_gpios_db; ++ switch (buswidth) { ++ case 8: ++ par->fbtftops.write = fbtft_write_gpio8_wr; ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus8; ++ break; ++ case 16: ++ par->fbtftops.write_register = fbtft_write_reg16_bus16; ++ if (latched) ++ par->fbtftops.write = fbtft_write_gpio16_wr_latched; ++ else ++ par->fbtftops.write = fbtft_write_gpio16_wr; ++ par->fbtftops.write_vmem = fbtft_write_vmem16_bus16; ++ break; ++ default: ++ dev_err(dev, "argument 'buswidth': %d is not supported with parallel.\n", buswidth); ++ return -EINVAL; ++ } ++ } ++ ++ /* set_addr_win function */ ++ switch (setaddrwin) { ++ case 0: ++ /* use default */ ++ break; ++ case 1: ++ par->fbtftops.set_addr_win = flexfb_set_addr_win_1; ++ break; ++ case 2: ++ par->fbtftops.set_addr_win = flexfb_set_addr_win_2; ++ break; ++ case 3: ++ par->fbtftops.set_addr_win = set_addr_win_3; ++ break; ++ default: ++ dev_err(dev, "argument 'setaddrwin': unknown value %d.\n", setaddrwin); ++ return -EINVAL; ++ } ++ ++ if (!nobacklight) ++ par->fbtftops.register_backlight = fbtft_register_backlight; ++ ++ ret = fbtft_register_framebuffer(info); ++ if (ret < 0) ++ goto out_release; ++ ++ return 0; ++ ++out_release: ++ fbtft_framebuffer_release(info); ++ ++ return ret; ++} ++ ++static int flexfb_remove_common(struct device *dev, struct fb_info *info) ++{ ++ struct fbtft_par *par; ++ ++ if (!info) ++ return -EINVAL; ++ par = info->par; ++ if (par) ++ fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par, ++ "%s()\n", __func__); ++ fbtft_unregister_framebuffer(info); ++ fbtft_framebuffer_release(info); ++ ++ return 0; ++} ++ ++static int flexfb_probe_spi(struct spi_device *spi) ++{ ++ return flexfb_probe_common(spi, NULL); ++} ++ ++static int flexfb_remove_spi(struct spi_device *spi) ++{ ++ struct fb_info *info = spi_get_drvdata(spi); ++ ++ return flexfb_remove_common(&spi->dev, info); ++} ++ ++static int flexfb_probe_pdev(struct platform_device *pdev) ++{ ++ return flexfb_probe_common(NULL, pdev); ++} ++ ++static int flexfb_remove_pdev(struct platform_device *pdev) ++{ ++ struct fb_info *info = platform_get_drvdata(pdev); ++ ++ return flexfb_remove_common(&pdev->dev, info); ++} ++ ++static struct spi_driver flexfb_spi_driver = { ++ .driver = { ++ .name = DRVNAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = flexfb_probe_spi, ++ .remove = flexfb_remove_spi, ++}; ++ ++static const struct platform_device_id flexfb_platform_ids[] = { ++ { "flexpfb", 0 }, ++ { }, ++}; ++ ++static struct platform_driver flexfb_platform_driver = { ++ .driver = { ++ .name = DRVNAME, ++ .owner = THIS_MODULE, ++ }, ++ .id_table = flexfb_platform_ids, ++ .probe = flexfb_probe_pdev, ++ .remove = flexfb_remove_pdev, ++}; ++ ++static int __init flexfb_init(void) ++{ ++ int ret, ret2; ++ ++ ret = spi_register_driver(&flexfb_spi_driver); ++ ret2 = platform_driver_register(&flexfb_platform_driver); ++ if (ret < 0) ++ return ret; ++ return ret2; ++} ++ ++static void __exit flexfb_exit(void) ++{ ++ spi_unregister_driver(&flexfb_spi_driver); ++ platform_driver_unregister(&flexfb_platform_driver); ++} ++ ++/* ------------------------------------------------------------------------- */ ++ ++module_init(flexfb_init); ++module_exit(flexfb_exit); ++ ++MODULE_DESCRIPTION("Generic FB driver for TFT LCD displays"); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From 397ebc2dd7de10b72dc36a56b4d65059ccb2695b Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:36 +0100 +Subject: [PATCH 152/178] staging: fbtft: add fbtft_device driver + +This commit adds the fbtft_device driver from the fbtft project at +https://github.com/notro/fbtft. + +Signed-off-by: Thomas Petazzoni +Signed-off-by: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/Kconfig | 4 + + drivers/staging/fbtft/Makefile | 3 + + drivers/staging/fbtft/fbtft_device.c | 1444 ++++++++++++++++++++++++++++++++++ + 3 files changed, 1451 insertions(+) + create mode 100644 drivers/staging/fbtft/fbtft_device.c + +diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig +index d7ddd6e..995a910 100644 +--- a/drivers/staging/fbtft/Kconfig ++++ b/drivers/staging/fbtft/Kconfig +@@ -163,3 +163,7 @@ config FB_FLEX + depends on FB_TFT + help + Generic Framebuffer support for TFT LCD displays. ++ ++config FB_TFT_FBTFT_DEVICE ++ tristate "Module to for adding FBTFT devices" ++ depends on FB_TFT +diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile +index 5b3254a..e773f0f 100644 +--- a/drivers/staging/fbtft/Makefile ++++ b/drivers/staging/fbtft/Makefile +@@ -29,3 +29,6 @@ obj-$(CONFIG_FB_TFT_UC1701) += fb_uc1701.o + obj-$(CONFIG_FB_TFT_UPD161704) += fb_upd161704.o + obj-$(CONFIG_FB_TFT_WATTEROTT) += fb_watterott.o + obj-$(CONFIG_FB_FLEX) += flexfb.o ++ ++# Device modules ++obj-$(CONFIG_FB_TFT_FBTFT_DEVICE) += fbtft_device.o +diff --git a/drivers/staging/fbtft/fbtft_device.c b/drivers/staging/fbtft/fbtft_device.c +new file mode 100644 +index 0000000..b9f4c30 +--- /dev/null ++++ b/drivers/staging/fbtft/fbtft_device.c +@@ -0,0 +1,1444 @@ ++/* ++ * ++ * Copyright (C) 2013, Noralf Tronnes ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fbtft.h" ++ ++#define DRVNAME "fbtft_device" ++ ++#define MAX_GPIOS 32 ++ ++struct spi_device *spi_device; ++struct platform_device *p_device; ++ ++static char *name; ++module_param(name, charp, 0); ++MODULE_PARM_DESC(name, "Devicename (required). " \ ++"name=list => list all supported devices."); ++ ++static unsigned rotate; ++module_param(rotate, uint, 0); ++MODULE_PARM_DESC(rotate, ++"Angle to rotate display counter clockwise: 0, 90, 180, 270"); ++ ++static unsigned busnum; ++module_param(busnum, uint, 0); ++MODULE_PARM_DESC(busnum, "SPI bus number (default=0)"); ++ ++static unsigned cs; ++module_param(cs, uint, 0); ++MODULE_PARM_DESC(cs, "SPI chip select (default=0)"); ++ ++static unsigned speed; ++module_param(speed, uint, 0); ++MODULE_PARM_DESC(speed, "SPI speed (override device default)"); ++ ++static int mode = -1; ++module_param(mode, int, 0); ++MODULE_PARM_DESC(mode, "SPI mode (override device default)"); ++ ++static char *gpios; ++module_param(gpios, charp, 0); ++MODULE_PARM_DESC(gpios, ++"List of gpios. Comma separated with the form: reset:23,dc:24 " \ ++"(when overriding the default, all gpios must be specified)"); ++ ++static unsigned fps; ++module_param(fps, uint, 0); ++MODULE_PARM_DESC(fps, "Frames per second (override driver default)"); ++ ++static char *gamma; ++module_param(gamma, charp, 0); ++MODULE_PARM_DESC(gamma, ++"String representation of Gamma Curve(s). Driver specific."); ++ ++static int txbuflen; ++module_param(txbuflen, int, 0); ++MODULE_PARM_DESC(txbuflen, "txbuflen (override driver default)"); ++ ++static int bgr = -1; ++module_param(bgr, int, 0); ++MODULE_PARM_DESC(bgr, ++"BGR bit (supported by some drivers)."); ++ ++static unsigned startbyte; ++module_param(startbyte, uint, 0); ++MODULE_PARM_DESC(startbyte, "Sets the Start byte used by some SPI displays."); ++ ++static bool custom; ++module_param(custom, bool, 0); ++MODULE_PARM_DESC(custom, "Add a custom display device. " \ ++"Use speed= argument to make it a SPI device, else platform_device"); ++ ++static unsigned width; ++module_param(width, uint, 0); ++MODULE_PARM_DESC(width, "Display width, used with the custom argument"); ++ ++static unsigned height; ++module_param(height, uint, 0); ++MODULE_PARM_DESC(height, "Display height, used with the custom argument"); ++ ++static unsigned buswidth = 8; ++module_param(buswidth, uint, 0); ++MODULE_PARM_DESC(buswidth, "Display bus width, used with the custom argument"); ++ ++static int init[FBTFT_MAX_INIT_SEQUENCE]; ++static int init_num; ++module_param_array(init, int, &init_num, 0); ++MODULE_PARM_DESC(init, "Init sequence, used with the custom argument"); ++ ++static unsigned long debug; ++module_param(debug, ulong , 0); ++MODULE_PARM_DESC(debug, ++"level: 0-7 (the remaining 29 bits is for advanced usage)"); ++ ++static unsigned verbose = 3; ++module_param(verbose, uint, 0); ++MODULE_PARM_DESC(verbose, ++"0 silent, >0 show gpios, >1 show devices, >2 show devices before (default=3)"); ++ ++ ++struct fbtft_device_display { ++ char *name; ++ struct spi_board_info *spi; ++ struct platform_device *pdev; ++}; ++ ++static void fbtft_device_pdev_release(struct device *dev); ++ ++static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len); ++static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par, ++ int xs, int ys, int xe, int ye); ++ ++#define ADAFRUIT18_GAMMA \ ++ "02 1c 07 12 37 32 29 2d 29 25 2B 39 00 01 03 10\n" \ ++ "03 1d 07 06 2E 2C 29 2D 2E 2E 37 3F 00 00 02 10" ++ ++static int hy28b_init_sequence[] = { ++ -1,0x00e7,0x0010,-1,0x0000,0x0001,-1,0x0001,0x0100,-1,0x0002,0x0700, ++ -1,0x0003,0x1030,-1,0x0004,0x0000,-1,0x0008,0x0207,-1,0x0009,0x0000, ++ -1,0x000a,0x0000,-1,0x000c,0x0001,-1,0x000d,0x0000,-1,0x000f,0x0000, ++ -1,0x0010,0x0000,-1,0x0011,0x0007,-1,0x0012,0x0000,-1,0x0013,0x0000, ++ -2,50,-1,0x0010,0x1590,-1,0x0011,0x0227,-2,50,-1,0x0012,0x009c,-2,50, ++ -1,0x0013,0x1900,-1,0x0029,0x0023,-1,0x002b,0x000e,-2,50, ++ -1,0x0020,0x0000,-1,0x0021,0x0000,-2,50,-1,0x0050,0x0000, ++ -1,0x0051,0x00ef,-1,0x0052,0x0000,-1,0x0053,0x013f,-1,0x0060,0xa700, ++ -1,0x0061,0x0001,-1,0x006a,0x0000,-1,0x0080,0x0000,-1,0x0081,0x0000, ++ -1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000,-1,0x0085,0x0000, ++ -1,0x0090,0x0010,-1,0x0092,0x0000,-1,0x0093,0x0003,-1,0x0095,0x0110, ++ -1,0x0097,0x0000,-1,0x0098,0x0000,-1,0x0007,0x0133,-1,0x0020,0x0000, ++ -1,0x0021,0x0000,-2,100,-3 }; ++ ++#define HY28B_GAMMA \ ++ "04 1F 4 7 7 0 7 7 6 0\n" \ ++ "0F 00 1 7 4 0 0 0 6 7" ++ ++static int pitft_init_sequence[] = { ++ -1,0x01,-2,5,-1,0x28,-1,0xEF,0x03,0x80,0x02,-1,0xCF,0x00,0xC1,0x30, ++ -1,0xED,0x64,0x03,0x12,0x81,-1,0xE8,0x85,0x00,0x78, ++ -1,0xCB,0x39,0x2C,0x00,0x34,0x02,-1,0xF7,0x20,-1,0xEA,0x00,0x00, ++ -1,0xC0,0x23,-1,0xC1,0x10,-1,0xC5,0x3e,0x28,-1,0xC7,0x86,-1,0x3A,0x55, ++ -1,0xB1,0x00,0x18,-1,0xB6,0x08,0x82,0x27,-1,0xF2,0x00,-1,0x26,0x01, ++ -1,0xE0,0x0F,0x31,0x2B,0x0C,0x0E,0x08,0x4E,0xF1,0x37,0x07,0x10,0x03, ++ 0x0E,0x09,0x00,-1,0xE1,0x00,0x0E,0x14,0x03,0x11,0x07,0x31,0xC1,0x48, ++ 0x08,0x0F,0x0C,0x31,0x36,0x0F,-1,0x11,-2,100,-1,0x29,-2,20,-3 }; ++ ++static int waveshare32b_init_sequence[] = { ++ -1,0xCB,0x39,0x2C,0x00,0x34,0x02,-1,0xCF,0x00,0xC1,0x30, ++ -1,0xE8,0x85,0x00,0x78,-1,0xEA,0x00,0x00,-1,0xED,0x64,0x03,0x12,0x81, ++ -1,0xF7,0x20,-1,0xC0,0x23,-1,0xC1,0x10,-1,0xC5,0x3e,0x28,-1,0xC7,0x86, ++ -1,0x36,0x28,-1,0x3A,0x55,-1,0xB1,0x00,0x18,-1,0xB6,0x08,0x82,0x27, ++ -1,0xF2,0x00,-1,0x26,0x01, ++ -1,0xE0,0x0F,0x31,0x2B,0x0C,0x0E,0x08,0x4E,0xF1,0x37,0x07,0x10,0x03,0x0E,0x09,0x00, ++ -1,0xE1,0x00,0x0E,0x14,0x03,0x11,0x07,0x31,0xC1,0x48,0x08,0x0F,0x0C,0x31,0x36,0x0F, ++ -1,0x11,-2,120,-1,0x29,-1,0x2c,-3 }; ++ ++/* Supported displays in alphabetical order */ ++static struct fbtft_device_display displays[] = { ++ { ++ .name = "adafruit18", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_st7735r", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ .gamma = ADAFRUIT18_GAMMA, ++ } ++ } ++ }, { ++ .name = "adafruit18_green", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_st7735r", ++ .max_speed_hz = 4000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ .fbtftops.set_addr_win = \ ++ adafruit18_green_tab_set_addr_win, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ .gamma = ADAFRUIT18_GAMMA, ++ } ++ } ++ }, { ++ .name = "adafruit22", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_hx8340bn", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 9, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "led", 23 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "adafruit22a", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9340", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "adafruit28", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9341", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "adafruit13m", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ssd1306", ++ .max_speed_hz = 16000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "agm1264k-fl", ++ .pdev = &(struct platform_device) { ++ .name = "fb_agm1264k-fl", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = FBTFT_ONBOARD_BACKLIGHT, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ }, ++ } ++ } ++ }, { ++ .name = "dogs102", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_uc1701", ++ .max_speed_hz = 8000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 13 }, ++ { "dc", 6 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "er_tftm050_2", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ra8875", ++ .max_speed_hz = 5000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ .width = 480, ++ .height = 272, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "er_tftm070_5", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ra8875", ++ .max_speed_hz = 5000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ .width = 800, ++ .height = 480, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "flexfb", ++ .spi = &(struct spi_board_info) { ++ .modalias = "flexfb", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "flexpfb", ++ .pdev = &(struct platform_device) { ++ .name = "flexpfb", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 17 }, ++ { "dc", 1 }, ++ { "wr", 0 }, ++ { "cs", 21 }, ++ { "db00", 9 }, ++ { "db01", 11 }, ++ { "db02", 18 }, ++ { "db03", 23 }, ++ { "db04", 24 }, ++ { "db05", 25 }, ++ { "db06", 8 }, ++ { "db07", 7 }, ++ { "led", 4 }, ++ {}, ++ }, ++ }, ++ } ++ } ++ }, { ++ .name = "freetronicsoled128", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ssd1351", ++ .max_speed_hz = 20000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = FBTFT_ONBOARD_BACKLIGHT, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 24 }, ++ { "dc", 25 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "hx8353d", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_hx8353d", ++ .max_speed_hz = 16000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 23 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "hy28a", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9320", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .startbyte = 0b01110000, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "hy28b", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9325", ++ .max_speed_hz = 48000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ .init_sequence = hy28b_init_sequence, ++ }, ++ .startbyte = 0b01110000, ++ .bgr = true, ++ .fps= 50, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "led", 18 }, ++ {}, ++ }, ++ .gamma = HY28B_GAMMA, ++ } ++ } ++ }, { ++ .name = "ili9481", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9481", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .regwidth = 16, ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 22 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "itdb24", ++ .pdev = &(struct platform_device) { ++ .name = "fb_s6d1121", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = false, ++ .gpios = (const struct fbtft_gpio []) { ++ /* Wiring for LCD adapter kit */ ++ { "reset", 7 }, ++ { "dc", 0 }, /* rev 2: 2 */ ++ { "wr", 1 }, /* rev 2: 3 */ ++ { "cs", 8 }, ++ { "db00", 17 }, ++ { "db01", 18 }, ++ { "db02", 21 }, /* rev 2: 27 */ ++ { "db03", 22 }, ++ { "db04", 23 }, ++ { "db05", 24 }, ++ { "db06", 25 }, ++ { "db07", 4 }, ++ {} ++ }, ++ }, ++ } ++ } ++ }, { ++ .name = "itdb28", ++ .pdev = &(struct platform_device) { ++ .name = "fb_ili9325", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ }, ++ } ++ } ++ }, { ++ .name = "itdb28_spi", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9325", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "mi0283qt-2", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_hx8347d", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .startbyte = 0b01110000, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "mi0283qt-9a", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9341", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 9, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "mi0283qt-v2", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_watterott", ++ .max_speed_hz = 4000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "nokia3310", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_pcd8544", ++ .max_speed_hz = 400000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 23 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "nokia3310a", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_tls8204", ++ .max_speed_hz = 1000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 23 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "piscreen", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9486", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .regwidth = 16, ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 22 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "pitft", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9340", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .chip_select = 0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ .init_sequence = pitft_init_sequence, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "dc", 25 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "pioled", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ssd1351", ++ .max_speed_hz = 20000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 24 }, ++ { "dc", 25 }, ++ {}, ++ }, ++ .gamma = "0 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 2 " \ ++ "2 2 2 2 2 2 2 3 " \ ++ "3 3 3 3 3 3 3 3 " \ ++ "3 3 3 3 3 3 3 3 " \ ++ "3 3 3 4 4 4 4 4 " \ ++ "4 4 4 4 4 4 4" ++ } ++ } ++ }, { ++ .name = "rpi-display", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9341", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 23 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "s6d02a1", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_s6d02a1", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 23 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "sainsmart18", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_st7735r", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "sainsmart32", ++ .pdev = &(struct platform_device) { ++ .name = "fb_ssd1289", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 16, ++ .txbuflen = -2, /* disable buffer */ ++ .backlight = 1, ++ .fbtftops.write = write_gpio16_wr_slow, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ }, ++ }, ++ } ++ }, { ++ .name = "sainsmart32_fast", ++ .pdev = &(struct platform_device) { ++ .name = "fb_ssd1289", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 16, ++ .txbuflen = -2, /* disable buffer */ ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ }, ++ }, ++ } ++ }, { ++ .name = "sainsmart32_latched", ++ .pdev = &(struct platform_device) { ++ .name = "fb_ssd1289", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 16, ++ .txbuflen = -2, /* disable buffer */ ++ .backlight = 1, ++ .fbtftops.write = \ ++ fbtft_write_gpio16_wr_latched, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ }, ++ }, ++ } ++ }, { ++ .name = "sainsmart32_spi", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ssd1289", ++ .max_speed_hz = 16000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "spidev", ++ .spi = &(struct spi_board_info) { ++ .modalias = "spidev", ++ .max_speed_hz = 500000, ++ .bus_num = 0, ++ .chip_select = 0, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "ssd1331", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ssd1331", ++ .max_speed_hz = 20000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 24 }, ++ { "dc", 25 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "tinylcd35", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_tinylcd", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "tm022hdh26", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9341", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 25 }, ++ { "dc", 24 }, ++ { "led", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "tontec35_9481", /* boards before 02 July 2014 */ ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9481", ++ .max_speed_hz = 128000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 15 }, ++ { "dc", 25 }, ++ { "led_", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "tontec35_9486", /* boards after 02 July 2014 */ ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9486", ++ .max_speed_hz = 128000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 15 }, ++ { "dc", 25 }, ++ { "led_", 18 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "upd161704", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_upd161704", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 24 }, ++ { "dc", 25 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "waveshare32b", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_ili9340", ++ .max_speed_hz = 48000000, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ .backlight = 1, ++ .init_sequence = waveshare32b_init_sequence, ++ }, ++ .bgr = true, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 27 }, ++ { "dc", 22 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ .name = "waveshare22", ++ .spi = &(struct spi_board_info) { ++ .modalias = "fb_bd663474", ++ .max_speed_hz = 32000000, ++ .mode = SPI_MODE_3, ++ .platform_data = &(struct fbtft_platform_data) { ++ .display = { ++ .buswidth = 8, ++ }, ++ .gpios = (const struct fbtft_gpio []) { ++ { "reset", 24 }, ++ { "dc", 25 }, ++ {}, ++ }, ++ } ++ } ++ }, { ++ /* This should be the last item. ++ Used with the custom argument */ ++ .name = "", ++ .spi = &(struct spi_board_info) { ++ .modalias = "", ++ .max_speed_hz = 0, ++ .mode = SPI_MODE_0, ++ .platform_data = &(struct fbtft_platform_data) { ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ } ++ }, ++ .pdev = &(struct platform_device) { ++ .name = "", ++ .id = 0, ++ .dev = { ++ .release = fbtft_device_pdev_release, ++ .platform_data = &(struct fbtft_platform_data) { ++ .gpios = (const struct fbtft_gpio []) { ++ {}, ++ }, ++ }, ++ }, ++ }, ++ } ++}; ++ ++static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len) ++{ ++ u16 data; ++ int i; ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ static u16 prev_data; ++#endif ++ ++ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, ++ "%s(len=%d): ", __func__, len); ++ ++ while (len) { ++ data = *(u16 *) buf; ++ ++ /* Start writing by pulling down /WR */ ++ gpio_set_value(par->gpio.wr, 0); ++ ++ /* Set data */ ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ if (data == prev_data) { ++ gpio_set_value(par->gpio.wr, 0); /* used as delay */ ++ } else { ++ for (i = 0; i < 16; i++) { ++ if ((data & 1) != (prev_data & 1)) ++ gpio_set_value(par->gpio.db[i], ++ (data & 1)); ++ data >>= 1; ++ prev_data >>= 1; ++ } ++ } ++#else ++ for (i = 0; i < 16; i++) { ++ gpio_set_value(par->gpio.db[i], (data & 1)); ++ data >>= 1; ++ } ++#endif ++ ++ /* Pullup /WR */ ++ gpio_set_value(par->gpio.wr, 1); ++ ++#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO ++ prev_data = *(u16 *) buf; ++#endif ++ buf += 2; ++ len -= 2; ++ } ++ ++ return 0; ++} ++ ++static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par, ++ int xs, int ys, int xe, int ye) ++{ ++ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, ++ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); ++ write_reg(par, 0x2A, 0, xs + 2, 0, xe + 2); ++ write_reg(par, 0x2B, 0, ys + 1, 0, ye + 1); ++ write_reg(par, 0x2C); ++} ++ ++/* used if gpios parameter is present */ ++static struct fbtft_gpio fbtft_device_param_gpios[MAX_GPIOS+1] = { }; ++ ++static void fbtft_device_pdev_release(struct device *dev) ++{ ++/* Needed to silence this message: ++Device 'xxx' does not have a release() function, it is broken and must be fixed ++*/ ++} ++ ++static int spi_device_found(struct device *dev, void *data) ++{ ++ struct spi_device *spi = container_of(dev, struct spi_device, dev); ++ ++ pr_info(DRVNAME": %s %s %dkHz %d bits mode=0x%02X\n", ++ spi->modalias, dev_name(dev), spi->max_speed_hz/1000, ++ spi->bits_per_word, spi->mode); ++ ++ return 0; ++} ++ ++static void pr_spi_devices(void) ++{ ++ pr_info(DRVNAME": SPI devices registered:\n"); ++ bus_for_each_dev(&spi_bus_type, NULL, NULL, spi_device_found); ++} ++ ++static int p_device_found(struct device *dev, void *data) ++{ ++ struct platform_device ++ *pdev = container_of(dev, struct platform_device, dev); ++ ++ if (strstr(pdev->name, "fb")) ++ pr_info(DRVNAME": %s id=%d pdata? %s\n", ++ pdev->name, pdev->id, ++ pdev->dev.platform_data ? "yes" : "no"); ++ ++ return 0; ++} ++ ++static void pr_p_devices(void) ++{ ++ pr_info(DRVNAME": 'fb' Platform devices registered:\n"); ++ bus_for_each_dev(&platform_bus_type, NULL, NULL, p_device_found); ++} ++ ++#ifdef MODULE ++static void fbtft_device_spi_delete(struct spi_master *master, unsigned cs) ++{ ++ struct device *dev; ++ char str[32]; ++ ++ snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs); ++ ++ dev = bus_find_device_by_name(&spi_bus_type, NULL, str); ++ if (dev) { ++ if (verbose) ++ pr_info(DRVNAME": Deleting %s\n", str); ++ device_del(dev); ++ } ++} ++ ++static int fbtft_device_spi_device_register(struct spi_board_info *spi) ++{ ++ struct spi_master *master; ++ ++ master = spi_busnum_to_master(spi->bus_num); ++ if (!master) { ++ pr_err(DRVNAME ": spi_busnum_to_master(%d) returned NULL\n", ++ spi->bus_num); ++ return -EINVAL; ++ } ++ /* make sure it's available */ ++ fbtft_device_spi_delete(master, spi->chip_select); ++ spi_device = spi_new_device(master, spi); ++ put_device(&master->dev); ++ if (!spi_device) { ++ pr_err(DRVNAME ": spi_new_device() returned NULL\n"); ++ return -EPERM; ++ } ++ return 0; ++} ++#else ++static int fbtft_device_spi_device_register(struct spi_board_info *spi) ++{ ++ return spi_register_board_info(spi, 1); ++} ++#endif ++ ++static int __init fbtft_device_init(void) ++{ ++ struct spi_board_info *spi = NULL; ++ struct fbtft_platform_data *pdata; ++ const struct fbtft_gpio *gpio = NULL; ++ char *p_gpio, *p_name, *p_num; ++ bool found = false; ++ int i = 0; ++ long val; ++ int ret = 0; ++ ++ pr_debug("\n\n"DRVNAME": init\n"); ++ ++ if (name == NULL) { ++#ifdef MODULE ++ pr_err(DRVNAME": missing module parameter: 'name'\n"); ++ return -EINVAL; ++#else ++ return 0; ++#endif ++ } ++ ++ if (init_num > FBTFT_MAX_INIT_SEQUENCE) { ++ pr_err(DRVNAME \ ++ ": init parameter: exceeded max array size: %d\n", ++ FBTFT_MAX_INIT_SEQUENCE); ++ return -EINVAL; ++ } ++ ++ /* parse module parameter: gpios */ ++ while ((p_gpio = strsep(&gpios, ","))) { ++ if (strchr(p_gpio, ':') == NULL) { ++ pr_err(DRVNAME \ ++ ": error: missing ':' in gpios parameter: %s\n", ++ p_gpio); ++ return -EINVAL; ++ } ++ p_num = p_gpio; ++ p_name = strsep(&p_num, ":"); ++ if (p_name == NULL || p_num == NULL) { ++ pr_err(DRVNAME \ ++ ": something bad happened parsing gpios parameter: %s\n", ++ p_gpio); ++ return -EINVAL; ++ } ++ ret = kstrtol(p_num, 10, &val); ++ if (ret) { ++ pr_err(DRVNAME \ ++ ": could not parse number in gpios parameter: %s:%s\n", ++ p_name, p_num); ++ return -EINVAL; ++ } ++ strcpy(fbtft_device_param_gpios[i].name, p_name); ++ fbtft_device_param_gpios[i++].gpio = (int) val; ++ if (i == MAX_GPIOS) { ++ pr_err(DRVNAME \ ++ ": gpios parameter: exceeded max array size: %d\n", ++ MAX_GPIOS); ++ return -EINVAL; ++ } ++ } ++ if (fbtft_device_param_gpios[0].name[0]) ++ gpio = fbtft_device_param_gpios; ++ ++ if (verbose > 2) ++ pr_spi_devices(); /* print list of registered SPI devices */ ++ ++ if (verbose > 2) ++ pr_p_devices(); /* print list of 'fb' platform devices */ ++ ++ pr_debug(DRVNAME": name='%s', busnum=%d, cs=%d\n", name, busnum, cs); ++ ++ if (rotate > 0 && rotate < 4) { ++ rotate = (4 - rotate) * 90; ++ pr_warn("argument 'rotate' should be an angle. Values 1-3 is deprecated. Setting it to %d.\n", ++ rotate); ++ } ++ if (rotate != 0 && rotate != 90 && rotate != 180 && rotate != 270) { ++ pr_warn("argument 'rotate' illegal value: %d. Setting it to 0.\n", ++ rotate); ++ rotate = 0; ++ } ++ ++ /* name=list lists all supported displays */ ++ if (strncmp(name, "list", 32) == 0) { ++ pr_info(DRVNAME": Supported displays:\n"); ++ ++ for (i = 0; i < ARRAY_SIZE(displays); i++) ++ pr_info(DRVNAME": %s\n", displays[i].name); ++ return -ECANCELED; ++ } ++ ++ if (custom) { ++ i = ARRAY_SIZE(displays) - 1; ++ displays[i].name = name; ++ if (speed == 0) { ++ displays[i].pdev->name = name; ++ displays[i].spi = NULL; ++ } else { ++ strncpy(displays[i].spi->modalias, name, SPI_NAME_SIZE); ++ displays[i].pdev = NULL; ++ } ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(displays); i++) { ++ if (strncmp(name, displays[i].name, 32) == 0) { ++ if (displays[i].spi) { ++ spi = displays[i].spi; ++ spi->chip_select = cs; ++ spi->bus_num = busnum; ++ if (speed) ++ spi->max_speed_hz = speed; ++ if (mode != -1) ++ spi->mode = mode; ++ pdata = (void *)spi->platform_data; ++ } else if (displays[i].pdev) { ++ p_device = displays[i].pdev; ++ pdata = p_device->dev.platform_data; ++ } else { ++ pr_err(DRVNAME": broken displays array\n"); ++ return -EINVAL; ++ } ++ ++ pdata->rotate = rotate; ++ if (bgr == 0) ++ pdata->bgr = false; ++ else if (bgr == 1) ++ pdata->bgr = true; ++ if (startbyte) ++ pdata->startbyte = startbyte; ++ if (gamma) ++ pdata->gamma = gamma; ++ pdata->display.debug = debug; ++ if (fps) ++ pdata->fps = fps; ++ if (txbuflen) ++ pdata->txbuflen = txbuflen; ++ if (init_num) ++ pdata->display.init_sequence = init; ++ if (gpio) ++ pdata->gpios = gpio; ++ if (custom) { ++ pdata->display.width = width; ++ pdata->display.height = height; ++ pdata->display.buswidth = buswidth; ++ pdata->display.backlight = 1; ++ } ++ ++ if (displays[i].spi) { ++ ret = fbtft_device_spi_device_register(spi); ++ if (ret) { ++ pr_err(DRVNAME \ ++ ": failed to register SPI device\n"); ++ return ret; ++ } ++ found = true; ++ break; ++ } else { ++ ret = platform_device_register(p_device); ++ if (ret < 0) { ++ pr_err(DRVNAME \ ++ ": platform_device_register() returned %d\n", ++ ret); ++ return ret; ++ } ++ found = true; ++ break; ++ } ++ } ++ } ++ ++ if (!found) { ++ pr_err(DRVNAME": display not supported: '%s'\n", name); ++ return -EINVAL; ++ } ++ ++ if (verbose && pdata && pdata->gpios) { ++ gpio = pdata->gpios; ++ pr_info(DRVNAME": GPIOS used by '%s':\n", name); ++ found = false; ++ while (verbose && gpio->name[0]) { ++ pr_info(DRVNAME": '%s' = GPIO%d\n", ++ gpio->name, gpio->gpio); ++ gpio++; ++ found = true; ++ } ++ if (!found) ++ pr_info(DRVNAME": (none)\n"); ++ } ++ ++ if (spi_device && (verbose > 1)) ++ pr_spi_devices(); ++ if (p_device && (verbose > 1)) ++ pr_p_devices(); ++ ++ return 0; ++} ++ ++static void __exit fbtft_device_exit(void) ++{ ++ pr_debug(DRVNAME" - exit\n"); ++ ++ if (spi_device) { ++ device_del(&spi_device->dev); ++ kfree(spi_device); ++ } ++ ++ if (p_device) ++ platform_device_unregister(p_device); ++ ++} ++ ++arch_initcall(fbtft_device_init); ++module_exit(fbtft_device_exit); ++ ++MODULE_DESCRIPTION("Add a FBTFT device."); ++MODULE_AUTHOR("Noralf Tronnes"); ++MODULE_LICENSE("GPL"); + +From eb04b5cfea1d7375d0c3c90a387564d61b418a49 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Tue, 20 Jan 2015 23:40:26 +0100 +Subject: [PATCH 153/178] staging: fbtft: remove ARCH_BCM2708 optimization +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +ARCH_BCM2708 is not present in mainline so remove optimization. + +Signed-off-by: Noralf Trønnes +Reported-by: Paul Bolle +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/fbtft-io.c | 170 --------------------------------------- + 1 file changed, 170 deletions(-) + +diff --git a/drivers/staging/fbtft/fbtft-io.c b/drivers/staging/fbtft/fbtft-io.c +index dfa2c46..32155a7 100644 +--- a/drivers/staging/fbtft/fbtft-io.c ++++ b/drivers/staging/fbtft/fbtft-io.c +@@ -2,9 +2,6 @@ + #include + #include + #include +-#ifdef CONFIG_ARCH_BCM2708 +-#include +-#endif + #include "fbtft.h" + + int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len) +@@ -129,171 +126,6 @@ int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len) + } + EXPORT_SYMBOL(fbtft_read_spi); + +- +-#ifdef CONFIG_ARCH_BCM2708 +- +-/* +- * Raspberry Pi +- * - writing directly to the registers is 40-50% faster than +- * optimized use of gpiolib +- */ +- +-#define GPIOSET(no, ishigh) \ +-do { \ +- if (ishigh) \ +- set |= (1 << (no)); \ +- else \ +- reset |= (1 << (no)); \ +-} while (0) +- +-int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len) +-{ +- unsigned int set = 0; +- unsigned int reset = 0; +- u8 data; +- +- fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, +- "%s(len=%d): ", __func__, len); +- +- while (len--) { +- data = *(u8 *) buf; +- buf++; +- +- /* Set data */ +- GPIOSET(par->gpio.db[0], (data&0x01)); +- GPIOSET(par->gpio.db[1], (data&0x02)); +- GPIOSET(par->gpio.db[2], (data&0x04)); +- GPIOSET(par->gpio.db[3], (data&0x08)); +- GPIOSET(par->gpio.db[4], (data&0x10)); +- GPIOSET(par->gpio.db[5], (data&0x20)); +- GPIOSET(par->gpio.db[6], (data&0x40)); +- GPIOSET(par->gpio.db[7], (data&0x80)); +- writel(set, __io_address(GPIO_BASE+0x1C)); +- writel(reset, __io_address(GPIO_BASE+0x28)); +- +- /* Pulse /WR low */ +- writel((1<gpio.wr), __io_address(GPIO_BASE+0x28)); +- writel(0, __io_address(GPIO_BASE+0x28)); /* used as a delay */ +- writel((1<gpio.wr), __io_address(GPIO_BASE+0x1C)); +- +- set = 0; +- reset = 0; +- } +- +- return 0; +-} +-EXPORT_SYMBOL(fbtft_write_gpio8_wr); +- +-int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len) +-{ +- unsigned int set = 0; +- unsigned int reset = 0; +- u16 data; +- +- fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, +- "%s(len=%d): ", __func__, len); +- +- while (len) { +- len -= 2; +- data = *(u16 *) buf; +- buf += 2; +- +- /* Start writing by pulling down /WR */ +- gpio_set_value(par->gpio.wr, 0); +- +- /* Set data */ +- GPIOSET(par->gpio.db[0], (data&0x0001)); +- GPIOSET(par->gpio.db[1], (data&0x0002)); +- GPIOSET(par->gpio.db[2], (data&0x0004)); +- GPIOSET(par->gpio.db[3], (data&0x0008)); +- GPIOSET(par->gpio.db[4], (data&0x0010)); +- GPIOSET(par->gpio.db[5], (data&0x0020)); +- GPIOSET(par->gpio.db[6], (data&0x0040)); +- GPIOSET(par->gpio.db[7], (data&0x0080)); +- +- GPIOSET(par->gpio.db[8], (data&0x0100)); +- GPIOSET(par->gpio.db[9], (data&0x0200)); +- GPIOSET(par->gpio.db[10], (data&0x0400)); +- GPIOSET(par->gpio.db[11], (data&0x0800)); +- GPIOSET(par->gpio.db[12], (data&0x1000)); +- GPIOSET(par->gpio.db[13], (data&0x2000)); +- GPIOSET(par->gpio.db[14], (data&0x4000)); +- GPIOSET(par->gpio.db[15], (data&0x8000)); +- +- writel(set, __io_address(GPIO_BASE+0x1C)); +- writel(reset, __io_address(GPIO_BASE+0x28)); +- +- /* Pullup /WR */ +- gpio_set_value(par->gpio.wr, 1); +- +- set = 0; +- reset = 0; +- } +- +- return 0; +-} +-EXPORT_SYMBOL(fbtft_write_gpio16_wr); +- +-int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len) +-{ +- unsigned int set = 0; +- unsigned int reset = 0; +- u16 data; +- +- fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, +- "%s(len=%d): ", __func__, len); +- +- while (len) { +- len -= 2; +- data = *(u16 *) buf; +- buf += 2; +- +- /* Start writing by pulling down /WR */ +- gpio_set_value(par->gpio.wr, 0); +- +- /* Low byte */ +- GPIOSET(par->gpio.db[0], (data&0x0001)); +- GPIOSET(par->gpio.db[1], (data&0x0002)); +- GPIOSET(par->gpio.db[2], (data&0x0004)); +- GPIOSET(par->gpio.db[3], (data&0x0008)); +- GPIOSET(par->gpio.db[4], (data&0x0010)); +- GPIOSET(par->gpio.db[5], (data&0x0020)); +- GPIOSET(par->gpio.db[6], (data&0x0040)); +- GPIOSET(par->gpio.db[7], (data&0x0080)); +- writel(set, __io_address(GPIO_BASE+0x1C)); +- writel(reset, __io_address(GPIO_BASE+0x28)); +- +- /* Pulse 'latch' high */ +- gpio_set_value(par->gpio.latch, 1); +- gpio_set_value(par->gpio.latch, 0); +- +- /* High byte */ +- GPIOSET(par->gpio.db[0], (data&0x0100)); +- GPIOSET(par->gpio.db[1], (data&0x0200)); +- GPIOSET(par->gpio.db[2], (data&0x0400)); +- GPIOSET(par->gpio.db[3], (data&0x0800)); +- GPIOSET(par->gpio.db[4], (data&0x1000)); +- GPIOSET(par->gpio.db[5], (data&0x2000)); +- GPIOSET(par->gpio.db[6], (data&0x4000)); +- GPIOSET(par->gpio.db[7], (data&0x8000)); +- writel(set, __io_address(GPIO_BASE+0x1C)); +- writel(reset, __io_address(GPIO_BASE+0x28)); +- +- /* Pullup /WR */ +- gpio_set_value(par->gpio.wr, 1); +- +- set = 0; +- reset = 0; +- } +- +- return 0; +-} +-EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched); +- +-#undef GPIOSET +- +-#else +- + /* + * Optimized use of gpiolib is twice as fast as no optimization + * only one driver can use the optimized version at a time +@@ -405,5 +237,3 @@ int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len) + return -1; + } + EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched); +- +-#endif /* CONFIG_ARCH_BCM2708 */ + +From 904a001171d6e91b3901bfd7034fb71ac4f81593 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Fri, 23 Jan 2015 17:20:25 +0300 +Subject: [PATCH 154/178] staging: fbtft: fix allyesconfig build + +There are two functions call reset() so the allyesconfig breaks. Let's +make this one static. + +Reported-by: Jim Davis +Signed-off-by: Dan Carpenter +Tested-by: Jim Davis +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/fb_agm1264k-fl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c +index 7fe4fa0..9cc7d25 100644 +--- a/drivers/staging/fbtft/fb_agm1264k-fl.c ++++ b/drivers/staging/fbtft/fb_agm1264k-fl.c +@@ -89,7 +89,7 @@ static int init_display(struct fbtft_par *par) + return 0; + } + +-void reset(struct fbtft_par *par) ++static void reset(struct fbtft_par *par) + { + if (par->gpio.reset == -1) + return; + +From bfc8094c950203b4b8a5c992339ebf0accf88042 Mon Sep 17 00:00:00 2001 +From: Krzysztof Adamski +Date: Thu, 22 Jan 2015 19:08:58 +0100 +Subject: [PATCH 155/178] staging: fbtft: fbtft-core mark functions static + +This fixes sparse warnings like: + warning: symbol XXX was not declared. Should it be static? + +by declaring all local functions static. + +Signed-off-by: Krzysztof Adamski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/fbtft-core.c | 47 +++++++++++++++++++++----------------- + 1 file changed, 26 insertions(+), 21 deletions(-) + +diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c +index 873e2c7..37dcf7e 100644 +--- a/drivers/staging/fbtft/fbtft-core.c ++++ b/drivers/staging/fbtft/fbtft-core.c +@@ -79,7 +79,7 @@ void fbtft_dbg_hex(const struct device *dev, int groupsize, + } + EXPORT_SYMBOL(fbtft_dbg_hex); + +-unsigned long fbtft_request_gpios_match(struct fbtft_par *par, ++static unsigned long fbtft_request_gpios_match(struct fbtft_par *par, + const struct fbtft_gpio *gpio) + { + int ret; +@@ -123,7 +123,7 @@ unsigned long fbtft_request_gpios_match(struct fbtft_par *par, + return FBTFT_GPIO_NO_MATCH; + } + +-int fbtft_request_gpios(struct fbtft_par *par) ++static int fbtft_request_gpios(struct fbtft_par *par) + { + struct fbtft_platform_data *pdata = par->pdata; + const struct fbtft_gpio *gpio; +@@ -249,7 +249,7 @@ static int fbtft_request_gpios_dt(struct fbtft_par *par) + #endif + + #ifdef CONFIG_FB_BACKLIGHT +-int fbtft_backlight_update_status(struct backlight_device *bd) ++static int fbtft_backlight_update_status(struct backlight_device *bd) + { + struct fbtft_par *par = bl_get_data(bd); + bool polarity = !!(bd->props.state & BL_CORE_DRIVER1); +@@ -266,7 +266,7 @@ int fbtft_backlight_update_status(struct backlight_device *bd) + return 0; + } + +-int fbtft_backlight_get_brightness(struct backlight_device *bd) ++static int fbtft_backlight_get_brightness(struct backlight_device *bd) + { + return bd->props.brightness; + } +@@ -337,7 +337,8 @@ void fbtft_unregister_backlight(struct fbtft_par *par) { }; + EXPORT_SYMBOL(fbtft_register_backlight); + EXPORT_SYMBOL(fbtft_unregister_backlight); + +-void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) ++static void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, ++ int ye) + { + fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, + "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); +@@ -355,7 +356,7 @@ void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) + } + + +-void fbtft_reset(struct fbtft_par *par) ++static void fbtft_reset(struct fbtft_par *par) + { + if (par->gpio.reset == -1) + return; +@@ -367,7 +368,8 @@ void fbtft_reset(struct fbtft_par *par) + } + + +-void fbtft_update_display(struct fbtft_par *par, unsigned start_line, unsigned end_line) ++static void fbtft_update_display(struct fbtft_par *par, unsigned start_line, ++ unsigned end_line) + { + size_t offset, len; + struct timespec ts_start, ts_end, ts_fps, ts_duration; +@@ -445,7 +447,7 @@ void fbtft_update_display(struct fbtft_par *par, unsigned start_line, unsigned e + } + + +-void fbtft_mkdirty(struct fb_info *info, int y, int height) ++static void fbtft_mkdirty(struct fb_info *info, int y, int height) + { + struct fbtft_par *par = info->par; + struct fb_deferred_io *fbdefio = info->fbdefio; +@@ -468,7 +470,7 @@ void fbtft_mkdirty(struct fb_info *info, int y, int height) + schedule_delayed_work(&info->deferred_work, fbdefio->delay); + } + +-void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) ++static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) + { + struct fbtft_par *par = info->par; + unsigned dirty_lines_start, dirty_lines_end; +@@ -507,7 +509,8 @@ void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist) + } + + +-void fbtft_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ++static void fbtft_fb_fillrect(struct fb_info *info, ++ const struct fb_fillrect *rect) + { + struct fbtft_par *par = info->par; + +@@ -519,7 +522,8 @@ void fbtft_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) + par->fbtftops.mkdirty(info, rect->dy, rect->height); + } + +-void fbtft_fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) ++static void fbtft_fb_copyarea(struct fb_info *info, ++ const struct fb_copyarea *area) + { + struct fbtft_par *par = info->par; + +@@ -531,7 +535,8 @@ void fbtft_fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) + par->fbtftops.mkdirty(info, area->dy, area->height); + } + +-void fbtft_fb_imageblit(struct fb_info *info, const struct fb_image *image) ++static void fbtft_fb_imageblit(struct fb_info *info, ++ const struct fb_image *image) + { + struct fbtft_par *par = info->par; + +@@ -543,8 +548,8 @@ void fbtft_fb_imageblit(struct fb_info *info, const struct fb_image *image) + par->fbtftops.mkdirty(info, image->dy, image->height); + } + +-ssize_t fbtft_fb_write(struct fb_info *info, +- const char __user *buf, size_t count, loff_t *ppos) ++static ssize_t fbtft_fb_write(struct fb_info *info, const char __user *buf, ++ size_t count, loff_t *ppos) + { + struct fbtft_par *par = info->par; + ssize_t res; +@@ -561,16 +566,16 @@ ssize_t fbtft_fb_write(struct fb_info *info, + } + + /* from pxafb.c */ +-unsigned int chan_to_field(unsigned chan, struct fb_bitfield *bf) ++static unsigned int chan_to_field(unsigned chan, struct fb_bitfield *bf) + { + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; + } + +-int fbtft_fb_setcolreg(unsigned regno, +- unsigned red, unsigned green, unsigned blue, +- unsigned transp, struct fb_info *info) ++static int fbtft_fb_setcolreg(unsigned regno, unsigned red, unsigned green, ++ unsigned blue, unsigned transp, ++ struct fb_info *info) + { + struct fbtft_par *par = info->par; + unsigned val; +@@ -598,7 +603,7 @@ int fbtft_fb_setcolreg(unsigned regno, + return ret; + } + +-int fbtft_fb_blank(int blank, struct fb_info *info) ++static int fbtft_fb_blank(int blank, struct fb_info *info) + { + struct fbtft_par *par = info->par; + int ret = -EINVAL; +@@ -623,7 +628,7 @@ int fbtft_fb_blank(int blank, struct fb_info *info) + return ret; + } + +-void fbtft_merge_fbtftops(struct fbtft_ops *dst, struct fbtft_ops *src) ++static void fbtft_merge_fbtftops(struct fbtft_ops *dst, struct fbtft_ops *src) + { + if (src->write) + dst->write = src->write; +@@ -1265,7 +1270,7 @@ EXPORT_SYMBOL(fbtft_init_display); + * + * Return: 0 if successful, negative if error + */ +-int fbtft_verify_gpios(struct fbtft_par *par) ++static int fbtft_verify_gpios(struct fbtft_par *par) + { + struct fbtft_platform_data *pdata; + int i; + +From 7816ff363be5d596daf3c4d7fad80801f30a5865 Mon Sep 17 00:00:00 2001 +From: Mauro Stettler +Date: Sun, 25 Jan 2015 20:26:17 +0900 +Subject: [PATCH 156/178] staging: flexfb: Remove initialization to 0 + +(the initial post had a typo in the short summary, reposting) + +This fixes some of the code style issues in the flexfb driver by removing +unnecessary initializations of static variables to 0 or to NULL. + +Signed-off-by: Mauro Stettler +Cc: Greg Kroah-Hartman +Cc: Thomas Petazzoni +Cc: Noralf Tronnes +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/flexfb.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c +index 45574a0..4eec888 100644 +--- a/drivers/staging/fbtft/flexfb.c ++++ b/drivers/staging/fbtft/flexfb.c +@@ -31,24 +31,24 @@ + #define DRVNAME "flexfb" + + +-static char *chip = NULL; ++static char *chip; + module_param(chip, charp, 0); + MODULE_PARM_DESC(chip, "LCD controller"); + +-static unsigned int width = 0; ++static unsigned int width; + module_param(width, uint, 0); + MODULE_PARM_DESC(width, "Display width"); + +-static unsigned int height = 0; ++static unsigned int height; + module_param(height, uint, 0); + MODULE_PARM_DESC(height, "Display height"); + + static int init[512]; +-static int init_num = 0; ++static int init_num; + module_param_array(init, int, &init_num, 0); + MODULE_PARM_DESC(init, "Init sequence"); + +-static unsigned int setaddrwin = 0; ++static unsigned int setaddrwin; + module_param(setaddrwin, uint, 0); + MODULE_PARM_DESC(setaddrwin, "Which set_addr_win() implementation to use"); + +@@ -60,17 +60,17 @@ static unsigned int regwidth = 8; + module_param(regwidth, uint, 0); + MODULE_PARM_DESC(regwidth, "Width of controller register (default: 8)"); + +-static bool nobacklight = false; ++static bool nobacklight; + module_param(nobacklight, bool, 0); + MODULE_PARM_DESC(nobacklight, "Turn off backlight functionality."); + +-static bool latched = false; ++static bool latched; + module_param(latched, bool, 0); + MODULE_PARM_DESC(latched, "Use with latched 16-bit databus"); + + +-static int *initp = NULL; +-static int initp_num = 0; ++static int *initp; ++static int initp_num; + + /* default init sequences */ + static int st7735r_init[] = { \ + +From 06d3386d0955feadd86e6805e9e0d55c6d14503e Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:33:03 +0200 +Subject: [PATCH 157/178] staging: fbtft: fix space required after that ';' + +This patch fixes the following checkpatch.pl error: +fix space required after that ';' + +Signed-off-by: Heba Aamer +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/fb_pcd8544.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/fbtft/fb_pcd8544.c b/drivers/staging/fbtft/fb_pcd8544.c +index c4f2a5b..a5f0ad4 100644 +--- a/drivers/staging/fbtft/fb_pcd8544.c ++++ b/drivers/staging/fbtft/fb_pcd8544.c +@@ -117,10 +117,10 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) + + fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); + +- for (x=0;x<84;x++) { +- for (y=0;y<6;y++) { ++ for (x=0; x<84; x++) { ++ for (y=0; y<6; y++) { + *buf = 0x00; +- for (i=0;i<8;i++) { ++ for (i=0; i<8; i++) { + *buf |= (vmem16[(y*8+i)*84+x] ? 1 : 0) << i; + } + buf++; + +From b9d35fa923f4de78373dc58d8c506ddd89452c08 Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:35:30 +0200 +Subject: [PATCH 158/178] staging: fbtft: fix spaces required around that '=' + +This patch fixes the following checkpatch.pl error: +fix spaces required around that '=' + +Signed-off-by: Heba Aamer +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/fb_pcd8544.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/fbtft/fb_pcd8544.c b/drivers/staging/fbtft/fb_pcd8544.c +index a5f0ad4..e44eecb 100644 +--- a/drivers/staging/fbtft/fb_pcd8544.c ++++ b/drivers/staging/fbtft/fb_pcd8544.c +@@ -117,10 +117,10 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) + + fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); + +- for (x=0; x<84; x++) { +- for (y=0; y<6; y++) { ++ for (x = 0; x<84; x++) { ++ for (y = 0; y<6; y++) { + *buf = 0x00; +- for (i=0; i<8; i++) { ++ for (i = 0; i<8; i++) { + *buf |= (vmem16[(y*8+i)*84+x] ? 1 : 0) << i; + } + buf++; + +From 0efa123797fdbacc654e21a38c630fe19e1cf7d4 Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:37:24 +0200 +Subject: [PATCH 159/178] staging: fbtft: fix spaces required around that '<' + +This patch fixes the following checkpatch.pl error: +fix spaces required around that '<' + +Signed-off-by: Heba Aamer +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/fb_pcd8544.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/fbtft/fb_pcd8544.c b/drivers/staging/fbtft/fb_pcd8544.c +index e44eecb..ab46ccf 100644 +--- a/drivers/staging/fbtft/fb_pcd8544.c ++++ b/drivers/staging/fbtft/fb_pcd8544.c +@@ -117,10 +117,10 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) + + fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); + +- for (x = 0; x<84; x++) { +- for (y = 0; y<6; y++) { ++ for (x = 0; x < 84; x++) { ++ for (y = 0; y < 6; y++) { + *buf = 0x00; +- for (i = 0; i<8; i++) { ++ for (i = 0; i < 8; i++) { + *buf |= (vmem16[(y*8+i)*84+x] ? 1 : 0) << i; + } + buf++; + +From faba25927f4fb7c09c8d568a9e85cbde97c72deb Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:39:56 +0200 +Subject: [PATCH 160/178] staging: fbtft: fix Macros with complex values should + be enclosed in parentheses + +This patch fixes the following checkpatch.pl error: +fix Macros with complex values should be enclosed in parentheses + +Signed-off-by: Heba Aamer +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/fb_pcd8544.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/fbtft/fb_pcd8544.c b/drivers/staging/fbtft/fb_pcd8544.c +index ab46ccf..1d1a865 100644 +--- a/drivers/staging/fbtft/fb_pcd8544.c ++++ b/drivers/staging/fbtft/fb_pcd8544.c +@@ -33,7 +33,7 @@ + #define DRVNAME "fb_pcd8544" + #define WIDTH 84 + #define HEIGHT 48 +-#define TXBUFLEN 84*6 ++#define TXBUFLEN (84*6) + #define DEFAULT_GAMMA "40" /* gamma is used to control contrast in this driver */ + + static unsigned tc = 0; + +From c6c1da7ddd2dc40aa628a627f8c837186584e934 Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:42:59 +0200 +Subject: [PATCH 161/178] staging: fbtft: fix do not initialise statics to 0 or + NULL + +This patch fixes the following checkpatch.pl error: +fix do not initialise statics to 0 or NULL + +Signed-off-by: Heba Aamer +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/fb_pcd8544.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/fbtft/fb_pcd8544.c b/drivers/staging/fbtft/fb_pcd8544.c +index 1d1a865..8b9ebfb 100644 +--- a/drivers/staging/fbtft/fb_pcd8544.c ++++ b/drivers/staging/fbtft/fb_pcd8544.c +@@ -36,7 +36,7 @@ + #define TXBUFLEN (84*6) + #define DEFAULT_GAMMA "40" /* gamma is used to control contrast in this driver */ + +-static unsigned tc = 0; ++static unsigned tc; + module_param(tc, uint, 0); + MODULE_PARM_DESC(tc, "TC[1:0] Temperature coefficient: 0-3 (default: 0)"); + + +From 486d0c392744ec2d4e7dcecebb2703c456a1b171 Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Wed, 28 Jan 2015 15:29:05 +0200 +Subject: [PATCH 162/178] staging: fbtft: remove redundant .owner + +This patch fixes the following coccicheck warning: +No need to set .owner here. The core will do it. + +Signed-off-by: Heba Aamer +Signed-off-by: Greg Kroah-Hartman +--- + drivers/staging/fbtft/flexfb.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c +index 4eec888..90832c3 100644 +--- a/drivers/staging/fbtft/flexfb.c ++++ b/drivers/staging/fbtft/flexfb.c +@@ -559,7 +559,6 @@ static const struct platform_device_id flexfb_platform_ids[] = { + static struct platform_driver flexfb_platform_driver = { + .driver = { + .name = DRVNAME, +- .owner = THIS_MODULE, + }, + .id_table = flexfb_platform_ids, + .probe = flexfb_probe_pdev, + +From 6beb92f3025352d64cfadd06a4e1bd47c96baa91 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Wed, 18 Feb 2015 22:49:42 +0100 +Subject: [PATCH 163/178] config: enable FBTFT drivers + +--- + arch/arm/configs/bcm2709_defconfig | 28 ++++++++++++++++++++++++++++ + arch/arm/configs/bcmrpi_defconfig | 28 ++++++++++++++++++++++++++++ + 2 files changed, 56 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index d4c18fa..2e68695 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -1016,6 +1016,34 @@ CONFIG_LIRC_IMON=m + CONFIG_LIRC_RPI=m + CONFIG_LIRC_SASEM=m + CONFIG_LIRC_SERIAL=m ++CONFIG_FB_TFT=m ++CONFIG_FB_TFT_AGM1264K_FL=m ++CONFIG_FB_TFT_BD663474=m ++CONFIG_FB_TFT_HX8340BN=m ++CONFIG_FB_TFT_HX8347D=m ++CONFIG_FB_TFT_HX8353D=m ++CONFIG_FB_TFT_ILI9320=m ++CONFIG_FB_TFT_ILI9325=m ++CONFIG_FB_TFT_ILI9340=m ++CONFIG_FB_TFT_ILI9341=m ++CONFIG_FB_TFT_ILI9481=m ++CONFIG_FB_TFT_ILI9486=m ++CONFIG_FB_TFT_PCD8544=m ++CONFIG_FB_TFT_RA8875=m ++CONFIG_FB_TFT_S6D02A1=m ++CONFIG_FB_TFT_S6D1121=m ++CONFIG_FB_TFT_SSD1289=m ++CONFIG_FB_TFT_SSD1306=m ++CONFIG_FB_TFT_SSD1331=m ++CONFIG_FB_TFT_SSD1351=m ++CONFIG_FB_TFT_ST7735R=m ++CONFIG_FB_TFT_TINYLCD=m ++CONFIG_FB_TFT_TLS8204=m ++CONFIG_FB_TFT_UC1701=m ++CONFIG_FB_TFT_UPD161704=m ++CONFIG_FB_TFT_WATTEROTT=m ++CONFIG_FB_FLEX=m ++CONFIG_FB_TFT_FBTFT_DEVICE=m + # CONFIG_IOMMU_SUPPORT is not set + CONFIG_EXTCON=m + CONFIG_EXTCON_ARIZONA=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 898ebd2..8674822 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -1009,6 +1009,34 @@ CONFIG_LIRC_IMON=m + CONFIG_LIRC_RPI=m + CONFIG_LIRC_SASEM=m + CONFIG_LIRC_SERIAL=m ++CONFIG_FB_TFT=m ++CONFIG_FB_TFT_AGM1264K_FL=m ++CONFIG_FB_TFT_BD663474=m ++CONFIG_FB_TFT_HX8340BN=m ++CONFIG_FB_TFT_HX8347D=m ++CONFIG_FB_TFT_HX8353D=m ++CONFIG_FB_TFT_ILI9320=m ++CONFIG_FB_TFT_ILI9325=m ++CONFIG_FB_TFT_ILI9340=m ++CONFIG_FB_TFT_ILI9341=m ++CONFIG_FB_TFT_ILI9481=m ++CONFIG_FB_TFT_ILI9486=m ++CONFIG_FB_TFT_PCD8544=m ++CONFIG_FB_TFT_RA8875=m ++CONFIG_FB_TFT_S6D02A1=m ++CONFIG_FB_TFT_S6D1121=m ++CONFIG_FB_TFT_SSD1289=m ++CONFIG_FB_TFT_SSD1306=m ++CONFIG_FB_TFT_SSD1331=m ++CONFIG_FB_TFT_SSD1351=m ++CONFIG_FB_TFT_ST7735R=m ++CONFIG_FB_TFT_TINYLCD=m ++CONFIG_FB_TFT_TLS8204=m ++CONFIG_FB_TFT_UC1701=m ++CONFIG_FB_TFT_UPD161704=m ++CONFIG_FB_TFT_WATTEROTT=m ++CONFIG_FB_FLEX=m ++CONFIG_FB_TFT_FBTFT_DEVICE=m + # CONFIG_IOMMU_SUPPORT is not set + CONFIG_EXTCON=m + CONFIG_EXTCON_ARIZONA=m + +From 1c3993986d73da1755d2dfa7e66ced306ab5cc4e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Thu, 26 Feb 2015 21:24:05 +0100 +Subject: [PATCH 164/178] dts: overlay: add support for rpi-display +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add Device Tree overlay for rpi-display by Watterott. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/rpi-display-overlay.dts | 81 +++++++++++++++++++++++++++++++ + 2 files changed, 82 insertions(+) + create mode 100644 arch/arm/boot/dts/rpi-display-overlay.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 56830ef..9eb5e05 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -75,6 +75,7 @@ dtb-$(RPI_DT_OVERLAYS) += lirc-rpi-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pcf2127-rtc-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pcf8523-rtc-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb +diff --git a/arch/arm/boot/dts/rpi-display-overlay.dts b/arch/arm/boot/dts/rpi-display-overlay.dts +new file mode 100644 +index 0000000..0578810 +--- /dev/null ++++ b/arch/arm/boot/dts/rpi-display-overlay.dts +@@ -0,0 +1,81 @@ ++/* ++ * Device Tree overlay for rpi-display by Watterott ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ rpi_display_pins: rpi_display_pins { ++ brcm,pins = <18 23 24 25>; ++ brcm,function = <1 1 1 0>; /* out out out in */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rpidisplay: rpi-display@0{ ++ compatible = "ilitek,ili9341"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rpi_display_pins>; ++ ++ spi-max-frequency = <32000000>; ++ rotate = <270>; ++ bgr; ++ fps = <30>; ++ buswidth = <8>; ++ reset-gpios = <&gpio 23 0>; ++ dc-gpios = <&gpio 24 0>; ++ led-gpios = <&gpio 18 1>; ++ debug = <0>; ++ }; ++ ++ rpidisplay_ts: rpi-display-ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <25 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 25 0>; ++ ti,x-plate-ohms = /bits/ 16 <60>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&rpidisplay>,"spi-max-frequency:0"; ++ rotate = <&rpidisplay>,"rotate:0"; ++ fps = <&rpidisplay>,"fps:0"; ++ debug = <&rpidisplay>,"debug:0"; ++ xohms = <&rpidisplay_ts>,"ti,x-plate-ohms;0"; ++ }; ++}; + +From 1e331ec363f7a5792bc8e32ec7d1a893c22b9485 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Thu, 26 Feb 2015 21:36:27 +0100 +Subject: [PATCH 165/178] dts: overlay: add support for HY28A display +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add Device Tree overlay for HY28A display by HAOYU Electronics. +Default values are set to match Texy's display shield. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/hy28a-overlay.dts | 87 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 88 insertions(+) + create mode 100644 arch/arm/boot/dts/hy28a-overlay.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 9eb5e05..eef6f6d 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -69,6 +69,7 @@ dtb-$(RPI_DT_OVERLAYS) += hifiberry-dac-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-dacplus-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-digi-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-amp-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += hy28a-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += iqaudio-dac-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += iqaudio-dacplus-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += lirc-rpi-overlay.dtb +diff --git a/arch/arm/boot/dts/hy28a-overlay.dts b/arch/arm/boot/dts/hy28a-overlay.dts +new file mode 100644 +index 0000000..3cd3083 +--- /dev/null ++++ b/arch/arm/boot/dts/hy28a-overlay.dts +@@ -0,0 +1,87 @@ ++/* ++ * Device Tree overlay for HY28A display ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ hy28a_pins: hy28a_pins { ++ brcm,pins = <17 25 18>; ++ brcm,function = <0 1 1>; /* in out out */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ hy28a: hy28a@0{ ++ compatible = "ilitek,ili9320"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hy28a_pins>; ++ ++ spi-max-frequency = <32000000>; ++ spi-cpol; ++ spi-cpha; ++ rotate = <270>; ++ bgr; ++ fps = <50>; ++ buswidth = <8>; ++ startbyte = <0x70>; ++ reset-gpios = <&gpio 25 0>; ++ led-gpios = <&gpio 18 1>; ++ debug = <0>; ++ }; ++ ++ hy28a_ts: hy28a-ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <17 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 17 0>; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&hy28a>,"spi-max-frequency:0"; ++ rotate = <&hy28a>,"rotate:0"; ++ fps = <&hy28a>,"fps:0"; ++ debug = <&hy28a>,"debug:0"; ++ xohms = <&hy28a_ts>,"ti,x-plate-ohms;0"; ++ resetgpio = <&hy28a>,"reset-gpios:4", ++ <&hy28a_pins>, "brcm,pins:1"; ++ ledgpio = <&hy28a>,"led-gpios:4", ++ <&hy28a_pins>, "brcm,pins:2"; ++ }; ++}; + +From 7ff39cec76419644cf4985d656d613a66875489b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Thu, 26 Feb 2015 21:38:00 +0100 +Subject: [PATCH 166/178] dts: overlay: add support for HY28B display +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add Device Tree overlay for HY28B display by HAOYU Electronics. +Default values are set to match Texy's display shield. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/hy28b-overlay.dts | 142 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 143 insertions(+) + create mode 100644 arch/arm/boot/dts/hy28b-overlay.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index eef6f6d..c08e9fc 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -70,6 +70,7 @@ dtb-$(RPI_DT_OVERLAYS) += hifiberry-dacplus-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-digi-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-amp-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hy28a-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += hy28b-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += iqaudio-dac-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += iqaudio-dacplus-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += lirc-rpi-overlay.dtb +diff --git a/arch/arm/boot/dts/hy28b-overlay.dts b/arch/arm/boot/dts/hy28b-overlay.dts +new file mode 100644 +index 0000000..f774c4a +--- /dev/null ++++ b/arch/arm/boot/dts/hy28b-overlay.dts +@@ -0,0 +1,142 @@ ++/* ++ * Device Tree overlay for HY28b display shield by Texy ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ hy28b_pins: hy28b_pins { ++ brcm,pins = <17 25 18>; ++ brcm,function = <0 1 1>; /* in out out */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ hy28b: hy28b@0{ ++ compatible = "ilitek,ili9325"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hy28b_pins>; ++ ++ spi-max-frequency = <48000000>; ++ spi-cpol; ++ spi-cpha; ++ rotate = <270>; ++ bgr; ++ fps = <50>; ++ buswidth = <8>; ++ startbyte = <0x70>; ++ reset-gpios = <&gpio 25 0>; ++ led-gpios = <&gpio 18 1>; ++ ++ gamma = "04 1F 4 7 7 0 7 7 6 0\n0F 00 1 7 4 0 0 0 6 7"; ++ ++ init = <0x10000e7 0x0010 ++ 0x1000000 0x0001 ++ 0x1000001 0x0100 ++ 0x1000002 0x0700 ++ 0x1000003 0x1030 ++ 0x1000004 0x0000 ++ 0x1000008 0x0207 ++ 0x1000009 0x0000 ++ 0x100000a 0x0000 ++ 0x100000c 0x0001 ++ 0x100000d 0x0000 ++ 0x100000f 0x0000 ++ 0x1000010 0x0000 ++ 0x1000011 0x0007 ++ 0x1000012 0x0000 ++ 0x1000013 0x0000 ++ 0x2000032 ++ 0x1000010 0x1590 ++ 0x1000011 0x0227 ++ 0x2000032 ++ 0x1000012 0x009c ++ 0x2000032 ++ 0x1000013 0x1900 ++ 0x1000029 0x0023 ++ 0x100002b 0x000e ++ 0x2000032 ++ 0x1000020 0x0000 ++ 0x1000021 0x0000 ++ 0x2000032 ++ 0x1000050 0x0000 ++ 0x1000051 0x00ef ++ 0x1000052 0x0000 ++ 0x1000053 0x013f ++ 0x1000060 0xa700 ++ 0x1000061 0x0001 ++ 0x100006a 0x0000 ++ 0x1000080 0x0000 ++ 0x1000081 0x0000 ++ 0x1000082 0x0000 ++ 0x1000083 0x0000 ++ 0x1000084 0x0000 ++ 0x1000085 0x0000 ++ 0x1000090 0x0010 ++ 0x1000092 0x0000 ++ 0x1000093 0x0003 ++ 0x1000095 0x0110 ++ 0x1000097 0x0000 ++ 0x1000098 0x0000 ++ 0x1000007 0x0133 ++ 0x1000020 0x0000 ++ 0x1000021 0x0000 ++ 0x2000064>; ++ debug = <0>; ++ }; ++ ++ hy28b_ts: hy28b-ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <17 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 17 0>; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&hy28b>,"spi-max-frequency:0"; ++ rotate = <&hy28b>,"rotate:0"; ++ fps = <&hy28b>,"fps:0"; ++ debug = <&hy28b>,"debug:0"; ++ xohms = <&hy28b_ts>,"ti,x-plate-ohms;0"; ++ resetgpio = <&hy28b>,"reset-gpios:4", ++ <&hy28b_pins>, "brcm,pins:1"; ++ ledgpio = <&hy28b>,"led-gpios:4", ++ <&hy28b_pins>, "brcm,pins:2"; ++ }; ++}; + +From f07dc05ff1cc107accff6c4ca65fa3515d369d2f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Thu, 26 Feb 2015 21:38:47 +0100 +Subject: [PATCH 167/178] dts: overlay: add support for PiScreen display +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add Device Tree overlay for PiScreen display by OzzMaker.com + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/piscreen-overlay.dts | 94 ++++++++++++++++++++++++++++++++++ + 2 files changed, 95 insertions(+) + create mode 100644 arch/arm/boot/dts/piscreen-overlay.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index c08e9fc..f411750 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -76,6 +76,7 @@ dtb-$(RPI_DT_OVERLAYS) += iqaudio-dacplus-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += lirc-rpi-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pcf2127-rtc-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pcf8523-rtc-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb +diff --git a/arch/arm/boot/dts/piscreen-overlay.dts b/arch/arm/boot/dts/piscreen-overlay.dts +new file mode 100644 +index 0000000..8cd6a95 +--- /dev/null ++++ b/arch/arm/boot/dts/piscreen-overlay.dts +@@ -0,0 +1,94 @@ ++/* ++ * Device Tree overlay for PiScreen 3.5" display shield by Ozzmaker ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ piscreen_pins: piscreen_pins { ++ brcm,pins = <17 25 24 22>; ++ brcm,function = <0 1 1 1>; /* in out out out */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ piscreen: piscreen@0{ ++ compatible = "ilitek,ili9486"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&piscreen_pins>; ++ ++ spi-max-frequency = <32000000>; ++ rotate = <270>; ++ bgr; ++ fps = <30>; ++ buswidth = <8>; ++ regwidth = <16>; ++ reset-gpios = <&gpio 25 0>; ++ dc-gpios = <&gpio 24 0>; ++ led-gpios = <&gpio 22 1>; ++ debug = <0>; ++ ++ init = <0x10000b0 0x00 ++ 0x1000011 ++ 0x20000ff ++ 0x100003a 0x55 ++ 0x1000036 0x28 ++ 0x10000c2 0x44 ++ 0x10000c5 0x00 0x00 0x00 0x00 ++ 0x10000e0 0x0f 0x1f 0x1c 0x0c 0x0f 0x08 0x48 0x98 0x37 0x0a 0x13 0x04 0x11 0x0d 0x00 ++ 0x10000e1 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 ++ 0x10000e2 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 ++ 0x1000011 ++ 0x1000029>; ++ }; ++ ++ piscreen-ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <17 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 17 0>; ++ ti,x-plate-ohms = /bits/ 16 <100>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&piscreen>,"spi-max-frequency:0"; ++ rotate = <&piscreen>,"rotate:0"; ++ fps = <&piscreen>,"fps:0"; ++ debug = <&piscreen>,"debug:0"; ++ }; ++}; + +From ec576f9b4efb3c8c7940f1e9bd63d01b16b6e7d1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Fri, 27 Feb 2015 18:16:51 +0100 +Subject: [PATCH 168/178] config: enable TOUCHSCREEN_STMPE and GPIO_BACKLIGHT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Needed by the Adafruit PiTFT 2.8" resistive touch screen + +Signed-off-by: Noralf Trønnes +--- + arch/arm/configs/bcm2709_defconfig | 5 +++++ + arch/arm/configs/bcmrpi_defconfig | 5 +++++ + 2 files changed, 10 insertions(+) + +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 2e68695..559fb04 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -527,6 +527,7 @@ CONFIG_JOYSTICK_XPAD=m + CONFIG_JOYSTICK_XPAD_FF=y + CONFIG_INPUT_TOUCHSCREEN=y + CONFIG_TOUCHSCREEN_ADS7846=m ++CONFIG_TOUCHSCREEN_STMPE=m + CONFIG_INPUT_MISC=y + CONFIG_INPUT_AD714X=m + CONFIG_INPUT_ATI_REMOTE2=m +@@ -567,6 +568,7 @@ CONFIG_PPS_CLIENT_LDISC=m + CONFIG_PPS_CLIENT_GPIO=m + CONFIG_GPIO_SYSFS=y + CONFIG_GPIO_ARIZONA=m ++CONFIG_GPIO_STMPE=y + CONFIG_W1=m + CONFIG_W1_MASTER_DS2490=m + CONFIG_W1_MASTER_DS2482=m +@@ -592,6 +594,8 @@ CONFIG_THERMAL_BCM2835=y + CONFIG_WATCHDOG=y + CONFIG_BCM2708_WDT=m + CONFIG_UCB1400_CORE=m ++CONFIG_MFD_STMPE=y ++CONFIG_STMPE_SPI=y + CONFIG_MFD_ARIZONA_I2C=m + CONFIG_MFD_ARIZONA_SPI=m + CONFIG_MFD_WM5102=y +@@ -763,6 +767,7 @@ CONFIG_VIDEO_MT9V011=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y + # CONFIG_BACKLIGHT_GENERIC is not set ++CONFIG_BACKLIGHT_GPIO=m + CONFIG_FRAMEBUFFER_CONSOLE=y + CONFIG_LOGO=y + # CONFIG_LOGO_LINUX_MONO is not set +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 8674822..9ca7d5e 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -520,6 +520,7 @@ CONFIG_JOYSTICK_XPAD=m + CONFIG_JOYSTICK_XPAD_FF=y + CONFIG_INPUT_TOUCHSCREEN=y + CONFIG_TOUCHSCREEN_ADS7846=m ++CONFIG_TOUCHSCREEN_STMPE=m + CONFIG_INPUT_MISC=y + CONFIG_INPUT_AD714X=m + CONFIG_INPUT_ATI_REMOTE2=m +@@ -560,6 +561,7 @@ CONFIG_PPS_CLIENT_LDISC=m + CONFIG_PPS_CLIENT_GPIO=m + CONFIG_GPIO_SYSFS=y + CONFIG_GPIO_ARIZONA=m ++CONFIG_GPIO_STMPE=y + CONFIG_W1=m + CONFIG_W1_MASTER_DS2490=m + CONFIG_W1_MASTER_DS2482=m +@@ -585,6 +587,8 @@ CONFIG_THERMAL_BCM2835=y + CONFIG_WATCHDOG=y + CONFIG_BCM2708_WDT=m + CONFIG_UCB1400_CORE=m ++CONFIG_MFD_STMPE=y ++CONFIG_STMPE_SPI=y + CONFIG_MFD_ARIZONA_I2C=m + CONFIG_MFD_ARIZONA_SPI=m + CONFIG_MFD_WM5102=y +@@ -756,6 +760,7 @@ CONFIG_VIDEO_MT9V011=m + CONFIG_FB=y + CONFIG_FB_BCM2708=y + # CONFIG_BACKLIGHT_GENERIC is not set ++CONFIG_BACKLIGHT_GPIO=m + CONFIG_FRAMEBUFFER_CONSOLE=y + CONFIG_LOGO=y + # CONFIG_LOGO_LINUX_MONO is not set + +From 82fc07dd4c1865ea53449e1d2d90d4478bba13e3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Fri, 27 Feb 2015 18:17:25 +0100 +Subject: [PATCH 169/178] dts: overlay: add support for Adafruit PiTFT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add DT overlay for the Adafruit PiTFT 2.8" resistive touch screen + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/pitft28-resistive-overlay.dts | 115 ++++++++++++++++++++++++ + 2 files changed, 116 insertions(+) + create mode 100644 arch/arm/boot/dts/pitft28-resistive-overlay.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index f411750..c302e1c 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -77,6 +77,7 @@ dtb-$(RPI_DT_OVERLAYS) += lirc-rpi-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pcf2127-rtc-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pcf8523-rtc-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += piscreen-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += pitft28-resistive-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb +diff --git a/arch/arm/boot/dts/pitft28-resistive-overlay.dts b/arch/arm/boot/dts/pitft28-resistive-overlay.dts +new file mode 100644 +index 0000000..d506eae +--- /dev/null ++++ b/arch/arm/boot/dts/pitft28-resistive-overlay.dts +@@ -0,0 +1,115 @@ ++/* ++ * Device Tree overlay for Adafruit PiTFT 2.8" resistive touch screen ++ * ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ spidev@1{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ pitft_pins: pitft_pins { ++ brcm,pins = <24 25>; ++ brcm,function = <0 1>; /* in out */ ++ brcm,pull = <2 0>; /* pullup none */ ++ }; ++ }; ++ }; ++ ++ fragment@2 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pitft: pitft@0{ ++ compatible = "ilitek,ili9340"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pitft_pins>; ++ ++ spi-max-frequency = <32000000>; ++ rotate = <90>; ++ fps = <25>; ++ bgr; ++ buswidth = <8>; ++ dc-gpios = <&gpio 25 0>; ++ debug = <0>; ++ }; ++ ++ pitft_ts@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "st,stmpe610"; ++ reg = <1>; ++ ++ spi-max-frequency = <500000>; ++ irq-gpio = <&gpio 24 0x2>; /* IRQF_TRIGGER_FALLING */ ++ interrupts = <24 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ interrupt-controller; ++ ++ stmpe_touchscreen { ++ compatible = "st,stmpe-ts"; ++ st,sample-time = <4>; ++ st,mod-12b = <1>; ++ st,ref-sel = <0>; ++ st,adc-freq = <2>; ++ st,ave-ctrl = <3>; ++ st,touch-det-delay = <4>; ++ st,settling = <2>; ++ st,fraction-z = <7>; ++ st,i-drive = <0>; ++ }; ++ ++ stmpe_gpio: stmpe_gpio { ++ #gpio-cells = <2>; ++ compatible = "st,stmpe-gpio"; ++ /* ++ * only GPIO2 is wired/available ++ * and it is wired to the backlight ++ */ ++ st,norequest-mask = <0x7b>; ++ }; ++ }; ++ }; ++ }; ++ ++ fragment@3 { ++ target-path = "/soc"; ++ __overlay__ { ++ backlight { ++ compatible = "gpio-backlight"; ++ gpios = <&stmpe_gpio 2 0>; ++ default-on; ++ }; ++ }; ++ }; ++ ++ __overrides__ { ++ speed = <&pitft>,"spi-max-frequency:0"; ++ rotate = <&pitft>,"rotate:0"; ++ fps = <&pitft>,"fps:0"; ++ debug = <&pitft>,"debug:0"; ++ }; ++}; + +From 79041c832b66c1b3609f770be30fb6939377dafc Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Mon, 2 Mar 2015 09:37:02 +0000 +Subject: [PATCH 170/178] enable compiling spi-bcm2835 and add overlay to allow + us to load the driver + +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/spi-bcm2835-overlay.dts | 18 ++++++++++++++++++ + arch/arm/configs/bcm2709_defconfig | 1 + + arch/arm/configs/bcmrpi_defconfig | 1 + + 4 files changed, 21 insertions(+) + create mode 100644 arch/arm/boot/dts/spi-bcm2835-overlay.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index c302e1c..e8dd028 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -82,6 +82,7 @@ dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += spi-bcm2835-overlay.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb + + dtb-$(CONFIG_ARCH_BCM_5301X) += bcm4708-netgear-r6250.dtb +diff --git a/arch/arm/boot/dts/spi-bcm2835-overlay.dts b/arch/arm/boot/dts/spi-bcm2835-overlay.dts +new file mode 100644 +index 0000000..fc1e39b +--- /dev/null ++++ b/arch/arm/boot/dts/spi-bcm2835-overlay.dts +@@ -0,0 +1,18 @@ ++/* ++ * Device tree overlay for spi-bcm2835 ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709"; ++ /* setting up compatiblity to allow loading the spi-bcm2835 driver */ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ compatible = "brcm,bcm2835-spi"; ++ }; ++ }; ++}; +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 559fb04..3a9ce71 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -562,6 +562,7 @@ CONFIG_I2C_MUX=m + CONFIG_I2C_BCM2708=m + CONFIG_SPI=y + CONFIG_SPI_BCM2708=m ++CONFIG_SPI_BCM2835=m + CONFIG_SPI_SPIDEV=y + CONFIG_PPS=m + CONFIG_PPS_CLIENT_LDISC=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 9ca7d5e..21708f6 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -555,6 +555,7 @@ CONFIG_I2C_MUX=m + CONFIG_I2C_BCM2708=m + CONFIG_SPI=y + CONFIG_SPI_BCM2708=m ++CONFIG_SPI_BCM2835=m + CONFIG_SPI_SPIDEV=y + CONFIG_PPS=m + CONFIG_PPS_CLIENT_LDISC=m + +From d9e7e8de173923f95ba00d1b770bba00e0131336 Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Mon, 2 Mar 2015 17:57:30 +0000 +Subject: [PATCH 171/178] added mcp251x module to list of modules to get + compiled as well as the corresponding overlay + +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/mcp2515-can0-overlay.dts | 69 ++++++++++++++++++++++++++++++ + arch/arm/configs/bcm2709_defconfig | 8 ++++ + arch/arm/configs/bcmrpi_defconfig | 8 ++++ + 4 files changed, 86 insertions(+) + create mode 100755 arch/arm/boot/dts/mcp2515-can0-overlay.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index e8dd028..ab7b77c 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -83,6 +83,7 @@ dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += spi-bcm2835-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += mcp2515-can0-overlay.dtb + dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb + + dtb-$(CONFIG_ARCH_BCM_5301X) += bcm4708-netgear-r6250.dtb +diff --git a/arch/arm/boot/dts/mcp2515-can0-overlay.dts b/arch/arm/boot/dts/mcp2515-can0-overlay.dts +new file mode 100755 +index 0000000..45b7a5a +--- /dev/null ++++ b/arch/arm/boot/dts/mcp2515-can0-overlay.dts +@@ -0,0 +1,69 @@ ++/* ++ * Device tree overlay for mcp251x/can0 on spi0.0 ++ */ ++ ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2835", "brcm,bcm2836", "brcm,bcm2708", "brcm,bcm2709"; ++ /* disable spi-dev for spi0.0 */ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ status = "okay"; ++ spidev@0{ ++ status = "disabled"; ++ }; ++ }; ++ }; ++ ++ /* the interrupt pin of the can-controller */ ++ fragment@1 { ++ target = <&gpio>; ++ __overlay__ { ++ can0_pins: can0_pins { ++ brcm,pins = <25>; ++ brcm,function = <0>; /* input */ ++ }; ++ }; ++ }; ++ ++ /* the clock/oscillator of the can-controller */ ++ fragment@2 { ++ target-path = "/clocks"; ++ __overlay__ { ++ /* external oscillator of mcp2515 on SPI0.0 */ ++ can0_osc: can0_osc { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <16000000>; ++ }; ++ }; ++ }; ++ ++ /* the spi config of the can-controller itself binding everything together */ ++ fragment@3 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ can0: mcp2515@0 { ++ reg = <0>; ++ compatible = "microchip,mcp2515"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&can0_pins>; ++ spi-max-frequency = <10000000>; ++ interrupt-parent = <&gpio>; ++ interrupts = <25 0x2>; ++ clocks = <&can0_osc>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ oscillator = <&can0_osc>,"oscillator-frequency"; ++ spimaxfrequency = <&can0>,"spi-max-frequency:0"; ++ interrupt = <&can0_pins>,"brcm,pins:0",<&can0>,"interrupts:0"; ++ }; ++}; +diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig +index 3a9ce71..fad999f 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -345,6 +345,14 @@ CONFIG_BPQETHER=m + CONFIG_BAYCOM_SER_FDX=m + CONFIG_BAYCOM_SER_HDX=m + CONFIG_YAM=m ++CONFIG_CAN=m ++CONFIG_CAN_RAW=m ++CONFIG_CAN_BCM=m ++CONFIG_CAN_GW=m ++CONFIG_CAN_VCAN=m ++CONFIG_CAN_DEV=m ++CONFIG_CAN_CALC_BITTIMING=y ++CONFIG_CAN_MCP251X=m + CONFIG_IRDA=m + CONFIG_IRLAN=m + CONFIG_IRNET=m +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 21708f6..0b40029 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -337,6 +337,14 @@ CONFIG_6PACK=m + CONFIG_BPQETHER=m + CONFIG_BAYCOM_SER_FDX=m + CONFIG_BAYCOM_SER_HDX=m ++CONFIG_CAN=m ++CONFIG_CAN_RAW=m ++CONFIG_CAN_BCM=m ++CONFIG_CAN_GW=m ++CONFIG_CAN_VCAN=m ++CONFIG_CAN_DEV=m ++CONFIG_CAN_CALC_BITTIMING=y ++CONFIG_CAN_MCP251X=m + CONFIG_YAM=m + CONFIG_IRDA=m + CONFIG_IRLAN=m + +From f00542bdeb53d1f08023c17d1774b9ebe0158794 Mon Sep 17 00:00:00 2001 +From: Howard Mitchell +Date: Fri, 27 Feb 2015 14:58:04 +0000 +Subject: [PATCH 172/178] Revert "pcm512x: Use a range macro for Volume and + rename to PCM." + +This reverts commit 457a0d6f5961c18f79a7643ca0a3e8565af8a0eb. +--- + sound/soc/codecs/pcm512x.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c +index b405719..640c991 100644 +--- a/sound/soc/codecs/pcm512x.c ++++ b/sound/soc/codecs/pcm512x.c +@@ -259,8 +259,8 @@ static const struct soc_enum pcm512x_veds = + pcm512x_ramp_step_text); + + static const struct snd_kcontrol_new pcm512x_controls[] = { +-SOC_DOUBLE_R_RANGE_TLV("PCM", PCM512x_DIGITAL_VOLUME_2, +- PCM512x_DIGITAL_VOLUME_3, 0, 40, 255, 1, digital_tlv), ++SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, ++ PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), + SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL, + PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), + SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, + +From 151c2331e1744012adc48f0f6bbf6ec5213059a8 Mon Sep 17 00:00:00 2001 +From: Howard Mitchell +Date: Mon, 2 Mar 2015 17:28:02 +0000 +Subject: [PATCH 173/178] Set a limit of 0dB on Digital Volume Control + +The main volume control in the PCM512x DAC has a range up to ++24dB. This is dangerously loud and can potentially cause massive +clipping in the output stages. Therefore this sets a sensible +limit of 0dB for this control. +--- + sound/soc/bcm/iqaudio-dac.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c +index ee8cd6e..a38e874 100644 +--- a/sound/soc/bcm/iqaudio-dac.c ++++ b/sound/soc/bcm/iqaudio-dac.c +@@ -25,7 +25,13 @@ + + static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd) + { +-// NOT USED struct snd_soc_codec *codec = rtd->codec; ++ int ret; ++ struct snd_soc_card *card = rtd->card; ++ struct snd_soc_codec *codec = rtd->codec; ++ ++ ret = snd_soc_limit_volume(codec, "Digital Playback Volume", 207); ++ if (ret < 0) ++ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret); + + return 0; + } + +From d3c1667d018aee1ec2db13189e35e4fd8588c29b Mon Sep 17 00:00:00 2001 +From: Rainer Herbers +Date: Sun, 15 Feb 2015 13:44:14 +0100 +Subject: [PATCH 174/178] Create bmp085_i2c-sensor-overlay.dts and update + Makefile + +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/bmp085_i2c-sensor-overlay.dts | 23 +++++++++++++++++++++++ + 2 files changed, 24 insertions(+) + create mode 100644 arch/arm/boot/dts/bmp085_i2c-sensor-overlay.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index ab7b77c..2506e51 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -64,6 +64,7 @@ endif + dtb-$(CONFIG_BCM2708_DT) += bcm2708-rpi-b.dtb + dtb-$(CONFIG_BCM2708_DT) += bcm2708-rpi-b-plus.dtb + dtb-$(CONFIG_BCM2709_DT) += bcm2709-rpi-2-b.dtb ++dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += ds1307-rtc-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-dac-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-dacplus-overlay.dtb +diff --git a/arch/arm/boot/dts/bmp085_i2c-sensor-overlay.dts b/arch/arm/boot/dts/bmp085_i2c-sensor-overlay.dts +new file mode 100644 +index 0000000..b830bf2 +--- /dev/null ++++ b/arch/arm/boot/dts/bmp085_i2c-sensor-overlay.dts +@@ -0,0 +1,23 @@ ++// Definitions for BMP085/BMP180 digital barometric pressure and temperature sensors from Bosch Sensortec ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2708"; ++ ++ fragment@0 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ bmp085@77 { ++ compatible = "bosch,bmp085"; ++ reg = <0x77>; ++ default-oversampling = <3>; ++ status = "okay"; ++ }; ++ }; ++ }; ++}; + +From ce58404581420a3ac3afc09e021d1305b9a7ea09 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 27 Feb 2015 15:10:24 +0000 +Subject: [PATCH 175/178] enc28j60: Add device tree compatible string and an + overlay + +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/enc28j60-overlay.dts | 29 +++++++++++++++++++++++++++++ + drivers/net/ethernet/microchip/enc28j60.c | 11 +++++++++++ + 3 files changed, 41 insertions(+) + create mode 100755 arch/arm/boot/dts/enc28j60-overlay.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 2506e51..d276d3f 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -66,6 +66,7 @@ dtb-$(CONFIG_BCM2708_DT) += bcm2708-rpi-b-plus.dtb + dtb-$(CONFIG_BCM2709_DT) += bcm2709-rpi-2-b.dtb + dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += ds1307-rtc-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-dac-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-dacplus-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-digi-overlay.dtb +diff --git a/arch/arm/boot/dts/enc28j60-overlay.dts b/arch/arm/boot/dts/enc28j60-overlay.dts +new file mode 100755 +index 0000000..aa9b645 +--- /dev/null ++++ b/arch/arm/boot/dts/enc28j60-overlay.dts +@@ -0,0 +1,29 @@ ++// Overlay for the Microchip ENC28J60 Ethernet Controller ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2708"; ++ ++ fragment@0 { ++ target = <&spi0>; ++ __overlay__ { ++ /* needed to avoid dtc warning */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "okay"; ++ ++ spidev@0{ ++ status = "disabled"; ++ }; ++ ++ enc28j60@0{ ++ compatible = "microchip,enc28j60"; ++ reg = <0>; /* CE0 */ ++ spi-max-frequency = <12000000>; ++ status = "okay"; ++ }; ++ }; ++ }; ++}; +diff --git a/drivers/net/ethernet/microchip/enc28j60.c b/drivers/net/ethernet/microchip/enc28j60.c +index b1b5f66..c6b6e1a 100644 +--- a/drivers/net/ethernet/microchip/enc28j60.c ++++ b/drivers/net/ethernet/microchip/enc28j60.c +@@ -1630,10 +1630,21 @@ static int enc28j60_remove(struct spi_device *spi) + return 0; + } + ++#ifdef CONFIG_OF ++static const struct of_device_id enc28j60_of_match[] = { ++ { .compatible = "microchip,enc28j60", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, enc28j60_of_match); ++#endif ++ + static struct spi_driver enc28j60_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, ++#ifdef CONFIG_OF ++ .of_match_table = enc28j60_of_match, ++#endif + }, + .probe = enc28j60_probe, + .remove = enc28j60_remove, + +From d857b512ed578b7a5014740caee046528944af65 Mon Sep 17 00:00:00 2001 +From: Jon Burgess +Date: Tue, 17 Feb 2015 13:22:17 +0000 +Subject: [PATCH 176/178] Create generic i2c-rtc overlay for supporting ds1307, + ds3231, pcf2127 and pcf8523. + +Signed-off-by: Jon Burgess +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/i2c-rtc-overlay.dts | 43 +++++++++++++++++++++++++++++++++++ + 2 files changed, 44 insertions(+) + create mode 100644 arch/arm/boot/dts/i2c-rtc-overlay.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index d276d3f..e1f6d11 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -67,6 +67,7 @@ dtb-$(CONFIG_BCM2709_DT) += bcm2709-rpi-2-b.dtb + dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += ds1307-rtc-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb ++dtb-$(RPI_DT_OVERLAYS) += i2c-rtc-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-dac-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-dacplus-overlay.dtb + dtb-$(RPI_DT_OVERLAYS) += hifiberry-digi-overlay.dtb +diff --git a/arch/arm/boot/dts/i2c-rtc-overlay.dts b/arch/arm/boot/dts/i2c-rtc-overlay.dts +new file mode 100644 +index 0000000..5d5abb1 +--- /dev/null ++++ b/arch/arm/boot/dts/i2c-rtc-overlay.dts +@@ -0,0 +1,43 @@ ++// Definitions for several I2C based Real Time Clocks ++/dts-v1/; ++/plugin/; ++ ++/ { ++ compatible = "brcm,bcm2708"; ++ ++ fragment@0 { ++ target = <&i2c1>; ++ __overlay__ { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ ds1307: ds1307@68 { ++ compatible = "maxim,ds1307"; ++ reg = <0x68>; ++ status = "disable"; ++ }; ++ ds3231: ds3231@68 { ++ compatible = "maxim,ds3231"; ++ reg = <0x68>; ++ status = "disable"; ++ }; ++ pcf2127: pcf2127@51 { ++ compatible = "nxp,pcf2127"; ++ reg = <0x51>; ++ status = "disable"; ++ }; ++ pcf8523: pcf8523@68 { ++ compatible = "nxp,pcf8523"; ++ reg = <0x68>; ++ status = "disable"; ++ }; ++ }; ++ }; ++ __overrides__ { ++ ds1307 = <&ds1307>,"status"; ++ ds3231 = <&ds3231>,"status"; ++ pcf2127 = <&pcf2127>,"status"; ++ pcf8523 = <&pcf8523>,"status"; ++ }; ++}; + +From 04122b5278524e8d1530bcf37c9169a8bff1e91f Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 25 Feb 2015 09:45:56 +0000 +Subject: [PATCH 177/178] vchiq_arm: Complete support for SYNCHRONOUS mode + +--- + .../vc04_services/interface/vchi/vchi_common.h | 1 + + .../vc04_services/interface/vchiq_arm/vchiq_cfg.h | 5 +- + .../vc04_services/interface/vchiq_arm/vchiq_core.c | 106 +++++++++++++++++---- + .../vc04_services/interface/vchiq_arm/vchiq_core.h | 1 + + .../vc04_services/interface/vchiq_arm/vchiq_shim.c | 3 + + 5 files changed, 98 insertions(+), 18 deletions(-) + +diff --git a/drivers/misc/vc04_services/interface/vchi/vchi_common.h b/drivers/misc/vc04_services/interface/vchi/vchi_common.h +index d76118c..d535a72 100644 +--- a/drivers/misc/vc04_services/interface/vchi/vchi_common.h ++++ b/drivers/misc/vc04_services/interface/vchi/vchi_common.h +@@ -116,6 +116,7 @@ typedef enum + VCHI_SERVICE_OPTION_MIN, + + VCHI_SERVICE_OPTION_TRACE, ++ VCHI_SERVICE_OPTION_SYNCHRONOUS, + + VCHI_SERVICE_OPTION_MAX + } VCHI_SERVICE_OPTION_T; +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h +index c382740..d2797db 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h +@@ -36,7 +36,7 @@ + + #define VCHIQ_MAGIC VCHIQ_MAKE_FOURCC('V', 'C', 'H', 'I') + /* The version of VCHIQ - change with any non-trivial change */ +-#define VCHIQ_VERSION 7 ++#define VCHIQ_VERSION 8 + /* The minimum compatible version - update to match VCHIQ_VERSION with any + ** incompatible change */ + #define VCHIQ_VERSION_MIN 3 +@@ -47,6 +47,9 @@ + /* The version that introduced the VCHIQ_IOC_CLOSE_DELIVERED ioctl */ + #define VCHIQ_VERSION_CLOSE_DELIVERED 7 + ++/* The version that made it safe to use SYNCHRONOUS mode */ ++#define VCHIQ_VERSION_SYNCHRONOUS_MODE 8 ++ + #define VCHIQ_MAX_STATES 1 + #define VCHIQ_MAX_SERVICES 4096 + #define VCHIQ_MAX_SLOTS 128 +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c +index 14a4155..835688b 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c +@@ -66,6 +66,13 @@ struct vchiq_openack_payload { + short version; + }; + ++enum ++{ ++ QMFLAGS_IS_BLOCKING = (1 << 0), ++ QMFLAGS_NO_MUTEX_LOCK = (1 << 1), ++ QMFLAGS_NO_MUTEX_UNLOCK = (1 << 2) ++}; ++ + /* we require this for consistency between endpoints */ + vchiq_static_assert(sizeof(VCHIQ_HEADER_T) == 8); + vchiq_static_assert(IS_POW2(sizeof(VCHIQ_HEADER_T))); +@@ -743,7 +750,7 @@ process_free_queue(VCHIQ_STATE_T *state) + static VCHIQ_STATUS_T + queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, + int msgid, const VCHIQ_ELEMENT_T *elements, +- int count, int size, int is_blocking) ++ int count, int size, int flags) + { + VCHIQ_SHARED_STATE_T *local; + VCHIQ_SERVICE_QUOTA_T *service_quota = NULL; +@@ -758,7 +765,7 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, + + WARN_ON(!(stride <= VCHIQ_SLOT_SIZE)); + +- if ((type != VCHIQ_MSG_RESUME) && ++ if (!(flags & QMFLAGS_NO_MUTEX_LOCK) && + (mutex_lock_interruptible(&state->slot_mutex) != 0)) + return VCHIQ_RETRY; + +@@ -766,6 +773,8 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, + int tx_end_index; + + BUG_ON(!service); ++ BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK | ++ QMFLAGS_NO_MUTEX_UNLOCK)) != 0); + + if (service->closing) { + /* The service has been closed */ +@@ -841,12 +850,15 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, + spin_unlock("a_spinlock); + } + +- header = reserve_space(state, stride, is_blocking); ++ header = reserve_space(state, stride, flags & QMFLAGS_IS_BLOCKING); + + if (!header) { + if (service) + VCHIQ_SERVICE_STATS_INC(service, slot_stalls); +- mutex_unlock(&state->slot_mutex); ++ /* In the event of a failure, return the mutex to the ++ state it was in */ ++ if (!(flags & QMFLAGS_NO_MUTEX_LOCK)) ++ mutex_unlock(&state->slot_mutex); + return VCHIQ_RETRY; + } + +@@ -864,6 +876,8 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, + VCHIQ_MSG_DSTPORT(msgid)); + + BUG_ON(!service); ++ BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK | ++ QMFLAGS_NO_MUTEX_UNLOCK)) != 0); + + for (i = 0, pos = 0; i < (unsigned int)count; + pos += elements[i++].size) +@@ -965,7 +979,7 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, + if (service && (type == VCHIQ_MSG_CLOSE)) + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT); + +- if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE) ++ if (!(flags & QMFLAGS_NO_MUTEX_UNLOCK)) + mutex_unlock(&state->slot_mutex); + + remote_event_signal(&state->remote->trigger); +@@ -1535,8 +1549,14 @@ parse_open(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header) + sizeof(ack_payload) + }; + ++ if (state->version_common < ++ VCHIQ_VERSION_SYNCHRONOUS_MODE) ++ service->sync = 0; ++ + /* Acknowledge the OPEN */ +- if (service->sync) { ++ if (service->sync && ++ (state->version_common >= ++ VCHIQ_VERSION_SYNCHRONOUS_MODE)) { + if (queue_message_sync(state, NULL, + VCHIQ_MAKE_MSG( + VCHIQ_MSG_OPENACK, +@@ -1790,6 +1810,8 @@ parse_rx_slots(VCHIQ_STATE_T *state) + vchiq_log_info(vchiq_core_log_level, + "%d: prs CONNECT@%x", + state->id, (unsigned int)header); ++ state->version_common = ((VCHIQ_SLOT_ZERO_T *) ++ state->slot_data)->version; + up(&state->connect); + break; + case VCHIQ_MSG_BULK_RX: +@@ -1943,7 +1965,8 @@ parse_rx_slots(VCHIQ_STATE_T *state) + /* Send a PAUSE in response */ + if (queue_message(state, NULL, + VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0), +- NULL, 0, 0, 0) == VCHIQ_RETRY) ++ NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK) ++ == VCHIQ_RETRY) + goto bail_not_ready; + if (state->is_master) + pause_bulks(state); +@@ -2041,7 +2064,9 @@ slot_handler_func(void *v) + pause_bulks(state); + if (queue_message(state, NULL, + VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0), +- NULL, 0, 0, 0) != VCHIQ_RETRY) { ++ NULL, 0, 0, ++ QMFLAGS_NO_MUTEX_UNLOCK) ++ != VCHIQ_RETRY) { + vchiq_set_conn_state(state, + VCHIQ_CONNSTATE_PAUSE_SENT); + } else { +@@ -2059,7 +2084,8 @@ slot_handler_func(void *v) + case VCHIQ_CONNSTATE_RESUMING: + if (queue_message(state, NULL, + VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0), +- NULL, 0, 0, 0) != VCHIQ_RETRY) { ++ NULL, 0, 0, QMFLAGS_NO_MUTEX_LOCK) ++ != VCHIQ_RETRY) { + if (state->is_master) + resume_bulks(state); + vchiq_set_conn_state(state, +@@ -2180,6 +2206,7 @@ sync_func(void *v) + service->remoteport = remoteport; + vchiq_set_service_state(service, + VCHIQ_SRVSTATE_OPENSYNC); ++ service->sync = 1; + up(&service->remove_event); + } + release_message_sync(state, header); +@@ -2358,6 +2385,9 @@ vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, + return VCHIQ_ERROR; + } + ++ if (VCHIQ_VERSION < slot_zero->version) ++ slot_zero->version = VCHIQ_VERSION; ++ + if (is_master) { + local = &slot_zero->master; + remote = &slot_zero->slave; +@@ -2661,7 +2691,7 @@ vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id) + vchiq_use_service_internal(service); + status = queue_message(service->state, NULL, + VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN, service->localport, 0), +- &body, 1, sizeof(payload), 1); ++ &body, 1, sizeof(payload), QMFLAGS_IS_BLOCKING); + if (status == VCHIQ_SUCCESS) { + /* Wait for the ACK/NAK */ + if (down_interruptible(&service->remove_event) != 0) { +@@ -2690,7 +2720,18 @@ release_service_messages(VCHIQ_SERVICE_T *service) + int slot_last = state->remote->slot_last; + int i; + +- /* Release any claimed messages */ ++ /* Release any claimed messages aimed at this service */ ++ ++ if (service->sync) { ++ VCHIQ_HEADER_T *header = ++ (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state, ++ state->remote->slot_sync); ++ if (VCHIQ_MSG_DSTPORT(header->msgid) == service->localport) ++ release_message_sync(state, header); ++ ++ return; ++ } ++ + for (i = state->remote->slot_first; i <= slot_last; i++) { + VCHIQ_SLOT_INFO_T *slot_info = + SLOT_INFO_FROM_INDEX(state, i); +@@ -2888,17 +2929,31 @@ vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd) + (VCHIQ_MSG_CLOSE, + service->localport, + VCHIQ_MSG_DSTPORT(service->remoteport)), +- NULL, 0, 0, 0); ++ NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK); + + if (status == VCHIQ_SUCCESS) { +- if (!close_recvd) ++ if (!close_recvd) { ++ /* Change the state while the mutex is ++ still held */ ++ vchiq_set_service_state(service, ++ VCHIQ_SRVSTATE_CLOSESENT); ++ mutex_unlock(&state->slot_mutex); ++ if (service->sync) ++ mutex_unlock(&state->sync_mutex); + break; ++ } + } else if (service->srvstate == VCHIQ_SRVSTATE_OPENSYNC) { + mutex_unlock(&state->sync_mutex); + break; + } else + break; + ++ /* Change the state while the mutex is still held */ ++ vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSERECVD); ++ mutex_unlock(&state->slot_mutex); ++ if (service->sync) ++ mutex_unlock(&state->sync_mutex); ++ + status = close_service_complete(service, + VCHIQ_SRVSTATE_CLOSERECVD); + break; +@@ -3005,7 +3060,7 @@ vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance) + if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) { + if (queue_message(state, NULL, + VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, 0, +- 0, 1) == VCHIQ_RETRY) ++ 0, QMFLAGS_IS_BLOCKING) == VCHIQ_RETRY) + return VCHIQ_RETRY; + + vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTING); +@@ -3291,6 +3346,16 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, + service->localport, service->remoteport, dir_char, + size, (unsigned int)bulk->data, (unsigned int)userdata); + ++ /* The slot mutex must be held when the service is being closed, so ++ claim it here to ensure that isn't happening */ ++ if (mutex_lock_interruptible(&state->slot_mutex) != 0) { ++ status = VCHIQ_RETRY; ++ goto cancel_bulk_error_exit; ++ } ++ ++ if (service->srvstate != VCHIQ_SRVSTATE_OPEN) ++ goto unlock_both_error_exit; ++ + if (state->is_master) { + queue->local_insert++; + if (resolve_bulks(service, queue)) +@@ -3304,14 +3369,17 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, + status = queue_message(state, NULL, + VCHIQ_MAKE_MSG(dir_msgtype, + service->localport, service->remoteport), +- &element, 1, sizeof(payload), 1); ++ &element, 1, sizeof(payload), ++ QMFLAGS_IS_BLOCKING | ++ QMFLAGS_NO_MUTEX_LOCK | ++ QMFLAGS_NO_MUTEX_UNLOCK); + if (status != VCHIQ_SUCCESS) { +- vchiq_complete_bulk(bulk); +- goto unlock_error_exit; ++ goto unlock_both_error_exit; + } + queue->local_insert++; + } + ++ mutex_unlock(&state->slot_mutex); + mutex_unlock(&service->bulk_mutex); + + vchiq_log_trace(vchiq_core_log_level, +@@ -3335,6 +3403,10 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, + + return status; + ++unlock_both_error_exit: ++ mutex_unlock(&state->slot_mutex); ++cancel_bulk_error_exit: ++ vchiq_complete_bulk(bulk); + unlock_error_exit: + mutex_unlock(&service->bulk_mutex); + +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h +index 1b27917..9be484c 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h +@@ -402,6 +402,7 @@ struct vchiq_state_struct { + int initialised; + VCHIQ_CONNSTATE_T conn_state; + int is_master; ++ short version_common; + + VCHIQ_SHARED_STATE_T *local; + VCHIQ_SHARED_STATE_T *remote; +diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c +index c26eff7..8072ff6 100644 +--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c ++++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c +@@ -738,6 +738,9 @@ int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle, + case VCHI_SERVICE_OPTION_TRACE: + vchiq_option = VCHIQ_SERVICE_OPTION_TRACE; + break; ++ case VCHI_SERVICE_OPTION_SYNCHRONOUS: ++ vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS; ++ break; + default: + service = NULL; + break; + +From 786219b8ef922ec8407895b51381cda3160e6e49 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 16 Feb 2015 13:51:02 +0000 +Subject: [PATCH 178/178] lirc-rpi: use getnstimeofday instead of + read_current_timer + +read_current_timer isn't guaranteed to return values in +microseconds, and indeed it doesn't on a Pi2. + +Issue: linux#827 +--- + drivers/staging/media/lirc/lirc_rpi.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/media/lirc/lirc_rpi.c b/drivers/staging/media/lirc/lirc_rpi.c +index cd66ca2..24563ec 100644 +--- a/drivers/staging/media/lirc/lirc_rpi.c ++++ b/drivers/staging/media/lirc/lirc_rpi.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -107,6 +108,13 @@ static void safe_udelay(unsigned long usecs) + udelay(usecs); + } + ++static unsigned long read_current_us(void) ++{ ++ struct timespec now; ++ getnstimeofday(&now); ++ return (now.tv_sec * 1000000) + (now.tv_nsec/1000); ++} ++ + static int init_timing_params(unsigned int new_duty_cycle, + unsigned int new_freq) + { +@@ -135,7 +143,7 @@ static long send_pulse_softcarrier(unsigned long length) + length *= 1000; + + actual = 0; target = 0; flag = 0; +- read_current_timer(&actual_us); ++ actual_us = read_current_us(); + + while (actual < length) { + if (flag) { +@@ -153,7 +161,7 @@ static long send_pulse_softcarrier(unsigned long length) + */ + if ((int)(target_us - actual_us) > 0) + udelay(target_us - actual_us); +- read_current_timer(&actual_us); ++ actual_us = read_current_us(); + actual += (actual_us - initial_us) * 1000; + flag = !flag; + }