diff --git a/projects/RPi/linux/linux.arm.conf b/projects/RPi/linux/linux.arm.conf index d566335005..ca76a656a7 100644 --- a/projects/RPi/linux/linux.arm.conf +++ b/projects/RPi/linux/linux.arm.conf @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 3.19.0 Kernel Configuration +# Linux/arm 3.19.1 Kernel Configuration # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -2939,6 +2939,7 @@ CONFIG_LIRC_XBOX=m # CONFIG_DGAP is not set # CONFIG_GS_FPGABOOT is not set # CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set +# CONFIG_FB_TFT is not set CONFIG_CLKDEV_LOOKUP=y CONFIG_HAVE_CLK_PREPARE=y CONFIG_COMMON_CLK=y diff --git a/projects/RPi/patches/linux/linux-01-RPi_support.patch b/projects/RPi/patches/linux/linux-01-RPi_support.patch index f7a8bf3072..fbe6e260a5 100644 --- a/projects/RPi/patches/linux/linux-01-RPi_support.patch +++ b/projects/RPi/patches/linux/linux-01-RPi_support.patch @@ -1,7 +1,7 @@ -From 0222939a3735e3ad819ce793bbcaa3f4759d6543 Mon Sep 17 00:00:00 2001 +From 8fa199a9eafe1ffbb0b1dd9c67989ea322f72306 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 001/116] Main bcm2708 linux port +Subject: [PATCH 001/172] Main bcm2708 linux port Signed-off-by: popcornmix --- @@ -2166,7 +2166,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 @@ @@ -5108,10 +5108,10 @@ index 9f32270..17ee61b 100644 mmc_pm_flag_t pm_caps; /* supported pm features */ -From db89dca23e5f1de2895f0f07d4fd14c00ab72e6e Mon Sep 17 00:00:00 2001 +From 2392ce74d3cd30172bc41023066f9f7abe7404ea Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 Oct 2014 18:50:05 +0100 -Subject: [PATCH 002/116] Add bcm2708_gpio driver +Subject: [PATCH 002/172] Add bcm2708_gpio driver Signed-off-by: popcornmix @@ -5715,10 +5715,10 @@ index 0000000..fb69624 + +#endif -From 138919e0b3e213effd883f4a80dd8b2cc4f55f4a Mon Sep 17 00:00:00 2001 +From 559f0c63be158be62310100cbe3e45d224be9592 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 7 May 2013 22:20:24 +0100 -Subject: [PATCH 003/116] Add quick config. +Subject: [PATCH 003/172] Add quick config. This is designed for quick compiling when developing. No modules are needed and it includes all Pi specific drivers @@ -5931,10 +5931,10 @@ index 0000000..e5efe75 +CONFIG_CRC_ITU_T=y +CONFIG_LIBCRC32C=y -From a2dc1f5efb2a618b0970218f3e96039776f3eaaf Mon Sep 17 00:00:00 2001 +From 08e12db8a1dcba12eeabca2b8eca4b4efa30f439 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 004/116] Add dwc_otg driver +Subject: [PATCH 004/172] Add dwc_otg driver Signed-off-by: popcornmix @@ -6095,10 +6095,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); @@ -62987,10 +62987,10 @@ index 0000000..cdc9963 +test_main(); +0; -From 426f9dbea63f0d6a35e05e80fd188b89dca321cd Mon Sep 17 00:00:00 2001 +From 21af740ba39591ca0b84bf217e5e17748c912ac8 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:54:32 +0100 -Subject: [PATCH 005/116] bcm2708 watchdog driver +Subject: [PATCH 005/172] bcm2708 watchdog driver Signed-off-by: popcornmix --- @@ -63418,11 +63418,10 @@ index 0000000..8a27d68 +MODULE_ALIAS_MISCDEV(TEMP_MINOR); +MODULE_LICENSE("GPL"); - -From 541af491f8c24af061d3e62fdc7da4fad34e5003 Mon Sep 17 00:00:00 2001 +From 44deeada252c455ee3325a19e375016d60826802 Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 008/116] Speed up console framebuffer imageblit function +Subject: [PATCH 008/172] 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 @@ -63631,10 +63630,10 @@ index a2bb276..436494f 100644 start_index, pitch_index); } else -From 21cf00e8ae1b424b05c9e218f28c509f296ac949 Mon Sep 17 00:00:00 2001 +From 33bcff1a531c7d7810dfd4f81546ddc3bffadeba Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 009/116] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 009/172] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -63727,10 +63726,10 @@ index fb795c3..fa72af0 100644 #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ #define FB_TYPE_PLANES 1 /* Non interleaved planes */ -From 57a4b2b0d8e5849d4b4cff404ac6a90bcdab0f37 Mon Sep 17 00:00:00 2001 +From 86c75685b2acfe9012480bb2301a818d3d0beea8 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:55:09 +0100 -Subject: [PATCH 010/116] bcm2708 framebuffer driver +Subject: [PATCH 010/172] bcm2708 framebuffer driver Signed-off-by: popcornmix @@ -67173,10 +67172,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 8178b4e7f56a040774a673f21b6d860a83d86d1d Mon Sep 17 00:00:00 2001 +From 3f8261010097c731e1128600efb3107dc83aa24f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 2 Jul 2013 23:42:01 +0100 -Subject: [PATCH 011/116] bcm2708 vchiq driver +Subject: [PATCH 011/172] bcm2708 vchiq driver Signed-off-by: popcornmix @@ -67298,7 +67297,7 @@ described above. create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_version.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index 006242c..4e6f46c 100644 +index 006242c..4e6f46c3 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -524,6 +524,7 @@ source "drivers/misc/carma/Kconfig" @@ -80125,10 +80124,10 @@ index 0000000..b6bfa21 + return vchiq_build_time; +} -From 48c4a760bace73c6c2e10ace250faf0b1c2cf603 Mon Sep 17 00:00:00 2001 +From 2e067b9b144d119a1b0b930dae88d2f1b29dd497 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 12 May 2014 15:12:02 +0100 -Subject: [PATCH 012/116] vchiq: Avoid high load when blocked and unkillable +Subject: [PATCH 012/172] 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 --- @@ -80290,10 +80289,10 @@ index c2eefef..05e7979 100644 static inline int is_pow2(int i) { -From d36beb1f111d0621d672edfc864c2ac018a05053 Mon Sep 17 00:00:00 2001 +From 38a6237db4d225352e14513dde856a7767e51c76 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 013/116] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 013/172] cma: Add vc_cma driver to enable use of CMA Signed-off-by: popcornmix --- @@ -81580,10 +81579,10 @@ index 0000000..5325832 + +#endif /* VC_CMA_H */ -From 9a5da41b08c71c403f7a50e3f1790bc7ce061c5d Mon Sep 17 00:00:00 2001 +From 3d1f88f9fc8393b6c8e34c991dac0dbc58ae3f4d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 014/116] bcm2708: alsa sound driver +Subject: [PATCH 014/172] bcm2708: alsa sound driver Signed-off-by: popcornmix @@ -84346,10 +84345,10 @@ index 0000000..af3e6eb + +#endif // _VC_AUDIO_DEFS_H_ -From e191bd0eb4395d58ca38628cac3a9832ac2a6644 Mon Sep 17 00:00:00 2001 +From 440a7ce5f52fd43466a0d25132a3bc855c224be9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:51:55 +0100 -Subject: [PATCH 015/116] Add hwrng (hardware random number generator) driver +Subject: [PATCH 015/172] Add hwrng (hardware random number generator) driver --- drivers/char/hw_random/Kconfig | 11 ++++ @@ -84516,10 +84515,10 @@ index 0000000..340f004 +MODULE_DESCRIPTION("BCM2708 H/W Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL and additional rights"); -From c8dfc6610d8ec3c1b55b9988aa93749420ef5ae5 Mon Sep 17 00:00:00 2001 +From f543037234f72aed89e2239f62f2dce7ea94aefa Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 016/116] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 016/172] 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 @@ -85251,10 +85250,10 @@ index 0000000..c688364 +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -From 95d8a71baa57259706f2211e2831910c5e8732df Mon Sep 17 00:00:00 2001 +From c66c4562de98ab99b0bd25fcd238104ce8f4ebbe Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 017/116] Add cpufreq driver +Subject: [PATCH 017/172] Add cpufreq driver --- arch/arm/Kconfig | 1 + @@ -85538,10 +85537,10 @@ index 0000000..447ca09 +module_init(bcm2835_cpufreq_module_init); +module_exit(bcm2835_cpufreq_module_exit); -From 59ae3e5f2544dacbdea86d9f005fe7f5598cdd30 Mon Sep 17 00:00:00 2001 +From b5de470ee4adcb247acbb7a8515a73db3a9494d7 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 018/116] Added hwmon/thermal driver for reporting core +Subject: [PATCH 018/172] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian --- @@ -86063,10 +86062,10 @@ index 0000000..85fceb5 + +module_platform_driver(bcm2835_thermal_driver); -From 5a2d7d0a26de7791c61462bd36cb190c8ac0857d Mon Sep 17 00:00:00 2001 +From 5af87652d480b6de0edca41bde86a469bf15ffc6 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 019/116] Allow mac address to be set in smsc95xx +Subject: [PATCH 019/172] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -86157,10 +86156,10 @@ index 26423ad..e29a323 100644 if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, dev->net->dev_addr) == 0) { -From 196215044abd081236a1acbecc02f007cb62b99c Mon Sep 17 00:00:00 2001 +From b8f0a117f160b4a8a9c41d3e61754dbe220a69dd Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 4 Nov 2013 18:56:10 +0000 -Subject: [PATCH 020/116] Add Chris Boot's i2c and spi drivers. +Subject: [PATCH 020/172] Add Chris Boot's i2c and spi drivers. i2c-bcm2708: fixed baudrate @@ -87507,10 +87506,10 @@ index 0000000..b04a57d +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From e9ce3b546b6fd5fb38952ba1437d479c6847ef5f Mon Sep 17 00:00:00 2001 +From 682719078e0d0e6ac1abe5845faa65e5f0b579bb Mon Sep 17 00:00:00 2001 From: cbeytas Date: Mon, 24 Jun 2013 00:05:40 -0400 -Subject: [PATCH 021/116] Perform I2C combined transactions when possible +Subject: [PATCH 021/172] Perform I2C combined transactions when possible Perform I2C combined transactions whenever possible, within the restrictions of the Broadcomm Serial Controller. @@ -87582,10 +87581,10 @@ index 09203c0..7d385a3 100644 } -From 3eeb43c7ff0ec0308e78481ef4c9612ee90c2e77 Mon Sep 17 00:00:00 2001 +From db6f4cb59c89e54db302266e6c827137f3da5d96 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 022/116] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 022/172] 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 @@ -87857,11 +87856,10 @@ index 2820924..fd0550f 100644 } } - -From b356d2a5324517f468c05664c36ae2d3ad51814e Mon Sep 17 00:00:00 2001 +From 8160010b3d9ff17f29c3e332e9f3c37c527e26c0 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 12 Apr 2013 23:58:47 +0100 -Subject: [PATCH 024/116] config: add missing options from 3.6.y kernel +Subject: [PATCH 024/172] config: add missing options from 3.6.y kernel --- arch/arm/configs/bcmrpi_defconfig | 692 ++++++++++++++++++++++++++++++++++++-- @@ -88848,10 +88846,10 @@ index 6d2eae1..6b39872 100644 # CONFIG_CRYPTO_HW is not set CONFIG_CRC_ITU_T=y -From 3c7bee5134f4d492af3b6ba74ac91a76241979cf Mon Sep 17 00:00:00 2001 +From 9546603deded7c808fd5a04a691377a0cdf2fa25 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 025/116] config: Enable CONFIG_MEMCG, but leave it disabled +Subject: [PATCH 025/172] config: Enable CONFIG_MEMCG, but leave it disabled (due to memory cost). Enable with cgroup_enable=memory. --- @@ -88919,10 +88917,10 @@ index 2f6893c..8778eba 100644 #ifdef CONFIG_MEMCG_SWAP -From 675b0e93160dcb81e3d36ea3548c6d9f289928c9 Mon Sep 17 00:00:00 2001 +From c73af020d71c020a59390d693ce357e0052cf457 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:46:42 +0100 -Subject: [PATCH 026/116] Add FIQ patch to dwc_otg driver. Enable with +Subject: [PATCH 026/172] 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 @@ -92215,10 +92213,10 @@ index 1b1f83c..c8590b5 100644 if (status.b.sr) { -From 8c9d2b02c39e52c89c27d306fa1a2781fd48b014 Mon Sep 17 00:00:00 2001 +From 5cd92267e90f236fd69402f1c98eef1613d2688a Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 19 Mar 2014 12:58:23 +0000 -Subject: [PATCH 027/116] dwc_otg: fiq_fsm: Base commit for driver rewrite +Subject: [PATCH 027/172] dwc_otg: fiq_fsm: Base commit for driver rewrite This commit removes the previous FIQ fixes entirely and adds fiq_fsm. @@ -97113,10 +97111,10 @@ index 5d310df..4b32941 100644 return -EBUSY; } -From c6121acf96ef39f9c95b15760846f58b45027ee9 Mon Sep 17 00:00:00 2001 +From 264fb63a197f8df7a31f27109409699c43a5c82e Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 028/116] bcm2835: add v4l2 camera device +Subject: [PATCH 028/172] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -97228,10 +97226,10 @@ index 0000000..c585a8f + +$ v4l2-ctl --list-formats diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index 765bffb..286b7ad 100644 +index 6a1334b..8fdd7a0 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig -@@ -118,6 +118,7 @@ config VIDEO_S3C_CAMIF +@@ -116,6 +116,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" @@ -103098,10 +103096,10 @@ index 0000000..9d1d11e + +#endif /* MMAL_VCHIQ_H */ -From 876eadd8476087d347e6114781d2897bb8a63ee9 Mon Sep 17 00:00:00 2001 +From 28e03357f47e284d1670f6b9aac95557d60ecb75 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 10:58:01 +0000 -Subject: [PATCH 029/116] V4L2: Fixes from 6by9 +Subject: [PATCH 029/172] V4L2: Fixes from 6by9 V4L2: Fix EV values. Add manual shutter speed control @@ -105513,10 +105511,10 @@ index a06fb44..76f249e 100644 release_msg: -From 1216981dc3569162148f1564fc923ee684e38f0a Mon Sep 17 00:00:00 2001 +From 62a271e1a6bbd67590b5f7a03cc0f23ec00c3e1c Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 030/116] dmaengine: Add support for BCM2708 +Subject: [PATCH 030/172] dmaengine: Add support for BCM2708 Add support for DMA controller of BCM2708 as used in the Raspberry Pi. Currently it only supports cyclic DMA. @@ -106655,10 +106653,10 @@ index 0000000..10463db +MODULE_AUTHOR("Gellert Weisz "); +MODULE_LICENSE("GPL v2"); -From 9958213bdc57c1c3fd8b22995b1f7a2395ba2583 Mon Sep 17 00:00:00 2001 +From 1cd0b002163ef24b26370db2efdc928aab23357b Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:33:38 +0100 -Subject: [PATCH 031/116] ASoC: Add support for BCM2708 +Subject: [PATCH 031/172] ASoC: Add support for BCM2708 This driver adds support for digital audio (I2S) for the BCM2708 SoC that is used by the @@ -107790,10 +107788,10 @@ index 0000000..6fdcbc1 + +#endif -From fb6b211a34ec8a53dc8802462e801cdb431fc083 Mon Sep 17 00:00:00 2001 +From 2ef6c0731bcb96af4407789a69e4bcf345ec7902 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:59:51 +0100 -Subject: [PATCH 032/116] ASoC: Add support for PCM5102A codec +Subject: [PATCH 032/172] ASoC: Add support for PCM5102A codec Some definitions to support the PCM5102A codec by Texas Instruments. @@ -107807,7 +107805,7 @@ Signed-off-by: Florian Meier create mode 100644 sound/soc/codecs/pcm5102a.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 8349f98..b289dd2 100644 +index ef2c70e..1fc4390 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -81,6 +81,7 @@ config SND_SOC_ALL_CODECS @@ -107918,10 +107916,10 @@ index 0000000..126f1e9 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From 9f755aa80ac220c641d5ed21166467ddd7dfac64 Mon Sep 17 00:00:00 2001 +From 2bac890f221788793aff1fcefaeab3eaa383c536 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:04:54 +0100 -Subject: [PATCH 033/116] BCM2708: Add I2S support to board file +Subject: [PATCH 033/172] BCM2708: Add I2S support to board file Adds the required initializations for I2S to the board file of mach-bcm2708. @@ -107976,10 +107974,10 @@ index a740344..dca28ad 100644 struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); -From f20bd5bbe4efd70685acd16e51bd4fd414f374fa Mon Sep 17 00:00:00 2001 +From 1395417905d319eb6d2299a90e8fee3931ebc40c Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 034/116] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 034/172] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -108128,10 +108126,10 @@ index 0000000..4b70b45 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); +MODULE_LICENSE("GPL v2"); -From 29f894439b2d2fb15351dfa6486c7d8cba374af3 Mon Sep 17 00:00:00 2001 +From da52bd290dc3f3af3f0836a958f42b34531018cb Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:21:34 +0100 -Subject: [PATCH 035/116] BCM2708: Add HifiBerry DAC to board file +Subject: [PATCH 035/172] BCM2708: Add HifiBerry DAC to board file This adds the initalization of the HifiBerry DAC to the mach-bcm2708 board file. @@ -108179,10 +108177,10 @@ index dca28ad..50d4991 100644 struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); -From ca637d75dfa6916b8c5d2d1dbd4114bfeacc086a Mon Sep 17 00:00:00 2001 +From c413288cdaabf5aa977f0afec318222b06adf10f Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Mon, 2 Dec 2013 20:28:22 +0100 -Subject: [PATCH 036/116] BCM2708: Add I2S and DMA support to default config +Subject: [PATCH 036/172] 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. @@ -108217,10 +108215,10 @@ index 63a6546..9a0e922 100644 CONFIG_UIO_PDRV_GENIRQ=m CONFIG_STAGING=y -From d4cda2a2b50cc69386e6f2292fc042baec93c418 Mon Sep 17 00:00:00 2001 +From 272884346f761c002999fa0aafdfa64e3c038b3c Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 6 Dec 2013 20:50:28 +0100 -Subject: [PATCH 037/116] ASoC: BCM2708: Add support for RPi-DAC +Subject: [PATCH 037/172] ASoC: BCM2708: Add support for RPi-DAC This adds a machine driver for the RPi-DAC. @@ -108418,7 +108416,7 @@ index 0000000..6d6e0ba +MODULE_DESCRIPTION("ASoC Driver for RPi-DAC"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index b289dd2..c32ecbe 100644 +index 1fc4390..0a7aaf7 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -82,6 +82,7 @@ config SND_SOC_ALL_CODECS @@ -108528,10 +108526,10 @@ index 0000000..b4eaa44 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From 72230403d9af4ca82a9075a9d9641a6fbad5ae8a Mon Sep 17 00:00:00 2001 +From 38defc6ccd2879e3b61ee7fbeb71da1982fda8fc Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 038/116] ASoC: wm8804: Implement MCLK configuration options, +Subject: [PATCH 038/172] 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 @@ -108571,10 +108569,10 @@ index 1315f76..3d86ba8 100644 #define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ -From 0bb2e4cadda70cee999665f14243faaf2c19150a Mon Sep 17 00:00:00 2001 +From 061cb19834ec2ebf649ae2028efbcaff9b4cf516 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 039/116] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 039/172] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -108777,10 +108775,10 @@ index 0000000..e4f769d +MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); +MODULE_LICENSE("GPL v2"); -From 2d6d6cd0ba7c029da824b0ca5c17eb17edad10ce Mon Sep 17 00:00:00 2001 +From 0d3ca97a92ba10f025d4beb3bd8f58e097847840 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:26:08 +0100 -Subject: [PATCH 040/116] BCM2708: Added support for HiFiBerry Digi board Board +Subject: [PATCH 040/172] BCM2708: Added support for HiFiBerry Digi board Board initalization by I2C Signed-off-by: Daniel Matuschek @@ -108827,10 +108825,10 @@ index 100c223..a57cb85 100644 bcm_register_device(&snd_rpi_dac_device); bcm_register_device(&snd_pcm1794a_codec_device); -From 501ead58b3fb28519674af7f7ca770f40fbdea49 Mon Sep 17 00:00:00 2001 +From b8e27019fe2d79dc6f12b04d4a2f4de1f7a7dc75 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:27:28 +0100 -Subject: [PATCH 041/116] BCM2708: Added HiFiBerry Digi configuration option It +Subject: [PATCH 041/172] BCM2708: Added HiFiBerry Digi configuration option It will be compiled as a module by default. This also includes the WM8804 driver. @@ -108852,10 +108850,10 @@ index 3f7a237..cbd53b1 100644 CONFIG_SND_SIMPLE_CARD=m CONFIG_SOUND_PRIME=m -From 819ab2ffbc41d5d4c6cc27ee6bb334fb7dd777ae Mon Sep 17 00:00:00 2001 +From b8243e95d60019cefde3bac2db44f25c773946d5 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:36:35 +0100 -Subject: [PATCH 042/116] ASoC: wm8804: Set idle_bias_off to false Idle bias +Subject: [PATCH 042/172] ASoC: wm8804: Set idle_bias_off to false Idle bias has been change to remove warning on driver startup Signed-off-by: Daniel Matuschek @@ -108877,10 +108875,10 @@ index 3d86ba8..34f7f76 100644 .controls = wm8804_snd_controls, .num_controls = ARRAY_SIZE(wm8804_snd_controls), -From c79ade9511f2b90a0cf84d152b7ea8e2afd6293e Mon Sep 17 00:00:00 2001 +From 88ba2e5743d41046c39726fd5a483b1bb02f76ce Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 043/116] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 043/172] Add IQaudIO Sound Card support for Raspberry Pi --- arch/arm/configs/bcmrpi_defconfig | 1 + @@ -109090,38 +109088,43 @@ index 0000000..8d0e2ae +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); -From c359a5ee3bd738961427186256be97188a87bfef Mon Sep 17 00:00:00 2001 +From 397ad3a8dabc60f4ce6b1c261de7e2c31b7b1030 Mon Sep 17 00:00:00 2001 From: Howard Mitchell -Date: Fri, 28 Mar 2014 16:40:31 +0000 -Subject: [PATCH 044/116] pcm512x: Use a range macro for Volume and rename to - PCM. +Date: Mon, 2 Mar 2015 17:28:02 +0000 +Subject: [PATCH 044/172] Set a limit of 0dB on Digital Volume Control -This allows limiting the output gain to avoid clipping in the -DAC ouput stages. +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/codecs/pcm512x.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) + sound/soc/bcm/iqaudio-dac.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) -diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c -index 30c673c..2054a69 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); +diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c +index 8d0e2ae..aff7377 100644 +--- a/sound/soc/bcm/iqaudio-dac.c ++++ b/sound/soc/bcm/iqaudio-dac.c +@@ -25,7 +25,13 @@ - static const struct snd_kcontrol_new pcm512x_controls[] = { --SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, -- PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), -+SOC_DOUBLE_R_RANGE_TLV("PCM", PCM512x_DIGITAL_VOLUME_2, -+ PCM512x_DIGITAL_VOLUME_3, 0, 40, 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, + 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 d985ba5c1251ebf4e0d53e9e49808e56f0cc8742 Mon Sep 17 00:00:00 2001 +From 11c1054be4dcd9cb41f69225c2ec6ddf6f863d0a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Jun 2014 13:42:01 +0100 -Subject: [PATCH 045/116] vmstat: Workaround for issue where dirty page count +Subject: [PATCH 045/172] vmstat: Workaround for issue where dirty page count goes negative See: @@ -109148,10 +109151,10 @@ index 82e7db7..f87d16d 100644 static inline void __inc_zone_page_state(struct page *page, -From 562475ed074e8496d440350422bf2537820e4b2e Mon Sep 17 00:00:00 2001 +From 6bc933a1c5417c9ce3d1f14fabd36ec806467de5 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 20 Jun 2014 16:03:12 +0100 -Subject: [PATCH 046/116] dwc_otg: Fix various issues with root port and +Subject: [PATCH 046/172] dwc_otg: Fix various issues with root port and transaction errors Process the host port interrupts correctly (and don't trample them). @@ -109221,10 +109224,10 @@ index 4195ff2..a5566bc 100644 fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "RESET "); } -From e4364915e5e486400186b16743f27e8e683bb122 Mon Sep 17 00:00:00 2001 +From 2a2ae2efa4a1c663642cefb333a2042590818785 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 20 Jun 2014 17:23:20 +0100 -Subject: [PATCH 047/116] fiq_fsm: Implement hack for Split Interrupt +Subject: [PATCH 047/172] fiq_fsm: Implement hack for Split Interrupt transactions Hubs aren't too picky about which endpoint we send Control type split @@ -109310,10 +109313,10 @@ index 130096b..68d4f3b 100644 break; } -From c879a654179c1997fb31343ffe193cba4ce8445e Mon Sep 17 00:00:00 2001 +From f8598c5aa941bdd6ebd3e83c1e2634f1ac6057c9 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 6 Jul 2014 12:07:25 +0200 -Subject: [PATCH 048/116] spi-bcm2708: Prepare for Common Clock Framework +Subject: [PATCH 048/172] spi-bcm2708: Prepare for Common Clock Framework migration As part of migrating to use the Common Clock Framework, replace clk_enable() @@ -109358,10 +109361,10 @@ index b04a57d..349d21f 100644 free_irq(bs->irq, master); iounmap(bs->base); -From 7a09a3dce774a0a5be04e106d6cab4c45a4b8225 Mon Sep 17 00:00:00 2001 +From 0e203cd8312e0f2ecbaaa91b84302ebd08b7c7ab Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 6 Jul 2014 12:09:30 +0200 -Subject: [PATCH 049/116] BCM2708: Migrate to the Common Clock Framework +Subject: [PATCH 049/172] 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. @@ -109631,10 +109634,10 @@ index 5f9d725..0000000 - unsigned long rate; -}; -From c2eb05044f3740a2183b5b39203e970e760a07c6 Mon Sep 17 00:00:00 2001 +From ec2d83be8df77ac09c47dac5f3ac7218d92e1619 Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:46:08 +0200 -Subject: [PATCH 050/116] BCM2708: Add core Device Tree support +Subject: [PATCH 050/172] BCM2708: Add core Device Tree support Add the bare minimum needed to boot BCM2708 from a Device Tree. @@ -109799,10 +109802,10 @@ index ef12cb8..747e27a 100644 module_param(boardrev, uint, 0644); -From fa27429ce9578e756197cf04b9835603f57dfb8f Mon Sep 17 00:00:00 2001 +From be8c3d8a94f6744f2e6b3f3d41c3604d4c6cb217 Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:47:48 +0200 -Subject: [PATCH 051/116] BCM2708: armctrl: Add IRQ Device Tree support +Subject: [PATCH 051/172] BCM2708: armctrl: Add IRQ Device Tree support Add Device Tree IRQ support for BCM2708. Usage is the same as for irq-bcm2835. @@ -109972,10 +109975,10 @@ index 96fa9b9..74bacb3 100644 return 0; } -From 276be851fc57b1badfef77e9bd067fd51875e462 Mon Sep 17 00:00:00 2001 +From 235c1c651b6b85fc9f83940c08bc2055902767c9 Mon Sep 17 00:00:00 2001 From: notro Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 052/116] BCM2708: use pinctrl-bcm2835 +Subject: [PATCH 052/172] BCM2708: use pinctrl-bcm2835 Use pinctrl-bcm2835 instead of the pinctrl-bcm2708 and bcm2708_gpio combination. @@ -110052,10 +110055,10 @@ index 9aa8a3f..9d1149e 100644 .can_sleep = false, }; -From 921c71ddf380c8fc028d90b8807ef4ace70086e6 Mon Sep 17 00:00:00 2001 +From 2fddb74c345dcb1cd2b03b60f64725bb5fbb26f0 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 27 Jul 2014 20:12:58 +0200 -Subject: [PATCH 053/116] spi: bcm2708: add device tree support +Subject: [PATCH 053/172] spi: bcm2708: add device tree support Add DT support to driver and add to .dtsi file. Setup pins and spidev in .dts file. @@ -110262,10 +110265,10 @@ index 349d21f..041b5e2 100644 .probe = bcm2708_spi_probe, .remove = bcm2708_spi_remove, -From e3bc961a920dfffd560efdc592d3c3a28b92630d Mon Sep 17 00:00:00 2001 +From a9dfef3e2161f0ec30100b32639de3d6d0682836 Mon Sep 17 00:00:00 2001 From: notro Date: Tue, 29 Jul 2014 11:04:49 +0200 -Subject: [PATCH 054/116] i2c: bcm2708: add device tree support +Subject: [PATCH 054/172] i2c: bcm2708: add device tree support Add DT support to driver and add to .dtsi file. Setup pins in .dts file. @@ -110489,10 +110492,10 @@ index 7d385a3..526129b 100644 .probe = bcm2708_i2c_probe, .remove = bcm2708_i2c_remove, -From dd70f130500963aafafcee3d5dc1564c51363674 Mon Sep 17 00:00:00 2001 +From 822709b4718fcc2922306017b9307f1523eb49ed Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 14 Jul 2014 22:02:09 +0100 -Subject: [PATCH 055/116] hid: Reduce default mouse polling interval to 60Hz +Subject: [PATCH 055/172] hid: Reduce default mouse polling interval to 60Hz Reduces overhead when using X --- @@ -110528,10 +110531,10 @@ index bfbe1be..a738b25 100644 ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { -From a87afb0647b5f16ab95189f1048c3e9098c59d04 Mon Sep 17 00:00:00 2001 +From 4da45e92b0bf783d7ab22c971310d2a5f0f5fda9 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 24 Jul 2014 21:24:03 +0100 -Subject: [PATCH 056/116] usb: core: make overcurrent messages more prominent +Subject: [PATCH 056/172] usb: core: make overcurrent messages more prominent Hub overcurrent messages are more serious than "debug". Increase loglevel. --- @@ -110539,7 +110542,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 aeb50bb..21844a7 100644 +index b4bfa3a..252a3f0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4921,7 +4921,7 @@ static void port_event(struct usb_hub *hub, int port1) @@ -110552,10 +110555,10 @@ index aeb50bb..21844a7 100644 USB_PORT_FEAT_C_OVER_CURRENT); msleep(100); /* Cool down */ -From b3c65bc61773703cd8993ffb457f23a85c7487d0 Mon Sep 17 00:00:00 2001 +From 1da5f92cf41f89b2415bfb8d6726604b2fbb9aca Mon Sep 17 00:00:00 2001 From: Tim Gover Date: Tue, 22 Jul 2014 15:41:04 +0100 -Subject: [PATCH 057/116] vcsm: VideoCore shared memory service for BCM2835 +Subject: [PATCH 057/172] 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 @@ -114889,10 +114892,10 @@ index 0000000..da1c523 +MODULE_DESCRIPTION("VideoCore SharedMemory Driver"); +MODULE_LICENSE("GPL v2"); -From 8d8dc6295c000c8c7b0e56cbb74b48eb4649ee3d Mon Sep 17 00:00:00 2001 +From c98028400be74c9edc4d170293f49dc2e27d5d80 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 7 Aug 2014 02:03:50 +0100 -Subject: [PATCH 058/116] Revert "ARM: dma: Use dma_pfn_offset for dma address +Subject: [PATCH 058/172] Revert "ARM: dma: Use dma_pfn_offset for dma address translation" This reverts commit 6ce0d20016925d031f1e24d64302e4c976d7cec6. @@ -114944,10 +114947,10 @@ index b52101d..f5572d9 100644 } -From 4c9c17fcc1f351cc06268e4902d0dee92fe1a68a Mon Sep 17 00:00:00 2001 +From 431ffd837c0694e865b7aa72e284eb15fc122d7c Mon Sep 17 00:00:00 2001 From: gellert Date: Fri, 15 Aug 2014 16:35:06 +0100 -Subject: [PATCH 059/116] MMC: added alternative MMC driver +Subject: [PATCH 059/172] MMC: added alternative MMC driver --- arch/arm/configs/bcmrpi_defconfig | 2 + @@ -116650,10 +116653,10 @@ index 0000000..92febc3 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gellert Weisz"); -From 8e777a27499279a8351836a80d4df838264dc0e3 Mon Sep 17 00:00:00 2001 +From 0ccc5b840254ab00236b28ccb0156f59ddc72807 Mon Sep 17 00:00:00 2001 From: P33M Date: Tue, 13 Jan 2015 17:12:18 +0000 -Subject: [PATCH 060/116] mmc: Disable CMD23 transfers on all cards +Subject: [PATCH 060/172] 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 @@ -116679,10 +116682,10 @@ index dd1d1e0..f472082 100644 } EXPORT_SYMBOL(mmc_fixup_device); -From a869a7389e5a734bbbc42c70c3950b2f49cc3591 Mon Sep 17 00:00:00 2001 +From 83621e3bccbabed1a256973918dc5bcf9039a56b Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 10:06:56 +0200 -Subject: [PATCH 061/116] Added support for HiFiBerry DAC+ +Subject: [PATCH 061/172] 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. @@ -116906,10 +116909,10 @@ index 0000000..c63387b +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+"); +MODULE_LICENSE("GPL v2"); -From 45fa955cf4e5d54a01c807c1a18cb0828bd45b9a Mon Sep 17 00:00:00 2001 +From ecc316d9abb1a30fae40c0581aba6439aa732474 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 11:09:58 +0200 -Subject: [PATCH 062/116] Added driver for HiFiBerry Amp amplifier add-on board +Subject: [PATCH 062/172] 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. @@ -117127,7 +117130,7 @@ index 0000000..1e87ee0 +MODULE_DESCRIPTION("ASoC driver for HiFiBerry-AMP"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index c32ecbe..664dc4d 100644 +index 0a7aaf7..45dd4fd 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -107,6 +107,7 @@ config SND_SOC_ALL_CODECS @@ -117753,10 +117756,10 @@ index 0000000..8f019e0 + +#endif /* _TAS5713_H */ -From 861c08aec9f2f1c1a22b3d7d8ae19fec798f7832 Mon Sep 17 00:00:00 2001 +From 0d81e702b6c48cf3f39d4a13588d273868554490 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Oct 2014 11:47:53 +0100 -Subject: [PATCH 063/116] Improve __copy_to_user and __copy_from_user +Subject: [PATCH 063/172] Improve __copy_to_user and __copy_from_user performance Provide a __copy_from_user that uses memcpy. On BCM2708, use @@ -119280,10 +119283,10 @@ index 3e58d71..0622891 100644 static unsigned long noinline __clear_user_memset(void __user *addr, unsigned long n) -From 118e894115980f246a4e092d51c15fa8fa17b242 Mon Sep 17 00:00:00 2001 +From 35fe870af907a92f71132723506d92329c3de6fe Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 1 Sep 2014 16:35:56 +0100 -Subject: [PATCH 064/116] bcm2708: Allow option card devices to be configured +Subject: [PATCH 064/172] bcm2708: Allow option card devices to be configured via DT If the kernel is built with Device Tree support, and if a DT blob @@ -119720,10 +119723,10 @@ index 03fa1cb..c816526 100644 static struct platform_driver bcm2835_i2s_driver = { .probe = bcm2835_i2s_probe, -From 2da679d67d7dd011f01649577c7bae50186f0363 Mon Sep 17 00:00:00 2001 +From 905b491a759bb3264e073771cbd200e747ef7a02 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 12 Nov 2014 17:07:02 +0000 -Subject: [PATCH 065/116] Adding Device Tree support for some RPi audio cards +Subject: [PATCH 065/172] Adding Device Tree support for some RPi audio cards --- arch/arm/boot/dts/Makefile | 4 ++ @@ -120292,10 +120295,10 @@ index e4f769d..76af8a6 100644 .probe = snd_rpi_hifiberry_digi_probe, .remove = snd_rpi_hifiberry_digi_remove, diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c -index 8d0e2ae..ee8cd6e 100644 +index aff7377..a38e874 100644 --- a/sound/soc/bcm/iqaudio-dac.c +++ b/sound/soc/bcm/iqaudio-dac.c -@@ -76,6 +76,21 @@ static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev) +@@ -82,6 +82,21 @@ static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev) int ret = 0; snd_rpi_iqaudio_dac.dev = &pdev->dev; @@ -120317,7 +120320,7 @@ index 8d0e2ae..ee8cd6e 100644 ret = snd_soc_register_card(&snd_rpi_iqaudio_dac); if (ret) dev_err(&pdev->dev, -@@ -93,6 +108,7 @@ static const struct of_device_id iqaudio_of_match[] = { +@@ -99,6 +114,7 @@ static const struct of_device_id iqaudio_of_match[] = { { .compatible = "iqaudio,iqaudio-dac", }, {}, }; @@ -120350,10 +120353,10 @@ index 126f1e9..7c6598e 100644 }; -From 5248d61fbed6a412104089d671ac2c864a76aa79 Mon Sep 17 00:00:00 2001 +From 50224e08199906d8bad2b40db5a2445f18f1851b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 5 Dec 2014 17:26:26 +0000 -Subject: [PATCH 066/116] fdt: Add support for the CONFIG_CMDLINE_EXTEND option +Subject: [PATCH 066/172] fdt: Add support for the CONFIG_CMDLINE_EXTEND option --- drivers/of/fdt.c | 29 ++++++++++++++++++++++++----- @@ -120408,10 +120411,10 @@ index 5100742..d6d944c 100644 pr_debug("Command line is: %s\n", (char*)data); -From e81caed711b76987fa7764e67896ac244c5b9974 Mon Sep 17 00:00:00 2001 +From e321ee5ea13db9279cc73e4ed85feb572738f520 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 25 Nov 2014 13:39:03 +0000 -Subject: [PATCH 067/116] config: Enable device tree +Subject: [PATCH 067/172] config: Enable device tree --- arch/arm/configs/bcmrpi_defconfig | 1 + @@ -120430,10 +120433,10 @@ index 8381041..c1621fa 100644 CONFIG_AEABI=y CONFIG_CLEANCACHE=y -From 3b2f8e42a35ab1ca8c7702bc1a8c6b63aa3def82 Mon Sep 17 00:00:00 2001 +From 30d815a127ab3fc90b634fc9e78b0a54e8cecd13 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 16 Dec 2014 10:23:48 +0000 -Subject: [PATCH 068/116] DT: Add overrides to enable i2c0, i2c1, spi and i2s +Subject: [PATCH 068/172] DT: Add overrides to enable i2c0, i2c1, spi and i2s --- arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 10 ++++++++++ @@ -120477,10 +120480,10 @@ index d8c6d15..167b22b 100644 + }; +}; -From 1e78b4625b77406af9cd50eef75ce67caf39a013 Mon Sep 17 00:00:00 2001 +From 4221b401eb7ca80823af64dfabf78e5663b96077 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 18 Dec 2014 16:48:32 +0000 -Subject: [PATCH 069/116] lirc-rpi: Add device tree support, and a suitable +Subject: [PATCH 069/172] lirc-rpi: Add device tree support, and a suitable overlay The overlay supports DT parameters that match the old module @@ -120774,10 +120777,10 @@ index c688364..cd66ca2 100644 if (result < 0) goto exit_rpi; -From 31368425270f59c0cb73143bf8bbdbb4ba8f380c Mon Sep 17 00:00:00 2001 +From 5dc9913bd2a47c049baf736b93efc014725c0527 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 6 Jan 2015 12:06:55 +0000 -Subject: [PATCH 070/116] Fix the activity LED in DT mode +Subject: [PATCH 070/172] 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: @@ -120909,10 +120912,10 @@ index 6b36128..1b56cb5 100644 clocks { -From 16c5ca7134e6e1fe86d9127dc4d43005ffd50b27 Mon Sep 17 00:00:00 2001 +From 86473a27065173f994c13a3431b1ebf3310e52e9 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 15 Jan 2015 10:39:06 +0000 -Subject: [PATCH 071/116] Adding w1-gpio device tree overlays +Subject: [PATCH 071/172] Adding w1-gpio device tree overlays N.B. Requires firmware supporting multi-target overrides @@ -121022,10 +121025,10 @@ index 0000000..b3e97c2 + }; +}; -From 62b86f21e94a0f4a01d825ec59cfab4cdb00642c Mon Sep 17 00:00:00 2001 +From 323b2e846c0d31be3fabcbed62734c0bb5023f80 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Fri, 23 Jan 2015 16:41:17 +0100 -Subject: [PATCH 072/116] TAS5713: return error if initialisation fails +Subject: [PATCH 072/172] 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 @@ -121092,10 +121095,10 @@ index a24c1da..9b27138 100644 return 0; } -From 10df9d22f5af3349cf9cc3a7d2a793237b65d41a Mon Sep 17 00:00:00 2001 +From 62301cba70c8943a53af4664c805573bdd86face Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 14:48:55 +0000 -Subject: [PATCH 073/116] scripts/dtc: Update to upstream version with overlay +Subject: [PATCH 073/172] scripts/dtc: Update to upstream version with overlay patches --- @@ -126308,10 +126311,10 @@ index 54d4e904..d644002 100644 -#define DTC_VERSION "DTC 1.4.0-dirty" +#define DTC_VERSION "DTC 1.4.1-g36c70742" -From 539a294591de138f45c9c2afd2a8e4477bc26e30 Mon Sep 17 00:00:00 2001 +From 919255c79510712b052391025207715033647954 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 15:18:03 +0000 -Subject: [PATCH 074/116] BCM2708_DT: Build the overlays as well +Subject: [PATCH 074/172] BCM2708_DT: Build the overlays as well --- arch/arm/boot/dts/Makefile | 13 +++++++++++++ @@ -126346,10 +126349,10 @@ index 76e5f96..54ee8c5 100644 + DTC_FLAGS ?= -@ +endif -From 4c4650200f97c0b51722931283ad0c9cb824a71f Mon Sep 17 00:00:00 2001 +From 404893c9ba110f8ea40335f8a62fb49465cf85df Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Sun, 25 Jan 2015 19:41:06 +0100 -Subject: [PATCH 075/116] Add device tree overlay for HiFiBerry Amp/Amp+ +Subject: [PATCH 075/172] Add device tree overlay for HiFiBerry Amp/Amp+ This patch add the missing device tree file for the HiFiBerry Amp and Amp+ boards. --- @@ -126416,10 +126419,10 @@ index 0000000..2c81448 + }; +}; -From d701420a7d7e98c562cd64ad17c9721fdb42b692 Mon Sep 17 00:00:00 2001 +From c38d9b463556778c95bdaafbae9d2a0617850797 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 26 Jan 2015 09:18:24 +0000 -Subject: [PATCH 076/116] Add pps-gpio DT overlay +Subject: [PATCH 076/172] Add pps-gpio DT overlay Parameters: gpiopin= // Default 18 @@ -126482,10 +126485,10 @@ index 0000000..40bf0e1 + }; +}; -From 2365c3f2d426fa6a31e77fc0d8f094118cb8094d Mon Sep 17 00:00:00 2001 +From a272e3850258f898431b680c23c771d6cd8a99a5 Mon Sep 17 00:00:00 2001 From: Serge Schneider Date: Wed, 3 Sep 2014 14:44:22 +0100 -Subject: [PATCH 077/116] I2C: Only register the I2C device for the current +Subject: [PATCH 077/172] I2C: Only register the I2C device for the current board revision --- @@ -126529,10 +126532,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 312bed5a32e235a6ee01550424b185a7c643ed16 Mon Sep 17 00:00:00 2001 +From be479e15759f47ee002fa335e7ad5120fb493a54 Mon Sep 17 00:00:00 2001 From: Timo Kokkonen Date: Wed, 29 Oct 2014 23:30:30 -0700 -Subject: [PATCH 078/116] Added support to reserve/enable a GPIO pin to be used +Subject: [PATCH 078/172] Added support to reserve/enable a GPIO pin to be used from pps-gpio module (LinuxPPS). Enable PPS modules in default config for RPi. @@ -126606,10 +126609,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 4a04725639c14e9895879571be4d4b79f190e603 Mon Sep 17 00:00:00 2001 +From f12f6d91c196ce12836bafcab75b0031903dc74c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 26 Jan 2015 15:26:10 +0000 -Subject: [PATCH 079/116] BCM2708_DT: Correct length of the peripheral space +Subject: [PATCH 079/172] BCM2708_DT: Correct length of the peripheral space --- arch/arm/boot/dts/bcm2708.dtsi | 2 +- @@ -126629,10 +126632,10 @@ index 1b56cb5..d879316 100644 intc: interrupt-controller { compatible = "brcm,bcm2708-armctrl-ic"; -From 64c6a61c55b29bc8768587849a1c9a31a90ca8c7 Mon Sep 17 00:00:00 2001 +From c9ee485e8bd038ba21ad37da134fe4170d32ab5c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 28 Jan 2015 16:22:04 +0000 -Subject: [PATCH 080/116] BCM2708_DT: Add pcf8523-rtc overlay +Subject: [PATCH 080/172] BCM2708_DT: Add pcf8523-rtc overlay --- arch/arm/boot/dts/Makefile | 1 + @@ -126681,10 +126684,10 @@ index 0000000..0071f62 + }; +}; -From 52f848ae973d5467bfc211499f12da71544f4b59 Mon Sep 17 00:00:00 2001 +From 10beb512f97f3d5c1bf4279ee2890316081e9edb Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Sat, 31 Jan 2015 16:07:56 +0100 -Subject: [PATCH 081/116] Add a parameter to turn off SPDIF output if no audio +Subject: [PATCH 081/172] 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. @@ -126756,10 +126759,10 @@ index 76af8a6..b0e3d28 100644 static struct snd_soc_dai_link snd_rpi_hifiberry_digi_dai[] = { -From be8aa60e5fc8f86ea278be93bd3b6c198940a4c3 Mon Sep 17 00:00:00 2001 +From 1993de13349743b8edfa8cfc3be4dc4219bd1a33 Mon Sep 17 00:00:00 2001 From: Joerg Hohensohn Date: Sun, 1 Feb 2015 22:08:03 +0100 -Subject: [PATCH 082/116] bugfix for 32kHz sample rate, was missing +Subject: [PATCH 082/172] bugfix for 32kHz sample rate, was missing --- sound/soc/bcm/hifiberry_digi.c | 1 + @@ -126778,10 +126781,10 @@ index b0e3d28..133d51b 100644 case 48000: case 88200: -From 69ba0d7bf053f31f78d26cb4ce71e0847762c35c Mon Sep 17 00:00:00 2001 +From 6085a9df53b0d0cc9898f09717f334a7c3eca4bc Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:25:49 -0700 -Subject: [PATCH 083/116] Update ds1307 driver for device-tree support +Subject: [PATCH 083/172] Update ds1307 driver for device-tree support Signed-off-by: Ryan Coe --- @@ -126808,10 +126811,10 @@ index 4ffabb3..c6789a7 100644 .driver = { .name = "rtc-ds1307", -From 41f71cd0934203eaa69c65afdab09c872700d76b Mon Sep 17 00:00:00 2001 +From a4d37a3da2f277ca9e0dc3ad5b1e1aebe16f34b5 Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:26:03 -0700 -Subject: [PATCH 084/116] Add device-tree overlay for ds1307 +Subject: [PATCH 084/172] Add device-tree overlay for ds1307 Signed-off-by: Ryan Coe --- @@ -126861,15 +126864,16 @@ index 0000000..7d27044 + }; +}; -From a32250b6048c747684e9b6666062070603903ce0 Mon Sep 17 00:00:00 2001 +From 2a055c5bad25645d230161b596df0a9702bbcc2b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 7 May 2013 14:32:27 +0100 -Subject: [PATCH 085/116] Add 2709 platform for Raspberry Pi 2 +Subject: [PATCH 085/172] Add 2709 platform for Raspberry Pi 2 --- arch/arm/Kconfig | 21 + arch/arm/Makefile | 1 + arch/arm/boot/dts/Makefile | 10 +- + arch/arm/boot/dts/bcm2708.dtsi | 2 +- arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 101 ++ arch/arm/boot/dts/bcm2709.dtsi | 160 +++ arch/arm/configs/bcm2709_defconfig | 1156 ++++++++++++++++++++ @@ -126885,7 +126889,7 @@ Subject: [PATCH 085/116] Add 2709 platform for Raspberry Pi 2 arch/arm/mach-bcm2709/armctrl.c | 357 +++++++ arch/arm/mach-bcm2709/armctrl.h | 27 + arch/arm/mach-bcm2709/bcm2708_gpio.c | 426 ++++++++ - arch/arm/mach-bcm2709/bcm2709.c | 1237 ++++++++++++++++++++++ + arch/arm/mach-bcm2709/bcm2709.c | 1234 ++++++++++++++++++++++ arch/arm/mach-bcm2709/bcm2709.h | 49 + arch/arm/mach-bcm2709/clock.c | 61 ++ arch/arm/mach-bcm2709/clock.h | 24 + @@ -126932,7 +126936,7 @@ Subject: [PATCH 085/116] Add 2709 platform for Raspberry Pi 2 drivers/watchdog/Kconfig | 2 +- sound/arm/Kconfig | 2 +- sound/soc/bcm/Kconfig | 2 +- - 65 files changed, 9006 insertions(+), 16 deletions(-) + 66 files changed, 9004 insertions(+), 17 deletions(-) create mode 100644 arch/arm/boot/dts/bcm2709-rpi-2-b.dts create mode 100644 arch/arm/boot/dts/bcm2709.dtsi create mode 100644 arch/arm/configs/bcm2709_defconfig @@ -127059,6 +127063,19 @@ index 2685794..83dceff 100644 +ifeq ($(RPI_DT_OVERLAYS),y) DTC_FLAGS ?= -@ endif +diff --git a/arch/arm/boot/dts/bcm2708.dtsi b/arch/arm/boot/dts/bcm2708.dtsi +index d879316..af6b1d9 100644 +--- a/arch/arm/boot/dts/bcm2708.dtsi ++++ b/arch/arm/boot/dts/bcm2708.dtsi +@@ -81,7 +81,7 @@ + compatible = "gpio-leds"; + + act_led: act { +- label = "ACT"; ++ label = "led0"; + linux,default-trigger = "mmc0"; + }; + }; diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts new file mode 100644 index 0000000..0cdff31 @@ -130095,10 +130112,10 @@ index 0000000..c1e9254 +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c new file mode 100644 -index 0000000..abe2b19 +index 0000000..3055e72d --- /dev/null +++ b/arch/arm/mach-bcm2709/bcm2709.c -@@ -0,0 +1,1237 @@ +@@ -0,0 +1,1234 @@ +/* + * linux/arch/arm/mach-bcm2709/bcm2709.c + * @@ -130922,10 +130939,13 @@ index 0000000..abe2b19 +{ + int ret; + ++ of_clk_init(NULL); + ret = of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + if (ret) { + pr_err("of_platform_populate failed: %d\n", ret); -+ use_dt = 0; ++ /* Proceed as if CONFIG_OF was not defined */ ++ } else { ++ use_dt = 1; + } +} +#else @@ -130943,8 +130963,7 @@ index 0000000..abe2b19 + pm_power_off = bcm2709_power_off; + + bcm2709_init_clocks(); -+ if (use_dt) -+ bcm2709_dt_init(); ++ bcm2709_dt_init(); + + bcm_register_device(&bcm2708_dmaman_device); + bcm_register_device(&bcm2708_vcio_device); @@ -131191,11 +131210,6 @@ index 0000000..abe2b19 + * the allocations won't fail. + */ + init_dma_coherent_pool_size(SZ_4M); -+ -+#ifdef CONFIG_OF -+ if (of_root) -+ use_dt = 1; -+#endif +} + +static void __init board_reserve(void) @@ -133804,7 +133818,7 @@ index 0000000..e6eb84d +#endif diff --git a/arch/arm/mach-bcm2709/include/mach/irqs.h b/arch/arm/mach-bcm2709/include/mach/irqs.h new file mode 100644 -index 0000000..3a883d2 +index 0000000..d301f06c --- /dev/null +++ b/arch/arm/mach-bcm2709/include/mach/irqs.h @@ -0,0 +1,225 @@ @@ -134027,9 +134041,9 @@ index 0000000..3a883d2 +#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_ */ @@ -136508,33 +136522,10 @@ index a562ddf..40d27c1 100644 select SND_SOC_DMAENGINE_PCM select SND_SOC_GENERIC_DMAENGINE_PCM -From 7aa31f395f25f5f05a01b1a89cde6b4db0d09008 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 11 Feb 2015 21:17:28 +0000 -Subject: [PATCH 086/116] m - ---- - arch/arm/boot/dts/bcm2708.dtsi | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm/boot/dts/bcm2708.dtsi b/arch/arm/boot/dts/bcm2708.dtsi -index d879316..af6b1d9 100644 ---- a/arch/arm/boot/dts/bcm2708.dtsi -+++ b/arch/arm/boot/dts/bcm2708.dtsi -@@ -81,7 +81,7 @@ - compatible = "gpio-leds"; - - act_led: act { -- label = "ACT"; -+ label = "led0"; - linux,default-trigger = "mmc0"; - }; - }; - -From 1ea263df8ad7e1f95b90c743928f4f16c4adad25 Mon Sep 17 00:00:00 2001 +From 3e5e6153b4da56ee47cb1becb41f40ad61d569b2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 Feb 2015 13:50:57 +0000 -Subject: [PATCH 087/116] BCM270x_DT: Add pwr_led, and the required "input" +Subject: [PATCH 086/172] BCM270x_DT: Add pwr_led, and the required "input" trigger The "input" trigger makes the associated GPIO an input. This is to support @@ -136797,10 +136788,10 @@ index 0000000..2ca2b98 +MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\""); +MODULE_LICENSE("GPL"); -From 6c049544cfa8435965027d48d006cbddb8ae9f9d Mon Sep 17 00:00:00 2001 +From d3db7dad4705421430c8dc3ba6853038a3988f99 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 20 Jun 2014 17:19:27 +0100 -Subject: [PATCH 088/116] bcm2709: Simplify and strip down IRQ handler +Subject: [PATCH 087/172] bcm2709: Simplify and strip down IRQ handler --- arch/arm/include/asm/entry-macro-multi.S | 2 + @@ -137017,10 +137008,10 @@ index d08591b..101d9f1 100644 +1: get_irqnr_and_base r0, r2, r6, lr + .endm -From 47f63d0ccfea3b7db13b87e2ccbebe33b7ddcf75 Mon Sep 17 00:00:00 2001 +From b54978ca2faf286b4a3836a232139140f514362f Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 24 Sep 2014 11:57:51 +0100 -Subject: [PATCH 089/116] dwc_otg: FIQ support on SMP. Set up FIQ stack and +Subject: [PATCH 088/172] dwc_otg: FIQ support on SMP. Set up FIQ stack and handler on Core 0 only. --- @@ -137150,10 +137141,10 @@ index 98e1dc5..4d8dd95 100644 otg_dev->hcd->otg_dev = otg_dev; -From 12805880485af569b79de901a9c3554ed921ee77 Mon Sep 17 00:00:00 2001 +From e012a834d4a47ffe38f00d1a48da854680d51be6 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 26 Sep 2014 11:32:09 +0100 -Subject: [PATCH 090/116] dwc_otg: introduce fiq_fsm_spin(un|)lock() +Subject: [PATCH 089/172] 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 @@ -137470,10 +137461,10 @@ index a5566bc..ee35196 100644 } -From f98835f1f026ab44f70fc03b301ab1c2e6e695e0 Mon Sep 17 00:00:00 2001 +From 2180b4febd684a72e2ef217fdb87a26dcc4073dc Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 22 Jan 2015 11:59:41 +0000 -Subject: [PATCH 091/116] fiq_fsm: fix build on bcm2708 and bcm2709 platforms +Subject: [PATCH 090/172] fiq_fsm: fix build on bcm2708 and bcm2709 platforms --- drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 8 ++++++++ @@ -137516,10 +137507,10 @@ index 84618a5..0d2b04e 100644 /** * fiq_fsm_restart_channel() - Poke channel enable bit for a split transaction -From 51c50dde85c608d033d80e415fc43a90301745f9 Mon Sep 17 00:00:00 2001 +From e4d3c223f680bb7a75fc99d53603923afb28b1dd Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 22 Jan 2015 17:49:23 +0000 -Subject: [PATCH 092/116] dwc_otg: put some barriers back where they should be +Subject: [PATCH 091/172] dwc_otg: put some barriers back where they should be for UP --- @@ -137559,17 +137550,17 @@ index 124ac16..ac70f1d 100644 local_fiq_enable(); return 0; -From 7ee3bc393f55effdcf46eeca95f4e03552d68ea6 Mon Sep 17 00:00:00 2001 +From e9c0e5a0de4a65238b03ba6729a3d3611e0e0d8a Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 22 Jan 2015 18:02:44 +0000 -Subject: [PATCH 093/116] mach_bcm2709: Add Mailbox resources to USB driver +Subject: [PATCH 092/172] mach_bcm2709: Add Mailbox resources to USB driver --- arch/arm/mach-bcm2709/bcm2709.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index abe2b19..945bb94 100644 +index 3055e72d..3cb3756 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -338,6 +338,16 @@ static struct resource bcm2708_usb_resources[] = { @@ -137590,10 +137581,10 @@ index abe2b19..945bb94 100644 -From 20c510ab62a8926d6737f7f8e2473abb9f0f8fe3 Mon Sep 17 00:00:00 2001 +From ec73fdffb06f1c2751229834465ffd3152bdfd3f Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 22 Jan 2015 18:45:23 +0000 -Subject: [PATCH 094/116] bcm2709/dwc_otg: Setup FIQ on core 1 if >1 core +Subject: [PATCH 093/172] bcm2709/dwc_otg: Setup FIQ on core 1 if >1 core active --- @@ -137656,17 +137647,17 @@ index 4d8dd95..1d28459 100644 otg_dev->hcd->otg_dev = otg_dev; hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd); -From b67ceafbe780931f9c14a2aac406b9a7b8089add Mon Sep 17 00:00:00 2001 +From f1c713f051a95787416095a6dbfe5846a15c9f8e Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 26 Jan 2015 17:40:22 +0000 -Subject: [PATCH 095/116] bcm2709: Port pps-gpio and i2c patches +Subject: [PATCH 094/172] bcm2709: Port pps-gpio and i2c patches --- arch/arm/mach-bcm2709/bcm2709.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index 945bb94..c4a37e8 100644 +index 3cb3756..8936427 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -37,6 +37,7 @@ @@ -137706,7 +137697,7 @@ index 945bb94..c4a37e8 100644 static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON); static struct platform_device bcm2708_fb_device = { -@@ -860,6 +876,16 @@ void __init bcm2709_init(void) +@@ -862,6 +878,16 @@ void __init bcm2709_init(void) #ifdef CONFIG_BCM2708_GPIO bcm_register_device_dt(&bcm2708_gpio_device); #endif @@ -137723,7 +137714,7 @@ index 945bb94..c4a37e8 100644 #if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE) w1_gpio_pdata.pin = w1_gpio_pin; w1_gpio_pdata.ext_pullup_enable_pin = w1_gpio_pullup; -@@ -884,8 +910,15 @@ void __init bcm2709_init(void) +@@ -886,8 +912,15 @@ void __init bcm2709_init(void) bcm_register_device(&bcm2835_thermal_device); bcm_register_device_dt(&bcm2708_spi_device); @@ -137741,7 +137732,7 @@ index 945bb94..c4a37e8 100644 #if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE) bcm_register_device_dt(&bcm2708_i2s_device); -@@ -1245,3 +1278,7 @@ module_param(disk_led_active_low, uint, 0644); +@@ -1242,3 +1275,7 @@ module_param(disk_led_active_low, uint, 0644); module_param(reboot_part, uint, 0644); module_param(w1_gpio_pin, uint, 0644); module_param(w1_gpio_pullup, uint, 0644); @@ -137750,20 +137741,20 @@ index 945bb94..c4a37e8 100644 +module_param(vc_i2c_override, bool, 0644); +MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral."); -From 69f6f452dba6d3cf1f3b34d1a51b514585f14ddc Mon Sep 17 00:00:00 2001 +From 30a40bd6d577e4b4b4b13c3bb249a99aa8216def Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 28 Jan 2015 17:57:23 +0000 -Subject: [PATCH 096/116] bcm2709: Also accept the 2708 machine ID +Subject: [PATCH 095/172] bcm2709: Also accept the 2708 machine ID --- arch/arm/mach-bcm2709/bcm2709.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index c4a37e8..8af141c 100644 +index 8936427..55c21a5 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c -@@ -1270,6 +1270,19 @@ MACHINE_START(BCM2709, "BCM2709") +@@ -1267,6 +1267,19 @@ MACHINE_START(BCM2709, "BCM2709") .dt_compat = bcm2709_compat, MACHINE_END @@ -137784,10 +137775,10 @@ index c4a37e8..8af141c 100644 module_param(serial, uint, 0644); module_param(uart_clock, uint, 0644); -From 05a197df4f859169c86c2a72f6ae05d4c22adcb9 Mon Sep 17 00:00:00 2001 +From 24097ac1917183b1b10b2315a1a3db527fcf8dfb Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 2 Feb 2015 12:45:07 +0000 -Subject: [PATCH 097/116] BCM2709_DT: Fix bad merge +Subject: [PATCH 096/172] BCM2709_DT: Fix bad merge --- arch/arm/boot/dts/Makefile | 25 +++++++++++++------------ @@ -137830,10 +137821,10 @@ index 83dceff..f3b6364 100644 dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b-plus.dtb dtb-$(CONFIG_ARCH_BCM_5301X) += \ -From 8e225da0cd3ec867d130c64274e1c721ca03a0b2 Mon Sep 17 00:00:00 2001 +From f3e38d36525f6f1f59dacddd9595ad860ae2eacd Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Tue, 3 Feb 2015 07:15:19 +0100 -Subject: [PATCH 098/116] HiFiBerry Amp: fix device-tree problems +Subject: [PATCH 097/172] 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. --- @@ -137887,10 +137878,10 @@ index 1e87ee0..5903915 100644 .probe = snd_rpi_hifiberry_amp_probe, .remove = snd_rpi_hifiberry_amp_remove, -From 3e5856f6269407f9671fdb7b4ad2571ad6491864 Mon Sep 17 00:00:00 2001 +From 93addb736b05475b6ed41035b4dab1eee9bf35e4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 3 Feb 2015 11:41:38 +0000 -Subject: [PATCH 099/116] BCM270x_DT: Add i2c0_baudrate and i2c1_baudrate +Subject: [PATCH 098/172] BCM270x_DT: Add i2c0_baudrate and i2c1_baudrate parameters --- @@ -137939,10 +137930,10 @@ index 46f4908..75c222f 100644 act_led_gpio = <&act_led>,"gpios:4"; act_led_activelow = <&act_led>,"gpios:8"; -From 9931580d09fb02180ad2b9951173adf4b616758b Mon Sep 17 00:00:00 2001 +From 83bef71ee725251abe65c91dd6ae76547acbc5ca Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 4 Feb 2015 10:02:24 +0000 -Subject: [PATCH 100/116] pinctrl-bcm2835: bcm2835_gpio_direction_output must +Subject: [PATCH 099/172] pinctrl-bcm2835: bcm2835_gpio_direction_output must set the value --- @@ -137970,10 +137961,10 @@ index 9d1149e..d9c727b 100644 static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -From 8473beee2daf191fed1f7f552a166300170afc8f Mon Sep 17 00:00:00 2001 +From 3e2353455d485d72a0bfbfefdfd7ce3dea783b93 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 4 Feb 2015 12:59:36 +0000 -Subject: [PATCH 101/116] w1-gpio: Sort out the pullup/parasitic power tangle +Subject: [PATCH 100/172] w1-gpio: Sort out the pullup/parasitic power tangle --- arch/arm/boot/dts/w1-gpio-overlay.dts | 4 +++- @@ -138146,10 +138137,10 @@ index d58594a..feae942 100644 unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; -From ecd1431f8ccf075d1a0b8126f964c5b060fe6728 Mon Sep 17 00:00:00 2001 +From ca08a2747acc5e2033abdbae1696d00769754fda Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 4 Feb 2015 12:16:50 +0000 -Subject: [PATCH 102/116] dwc_otg: fixup read-modify-write in critical paths +Subject: [PATCH 101/172] dwc_otg: fixup read-modify-write in critical paths Be more careful about read-modify-write on registers that the FIQ also touches. @@ -138279,10 +138270,10 @@ index 17d3030..acd0dd7 100644 } } -From 49079860970f0a0435515c9a5fb2a91f08fe799d Mon Sep 17 00:00:00 2001 +From 14a8bf59835972411f4b73c37aae457ab46b6ee1 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 5 Feb 2015 16:01:44 +0000 -Subject: [PATCH 103/116] i2c_bcm2708: Fix clock reference counting +Subject: [PATCH 102/172] i2c_bcm2708: Fix clock reference counting --- drivers/i2c/busses/i2c-bcm2708.c | 12 ++++++++++-- @@ -138330,10 +138321,10 @@ index 526129b..fda59ba 100644 kfree(bi); -From 8bc381a8da1b10744c1783455495416f977f3e7c Mon Sep 17 00:00:00 2001 +From 2ec0ca5c31b9dc7498362727d40361b5d542552a Mon Sep 17 00:00:00 2001 From: Byron Bradley Date: Fri, 6 Feb 2015 14:19:41 +0000 -Subject: [PATCH 104/116] Add device-tree overlay for pcf2127 +Subject: [PATCH 103/172] Add device-tree overlay for pcf2127 Signed-off-by: Byron Bradley --- @@ -138383,10 +138374,10 @@ index 0000000..01fc81d + }; +}; -From ee1f9890529733d06b8cc1d142b16b416ada70de Mon Sep 17 00:00:00 2001 +From dc183cc424cc15195d4f5f6d559ba14da39e4c9f Mon Sep 17 00:00:00 2001 From: android Date: Mon, 25 Aug 2014 13:18:21 +0100 -Subject: [PATCH 105/116] BCM2708_VCIO : Add automatic creation of device node +Subject: [PATCH 104/172] BCM2708_VCIO : Add automatic creation of device node --- arch/arm/mach-bcm2708/vcio.c | 12 +++++++++++- @@ -138468,10 +138459,10 @@ index 5e43e85..700bff4 100644 } -From 0ca4c1f57c84bb114641176d63d16ce345f5a95d Mon Sep 17 00:00:00 2001 +From 7ae975fb0e9e826f87a895915a958b9a65c0f073 Mon Sep 17 00:00:00 2001 From: jeanleflambeur Date: Sun, 1 Feb 2015 12:35:38 +0100 -Subject: [PATCH 106/116] Fix grabbing lock from atomic context in i2c driver +Subject: [PATCH 105/172] 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: @@ -138690,37 +138681,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 d3d9b024cf0bb6acdf4b79066e782fe9dab7bedd Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 8 Feb 2015 13:17:00 +0000 -Subject: [PATCH 107/116] 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 f58911890f7c4585275f9cc2b7f31b27dc8d9393 Mon Sep 17 00:00:00 2001 +From 777022879290ae0dcd44f327a73088369957f2b8 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 12 Feb 2015 11:17:53 +0000 -Subject: [PATCH 108/116] Fix LED "input" trigger implementation for 3.19 +Subject: [PATCH 106/172] Fix LED "input" trigger implementation for 3.19 --- drivers/leds/leds-gpio.c | 10 +++++++++- @@ -138807,10 +138771,10 @@ index cfceef3..4c8dc19 100644 /* Set LED brightness level */ /* Must not sleep, use a workqueue if needed */ -From 087966e5e3bafdeb9f9ac7578f4995c7cc7ecf1d Mon Sep 17 00:00:00 2001 +From 8d8b2a22f6227d1c55b05b7e4247c57fcbb3bd88 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 12 Feb 2015 11:20:00 +0000 -Subject: [PATCH 109/116] fiq_fsm: Falling out of the state machine isn't fatal +Subject: [PATCH 107/172] 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. @@ -138880,10 +138844,10 @@ index 6266661..8a31562 100644 /** Handles interrupt for a specific Host Channel */ -From 9883079d5aaa02b17431f38b90e99e8f2bcd9911 Mon Sep 17 00:00:00 2001 +From 2455e8024a76f5de920dfa3d7e3177830fcacb7a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 15 Feb 2015 12:06:16 +0000 -Subject: [PATCH 110/116] platform: Remove bcmrpi_small_defconfig +Subject: [PATCH 108/172] platform: Remove bcmrpi_small_defconfig --- arch/arm/configs/bcmrpi_small_defconfig | 103 -------------------------------- @@ -139000,10 +138964,10 @@ index 3f6e378..0000000 -CONFIG_CRC_ITU_T=y -CONFIG_LIBCRC32C=y -From d5a3db1a12fa0f7882c0830ea580f9f253859f89 Mon Sep 17 00:00:00 2001 +From 82c208c7034e6a112808b16ee6fd1b910a50494c Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 15 Feb 2015 12:09:47 +0000 -Subject: [PATCH 111/116] platform: Remove bcmrpi_sdcard_defconfig +Subject: [PATCH 109/172] platform: Remove bcmrpi_sdcard_defconfig --- arch/arm/configs/bcmrpi_sdcard_defconfig | 176 ------------------------------- @@ -139193,10 +139157,10 @@ index fef887a..0000000 -CONFIG_CRC_ITU_T=y -CONFIG_LIBCRC32C=y -From 6e8273a7683b5967a4823c961729803ef1d4e3a1 Mon Sep 17 00:00:00 2001 +From cf9e2491332c7b58f25d489baa2040ab529e7223 Mon Sep 17 00:00:00 2001 From: Rainer Herbers Date: Sun, 15 Feb 2015 13:44:14 +0100 -Subject: [PATCH 112/116] Create bmp085_i2c-sensor-overlay.dts and update +Subject: [PATCH 110/172] Create bmp085_i2c-sensor-overlay.dts and update Makefile --- @@ -139247,10 +139211,10 @@ index 0000000..b830bf2 + }; +}; -From a8f400dc12f70c4460dd162e3d8d617cf7d01493 Mon Sep 17 00:00:00 2001 +From 62d72625e0c8f80a16aca64437885bea2d8e5bee Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 16 Feb 2015 13:51:02 +0000 -Subject: [PATCH 113/116] lirc-rpi: use getnstimeofday instead of +Subject: [PATCH 111/172] lirc-rpi: use getnstimeofday instead of read_current_timer read_current_timer isn't guaranteed to return values in @@ -139306,237 +139270,10 @@ index cd66ca2..24563ec 100644 flag = !flag; } -From 5c6ec05ffc9261163ab699a95398afd23c5f2aeb Mon Sep 17 00:00:00 2001 -From: Dave Martin -Date: Tue, 17 Feb 2015 16:28:52 +0000 -Subject: [PATCH 114/116] serial: amba-pl011: Kickstart TX by explicit FIFO - fill - -urrently, the transmit state machine arranges for the TX IRQ -always to be asserted whever the FIFO fill level is below the -watermark set in IFLS, with all actual transmission being done on -the back of the TX IRQ. - -To kickstart transmission, pl011_startup() temporarily disables the -FIFO, enables loopback mode and transmits a dummy character in -order to trigger the initial assertion of the IRQ. - -This leads to two problems: - - * Unfortunately, at least some pl011-based systems seem to send - this dummy character down the wire even in loopback mode (in - addition to looping it back). This means that if - pl011_startup() is called in between other transmissions, the - odd timing of the dummy tx forces the receiver out of sync. - - This causes problems when the console is on pl011 and userspace - opens and closes the same port often (*cough* systemd *cough*, - where large amounts of console output get turned to garbage as a - result). - - It also causes a single framing error whenever the port is - opened, in particulary in kernel_init_freeable() when preparing - the initial userspace environment. - - * The ARM SBSA UART[1] is a cut-down version of pl011. The lack - of a loopback mode means that the dummy tx strategy isn't - suitable for this UART, but the other differences should be less - invasive. - -This patch makes an initial call to pl011_tx_chars() to get things -going instead of sending a dummy character. This should reduce the -turnaround time of an XON/XOFF by one IRQ latency or so, as well as -eliminating some IRQs around short writes from the tty layer. - -There is no way to find out the TX FIFO fill level from the -hardware directly, which becomes a problem when transmitting -characters outside the interrupt handler. To address this while -keeping status polling minimal, a minimum bound on the space -available is maintained in uap->tx_avail. For now, if we are not -sure there is any FIFO space at all, the driver transmits nothing -and falls back to waiting for the next TX inerrupt. - -Thanks to Andrew Jackson for spotting some dumb bugs while I was -developing this patch. - -[1] ARM-DEN-0029 Server Base System Architecture, available (click- - thru...) from http://infocenter.arm.com. Version v2.3 was - referred to when drawing the above conclusions. - -Signed-off-by: Dave Martin -Cc: Russell King -Cc: Andre Przywara ---- - drivers/tty/serial/amba-pl011.c | 64 ++++++++++++++++++----------------------- - 1 file changed, 28 insertions(+), 36 deletions(-) - -diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c -index 16ca535..e00ca32 100644 ---- a/drivers/tty/serial/amba-pl011.c -+++ b/drivers/tty/serial/amba-pl011.c -@@ -157,6 +157,7 @@ struct uart_amba_port { - unsigned int lcrh_rx; /* vendor-specific */ - unsigned int old_cr; /* state during shutdown */ - bool autorts; -+ unsigned int tx_avail; /* min TX FIFO space */ - char type[12]; - #ifdef CONFIG_DMA_ENGINE - /* DMA stuff */ -@@ -585,6 +586,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) - */ - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx += count; -+ uap->tx_avail = 0; /* DMA will be keeping the FIFO full now */ - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uap->port); -@@ -686,7 +688,8 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) - uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); - -- if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) { -+ if (uap->tx_avail < 1 && -+ readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) { - /* - * No space in the FIFO, so enable the transmit interrupt - * so we know when there is space. Note that once we've -@@ -698,6 +701,8 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) - writew(uap->port.x_char, uap->port.membase + UART01x_DR); - uap->port.icount.tx++; - uap->port.x_char = 0; -+ if (uap->tx_avail > 0) -+ uap->tx_avail--; - - /* Success - restore the DMA state */ - uap->dmacr = dmacr; -@@ -1208,6 +1213,8 @@ static void pl011_stop_tx(struct uart_port *port) - pl011_dma_tx_stop(uap); - } - -+static void pl011_tx_chars(struct uart_amba_port *uap); -+ - static void pl011_start_tx(struct uart_port *port) - { - struct uart_amba_port *uap = -@@ -1216,6 +1223,7 @@ static void pl011_start_tx(struct uart_port *port) - if (!pl011_dma_tx_start(uap)) { - uap->im |= UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); -+ pl011_tx_chars(uap); - } - } - -@@ -1283,6 +1291,7 @@ static void pl011_tx_chars(struct uart_amba_port *uap) - writew(uap->port.x_char, uap->port.membase + UART01x_DR); - uap->port.icount.tx++; - uap->port.x_char = 0; -+ uap->tx_avail--; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { -@@ -1294,14 +1303,16 @@ static void pl011_tx_chars(struct uart_amba_port *uap) - if (pl011_dma_tx_irq(uap)) - return; - -- count = uap->fifosize >> 1; -- do { -+ count = uart_circ_chars_pending(xmit); -+ if (uap->tx_avail < count) -+ count = uap->tx_avail; -+ -+ while (count--) { - writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx++; -- if (uart_circ_empty(xmit)) -- break; -- } while (--count > 0); -+ uap->tx_avail--; -+ } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uap->port); -@@ -1372,8 +1383,10 @@ static irqreturn_t pl011_int(int irq, void *dev_id) - if (status & (UART011_DSRMIS|UART011_DCDMIS| - UART011_CTSMIS|UART011_RIMIS)) - pl011_modem_status(uap); -- if (status & UART011_TXIS) -+ if (status & UART011_TXIS) { -+ uap->tx_avail = uap->fifosize >> 1; - pl011_tx_chars(uap); -+ } - - if (pass_counter-- == 0) - break; -@@ -1392,8 +1405,12 @@ static unsigned int pl011_tx_empty(struct uart_port *port) - { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); -- unsigned int status = readw(uap->port.membase + UART01x_FR); -- return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; -+ unsigned int status = readw(uap->port.membase + UART01x_FR) & -+ (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; -+ -+ if (status) -+ uap->tx_avail = uap->fifosize; -+ return status; - } - - static unsigned int pl011_get_mctrl(struct uart_port *port) -@@ -1577,7 +1594,7 @@ static int pl011_startup(struct uart_port *port) - { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); -- unsigned int cr, lcr_h, fbrd, ibrd; -+ unsigned int cr; - int retval; - - retval = pl011_hwinit(port); -@@ -1594,38 +1611,13 @@ static int pl011_startup(struct uart_port *port) - goto clk_dis; - - writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); -- -- /* -- * Provoke TX FIFO interrupt into asserting. Taking care to preserve -- * baud rate and data format specified by FBRD, IBRD and LCRH as the -- * UART may already be in use as a console. -- */ -- spin_lock_irq(&uap->port.lock); -- -- fbrd = readw(uap->port.membase + UART011_FBRD); -- ibrd = readw(uap->port.membase + UART011_IBRD); -- lcr_h = readw(uap->port.membase + uap->lcrh_rx); -- -- cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; -- writew(cr, uap->port.membase + UART011_CR); -- writew(0, uap->port.membase + UART011_FBRD); -- writew(1, uap->port.membase + UART011_IBRD); -- pl011_write_lcr_h(uap, 0); -- writew(0, uap->port.membase + UART01x_DR); -- while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) -- barrier(); -- -- writew(fbrd, uap->port.membase + UART011_FBRD); -- writew(ibrd, uap->port.membase + UART011_IBRD); -- pl011_write_lcr_h(uap, lcr_h); -+ uap->tx_avail = uap->fifosize; /* FIFO should be empty */ - - /* restore RTS and DTR */ - cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); - cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; - writew(cr, uap->port.membase + UART011_CR); - -- spin_unlock_irq(&uap->port.lock); -- - /* - * initialise the old status of the modem signals - */ - -From d0a44cbe02c860f3b533b34916c6c8efd45fffac Mon Sep 17 00:00:00 2001 +From d38f6c099572f92660d4a7125b97159b89ac5970 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 18 Feb 2015 10:40:28 +0000 -Subject: [PATCH 115/116] vc_cma: Make the vc_cma area the default contiguous +Subject: [PATCH 112/172] vc_cma: Make the vc_cma area the default contiguous DMA area --- @@ -139747,37 +139484,15229 @@ index a635f9f..bd64317 100644 VC_CMA_CHUNK_ORDER); if (!chunk) -From 3c9fd364bfa6c0f6ef725d74b72a9b77dd0d0fb4 Mon Sep 17 00:00:00 2001 +From 35c8e88b85da5994d81aad77928546f82784d5cc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Feb 2015 22:00:00 +0000 -Subject: [PATCH 116/116] config: Add TOUCHSCREEN_EGALAX +Subject: [PATCH 113/172] config: extra options --- - arch/arm/configs/bcm2709_defconfig | 1 + - arch/arm/configs/bcmrpi_defconfig | 1 + - 2 files changed, 2 insertions(+) + arch/arm/configs/bcm2709_defconfig | 23 +++- + arch/arm/configs/bcm2835_sdcard_defconfig | 176 ------------------------------ + arch/arm/configs/bcmrpi_defconfig | 22 +++- + 3 files changed, 33 insertions(+), 188 deletions(-) + delete mode 100644 arch/arm/configs/bcm2835_sdcard_defconfig diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig -index d4c18fa..1413673 100644 +index d4c18fa..bc557a5 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig -@@ -527,6 +527,7 @@ CONFIG_JOYSTICK_XPAD=m +@@ -5,7 +5,6 @@ CONFIG_LOCALVERSION="-v7" + CONFIG_SYSVIPC=y + CONFIG_POSIX_MQUEUE=y + CONFIG_FHANDLE=y +-CONFIG_AUDIT=y + CONFIG_NO_HZ=y + CONFIG_HIGH_RES_TIMERS=y + CONFIG_BSD_PROCESS_ACCT=y +@@ -14,12 +13,11 @@ CONFIG_TASKSTATS=y + CONFIG_TASK_DELAY_ACCT=y + CONFIG_TASK_XACCT=y + CONFIG_TASK_IO_ACCOUNTING=y +-CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG=m + CONFIG_IKCONFIG_PROC=y + CONFIG_CGROUP_FREEZER=y + CONFIG_CGROUP_DEVICE=y + CONFIG_CGROUP_CPUACCT=y +-CONFIG_RESOURCE_COUNTERS=y + CONFIG_MEMCG=y + CONFIG_BLK_CGROUP=y + CONFIG_NAMESPACES=y +@@ -55,7 +53,6 @@ CONFIG_SECCOMP=y + CONFIG_ZBOOT_ROM_TEXT=0x0 + CONFIG_ZBOOT_ROM_BSS=0x0 + CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait" +-CONFIG_KEXEC=y + CONFIG_CPU_FREQ=y + CONFIG_CPU_FREQ_STAT=m + CONFIG_CPU_FREQ_STAT_DETAILS=y +@@ -64,11 +61,11 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y + CONFIG_CPU_FREQ_GOV_USERSPACE=y + CONFIG_CPU_FREQ_GOV_ONDEMAND=y + CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +-CONFIG_CPU_IDLE=y + CONFIG_VFP=y + CONFIG_NEON=y + CONFIG_KERNEL_MODE_NEON=y + CONFIG_BINFMT_MISC=m ++# CONFIG_SUSPEND is not set + CONFIG_NET=y + CONFIG_PACKET=y + CONFIG_UNIX=y +@@ -126,7 +123,6 @@ CONFIG_NF_CONNTRACK_SIP=m + CONFIG_NF_CONNTRACK_TFTP=m + CONFIG_NF_CT_NETLINK=m + CONFIG_NETFILTER_XT_SET=m +-CONFIG_NETFILTER_XT_TARGET_AUDIT=m + CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m + CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m + CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +@@ -282,6 +278,7 @@ CONFIG_BRIDGE=m + CONFIG_VLAN_8021Q=m + CONFIG_VLAN_8021Q_GVRP=y + CONFIG_ATALK=m ++CONFIG_6LOWPAN=m + CONFIG_NET_SCHED=y + CONFIG_NET_SCH_CBQ=m + CONFIG_NET_SCH_HTB=m +@@ -345,6 +342,9 @@ CONFIG_BPQETHER=m + CONFIG_BAYCOM_SER_FDX=m + CONFIG_BAYCOM_SER_HDX=m + CONFIG_YAM=m ++CONFIG_CAN=m ++CONFIG_CAN_VCAN=m ++CONFIG_CAN_MCP251X=m + CONFIG_IRDA=m + CONFIG_IRLAN=m + CONFIG_IRNET=m +@@ -360,12 +360,14 @@ CONFIG_USB_IRDA=m + CONFIG_SIGMATEL_FIR=m + CONFIG_MCS_FIR=m + CONFIG_BT=m ++CONFIG_BT_6LOWPAN=m + CONFIG_BT_RFCOMM=m + CONFIG_BT_RFCOMM_TTY=y + CONFIG_BT_BNEP=m + CONFIG_BT_BNEP_MC_FILTER=y + CONFIG_BT_BNEP_PROTO_FILTER=y + CONFIG_BT_HIDP=m ++CONFIG_BT_6LOWPAN=m + CONFIG_BT_HCIBTUSB=m + CONFIG_BT_HCIBCM203X=m + CONFIG_BT_HCIBPA10X=m +@@ -394,6 +396,7 @@ CONFIG_BLK_DEV_DRBD=m + CONFIG_BLK_DEV_NBD=m + CONFIG_BLK_DEV_RAM=y + CONFIG_CDROM_PKTCDVD=m ++CONFIG_ATA_OVER_ETH=m + CONFIG_EEPROM_AT24=m + CONFIG_SCSI=y + # CONFIG_SCSI_PROC_FS is not set +@@ -527,6 +530,9 @@ CONFIG_JOYSTICK_XPAD=m CONFIG_JOYSTICK_XPAD_FF=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_EGALAX=m ++CONFIG_TOUCHSCREEN_USB_COMPOSITE=m ++CONFIG_TOUCHSCREEN_STMPE=m CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_ATI_REMOTE2=m +@@ -560,6 +566,7 @@ CONFIG_I2C_CHARDEV=m + CONFIG_I2C_MUX=m + CONFIG_I2C_BCM2708=m + CONFIG_SPI=y ++CONFIG_SPI_BCM2835=m + CONFIG_SPI_BCM2708=m + CONFIG_SPI_SPIDEV=y + CONFIG_PPS=m +@@ -567,6 +574,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 +600,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 +773,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/bcm2835_sdcard_defconfig b/arch/arm/configs/bcm2835_sdcard_defconfig +deleted file mode 100644 +index 987471b..0000000 +--- a/arch/arm/configs/bcm2835_sdcard_defconfig ++++ /dev/null +@@ -1,176 +0,0 @@ +-# CONFIG_ARM_PATCH_PHYS_VIRT is not set +-CONFIG_LOCALVERSION="-quick" +-# CONFIG_LOCALVERSION_AUTO is not set +-# CONFIG_SWAP is not set +-CONFIG_SYSVIPC=y +-CONFIG_POSIX_MQUEUE=y +-CONFIG_NO_HZ=y +-CONFIG_HIGH_RES_TIMERS=y +-CONFIG_IKCONFIG=y +-CONFIG_IKCONFIG_PROC=y +-CONFIG_KALLSYMS_ALL=y +-CONFIG_EMBEDDED=y +-CONFIG_PERF_EVENTS=y +-# CONFIG_COMPAT_BRK is not set +-CONFIG_SLAB=y +-# CONFIG_BLK_DEV_BSG is not set +-CONFIG_ARCH_BCM2708=y +-# CONFIG_BCM2708_GPIO is not set +-CONFIG_PREEMPT=y +-CONFIG_AEABI=y +-CONFIG_UACCESS_WITH_MEMCPY=y +-CONFIG_ZBOOT_ROM_TEXT=0x0 +-CONFIG_ZBOOT_ROM_BSS=0x0 +-CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait" +-CONFIG_CPU_FREQ=y +-CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y +-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +-CONFIG_CPU_FREQ_GOV_USERSPACE=y +-CONFIG_CPU_FREQ_GOV_ONDEMAND=y +-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +-CONFIG_CPU_IDLE=y +-CONFIG_VFP=y +-CONFIG_BINFMT_MISC=y +-CONFIG_NET=y +-CONFIG_PACKET=y +-CONFIG_UNIX=y +-CONFIG_INET=y +-CONFIG_IP_MULTICAST=y +-CONFIG_IP_PNP=y +-CONFIG_IP_PNP_DHCP=y +-CONFIG_IP_PNP_RARP=y +-CONFIG_SYN_COOKIES=y +-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +-# CONFIG_INET_XFRM_MODE_TUNNEL is not set +-# CONFIG_INET_XFRM_MODE_BEET is not set +-# CONFIG_INET_LRO is not set +-# CONFIG_INET_DIAG is not set +-# CONFIG_IPV6 is not set +-# CONFIG_WIRELESS is not set +-CONFIG_DEVTMPFS=y +-CONFIG_DEVTMPFS_MOUNT=y +-CONFIG_BLK_DEV_LOOP=y +-CONFIG_BLK_DEV_RAM=y +-CONFIG_SCSI=y +-# CONFIG_SCSI_PROC_FS is not set +-# CONFIG_SCSI_LOWLEVEL is not set +-CONFIG_NETDEVICES=y +-CONFIG_MII=y +-# CONFIG_NET_VENDOR_BROADCOM is not set +-# CONFIG_NET_VENDOR_CIRRUS is not set +-# CONFIG_NET_VENDOR_FARADAY is not set +-# CONFIG_NET_VENDOR_INTEL is not set +-# CONFIG_NET_VENDOR_MARVELL is not set +-# CONFIG_NET_VENDOR_MICREL is not set +-# CONFIG_NET_VENDOR_NATSEMI is not set +-# CONFIG_NET_VENDOR_SEEQ is not set +-# CONFIG_NET_VENDOR_STMICRO is not set +-# CONFIG_NET_VENDOR_WIZNET is not set +-CONFIG_PHYLIB=y +-# CONFIG_WLAN is not set +-# CONFIG_INPUT_MOUSEDEV is not set +-CONFIG_INPUT_EVDEV=y +-# CONFIG_INPUT_KEYBOARD is not set +-# CONFIG_INPUT_MOUSE is not set +-# CONFIG_SERIO is not set +-CONFIG_VT_HW_CONSOLE_BINDING=y +-# CONFIG_LEGACY_PTYS is not set +-# CONFIG_DEVKMEM is not set +-CONFIG_SERIAL_AMBA_PL011=y +-CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +-CONFIG_TTY_PRINTK=y +-CONFIG_RAW_DRIVER=y +-CONFIG_WATCHDOG=y +-CONFIG_REGULATOR=y +-CONFIG_REGULATOR_DEBUG=y +-CONFIG_REGULATOR_FIXED_VOLTAGE=y +-CONFIG_REGULATOR_VIRTUAL_CONSUMER=y +-CONFIG_REGULATOR_USERSPACE_CONSUMER=y +-CONFIG_FB=y +-CONFIG_FRAMEBUFFER_CONSOLE=y +-CONFIG_LOGO=y +-# CONFIG_LOGO_LINUX_MONO is not set +-# CONFIG_LOGO_LINUX_VGA16 is not set +-CONFIG_SOUND=y +-CONFIG_SND=y +-CONFIG_MMC=y +-CONFIG_MMC_SDHCI=y +-CONFIG_MMC_SDHCI_PLTFM=y +-CONFIG_MMC_SDHCI_BCM2708=y +-CONFIG_MMC_SDHCI_BCM2708_DMA=y +-CONFIG_NEW_LEDS=y +-CONFIG_LEDS_CLASS=y +-CONFIG_LEDS_TRIGGERS=y +-# CONFIG_IOMMU_SUPPORT is not set +-CONFIG_EXT4_FS=y +-CONFIG_EXT4_FS_POSIX_ACL=y +-CONFIG_EXT4_FS_SECURITY=y +-CONFIG_AUTOFS4_FS=y +-CONFIG_FSCACHE=y +-CONFIG_CACHEFILES=y +-CONFIG_MSDOS_FS=y +-CONFIG_VFAT_FS=y +-CONFIG_FAT_DEFAULT_IOCHARSET="ascii" +-CONFIG_TMPFS=y +-CONFIG_TMPFS_POSIX_ACL=y +-CONFIG_CONFIGFS_FS=y +-# CONFIG_MISC_FILESYSTEMS is not set +-CONFIG_NFS_FS=y +-CONFIG_NFS_V3_ACL=y +-CONFIG_NFS_V4=y +-CONFIG_ROOT_NFS=y +-CONFIG_NFS_FSCACHE=y +-CONFIG_NLS_DEFAULT="utf8" +-CONFIG_NLS_CODEPAGE_437=y +-CONFIG_NLS_CODEPAGE_737=y +-CONFIG_NLS_CODEPAGE_775=y +-CONFIG_NLS_CODEPAGE_850=y +-CONFIG_NLS_CODEPAGE_852=y +-CONFIG_NLS_CODEPAGE_855=y +-CONFIG_NLS_CODEPAGE_857=y +-CONFIG_NLS_CODEPAGE_860=y +-CONFIG_NLS_CODEPAGE_861=y +-CONFIG_NLS_CODEPAGE_862=y +-CONFIG_NLS_CODEPAGE_863=y +-CONFIG_NLS_CODEPAGE_864=y +-CONFIG_NLS_CODEPAGE_865=y +-CONFIG_NLS_CODEPAGE_866=y +-CONFIG_NLS_CODEPAGE_869=y +-CONFIG_NLS_CODEPAGE_936=y +-CONFIG_NLS_CODEPAGE_950=y +-CONFIG_NLS_CODEPAGE_932=y +-CONFIG_NLS_CODEPAGE_949=y +-CONFIG_NLS_CODEPAGE_874=y +-CONFIG_NLS_ISO8859_8=y +-CONFIG_NLS_CODEPAGE_1250=y +-CONFIG_NLS_CODEPAGE_1251=y +-CONFIG_NLS_ASCII=y +-CONFIG_NLS_ISO8859_1=y +-CONFIG_NLS_ISO8859_2=y +-CONFIG_NLS_ISO8859_3=y +-CONFIG_NLS_ISO8859_4=y +-CONFIG_NLS_ISO8859_5=y +-CONFIG_NLS_ISO8859_6=y +-CONFIG_NLS_ISO8859_7=y +-CONFIG_NLS_ISO8859_9=y +-CONFIG_NLS_ISO8859_13=y +-CONFIG_NLS_ISO8859_14=y +-CONFIG_NLS_ISO8859_15=y +-CONFIG_NLS_UTF8=y +-CONFIG_PRINTK_TIME=y +-CONFIG_DEBUG_FS=y +-# CONFIG_DEBUG_PREEMPT is not set +-# CONFIG_DEBUG_BUGVERBOSE is not set +-# CONFIG_FTRACE is not set +-CONFIG_KGDB=y +-CONFIG_KGDB_KDB=y +-# CONFIG_ARM_UNWIND is not set +-CONFIG_CRYPTO_CBC=y +-CONFIG_CRYPTO_HMAC=y +-CONFIG_CRYPTO_MD5=y +-CONFIG_CRYPTO_SHA1=y +-CONFIG_CRYPTO_DES=y +-# CONFIG_CRYPTO_ANSI_CPRNG is not set +-# CONFIG_CRYPTO_HW is not set +-CONFIG_CRC_ITU_T=y +-CONFIG_LIBCRC32C=y diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 898ebd2..70a5ea3 100644 +index 898ebd2..4d703f4 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -520,6 +520,7 @@ CONFIG_JOYSTICK_XPAD=m +@@ -4,7 +4,6 @@ CONFIG_PHYS_OFFSET=0 + CONFIG_SYSVIPC=y + CONFIG_POSIX_MQUEUE=y + CONFIG_FHANDLE=y +-CONFIG_AUDIT=y + CONFIG_NO_HZ=y + CONFIG_HIGH_RES_TIMERS=y + CONFIG_BSD_PROCESS_ACCT=y +@@ -13,12 +12,11 @@ CONFIG_TASKSTATS=y + CONFIG_TASK_DELAY_ACCT=y + CONFIG_TASK_XACCT=y + CONFIG_TASK_IO_ACCOUNTING=y +-CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG=m + CONFIG_IKCONFIG_PROC=y + CONFIG_CGROUP_FREEZER=y + CONFIG_CGROUP_DEVICE=y + CONFIG_CGROUP_CPUACCT=y +-CONFIG_RESOURCE_COUNTERS=y + CONFIG_MEMCG=y + CONFIG_BLK_CGROUP=y + CONFIG_NAMESPACES=y +@@ -50,7 +48,6 @@ CONFIG_SECCOMP=y + CONFIG_ZBOOT_ROM_TEXT=0x0 + CONFIG_ZBOOT_ROM_BSS=0x0 + CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait" +-CONFIG_KEXEC=y + CONFIG_CPU_FREQ=y + CONFIG_CPU_FREQ_STAT=m + CONFIG_CPU_FREQ_STAT_DETAILS=y +@@ -59,9 +56,9 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y + CONFIG_CPU_FREQ_GOV_USERSPACE=y + CONFIG_CPU_FREQ_GOV_ONDEMAND=y + CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +-CONFIG_CPU_IDLE=y + CONFIG_VFP=y + CONFIG_BINFMT_MISC=m ++# CONFIG_SUSPEND is not set + CONFIG_NET=y + CONFIG_PACKET=y + CONFIG_UNIX=y +@@ -119,7 +116,6 @@ CONFIG_NF_CONNTRACK_SIP=m + CONFIG_NF_CONNTRACK_TFTP=m + CONFIG_NF_CT_NETLINK=m + CONFIG_NETFILTER_XT_SET=m +-CONFIG_NETFILTER_XT_TARGET_AUDIT=m + CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m + CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m + CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +@@ -275,6 +271,7 @@ CONFIG_BRIDGE=m + CONFIG_VLAN_8021Q=m + CONFIG_VLAN_8021Q_GVRP=y + CONFIG_ATALK=m ++CONFIG_6LOWPAN=m + CONFIG_NET_SCHED=y + CONFIG_NET_SCH_CBQ=m + CONFIG_NET_SCH_HTB=m +@@ -338,6 +335,9 @@ CONFIG_BPQETHER=m + CONFIG_BAYCOM_SER_FDX=m + CONFIG_BAYCOM_SER_HDX=m + CONFIG_YAM=m ++CONFIG_CAN=m ++CONFIG_CAN_VCAN=m ++CONFIG_CAN_MCP251X=m + CONFIG_IRDA=m + CONFIG_IRLAN=m + CONFIG_IRNET=m +@@ -353,6 +353,7 @@ CONFIG_USB_IRDA=m + CONFIG_SIGMATEL_FIR=m + CONFIG_MCS_FIR=m + CONFIG_BT=m ++CONFIG_BT_6LOWPAN=m + CONFIG_BT_RFCOMM=m + CONFIG_BT_RFCOMM_TTY=y + CONFIG_BT_BNEP=m +@@ -387,6 +388,7 @@ CONFIG_BLK_DEV_DRBD=m + CONFIG_BLK_DEV_NBD=m + CONFIG_BLK_DEV_RAM=y + CONFIG_CDROM_PKTCDVD=m ++CONFIG_ATA_OVER_ETH=m + CONFIG_EEPROM_AT24=m + CONFIG_SCSI=y + # CONFIG_SCSI_PROC_FS is not set +@@ -520,6 +522,9 @@ CONFIG_JOYSTICK_XPAD=m CONFIG_JOYSTICK_XPAD_FF=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_EGALAX=m ++CONFIG_TOUCHSCREEN_USB_COMPOSITE=m ++CONFIG_TOUCHSCREEN_STMPE=m CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_ATI_REMOTE2=m +@@ -553,6 +558,7 @@ CONFIG_I2C_CHARDEV=m + CONFIG_I2C_MUX=m + CONFIG_I2C_BCM2708=m + CONFIG_SPI=y ++CONFIG_SPI_BCM2835=m + CONFIG_SPI_BCM2708=m + CONFIG_SPI_SPIDEV=y + CONFIG_PPS=m +@@ -560,6 +566,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 +592,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 +765,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 b08151a4eda84af4ce2dbe0b85dab4895964b692 Mon Sep 17 00:00:00 2001 +From: "Yann E. MORIN" +Date: Wed, 18 Feb 2015 12:46:07 +0100 +Subject: [PATCH 114/172] 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 60a017bba035a8623994425e9a4e72bf73988358 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 24 Feb 2015 13:40:50 +0000 +Subject: [PATCH 115/172] 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 d9c727b..01a8966 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 4ac9769f94555bf911430ae6bb60147c86eef83c Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 25 Feb 2015 17:14:57 +0000 +Subject: [PATCH 116/172] 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 e9793e25e0c44d44d780efcda5b338185d158b41 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Thu, 26 Feb 2015 11:42:34 +0000 +Subject: [PATCH 117/172] pinctrl: squash + +--- + drivers/pinctrl/pinctrl-bcm2835.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c +index 01a8966..ae68710 100644 +--- a/drivers/pinctrl/pinctrl-bcm2835.c ++++ b/drivers/pinctrl/pinctrl-bcm2835.c +@@ -1095,6 +1095,7 @@ static struct platform_driver bcm2835_pinctrl_driver = { + .remove = bcm2835_pinctrl_remove, + .driver = { + .name = MODULE_NAME, ++ .owner = THIS_MODULE, + .of_match_table = bcm2835_pinctrl_match, + }, + }; + +From 30ed96c07f97f78a923fa5ef0611ace11e521d1c Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 26 Feb 2015 09:58:22 +0000 +Subject: [PATCH 118/172] 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 ac3374c94c497e1e55a7b734f3bf238a5587430a Mon Sep 17 00:00:00 2001 +From: Dave Martin +Date: Fri, 27 Feb 2015 15:51:37 +0000 +Subject: [PATCH 119/172] serial/amba-pl011: Activate TX IRQ passively + +The current PL011 driver transmits a dummy character when the UART +is opened, to assert the TX IRQ for the first time +(see pl011_startup()). The UART is put in loopback mode temporarily, +so the receiver presumably shouldn't see anything. + +However... + +At least some platforms containing a PL011 send characters down the +wire even when loopback mode is enabled. This means that a +spurious NUL character may be seen at the receiver when the PL011 is +opened through the TTY layer. + +The current code also temporarily sets the baud rate to maximum and +the character width to the minimum, to that the dummy TX completes +as quickly as possible. If this is seen by the receiver it will +result in a framing error and can knock the receiver out of sync -- +turning subsequent output into garbage until synchronisation +is reestablished. (Particularly problematic during boot with systemd.) + +To avoid spurious transmissions, this patch removes assumptions about +whether the TX IRQ will fire until at least one TX IRQ has been seen. + +Instead, the UART will unmask the TX IRQ and then slow-start via +polling and timer-based soft IRQs initially. If the TTY layer writes +enough data to fill the FIFO to the interrupt threshold in one go, +the TX IRQ should assert, at which point the driver changes to +fully interrupt-driven TX. + +In this way, the TX IRQ is activated as a side-effect instead of +being done deliberately. + +This should also mean that the driver works on the SBSA Generic +UART[1] (a cut-down PL011) without invasive changes. The Generic +UART lacks some features needed for the dummy TX approach to work +(FIFO disabling and loopback). + +[1] Server Base System Architecture (ARM-DEN-0029-v2.3) + http://infocenter.arm.com/ + (click-thru required :/) + +Signed-off-by: Dave Martin +--- + drivers/tty/serial/amba-pl011.c | 165 ++++++++++++++++++++++++++++------------ + 1 file changed, 115 insertions(+), 50 deletions(-) + +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index 16ca535..c243729 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -58,6 +58,7 @@ + #include + #include + #include ++#include + + #define UART_NR 14 + +@@ -156,7 +157,9 @@ struct uart_amba_port { + unsigned int lcrh_tx; /* vendor-specific */ + unsigned int lcrh_rx; /* vendor-specific */ + unsigned int old_cr; /* state during shutdown */ ++ struct delayed_work tx_softirq_work; + bool autorts; ++ unsigned int tx_irq_seen; /* 0=none, 1=1, 2=2 or more */ + char type[12]; + #ifdef CONFIG_DMA_ENGINE + /* DMA stuff */ +@@ -440,8 +443,9 @@ static void pl011_dma_remove(struct uart_amba_port *uap) + dma_release_channel(uap->dmarx.chan); + } + +-/* Forward declare this for the refill routine */ ++/* Forward declare these for the refill routine */ + static int pl011_dma_tx_refill(struct uart_amba_port *uap); ++static void pl011_start_tx_pio(struct uart_amba_port *uap); + + /* + * The current DMA TX buffer has been sent. +@@ -479,14 +483,13 @@ static void pl011_dma_tx_callback(void *data) + return; + } + +- if (pl011_dma_tx_refill(uap) <= 0) { ++ if (pl011_dma_tx_refill(uap) <= 0) + /* + * We didn't queue a DMA buffer for some reason, but we + * have data pending to be sent. Re-enable the TX IRQ. + */ +- uap->im |= UART011_TXIM; +- writew(uap->im, uap->port.membase + UART011_IMSC); +- } ++ pl011_start_tx_pio(uap); ++ + spin_unlock_irqrestore(&uap->port.lock, flags); + } + +@@ -664,12 +667,10 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) + if (!uap->dmatx.queued) { + if (pl011_dma_tx_refill(uap) > 0) { + uap->im &= ~UART011_TXIM; +- ret = true; +- } else { +- uap->im |= UART011_TXIM; ++ writew(uap->im, uap->port.membase + ++ UART011_IMSC); ++ } else + ret = false; +- } +- writew(uap->im, uap->port.membase + UART011_IMSC); + } else if (!(uap->dmacr & UART011_TXDMAE)) { + uap->dmacr |= UART011_TXDMAE; + writew(uap->dmacr, +@@ -1208,15 +1209,24 @@ static void pl011_stop_tx(struct uart_port *port) + pl011_dma_tx_stop(uap); + } + ++static bool pl011_tx_chars(struct uart_amba_port *uap); ++ ++/* Start TX with programmed I/O only (no DMA) */ ++static void pl011_start_tx_pio(struct uart_amba_port *uap) ++{ ++ uap->im |= UART011_TXIM; ++ writew(uap->im, uap->port.membase + UART011_IMSC); ++ if (!uap->tx_irq_seen) ++ pl011_tx_chars(uap); ++} ++ + static void pl011_start_tx(struct uart_port *port) + { + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + +- if (!pl011_dma_tx_start(uap)) { +- uap->im |= UART011_TXIM; +- writew(uap->im, uap->port.membase + UART011_IMSC); +- } ++ if (!pl011_dma_tx_start(uap)) ++ pl011_start_tx_pio(uap); + } + + static void pl011_stop_rx(struct uart_port *port) +@@ -1274,40 +1284,87 @@ __acquires(&uap->port.lock) + spin_lock(&uap->port.lock); + } + +-static void pl011_tx_chars(struct uart_amba_port *uap) ++/* ++ * Transmit a character ++ * There must be at least one free entry in the TX FIFO to accept the char. ++ * ++ * Returns true if the FIFO might have space in it afterwards; ++ * returns false if the FIFO definitely became full. ++ */ ++static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c) ++{ ++ writew(c, uap->port.membase + UART01x_DR); ++ uap->port.icount.tx++; ++ ++ if (likely(uap->tx_irq_seen > 1)) ++ return true; ++ ++ return !(readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF); ++} ++ ++static bool pl011_tx_chars(struct uart_amba_port *uap) + { + struct circ_buf *xmit = &uap->port.state->xmit; + int count; + ++ if (unlikely(uap->tx_irq_seen < 2)) ++ /* ++ * Initial FIFO fill level unknown: we must check TXFF ++ * after each write, so just try to fill up the FIFO. ++ */ ++ count = uap->fifosize; ++ else /* tx_irq_seen >= 2 */ ++ /* ++ * FIFO initially at least half-empty, so we can simply ++ * write half the FIFO without polling TXFF. ++ ++ * Note: the *first* TX IRQ can still race with ++ * pl011_start_tx_pio(), which can result in the FIFO ++ * being fuller than expected in that case. ++ */ ++ count = uap->fifosize >> 1; ++ ++ /* ++ * If the FIFO is full we're guaranteed a TX IRQ at some later point, ++ * and can't transmit immediately in any case: ++ */ ++ if (unlikely(uap->tx_irq_seen < 2 && ++ readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)) ++ return false; ++ + if (uap->port.x_char) { +- writew(uap->port.x_char, uap->port.membase + UART01x_DR); +- uap->port.icount.tx++; ++ pl011_tx_char(uap, uap->port.x_char); + uap->port.x_char = 0; +- return; ++ --count; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { + pl011_stop_tx(&uap->port); +- return; ++ goto done; + } + + /* If we are using DMA mode, try to send some characters. */ + if (pl011_dma_tx_irq(uap)) +- return; ++ goto done; + +- count = uap->fifosize >> 1; +- do { +- writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); ++ while (count-- > 0 && pl011_tx_char(uap, xmit->buf[xmit->tail])) { + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); +- uap->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; +- } while (--count > 0); ++ } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uap->port); + +- if (uart_circ_empty(xmit)) ++ if (uart_circ_empty(xmit)) { + pl011_stop_tx(&uap->port); ++ goto done; ++ } ++ ++ if (unlikely(!uap->tx_irq_seen)) ++ schedule_delayed_work(&uap->tx_softirq_work, uap->port.timeout); ++ ++done: ++ return false; + } + + static void pl011_modem_status(struct uart_amba_port *uap) +@@ -1334,6 +1391,28 @@ static void pl011_modem_status(struct uart_amba_port *uap) + wake_up_interruptible(&uap->port.state->port.delta_msr_wait); + } + ++static void pl011_tx_softirq(struct work_struct *work) ++{ ++ struct delayed_work *dwork = to_delayed_work(work); ++ struct uart_amba_port *uap = ++ container_of(dwork, struct uart_amba_port, tx_softirq_work); ++ ++ spin_lock(&uap->port.lock); ++ while (pl011_tx_chars(uap)) ; ++ spin_unlock(&uap->port.lock); ++} ++ ++static void pl011_tx_irq_seen(struct uart_amba_port *uap) ++{ ++ if (likely(uap->tx_irq_seen > 1)) ++ return; ++ ++ uap->tx_irq_seen++; ++ if (uap->tx_irq_seen < 2) ++ /* first TX IRQ */ ++ cancel_delayed_work(&uap->tx_softirq_work); ++} ++ + static irqreturn_t pl011_int(int irq, void *dev_id) + { + struct uart_amba_port *uap = dev_id; +@@ -1372,8 +1451,10 @@ static irqreturn_t pl011_int(int irq, void *dev_id) + if (status & (UART011_DSRMIS|UART011_DCDMIS| + UART011_CTSMIS|UART011_RIMIS)) + pl011_modem_status(uap); +- if (status & UART011_TXIS) ++ if (status & UART011_TXIS) { ++ pl011_tx_irq_seen(uap); + pl011_tx_chars(uap); ++ } + + if (pass_counter-- == 0) + break; +@@ -1577,7 +1658,7 @@ static int pl011_startup(struct uart_port *port) + { + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); +- unsigned int cr, lcr_h, fbrd, ibrd; ++ unsigned int cr; + int retval; + + retval = pl011_hwinit(port); +@@ -1595,29 +1676,10 @@ static int pl011_startup(struct uart_port *port) + + writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); + +- /* +- * Provoke TX FIFO interrupt into asserting. Taking care to preserve +- * baud rate and data format specified by FBRD, IBRD and LCRH as the +- * UART may already be in use as a console. +- */ +- spin_lock_irq(&uap->port.lock); +- +- fbrd = readw(uap->port.membase + UART011_FBRD); +- ibrd = readw(uap->port.membase + UART011_IBRD); +- lcr_h = readw(uap->port.membase + uap->lcrh_rx); +- +- cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; +- writew(cr, uap->port.membase + UART011_CR); +- writew(0, uap->port.membase + UART011_FBRD); +- writew(1, uap->port.membase + UART011_IBRD); +- pl011_write_lcr_h(uap, 0); +- writew(0, uap->port.membase + UART01x_DR); +- while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) +- barrier(); ++ /* Assume that TX IRQ doesn't work until we see one: */ ++ uap->tx_irq_seen = 0; + +- writew(fbrd, uap->port.membase + UART011_FBRD); +- writew(ibrd, uap->port.membase + UART011_IBRD); +- pl011_write_lcr_h(uap, lcr_h); ++ spin_lock_irq(&uap->port.lock); + + /* restore RTS and DTR */ + cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); +@@ -1672,6 +1734,8 @@ static void pl011_shutdown(struct uart_port *port) + container_of(port, struct uart_amba_port, port); + unsigned int cr; + ++ cancel_delayed_work_sync(&uap->tx_softirq_work); ++ + /* + * disable all interrupts + */ +@@ -2218,6 +2282,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) + uap->port.ops = &amba_pl011_pops; + uap->port.flags = UPF_BOOT_AUTOCONF; + uap->port.line = i; ++ INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq); + pl011_dma_probe(&dev->dev, uap); + + /* Ensure interrupts from this UART are masked and cleared */ + +From 2820ce043829968ca725e149e5a008e3eb86b570 Mon Sep 17 00:00:00 2001 +From: Dave Martin +Date: Fri, 27 Feb 2015 15:52:31 +0000 +Subject: [PATCH 120/172] serial/amba-pl011: Leave the TX IRQ alone when the + UART is not open + +Getting the TX IRQ re-asserted from scratch can be inefficient in +some setups. + +This patch avoids clearing the TX IRQ across pl011_shutdown()... +pl011_startup(), so that if the port is closed and reopened, the +IRQ will still work afterwards without having to bootstrap it again. + +The TX IRQ continues to be masked in IMSC when the UART is not in +use. + +Signed-off-by: Dave Martin +--- + drivers/tty/serial/amba-pl011.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index c243729..9c6a2f4 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -1676,9 +1676,6 @@ static int pl011_startup(struct uart_port *port) + + writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); + +- /* Assume that TX IRQ doesn't work until we see one: */ +- uap->tx_irq_seen = 0; +- + spin_lock_irq(&uap->port.lock); + + /* restore RTS and DTR */ +@@ -1742,7 +1739,7 @@ static void pl011_shutdown(struct uart_port *port) + spin_lock_irq(&uap->port.lock); + uap->im = 0; + writew(uap->im, uap->port.membase + UART011_IMSC); +- writew(0xffff, uap->port.membase + UART011_ICR); ++ writew(0xffff & ~UART011_TXIS, uap->port.membase + UART011_ICR); + spin_unlock_irq(&uap->port.lock); + + pl011_dma_shutdown(uap); + +From 8def067fc67ecc6a7023cb22af2d7e39e7af3a3d Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:09 +0100 +Subject: [PATCH 121/172] 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 815de37..ce8f420 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -106,4 +106,6 @@ source "drivers/staging/unisys/Kconfig" + + source "drivers/staging/clocking-wizard/Kconfig" + ++source "drivers/staging/fbtft/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index 33c640b..c242787 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -45,3 +45,4 @@ obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/ + obj-$(CONFIG_CRYPTO_SKEIN) += skein/ + obj-$(CONFIG_UNISYSSPAR) += unisys/ + obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/ ++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 06d51134bbb3a8c0424ff056c590f48c5c118655 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:10 +0100 +Subject: [PATCH 122/172] 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 d39ffbc96a102b600acb37c3474492efa6ec8cff Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:11 +0100 +Subject: [PATCH 123/172] 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 67c6f93bb8a6222372f8a9101f0cc251519af1cb Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:12 +0100 +Subject: [PATCH 124/172] 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 8085e50c45d7c0265dc4e964c8c97cbe6c94f0f7 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:13 +0100 +Subject: [PATCH 125/172] 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 e8dd102dd88b944666f475b2561947f014dc5322 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:14 +0100 +Subject: [PATCH 126/172] 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 ac4b97f943abb1e75ae9ce89b9a87c4c11ca7540 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:15 +0100 +Subject: [PATCH 127/172] 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 f4cd1ccd1d97e19bf697027ef2bf6fe49b7931d9 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:16 +0100 +Subject: [PATCH 128/172] 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 1fde4032c966ca64aa650d1d432f0e624dda2ef4 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:17 +0100 +Subject: [PATCH 129/172] 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 231a5ec27c7d2ef02ec3bebe2797ece490f3083e Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:18 +0100 +Subject: [PATCH 130/172] 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 4df2aaf201deb710cb086303678f90ea9f734a5e Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:19 +0100 +Subject: [PATCH 131/172] 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 514dc6a5071ade3f146f9fb20e1ed602a79858b2 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:20 +0100 +Subject: [PATCH 132/172] 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 0c2fe050a244e71f458b93795c7542f0c0f7adf9 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:21 +0100 +Subject: [PATCH 133/172] 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 0f29b5d63e6cab9d69eb1f7b18b6bd6fd79cf7bc Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:22 +0100 +Subject: [PATCH 134/172] 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 a3cb66339f091b595534af93c2e2d5439ea6eddd Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:23 +0100 +Subject: [PATCH 135/172] 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 664ff53df529fa15bbdbd95ec761b9438463ca9d Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:24 +0100 +Subject: [PATCH 136/172] 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 147010bf2cc6bcd6e415c50c9c1af9dd4e32625a Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:25 +0100 +Subject: [PATCH 137/172] 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 358b88a04cd9f842fe7ee796f366f1974f9388af Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:26 +0100 +Subject: [PATCH 138/172] 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 21e5c10651440dde2f52472e220cab45418250a2 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:27 +0100 +Subject: [PATCH 139/172] 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 c5d81394418cd5a1c03d9fb1806b487d3aeaa8c8 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:28 +0100 +Subject: [PATCH 140/172] 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 4ea4d4cde4cefeddf0de53fac33251c1e1fbef0c Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:29 +0100 +Subject: [PATCH 141/172] 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 4c95802207386b77ce4382d6da461c531b0a5233 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:30 +0100 +Subject: [PATCH 142/172] 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 bda5811957a10834fb6fff897798cb88f483df69 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:31 +0100 +Subject: [PATCH 143/172] 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 356a07e91094b2137aa065cda8109f3b311c049b Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:32 +0100 +Subject: [PATCH 144/172] 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 9b7cb18c0b0d94f9f810f51c3f1ea702041ee48a Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:33 +0100 +Subject: [PATCH 145/172] 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 fba3874e2796888b550853e6a64b38bf0dfe97f5 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:34 +0100 +Subject: [PATCH 146/172] 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 dcf965435e041238d46101633705e5b60bd448e3 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:35 +0100 +Subject: [PATCH 147/172] 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 e6ea545ba51748ab7d35a9a66d15130f10b20cde Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:36 +0100 +Subject: [PATCH 148/172] 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 6cd6c52b928abddd97ed84d81dc7dc4299e4ef0b 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 149/172] 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 4db13fcabcf3976a2996aeaabaae5c14dd203506 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Fri, 23 Jan 2015 17:20:25 +0300 +Subject: [PATCH 150/172] 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 6d2e37a80dfcefcbfbe944a494bfacd7a67fb850 Mon Sep 17 00:00:00 2001 +From: Krzysztof Adamski +Date: Thu, 22 Jan 2015 19:08:58 +0100 +Subject: [PATCH 151/172] 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 beabd79f51c4211da36c358630199afc2ecc0d70 Mon Sep 17 00:00:00 2001 +From: Mauro Stettler +Date: Sun, 25 Jan 2015 20:26:17 +0900 +Subject: [PATCH 152/172] 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 7e831153b89601cab2d004a6ac0eaeb6e734a2c8 Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:33:03 +0200 +Subject: [PATCH 153/172] 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 fd28a2e66acf9bb757cb5b63aba22e6765ab441b Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:35:30 +0200 +Subject: [PATCH 154/172] 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 6f65a6510903f0c9fceb1f3d65ff28bd9a784e6c Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:37:24 +0200 +Subject: [PATCH 155/172] 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 2e22627744670a081bb431ca45bbf5cf84a2030c Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:39:56 +0200 +Subject: [PATCH 156/172] 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 3b5f096eae4c0080b6e88f6b8aaa1fffefc5a0c7 Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:42:59 +0200 +Subject: [PATCH 157/172] 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 608b9170aa906a03b34017095c076df47c68b10b Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Wed, 28 Jan 2015 15:29:05 +0200 +Subject: [PATCH 158/172] 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 fc7a6c1b574ecf2541ba11643b4936e8b24d2b09 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 159/172] 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 bc557a5..70d9e3b 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -1027,6 +1027,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 4d703f4..1563996 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -1019,6 +1019,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 1e1f6c97e1b39e609d2c5e63db46082f5dbd1312 Mon Sep 17 00:00:00 2001 +From: Jon Burgess +Date: Tue, 17 Feb 2015 13:22:17 +0000 +Subject: [PATCH 160/172] 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 754291e..831d946 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) += 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 b06a6f1514466b593b2a533c128dc87cc8d16979 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 161/172] 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 831d946..b3b775b 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) += 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 9da9198099befac4b05083230123fd114c5d286d 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 162/172] 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 b3b775b..9d6f947 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -71,6 +71,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 44b11d19ade98ef346cb6135d5b9697deadd8b39 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 163/172] 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 9d6f947..e4b26b3 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -72,6 +72,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 9fa8ac547b9ec39fb6fcdaa4a3409aa518ffd5cc 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 164/172] 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 e4b26b3..890c789 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -78,6 +78,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 75aedead57189858c6aec1568f028d8e13445752 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 165/172] 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 4c8a8d6a18dea92a111c797d48e4b05491ec1399 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 25 Feb 2015 09:45:56 +0000 +Subject: [PATCH 166/172] 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 32765026651961cf8f67a28d224165af9adeae32 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 27 Feb 2015 15:10:24 +0000 +Subject: [PATCH 167/172] 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 890c789..7480e1c 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) += i2c-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/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 d90aba0187af45d761259e4060387821b9bfa3f4 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 168/172] 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 7480e1c..ad6984e 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -80,6 +80,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 acc9df3814ad9edf4a323c12b150123fd690f3be Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Mon, 2 Mar 2015 09:37:02 +0000 +Subject: [PATCH 169/172] 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 ad6984e..ed45f81 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -85,6 +85,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_BCM2835) += bcm2835-rpi-b-plus.dtb + dtb-$(CONFIG_ARCH_BCM_5301X) += \ +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 70d9e3b..d1d6b6c 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -568,6 +568,7 @@ CONFIG_I2C_BCM2708=m + CONFIG_SPI=y + CONFIG_SPI_BCM2835=m + 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 1563996..044de53 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -560,6 +560,7 @@ CONFIG_I2C_BCM2708=m + CONFIG_SPI=y + CONFIG_SPI_BCM2835=m + CONFIG_SPI_BCM2708=m ++CONFIG_SPI_BCM2835=m + CONFIG_SPI_SPIDEV=y + CONFIG_PPS=m + CONFIG_PPS_CLIENT_LDISC=m + +From b27eece1cbc6981540739b849572a58ffd34aefb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sat, 7 Mar 2015 20:39:30 +0100 +Subject: [PATCH 170/172] dts: overlay: add support for MZ61581 display +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add Device Tree overlay for MZ61581 display by Tontec. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/mz61581-overlay.dts | 109 ++++++++++++++++++++++++++++++++++ + 2 files changed, 110 insertions(+) + create mode 100644 arch/arm/boot/dts/mz61581-overlay.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index ed45f81..f918523 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -77,6 +77,7 @@ 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 ++dtb-$(RPI_DT_OVERLAYS) += mz61581-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 +diff --git a/arch/arm/boot/dts/mz61581-overlay.dts b/arch/arm/boot/dts/mz61581-overlay.dts +new file mode 100644 +index 0000000..c06fe12 +--- /dev/null ++++ b/arch/arm/boot/dts/mz61581-overlay.dts +@@ -0,0 +1,109 @@ ++/* ++ * Device Tree overlay for MZ61581-PI-EXT 2014.12.28 by Tontec ++ * ++ */ ++ ++/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__ { ++ mz61581_pins: mz61581_pins { ++ brcm,pins = <4 15 18 25>; ++ 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>; ++ ++ mz61581: mz61581@0{ ++ compatible = "samsung,s6d02a1"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mz61581_pins>; ++ ++ spi-max-frequency = <128000000>; ++ spi-cpol; ++ spi-cpha; ++ ++ width = <320>; ++ height = <480>; ++ rotate = <270>; ++ bgr; ++ fps = <30>; ++ buswidth = <8>; ++ ++ reset-gpios = <&gpio 15 0>; ++ dc-gpios = <&gpio 25 0>; ++ led-gpios = <&gpio 18 0>; ++ ++ init = <0x10000b0 00 ++ 0x1000011 ++ 0x20000ff ++ 0x10000b3 0x02 0x00 0x00 0x00 ++ 0x10000c0 0x13 0x3b 0x00 0x02 0x00 0x01 0x00 0x43 ++ 0x10000c1 0x08 0x16 0x08 0x08 ++ 0x10000c4 0x11 0x07 0x03 0x03 ++ 0x10000c6 0x00 ++ 0x10000c8 0x03 0x03 0x13 0x5c 0x03 0x07 0x14 0x08 0x00 0x21 0x08 0x14 0x07 0x53 0x0c 0x13 0x03 0x03 0x21 0x00 ++ 0x1000035 0x00 ++ 0x1000036 0xa0 ++ 0x100003a 0x55 ++ 0x1000044 0x00 0x01 ++ 0x10000d0 0x07 0x07 0x1d 0x03 ++ 0x10000d1 0x03 0x30 0x10 ++ 0x10000d2 0x03 0x14 0x04 ++ 0x1000029 ++ 0x100002c>; ++ ++ /* This is a workaround to make sure the init sequence slows down and doesn't fail */ ++ debug = <3>; ++ }; ++ ++ mz61581_ts: mz61581_ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <4 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 4 0>; ++ ++ ti,x-plate-ohms = /bits/ 16 <60>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&mz61581>, "spi-max-frequency:0"; ++ rotate = <&mz61581>, "rotate:0"; ++ fps = <&mz61581>, "fps:0"; ++ debug = <&mz61581>, "debug:0"; ++ xohms = <&mz61581_ts>,"ti,x-plate-ohms;0"; ++ }; ++}; + +From e5c5c9e51bb483f34f0210f0406a3cf9597f77d0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sat, 7 Mar 2015 20:40:07 +0100 +Subject: [PATCH 171/172] dts: overlay: piscreen: set speed to 24MHz +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some of the displays can't handle the 32MHz speed. +Lower the default speed to 24MHz. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/piscreen-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/piscreen-overlay.dts b/arch/arm/boot/dts/piscreen-overlay.dts +index 8cd6a95..b7fd7ea 100644 +--- a/arch/arm/boot/dts/piscreen-overlay.dts ++++ b/arch/arm/boot/dts/piscreen-overlay.dts +@@ -47,7 +47,7 @@ + pinctrl-names = "default"; + pinctrl-0 = <&piscreen_pins>; + +- spi-max-frequency = <32000000>; ++ spi-max-frequency = <24000000>; + rotate = <270>; + bgr; + fps = <30>; + +From a1c1709f994bde15ce55aac74de0dcb40761fc7b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sat, 7 Mar 2015 20:40:43 +0100 +Subject: [PATCH 172/172] dts: overlay: rpi-display: pullup irq gpio +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +An early version of rpi-display needs the touch controller irq +to be pulled up. This is the version with 9-bit SPI as default. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/rpi-display-overlay.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/rpi-display-overlay.dts b/arch/arm/boot/dts/rpi-display-overlay.dts +index 0578810..a8fa974 100644 +--- a/arch/arm/boot/dts/rpi-display-overlay.dts ++++ b/arch/arm/boot/dts/rpi-display-overlay.dts +@@ -30,6 +30,7 @@ + rpi_display_pins: rpi_display_pins { + brcm,pins = <18 23 24 25>; + brcm,function = <1 1 1 0>; /* out out out in */ ++ brcm,pull = <0 0 0 2>; /* - - - up */ + }; + }; + }; diff --git a/projects/RPi2/linux/linux.arm.conf b/projects/RPi2/linux/linux.arm.conf index e98a345de9..51d2bb19ef 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.19.0 Kernel Configuration +# Linux/arm 3.19.1 Kernel Configuration # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -92,7 +92,6 @@ CONFIG_TICK_CPU_ACCOUNTING=y # RCU Subsystem # CONFIG_TREE_RCU=y -# CONFIG_PREEMPT_RCU is not set # CONFIG_TASKS_RCU is not set CONFIG_RCU_STALL_COMMON=y # CONFIG_RCU_USER_QS is not set @@ -102,9 +101,6 @@ CONFIG_RCU_FANOUT_LEAF=16 # CONFIG_RCU_FAST_NO_HZ is not set # CONFIG_TREE_RCU_TRACE is not set # CONFIG_RCU_NOCB_CPU is not set -# CONFIG_RCU_NOCB_CPU_NONE is not set -# CONFIG_RCU_NOCB_CPU_ZERO is not set -# CONFIG_RCU_NOCB_CPU_ALL is not set CONFIG_BUILD_BIN2C=y CONFIG_IKCONFIG=m CONFIG_IKCONFIG_PROC=y @@ -2994,6 +2990,7 @@ CONFIG_LIRC_XBOX=m # CONFIG_DGAP is not set # CONFIG_GS_FPGABOOT is not set # CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set +# CONFIG_FB_TFT is not set CONFIG_CLKDEV_LOOKUP=y CONFIG_HAVE_CLK_PREPARE=y CONFIG_COMMON_CLK=y diff --git a/projects/RPi2/patches/linux/linux-01-RPi_support.patch b/projects/RPi2/patches/linux/linux-01-RPi_support.patch index f7a8bf3072..fbe6e260a5 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 0222939a3735e3ad819ce793bbcaa3f4759d6543 Mon Sep 17 00:00:00 2001 +From 8fa199a9eafe1ffbb0b1dd9c67989ea322f72306 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 001/116] Main bcm2708 linux port +Subject: [PATCH 001/172] Main bcm2708 linux port Signed-off-by: popcornmix --- @@ -2166,7 +2166,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 @@ @@ -5108,10 +5108,10 @@ index 9f32270..17ee61b 100644 mmc_pm_flag_t pm_caps; /* supported pm features */ -From db89dca23e5f1de2895f0f07d4fd14c00ab72e6e Mon Sep 17 00:00:00 2001 +From 2392ce74d3cd30172bc41023066f9f7abe7404ea Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 Oct 2014 18:50:05 +0100 -Subject: [PATCH 002/116] Add bcm2708_gpio driver +Subject: [PATCH 002/172] Add bcm2708_gpio driver Signed-off-by: popcornmix @@ -5715,10 +5715,10 @@ index 0000000..fb69624 + +#endif -From 138919e0b3e213effd883f4a80dd8b2cc4f55f4a Mon Sep 17 00:00:00 2001 +From 559f0c63be158be62310100cbe3e45d224be9592 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 7 May 2013 22:20:24 +0100 -Subject: [PATCH 003/116] Add quick config. +Subject: [PATCH 003/172] Add quick config. This is designed for quick compiling when developing. No modules are needed and it includes all Pi specific drivers @@ -5931,10 +5931,10 @@ index 0000000..e5efe75 +CONFIG_CRC_ITU_T=y +CONFIG_LIBCRC32C=y -From a2dc1f5efb2a618b0970218f3e96039776f3eaaf Mon Sep 17 00:00:00 2001 +From 08e12db8a1dcba12eeabca2b8eca4b4efa30f439 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 004/116] Add dwc_otg driver +Subject: [PATCH 004/172] Add dwc_otg driver Signed-off-by: popcornmix @@ -6095,10 +6095,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); @@ -62987,10 +62987,10 @@ index 0000000..cdc9963 +test_main(); +0; -From 426f9dbea63f0d6a35e05e80fd188b89dca321cd Mon Sep 17 00:00:00 2001 +From 21af740ba39591ca0b84bf217e5e17748c912ac8 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:54:32 +0100 -Subject: [PATCH 005/116] bcm2708 watchdog driver +Subject: [PATCH 005/172] bcm2708 watchdog driver Signed-off-by: popcornmix --- @@ -63418,11 +63418,10 @@ index 0000000..8a27d68 +MODULE_ALIAS_MISCDEV(TEMP_MINOR); +MODULE_LICENSE("GPL"); - -From 541af491f8c24af061d3e62fdc7da4fad34e5003 Mon Sep 17 00:00:00 2001 +From 44deeada252c455ee3325a19e375016d60826802 Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 008/116] Speed up console framebuffer imageblit function +Subject: [PATCH 008/172] 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 @@ -63631,10 +63630,10 @@ index a2bb276..436494f 100644 start_index, pitch_index); } else -From 21cf00e8ae1b424b05c9e218f28c509f296ac949 Mon Sep 17 00:00:00 2001 +From 33bcff1a531c7d7810dfd4f81546ddc3bffadeba Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 009/116] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 009/172] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -63727,10 +63726,10 @@ index fb795c3..fa72af0 100644 #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ #define FB_TYPE_PLANES 1 /* Non interleaved planes */ -From 57a4b2b0d8e5849d4b4cff404ac6a90bcdab0f37 Mon Sep 17 00:00:00 2001 +From 86c75685b2acfe9012480bb2301a818d3d0beea8 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:55:09 +0100 -Subject: [PATCH 010/116] bcm2708 framebuffer driver +Subject: [PATCH 010/172] bcm2708 framebuffer driver Signed-off-by: popcornmix @@ -67173,10 +67172,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 8178b4e7f56a040774a673f21b6d860a83d86d1d Mon Sep 17 00:00:00 2001 +From 3f8261010097c731e1128600efb3107dc83aa24f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 2 Jul 2013 23:42:01 +0100 -Subject: [PATCH 011/116] bcm2708 vchiq driver +Subject: [PATCH 011/172] bcm2708 vchiq driver Signed-off-by: popcornmix @@ -67298,7 +67297,7 @@ described above. create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_version.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index 006242c..4e6f46c 100644 +index 006242c..4e6f46c3 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -524,6 +524,7 @@ source "drivers/misc/carma/Kconfig" @@ -80125,10 +80124,10 @@ index 0000000..b6bfa21 + return vchiq_build_time; +} -From 48c4a760bace73c6c2e10ace250faf0b1c2cf603 Mon Sep 17 00:00:00 2001 +From 2e067b9b144d119a1b0b930dae88d2f1b29dd497 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 12 May 2014 15:12:02 +0100 -Subject: [PATCH 012/116] vchiq: Avoid high load when blocked and unkillable +Subject: [PATCH 012/172] 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 --- @@ -80290,10 +80289,10 @@ index c2eefef..05e7979 100644 static inline int is_pow2(int i) { -From d36beb1f111d0621d672edfc864c2ac018a05053 Mon Sep 17 00:00:00 2001 +From 38a6237db4d225352e14513dde856a7767e51c76 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 013/116] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 013/172] cma: Add vc_cma driver to enable use of CMA Signed-off-by: popcornmix --- @@ -81580,10 +81579,10 @@ index 0000000..5325832 + +#endif /* VC_CMA_H */ -From 9a5da41b08c71c403f7a50e3f1790bc7ce061c5d Mon Sep 17 00:00:00 2001 +From 3d1f88f9fc8393b6c8e34c991dac0dbc58ae3f4d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 014/116] bcm2708: alsa sound driver +Subject: [PATCH 014/172] bcm2708: alsa sound driver Signed-off-by: popcornmix @@ -84346,10 +84345,10 @@ index 0000000..af3e6eb + +#endif // _VC_AUDIO_DEFS_H_ -From e191bd0eb4395d58ca38628cac3a9832ac2a6644 Mon Sep 17 00:00:00 2001 +From 440a7ce5f52fd43466a0d25132a3bc855c224be9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:51:55 +0100 -Subject: [PATCH 015/116] Add hwrng (hardware random number generator) driver +Subject: [PATCH 015/172] Add hwrng (hardware random number generator) driver --- drivers/char/hw_random/Kconfig | 11 ++++ @@ -84516,10 +84515,10 @@ index 0000000..340f004 +MODULE_DESCRIPTION("BCM2708 H/W Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL and additional rights"); -From c8dfc6610d8ec3c1b55b9988aa93749420ef5ae5 Mon Sep 17 00:00:00 2001 +From f543037234f72aed89e2239f62f2dce7ea94aefa Mon Sep 17 00:00:00 2001 From: Aron Szabo Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 016/116] lirc: added support for RaspberryPi GPIO +Subject: [PATCH 016/172] 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 @@ -85251,10 +85250,10 @@ index 0000000..c688364 +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -From 95d8a71baa57259706f2211e2831910c5e8732df Mon Sep 17 00:00:00 2001 +From c66c4562de98ab99b0bd25fcd238104ce8f4ebbe Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 017/116] Add cpufreq driver +Subject: [PATCH 017/172] Add cpufreq driver --- arch/arm/Kconfig | 1 + @@ -85538,10 +85537,10 @@ index 0000000..447ca09 +module_init(bcm2835_cpufreq_module_init); +module_exit(bcm2835_cpufreq_module_exit); -From 59ae3e5f2544dacbdea86d9f005fe7f5598cdd30 Mon Sep 17 00:00:00 2001 +From b5de470ee4adcb247acbb7a8515a73db3a9494d7 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 018/116] Added hwmon/thermal driver for reporting core +Subject: [PATCH 018/172] Added hwmon/thermal driver for reporting core temperature. Thanks Dorian --- @@ -86063,10 +86062,10 @@ index 0000000..85fceb5 + +module_platform_driver(bcm2835_thermal_driver); -From 5a2d7d0a26de7791c61462bd36cb190c8ac0857d Mon Sep 17 00:00:00 2001 +From 5af87652d480b6de0edca41bde86a469bf15ffc6 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 019/116] Allow mac address to be set in smsc95xx +Subject: [PATCH 019/172] Allow mac address to be set in smsc95xx Signed-off-by: popcornmix --- @@ -86157,10 +86156,10 @@ index 26423ad..e29a323 100644 if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, dev->net->dev_addr) == 0) { -From 196215044abd081236a1acbecc02f007cb62b99c Mon Sep 17 00:00:00 2001 +From b8f0a117f160b4a8a9c41d3e61754dbe220a69dd Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 4 Nov 2013 18:56:10 +0000 -Subject: [PATCH 020/116] Add Chris Boot's i2c and spi drivers. +Subject: [PATCH 020/172] Add Chris Boot's i2c and spi drivers. i2c-bcm2708: fixed baudrate @@ -87507,10 +87506,10 @@ index 0000000..b04a57d +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -From e9ce3b546b6fd5fb38952ba1437d479c6847ef5f Mon Sep 17 00:00:00 2001 +From 682719078e0d0e6ac1abe5845faa65e5f0b579bb Mon Sep 17 00:00:00 2001 From: cbeytas Date: Mon, 24 Jun 2013 00:05:40 -0400 -Subject: [PATCH 021/116] Perform I2C combined transactions when possible +Subject: [PATCH 021/172] Perform I2C combined transactions when possible Perform I2C combined transactions whenever possible, within the restrictions of the Broadcomm Serial Controller. @@ -87582,10 +87581,10 @@ index 09203c0..7d385a3 100644 } -From 3eeb43c7ff0ec0308e78481ef4c9612ee90c2e77 Mon Sep 17 00:00:00 2001 +From db6f4cb59c89e54db302266e6c827137f3da5d96 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 022/116] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 022/172] 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 @@ -87857,11 +87856,10 @@ index 2820924..fd0550f 100644 } } - -From b356d2a5324517f468c05664c36ae2d3ad51814e Mon Sep 17 00:00:00 2001 +From 8160010b3d9ff17f29c3e332e9f3c37c527e26c0 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 12 Apr 2013 23:58:47 +0100 -Subject: [PATCH 024/116] config: add missing options from 3.6.y kernel +Subject: [PATCH 024/172] config: add missing options from 3.6.y kernel --- arch/arm/configs/bcmrpi_defconfig | 692 ++++++++++++++++++++++++++++++++++++-- @@ -88848,10 +88846,10 @@ index 6d2eae1..6b39872 100644 # CONFIG_CRYPTO_HW is not set CONFIG_CRC_ITU_T=y -From 3c7bee5134f4d492af3b6ba74ac91a76241979cf Mon Sep 17 00:00:00 2001 +From 9546603deded7c808fd5a04a691377a0cdf2fa25 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 025/116] config: Enable CONFIG_MEMCG, but leave it disabled +Subject: [PATCH 025/172] config: Enable CONFIG_MEMCG, but leave it disabled (due to memory cost). Enable with cgroup_enable=memory. --- @@ -88919,10 +88917,10 @@ index 2f6893c..8778eba 100644 #ifdef CONFIG_MEMCG_SWAP -From 675b0e93160dcb81e3d36ea3548c6d9f289928c9 Mon Sep 17 00:00:00 2001 +From c73af020d71c020a59390d693ce357e0052cf457 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:46:42 +0100 -Subject: [PATCH 026/116] Add FIQ patch to dwc_otg driver. Enable with +Subject: [PATCH 026/172] 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 @@ -92215,10 +92213,10 @@ index 1b1f83c..c8590b5 100644 if (status.b.sr) { -From 8c9d2b02c39e52c89c27d306fa1a2781fd48b014 Mon Sep 17 00:00:00 2001 +From 5cd92267e90f236fd69402f1c98eef1613d2688a Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 19 Mar 2014 12:58:23 +0000 -Subject: [PATCH 027/116] dwc_otg: fiq_fsm: Base commit for driver rewrite +Subject: [PATCH 027/172] dwc_otg: fiq_fsm: Base commit for driver rewrite This commit removes the previous FIQ fixes entirely and adds fiq_fsm. @@ -97113,10 +97111,10 @@ index 5d310df..4b32941 100644 return -EBUSY; } -From c6121acf96ef39f9c95b15760846f58b45027ee9 Mon Sep 17 00:00:00 2001 +From 264fb63a197f8df7a31f27109409699c43a5c82e Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 028/116] bcm2835: add v4l2 camera device +Subject: [PATCH 028/172] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -97228,10 +97226,10 @@ index 0000000..c585a8f + +$ v4l2-ctl --list-formats diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index 765bffb..286b7ad 100644 +index 6a1334b..8fdd7a0 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig -@@ -118,6 +118,7 @@ config VIDEO_S3C_CAMIF +@@ -116,6 +116,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" @@ -103098,10 +103096,10 @@ index 0000000..9d1d11e + +#endif /* MMAL_VCHIQ_H */ -From 876eadd8476087d347e6114781d2897bb8a63ee9 Mon Sep 17 00:00:00 2001 +From 28e03357f47e284d1670f6b9aac95557d60ecb75 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 10:58:01 +0000 -Subject: [PATCH 029/116] V4L2: Fixes from 6by9 +Subject: [PATCH 029/172] V4L2: Fixes from 6by9 V4L2: Fix EV values. Add manual shutter speed control @@ -105513,10 +105511,10 @@ index a06fb44..76f249e 100644 release_msg: -From 1216981dc3569162148f1564fc923ee684e38f0a Mon Sep 17 00:00:00 2001 +From 62a271e1a6bbd67590b5f7a03cc0f23ec00c3e1c Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 030/116] dmaengine: Add support for BCM2708 +Subject: [PATCH 030/172] dmaengine: Add support for BCM2708 Add support for DMA controller of BCM2708 as used in the Raspberry Pi. Currently it only supports cyclic DMA. @@ -106655,10 +106653,10 @@ index 0000000..10463db +MODULE_AUTHOR("Gellert Weisz "); +MODULE_LICENSE("GPL v2"); -From 9958213bdc57c1c3fd8b22995b1f7a2395ba2583 Mon Sep 17 00:00:00 2001 +From 1cd0b002163ef24b26370db2efdc928aab23357b Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:33:38 +0100 -Subject: [PATCH 031/116] ASoC: Add support for BCM2708 +Subject: [PATCH 031/172] ASoC: Add support for BCM2708 This driver adds support for digital audio (I2S) for the BCM2708 SoC that is used by the @@ -107790,10 +107788,10 @@ index 0000000..6fdcbc1 + +#endif -From fb6b211a34ec8a53dc8802462e801cdb431fc083 Mon Sep 17 00:00:00 2001 +From 2ef6c0731bcb96af4407789a69e4bcf345ec7902 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 14:59:51 +0100 -Subject: [PATCH 032/116] ASoC: Add support for PCM5102A codec +Subject: [PATCH 032/172] ASoC: Add support for PCM5102A codec Some definitions to support the PCM5102A codec by Texas Instruments. @@ -107807,7 +107805,7 @@ Signed-off-by: Florian Meier create mode 100644 sound/soc/codecs/pcm5102a.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 8349f98..b289dd2 100644 +index ef2c70e..1fc4390 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -81,6 +81,7 @@ config SND_SOC_ALL_CODECS @@ -107918,10 +107916,10 @@ index 0000000..126f1e9 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From 9f755aa80ac220c641d5ed21166467ddd7dfac64 Mon Sep 17 00:00:00 2001 +From 2bac890f221788793aff1fcefaeab3eaa383c536 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:04:54 +0100 -Subject: [PATCH 033/116] BCM2708: Add I2S support to board file +Subject: [PATCH 033/172] BCM2708: Add I2S support to board file Adds the required initializations for I2S to the board file of mach-bcm2708. @@ -107976,10 +107974,10 @@ index a740344..dca28ad 100644 struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); -From f20bd5bbe4efd70685acd16e51bd4fd414f374fa Mon Sep 17 00:00:00 2001 +From 1395417905d319eb6d2299a90e8fee3931ebc40c Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 034/116] ASoC: Add support for HifiBerry DAC +Subject: [PATCH 034/172] ASoC: Add support for HifiBerry DAC This adds a machine driver for the HifiBerry DAC. It is a sound card that can @@ -108128,10 +108126,10 @@ index 0000000..4b70b45 +MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); +MODULE_LICENSE("GPL v2"); -From 29f894439b2d2fb15351dfa6486c7d8cba374af3 Mon Sep 17 00:00:00 2001 +From da52bd290dc3f3af3f0836a958f42b34531018cb Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 19:21:34 +0100 -Subject: [PATCH 035/116] BCM2708: Add HifiBerry DAC to board file +Subject: [PATCH 035/172] BCM2708: Add HifiBerry DAC to board file This adds the initalization of the HifiBerry DAC to the mach-bcm2708 board file. @@ -108179,10 +108177,10 @@ index dca28ad..50d4991 100644 struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); -From ca637d75dfa6916b8c5d2d1dbd4114bfeacc086a Mon Sep 17 00:00:00 2001 +From c413288cdaabf5aa977f0afec318222b06adf10f Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Mon, 2 Dec 2013 20:28:22 +0100 -Subject: [PATCH 036/116] BCM2708: Add I2S and DMA support to default config +Subject: [PATCH 036/172] 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. @@ -108217,10 +108215,10 @@ index 63a6546..9a0e922 100644 CONFIG_UIO_PDRV_GENIRQ=m CONFIG_STAGING=y -From d4cda2a2b50cc69386e6f2292fc042baec93c418 Mon Sep 17 00:00:00 2001 +From 272884346f761c002999fa0aafdfa64e3c038b3c Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 6 Dec 2013 20:50:28 +0100 -Subject: [PATCH 037/116] ASoC: BCM2708: Add support for RPi-DAC +Subject: [PATCH 037/172] ASoC: BCM2708: Add support for RPi-DAC This adds a machine driver for the RPi-DAC. @@ -108418,7 +108416,7 @@ index 0000000..6d6e0ba +MODULE_DESCRIPTION("ASoC Driver for RPi-DAC"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index b289dd2..c32ecbe 100644 +index 1fc4390..0a7aaf7 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -82,6 +82,7 @@ config SND_SOC_ALL_CODECS @@ -108528,10 +108526,10 @@ index 0000000..b4eaa44 +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -From 72230403d9af4ca82a9075a9d9641a6fbad5ae8a Mon Sep 17 00:00:00 2001 +From 38defc6ccd2879e3b61ee7fbeb71da1982fda8fc Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 038/116] ASoC: wm8804: Implement MCLK configuration options, +Subject: [PATCH 038/172] 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 @@ -108571,10 +108569,10 @@ index 1315f76..3d86ba8 100644 #define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ -From 0bb2e4cadda70cee999665f14243faaf2c19150a Mon Sep 17 00:00:00 2001 +From 061cb19834ec2ebf649ae2028efbcaff9b4cf516 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 039/116] ASoC: BCM:Add support for HiFiBerry Digi. Driver is +Subject: [PATCH 039/172] ASoC: BCM:Add support for HiFiBerry Digi. Driver is based on the patched WM8804 driver. Signed-off-by: Daniel Matuschek @@ -108777,10 +108775,10 @@ index 0000000..e4f769d +MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); +MODULE_LICENSE("GPL v2"); -From 2d6d6cd0ba7c029da824b0ca5c17eb17edad10ce Mon Sep 17 00:00:00 2001 +From 0d3ca97a92ba10f025d4beb3bd8f58e097847840 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:26:08 +0100 -Subject: [PATCH 040/116] BCM2708: Added support for HiFiBerry Digi board Board +Subject: [PATCH 040/172] BCM2708: Added support for HiFiBerry Digi board Board initalization by I2C Signed-off-by: Daniel Matuschek @@ -108827,10 +108825,10 @@ index 100c223..a57cb85 100644 bcm_register_device(&snd_rpi_dac_device); bcm_register_device(&snd_pcm1794a_codec_device); -From 501ead58b3fb28519674af7f7ca770f40fbdea49 Mon Sep 17 00:00:00 2001 +From b8e27019fe2d79dc6f12b04d4a2f4de1f7a7dc75 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:27:28 +0100 -Subject: [PATCH 041/116] BCM2708: Added HiFiBerry Digi configuration option It +Subject: [PATCH 041/172] BCM2708: Added HiFiBerry Digi configuration option It will be compiled as a module by default. This also includes the WM8804 driver. @@ -108852,10 +108850,10 @@ index 3f7a237..cbd53b1 100644 CONFIG_SND_SIMPLE_CARD=m CONFIG_SOUND_PRIME=m -From 819ab2ffbc41d5d4c6cc27ee6bb334fb7dd777ae Mon Sep 17 00:00:00 2001 +From b8243e95d60019cefde3bac2db44f25c773946d5 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Thu, 16 Jan 2014 07:36:35 +0100 -Subject: [PATCH 042/116] ASoC: wm8804: Set idle_bias_off to false Idle bias +Subject: [PATCH 042/172] ASoC: wm8804: Set idle_bias_off to false Idle bias has been change to remove warning on driver startup Signed-off-by: Daniel Matuschek @@ -108877,10 +108875,10 @@ index 3d86ba8..34f7f76 100644 .controls = wm8804_snd_controls, .num_controls = ARRAY_SIZE(wm8804_snd_controls), -From c79ade9511f2b90a0cf84d152b7ea8e2afd6293e Mon Sep 17 00:00:00 2001 +From 88ba2e5743d41046c39726fd5a483b1bb02f76ce Mon Sep 17 00:00:00 2001 From: Gordon Garrity Date: Sat, 8 Mar 2014 16:56:57 +0000 -Subject: [PATCH 043/116] Add IQaudIO Sound Card support for Raspberry Pi +Subject: [PATCH 043/172] Add IQaudIO Sound Card support for Raspberry Pi --- arch/arm/configs/bcmrpi_defconfig | 1 + @@ -109090,38 +109088,43 @@ index 0000000..8d0e2ae +MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); +MODULE_LICENSE("GPL v2"); -From c359a5ee3bd738961427186256be97188a87bfef Mon Sep 17 00:00:00 2001 +From 397ad3a8dabc60f4ce6b1c261de7e2c31b7b1030 Mon Sep 17 00:00:00 2001 From: Howard Mitchell -Date: Fri, 28 Mar 2014 16:40:31 +0000 -Subject: [PATCH 044/116] pcm512x: Use a range macro for Volume and rename to - PCM. +Date: Mon, 2 Mar 2015 17:28:02 +0000 +Subject: [PATCH 044/172] Set a limit of 0dB on Digital Volume Control -This allows limiting the output gain to avoid clipping in the -DAC ouput stages. +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/codecs/pcm512x.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) + sound/soc/bcm/iqaudio-dac.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) -diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c -index 30c673c..2054a69 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); +diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c +index 8d0e2ae..aff7377 100644 +--- a/sound/soc/bcm/iqaudio-dac.c ++++ b/sound/soc/bcm/iqaudio-dac.c +@@ -25,7 +25,13 @@ - static const struct snd_kcontrol_new pcm512x_controls[] = { --SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, -- PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), -+SOC_DOUBLE_R_RANGE_TLV("PCM", PCM512x_DIGITAL_VOLUME_2, -+ PCM512x_DIGITAL_VOLUME_3, 0, 40, 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, + 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 d985ba5c1251ebf4e0d53e9e49808e56f0cc8742 Mon Sep 17 00:00:00 2001 +From 11c1054be4dcd9cb41f69225c2ec6ddf6f863d0a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Jun 2014 13:42:01 +0100 -Subject: [PATCH 045/116] vmstat: Workaround for issue where dirty page count +Subject: [PATCH 045/172] vmstat: Workaround for issue where dirty page count goes negative See: @@ -109148,10 +109151,10 @@ index 82e7db7..f87d16d 100644 static inline void __inc_zone_page_state(struct page *page, -From 562475ed074e8496d440350422bf2537820e4b2e Mon Sep 17 00:00:00 2001 +From 6bc933a1c5417c9ce3d1f14fabd36ec806467de5 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 20 Jun 2014 16:03:12 +0100 -Subject: [PATCH 046/116] dwc_otg: Fix various issues with root port and +Subject: [PATCH 046/172] dwc_otg: Fix various issues with root port and transaction errors Process the host port interrupts correctly (and don't trample them). @@ -109221,10 +109224,10 @@ index 4195ff2..a5566bc 100644 fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "RESET "); } -From e4364915e5e486400186b16743f27e8e683bb122 Mon Sep 17 00:00:00 2001 +From 2a2ae2efa4a1c663642cefb333a2042590818785 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 20 Jun 2014 17:23:20 +0100 -Subject: [PATCH 047/116] fiq_fsm: Implement hack for Split Interrupt +Subject: [PATCH 047/172] fiq_fsm: Implement hack for Split Interrupt transactions Hubs aren't too picky about which endpoint we send Control type split @@ -109310,10 +109313,10 @@ index 130096b..68d4f3b 100644 break; } -From c879a654179c1997fb31343ffe193cba4ce8445e Mon Sep 17 00:00:00 2001 +From f8598c5aa941bdd6ebd3e83c1e2634f1ac6057c9 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 6 Jul 2014 12:07:25 +0200 -Subject: [PATCH 048/116] spi-bcm2708: Prepare for Common Clock Framework +Subject: [PATCH 048/172] spi-bcm2708: Prepare for Common Clock Framework migration As part of migrating to use the Common Clock Framework, replace clk_enable() @@ -109358,10 +109361,10 @@ index b04a57d..349d21f 100644 free_irq(bs->irq, master); iounmap(bs->base); -From 7a09a3dce774a0a5be04e106d6cab4c45a4b8225 Mon Sep 17 00:00:00 2001 +From 0e203cd8312e0f2ecbaaa91b84302ebd08b7c7ab Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 6 Jul 2014 12:09:30 +0200 -Subject: [PATCH 049/116] BCM2708: Migrate to the Common Clock Framework +Subject: [PATCH 049/172] 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. @@ -109631,10 +109634,10 @@ index 5f9d725..0000000 - unsigned long rate; -}; -From c2eb05044f3740a2183b5b39203e970e760a07c6 Mon Sep 17 00:00:00 2001 +From ec2d83be8df77ac09c47dac5f3ac7218d92e1619 Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:46:08 +0200 -Subject: [PATCH 050/116] BCM2708: Add core Device Tree support +Subject: [PATCH 050/172] BCM2708: Add core Device Tree support Add the bare minimum needed to boot BCM2708 from a Device Tree. @@ -109799,10 +109802,10 @@ index ef12cb8..747e27a 100644 module_param(boardrev, uint, 0644); -From fa27429ce9578e756197cf04b9835603f57dfb8f Mon Sep 17 00:00:00 2001 +From be8c3d8a94f6744f2e6b3f3d41c3604d4c6cb217 Mon Sep 17 00:00:00 2001 From: notro Date: Wed, 9 Jul 2014 14:47:48 +0200 -Subject: [PATCH 051/116] BCM2708: armctrl: Add IRQ Device Tree support +Subject: [PATCH 051/172] BCM2708: armctrl: Add IRQ Device Tree support Add Device Tree IRQ support for BCM2708. Usage is the same as for irq-bcm2835. @@ -109972,10 +109975,10 @@ index 96fa9b9..74bacb3 100644 return 0; } -From 276be851fc57b1badfef77e9bd067fd51875e462 Mon Sep 17 00:00:00 2001 +From 235c1c651b6b85fc9f83940c08bc2055902767c9 Mon Sep 17 00:00:00 2001 From: notro Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 052/116] BCM2708: use pinctrl-bcm2835 +Subject: [PATCH 052/172] BCM2708: use pinctrl-bcm2835 Use pinctrl-bcm2835 instead of the pinctrl-bcm2708 and bcm2708_gpio combination. @@ -110052,10 +110055,10 @@ index 9aa8a3f..9d1149e 100644 .can_sleep = false, }; -From 921c71ddf380c8fc028d90b8807ef4ace70086e6 Mon Sep 17 00:00:00 2001 +From 2fddb74c345dcb1cd2b03b60f64725bb5fbb26f0 Mon Sep 17 00:00:00 2001 From: notro Date: Sun, 27 Jul 2014 20:12:58 +0200 -Subject: [PATCH 053/116] spi: bcm2708: add device tree support +Subject: [PATCH 053/172] spi: bcm2708: add device tree support Add DT support to driver and add to .dtsi file. Setup pins and spidev in .dts file. @@ -110262,10 +110265,10 @@ index 349d21f..041b5e2 100644 .probe = bcm2708_spi_probe, .remove = bcm2708_spi_remove, -From e3bc961a920dfffd560efdc592d3c3a28b92630d Mon Sep 17 00:00:00 2001 +From a9dfef3e2161f0ec30100b32639de3d6d0682836 Mon Sep 17 00:00:00 2001 From: notro Date: Tue, 29 Jul 2014 11:04:49 +0200 -Subject: [PATCH 054/116] i2c: bcm2708: add device tree support +Subject: [PATCH 054/172] i2c: bcm2708: add device tree support Add DT support to driver and add to .dtsi file. Setup pins in .dts file. @@ -110489,10 +110492,10 @@ index 7d385a3..526129b 100644 .probe = bcm2708_i2c_probe, .remove = bcm2708_i2c_remove, -From dd70f130500963aafafcee3d5dc1564c51363674 Mon Sep 17 00:00:00 2001 +From 822709b4718fcc2922306017b9307f1523eb49ed Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 14 Jul 2014 22:02:09 +0100 -Subject: [PATCH 055/116] hid: Reduce default mouse polling interval to 60Hz +Subject: [PATCH 055/172] hid: Reduce default mouse polling interval to 60Hz Reduces overhead when using X --- @@ -110528,10 +110531,10 @@ index bfbe1be..a738b25 100644 ret = -ENOMEM; if (usb_endpoint_dir_in(endpoint)) { -From a87afb0647b5f16ab95189f1048c3e9098c59d04 Mon Sep 17 00:00:00 2001 +From 4da45e92b0bf783d7ab22c971310d2a5f0f5fda9 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 24 Jul 2014 21:24:03 +0100 -Subject: [PATCH 056/116] usb: core: make overcurrent messages more prominent +Subject: [PATCH 056/172] usb: core: make overcurrent messages more prominent Hub overcurrent messages are more serious than "debug". Increase loglevel. --- @@ -110539,7 +110542,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 aeb50bb..21844a7 100644 +index b4bfa3a..252a3f0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4921,7 +4921,7 @@ static void port_event(struct usb_hub *hub, int port1) @@ -110552,10 +110555,10 @@ index aeb50bb..21844a7 100644 USB_PORT_FEAT_C_OVER_CURRENT); msleep(100); /* Cool down */ -From b3c65bc61773703cd8993ffb457f23a85c7487d0 Mon Sep 17 00:00:00 2001 +From 1da5f92cf41f89b2415bfb8d6726604b2fbb9aca Mon Sep 17 00:00:00 2001 From: Tim Gover Date: Tue, 22 Jul 2014 15:41:04 +0100 -Subject: [PATCH 057/116] vcsm: VideoCore shared memory service for BCM2835 +Subject: [PATCH 057/172] 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 @@ -114889,10 +114892,10 @@ index 0000000..da1c523 +MODULE_DESCRIPTION("VideoCore SharedMemory Driver"); +MODULE_LICENSE("GPL v2"); -From 8d8dc6295c000c8c7b0e56cbb74b48eb4649ee3d Mon Sep 17 00:00:00 2001 +From c98028400be74c9edc4d170293f49dc2e27d5d80 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 7 Aug 2014 02:03:50 +0100 -Subject: [PATCH 058/116] Revert "ARM: dma: Use dma_pfn_offset for dma address +Subject: [PATCH 058/172] Revert "ARM: dma: Use dma_pfn_offset for dma address translation" This reverts commit 6ce0d20016925d031f1e24d64302e4c976d7cec6. @@ -114944,10 +114947,10 @@ index b52101d..f5572d9 100644 } -From 4c9c17fcc1f351cc06268e4902d0dee92fe1a68a Mon Sep 17 00:00:00 2001 +From 431ffd837c0694e865b7aa72e284eb15fc122d7c Mon Sep 17 00:00:00 2001 From: gellert Date: Fri, 15 Aug 2014 16:35:06 +0100 -Subject: [PATCH 059/116] MMC: added alternative MMC driver +Subject: [PATCH 059/172] MMC: added alternative MMC driver --- arch/arm/configs/bcmrpi_defconfig | 2 + @@ -116650,10 +116653,10 @@ index 0000000..92febc3 +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Gellert Weisz"); -From 8e777a27499279a8351836a80d4df838264dc0e3 Mon Sep 17 00:00:00 2001 +From 0ccc5b840254ab00236b28ccb0156f59ddc72807 Mon Sep 17 00:00:00 2001 From: P33M Date: Tue, 13 Jan 2015 17:12:18 +0000 -Subject: [PATCH 060/116] mmc: Disable CMD23 transfers on all cards +Subject: [PATCH 060/172] 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 @@ -116679,10 +116682,10 @@ index dd1d1e0..f472082 100644 } EXPORT_SYMBOL(mmc_fixup_device); -From a869a7389e5a734bbbc42c70c3950b2f49cc3591 Mon Sep 17 00:00:00 2001 +From 83621e3bccbabed1a256973918dc5bcf9039a56b Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 10:06:56 +0200 -Subject: [PATCH 061/116] Added support for HiFiBerry DAC+ +Subject: [PATCH 061/172] 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. @@ -116906,10 +116909,10 @@ index 0000000..c63387b +MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+"); +MODULE_LICENSE("GPL v2"); -From 45fa955cf4e5d54a01c807c1a18cb0828bd45b9a Mon Sep 17 00:00:00 2001 +From ecc316d9abb1a30fae40c0581aba6439aa732474 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Mon, 4 Aug 2014 11:09:58 +0200 -Subject: [PATCH 062/116] Added driver for HiFiBerry Amp amplifier add-on board +Subject: [PATCH 062/172] 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. @@ -117127,7 +117130,7 @@ index 0000000..1e87ee0 +MODULE_DESCRIPTION("ASoC driver for HiFiBerry-AMP"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index c32ecbe..664dc4d 100644 +index 0a7aaf7..45dd4fd 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -107,6 +107,7 @@ config SND_SOC_ALL_CODECS @@ -117753,10 +117756,10 @@ index 0000000..8f019e0 + +#endif /* _TAS5713_H */ -From 861c08aec9f2f1c1a22b3d7d8ae19fec798f7832 Mon Sep 17 00:00:00 2001 +From 0d81e702b6c48cf3f39d4a13588d273868554490 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 13 Oct 2014 11:47:53 +0100 -Subject: [PATCH 063/116] Improve __copy_to_user and __copy_from_user +Subject: [PATCH 063/172] Improve __copy_to_user and __copy_from_user performance Provide a __copy_from_user that uses memcpy. On BCM2708, use @@ -119280,10 +119283,10 @@ index 3e58d71..0622891 100644 static unsigned long noinline __clear_user_memset(void __user *addr, unsigned long n) -From 118e894115980f246a4e092d51c15fa8fa17b242 Mon Sep 17 00:00:00 2001 +From 35fe870af907a92f71132723506d92329c3de6fe Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 1 Sep 2014 16:35:56 +0100 -Subject: [PATCH 064/116] bcm2708: Allow option card devices to be configured +Subject: [PATCH 064/172] bcm2708: Allow option card devices to be configured via DT If the kernel is built with Device Tree support, and if a DT blob @@ -119720,10 +119723,10 @@ index 03fa1cb..c816526 100644 static struct platform_driver bcm2835_i2s_driver = { .probe = bcm2835_i2s_probe, -From 2da679d67d7dd011f01649577c7bae50186f0363 Mon Sep 17 00:00:00 2001 +From 905b491a759bb3264e073771cbd200e747ef7a02 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 12 Nov 2014 17:07:02 +0000 -Subject: [PATCH 065/116] Adding Device Tree support for some RPi audio cards +Subject: [PATCH 065/172] Adding Device Tree support for some RPi audio cards --- arch/arm/boot/dts/Makefile | 4 ++ @@ -120292,10 +120295,10 @@ index e4f769d..76af8a6 100644 .probe = snd_rpi_hifiberry_digi_probe, .remove = snd_rpi_hifiberry_digi_remove, diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c -index 8d0e2ae..ee8cd6e 100644 +index aff7377..a38e874 100644 --- a/sound/soc/bcm/iqaudio-dac.c +++ b/sound/soc/bcm/iqaudio-dac.c -@@ -76,6 +76,21 @@ static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev) +@@ -82,6 +82,21 @@ static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev) int ret = 0; snd_rpi_iqaudio_dac.dev = &pdev->dev; @@ -120317,7 +120320,7 @@ index 8d0e2ae..ee8cd6e 100644 ret = snd_soc_register_card(&snd_rpi_iqaudio_dac); if (ret) dev_err(&pdev->dev, -@@ -93,6 +108,7 @@ static const struct of_device_id iqaudio_of_match[] = { +@@ -99,6 +114,7 @@ static const struct of_device_id iqaudio_of_match[] = { { .compatible = "iqaudio,iqaudio-dac", }, {}, }; @@ -120350,10 +120353,10 @@ index 126f1e9..7c6598e 100644 }; -From 5248d61fbed6a412104089d671ac2c864a76aa79 Mon Sep 17 00:00:00 2001 +From 50224e08199906d8bad2b40db5a2445f18f1851b Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 5 Dec 2014 17:26:26 +0000 -Subject: [PATCH 066/116] fdt: Add support for the CONFIG_CMDLINE_EXTEND option +Subject: [PATCH 066/172] fdt: Add support for the CONFIG_CMDLINE_EXTEND option --- drivers/of/fdt.c | 29 ++++++++++++++++++++++++----- @@ -120408,10 +120411,10 @@ index 5100742..d6d944c 100644 pr_debug("Command line is: %s\n", (char*)data); -From e81caed711b76987fa7764e67896ac244c5b9974 Mon Sep 17 00:00:00 2001 +From e321ee5ea13db9279cc73e4ed85feb572738f520 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 25 Nov 2014 13:39:03 +0000 -Subject: [PATCH 067/116] config: Enable device tree +Subject: [PATCH 067/172] config: Enable device tree --- arch/arm/configs/bcmrpi_defconfig | 1 + @@ -120430,10 +120433,10 @@ index 8381041..c1621fa 100644 CONFIG_AEABI=y CONFIG_CLEANCACHE=y -From 3b2f8e42a35ab1ca8c7702bc1a8c6b63aa3def82 Mon Sep 17 00:00:00 2001 +From 30d815a127ab3fc90b634fc9e78b0a54e8cecd13 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 16 Dec 2014 10:23:48 +0000 -Subject: [PATCH 068/116] DT: Add overrides to enable i2c0, i2c1, spi and i2s +Subject: [PATCH 068/172] DT: Add overrides to enable i2c0, i2c1, spi and i2s --- arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 10 ++++++++++ @@ -120477,10 +120480,10 @@ index d8c6d15..167b22b 100644 + }; +}; -From 1e78b4625b77406af9cd50eef75ce67caf39a013 Mon Sep 17 00:00:00 2001 +From 4221b401eb7ca80823af64dfabf78e5663b96077 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 18 Dec 2014 16:48:32 +0000 -Subject: [PATCH 069/116] lirc-rpi: Add device tree support, and a suitable +Subject: [PATCH 069/172] lirc-rpi: Add device tree support, and a suitable overlay The overlay supports DT parameters that match the old module @@ -120774,10 +120777,10 @@ index c688364..cd66ca2 100644 if (result < 0) goto exit_rpi; -From 31368425270f59c0cb73143bf8bbdbb4ba8f380c Mon Sep 17 00:00:00 2001 +From 5dc9913bd2a47c049baf736b93efc014725c0527 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 6 Jan 2015 12:06:55 +0000 -Subject: [PATCH 070/116] Fix the activity LED in DT mode +Subject: [PATCH 070/172] 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: @@ -120909,10 +120912,10 @@ index 6b36128..1b56cb5 100644 clocks { -From 16c5ca7134e6e1fe86d9127dc4d43005ffd50b27 Mon Sep 17 00:00:00 2001 +From 86473a27065173f994c13a3431b1ebf3310e52e9 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 15 Jan 2015 10:39:06 +0000 -Subject: [PATCH 071/116] Adding w1-gpio device tree overlays +Subject: [PATCH 071/172] Adding w1-gpio device tree overlays N.B. Requires firmware supporting multi-target overrides @@ -121022,10 +121025,10 @@ index 0000000..b3e97c2 + }; +}; -From 62b86f21e94a0f4a01d825ec59cfab4cdb00642c Mon Sep 17 00:00:00 2001 +From 323b2e846c0d31be3fabcbed62734c0bb5023f80 Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Fri, 23 Jan 2015 16:41:17 +0100 -Subject: [PATCH 072/116] TAS5713: return error if initialisation fails +Subject: [PATCH 072/172] 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 @@ -121092,10 +121095,10 @@ index a24c1da..9b27138 100644 return 0; } -From 10df9d22f5af3349cf9cc3a7d2a793237b65d41a Mon Sep 17 00:00:00 2001 +From 62301cba70c8943a53af4664c805573bdd86face Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 14:48:55 +0000 -Subject: [PATCH 073/116] scripts/dtc: Update to upstream version with overlay +Subject: [PATCH 073/172] scripts/dtc: Update to upstream version with overlay patches --- @@ -126308,10 +126311,10 @@ index 54d4e904..d644002 100644 -#define DTC_VERSION "DTC 1.4.0-dirty" +#define DTC_VERSION "DTC 1.4.1-g36c70742" -From 539a294591de138f45c9c2afd2a8e4477bc26e30 Mon Sep 17 00:00:00 2001 +From 919255c79510712b052391025207715033647954 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 23 Jan 2015 15:18:03 +0000 -Subject: [PATCH 074/116] BCM2708_DT: Build the overlays as well +Subject: [PATCH 074/172] BCM2708_DT: Build the overlays as well --- arch/arm/boot/dts/Makefile | 13 +++++++++++++ @@ -126346,10 +126349,10 @@ index 76e5f96..54ee8c5 100644 + DTC_FLAGS ?= -@ +endif -From 4c4650200f97c0b51722931283ad0c9cb824a71f Mon Sep 17 00:00:00 2001 +From 404893c9ba110f8ea40335f8a62fb49465cf85df Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Sun, 25 Jan 2015 19:41:06 +0100 -Subject: [PATCH 075/116] Add device tree overlay for HiFiBerry Amp/Amp+ +Subject: [PATCH 075/172] Add device tree overlay for HiFiBerry Amp/Amp+ This patch add the missing device tree file for the HiFiBerry Amp and Amp+ boards. --- @@ -126416,10 +126419,10 @@ index 0000000..2c81448 + }; +}; -From d701420a7d7e98c562cd64ad17c9721fdb42b692 Mon Sep 17 00:00:00 2001 +From c38d9b463556778c95bdaafbae9d2a0617850797 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 26 Jan 2015 09:18:24 +0000 -Subject: [PATCH 076/116] Add pps-gpio DT overlay +Subject: [PATCH 076/172] Add pps-gpio DT overlay Parameters: gpiopin= // Default 18 @@ -126482,10 +126485,10 @@ index 0000000..40bf0e1 + }; +}; -From 2365c3f2d426fa6a31e77fc0d8f094118cb8094d Mon Sep 17 00:00:00 2001 +From a272e3850258f898431b680c23c771d6cd8a99a5 Mon Sep 17 00:00:00 2001 From: Serge Schneider Date: Wed, 3 Sep 2014 14:44:22 +0100 -Subject: [PATCH 077/116] I2C: Only register the I2C device for the current +Subject: [PATCH 077/172] I2C: Only register the I2C device for the current board revision --- @@ -126529,10 +126532,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 312bed5a32e235a6ee01550424b185a7c643ed16 Mon Sep 17 00:00:00 2001 +From be479e15759f47ee002fa335e7ad5120fb493a54 Mon Sep 17 00:00:00 2001 From: Timo Kokkonen Date: Wed, 29 Oct 2014 23:30:30 -0700 -Subject: [PATCH 078/116] Added support to reserve/enable a GPIO pin to be used +Subject: [PATCH 078/172] Added support to reserve/enable a GPIO pin to be used from pps-gpio module (LinuxPPS). Enable PPS modules in default config for RPi. @@ -126606,10 +126609,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 4a04725639c14e9895879571be4d4b79f190e603 Mon Sep 17 00:00:00 2001 +From f12f6d91c196ce12836bafcab75b0031903dc74c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 26 Jan 2015 15:26:10 +0000 -Subject: [PATCH 079/116] BCM2708_DT: Correct length of the peripheral space +Subject: [PATCH 079/172] BCM2708_DT: Correct length of the peripheral space --- arch/arm/boot/dts/bcm2708.dtsi | 2 +- @@ -126629,10 +126632,10 @@ index 1b56cb5..d879316 100644 intc: interrupt-controller { compatible = "brcm,bcm2708-armctrl-ic"; -From 64c6a61c55b29bc8768587849a1c9a31a90ca8c7 Mon Sep 17 00:00:00 2001 +From c9ee485e8bd038ba21ad37da134fe4170d32ab5c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 28 Jan 2015 16:22:04 +0000 -Subject: [PATCH 080/116] BCM2708_DT: Add pcf8523-rtc overlay +Subject: [PATCH 080/172] BCM2708_DT: Add pcf8523-rtc overlay --- arch/arm/boot/dts/Makefile | 1 + @@ -126681,10 +126684,10 @@ index 0000000..0071f62 + }; +}; -From 52f848ae973d5467bfc211499f12da71544f4b59 Mon Sep 17 00:00:00 2001 +From 10beb512f97f3d5c1bf4279ee2890316081e9edb Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Sat, 31 Jan 2015 16:07:56 +0100 -Subject: [PATCH 081/116] Add a parameter to turn off SPDIF output if no audio +Subject: [PATCH 081/172] 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. @@ -126756,10 +126759,10 @@ index 76af8a6..b0e3d28 100644 static struct snd_soc_dai_link snd_rpi_hifiberry_digi_dai[] = { -From be8aa60e5fc8f86ea278be93bd3b6c198940a4c3 Mon Sep 17 00:00:00 2001 +From 1993de13349743b8edfa8cfc3be4dc4219bd1a33 Mon Sep 17 00:00:00 2001 From: Joerg Hohensohn Date: Sun, 1 Feb 2015 22:08:03 +0100 -Subject: [PATCH 082/116] bugfix for 32kHz sample rate, was missing +Subject: [PATCH 082/172] bugfix for 32kHz sample rate, was missing --- sound/soc/bcm/hifiberry_digi.c | 1 + @@ -126778,10 +126781,10 @@ index b0e3d28..133d51b 100644 case 48000: case 88200: -From 69ba0d7bf053f31f78d26cb4ce71e0847762c35c Mon Sep 17 00:00:00 2001 +From 6085a9df53b0d0cc9898f09717f334a7c3eca4bc Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:25:49 -0700 -Subject: [PATCH 083/116] Update ds1307 driver for device-tree support +Subject: [PATCH 083/172] Update ds1307 driver for device-tree support Signed-off-by: Ryan Coe --- @@ -126808,10 +126811,10 @@ index 4ffabb3..c6789a7 100644 .driver = { .name = "rtc-ds1307", -From 41f71cd0934203eaa69c65afdab09c872700d76b Mon Sep 17 00:00:00 2001 +From a4d37a3da2f277ca9e0dc3ad5b1e1aebe16f34b5 Mon Sep 17 00:00:00 2001 From: Ryan Coe Date: Sat, 31 Jan 2015 18:26:03 -0700 -Subject: [PATCH 084/116] Add device-tree overlay for ds1307 +Subject: [PATCH 084/172] Add device-tree overlay for ds1307 Signed-off-by: Ryan Coe --- @@ -126861,15 +126864,16 @@ index 0000000..7d27044 + }; +}; -From a32250b6048c747684e9b6666062070603903ce0 Mon Sep 17 00:00:00 2001 +From 2a055c5bad25645d230161b596df0a9702bbcc2b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 7 May 2013 14:32:27 +0100 -Subject: [PATCH 085/116] Add 2709 platform for Raspberry Pi 2 +Subject: [PATCH 085/172] Add 2709 platform for Raspberry Pi 2 --- arch/arm/Kconfig | 21 + arch/arm/Makefile | 1 + arch/arm/boot/dts/Makefile | 10 +- + arch/arm/boot/dts/bcm2708.dtsi | 2 +- arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 101 ++ arch/arm/boot/dts/bcm2709.dtsi | 160 +++ arch/arm/configs/bcm2709_defconfig | 1156 ++++++++++++++++++++ @@ -126885,7 +126889,7 @@ Subject: [PATCH 085/116] Add 2709 platform for Raspberry Pi 2 arch/arm/mach-bcm2709/armctrl.c | 357 +++++++ arch/arm/mach-bcm2709/armctrl.h | 27 + arch/arm/mach-bcm2709/bcm2708_gpio.c | 426 ++++++++ - arch/arm/mach-bcm2709/bcm2709.c | 1237 ++++++++++++++++++++++ + arch/arm/mach-bcm2709/bcm2709.c | 1234 ++++++++++++++++++++++ arch/arm/mach-bcm2709/bcm2709.h | 49 + arch/arm/mach-bcm2709/clock.c | 61 ++ arch/arm/mach-bcm2709/clock.h | 24 + @@ -126932,7 +126936,7 @@ Subject: [PATCH 085/116] Add 2709 platform for Raspberry Pi 2 drivers/watchdog/Kconfig | 2 +- sound/arm/Kconfig | 2 +- sound/soc/bcm/Kconfig | 2 +- - 65 files changed, 9006 insertions(+), 16 deletions(-) + 66 files changed, 9004 insertions(+), 17 deletions(-) create mode 100644 arch/arm/boot/dts/bcm2709-rpi-2-b.dts create mode 100644 arch/arm/boot/dts/bcm2709.dtsi create mode 100644 arch/arm/configs/bcm2709_defconfig @@ -127059,6 +127063,19 @@ index 2685794..83dceff 100644 +ifeq ($(RPI_DT_OVERLAYS),y) DTC_FLAGS ?= -@ endif +diff --git a/arch/arm/boot/dts/bcm2708.dtsi b/arch/arm/boot/dts/bcm2708.dtsi +index d879316..af6b1d9 100644 +--- a/arch/arm/boot/dts/bcm2708.dtsi ++++ b/arch/arm/boot/dts/bcm2708.dtsi +@@ -81,7 +81,7 @@ + compatible = "gpio-leds"; + + act_led: act { +- label = "ACT"; ++ label = "led0"; + linux,default-trigger = "mmc0"; + }; + }; diff --git a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts new file mode 100644 index 0000000..0cdff31 @@ -130095,10 +130112,10 @@ index 0000000..c1e9254 +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c new file mode 100644 -index 0000000..abe2b19 +index 0000000..3055e72d --- /dev/null +++ b/arch/arm/mach-bcm2709/bcm2709.c -@@ -0,0 +1,1237 @@ +@@ -0,0 +1,1234 @@ +/* + * linux/arch/arm/mach-bcm2709/bcm2709.c + * @@ -130922,10 +130939,13 @@ index 0000000..abe2b19 +{ + int ret; + ++ of_clk_init(NULL); + ret = of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + if (ret) { + pr_err("of_platform_populate failed: %d\n", ret); -+ use_dt = 0; ++ /* Proceed as if CONFIG_OF was not defined */ ++ } else { ++ use_dt = 1; + } +} +#else @@ -130943,8 +130963,7 @@ index 0000000..abe2b19 + pm_power_off = bcm2709_power_off; + + bcm2709_init_clocks(); -+ if (use_dt) -+ bcm2709_dt_init(); ++ bcm2709_dt_init(); + + bcm_register_device(&bcm2708_dmaman_device); + bcm_register_device(&bcm2708_vcio_device); @@ -131191,11 +131210,6 @@ index 0000000..abe2b19 + * the allocations won't fail. + */ + init_dma_coherent_pool_size(SZ_4M); -+ -+#ifdef CONFIG_OF -+ if (of_root) -+ use_dt = 1; -+#endif +} + +static void __init board_reserve(void) @@ -133804,7 +133818,7 @@ index 0000000..e6eb84d +#endif diff --git a/arch/arm/mach-bcm2709/include/mach/irqs.h b/arch/arm/mach-bcm2709/include/mach/irqs.h new file mode 100644 -index 0000000..3a883d2 +index 0000000..d301f06c --- /dev/null +++ b/arch/arm/mach-bcm2709/include/mach/irqs.h @@ -0,0 +1,225 @@ @@ -134027,9 +134041,9 @@ index 0000000..3a883d2 +#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_ */ @@ -136508,33 +136522,10 @@ index a562ddf..40d27c1 100644 select SND_SOC_DMAENGINE_PCM select SND_SOC_GENERIC_DMAENGINE_PCM -From 7aa31f395f25f5f05a01b1a89cde6b4db0d09008 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 11 Feb 2015 21:17:28 +0000 -Subject: [PATCH 086/116] m - ---- - arch/arm/boot/dts/bcm2708.dtsi | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm/boot/dts/bcm2708.dtsi b/arch/arm/boot/dts/bcm2708.dtsi -index d879316..af6b1d9 100644 ---- a/arch/arm/boot/dts/bcm2708.dtsi -+++ b/arch/arm/boot/dts/bcm2708.dtsi -@@ -81,7 +81,7 @@ - compatible = "gpio-leds"; - - act_led: act { -- label = "ACT"; -+ label = "led0"; - linux,default-trigger = "mmc0"; - }; - }; - -From 1ea263df8ad7e1f95b90c743928f4f16c4adad25 Mon Sep 17 00:00:00 2001 +From 3e5e6153b4da56ee47cb1becb41f40ad61d569b2 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 6 Feb 2015 13:50:57 +0000 -Subject: [PATCH 087/116] BCM270x_DT: Add pwr_led, and the required "input" +Subject: [PATCH 086/172] BCM270x_DT: Add pwr_led, and the required "input" trigger The "input" trigger makes the associated GPIO an input. This is to support @@ -136797,10 +136788,10 @@ index 0000000..2ca2b98 +MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\""); +MODULE_LICENSE("GPL"); -From 6c049544cfa8435965027d48d006cbddb8ae9f9d Mon Sep 17 00:00:00 2001 +From d3db7dad4705421430c8dc3ba6853038a3988f99 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 20 Jun 2014 17:19:27 +0100 -Subject: [PATCH 088/116] bcm2709: Simplify and strip down IRQ handler +Subject: [PATCH 087/172] bcm2709: Simplify and strip down IRQ handler --- arch/arm/include/asm/entry-macro-multi.S | 2 + @@ -137017,10 +137008,10 @@ index d08591b..101d9f1 100644 +1: get_irqnr_and_base r0, r2, r6, lr + .endm -From 47f63d0ccfea3b7db13b87e2ccbebe33b7ddcf75 Mon Sep 17 00:00:00 2001 +From b54978ca2faf286b4a3836a232139140f514362f Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 24 Sep 2014 11:57:51 +0100 -Subject: [PATCH 089/116] dwc_otg: FIQ support on SMP. Set up FIQ stack and +Subject: [PATCH 088/172] dwc_otg: FIQ support on SMP. Set up FIQ stack and handler on Core 0 only. --- @@ -137150,10 +137141,10 @@ index 98e1dc5..4d8dd95 100644 otg_dev->hcd->otg_dev = otg_dev; -From 12805880485af569b79de901a9c3554ed921ee77 Mon Sep 17 00:00:00 2001 +From e012a834d4a47ffe38f00d1a48da854680d51be6 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 26 Sep 2014 11:32:09 +0100 -Subject: [PATCH 090/116] dwc_otg: introduce fiq_fsm_spin(un|)lock() +Subject: [PATCH 089/172] 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 @@ -137470,10 +137461,10 @@ index a5566bc..ee35196 100644 } -From f98835f1f026ab44f70fc03b301ab1c2e6e695e0 Mon Sep 17 00:00:00 2001 +From 2180b4febd684a72e2ef217fdb87a26dcc4073dc Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 22 Jan 2015 11:59:41 +0000 -Subject: [PATCH 091/116] fiq_fsm: fix build on bcm2708 and bcm2709 platforms +Subject: [PATCH 090/172] fiq_fsm: fix build on bcm2708 and bcm2709 platforms --- drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 8 ++++++++ @@ -137516,10 +137507,10 @@ index 84618a5..0d2b04e 100644 /** * fiq_fsm_restart_channel() - Poke channel enable bit for a split transaction -From 51c50dde85c608d033d80e415fc43a90301745f9 Mon Sep 17 00:00:00 2001 +From e4d3c223f680bb7a75fc99d53603923afb28b1dd Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 22 Jan 2015 17:49:23 +0000 -Subject: [PATCH 092/116] dwc_otg: put some barriers back where they should be +Subject: [PATCH 091/172] dwc_otg: put some barriers back where they should be for UP --- @@ -137559,17 +137550,17 @@ index 124ac16..ac70f1d 100644 local_fiq_enable(); return 0; -From 7ee3bc393f55effdcf46eeca95f4e03552d68ea6 Mon Sep 17 00:00:00 2001 +From e9c0e5a0de4a65238b03ba6729a3d3611e0e0d8a Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 22 Jan 2015 18:02:44 +0000 -Subject: [PATCH 093/116] mach_bcm2709: Add Mailbox resources to USB driver +Subject: [PATCH 092/172] mach_bcm2709: Add Mailbox resources to USB driver --- arch/arm/mach-bcm2709/bcm2709.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index abe2b19..945bb94 100644 +index 3055e72d..3cb3756 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -338,6 +338,16 @@ static struct resource bcm2708_usb_resources[] = { @@ -137590,10 +137581,10 @@ index abe2b19..945bb94 100644 -From 20c510ab62a8926d6737f7f8e2473abb9f0f8fe3 Mon Sep 17 00:00:00 2001 +From ec73fdffb06f1c2751229834465ffd3152bdfd3f Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 22 Jan 2015 18:45:23 +0000 -Subject: [PATCH 094/116] bcm2709/dwc_otg: Setup FIQ on core 1 if >1 core +Subject: [PATCH 093/172] bcm2709/dwc_otg: Setup FIQ on core 1 if >1 core active --- @@ -137656,17 +137647,17 @@ index 4d8dd95..1d28459 100644 otg_dev->hcd->otg_dev = otg_dev; hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd); -From b67ceafbe780931f9c14a2aac406b9a7b8089add Mon Sep 17 00:00:00 2001 +From f1c713f051a95787416095a6dbfe5846a15c9f8e Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 26 Jan 2015 17:40:22 +0000 -Subject: [PATCH 095/116] bcm2709: Port pps-gpio and i2c patches +Subject: [PATCH 094/172] bcm2709: Port pps-gpio and i2c patches --- arch/arm/mach-bcm2709/bcm2709.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index 945bb94..c4a37e8 100644 +index 3cb3756..8936427 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c @@ -37,6 +37,7 @@ @@ -137706,7 +137697,7 @@ index 945bb94..c4a37e8 100644 static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON); static struct platform_device bcm2708_fb_device = { -@@ -860,6 +876,16 @@ void __init bcm2709_init(void) +@@ -862,6 +878,16 @@ void __init bcm2709_init(void) #ifdef CONFIG_BCM2708_GPIO bcm_register_device_dt(&bcm2708_gpio_device); #endif @@ -137723,7 +137714,7 @@ index 945bb94..c4a37e8 100644 #if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE) w1_gpio_pdata.pin = w1_gpio_pin; w1_gpio_pdata.ext_pullup_enable_pin = w1_gpio_pullup; -@@ -884,8 +910,15 @@ void __init bcm2709_init(void) +@@ -886,8 +912,15 @@ void __init bcm2709_init(void) bcm_register_device(&bcm2835_thermal_device); bcm_register_device_dt(&bcm2708_spi_device); @@ -137741,7 +137732,7 @@ index 945bb94..c4a37e8 100644 #if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE) bcm_register_device_dt(&bcm2708_i2s_device); -@@ -1245,3 +1278,7 @@ module_param(disk_led_active_low, uint, 0644); +@@ -1242,3 +1275,7 @@ module_param(disk_led_active_low, uint, 0644); module_param(reboot_part, uint, 0644); module_param(w1_gpio_pin, uint, 0644); module_param(w1_gpio_pullup, uint, 0644); @@ -137750,20 +137741,20 @@ index 945bb94..c4a37e8 100644 +module_param(vc_i2c_override, bool, 0644); +MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral."); -From 69f6f452dba6d3cf1f3b34d1a51b514585f14ddc Mon Sep 17 00:00:00 2001 +From 30a40bd6d577e4b4b4b13c3bb249a99aa8216def Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 28 Jan 2015 17:57:23 +0000 -Subject: [PATCH 096/116] bcm2709: Also accept the 2708 machine ID +Subject: [PATCH 095/172] bcm2709: Also accept the 2708 machine ID --- arch/arm/mach-bcm2709/bcm2709.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/mach-bcm2709/bcm2709.c b/arch/arm/mach-bcm2709/bcm2709.c -index c4a37e8..8af141c 100644 +index 8936427..55c21a5 100644 --- a/arch/arm/mach-bcm2709/bcm2709.c +++ b/arch/arm/mach-bcm2709/bcm2709.c -@@ -1270,6 +1270,19 @@ MACHINE_START(BCM2709, "BCM2709") +@@ -1267,6 +1267,19 @@ MACHINE_START(BCM2709, "BCM2709") .dt_compat = bcm2709_compat, MACHINE_END @@ -137784,10 +137775,10 @@ index c4a37e8..8af141c 100644 module_param(serial, uint, 0644); module_param(uart_clock, uint, 0644); -From 05a197df4f859169c86c2a72f6ae05d4c22adcb9 Mon Sep 17 00:00:00 2001 +From 24097ac1917183b1b10b2315a1a3db527fcf8dfb Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 2 Feb 2015 12:45:07 +0000 -Subject: [PATCH 097/116] BCM2709_DT: Fix bad merge +Subject: [PATCH 096/172] BCM2709_DT: Fix bad merge --- arch/arm/boot/dts/Makefile | 25 +++++++++++++------------ @@ -137830,10 +137821,10 @@ index 83dceff..f3b6364 100644 dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b-plus.dtb dtb-$(CONFIG_ARCH_BCM_5301X) += \ -From 8e225da0cd3ec867d130c64274e1c721ca03a0b2 Mon Sep 17 00:00:00 2001 +From f3e38d36525f6f1f59dacddd9595ad860ae2eacd Mon Sep 17 00:00:00 2001 From: Daniel Matuschek Date: Tue, 3 Feb 2015 07:15:19 +0100 -Subject: [PATCH 098/116] HiFiBerry Amp: fix device-tree problems +Subject: [PATCH 097/172] 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. --- @@ -137887,10 +137878,10 @@ index 1e87ee0..5903915 100644 .probe = snd_rpi_hifiberry_amp_probe, .remove = snd_rpi_hifiberry_amp_remove, -From 3e5856f6269407f9671fdb7b4ad2571ad6491864 Mon Sep 17 00:00:00 2001 +From 93addb736b05475b6ed41035b4dab1eee9bf35e4 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 3 Feb 2015 11:41:38 +0000 -Subject: [PATCH 099/116] BCM270x_DT: Add i2c0_baudrate and i2c1_baudrate +Subject: [PATCH 098/172] BCM270x_DT: Add i2c0_baudrate and i2c1_baudrate parameters --- @@ -137939,10 +137930,10 @@ index 46f4908..75c222f 100644 act_led_gpio = <&act_led>,"gpios:4"; act_led_activelow = <&act_led>,"gpios:8"; -From 9931580d09fb02180ad2b9951173adf4b616758b Mon Sep 17 00:00:00 2001 +From 83bef71ee725251abe65c91dd6ae76547acbc5ca Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 4 Feb 2015 10:02:24 +0000 -Subject: [PATCH 100/116] pinctrl-bcm2835: bcm2835_gpio_direction_output must +Subject: [PATCH 099/172] pinctrl-bcm2835: bcm2835_gpio_direction_output must set the value --- @@ -137970,10 +137961,10 @@ index 9d1149e..d9c727b 100644 static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -From 8473beee2daf191fed1f7f552a166300170afc8f Mon Sep 17 00:00:00 2001 +From 3e2353455d485d72a0bfbfefdfd7ce3dea783b93 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 4 Feb 2015 12:59:36 +0000 -Subject: [PATCH 101/116] w1-gpio: Sort out the pullup/parasitic power tangle +Subject: [PATCH 100/172] w1-gpio: Sort out the pullup/parasitic power tangle --- arch/arm/boot/dts/w1-gpio-overlay.dts | 4 +++- @@ -138146,10 +138137,10 @@ index d58594a..feae942 100644 unsigned int ext_pullup_enable_pin; unsigned int pullup_duration; -From ecd1431f8ccf075d1a0b8126f964c5b060fe6728 Mon Sep 17 00:00:00 2001 +From ca08a2747acc5e2033abdbae1696d00769754fda Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 4 Feb 2015 12:16:50 +0000 -Subject: [PATCH 102/116] dwc_otg: fixup read-modify-write in critical paths +Subject: [PATCH 101/172] dwc_otg: fixup read-modify-write in critical paths Be more careful about read-modify-write on registers that the FIQ also touches. @@ -138279,10 +138270,10 @@ index 17d3030..acd0dd7 100644 } } -From 49079860970f0a0435515c9a5fb2a91f08fe799d Mon Sep 17 00:00:00 2001 +From 14a8bf59835972411f4b73c37aae457ab46b6ee1 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 5 Feb 2015 16:01:44 +0000 -Subject: [PATCH 103/116] i2c_bcm2708: Fix clock reference counting +Subject: [PATCH 102/172] i2c_bcm2708: Fix clock reference counting --- drivers/i2c/busses/i2c-bcm2708.c | 12 ++++++++++-- @@ -138330,10 +138321,10 @@ index 526129b..fda59ba 100644 kfree(bi); -From 8bc381a8da1b10744c1783455495416f977f3e7c Mon Sep 17 00:00:00 2001 +From 2ec0ca5c31b9dc7498362727d40361b5d542552a Mon Sep 17 00:00:00 2001 From: Byron Bradley Date: Fri, 6 Feb 2015 14:19:41 +0000 -Subject: [PATCH 104/116] Add device-tree overlay for pcf2127 +Subject: [PATCH 103/172] Add device-tree overlay for pcf2127 Signed-off-by: Byron Bradley --- @@ -138383,10 +138374,10 @@ index 0000000..01fc81d + }; +}; -From ee1f9890529733d06b8cc1d142b16b416ada70de Mon Sep 17 00:00:00 2001 +From dc183cc424cc15195d4f5f6d559ba14da39e4c9f Mon Sep 17 00:00:00 2001 From: android Date: Mon, 25 Aug 2014 13:18:21 +0100 -Subject: [PATCH 105/116] BCM2708_VCIO : Add automatic creation of device node +Subject: [PATCH 104/172] BCM2708_VCIO : Add automatic creation of device node --- arch/arm/mach-bcm2708/vcio.c | 12 +++++++++++- @@ -138468,10 +138459,10 @@ index 5e43e85..700bff4 100644 } -From 0ca4c1f57c84bb114641176d63d16ce345f5a95d Mon Sep 17 00:00:00 2001 +From 7ae975fb0e9e826f87a895915a958b9a65c0f073 Mon Sep 17 00:00:00 2001 From: jeanleflambeur Date: Sun, 1 Feb 2015 12:35:38 +0100 -Subject: [PATCH 106/116] Fix grabbing lock from atomic context in i2c driver +Subject: [PATCH 105/172] 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: @@ -138690,37 +138681,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 d3d9b024cf0bb6acdf4b79066e782fe9dab7bedd Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 8 Feb 2015 13:17:00 +0000 -Subject: [PATCH 107/116] 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 f58911890f7c4585275f9cc2b7f31b27dc8d9393 Mon Sep 17 00:00:00 2001 +From 777022879290ae0dcd44f327a73088369957f2b8 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 12 Feb 2015 11:17:53 +0000 -Subject: [PATCH 108/116] Fix LED "input" trigger implementation for 3.19 +Subject: [PATCH 106/172] Fix LED "input" trigger implementation for 3.19 --- drivers/leds/leds-gpio.c | 10 +++++++++- @@ -138807,10 +138771,10 @@ index cfceef3..4c8dc19 100644 /* Set LED brightness level */ /* Must not sleep, use a workqueue if needed */ -From 087966e5e3bafdeb9f9ac7578f4995c7cc7ecf1d Mon Sep 17 00:00:00 2001 +From 8d8b2a22f6227d1c55b05b7e4247c57fcbb3bd88 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 12 Feb 2015 11:20:00 +0000 -Subject: [PATCH 109/116] fiq_fsm: Falling out of the state machine isn't fatal +Subject: [PATCH 107/172] 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. @@ -138880,10 +138844,10 @@ index 6266661..8a31562 100644 /** Handles interrupt for a specific Host Channel */ -From 9883079d5aaa02b17431f38b90e99e8f2bcd9911 Mon Sep 17 00:00:00 2001 +From 2455e8024a76f5de920dfa3d7e3177830fcacb7a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 15 Feb 2015 12:06:16 +0000 -Subject: [PATCH 110/116] platform: Remove bcmrpi_small_defconfig +Subject: [PATCH 108/172] platform: Remove bcmrpi_small_defconfig --- arch/arm/configs/bcmrpi_small_defconfig | 103 -------------------------------- @@ -139000,10 +138964,10 @@ index 3f6e378..0000000 -CONFIG_CRC_ITU_T=y -CONFIG_LIBCRC32C=y -From d5a3db1a12fa0f7882c0830ea580f9f253859f89 Mon Sep 17 00:00:00 2001 +From 82c208c7034e6a112808b16ee6fd1b910a50494c Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 15 Feb 2015 12:09:47 +0000 -Subject: [PATCH 111/116] platform: Remove bcmrpi_sdcard_defconfig +Subject: [PATCH 109/172] platform: Remove bcmrpi_sdcard_defconfig --- arch/arm/configs/bcmrpi_sdcard_defconfig | 176 ------------------------------- @@ -139193,10 +139157,10 @@ index fef887a..0000000 -CONFIG_CRC_ITU_T=y -CONFIG_LIBCRC32C=y -From 6e8273a7683b5967a4823c961729803ef1d4e3a1 Mon Sep 17 00:00:00 2001 +From cf9e2491332c7b58f25d489baa2040ab529e7223 Mon Sep 17 00:00:00 2001 From: Rainer Herbers Date: Sun, 15 Feb 2015 13:44:14 +0100 -Subject: [PATCH 112/116] Create bmp085_i2c-sensor-overlay.dts and update +Subject: [PATCH 110/172] Create bmp085_i2c-sensor-overlay.dts and update Makefile --- @@ -139247,10 +139211,10 @@ index 0000000..b830bf2 + }; +}; -From a8f400dc12f70c4460dd162e3d8d617cf7d01493 Mon Sep 17 00:00:00 2001 +From 62d72625e0c8f80a16aca64437885bea2d8e5bee Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Mon, 16 Feb 2015 13:51:02 +0000 -Subject: [PATCH 113/116] lirc-rpi: use getnstimeofday instead of +Subject: [PATCH 111/172] lirc-rpi: use getnstimeofday instead of read_current_timer read_current_timer isn't guaranteed to return values in @@ -139306,237 +139270,10 @@ index cd66ca2..24563ec 100644 flag = !flag; } -From 5c6ec05ffc9261163ab699a95398afd23c5f2aeb Mon Sep 17 00:00:00 2001 -From: Dave Martin -Date: Tue, 17 Feb 2015 16:28:52 +0000 -Subject: [PATCH 114/116] serial: amba-pl011: Kickstart TX by explicit FIFO - fill - -urrently, the transmit state machine arranges for the TX IRQ -always to be asserted whever the FIFO fill level is below the -watermark set in IFLS, with all actual transmission being done on -the back of the TX IRQ. - -To kickstart transmission, pl011_startup() temporarily disables the -FIFO, enables loopback mode and transmits a dummy character in -order to trigger the initial assertion of the IRQ. - -This leads to two problems: - - * Unfortunately, at least some pl011-based systems seem to send - this dummy character down the wire even in loopback mode (in - addition to looping it back). This means that if - pl011_startup() is called in between other transmissions, the - odd timing of the dummy tx forces the receiver out of sync. - - This causes problems when the console is on pl011 and userspace - opens and closes the same port often (*cough* systemd *cough*, - where large amounts of console output get turned to garbage as a - result). - - It also causes a single framing error whenever the port is - opened, in particulary in kernel_init_freeable() when preparing - the initial userspace environment. - - * The ARM SBSA UART[1] is a cut-down version of pl011. The lack - of a loopback mode means that the dummy tx strategy isn't - suitable for this UART, but the other differences should be less - invasive. - -This patch makes an initial call to pl011_tx_chars() to get things -going instead of sending a dummy character. This should reduce the -turnaround time of an XON/XOFF by one IRQ latency or so, as well as -eliminating some IRQs around short writes from the tty layer. - -There is no way to find out the TX FIFO fill level from the -hardware directly, which becomes a problem when transmitting -characters outside the interrupt handler. To address this while -keeping status polling minimal, a minimum bound on the space -available is maintained in uap->tx_avail. For now, if we are not -sure there is any FIFO space at all, the driver transmits nothing -and falls back to waiting for the next TX inerrupt. - -Thanks to Andrew Jackson for spotting some dumb bugs while I was -developing this patch. - -[1] ARM-DEN-0029 Server Base System Architecture, available (click- - thru...) from http://infocenter.arm.com. Version v2.3 was - referred to when drawing the above conclusions. - -Signed-off-by: Dave Martin -Cc: Russell King -Cc: Andre Przywara ---- - drivers/tty/serial/amba-pl011.c | 64 ++++++++++++++++++----------------------- - 1 file changed, 28 insertions(+), 36 deletions(-) - -diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c -index 16ca535..e00ca32 100644 ---- a/drivers/tty/serial/amba-pl011.c -+++ b/drivers/tty/serial/amba-pl011.c -@@ -157,6 +157,7 @@ struct uart_amba_port { - unsigned int lcrh_rx; /* vendor-specific */ - unsigned int old_cr; /* state during shutdown */ - bool autorts; -+ unsigned int tx_avail; /* min TX FIFO space */ - char type[12]; - #ifdef CONFIG_DMA_ENGINE - /* DMA stuff */ -@@ -585,6 +586,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) - */ - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx += count; -+ uap->tx_avail = 0; /* DMA will be keeping the FIFO full now */ - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uap->port); -@@ -686,7 +688,8 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) - uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); - -- if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) { -+ if (uap->tx_avail < 1 && -+ readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) { - /* - * No space in the FIFO, so enable the transmit interrupt - * so we know when there is space. Note that once we've -@@ -698,6 +701,8 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) - writew(uap->port.x_char, uap->port.membase + UART01x_DR); - uap->port.icount.tx++; - uap->port.x_char = 0; -+ if (uap->tx_avail > 0) -+ uap->tx_avail--; - - /* Success - restore the DMA state */ - uap->dmacr = dmacr; -@@ -1208,6 +1213,8 @@ static void pl011_stop_tx(struct uart_port *port) - pl011_dma_tx_stop(uap); - } - -+static void pl011_tx_chars(struct uart_amba_port *uap); -+ - static void pl011_start_tx(struct uart_port *port) - { - struct uart_amba_port *uap = -@@ -1216,6 +1223,7 @@ static void pl011_start_tx(struct uart_port *port) - if (!pl011_dma_tx_start(uap)) { - uap->im |= UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); -+ pl011_tx_chars(uap); - } - } - -@@ -1283,6 +1291,7 @@ static void pl011_tx_chars(struct uart_amba_port *uap) - writew(uap->port.x_char, uap->port.membase + UART01x_DR); - uap->port.icount.tx++; - uap->port.x_char = 0; -+ uap->tx_avail--; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { -@@ -1294,14 +1303,16 @@ static void pl011_tx_chars(struct uart_amba_port *uap) - if (pl011_dma_tx_irq(uap)) - return; - -- count = uap->fifosize >> 1; -- do { -+ count = uart_circ_chars_pending(xmit); -+ if (uap->tx_avail < count) -+ count = uap->tx_avail; -+ -+ while (count--) { - writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - uap->port.icount.tx++; -- if (uart_circ_empty(xmit)) -- break; -- } while (--count > 0); -+ uap->tx_avail--; -+ } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&uap->port); -@@ -1372,8 +1383,10 @@ static irqreturn_t pl011_int(int irq, void *dev_id) - if (status & (UART011_DSRMIS|UART011_DCDMIS| - UART011_CTSMIS|UART011_RIMIS)) - pl011_modem_status(uap); -- if (status & UART011_TXIS) -+ if (status & UART011_TXIS) { -+ uap->tx_avail = uap->fifosize >> 1; - pl011_tx_chars(uap); -+ } - - if (pass_counter-- == 0) - break; -@@ -1392,8 +1405,12 @@ static unsigned int pl011_tx_empty(struct uart_port *port) - { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); -- unsigned int status = readw(uap->port.membase + UART01x_FR); -- return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; -+ unsigned int status = readw(uap->port.membase + UART01x_FR) & -+ (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; -+ -+ if (status) -+ uap->tx_avail = uap->fifosize; -+ return status; - } - - static unsigned int pl011_get_mctrl(struct uart_port *port) -@@ -1577,7 +1594,7 @@ static int pl011_startup(struct uart_port *port) - { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); -- unsigned int cr, lcr_h, fbrd, ibrd; -+ unsigned int cr; - int retval; - - retval = pl011_hwinit(port); -@@ -1594,38 +1611,13 @@ static int pl011_startup(struct uart_port *port) - goto clk_dis; - - writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); -- -- /* -- * Provoke TX FIFO interrupt into asserting. Taking care to preserve -- * baud rate and data format specified by FBRD, IBRD and LCRH as the -- * UART may already be in use as a console. -- */ -- spin_lock_irq(&uap->port.lock); -- -- fbrd = readw(uap->port.membase + UART011_FBRD); -- ibrd = readw(uap->port.membase + UART011_IBRD); -- lcr_h = readw(uap->port.membase + uap->lcrh_rx); -- -- cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; -- writew(cr, uap->port.membase + UART011_CR); -- writew(0, uap->port.membase + UART011_FBRD); -- writew(1, uap->port.membase + UART011_IBRD); -- pl011_write_lcr_h(uap, 0); -- writew(0, uap->port.membase + UART01x_DR); -- while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) -- barrier(); -- -- writew(fbrd, uap->port.membase + UART011_FBRD); -- writew(ibrd, uap->port.membase + UART011_IBRD); -- pl011_write_lcr_h(uap, lcr_h); -+ uap->tx_avail = uap->fifosize; /* FIFO should be empty */ - - /* restore RTS and DTR */ - cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); - cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; - writew(cr, uap->port.membase + UART011_CR); - -- spin_unlock_irq(&uap->port.lock); -- - /* - * initialise the old status of the modem signals - */ - -From d0a44cbe02c860f3b533b34916c6c8efd45fffac Mon Sep 17 00:00:00 2001 +From d38f6c099572f92660d4a7125b97159b89ac5970 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 18 Feb 2015 10:40:28 +0000 -Subject: [PATCH 115/116] vc_cma: Make the vc_cma area the default contiguous +Subject: [PATCH 112/172] vc_cma: Make the vc_cma area the default contiguous DMA area --- @@ -139747,37 +139484,15229 @@ index a635f9f..bd64317 100644 VC_CMA_CHUNK_ORDER); if (!chunk) -From 3c9fd364bfa6c0f6ef725d74b72a9b77dd0d0fb4 Mon Sep 17 00:00:00 2001 +From 35c8e88b85da5994d81aad77928546f82784d5cc Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 18 Feb 2015 22:00:00 +0000 -Subject: [PATCH 116/116] config: Add TOUCHSCREEN_EGALAX +Subject: [PATCH 113/172] config: extra options --- - arch/arm/configs/bcm2709_defconfig | 1 + - arch/arm/configs/bcmrpi_defconfig | 1 + - 2 files changed, 2 insertions(+) + arch/arm/configs/bcm2709_defconfig | 23 +++- + arch/arm/configs/bcm2835_sdcard_defconfig | 176 ------------------------------ + arch/arm/configs/bcmrpi_defconfig | 22 +++- + 3 files changed, 33 insertions(+), 188 deletions(-) + delete mode 100644 arch/arm/configs/bcm2835_sdcard_defconfig diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig -index d4c18fa..1413673 100644 +index d4c18fa..bc557a5 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig -@@ -527,6 +527,7 @@ CONFIG_JOYSTICK_XPAD=m +@@ -5,7 +5,6 @@ CONFIG_LOCALVERSION="-v7" + CONFIG_SYSVIPC=y + CONFIG_POSIX_MQUEUE=y + CONFIG_FHANDLE=y +-CONFIG_AUDIT=y + CONFIG_NO_HZ=y + CONFIG_HIGH_RES_TIMERS=y + CONFIG_BSD_PROCESS_ACCT=y +@@ -14,12 +13,11 @@ CONFIG_TASKSTATS=y + CONFIG_TASK_DELAY_ACCT=y + CONFIG_TASK_XACCT=y + CONFIG_TASK_IO_ACCOUNTING=y +-CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG=m + CONFIG_IKCONFIG_PROC=y + CONFIG_CGROUP_FREEZER=y + CONFIG_CGROUP_DEVICE=y + CONFIG_CGROUP_CPUACCT=y +-CONFIG_RESOURCE_COUNTERS=y + CONFIG_MEMCG=y + CONFIG_BLK_CGROUP=y + CONFIG_NAMESPACES=y +@@ -55,7 +53,6 @@ CONFIG_SECCOMP=y + CONFIG_ZBOOT_ROM_TEXT=0x0 + CONFIG_ZBOOT_ROM_BSS=0x0 + CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait" +-CONFIG_KEXEC=y + CONFIG_CPU_FREQ=y + CONFIG_CPU_FREQ_STAT=m + CONFIG_CPU_FREQ_STAT_DETAILS=y +@@ -64,11 +61,11 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y + CONFIG_CPU_FREQ_GOV_USERSPACE=y + CONFIG_CPU_FREQ_GOV_ONDEMAND=y + CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +-CONFIG_CPU_IDLE=y + CONFIG_VFP=y + CONFIG_NEON=y + CONFIG_KERNEL_MODE_NEON=y + CONFIG_BINFMT_MISC=m ++# CONFIG_SUSPEND is not set + CONFIG_NET=y + CONFIG_PACKET=y + CONFIG_UNIX=y +@@ -126,7 +123,6 @@ CONFIG_NF_CONNTRACK_SIP=m + CONFIG_NF_CONNTRACK_TFTP=m + CONFIG_NF_CT_NETLINK=m + CONFIG_NETFILTER_XT_SET=m +-CONFIG_NETFILTER_XT_TARGET_AUDIT=m + CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m + CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m + CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +@@ -282,6 +278,7 @@ CONFIG_BRIDGE=m + CONFIG_VLAN_8021Q=m + CONFIG_VLAN_8021Q_GVRP=y + CONFIG_ATALK=m ++CONFIG_6LOWPAN=m + CONFIG_NET_SCHED=y + CONFIG_NET_SCH_CBQ=m + CONFIG_NET_SCH_HTB=m +@@ -345,6 +342,9 @@ CONFIG_BPQETHER=m + CONFIG_BAYCOM_SER_FDX=m + CONFIG_BAYCOM_SER_HDX=m + CONFIG_YAM=m ++CONFIG_CAN=m ++CONFIG_CAN_VCAN=m ++CONFIG_CAN_MCP251X=m + CONFIG_IRDA=m + CONFIG_IRLAN=m + CONFIG_IRNET=m +@@ -360,12 +360,14 @@ CONFIG_USB_IRDA=m + CONFIG_SIGMATEL_FIR=m + CONFIG_MCS_FIR=m + CONFIG_BT=m ++CONFIG_BT_6LOWPAN=m + CONFIG_BT_RFCOMM=m + CONFIG_BT_RFCOMM_TTY=y + CONFIG_BT_BNEP=m + CONFIG_BT_BNEP_MC_FILTER=y + CONFIG_BT_BNEP_PROTO_FILTER=y + CONFIG_BT_HIDP=m ++CONFIG_BT_6LOWPAN=m + CONFIG_BT_HCIBTUSB=m + CONFIG_BT_HCIBCM203X=m + CONFIG_BT_HCIBPA10X=m +@@ -394,6 +396,7 @@ CONFIG_BLK_DEV_DRBD=m + CONFIG_BLK_DEV_NBD=m + CONFIG_BLK_DEV_RAM=y + CONFIG_CDROM_PKTCDVD=m ++CONFIG_ATA_OVER_ETH=m + CONFIG_EEPROM_AT24=m + CONFIG_SCSI=y + # CONFIG_SCSI_PROC_FS is not set +@@ -527,6 +530,9 @@ CONFIG_JOYSTICK_XPAD=m CONFIG_JOYSTICK_XPAD_FF=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_EGALAX=m ++CONFIG_TOUCHSCREEN_USB_COMPOSITE=m ++CONFIG_TOUCHSCREEN_STMPE=m CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_ATI_REMOTE2=m +@@ -560,6 +566,7 @@ CONFIG_I2C_CHARDEV=m + CONFIG_I2C_MUX=m + CONFIG_I2C_BCM2708=m + CONFIG_SPI=y ++CONFIG_SPI_BCM2835=m + CONFIG_SPI_BCM2708=m + CONFIG_SPI_SPIDEV=y + CONFIG_PPS=m +@@ -567,6 +574,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 +600,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 +773,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/bcm2835_sdcard_defconfig b/arch/arm/configs/bcm2835_sdcard_defconfig +deleted file mode 100644 +index 987471b..0000000 +--- a/arch/arm/configs/bcm2835_sdcard_defconfig ++++ /dev/null +@@ -1,176 +0,0 @@ +-# CONFIG_ARM_PATCH_PHYS_VIRT is not set +-CONFIG_LOCALVERSION="-quick" +-# CONFIG_LOCALVERSION_AUTO is not set +-# CONFIG_SWAP is not set +-CONFIG_SYSVIPC=y +-CONFIG_POSIX_MQUEUE=y +-CONFIG_NO_HZ=y +-CONFIG_HIGH_RES_TIMERS=y +-CONFIG_IKCONFIG=y +-CONFIG_IKCONFIG_PROC=y +-CONFIG_KALLSYMS_ALL=y +-CONFIG_EMBEDDED=y +-CONFIG_PERF_EVENTS=y +-# CONFIG_COMPAT_BRK is not set +-CONFIG_SLAB=y +-# CONFIG_BLK_DEV_BSG is not set +-CONFIG_ARCH_BCM2708=y +-# CONFIG_BCM2708_GPIO is not set +-CONFIG_PREEMPT=y +-CONFIG_AEABI=y +-CONFIG_UACCESS_WITH_MEMCPY=y +-CONFIG_ZBOOT_ROM_TEXT=0x0 +-CONFIG_ZBOOT_ROM_BSS=0x0 +-CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait" +-CONFIG_CPU_FREQ=y +-CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y +-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +-CONFIG_CPU_FREQ_GOV_USERSPACE=y +-CONFIG_CPU_FREQ_GOV_ONDEMAND=y +-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +-CONFIG_CPU_IDLE=y +-CONFIG_VFP=y +-CONFIG_BINFMT_MISC=y +-CONFIG_NET=y +-CONFIG_PACKET=y +-CONFIG_UNIX=y +-CONFIG_INET=y +-CONFIG_IP_MULTICAST=y +-CONFIG_IP_PNP=y +-CONFIG_IP_PNP_DHCP=y +-CONFIG_IP_PNP_RARP=y +-CONFIG_SYN_COOKIES=y +-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +-# CONFIG_INET_XFRM_MODE_TUNNEL is not set +-# CONFIG_INET_XFRM_MODE_BEET is not set +-# CONFIG_INET_LRO is not set +-# CONFIG_INET_DIAG is not set +-# CONFIG_IPV6 is not set +-# CONFIG_WIRELESS is not set +-CONFIG_DEVTMPFS=y +-CONFIG_DEVTMPFS_MOUNT=y +-CONFIG_BLK_DEV_LOOP=y +-CONFIG_BLK_DEV_RAM=y +-CONFIG_SCSI=y +-# CONFIG_SCSI_PROC_FS is not set +-# CONFIG_SCSI_LOWLEVEL is not set +-CONFIG_NETDEVICES=y +-CONFIG_MII=y +-# CONFIG_NET_VENDOR_BROADCOM is not set +-# CONFIG_NET_VENDOR_CIRRUS is not set +-# CONFIG_NET_VENDOR_FARADAY is not set +-# CONFIG_NET_VENDOR_INTEL is not set +-# CONFIG_NET_VENDOR_MARVELL is not set +-# CONFIG_NET_VENDOR_MICREL is not set +-# CONFIG_NET_VENDOR_NATSEMI is not set +-# CONFIG_NET_VENDOR_SEEQ is not set +-# CONFIG_NET_VENDOR_STMICRO is not set +-# CONFIG_NET_VENDOR_WIZNET is not set +-CONFIG_PHYLIB=y +-# CONFIG_WLAN is not set +-# CONFIG_INPUT_MOUSEDEV is not set +-CONFIG_INPUT_EVDEV=y +-# CONFIG_INPUT_KEYBOARD is not set +-# CONFIG_INPUT_MOUSE is not set +-# CONFIG_SERIO is not set +-CONFIG_VT_HW_CONSOLE_BINDING=y +-# CONFIG_LEGACY_PTYS is not set +-# CONFIG_DEVKMEM is not set +-CONFIG_SERIAL_AMBA_PL011=y +-CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +-CONFIG_TTY_PRINTK=y +-CONFIG_RAW_DRIVER=y +-CONFIG_WATCHDOG=y +-CONFIG_REGULATOR=y +-CONFIG_REGULATOR_DEBUG=y +-CONFIG_REGULATOR_FIXED_VOLTAGE=y +-CONFIG_REGULATOR_VIRTUAL_CONSUMER=y +-CONFIG_REGULATOR_USERSPACE_CONSUMER=y +-CONFIG_FB=y +-CONFIG_FRAMEBUFFER_CONSOLE=y +-CONFIG_LOGO=y +-# CONFIG_LOGO_LINUX_MONO is not set +-# CONFIG_LOGO_LINUX_VGA16 is not set +-CONFIG_SOUND=y +-CONFIG_SND=y +-CONFIG_MMC=y +-CONFIG_MMC_SDHCI=y +-CONFIG_MMC_SDHCI_PLTFM=y +-CONFIG_MMC_SDHCI_BCM2708=y +-CONFIG_MMC_SDHCI_BCM2708_DMA=y +-CONFIG_NEW_LEDS=y +-CONFIG_LEDS_CLASS=y +-CONFIG_LEDS_TRIGGERS=y +-# CONFIG_IOMMU_SUPPORT is not set +-CONFIG_EXT4_FS=y +-CONFIG_EXT4_FS_POSIX_ACL=y +-CONFIG_EXT4_FS_SECURITY=y +-CONFIG_AUTOFS4_FS=y +-CONFIG_FSCACHE=y +-CONFIG_CACHEFILES=y +-CONFIG_MSDOS_FS=y +-CONFIG_VFAT_FS=y +-CONFIG_FAT_DEFAULT_IOCHARSET="ascii" +-CONFIG_TMPFS=y +-CONFIG_TMPFS_POSIX_ACL=y +-CONFIG_CONFIGFS_FS=y +-# CONFIG_MISC_FILESYSTEMS is not set +-CONFIG_NFS_FS=y +-CONFIG_NFS_V3_ACL=y +-CONFIG_NFS_V4=y +-CONFIG_ROOT_NFS=y +-CONFIG_NFS_FSCACHE=y +-CONFIG_NLS_DEFAULT="utf8" +-CONFIG_NLS_CODEPAGE_437=y +-CONFIG_NLS_CODEPAGE_737=y +-CONFIG_NLS_CODEPAGE_775=y +-CONFIG_NLS_CODEPAGE_850=y +-CONFIG_NLS_CODEPAGE_852=y +-CONFIG_NLS_CODEPAGE_855=y +-CONFIG_NLS_CODEPAGE_857=y +-CONFIG_NLS_CODEPAGE_860=y +-CONFIG_NLS_CODEPAGE_861=y +-CONFIG_NLS_CODEPAGE_862=y +-CONFIG_NLS_CODEPAGE_863=y +-CONFIG_NLS_CODEPAGE_864=y +-CONFIG_NLS_CODEPAGE_865=y +-CONFIG_NLS_CODEPAGE_866=y +-CONFIG_NLS_CODEPAGE_869=y +-CONFIG_NLS_CODEPAGE_936=y +-CONFIG_NLS_CODEPAGE_950=y +-CONFIG_NLS_CODEPAGE_932=y +-CONFIG_NLS_CODEPAGE_949=y +-CONFIG_NLS_CODEPAGE_874=y +-CONFIG_NLS_ISO8859_8=y +-CONFIG_NLS_CODEPAGE_1250=y +-CONFIG_NLS_CODEPAGE_1251=y +-CONFIG_NLS_ASCII=y +-CONFIG_NLS_ISO8859_1=y +-CONFIG_NLS_ISO8859_2=y +-CONFIG_NLS_ISO8859_3=y +-CONFIG_NLS_ISO8859_4=y +-CONFIG_NLS_ISO8859_5=y +-CONFIG_NLS_ISO8859_6=y +-CONFIG_NLS_ISO8859_7=y +-CONFIG_NLS_ISO8859_9=y +-CONFIG_NLS_ISO8859_13=y +-CONFIG_NLS_ISO8859_14=y +-CONFIG_NLS_ISO8859_15=y +-CONFIG_NLS_UTF8=y +-CONFIG_PRINTK_TIME=y +-CONFIG_DEBUG_FS=y +-# CONFIG_DEBUG_PREEMPT is not set +-# CONFIG_DEBUG_BUGVERBOSE is not set +-# CONFIG_FTRACE is not set +-CONFIG_KGDB=y +-CONFIG_KGDB_KDB=y +-# CONFIG_ARM_UNWIND is not set +-CONFIG_CRYPTO_CBC=y +-CONFIG_CRYPTO_HMAC=y +-CONFIG_CRYPTO_MD5=y +-CONFIG_CRYPTO_SHA1=y +-CONFIG_CRYPTO_DES=y +-# CONFIG_CRYPTO_ANSI_CPRNG is not set +-# CONFIG_CRYPTO_HW is not set +-CONFIG_CRC_ITU_T=y +-CONFIG_LIBCRC32C=y diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 898ebd2..70a5ea3 100644 +index 898ebd2..4d703f4 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig -@@ -520,6 +520,7 @@ CONFIG_JOYSTICK_XPAD=m +@@ -4,7 +4,6 @@ CONFIG_PHYS_OFFSET=0 + CONFIG_SYSVIPC=y + CONFIG_POSIX_MQUEUE=y + CONFIG_FHANDLE=y +-CONFIG_AUDIT=y + CONFIG_NO_HZ=y + CONFIG_HIGH_RES_TIMERS=y + CONFIG_BSD_PROCESS_ACCT=y +@@ -13,12 +12,11 @@ CONFIG_TASKSTATS=y + CONFIG_TASK_DELAY_ACCT=y + CONFIG_TASK_XACCT=y + CONFIG_TASK_IO_ACCOUNTING=y +-CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG=m + CONFIG_IKCONFIG_PROC=y + CONFIG_CGROUP_FREEZER=y + CONFIG_CGROUP_DEVICE=y + CONFIG_CGROUP_CPUACCT=y +-CONFIG_RESOURCE_COUNTERS=y + CONFIG_MEMCG=y + CONFIG_BLK_CGROUP=y + CONFIG_NAMESPACES=y +@@ -50,7 +48,6 @@ CONFIG_SECCOMP=y + CONFIG_ZBOOT_ROM_TEXT=0x0 + CONFIG_ZBOOT_ROM_BSS=0x0 + CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait" +-CONFIG_KEXEC=y + CONFIG_CPU_FREQ=y + CONFIG_CPU_FREQ_STAT=m + CONFIG_CPU_FREQ_STAT_DETAILS=y +@@ -59,9 +56,9 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y + CONFIG_CPU_FREQ_GOV_USERSPACE=y + CONFIG_CPU_FREQ_GOV_ONDEMAND=y + CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +-CONFIG_CPU_IDLE=y + CONFIG_VFP=y + CONFIG_BINFMT_MISC=m ++# CONFIG_SUSPEND is not set + CONFIG_NET=y + CONFIG_PACKET=y + CONFIG_UNIX=y +@@ -119,7 +116,6 @@ CONFIG_NF_CONNTRACK_SIP=m + CONFIG_NF_CONNTRACK_TFTP=m + CONFIG_NF_CT_NETLINK=m + CONFIG_NETFILTER_XT_SET=m +-CONFIG_NETFILTER_XT_TARGET_AUDIT=m + CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m + CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m + CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +@@ -275,6 +271,7 @@ CONFIG_BRIDGE=m + CONFIG_VLAN_8021Q=m + CONFIG_VLAN_8021Q_GVRP=y + CONFIG_ATALK=m ++CONFIG_6LOWPAN=m + CONFIG_NET_SCHED=y + CONFIG_NET_SCH_CBQ=m + CONFIG_NET_SCH_HTB=m +@@ -338,6 +335,9 @@ CONFIG_BPQETHER=m + CONFIG_BAYCOM_SER_FDX=m + CONFIG_BAYCOM_SER_HDX=m + CONFIG_YAM=m ++CONFIG_CAN=m ++CONFIG_CAN_VCAN=m ++CONFIG_CAN_MCP251X=m + CONFIG_IRDA=m + CONFIG_IRLAN=m + CONFIG_IRNET=m +@@ -353,6 +353,7 @@ CONFIG_USB_IRDA=m + CONFIG_SIGMATEL_FIR=m + CONFIG_MCS_FIR=m + CONFIG_BT=m ++CONFIG_BT_6LOWPAN=m + CONFIG_BT_RFCOMM=m + CONFIG_BT_RFCOMM_TTY=y + CONFIG_BT_BNEP=m +@@ -387,6 +388,7 @@ CONFIG_BLK_DEV_DRBD=m + CONFIG_BLK_DEV_NBD=m + CONFIG_BLK_DEV_RAM=y + CONFIG_CDROM_PKTCDVD=m ++CONFIG_ATA_OVER_ETH=m + CONFIG_EEPROM_AT24=m + CONFIG_SCSI=y + # CONFIG_SCSI_PROC_FS is not set +@@ -520,6 +522,9 @@ CONFIG_JOYSTICK_XPAD=m CONFIG_JOYSTICK_XPAD_FF=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_EGALAX=m ++CONFIG_TOUCHSCREEN_USB_COMPOSITE=m ++CONFIG_TOUCHSCREEN_STMPE=m CONFIG_INPUT_MISC=y CONFIG_INPUT_AD714X=m CONFIG_INPUT_ATI_REMOTE2=m +@@ -553,6 +558,7 @@ CONFIG_I2C_CHARDEV=m + CONFIG_I2C_MUX=m + CONFIG_I2C_BCM2708=m + CONFIG_SPI=y ++CONFIG_SPI_BCM2835=m + CONFIG_SPI_BCM2708=m + CONFIG_SPI_SPIDEV=y + CONFIG_PPS=m +@@ -560,6 +566,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 +592,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 +765,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 b08151a4eda84af4ce2dbe0b85dab4895964b692 Mon Sep 17 00:00:00 2001 +From: "Yann E. MORIN" +Date: Wed, 18 Feb 2015 12:46:07 +0100 +Subject: [PATCH 114/172] 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 60a017bba035a8623994425e9a4e72bf73988358 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 24 Feb 2015 13:40:50 +0000 +Subject: [PATCH 115/172] 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 d9c727b..01a8966 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 4ac9769f94555bf911430ae6bb60147c86eef83c Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 25 Feb 2015 17:14:57 +0000 +Subject: [PATCH 116/172] 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 e9793e25e0c44d44d780efcda5b338185d158b41 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Thu, 26 Feb 2015 11:42:34 +0000 +Subject: [PATCH 117/172] pinctrl: squash + +--- + drivers/pinctrl/pinctrl-bcm2835.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c +index 01a8966..ae68710 100644 +--- a/drivers/pinctrl/pinctrl-bcm2835.c ++++ b/drivers/pinctrl/pinctrl-bcm2835.c +@@ -1095,6 +1095,7 @@ static struct platform_driver bcm2835_pinctrl_driver = { + .remove = bcm2835_pinctrl_remove, + .driver = { + .name = MODULE_NAME, ++ .owner = THIS_MODULE, + .of_match_table = bcm2835_pinctrl_match, + }, + }; + +From 30ed96c07f97f78a923fa5ef0611ace11e521d1c Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 26 Feb 2015 09:58:22 +0000 +Subject: [PATCH 118/172] 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 ac3374c94c497e1e55a7b734f3bf238a5587430a Mon Sep 17 00:00:00 2001 +From: Dave Martin +Date: Fri, 27 Feb 2015 15:51:37 +0000 +Subject: [PATCH 119/172] serial/amba-pl011: Activate TX IRQ passively + +The current PL011 driver transmits a dummy character when the UART +is opened, to assert the TX IRQ for the first time +(see pl011_startup()). The UART is put in loopback mode temporarily, +so the receiver presumably shouldn't see anything. + +However... + +At least some platforms containing a PL011 send characters down the +wire even when loopback mode is enabled. This means that a +spurious NUL character may be seen at the receiver when the PL011 is +opened through the TTY layer. + +The current code also temporarily sets the baud rate to maximum and +the character width to the minimum, to that the dummy TX completes +as quickly as possible. If this is seen by the receiver it will +result in a framing error and can knock the receiver out of sync -- +turning subsequent output into garbage until synchronisation +is reestablished. (Particularly problematic during boot with systemd.) + +To avoid spurious transmissions, this patch removes assumptions about +whether the TX IRQ will fire until at least one TX IRQ has been seen. + +Instead, the UART will unmask the TX IRQ and then slow-start via +polling and timer-based soft IRQs initially. If the TTY layer writes +enough data to fill the FIFO to the interrupt threshold in one go, +the TX IRQ should assert, at which point the driver changes to +fully interrupt-driven TX. + +In this way, the TX IRQ is activated as a side-effect instead of +being done deliberately. + +This should also mean that the driver works on the SBSA Generic +UART[1] (a cut-down PL011) without invasive changes. The Generic +UART lacks some features needed for the dummy TX approach to work +(FIFO disabling and loopback). + +[1] Server Base System Architecture (ARM-DEN-0029-v2.3) + http://infocenter.arm.com/ + (click-thru required :/) + +Signed-off-by: Dave Martin +--- + drivers/tty/serial/amba-pl011.c | 165 ++++++++++++++++++++++++++++------------ + 1 file changed, 115 insertions(+), 50 deletions(-) + +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index 16ca535..c243729 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -58,6 +58,7 @@ + #include + #include + #include ++#include + + #define UART_NR 14 + +@@ -156,7 +157,9 @@ struct uart_amba_port { + unsigned int lcrh_tx; /* vendor-specific */ + unsigned int lcrh_rx; /* vendor-specific */ + unsigned int old_cr; /* state during shutdown */ ++ struct delayed_work tx_softirq_work; + bool autorts; ++ unsigned int tx_irq_seen; /* 0=none, 1=1, 2=2 or more */ + char type[12]; + #ifdef CONFIG_DMA_ENGINE + /* DMA stuff */ +@@ -440,8 +443,9 @@ static void pl011_dma_remove(struct uart_amba_port *uap) + dma_release_channel(uap->dmarx.chan); + } + +-/* Forward declare this for the refill routine */ ++/* Forward declare these for the refill routine */ + static int pl011_dma_tx_refill(struct uart_amba_port *uap); ++static void pl011_start_tx_pio(struct uart_amba_port *uap); + + /* + * The current DMA TX buffer has been sent. +@@ -479,14 +483,13 @@ static void pl011_dma_tx_callback(void *data) + return; + } + +- if (pl011_dma_tx_refill(uap) <= 0) { ++ if (pl011_dma_tx_refill(uap) <= 0) + /* + * We didn't queue a DMA buffer for some reason, but we + * have data pending to be sent. Re-enable the TX IRQ. + */ +- uap->im |= UART011_TXIM; +- writew(uap->im, uap->port.membase + UART011_IMSC); +- } ++ pl011_start_tx_pio(uap); ++ + spin_unlock_irqrestore(&uap->port.lock, flags); + } + +@@ -664,12 +667,10 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) + if (!uap->dmatx.queued) { + if (pl011_dma_tx_refill(uap) > 0) { + uap->im &= ~UART011_TXIM; +- ret = true; +- } else { +- uap->im |= UART011_TXIM; ++ writew(uap->im, uap->port.membase + ++ UART011_IMSC); ++ } else + ret = false; +- } +- writew(uap->im, uap->port.membase + UART011_IMSC); + } else if (!(uap->dmacr & UART011_TXDMAE)) { + uap->dmacr |= UART011_TXDMAE; + writew(uap->dmacr, +@@ -1208,15 +1209,24 @@ static void pl011_stop_tx(struct uart_port *port) + pl011_dma_tx_stop(uap); + } + ++static bool pl011_tx_chars(struct uart_amba_port *uap); ++ ++/* Start TX with programmed I/O only (no DMA) */ ++static void pl011_start_tx_pio(struct uart_amba_port *uap) ++{ ++ uap->im |= UART011_TXIM; ++ writew(uap->im, uap->port.membase + UART011_IMSC); ++ if (!uap->tx_irq_seen) ++ pl011_tx_chars(uap); ++} ++ + static void pl011_start_tx(struct uart_port *port) + { + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + +- if (!pl011_dma_tx_start(uap)) { +- uap->im |= UART011_TXIM; +- writew(uap->im, uap->port.membase + UART011_IMSC); +- } ++ if (!pl011_dma_tx_start(uap)) ++ pl011_start_tx_pio(uap); + } + + static void pl011_stop_rx(struct uart_port *port) +@@ -1274,40 +1284,87 @@ __acquires(&uap->port.lock) + spin_lock(&uap->port.lock); + } + +-static void pl011_tx_chars(struct uart_amba_port *uap) ++/* ++ * Transmit a character ++ * There must be at least one free entry in the TX FIFO to accept the char. ++ * ++ * Returns true if the FIFO might have space in it afterwards; ++ * returns false if the FIFO definitely became full. ++ */ ++static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c) ++{ ++ writew(c, uap->port.membase + UART01x_DR); ++ uap->port.icount.tx++; ++ ++ if (likely(uap->tx_irq_seen > 1)) ++ return true; ++ ++ return !(readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF); ++} ++ ++static bool pl011_tx_chars(struct uart_amba_port *uap) + { + struct circ_buf *xmit = &uap->port.state->xmit; + int count; + ++ if (unlikely(uap->tx_irq_seen < 2)) ++ /* ++ * Initial FIFO fill level unknown: we must check TXFF ++ * after each write, so just try to fill up the FIFO. ++ */ ++ count = uap->fifosize; ++ else /* tx_irq_seen >= 2 */ ++ /* ++ * FIFO initially at least half-empty, so we can simply ++ * write half the FIFO without polling TXFF. ++ ++ * Note: the *first* TX IRQ can still race with ++ * pl011_start_tx_pio(), which can result in the FIFO ++ * being fuller than expected in that case. ++ */ ++ count = uap->fifosize >> 1; ++ ++ /* ++ * If the FIFO is full we're guaranteed a TX IRQ at some later point, ++ * and can't transmit immediately in any case: ++ */ ++ if (unlikely(uap->tx_irq_seen < 2 && ++ readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)) ++ return false; ++ + if (uap->port.x_char) { +- writew(uap->port.x_char, uap->port.membase + UART01x_DR); +- uap->port.icount.tx++; ++ pl011_tx_char(uap, uap->port.x_char); + uap->port.x_char = 0; +- return; ++ --count; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { + pl011_stop_tx(&uap->port); +- return; ++ goto done; + } + + /* If we are using DMA mode, try to send some characters. */ + if (pl011_dma_tx_irq(uap)) +- return; ++ goto done; + +- count = uap->fifosize >> 1; +- do { +- writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); ++ while (count-- > 0 && pl011_tx_char(uap, xmit->buf[xmit->tail])) { + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); +- uap->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; +- } while (--count > 0); ++ } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uap->port); + +- if (uart_circ_empty(xmit)) ++ if (uart_circ_empty(xmit)) { + pl011_stop_tx(&uap->port); ++ goto done; ++ } ++ ++ if (unlikely(!uap->tx_irq_seen)) ++ schedule_delayed_work(&uap->tx_softirq_work, uap->port.timeout); ++ ++done: ++ return false; + } + + static void pl011_modem_status(struct uart_amba_port *uap) +@@ -1334,6 +1391,28 @@ static void pl011_modem_status(struct uart_amba_port *uap) + wake_up_interruptible(&uap->port.state->port.delta_msr_wait); + } + ++static void pl011_tx_softirq(struct work_struct *work) ++{ ++ struct delayed_work *dwork = to_delayed_work(work); ++ struct uart_amba_port *uap = ++ container_of(dwork, struct uart_amba_port, tx_softirq_work); ++ ++ spin_lock(&uap->port.lock); ++ while (pl011_tx_chars(uap)) ; ++ spin_unlock(&uap->port.lock); ++} ++ ++static void pl011_tx_irq_seen(struct uart_amba_port *uap) ++{ ++ if (likely(uap->tx_irq_seen > 1)) ++ return; ++ ++ uap->tx_irq_seen++; ++ if (uap->tx_irq_seen < 2) ++ /* first TX IRQ */ ++ cancel_delayed_work(&uap->tx_softirq_work); ++} ++ + static irqreturn_t pl011_int(int irq, void *dev_id) + { + struct uart_amba_port *uap = dev_id; +@@ -1372,8 +1451,10 @@ static irqreturn_t pl011_int(int irq, void *dev_id) + if (status & (UART011_DSRMIS|UART011_DCDMIS| + UART011_CTSMIS|UART011_RIMIS)) + pl011_modem_status(uap); +- if (status & UART011_TXIS) ++ if (status & UART011_TXIS) { ++ pl011_tx_irq_seen(uap); + pl011_tx_chars(uap); ++ } + + if (pass_counter-- == 0) + break; +@@ -1577,7 +1658,7 @@ static int pl011_startup(struct uart_port *port) + { + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); +- unsigned int cr, lcr_h, fbrd, ibrd; ++ unsigned int cr; + int retval; + + retval = pl011_hwinit(port); +@@ -1595,29 +1676,10 @@ static int pl011_startup(struct uart_port *port) + + writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); + +- /* +- * Provoke TX FIFO interrupt into asserting. Taking care to preserve +- * baud rate and data format specified by FBRD, IBRD and LCRH as the +- * UART may already be in use as a console. +- */ +- spin_lock_irq(&uap->port.lock); +- +- fbrd = readw(uap->port.membase + UART011_FBRD); +- ibrd = readw(uap->port.membase + UART011_IBRD); +- lcr_h = readw(uap->port.membase + uap->lcrh_rx); +- +- cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; +- writew(cr, uap->port.membase + UART011_CR); +- writew(0, uap->port.membase + UART011_FBRD); +- writew(1, uap->port.membase + UART011_IBRD); +- pl011_write_lcr_h(uap, 0); +- writew(0, uap->port.membase + UART01x_DR); +- while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) +- barrier(); ++ /* Assume that TX IRQ doesn't work until we see one: */ ++ uap->tx_irq_seen = 0; + +- writew(fbrd, uap->port.membase + UART011_FBRD); +- writew(ibrd, uap->port.membase + UART011_IBRD); +- pl011_write_lcr_h(uap, lcr_h); ++ spin_lock_irq(&uap->port.lock); + + /* restore RTS and DTR */ + cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); +@@ -1672,6 +1734,8 @@ static void pl011_shutdown(struct uart_port *port) + container_of(port, struct uart_amba_port, port); + unsigned int cr; + ++ cancel_delayed_work_sync(&uap->tx_softirq_work); ++ + /* + * disable all interrupts + */ +@@ -2218,6 +2282,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) + uap->port.ops = &amba_pl011_pops; + uap->port.flags = UPF_BOOT_AUTOCONF; + uap->port.line = i; ++ INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq); + pl011_dma_probe(&dev->dev, uap); + + /* Ensure interrupts from this UART are masked and cleared */ + +From 2820ce043829968ca725e149e5a008e3eb86b570 Mon Sep 17 00:00:00 2001 +From: Dave Martin +Date: Fri, 27 Feb 2015 15:52:31 +0000 +Subject: [PATCH 120/172] serial/amba-pl011: Leave the TX IRQ alone when the + UART is not open + +Getting the TX IRQ re-asserted from scratch can be inefficient in +some setups. + +This patch avoids clearing the TX IRQ across pl011_shutdown()... +pl011_startup(), so that if the port is closed and reopened, the +IRQ will still work afterwards without having to bootstrap it again. + +The TX IRQ continues to be masked in IMSC when the UART is not in +use. + +Signed-off-by: Dave Martin +--- + drivers/tty/serial/amba-pl011.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c +index c243729..9c6a2f4 100644 +--- a/drivers/tty/serial/amba-pl011.c ++++ b/drivers/tty/serial/amba-pl011.c +@@ -1676,9 +1676,6 @@ static int pl011_startup(struct uart_port *port) + + writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); + +- /* Assume that TX IRQ doesn't work until we see one: */ +- uap->tx_irq_seen = 0; +- + spin_lock_irq(&uap->port.lock); + + /* restore RTS and DTR */ +@@ -1742,7 +1739,7 @@ static void pl011_shutdown(struct uart_port *port) + spin_lock_irq(&uap->port.lock); + uap->im = 0; + writew(uap->im, uap->port.membase + UART011_IMSC); +- writew(0xffff, uap->port.membase + UART011_ICR); ++ writew(0xffff & ~UART011_TXIS, uap->port.membase + UART011_ICR); + spin_unlock_irq(&uap->port.lock); + + pl011_dma_shutdown(uap); + +From 8def067fc67ecc6a7023cb22af2d7e39e7af3a3d Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:09 +0100 +Subject: [PATCH 121/172] 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 815de37..ce8f420 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -106,4 +106,6 @@ source "drivers/staging/unisys/Kconfig" + + source "drivers/staging/clocking-wizard/Kconfig" + ++source "drivers/staging/fbtft/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index 33c640b..c242787 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -45,3 +45,4 @@ obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/ + obj-$(CONFIG_CRYPTO_SKEIN) += skein/ + obj-$(CONFIG_UNISYSSPAR) += unisys/ + obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/ ++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 06d51134bbb3a8c0424ff056c590f48c5c118655 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:10 +0100 +Subject: [PATCH 122/172] 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 d39ffbc96a102b600acb37c3474492efa6ec8cff Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:11 +0100 +Subject: [PATCH 123/172] 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 67c6f93bb8a6222372f8a9101f0cc251519af1cb Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:12 +0100 +Subject: [PATCH 124/172] 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 8085e50c45d7c0265dc4e964c8c97cbe6c94f0f7 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:13 +0100 +Subject: [PATCH 125/172] 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 e8dd102dd88b944666f475b2561947f014dc5322 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:14 +0100 +Subject: [PATCH 126/172] 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 ac4b97f943abb1e75ae9ce89b9a87c4c11ca7540 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:15 +0100 +Subject: [PATCH 127/172] 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 f4cd1ccd1d97e19bf697027ef2bf6fe49b7931d9 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:16 +0100 +Subject: [PATCH 128/172] 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 1fde4032c966ca64aa650d1d432f0e624dda2ef4 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:17 +0100 +Subject: [PATCH 129/172] 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 231a5ec27c7d2ef02ec3bebe2797ece490f3083e Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:18 +0100 +Subject: [PATCH 130/172] 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 4df2aaf201deb710cb086303678f90ea9f734a5e Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:19 +0100 +Subject: [PATCH 131/172] 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 514dc6a5071ade3f146f9fb20e1ed602a79858b2 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:20 +0100 +Subject: [PATCH 132/172] 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 0c2fe050a244e71f458b93795c7542f0c0f7adf9 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:21 +0100 +Subject: [PATCH 133/172] 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 0f29b5d63e6cab9d69eb1f7b18b6bd6fd79cf7bc Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:22 +0100 +Subject: [PATCH 134/172] 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 a3cb66339f091b595534af93c2e2d5439ea6eddd Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:23 +0100 +Subject: [PATCH 135/172] 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 664ff53df529fa15bbdbd95ec761b9438463ca9d Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:24 +0100 +Subject: [PATCH 136/172] 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 147010bf2cc6bcd6e415c50c9c1af9dd4e32625a Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:25 +0100 +Subject: [PATCH 137/172] 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 358b88a04cd9f842fe7ee796f366f1974f9388af Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:26 +0100 +Subject: [PATCH 138/172] 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 21e5c10651440dde2f52472e220cab45418250a2 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:27 +0100 +Subject: [PATCH 139/172] 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 c5d81394418cd5a1c03d9fb1806b487d3aeaa8c8 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:28 +0100 +Subject: [PATCH 140/172] 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 4ea4d4cde4cefeddf0de53fac33251c1e1fbef0c Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:29 +0100 +Subject: [PATCH 141/172] 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 4c95802207386b77ce4382d6da461c531b0a5233 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:30 +0100 +Subject: [PATCH 142/172] 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 bda5811957a10834fb6fff897798cb88f483df69 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:31 +0100 +Subject: [PATCH 143/172] 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 356a07e91094b2137aa065cda8109f3b311c049b Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:32 +0100 +Subject: [PATCH 144/172] 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 9b7cb18c0b0d94f9f810f51c3f1ea702041ee48a Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:33 +0100 +Subject: [PATCH 145/172] 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 fba3874e2796888b550853e6a64b38bf0dfe97f5 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:34 +0100 +Subject: [PATCH 146/172] 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 dcf965435e041238d46101633705e5b60bd448e3 Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:35 +0100 +Subject: [PATCH 147/172] 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 e6ea545ba51748ab7d35a9a66d15130f10b20cde Mon Sep 17 00:00:00 2001 +From: Thomas Petazzoni +Date: Wed, 31 Dec 2014 10:11:36 +0100 +Subject: [PATCH 148/172] 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 6cd6c52b928abddd97ed84d81dc7dc4299e4ef0b 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 149/172] 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 4db13fcabcf3976a2996aeaabaae5c14dd203506 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Fri, 23 Jan 2015 17:20:25 +0300 +Subject: [PATCH 150/172] 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 6d2e37a80dfcefcbfbe944a494bfacd7a67fb850 Mon Sep 17 00:00:00 2001 +From: Krzysztof Adamski +Date: Thu, 22 Jan 2015 19:08:58 +0100 +Subject: [PATCH 151/172] 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 beabd79f51c4211da36c358630199afc2ecc0d70 Mon Sep 17 00:00:00 2001 +From: Mauro Stettler +Date: Sun, 25 Jan 2015 20:26:17 +0900 +Subject: [PATCH 152/172] 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 7e831153b89601cab2d004a6ac0eaeb6e734a2c8 Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:33:03 +0200 +Subject: [PATCH 153/172] 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 fd28a2e66acf9bb757cb5b63aba22e6765ab441b Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:35:30 +0200 +Subject: [PATCH 154/172] 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 6f65a6510903f0c9fceb1f3d65ff28bd9a784e6c Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:37:24 +0200 +Subject: [PATCH 155/172] 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 2e22627744670a081bb431ca45bbf5cf84a2030c Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:39:56 +0200 +Subject: [PATCH 156/172] 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 3b5f096eae4c0080b6e88f6b8aaa1fffefc5a0c7 Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Tue, 27 Jan 2015 22:42:59 +0200 +Subject: [PATCH 157/172] 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 608b9170aa906a03b34017095c076df47c68b10b Mon Sep 17 00:00:00 2001 +From: Heba Aamer +Date: Wed, 28 Jan 2015 15:29:05 +0200 +Subject: [PATCH 158/172] 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 fc7a6c1b574ecf2541ba11643b4936e8b24d2b09 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 159/172] 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 bc557a5..70d9e3b 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -1027,6 +1027,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 4d703f4..1563996 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -1019,6 +1019,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 1e1f6c97e1b39e609d2c5e63db46082f5dbd1312 Mon Sep 17 00:00:00 2001 +From: Jon Burgess +Date: Tue, 17 Feb 2015 13:22:17 +0000 +Subject: [PATCH 160/172] 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 754291e..831d946 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) += 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 b06a6f1514466b593b2a533c128dc87cc8d16979 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 161/172] 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 831d946..b3b775b 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) += 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 9da9198099befac4b05083230123fd114c5d286d 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 162/172] 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 b3b775b..9d6f947 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -71,6 +71,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 44b11d19ade98ef346cb6135d5b9697deadd8b39 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 163/172] 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 9d6f947..e4b26b3 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -72,6 +72,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 9fa8ac547b9ec39fb6fcdaa4a3409aa518ffd5cc 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 164/172] 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 e4b26b3..890c789 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -78,6 +78,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 75aedead57189858c6aec1568f028d8e13445752 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 165/172] 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 4c8a8d6a18dea92a111c797d48e4b05491ec1399 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Wed, 25 Feb 2015 09:45:56 +0000 +Subject: [PATCH 166/172] 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 32765026651961cf8f67a28d224165af9adeae32 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 27 Feb 2015 15:10:24 +0000 +Subject: [PATCH 167/172] 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 890c789..7480e1c 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) += i2c-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/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 d90aba0187af45d761259e4060387821b9bfa3f4 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 168/172] 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 7480e1c..ad6984e 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -80,6 +80,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 acc9df3814ad9edf4a323c12b150123fd690f3be Mon Sep 17 00:00:00 2001 +From: Martin Sperl +Date: Mon, 2 Mar 2015 09:37:02 +0000 +Subject: [PATCH 169/172] 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 ad6984e..ed45f81 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -85,6 +85,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_BCM2835) += bcm2835-rpi-b-plus.dtb + dtb-$(CONFIG_ARCH_BCM_5301X) += \ +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 70d9e3b..d1d6b6c 100644 +--- a/arch/arm/configs/bcm2709_defconfig ++++ b/arch/arm/configs/bcm2709_defconfig +@@ -568,6 +568,7 @@ CONFIG_I2C_BCM2708=m + CONFIG_SPI=y + CONFIG_SPI_BCM2835=m + 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 1563996..044de53 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -560,6 +560,7 @@ CONFIG_I2C_BCM2708=m + CONFIG_SPI=y + CONFIG_SPI_BCM2835=m + CONFIG_SPI_BCM2708=m ++CONFIG_SPI_BCM2835=m + CONFIG_SPI_SPIDEV=y + CONFIG_PPS=m + CONFIG_PPS_CLIENT_LDISC=m + +From b27eece1cbc6981540739b849572a58ffd34aefb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sat, 7 Mar 2015 20:39:30 +0100 +Subject: [PATCH 170/172] dts: overlay: add support for MZ61581 display +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add Device Tree overlay for MZ61581 display by Tontec. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/Makefile | 1 + + arch/arm/boot/dts/mz61581-overlay.dts | 109 ++++++++++++++++++++++++++++++++++ + 2 files changed, 110 insertions(+) + create mode 100644 arch/arm/boot/dts/mz61581-overlay.dts + +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index ed45f81..f918523 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -77,6 +77,7 @@ 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 ++dtb-$(RPI_DT_OVERLAYS) += mz61581-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 +diff --git a/arch/arm/boot/dts/mz61581-overlay.dts b/arch/arm/boot/dts/mz61581-overlay.dts +new file mode 100644 +index 0000000..c06fe12 +--- /dev/null ++++ b/arch/arm/boot/dts/mz61581-overlay.dts +@@ -0,0 +1,109 @@ ++/* ++ * Device Tree overlay for MZ61581-PI-EXT 2014.12.28 by Tontec ++ * ++ */ ++ ++/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__ { ++ mz61581_pins: mz61581_pins { ++ brcm,pins = <4 15 18 25>; ++ 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>; ++ ++ mz61581: mz61581@0{ ++ compatible = "samsung,s6d02a1"; ++ reg = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mz61581_pins>; ++ ++ spi-max-frequency = <128000000>; ++ spi-cpol; ++ spi-cpha; ++ ++ width = <320>; ++ height = <480>; ++ rotate = <270>; ++ bgr; ++ fps = <30>; ++ buswidth = <8>; ++ ++ reset-gpios = <&gpio 15 0>; ++ dc-gpios = <&gpio 25 0>; ++ led-gpios = <&gpio 18 0>; ++ ++ init = <0x10000b0 00 ++ 0x1000011 ++ 0x20000ff ++ 0x10000b3 0x02 0x00 0x00 0x00 ++ 0x10000c0 0x13 0x3b 0x00 0x02 0x00 0x01 0x00 0x43 ++ 0x10000c1 0x08 0x16 0x08 0x08 ++ 0x10000c4 0x11 0x07 0x03 0x03 ++ 0x10000c6 0x00 ++ 0x10000c8 0x03 0x03 0x13 0x5c 0x03 0x07 0x14 0x08 0x00 0x21 0x08 0x14 0x07 0x53 0x0c 0x13 0x03 0x03 0x21 0x00 ++ 0x1000035 0x00 ++ 0x1000036 0xa0 ++ 0x100003a 0x55 ++ 0x1000044 0x00 0x01 ++ 0x10000d0 0x07 0x07 0x1d 0x03 ++ 0x10000d1 0x03 0x30 0x10 ++ 0x10000d2 0x03 0x14 0x04 ++ 0x1000029 ++ 0x100002c>; ++ ++ /* This is a workaround to make sure the init sequence slows down and doesn't fail */ ++ debug = <3>; ++ }; ++ ++ mz61581_ts: mz61581_ts@1 { ++ compatible = "ti,ads7846"; ++ reg = <1>; ++ ++ spi-max-frequency = <2000000>; ++ interrupts = <4 2>; /* high-to-low edge triggered */ ++ interrupt-parent = <&gpio>; ++ pendown-gpio = <&gpio 4 0>; ++ ++ ti,x-plate-ohms = /bits/ 16 <60>; ++ ti,pressure-max = /bits/ 16 <255>; ++ }; ++ }; ++ }; ++ __overrides__ { ++ speed = <&mz61581>, "spi-max-frequency:0"; ++ rotate = <&mz61581>, "rotate:0"; ++ fps = <&mz61581>, "fps:0"; ++ debug = <&mz61581>, "debug:0"; ++ xohms = <&mz61581_ts>,"ti,x-plate-ohms;0"; ++ }; ++}; + +From e5c5c9e51bb483f34f0210f0406a3cf9597f77d0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sat, 7 Mar 2015 20:40:07 +0100 +Subject: [PATCH 171/172] dts: overlay: piscreen: set speed to 24MHz +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some of the displays can't handle the 32MHz speed. +Lower the default speed to 24MHz. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/piscreen-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/piscreen-overlay.dts b/arch/arm/boot/dts/piscreen-overlay.dts +index 8cd6a95..b7fd7ea 100644 +--- a/arch/arm/boot/dts/piscreen-overlay.dts ++++ b/arch/arm/boot/dts/piscreen-overlay.dts +@@ -47,7 +47,7 @@ + pinctrl-names = "default"; + pinctrl-0 = <&piscreen_pins>; + +- spi-max-frequency = <32000000>; ++ spi-max-frequency = <24000000>; + rotate = <270>; + bgr; + fps = <30>; + +From a1c1709f994bde15ce55aac74de0dcb40761fc7b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Sat, 7 Mar 2015 20:40:43 +0100 +Subject: [PATCH 172/172] dts: overlay: rpi-display: pullup irq gpio +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +An early version of rpi-display needs the touch controller irq +to be pulled up. This is the version with 9-bit SPI as default. + +Signed-off-by: Noralf Trønnes +--- + arch/arm/boot/dts/rpi-display-overlay.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/rpi-display-overlay.dts b/arch/arm/boot/dts/rpi-display-overlay.dts +index 0578810..a8fa974 100644 +--- a/arch/arm/boot/dts/rpi-display-overlay.dts ++++ b/arch/arm/boot/dts/rpi-display-overlay.dts +@@ -30,6 +30,7 @@ + rpi_display_pins: rpi_display_pins { + brcm,pins = <18 23 24 25>; + brcm,function = <1 1 1 0>; /* out out out in */ ++ brcm,pull = <0 0 0 2>; /* - - - up */ + }; + }; + };