├── .github └── workflows │ └── stale.yml ├── .gitignore ├── Kconfig ├── Makefile ├── README ├── dts ├── overlays │ └── rpi │ │ ├── hy28a-overlay.dts │ │ ├── hy28b-overlay.dts │ │ ├── mz61581-overlay.dts │ │ ├── piscreen-overlay.dts │ │ ├── pitft28-resistive-overlay.dts │ │ ├── rpi-display-overlay.dts │ │ └── tinylcd35-overlay.dts └── rpi.dts ├── fb_agm1264k-fl.c ├── fb_bd663474.c ├── fb_hx8340bn.c ├── fb_hx8347d.c ├── fb_hx8353d.c ├── fb_ili9320.c ├── fb_ili9325.c ├── fb_ili9340.c ├── fb_ili9341.c ├── fb_ili9481.c ├── fb_ili9486.c ├── fb_pcd8544.c ├── fb_ra8875.c ├── fb_s6d02a1.c ├── fb_s6d1121.c ├── fb_ssd1289.c ├── fb_ssd1306.c ├── fb_ssd1331.c ├── fb_ssd1351.c ├── fb_st7735r.c ├── fb_tinylcd.c ├── fb_tls8204.c ├── fb_uc1701.c ├── fb_upd161704.c ├── fb_watterott.c ├── fbtft-bus.c ├── fbtft-core.c ├── fbtft-io.c ├── fbtft-sysfs.c ├── fbtft.h ├── fbtft_device.c └── flexfb.c /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Mark stale issues and pull requests 2 | 3 | on: 4 | schedule: 5 | - cron: '28 8 * * *' 6 | 7 | jobs: 8 | stale: 9 | 10 | runs-on: ubuntu-latest 11 | permissions: 12 | issues: write 13 | pull-requests: write 14 | 15 | steps: 16 | - uses: actions/stale@v3 17 | with: 18 | repo-token: ${{ secrets.GITHUB_TOKEN }} 19 | stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.' 20 | stale-pr-message: '' 21 | stale-issue-label: 'no-issue-activity' 22 | stale-pr-label: 'no-pr-activity' 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is copied from the Linux kernel sources 2 | # 3 | # NOTE! Don't add files that are generated in specific 4 | # subdirectories here. Add them in the ".gitignore" file 5 | # in that subdirectory instead. 6 | # 7 | # NOTE! Please use 'git ls-files -i --exclude-standard' 8 | # command after changing this file, to see if there are 9 | # any tracked files which get ignored after the change. 10 | # 11 | # Normal rules 12 | # 13 | .* 14 | *.o 15 | *.o.* 16 | *.a 17 | *.s 18 | *.ko 19 | *.so 20 | *.so.dbg 21 | *.mod.c 22 | *.i 23 | *.lst 24 | *.symtypes 25 | *.order 26 | modules.builtin 27 | *.elf 28 | *.bin 29 | *.gz 30 | *.bz2 31 | *.lzma 32 | *.xz 33 | *.lzo 34 | *.patch 35 | *.gcno 36 | 37 | # 38 | # Top-level generic files 39 | # 40 | /tags 41 | /TAGS 42 | /linux 43 | /vmlinux 44 | /vmlinuz 45 | /System.map 46 | /Module.markers 47 | /Module.symvers 48 | 49 | # 50 | # Debian directory (make deb-pkg) 51 | # 52 | /debian/ 53 | 54 | # 55 | # git files that we don't want to ignore even it they are dot-files 56 | # 57 | !.gitignore 58 | !.mailmap 59 | 60 | # 61 | # Generated include files 62 | # 63 | include/config 64 | include/linux/version.h 65 | include/generated 66 | arch/*/include/generated 67 | 68 | # stgit generated dirs 69 | patches-* 70 | 71 | # quilt's files 72 | patches 73 | series 74 | 75 | # cscope files 76 | cscope.* 77 | ncscope.* 78 | 79 | # gnu global files 80 | GPATH 81 | GRTAGS 82 | GSYMS 83 | GTAGS 84 | 85 | *.orig 86 | *~ 87 | \#*# 88 | -------------------------------------------------------------------------------- /Kconfig: -------------------------------------------------------------------------------- 1 | menuconfig FB_TFT 2 | tristate "Support for small TFT LCD display modules" 3 | depends on FB && SPI && GPIOLIB 4 | select FB_SYS_FILLRECT 5 | select FB_SYS_COPYAREA 6 | select FB_SYS_IMAGEBLIT 7 | select FB_SYS_FOPS 8 | select FB_DEFERRED_IO 9 | select FB_BACKLIGHT 10 | 11 | config FB_TFT_AGM1264K_FL 12 | tristate "FB driver for the AGM1264K-FL LCD display" 13 | depends on FB_TFT 14 | help 15 | Framebuffer support for the AGM1264K-FL LCD display (two Samsung KS0108 compatable chips) 16 | 17 | config FB_TFT_BD663474 18 | tristate "FB driver for the BD663474 LCD Controller" 19 | depends on FB_TFT 20 | help 21 | Generic Framebuffer support for BD663474 22 | 23 | config FB_TFT_HX8340BN 24 | tristate "FB driver for the HX8340BN LCD Controller" 25 | depends on FB_TFT 26 | help 27 | Generic Framebuffer support for HX8340BN 28 | 29 | config FB_TFT_HX8347D 30 | tristate "FB driver for the HX8347D LCD Controller" 31 | depends on FB_TFT 32 | help 33 | Generic Framebuffer support for HX8347D 34 | 35 | config FB_TFT_HX8353D 36 | tristate "FB driver for the HX8353D LCD Controller" 37 | depends on FB_TFT 38 | help 39 | Generic Framebuffer support for HX8353D 40 | 41 | config FB_TFT_ILI9320 42 | tristate "FB driver for the ILI9320 LCD Controller" 43 | depends on FB_TFT 44 | help 45 | Generic Framebuffer support for ILI9320 46 | 47 | config FB_TFT_ILI9325 48 | tristate "FB driver for the ILI9325 LCD Controller" 49 | depends on FB_TFT 50 | help 51 | Generic Framebuffer support for ILI9325 52 | 53 | config FB_TFT_ILI9340 54 | tristate "FB driver for the ILI9340 LCD Controller" 55 | depends on FB_TFT 56 | help 57 | Generic Framebuffer support for ILI9340 58 | 59 | config FB_TFT_ILI9341 60 | tristate "FB driver for the ILI9341 LCD Controller" 61 | depends on FB_TFT 62 | help 63 | Generic Framebuffer support for ILI9341 64 | 65 | config FB_TFT_ILI9481 66 | tristate "FB driver for the ILI9481 LCD Controller" 67 | depends on FB_TFT 68 | help 69 | Generic Framebuffer support for ILI9481 70 | 71 | config FB_TFT_ILI9486 72 | tristate "FB driver for the ILI9486 LCD Controller" 73 | depends on FB_TFT 74 | help 75 | Generic Framebuffer support for ILI9486 76 | 77 | config FB_TFT_PCD8544 78 | tristate "FB driver for the PCD8544 LCD Controller" 79 | depends on FB_TFT 80 | help 81 | Generic Framebuffer support for PCD8544 82 | 83 | config FB_TFT_RA8875 84 | tristate "FB driver for the RA8875 LCD Controller" 85 | depends on FB_TFT 86 | help 87 | Generic Framebuffer support for RA8875 88 | 89 | config FB_TFT_S6D02A1 90 | tristate "FB driver for the S6D02A1 LCD Controller" 91 | depends on FB_TFT 92 | help 93 | Generic Framebuffer support for S6D02A1 94 | 95 | config FB_TFT_S6D1121 96 | tristate "FB driver for the S6D1211 LCD Controller" 97 | depends on FB_TFT 98 | help 99 | Generic Framebuffer support for S6D1121 100 | 101 | config FB_TFT_SSD1289 102 | tristate "FB driver for the SSD1289 LCD Controller" 103 | depends on FB_TFT 104 | help 105 | Framebuffer support for SSD1289 106 | 107 | config FB_TFT_SSD1306 108 | tristate "FB driver for the SSD1306 OLED Controller" 109 | depends on FB_TFT 110 | help 111 | Framebuffer support for SSD1306 112 | 113 | config FB_TFT_SSD1331 114 | tristate "FB driver for the SSD1331 LCD Controller" 115 | depends on FB_TFT 116 | help 117 | Framebuffer support for SSD1331 118 | 119 | config FB_TFT_SSD1351 120 | tristate "FB driver for the SSD1351 LCD Controller" 121 | depends on FB_TFT 122 | help 123 | Framebuffer support for SSD1351 124 | 125 | config FB_TFT_ST7735R 126 | tristate "FB driver for the ST7735R LCD Controller" 127 | depends on FB_TFT 128 | help 129 | Generic Framebuffer support for ST7735R 130 | 131 | config FB_TFT_TINYLCD 132 | tristate "FB driver for tinylcd.com display" 133 | depends on FB_TFT 134 | help 135 | Custom Framebuffer support for tinylcd.com display 136 | 137 | config FB_TFT_TLS8204 138 | tristate "FB driver for the TLS8204 LCD Controller" 139 | depends on FB_TFT 140 | help 141 | Generic Framebuffer support for TLS8204 142 | 143 | config FB_TFT_UC1701 144 | tristate "FB driver for the UC1701 LCD Controller" 145 | depends on FB_TFT 146 | help 147 | Generic Framebuffer support for UC1701 148 | 149 | config FB_TFT_UPD161704 150 | tristate "FB driver for the uPD161704 LCD Controller" 151 | depends on FB_TFT 152 | help 153 | Generic Framebuffer support for uPD161704 154 | 155 | config FB_TFT_WATTEROTT 156 | tristate "FB driver for the WATTEROTT LCD Controller" 157 | depends on FB_TFT 158 | help 159 | Generic Framebuffer support for WATTEROTT 160 | 161 | config FB_FLEX 162 | tristate "Generic FB driver for TFT LCD displays" 163 | depends on FB_TFT 164 | help 165 | Generic Framebuffer support for TFT LCD displays. 166 | 167 | config FB_TFT_FBTFT_DEVICE 168 | tristate "Module to for adding FBTFT devices" 169 | depends on FB_TFT 170 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # kbuild part of makefile 3 | 4 | # Optionally, include config file to allow out of tree kernel modules build 5 | -include $(src)/.config 6 | 7 | # Core module 8 | obj-$(CONFIG_FB_TFT) += fbtft.o 9 | fbtft-y += fbtft-core.o fbtft-sysfs.o fbtft-bus.o fbtft-io.o 10 | 11 | # drivers 12 | obj-$(CONFIG_FB_TFT_AGM1264K_FL) += fb_agm1264k-fl.o 13 | obj-$(CONFIG_FB_TFT_BD663474) += fb_bd663474.o 14 | obj-$(CONFIG_FB_TFT_HX8340BN) += fb_hx8340bn.o 15 | obj-$(CONFIG_FB_TFT_HX8347D) += fb_hx8347d.o 16 | obj-$(CONFIG_FB_TFT_HX8353D) += fb_hx8353d.o 17 | obj-$(CONFIG_FB_TFT_ILI9320) += fb_ili9320.o 18 | obj-$(CONFIG_FB_TFT_ILI9325) += fb_ili9325.o 19 | obj-$(CONFIG_FB_TFT_ILI9340) += fb_ili9340.o 20 | obj-$(CONFIG_FB_TFT_ILI9341) += fb_ili9341.o 21 | obj-$(CONFIG_FB_TFT_ILI9481) += fb_ili9481.o 22 | obj-$(CONFIG_FB_TFT_ILI9486) += fb_ili9486.o 23 | obj-$(CONFIG_FB_TFT_PCD8544) += fb_pcd8544.o 24 | obj-$(CONFIG_FB_TFT_RA8875) += fb_ra8875.o 25 | obj-$(CONFIG_FB_TFT_S6D02A1) += fb_s6d02a1.o 26 | obj-$(CONFIG_FB_TFT_S6D1121) += fb_s6d1121.o 27 | obj-$(CONFIG_FB_TFT_SSD1289) += fb_ssd1289.o 28 | obj-$(CONFIG_FB_TFT_SSD1306) += fb_ssd1306.o 29 | obj-$(CONFIG_FB_TFT_SSD1331) += fb_ssd1331.o 30 | obj-$(CONFIG_FB_TFT_SSD1351) += fb_ssd1351.o 31 | obj-$(CONFIG_FB_TFT_ST7735R) += fb_st7735r.o 32 | obj-$(CONFIG_FB_TFT_TINYLCD) += fb_tinylcd.o 33 | obj-$(CONFIG_FB_TFT_TLS8204) += fb_tls8204.o 34 | obj-$(CONFIG_FB_TFT_UC1701) += fb_uc1701.o 35 | obj-$(CONFIG_FB_TFT_UPD161704) += fb_upd161704.o 36 | obj-$(CONFIG_FB_TFT_WATTEROTT) += fb_watterott.o 37 | obj-$(CONFIG_FB_FLEX) += flexfb.o 38 | 39 | # Device modules 40 | obj-$(CONFIG_FB_TFT_FBTFT_DEVICE) += fbtft_device.o 41 | 42 | else 43 | # normal makefile 44 | KDIR ?= /lib/modules/`uname -r`/build 45 | 46 | default: .config 47 | $(MAKE) -C $(KDIR) M=$$PWD modules 48 | 49 | .config: 50 | grep config Kconfig | cut -d' ' -f2 | sed 's@^@CONFIG_@; s@$$@=m@' > .config 51 | 52 | install: 53 | $(MAKE) -C $(KDIR) M=$$PWD modules_install 54 | 55 | 56 | clean: 57 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions \ 58 | modules.order Module.symvers 59 | 60 | endif 61 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | FBTFT 2 | ========= 3 | 4 | 2015-01-19 5 | The FBTFT drivers are now in the Linux kernel staging tree: https://git.kernel.org/cgit/linux/kernel/git/gregkh/staging.git/tree/drivers/staging/fbtft?h=staging-testing 6 | Development in this github repo has ceased. 7 | 8 | 9 | Linux Framebuffer drivers for small TFT LCD display modules. 10 | The module 'fbtft' makes writing drivers for some of these displays very easy. 11 | 12 | Development is done on a Raspberry Pi running the Raspbian "wheezy" distribution. 13 | 14 | INSTALLATION 15 | Download kernel sources 16 | 17 | From Linux 3.15 18 | cd drivers/video/fbdev 19 | git clone https://github.com/notro/fbtft.git 20 | 21 | Add to drivers/video/fbdev/Kconfig: source "drivers/video/fbdev/fbtft/Kconfig" 22 | Add to drivers/video/fbdev/Makefile: obj-y += fbtft/ 23 | 24 | Before Linux 3.15 25 | cd drivers/video 26 | git clone https://github.com/notro/fbtft.git 27 | 28 | Add to drivers/video/Kconfig: source "drivers/video/fbtft/Kconfig" 29 | Add to drivers/video/Makefile: obj-y += fbtft/ 30 | 31 | Enable driver(s) in menuconfig and build the kernel 32 | 33 | 34 | See wiki for more information: https://github.com/notro/fbtft/wiki 35 | 36 | 37 | Source: https://github.com/notro/fbtft/ 38 | -------------------------------------------------------------------------------- /dts/overlays/rpi/hy28a-overlay.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Device Tree overlay for HY28A display shield by Texy 3 | * 4 | */ 5 | 6 | /dts-v1/; 7 | /plugin/; 8 | 9 | / { 10 | compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; 11 | 12 | fragment@0 { 13 | target = <&spi0>; 14 | __overlay__ { 15 | status = "okay"; 16 | 17 | spidev@0{ 18 | status = "disabled"; 19 | }; 20 | 21 | spidev@1{ 22 | status = "disabled"; 23 | }; 24 | }; 25 | }; 26 | 27 | fragment@1 { 28 | target = <&gpio>; 29 | __overlay__ { 30 | hy28a_pins: hy28a_pins { 31 | brcm,pins = <17 25 18>; 32 | brcm,function = <0 1 1>; /* in out out */ 33 | }; 34 | }; 35 | }; 36 | 37 | fragment@2 { 38 | target = <&spi0>; 39 | __overlay__ { 40 | /* needed to avoid dtc warning */ 41 | #address-cells = <1>; 42 | #size-cells = <0>; 43 | 44 | hy28a: hy28a@0{ 45 | compatible = "ilitek,ili9320"; 46 | reg = <0>; 47 | pinctrl-names = "default"; 48 | pinctrl-0 = <&hy28a_pins>; 49 | 50 | spi-max-frequency = <32000000>; 51 | spi-cpol; 52 | spi-cpha; 53 | rotate = <270>; 54 | bgr; 55 | fps = <50>; 56 | buswidth = <8>; 57 | startbyte = <0x70>; 58 | reset-gpios = <&gpio 25 0>; 59 | led-gpios = <&gpio 18 1>; 60 | debug = <0>; 61 | }; 62 | 63 | hy28a_ts: hy28a-ts@1 { 64 | compatible = "ti,ads7846"; 65 | reg = <1>; 66 | 67 | spi-max-frequency = <2000000>; 68 | interrupts = <17 2>; /* high-to-low edge triggered */ 69 | interrupt-parent = <&gpio>; 70 | pendown-gpio = <&gpio 17 0>; 71 | ti,x-plate-ohms = /bits/ 16 <100>; 72 | ti,pressure-max = /bits/ 16 <255>; 73 | }; 74 | }; 75 | }; 76 | __overrides__ { 77 | speed = <&hy28a>,"spi-max-frequency:0"; 78 | rotate = <&hy28a>,"rotate:0"; 79 | fps = <&hy28a>,"fps:0"; 80 | debug = <&hy28a>,"debug:0"; 81 | xohms = <&hy28a_ts>,"ti,x-plate-ohms;0"; 82 | resetgpio = <&hy28a>,"reset-gpios:4", 83 | <&hy28a_pins>, "brcm,pins:1"; 84 | ledgpio = <&hy28a>,"led-gpios:4", 85 | <&hy28a_pins>, "brcm,pins:2"; 86 | }; 87 | }; 88 | -------------------------------------------------------------------------------- /dts/overlays/rpi/hy28b-overlay.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Device Tree overlay for HY28b display shield by Texy 3 | * 4 | */ 5 | 6 | /dts-v1/; 7 | /plugin/; 8 | 9 | / { 10 | compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; 11 | 12 | fragment@0 { 13 | target = <&spi0>; 14 | __overlay__ { 15 | status = "okay"; 16 | 17 | spidev@0{ 18 | status = "disabled"; 19 | }; 20 | 21 | spidev@1{ 22 | status = "disabled"; 23 | }; 24 | }; 25 | }; 26 | 27 | fragment@1 { 28 | target = <&gpio>; 29 | __overlay__ { 30 | hy28b_pins: hy28b_pins { 31 | brcm,pins = <17 25 18>; 32 | brcm,function = <0 1 1>; /* in out out */ 33 | }; 34 | }; 35 | }; 36 | 37 | fragment@2 { 38 | target = <&spi0>; 39 | __overlay__ { 40 | /* needed to avoid dtc warning */ 41 | #address-cells = <1>; 42 | #size-cells = <0>; 43 | 44 | hy28b: hy28b@0{ 45 | compatible = "ilitek,ili9325"; 46 | reg = <0>; 47 | pinctrl-names = "default"; 48 | pinctrl-0 = <&hy28b_pins>; 49 | 50 | spi-max-frequency = <48000000>; 51 | spi-cpol; 52 | spi-cpha; 53 | rotate = <270>; 54 | bgr; 55 | fps = <50>; 56 | buswidth = <8>; 57 | startbyte = <0x70>; 58 | reset-gpios = <&gpio 25 0>; 59 | led-gpios = <&gpio 18 1>; 60 | 61 | gamma = "04 1F 4 7 7 0 7 7 6 0\n0F 00 1 7 4 0 0 0 6 7"; 62 | 63 | init = <0x10000e7 0x0010 64 | 0x1000000 0x0001 65 | 0x1000001 0x0100 66 | 0x1000002 0x0700 67 | 0x1000003 0x1030 68 | 0x1000004 0x0000 69 | 0x1000008 0x0207 70 | 0x1000009 0x0000 71 | 0x100000a 0x0000 72 | 0x100000c 0x0001 73 | 0x100000d 0x0000 74 | 0x100000f 0x0000 75 | 0x1000010 0x0000 76 | 0x1000011 0x0007 77 | 0x1000012 0x0000 78 | 0x1000013 0x0000 79 | 0x2000032 80 | 0x1000010 0x1590 81 | 0x1000011 0x0227 82 | 0x2000032 83 | 0x1000012 0x009c 84 | 0x2000032 85 | 0x1000013 0x1900 86 | 0x1000029 0x0023 87 | 0x100002b 0x000e 88 | 0x2000032 89 | 0x1000020 0x0000 90 | 0x1000021 0x0000 91 | 0x2000032 92 | 0x1000050 0x0000 93 | 0x1000051 0x00ef 94 | 0x1000052 0x0000 95 | 0x1000053 0x013f 96 | 0x1000060 0xa700 97 | 0x1000061 0x0001 98 | 0x100006a 0x0000 99 | 0x1000080 0x0000 100 | 0x1000081 0x0000 101 | 0x1000082 0x0000 102 | 0x1000083 0x0000 103 | 0x1000084 0x0000 104 | 0x1000085 0x0000 105 | 0x1000090 0x0010 106 | 0x1000092 0x0000 107 | 0x1000093 0x0003 108 | 0x1000095 0x0110 109 | 0x1000097 0x0000 110 | 0x1000098 0x0000 111 | 0x1000007 0x0133 112 | 0x1000020 0x0000 113 | 0x1000021 0x0000 114 | 0x2000064>; 115 | debug = <0>; 116 | }; 117 | 118 | hy28b_ts: hy28b-ts@1 { 119 | compatible = "ti,ads7846"; 120 | reg = <1>; 121 | 122 | spi-max-frequency = <2000000>; 123 | interrupts = <17 2>; /* high-to-low edge triggered */ 124 | interrupt-parent = <&gpio>; 125 | pendown-gpio = <&gpio 17 0>; 126 | ti,x-plate-ohms = /bits/ 16 <100>; 127 | ti,pressure-max = /bits/ 16 <255>; 128 | }; 129 | }; 130 | }; 131 | __overrides__ { 132 | speed = <&hy28b>,"spi-max-frequency:0"; 133 | rotate = <&hy28b>,"rotate:0"; 134 | fps = <&hy28b>,"fps:0"; 135 | debug = <&hy28b>,"debug:0"; 136 | xohms = <&hy28b_ts>,"ti,x-plate-ohms;0"; 137 | resetgpio = <&hy28b>,"reset-gpios:4", 138 | <&hy28b_pins>, "brcm,pins:1"; 139 | ledgpio = <&hy28b>,"led-gpios:4", 140 | <&hy28b_pins>, "brcm,pins:2"; 141 | }; 142 | }; 143 | -------------------------------------------------------------------------------- /dts/overlays/rpi/mz61581-overlay.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Device Tree overlay for MZ61581-PI-EXT 2014.12.28 by Tontec 3 | * 4 | */ 5 | 6 | /dts-v1/; 7 | /plugin/; 8 | 9 | / { 10 | compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; 11 | 12 | fragment@0 { 13 | target = <&spi0>; 14 | __overlay__ { 15 | status = "okay"; 16 | 17 | spidev@0{ 18 | status = "disabled"; 19 | }; 20 | 21 | spidev@1{ 22 | status = "disabled"; 23 | }; 24 | }; 25 | }; 26 | 27 | fragment@1 { 28 | target = <&gpio>; 29 | __overlay__ { 30 | mz61581_pins: mz61581_pins { 31 | brcm,pins = <4 15 18 25>; 32 | brcm,function = <0 1 1 1>; /* in out out out */ 33 | }; 34 | }; 35 | }; 36 | 37 | fragment@2 { 38 | target = <&spi0>; 39 | __overlay__ { 40 | /* needed to avoid dtc warning */ 41 | #address-cells = <1>; 42 | #size-cells = <0>; 43 | 44 | mz61581: mz61581@0{ 45 | compatible = "samsung,s6d02a1"; 46 | reg = <0>; 47 | pinctrl-names = "default"; 48 | pinctrl-0 = <&mz61581_pins>; 49 | 50 | spi-max-frequency = <128000000>; 51 | spi-cpol; 52 | spi-cpha; 53 | 54 | width = <320>; 55 | height = <480>; 56 | rotate = <270>; 57 | bgr; 58 | fps = <30>; 59 | buswidth = <8>; 60 | 61 | reset-gpios = <&gpio 15 0>; 62 | dc-gpios = <&gpio 25 0>; 63 | led-gpios = <&gpio 18 0>; 64 | 65 | init = <0x10000b0 00 66 | 0x1000011 67 | 0x20000ff 68 | 0x10000b3 0x02 0x00 0x00 0x00 69 | 0x10000c0 0x13 0x3b 0x00 0x02 0x00 0x01 0x00 0x43 70 | 0x10000c1 0x08 0x16 0x08 0x08 71 | 0x10000c4 0x11 0x07 0x03 0x03 72 | 0x10000c6 0x00 73 | 0x10000c8 0x03 0x03 0x13 0x5c 0x03 0x07 0x14 0x08 0x00 0x21 0x08 0x14 0x07 0x53 0x0c 0x13 0x03 0x03 0x21 0x00 74 | 0x1000035 0x00 75 | 0x1000036 0xa0 76 | 0x100003a 0x55 77 | 0x1000044 0x00 0x01 78 | 0x10000d0 0x07 0x07 0x1d 0x03 79 | 0x10000d1 0x03 0x30 0x10 80 | 0x10000d2 0x03 0x14 0x04 81 | 0x1000029 82 | 0x100002c>; 83 | 84 | /* This is a workaround to make sure the init sequence slows down and doesn't fail */ 85 | debug = <3>; 86 | }; 87 | 88 | mz61581_ts: mz61581_ts@1 { 89 | compatible = "ti,ads7846"; 90 | reg = <1>; 91 | 92 | spi-max-frequency = <2000000>; 93 | interrupts = <4 2>; /* high-to-low edge triggered */ 94 | interrupt-parent = <&gpio>; 95 | pendown-gpio = <&gpio 4 0>; 96 | 97 | ti,x-plate-ohms = /bits/ 16 <60>; 98 | ti,pressure-max = /bits/ 16 <255>; 99 | }; 100 | }; 101 | }; 102 | __overrides__ { 103 | speed = <&mz61581>, "spi-max-frequency:0"; 104 | rotate = <&mz61581>, "rotate:0"; 105 | fps = <&mz61581>, "fps:0"; 106 | debug = <&mz61581>, "debug:0"; 107 | xohms = <&mz61581_ts>,"ti,x-plate-ohms;0"; 108 | }; 109 | }; 110 | -------------------------------------------------------------------------------- /dts/overlays/rpi/piscreen-overlay.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Device Tree overlay for PiScreen 3.5" display shield by Ozzmaker 3 | * 4 | */ 5 | 6 | /dts-v1/; 7 | /plugin/; 8 | 9 | / { 10 | compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; 11 | 12 | fragment@0 { 13 | target = <&spi0>; 14 | __overlay__ { 15 | status = "okay"; 16 | 17 | spidev@0{ 18 | status = "disabled"; 19 | }; 20 | 21 | spidev@1{ 22 | status = "disabled"; 23 | }; 24 | }; 25 | }; 26 | 27 | fragment@1 { 28 | target = <&gpio>; 29 | __overlay__ { 30 | piscreen_pins: piscreen_pins { 31 | brcm,pins = <17 25 24 22>; 32 | brcm,function = <0 1 1 1>; /* in out out out */ 33 | }; 34 | }; 35 | }; 36 | 37 | fragment@2 { 38 | target = <&spi0>; 39 | __overlay__ { 40 | /* needed to avoid dtc warning */ 41 | #address-cells = <1>; 42 | #size-cells = <0>; 43 | 44 | piscreen: piscreen@0{ 45 | compatible = "ilitek,ili9486"; 46 | reg = <0>; 47 | pinctrl-names = "default"; 48 | pinctrl-0 = <&piscreen_pins>; 49 | 50 | spi-max-frequency = <32000000>; 51 | rotate = <270>; 52 | bgr; 53 | fps = <30>; 54 | buswidth = <8>; 55 | regwidth = <16>; 56 | reset-gpios = <&gpio 25 0>; 57 | dc-gpios = <&gpio 24 0>; 58 | led-gpios = <&gpio 22 1>; 59 | debug = <0>; 60 | 61 | init = <0x10000b0 0x00 62 | 0x1000011 63 | 0x20000ff 64 | 0x100003a 0x55 65 | 0x1000036 0x28 66 | 0x10000c2 0x44 67 | 0x10000c5 0x00 0x00 0x00 0x00 68 | 0x10000e0 0x0f 0x1f 0x1c 0x0c 0x0f 0x08 0x48 0x98 0x37 0x0a 0x13 0x04 0x11 0x0d 0x00 69 | 0x10000e1 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 70 | 0x10000e2 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 71 | 0x1000011 72 | 0x1000029>; 73 | }; 74 | 75 | piscreen-ts@1 { 76 | compatible = "ti,ads7846"; 77 | reg = <1>; 78 | 79 | spi-max-frequency = <2000000>; 80 | interrupts = <17 2>; /* high-to-low edge triggered */ 81 | interrupt-parent = <&gpio>; 82 | pendown-gpio = <&gpio 17 0>; 83 | ti,x-plate-ohms = /bits/ 16 <100>; 84 | ti,pressure-max = /bits/ 16 <255>; 85 | }; 86 | }; 87 | }; 88 | __overrides__ { 89 | speed = <&piscreen>,"spi-max-frequency:0"; 90 | rotate = <&piscreen>,"rotate:0"; 91 | fps = <&piscreen>,"fps:0"; 92 | debug = <&piscreen>,"debug:0"; 93 | }; 94 | }; 95 | -------------------------------------------------------------------------------- /dts/overlays/rpi/pitft28-resistive-overlay.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Device Tree overlay for pitft resistive by Adafruit 3 | * 4 | */ 5 | 6 | /dts-v1/; 7 | /plugin/; 8 | 9 | / { 10 | compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; 11 | 12 | fragment@0 { 13 | target = <&spi0>; 14 | __overlay__ { 15 | status = "okay"; 16 | 17 | spidev@0{ 18 | status = "disabled"; 19 | }; 20 | 21 | spidev@1{ 22 | status = "disabled"; 23 | }; 24 | }; 25 | }; 26 | 27 | fragment@1 { 28 | target = <&gpio>; 29 | __overlay__ { 30 | pitft_pins: pitft_pins { 31 | brcm,pins = <24 25>; 32 | brcm,function = <0 1>; /* in out */ 33 | brcm,pull = <2 0>; /* pullup none */ 34 | }; 35 | }; 36 | }; 37 | 38 | fragment@2 { 39 | target = <&spi0>; 40 | __overlay__ { 41 | /* needed to avoid dtc warning */ 42 | #address-cells = <1>; 43 | #size-cells = <0>; 44 | 45 | pitft: pitft@0{ 46 | compatible = "ilitek,ili9340"; 47 | reg = <0>; 48 | pinctrl-names = "default"; 49 | pinctrl-0 = <&pitft_pins>; 50 | 51 | spi-max-frequency = <16000000>; 52 | rotate = <90>; 53 | fps = <25>; 54 | bgr; 55 | buswidth = <8>; 56 | dc-gpios = <&gpio 25 0>; 57 | debug = <0>; 58 | }; 59 | 60 | pitft_ts@1 { 61 | #address-cells = <1>; 62 | #size-cells = <0>; 63 | compatible = "st,stmpe610"; 64 | reg = <1>; 65 | 66 | spi-max-frequency = <500000>; 67 | irq-gpio = <&gpio 24 0x2>; /* IRQF_TRIGGER_FALLING */ 68 | interrupts = <24 2>; /* high-to-low edge triggered */ 69 | interrupt-parent = <&gpio>; 70 | interrupt-controller; 71 | 72 | stmpe_touchscreen { 73 | compatible = "st,stmpe-ts"; 74 | st,sample-time = <4>; 75 | st,mod-12b = <1>; 76 | st,ref-sel = <0>; 77 | st,adc-freq = <2>; 78 | st,ave-ctrl = <3>; 79 | st,touch-det-delay = <4>; 80 | st,settling = <2>; 81 | st,fraction-z = <7>; 82 | st,i-drive = <0>; 83 | }; 84 | 85 | stmpe_gpio: stmpe_gpio { 86 | #gpio-cells = <2>; 87 | compatible = "st,stmpe-gpio"; 88 | /* 89 | * only GPIO2 is wired/available 90 | * and it is wired to the backlight 91 | */ 92 | st,norequest-mask = <0x7b>; 93 | }; 94 | }; 95 | }; 96 | }; 97 | 98 | fragment@3 { 99 | target-path = "/soc"; 100 | __overlay__ { 101 | backlight { 102 | compatible = "gpio-backlight"; 103 | gpios = <&stmpe_gpio 2 0>; 104 | default-on; 105 | }; 106 | }; 107 | }; 108 | 109 | __overrides__ { 110 | speed = <&pitft>,"spi-max-frequency:0"; 111 | rotate = <&pitft>,"rotate:0"; 112 | fps = <&pitft>,"fps:0"; 113 | debug = <&pitft>,"debug:0"; 114 | }; 115 | }; 116 | -------------------------------------------------------------------------------- /dts/overlays/rpi/rpi-display-overlay.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Device Tree overlay for rpi-display by Watterott 3 | * 4 | */ 5 | 6 | /dts-v1/; 7 | /plugin/; 8 | 9 | / { 10 | compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; 11 | 12 | fragment@0 { 13 | target = <&spi0>; 14 | __overlay__ { 15 | status = "okay"; 16 | 17 | spidev@0{ 18 | status = "disabled"; 19 | }; 20 | 21 | spidev@1{ 22 | status = "disabled"; 23 | }; 24 | }; 25 | }; 26 | 27 | fragment@1 { 28 | target = <&gpio>; 29 | __overlay__ { 30 | rpi_display_pins: rpi_display_pins { 31 | brcm,pins = <18 23 24 25>; 32 | brcm,function = <1 1 1 0>; /* out out out in */ 33 | }; 34 | }; 35 | }; 36 | 37 | fragment@2 { 38 | target = <&spi0>; 39 | __overlay__ { 40 | /* needed to avoid dtc warning */ 41 | #address-cells = <1>; 42 | #size-cells = <0>; 43 | 44 | rpidisplay: rpi-display@0{ 45 | compatible = "ilitek,ili9341"; 46 | reg = <0>; 47 | pinctrl-names = "default"; 48 | pinctrl-0 = <&rpi_display_pins>; 49 | 50 | spi-max-frequency = <32000000>; 51 | rotate = <270>; 52 | bgr; 53 | fps = <30>; 54 | buswidth = <8>; 55 | reset-gpios = <&gpio 23 0>; 56 | dc-gpios = <&gpio 24 0>; 57 | led-gpios = <&gpio 18 1>; 58 | debug = <0>; 59 | }; 60 | 61 | rpidisplay_ts: rpi-display-ts@1 { 62 | compatible = "ti,ads7846"; 63 | reg = <1>; 64 | 65 | spi-max-frequency = <2000000>; 66 | interrupts = <25 2>; /* high-to-low edge triggered */ 67 | interrupt-parent = <&gpio>; 68 | pendown-gpio = <&gpio 25 0>; 69 | ti,x-plate-ohms = /bits/ 16 <60>; 70 | ti,pressure-max = /bits/ 16 <255>; 71 | }; 72 | }; 73 | }; 74 | __overrides__ { 75 | speed = <&rpidisplay>,"spi-max-frequency:0"; 76 | rotate = <&rpidisplay>,"rotate:0"; 77 | fps = <&rpidisplay>,"fps:0"; 78 | debug = <&rpidisplay>,"debug:0"; 79 | xohms = <&rpidisplay_ts>,"ti,x-plate-ohms;0"; 80 | }; 81 | }; 82 | -------------------------------------------------------------------------------- /dts/overlays/rpi/tinylcd35-overlay.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * tinylcd 3.5" display 3 | * 4 | */ 5 | 6 | /dts-v1/; 7 | /plugin/; 8 | 9 | / { 10 | compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; 11 | 12 | fragment@0 { 13 | target = <&spi0>; 14 | __overlay__ { 15 | status = "okay"; 16 | 17 | spidev@0{ 18 | status = "disabled"; 19 | }; 20 | 21 | spidev@1{ 22 | status = "disabled"; 23 | }; 24 | }; 25 | }; 26 | 27 | fragment@1 { 28 | target = <&gpio>; 29 | __overlay__ { 30 | tinylcd35_pins: tinylcd35_pins { 31 | brcm,pins = <25 24 18>; 32 | brcm,function = <1>; /* out */ 33 | }; 34 | tinylcd35_ts_pins: tinylcd35_ts_pins { 35 | brcm,pins = <5>; 36 | brcm,function = <0>; /* in */ 37 | }; 38 | keypad_pins: keypad_pins { 39 | brcm,pins = <4 17 22 23 27>; 40 | brcm,function = <0>; /* in */ 41 | brcm,pull = <1>; /* down */ 42 | }; 43 | }; 44 | }; 45 | 46 | fragment@2 { 47 | target = <&spi0>; 48 | __overlay__ { 49 | /* needed to avoid dtc warning */ 50 | #address-cells = <1>; 51 | #size-cells = <0>; 52 | 53 | tinylcd35: tinylcd35@0{ 54 | compatible = "neosec,tinylcd"; 55 | reg = <0>; 56 | pinctrl-names = "default"; 57 | pinctrl-0 = <&tinylcd35_pins>, 58 | <&tinylcd35_ts_pins>; 59 | 60 | spi-max-frequency = <48000000>; 61 | rotate = <270>; 62 | fps = <20>; 63 | bgr; 64 | buswidth = <8>; 65 | reset-gpios = <&gpio 25 0>; 66 | dc-gpios = <&gpio 24 0>; 67 | led-gpios = <&gpio 18 1>; 68 | debug = <0>; 69 | 70 | init = <0x10000B0 0x80 71 | 0x10000C0 0x0A 0x0A 72 | 0x10000C1 0x01 0x01 73 | 0x10000C2 0x33 74 | 0x10000C5 0x00 0x42 0x80 75 | 0x10000B1 0xD0 0x11 76 | 0x10000B4 0x02 77 | 0x10000B6 0x00 0x22 0x3B 78 | 0x10000B7 0x07 79 | 0x1000036 0x58 80 | 0x10000F0 0x36 0xA5 0xD3 81 | 0x10000E5 0x80 82 | 0x10000E5 0x01 83 | 0x10000B3 0x00 84 | 0x10000E5 0x00 85 | 0x10000F0 0x36 0xA5 0x53 86 | 0x10000E0 0x00 0x35 0x33 0x00 0x00 0x00 0x00 0x35 0x33 0x00 0x00 0x00 87 | 0x100003A 0x55 88 | 0x1000011 89 | 0x2000001 90 | 0x1000029>; 91 | }; 92 | 93 | tinylcd35_ts: tinylcd35_ts@1 { 94 | compatible = "ti,ads7846"; 95 | reg = <1>; 96 | status = "disabled"; 97 | 98 | spi-max-frequency = <2000000>; 99 | interrupts = <5 2>; /* high-to-low edge triggered */ 100 | interrupt-parent = <&gpio>; 101 | pendown-gpio = <&gpio 5 0>; 102 | ti,x-plate-ohms = /bits/ 16 <100>; 103 | ti,pressure-max = /bits/ 16 <255>; 104 | }; 105 | }; 106 | }; 107 | 108 | fragment@3 { 109 | target = <&i2c1>; 110 | __overlay__ { 111 | #address-cells = <1>; 112 | #size-cells = <0>; 113 | 114 | pcf8563: pcf8563@51 { 115 | compatible = "nxp,pcf8563"; 116 | reg = <0x51>; 117 | status = "disabled"; 118 | }; 119 | }; 120 | }; 121 | 122 | /* 123 | * Values for input event code is found under the 124 | * 'Keys and buttons' heading in include/uapi/linux/input.h 125 | */ 126 | fragment@4 { 127 | target-path = "/soc"; 128 | __overlay__ { 129 | keypad: keypad { 130 | compatible = "gpio-keys"; 131 | #address-cells = <1>; 132 | #size-cells = <0>; 133 | pinctrl-names = "default"; 134 | pinctrl-0 = <&keypad_pins>; 135 | status = "disabled"; 136 | autorepeat; 137 | 138 | button@17 { 139 | label = "GPIO KEY_UP"; 140 | linux,code = <103>; 141 | gpios = <&gpio 17 0>; 142 | }; 143 | button@22 { 144 | label = "GPIO KEY_DOWN"; 145 | linux,code = <108>; 146 | gpios = <&gpio 22 0>; 147 | }; 148 | button@27 { 149 | label = "GPIO KEY_LEFT"; 150 | linux,code = <105>; 151 | gpios = <&gpio 27 0>; 152 | }; 153 | button@23 { 154 | label = "GPIO KEY_RIGHT"; 155 | linux,code = <106>; 156 | gpios = <&gpio 23 0>; 157 | }; 158 | button@4 { 159 | label = "GPIO KEY_ENTER"; 160 | linux,code = <28>; 161 | gpios = <&gpio 4 0>; 162 | }; 163 | }; 164 | }; 165 | }; 166 | 167 | __overrides__ { 168 | speed = <&tinylcd35>,"spi-max-frequency:0"; 169 | rotate = <&tinylcd35>,"rotate:0"; 170 | fps = <&tinylcd35>,"fps:0"; 171 | debug = <&tinylcd35>,"debug:0"; 172 | touch = <&tinylcd35_ts>,"status"; 173 | touchgpio = <&tinylcd35_ts_pins>,"brcm,pins:0", 174 | <&tinylcd35_ts>,"interrupts:0", 175 | <&tinylcd35_ts>,"pendown-gpio:4"; 176 | xohms = <&tinylcd35_ts>,"ti,x-plate-ohms;0"; 177 | rtc = <&i2c1>,"status", 178 | <&pcf8563>,"status"; 179 | keypad = <&keypad>,"status"; 180 | }; 181 | }; 182 | -------------------------------------------------------------------------------- /dts/rpi.dts: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * FBTFT Device Tree part for the Raspberry Pi 4 | * Add this file to the end of the *rpi-b.dts file 5 | * 6 | * Please keep it sorted alphabetically on display name 7 | * 8 | * Notes: 9 | * - use ads7846 instead of tsc2046 to get module autoloading 10 | * - use polarity 1 to drive backlight initially low (off): 11 | * led-gpios = <&gpio 18 1>; 12 | */ 13 | 14 | &spi0 { 15 | /* this is provided here to make it easy to enable SPI when editing this file */ 16 | // status = "okay"; 17 | }; 18 | 19 | 20 | 21 | /* 22 | * Texy 23 | * 2.8" TFT + Touch Shield Board (320x240) HY28A 24 | * 25 | */ 26 | &spi0 { 27 | hy28a@0{ 28 | compatible = "ilitek,ili9320"; 29 | reg = <0>; 30 | status = "disabled"; 31 | 32 | spi-max-frequency = <32000000>; 33 | spi-cpol; 34 | spi-cpha; 35 | rotate = <270>; 36 | bgr; 37 | fps = <50>; 38 | buswidth = <8>; 39 | startbyte = <0x70>; 40 | reset-gpios = <&gpio 25 0>; 41 | led-gpios = <&gpio 18 1>; 42 | debug = <0>; 43 | }; 44 | 45 | hy28a_ts@1 { 46 | compatible = "ti,ads7846"; 47 | reg = <1>; 48 | status = "disabled"; 49 | 50 | spi-max-frequency = <2000000>; 51 | interrupts = <3 17>; 52 | pendown-gpio = <&gpio 17 0>; 53 | ti,x-plate-ohms = /bits/ 16 <100>; 54 | ti,pressure-max = /bits/ 16 <255>; 55 | }; 56 | }; 57 | 58 | 59 | 60 | 61 | /* 62 | * Texy 63 | * 2.8" TFT + Touch Shield Board (320x240) HY28B 64 | * NOT TESTED 65 | */ 66 | &spi0 { 67 | hy28b@0{ 68 | compatible = "ilitek,ili9325"; 69 | reg = <0>; 70 | status = "disabled"; 71 | 72 | spi-max-frequency = <48000000>; 73 | rotate = <270>; 74 | bgr; 75 | fps = <50>; 76 | buswidth = <8>; 77 | startbyte = <0x70>; 78 | reset-gpios = <&gpio 25 0>; 79 | led-gpios = <&gpio 18 1>; 80 | 81 | gamma = "04 1F 4 7 7 0 7 7 6 0\n0F 00 1 7 4 0 0 0 6 7"; 82 | 83 | init = <0x10000e7 0x0010 84 | 0x1000000 0x0001 85 | 0x1000001 0x0100 86 | 0x1000002 0x0700 87 | 0x1000003 0x1030 88 | 0x1000004 0x0000 89 | 0x1000008 0x0207 90 | 0x1000009 0x0000 91 | 0x100000a 0x0000 92 | 0x100000c 0x0001 93 | 0x100000d 0x0000 94 | 0x100000f 0x0000 95 | 0x1000010 0x0000 96 | 0x1000011 0x0007 97 | 0x1000012 0x0000 98 | 0x1000013 0x0000 99 | 0x2000032 100 | 0x1000010 0x1590 101 | 0x1000011 0x0227 102 | 0x2000032 103 | 0x1000012 0x009c 104 | 0x2000032 105 | 0x1000013 0x1900 106 | 0x1000029 0x0023 107 | 0x100002b 0x000e 108 | 0x2000032 109 | 0x1000020 0x0000 110 | 0x1000021 0x0000 111 | 0x2000032 112 | 0x1000050 0x0000 113 | 0x1000051 0x00ef 114 | 0x1000052 0x0000 115 | 0x1000053 0x013f 116 | 0x1000060 0xa700 117 | 0x1000061 0x0001 118 | 0x100006a 0x0000 119 | 0x1000080 0x0000 120 | 0x1000081 0x0000 121 | 0x1000082 0x0000 122 | 0x1000083 0x0000 123 | 0x1000084 0x0000 124 | 0x1000085 0x0000 125 | 0x1000090 0x0010 126 | 0x1000092 0x0000 127 | 0x1000093 0x0003 128 | 0x1000095 0x0110 129 | 0x1000097 0x0000 130 | 0x1000098 0x0000 131 | 0x1000007 0x0133 132 | 0x1000020 0x0000 133 | 0x1000021 0x0000 134 | 0x2000064>; 135 | debug = <0>; 136 | }; 137 | 138 | hy28b_ts@1 { 139 | compatible = "ti,ads7846"; 140 | reg = <1>; 141 | status = "disabled"; 142 | 143 | spi-max-frequency = <2000000>; 144 | interrupts = <3 17>; 145 | pendown-gpio = <&gpio 17 0>; 146 | ti,x-plate-ohms = /bits/ 16 <100>; 147 | ti,pressure-max = /bits/ 16 <255>; 148 | }; 149 | }; 150 | 151 | 152 | 153 | 154 | /* 155 | * ITEAD 156 | * ITDB02-2.8 157 | * 158 | */ 159 | / { 160 | itdb28 { 161 | compatible = "ilitek,ili9325"; 162 | status = "disabled"; 163 | 164 | rotate = <0>; 165 | bgr; 166 | buswidth = <8>; 167 | reset-gpios = <&gpio 17 0>; 168 | dc-gpios = <&gpio 3 0>; 169 | cs-gpios = <&gpio 27 0>; 170 | wr-gpios = <&gpio 2 0>; 171 | db-gpios = <&gpio 9 0>, 172 | <&gpio 11 0>, 173 | <&gpio 18 0>, 174 | <&gpio 23 0>, 175 | <&gpio 24 0>, 176 | <&gpio 25 0>, 177 | <&gpio 8 0>, 178 | <&gpio 7 0>; 179 | /* LED pin drives backlight directly. Use transistor (50mA) */ 180 | /* led-gpios = <&gpio 4 1>; */ 181 | debug = <0>; 182 | }; 183 | }; 184 | 185 | 186 | 187 | 188 | /* 189 | * Watterott 190 | * RPi-Display - 2.8" Touch-Display (320x240) 191 | * 192 | */ 193 | &spi0 { 194 | rpi-display@0{ 195 | compatible = "ilitek,ili9341"; 196 | reg = <0>; 197 | status = "disabled"; 198 | 199 | spi-max-frequency = <32000000>; 200 | rotate = <270>; 201 | bgr; 202 | fps = <30>; 203 | buswidth = <8>; 204 | reset-gpios = <&gpio 23 0>; 205 | dc-gpios = <&gpio 24 0>; 206 | led-gpios = <&gpio 18 1>; 207 | debug = <0>; 208 | }; 209 | 210 | rpi-display_ts@1 { 211 | compatible = "ti,ads7846"; 212 | reg = <1>; 213 | status = "disabled"; 214 | 215 | spi-max-frequency = <2000000>; 216 | interrupts = <3 25>; 217 | pendown-gpio = <&gpio 25 0>; 218 | ti,x-plate-ohms = /bits/ 16 <60>; 219 | ti,pressure-max = /bits/ 16 <255>; 220 | }; 221 | }; 222 | 223 | 224 | 225 | 226 | /* 227 | * Ozzmaker 228 | * PiScreen - 3.5" TFT touchscreen (480x320) 229 | * 230 | */ 231 | &spi0 { 232 | piscreen@0{ 233 | compatible = "ilitek,ili9486"; 234 | reg = <0>; 235 | status = "disabled"; 236 | 237 | spi-max-frequency = <20000000>; 238 | rotate = <270>; 239 | bgr; 240 | fps = <30>; 241 | buswidth = <8>; 242 | reset-gpios = <&gpio 25 0>; 243 | dc-gpios = <&gpio 24 0>; 244 | led-gpios = <&gpio 22 1>; 245 | 246 | init = <0x10000b0 0x00 247 | 0x1000011 248 | 0x20000FF 249 | 0x100003A 0x55 250 | 0x1000036 0x28 251 | 0x10000C2 0x44 252 | 0x10000C5 0x00 0x00 0x00 0x00 253 | 0x10000E0 0x0F 0x1F 0x1C 0x0C 0x0F 0x08 0x48 0x98 0x37 0x0A 0x13 0x04 0x11 0x0D 0x00 254 | 0x10000E1 0x0F 0x32 0x2E 0x0B 0x0D 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 255 | 0x10000E2 0x0F 0x32 0x2E 0x0B 0x0D 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 256 | 0x1000011 257 | 0X1000029>; 258 | debug = <0>; 259 | }; 260 | 261 | piscreen_ts@1 { 262 | compatible = "ti,ads7846"; 263 | reg = <1>; 264 | status = "disabled"; 265 | 266 | spi-max-frequency = <2000000>; 267 | interrupts = <3 17>; 268 | pendown-gpio = <&gpio 17 0>; 269 | ti,x-plate-ohms = /bits/ 16 <100>; 270 | ti,pressure-max = /bits/ 16 <255>; 271 | }; 272 | }; 273 | 274 | 275 | 276 | 277 | /* 278 | * Adafruit 279 | * PiTFT Mini Kit - 320x240 2.8" TFT+Touchscreen for Raspberry Pi 280 | * 281 | * Couldn't get touch controller to work 282 | */ 283 | 284 | &gpio { 285 | stmpets_pins: stmpets_pins { 286 | brcm,pins = <24>; 287 | brcm,function = <0>; /* gpio in */ 288 | brcm,pull = <2>; /* pull up */ 289 | }; 290 | }; 291 | 292 | &spi0 { 293 | pitft@0{ 294 | compatible = "ilitek,ili9340"; 295 | reg = <0>; 296 | status = "disabled"; 297 | 298 | spi-max-frequency = <32000000>; 299 | rotate = <90>; 300 | bgr; 301 | buswidth = <8>; 302 | dc-gpios = <&gpio 25 0>; 303 | 304 | init = <0x1000001 305 | 0x2000005 306 | 0x1000028 307 | 0x10000EF 0x03 0x80 0x02 308 | 0x10000CF 0x00 0xC1 0x30 309 | 0x10000ED 0x64 0x03 0x12 0x81 310 | 0x10000E8 0x85 0x00 0x78 311 | 0x10000CB 0x39 0x2C 0x00 0x34 0x02 312 | 0x10000F7 0x20 313 | 0x10000EA 0x00 0x00 314 | 0x10000C0 0x23 315 | 0x10000C1 0x10 316 | 0x10000C5 0x3e 0x28 317 | 0x10000C7 0x86 318 | 0x100003A 0x55 319 | 0x10000B1 0x00 0x18 320 | 0x10000B6 0x08 0x82 0x27 321 | 0x10000F2 0x00 322 | 0x1000026 0x01 323 | 0x10000E0 0x0F 0x31 0x2B 0x0C 0x0E 0x08 0x4E 0xF1 0x37 0x07 0x10 0x03 0x0E 0x09 0x00 324 | 0x10000E1 0x00 0x0E 0x14 0x03 0x11 0x07 0x31 0xC1 0x48 0x08 0x0F 0x0C 0x31 0x36 0x0F 325 | 0x1000011 326 | 0x2000064 327 | 0x1000029 328 | 0x2000014>; 329 | debug = <0>; 330 | }; 331 | /* 332 | Touchscreen didn't work. I guess it has something to do with it being an interrupt controller. 333 | I have never tried this before with DT and ARCH_BCM2708. 334 | On ARCH_BCM2835 it should be OK, since the GPIO controller acts as an interrupt controller as well. 335 | (stmpe_device can't be used from 3.16, because irq_base can't be set anymore) 336 | 337 | [ 8.889056] irq: irq_create_mapping(0xc3008800, 0xc2) 338 | [ 8.895698] irq: -> using domain @c3008800 339 | [ 8.900796] irq: -> existing mapping on virq 194 340 | [ 8.925048] stmpe-spi spi0.1: stmpe610 detected, chip id: 0x811 341 | [ 8.936650] irq: Added domain (null) 342 | [ 8.941780] irq: irq_create_mapping(0xc1dc1a20, 0x0) 343 | [ 8.949047] irq: -> using domain @c1dc1a20 344 | [ 8.954421] irq: -> virq allocation failed 345 | [ 8.959926] irq: irq_create_mapping(0xc1dc1a20, 0x1) 346 | [ 8.967366] irq: -> using domain @c1dc1a20 347 | [ 8.972870] irq: -> virq allocation failed 348 | */ 349 | pitft_ts@1 { 350 | compatible = "st,stmpe610"; 351 | #address-cells = <1>; 352 | #size-cells = <0>; 353 | reg = <1>; 354 | status = "disabled"; 355 | pinctrl-names = "default"; 356 | pinctrl-0 = <&stmpets_pins>; 357 | 358 | spi-max-frequency = <500000>; 359 | interrupts = <3 24>; 360 | interrupt-parent = <&intc>; 361 | interrupt-controller; 362 | 363 | stmpe_touchscreen { 364 | compatible = "st,stmpe-ts"; 365 | st,sample-time = <4>; 366 | st,mod-12b = <1>; 367 | st,ref-sel = <0>; 368 | st,adc-freq = <2>; 369 | st,ave-ctrl = <3>; 370 | st,touch-det-delay = <4>; 371 | st,settling = <2>; 372 | st,fraction-z = <7>; 373 | st,i-drive = <0>; 374 | }; 375 | }; 376 | }; 377 | 378 | 379 | 380 | 381 | /* 382 | * NeoSec LLC 383 | * 3.5 inch TFT Display (320x480) 384 | * 385 | */ 386 | &spi0 { 387 | tinylcd35@0{ 388 | compatible = "neosec,tinylcd"; 389 | reg = <0>; 390 | status = "disabled"; 391 | 392 | spi-max-frequency = <48000000>; 393 | rotate = <270>; 394 | bgr; 395 | fps = <50>; 396 | buswidth = <8>; 397 | reset-gpios = <&gpio 25 0>; 398 | dc-gpios = <&gpio 24 0>; 399 | led-gpios = <&gpio 18 1>; 400 | debug = <0>; 401 | }; 402 | 403 | tinylcd35@1 { 404 | compatible = "ti,ads7846"; 405 | reg = <1>; 406 | status = "disabled"; 407 | 408 | spi-max-frequency = <2000000>; 409 | interrupts = <3 3>; 410 | pendown-gpio = <&gpio 3 0>; 411 | ti,x-plate-ohms = /bits/ 16 <100>; 412 | ti,pressure-max = /bits/ 16 <255>; 413 | }; 414 | }; 415 | -------------------------------------------------------------------------------- /fb_agm1264k-fl.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notro/fbtft/e9fc10a080a6c52e46e004c4c2bc9fd3cf3d7445/fb_agm1264k-fl.c -------------------------------------------------------------------------------- /fb_bd663474.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the uPD161704 LCD Controller 3 | * 4 | * Copyright (C) 2014 Seong-Woo Kim 5 | * 6 | * Based on fb_ili9325.c by Noralf Tronnes 7 | * Based on ili9325.c by Jeroen Domburg 8 | * Init code from UTFT library by Henning Karlsen 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "fbtft.h" 32 | 33 | #define DRVNAME "fb_bd663474" 34 | #define WIDTH 240 35 | #define HEIGHT 320 36 | #define BPP 16 37 | 38 | static int init_display(struct fbtft_par *par) 39 | { 40 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 41 | 42 | if (par->gpio.cs != -1) 43 | gpio_set_value(par->gpio.cs, 0); /* Activate chip */ 44 | 45 | par->fbtftops.reset(par); 46 | 47 | /* Initialization sequence from Lib_UTFT */ 48 | 49 | /* oscillator start */ 50 | write_reg(par, 0x000,0x0001); /*oscillator 0: stop, 1: operation */ 51 | mdelay(10); 52 | 53 | /* Power settings */ 54 | write_reg(par, 0x100, 0x0000 ); /* power supply setup */ 55 | write_reg(par, 0x101, 0x0000 ); 56 | write_reg(par, 0x102, 0x3110 ); 57 | write_reg(par, 0x103, 0xe200 ); 58 | write_reg(par, 0x110, 0x009d ); 59 | write_reg(par, 0x111, 0x0022 ); 60 | write_reg(par, 0x100, 0x0120 ); 61 | mdelay( 20 ); 62 | 63 | write_reg(par, 0x100, 0x3120 ); 64 | mdelay( 80 ); 65 | /* Display control */ 66 | write_reg(par, 0x001, 0x0100 ); 67 | write_reg(par, 0x002, 0x0000 ); 68 | write_reg(par, 0x003, 0x1230 ); 69 | write_reg(par, 0x006, 0x0000 ); 70 | write_reg(par, 0x007, 0x0101 ); 71 | write_reg(par, 0x008, 0x0808 ); 72 | write_reg(par, 0x009, 0x0000 ); 73 | write_reg(par, 0x00b, 0x0000 ); 74 | write_reg(par, 0x00c, 0x0000 ); 75 | write_reg(par, 0x00d, 0x0018 ); 76 | /* LTPS control settings */ 77 | write_reg(par, 0x012, 0x0000 ); 78 | write_reg(par, 0x013, 0x0000 ); 79 | write_reg(par, 0x018, 0x0000 ); 80 | write_reg(par, 0x019, 0x0000 ); 81 | 82 | write_reg(par, 0x203, 0x0000 ); 83 | write_reg(par, 0x204, 0x0000 ); 84 | 85 | write_reg(par, 0x210, 0x0000 ); 86 | write_reg(par, 0x211, 0x00ef ); 87 | write_reg(par, 0x212, 0x0000 ); 88 | write_reg(par, 0x213, 0x013f ); 89 | write_reg(par, 0x214, 0x0000 ); 90 | write_reg(par, 0x215, 0x0000 ); 91 | write_reg(par, 0x216, 0x0000 ); 92 | write_reg(par, 0x217, 0x0000 ); 93 | 94 | /* Gray scale settings */ 95 | write_reg(par, 0x300, 0x5343); 96 | write_reg(par, 0x301, 0x1021); 97 | write_reg(par, 0x302, 0x0003); 98 | write_reg(par, 0x303, 0x0011); 99 | write_reg(par, 0x304, 0x050a); 100 | write_reg(par, 0x305, 0x4342); 101 | write_reg(par, 0x306, 0x1100); 102 | write_reg(par, 0x307, 0x0003); 103 | write_reg(par, 0x308, 0x1201); 104 | write_reg(par, 0x309, 0x050a); 105 | 106 | /* RAM access settings */ 107 | write_reg(par, 0x400, 0x4027 ); 108 | write_reg(par, 0x401, 0x0000 ); 109 | write_reg(par, 0x402, 0x0000 ); /* First screen drive position (1) */ 110 | write_reg(par, 0x403, 0x013f ); /* First screen drive position (2) */ 111 | write_reg(par, 0x404, 0x0000 ); 112 | 113 | write_reg(par, 0x200, 0x0000 ); 114 | write_reg(par, 0x201, 0x0000 ); 115 | write_reg(par, 0x100, 0x7120 ); 116 | write_reg(par, 0x007, 0x0103 ); 117 | mdelay( 10 ); 118 | write_reg(par, 0x007, 0x0113 ); 119 | 120 | return 0; 121 | } 122 | 123 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 124 | { 125 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 126 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 127 | switch (par->info->var.rotate) { 128 | /* R200h = Horizontal GRAM Start Address */ 129 | /* R201h = Vertical GRAM Start Address */ 130 | case 0: 131 | write_reg(par, 0x0200, xs); 132 | write_reg(par, 0x0201, ys); 133 | break; 134 | case 180: 135 | write_reg(par, 0x0200, WIDTH - 1 - xs); 136 | write_reg(par, 0x0201, HEIGHT - 1 - ys); 137 | break; 138 | case 270: 139 | write_reg(par, 0x0200, WIDTH - 1 - ys); 140 | write_reg(par, 0x0201, xs); 141 | break; 142 | case 90: 143 | write_reg(par, 0x0200, ys); 144 | write_reg(par, 0x0201, HEIGHT - 1 - xs); 145 | break; 146 | } 147 | write_reg(par, 0x202); /* Write Data to GRAM */ 148 | } 149 | 150 | static int set_var(struct fbtft_par *par) 151 | { 152 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 153 | 154 | switch (par->info->var.rotate) { 155 | /* AM: GRAM update direction */ 156 | case 0: 157 | write_reg(par, 0x003, 0x1230); 158 | break; 159 | case 180: 160 | write_reg(par, 0x003, 0x1200); 161 | break; 162 | case 270: 163 | write_reg(par, 0x003, 0x1228); 164 | break; 165 | case 90: 166 | write_reg(par, 0x003, 0x1218); 167 | break; 168 | } 169 | 170 | return 0; 171 | } 172 | 173 | static struct fbtft_display display = { 174 | .regwidth = 16, 175 | .width = WIDTH, 176 | .height = HEIGHT, 177 | .bpp = BPP, 178 | .fbtftops = { 179 | .init_display = init_display, 180 | .set_addr_win = set_addr_win, 181 | .set_var = set_var, 182 | }, 183 | }; 184 | FBTFT_REGISTER_DRIVER(DRVNAME, "hitachi,bd663474", &display); 185 | 186 | MODULE_ALIAS("spi:" DRVNAME); 187 | MODULE_ALIAS("platform:" DRVNAME); 188 | MODULE_ALIAS("spi:bd663474"); 189 | MODULE_ALIAS("platform:bd663474"); 190 | 191 | MODULE_DESCRIPTION("FB driver for the uPD161704 LCD Controller"); 192 | MODULE_AUTHOR("Seong-Woo Kim"); 193 | MODULE_LICENSE("GPL"); 194 | -------------------------------------------------------------------------------- /fb_hx8340bn.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the HX8340BN LCD Controller 3 | * 4 | * This display uses 9-bit SPI: Data/Command bit + 8 data bits 5 | * For platforms that doesn't support 9-bit, the driver is capable 6 | * of emulating this using 8-bit transfer. 7 | * This is done by transfering eight 9-bit words in 9 bytes. 8 | * 9 | * Copyright (C) 2013 Noralf Tronnes 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; if not, write to the Free Software 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "fbtft.h" 34 | 35 | #define DRVNAME "fb_hx8340bn" 36 | #define WIDTH 176 37 | #define HEIGHT 220 38 | #define TXBUFLEN (4 * PAGE_SIZE) 39 | #define DEFAULT_GAMMA "1 3 0E 5 0 2 09 0 6 1 7 1 0 2 2\n" \ 40 | "3 3 17 8 4 7 05 7 6 0 3 1 6 0 0 " 41 | 42 | 43 | static bool emulate; 44 | module_param(emulate, bool, 0); 45 | MODULE_PARM_DESC(emulate, "Force emulation in 9-bit mode"); 46 | 47 | 48 | static int init_display(struct fbtft_par *par) 49 | { 50 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 51 | 52 | par->fbtftops.reset(par); 53 | 54 | /* BTL221722-276L startup sequence, from datasheet */ 55 | 56 | /* SETEXTCOM: Set extended command set (C1h) 57 | This command is used to set extended command set access enable. 58 | Enable: After command (C1h), must write: ffh,83h,40h */ 59 | write_reg(par, 0xC1, 0xFF, 0x83, 0x40); 60 | 61 | /* Sleep out 62 | This command turns off sleep mode. 63 | In this mode the DC/DC converter is enabled, Internal oscillator 64 | is started, and panel scanning is started. */ 65 | write_reg(par, 0x11); 66 | mdelay(150); 67 | 68 | /* Undoc'd register? */ 69 | write_reg(par, 0xCA, 0x70, 0x00, 0xD9); 70 | 71 | /* SETOSC: Set Internal Oscillator (B0h) 72 | This command is used to set internal oscillator related settings */ 73 | /* OSC_EN: Enable internal oscillator */ 74 | /* Internal oscillator frequency: 125% x 2.52MHz */ 75 | write_reg(par, 0xB0, 0x01, 0x11); 76 | 77 | /* Drive ability setting */ 78 | write_reg(par, 0xC9, 0x90, 0x49, 0x10, 0x28, 0x28, 0x10, 0x00, 0x06); 79 | mdelay(20); 80 | 81 | /* SETPWCTR5: Set Power Control 5(B5h) 82 | This command is used to set VCOM Low and VCOM High Voltage */ 83 | /* VCOMH 0110101 : 3.925 */ 84 | /* VCOML 0100000 : -1.700 */ 85 | /* 45h=69 VCOMH: "VMH" + 5d VCOML: "VMH" + 5d */ 86 | write_reg(par, 0xB5, 0x35, 0x20, 0x45); 87 | 88 | /* SETPWCTR4: Set Power Control 4(B4h) 89 | VRH[4:0]: Specify the VREG1 voltage adjusting. 90 | VREG1 voltage is for gamma voltage setting. 91 | BT[2:0]: Switch the output factor of step-up circuit 2 92 | for VGH and VGL voltage generation. */ 93 | write_reg(par, 0xB4, 0x33, 0x25, 0x4C); 94 | mdelay(10); 95 | 96 | /* Interface Pixel Format (3Ah) 97 | This command is used to define the format of RGB picture data, 98 | which is to be transfer via the system and RGB interface. */ 99 | /* RGB interface: 16 Bit/Pixel */ 100 | write_reg(par, 0x3A, 0x05); 101 | 102 | /* Display on (29h) 103 | This command is used to recover from DISPLAY OFF mode. 104 | Output from the Frame Memory is enabled. */ 105 | write_reg(par, 0x29); 106 | mdelay(10); 107 | 108 | return 0; 109 | } 110 | 111 | void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 112 | { 113 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 114 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 115 | 116 | write_reg(par, FBTFT_CASET, 0x00, xs, 0x00, xe); 117 | write_reg(par, FBTFT_RASET, 0x00, ys, 0x00, ye); 118 | write_reg(par, FBTFT_RAMWR); 119 | } 120 | 121 | static int set_var(struct fbtft_par *par) 122 | { 123 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 124 | 125 | /* MADCTL - Memory data access control */ 126 | /* RGB/BGR can be set with H/W pin SRGB and MADCTL BGR bit */ 127 | #define MY (1 << 7) 128 | #define MX (1 << 6) 129 | #define MV (1 << 5) 130 | switch (par->info->var.rotate) { 131 | case 0: 132 | write_reg(par, 0x36, (par->bgr << 3)); 133 | break; 134 | case 270: 135 | write_reg(par, 0x36, MX | MV | (par->bgr << 3)); 136 | break; 137 | case 180: 138 | write_reg(par, 0x36, MX | MY | (par->bgr << 3)); 139 | break; 140 | case 90: 141 | write_reg(par, 0x36, MY | MV | (par->bgr << 3)); 142 | break; 143 | } 144 | 145 | return 0; 146 | } 147 | 148 | /* 149 | Gamma Curve selection, GC (only GC0 can be customized): 150 | 0 = 2.2, 1 = 1.8, 2 = 2.5, 3 = 1.0 151 | Gamma string format: 152 | OP0 OP1 CP0 CP1 CP2 CP3 CP4 MP0 MP1 MP2 MP3 MP4 MP5 CGM0 CGM1 153 | ON0 ON1 CN0 CN1 CN2 CN3 CN4 MN0 MN1 MN2 MN3 MN4 MN5 XXXX GC 154 | */ 155 | #define CURVE(num, idx) curves[num*par->gamma.num_values + idx] 156 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 157 | { 158 | unsigned long mask[] = { 159 | 0b1111, 0b1111, 0b11111, 0b1111, 0b1111, 0b1111, 0b11111, 160 | 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b11, 0b11, 161 | 0b1111, 0b1111, 0b11111, 0b1111, 0b1111, 0b1111, 0b11111, 162 | 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b0, 0b0 }; 163 | int i, j; 164 | 165 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 166 | 167 | /* apply mask */ 168 | for (i = 0; i < par->gamma.num_curves; i++) 169 | for (j = 0; j < par->gamma.num_values; j++) 170 | CURVE(i, j) &= mask[i * par->gamma.num_values + j]; 171 | 172 | write_reg(par, 0x26, 1 << CURVE(1, 14)); /* Gamma Set (26h) */ 173 | 174 | if (CURVE(1, 14)) 175 | return 0; /* only GC0 can be customized */ 176 | 177 | write_reg(par, 0xC2, 178 | (CURVE(0, 8) << 4) | CURVE(0, 7), 179 | (CURVE(0, 10) << 4) | CURVE(0, 9), 180 | (CURVE(0, 12) << 4) | CURVE(0, 11), 181 | CURVE(0, 2), 182 | (CURVE(0, 4) << 4) | CURVE(0, 3), 183 | CURVE(0, 5), 184 | CURVE(0, 6), 185 | (CURVE(0, 1) << 4) | CURVE(0, 0), 186 | (CURVE(0, 14) << 2) | CURVE(0, 13)); 187 | 188 | write_reg(par, 0xC3, 189 | (CURVE(1, 8) << 4) | CURVE(1, 7), 190 | (CURVE(1, 10) << 4) | CURVE(1, 9), 191 | (CURVE(1, 12) << 4) | CURVE(1, 11), 192 | CURVE(1, 2), 193 | (CURVE(1, 4) << 4) | CURVE(1, 3), 194 | CURVE(1, 5), 195 | CURVE(1, 6), 196 | (CURVE(1, 1) << 4) | CURVE(1, 0)); 197 | 198 | mdelay(10); 199 | 200 | return 0; 201 | } 202 | #undef CURVE 203 | 204 | 205 | static struct fbtft_display display = { 206 | .regwidth = 8, 207 | .width = WIDTH, 208 | .height = HEIGHT, 209 | .txbuflen = TXBUFLEN, 210 | .gamma_num = 2, 211 | .gamma_len = 15, 212 | .gamma = DEFAULT_GAMMA, 213 | .fbtftops = { 214 | .init_display = init_display, 215 | .set_addr_win = set_addr_win, 216 | .set_var = set_var, 217 | .set_gamma = set_gamma, 218 | }, 219 | }; 220 | FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8340bn", &display); 221 | 222 | MODULE_ALIAS("spi:" DRVNAME); 223 | MODULE_ALIAS("platform:" DRVNAME); 224 | MODULE_ALIAS("spi:hx8340bn"); 225 | MODULE_ALIAS("platform:hx8340bn"); 226 | 227 | MODULE_DESCRIPTION("FB driver for the HX8340BN LCD Controller"); 228 | MODULE_AUTHOR("Noralf Tronnes"); 229 | MODULE_LICENSE("GPL"); 230 | -------------------------------------------------------------------------------- /fb_hx8347d.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the HX8347D LCD Controller 3 | * 4 | * Copyright (C) 2013 Christian Vogelgsang 5 | * 6 | * Based on driver code found here: https://github.com/watterott/r61505u-Adapter 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "fbtft.h" 29 | 30 | #define DRVNAME "fb_hx8347d" 31 | #define WIDTH 320 32 | #define HEIGHT 240 33 | #define DEFAULT_GAMMA "0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" \ 34 | "0 0 0 0 0 0 0 0 0 0 0 0 0 0" 35 | 36 | 37 | static int init_display(struct fbtft_par *par) 38 | { 39 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 40 | 41 | par->fbtftops.reset(par); 42 | 43 | /* driving ability */ 44 | write_reg(par, 0xEA, 0x00); 45 | write_reg(par, 0xEB, 0x20); 46 | write_reg(par, 0xEC, 0x0C); 47 | write_reg(par, 0xED, 0xC4); 48 | write_reg(par, 0xE8, 0x40); 49 | write_reg(par, 0xE9, 0x38); 50 | write_reg(par, 0xF1, 0x01); 51 | write_reg(par, 0xF2, 0x10); 52 | write_reg(par, 0x27, 0xA3); 53 | 54 | /* power voltage */ 55 | write_reg(par, 0x1B, 0x1B); 56 | write_reg(par, 0x1A, 0x01); 57 | write_reg(par, 0x24, 0x2F); 58 | write_reg(par, 0x25, 0x57); 59 | 60 | /* VCOM offset */ 61 | write_reg(par, 0x23, 0x8D); /* for flicker adjust */ 62 | 63 | /* power on */ 64 | write_reg(par, 0x18, 0x36); 65 | write_reg(par, 0x19, 0x01); /* start osc */ 66 | write_reg(par, 0x01, 0x00); /* wakeup */ 67 | write_reg(par, 0x1F, 0x88); 68 | mdelay(5); 69 | write_reg(par, 0x1F, 0x80); 70 | mdelay(5); 71 | write_reg(par, 0x1F, 0x90); 72 | mdelay(5); 73 | write_reg(par, 0x1F, 0xD0); 74 | mdelay(5); 75 | 76 | /* color selection */ 77 | write_reg(par, 0x17, 0x05); /* 65k */ 78 | 79 | /*panel characteristic */ 80 | write_reg(par, 0x36, 0x00); 81 | 82 | /*display on */ 83 | write_reg(par, 0x28, 0x38); 84 | mdelay(40); 85 | write_reg(par, 0x28, 0x3C); 86 | 87 | /* orientation */ 88 | write_reg(par, 0x16, 0x60 | (par->bgr << 3)); 89 | 90 | return 0; 91 | } 92 | 93 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 94 | { 95 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 96 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 97 | 98 | write_reg(par, 0x02, (xs >> 8) & 0xFF); 99 | write_reg(par, 0x03, xs & 0xFF); 100 | write_reg(par, 0x04, (xe >> 8) & 0xFF); 101 | write_reg(par, 0x05, xe & 0xFF); 102 | write_reg(par, 0x06, (ys >> 8) & 0xFF); 103 | write_reg(par, 0x07, ys & 0xFF); 104 | write_reg(par, 0x08, (ye >> 8) & 0xFF); 105 | write_reg(par, 0x09, ye & 0xFF); 106 | write_reg(par, 0x22); 107 | } 108 | 109 | /* 110 | Gamma string format: 111 | VRP0 VRP1 VRP2 VRP3 VRP4 VRP5 PRP0 PRP1 PKP0 PKP1 PKP2 PKP3 PKP4 CGM 112 | VRN0 VRN1 VRN2 VRN3 VRN4 VRN5 PRN0 PRN1 PKN0 PKN1 PKN2 PKN3 PKN4 CGM 113 | */ 114 | #define CURVE(num, idx) curves[num*par->gamma.num_values + idx] 115 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 116 | { 117 | unsigned long mask[] = { 118 | 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 119 | 0b1111111, 0b1111111, 120 | 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 121 | 0b1111}; 122 | int i, j; 123 | int acc = 0; 124 | 125 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 126 | 127 | /* apply mask */ 128 | for (i = 0; i < par->gamma.num_curves; i++) 129 | for (j = 0; j < par->gamma.num_values; j++) { 130 | acc += CURVE(i, j); 131 | CURVE(i, j) &= mask[j]; 132 | } 133 | 134 | if (acc == 0) /* skip if all values are zero */ 135 | return 0; 136 | 137 | for (i = 0; i < par->gamma.num_curves; i++) { 138 | write_reg(par, 0x40 + (i * 0x10), CURVE(i, 0)); 139 | write_reg(par, 0x41 + (i * 0x10), CURVE(i, 1)); 140 | write_reg(par, 0x42 + (i * 0x10), CURVE(i, 2)); 141 | write_reg(par, 0x43 + (i * 0x10), CURVE(i, 3)); 142 | write_reg(par, 0x44 + (i * 0x10), CURVE(i, 4)); 143 | write_reg(par, 0x45 + (i * 0x10), CURVE(i, 5)); 144 | write_reg(par, 0x46 + (i * 0x10), CURVE(i, 6)); 145 | write_reg(par, 0x47 + (i * 0x10), CURVE(i, 7)); 146 | write_reg(par, 0x48 + (i * 0x10), CURVE(i, 8)); 147 | write_reg(par, 0x49 + (i * 0x10), CURVE(i, 9)); 148 | write_reg(par, 0x4A + (i * 0x10), CURVE(i, 10)); 149 | write_reg(par, 0x4B + (i * 0x10), CURVE(i, 11)); 150 | write_reg(par, 0x4C + (i * 0x10), CURVE(i, 12)); 151 | } 152 | write_reg(par, 0x5D, (CURVE(1, 0) << 4) | CURVE(0, 0)); 153 | 154 | return 0; 155 | } 156 | #undef CURVE 157 | 158 | 159 | static struct fbtft_display display = { 160 | .regwidth = 8, 161 | .width = WIDTH, 162 | .height = HEIGHT, 163 | .gamma_num = 2, 164 | .gamma_len = 14, 165 | .gamma = DEFAULT_GAMMA, 166 | .fbtftops = { 167 | .init_display = init_display, 168 | .set_addr_win = set_addr_win, 169 | .set_gamma = set_gamma, 170 | }, 171 | }; 172 | FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8347d", &display); 173 | 174 | MODULE_ALIAS("spi:" DRVNAME); 175 | MODULE_ALIAS("platform:" DRVNAME); 176 | MODULE_ALIAS("spi:hx8347d"); 177 | MODULE_ALIAS("platform:hx8347d"); 178 | 179 | MODULE_DESCRIPTION("FB driver for the HX8347D LCD Controller"); 180 | MODULE_AUTHOR("Christian Vogelgsang"); 181 | MODULE_LICENSE("GPL"); 182 | -------------------------------------------------------------------------------- /fb_hx8353d.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the HX8353D LCD Controller 3 | * 4 | * Copyright (c) 2014 Petr Olivka 5 | * Copyright (c) 2013 Noralf Tronnes 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "fbtft.h" 28 | 29 | #define DRVNAME "fb_hx8353d" 30 | #define DEFAULT_GAMMA "50 77 40 08 BF 00 03 0F 00 01 73 00 72 03 B0 0F 08 00 0F" 31 | 32 | static int init_display(struct fbtft_par *par) 33 | { 34 | 35 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 36 | 37 | par->fbtftops.reset(par); 38 | mdelay(150); 39 | 40 | /* SETEXTC */ 41 | write_reg(par, 0xB9, 0xFF, 0x83, 0x53); 42 | 43 | /* RADJ */ 44 | write_reg(par, 0xB0, 0x3C, 0x01); 45 | 46 | /* VCOM */ 47 | write_reg(par, 0xB6, 0x94, 0x6C, 0x50); 48 | 49 | /* PWR */ 50 | write_reg(par, 0xB1, 0x00, 0x01, 0x1B, 0x03, 0x01, 0x08, 0x77, 0x89); 51 | 52 | /* COLMOD */ 53 | write_reg(par, 0x3A, 0x05); 54 | 55 | /* MEM ACCESS */ 56 | write_reg(par, 0x36, 0xC0); 57 | 58 | /* SLPOUT - Sleep out & booster on */ 59 | write_reg(par, 0x11); 60 | mdelay(150); 61 | 62 | /* DISPON - Display On */ 63 | write_reg(par, 0x29); 64 | 65 | /* RGBSET */ 66 | write_reg(par, 0x2D, 67 | 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 68 | 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 69 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 70 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 71 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 72 | 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 73 | 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 74 | 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62); 75 | 76 | return 0; 77 | }; 78 | 79 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 80 | { 81 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 82 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 83 | 84 | /* column address */ 85 | write_reg(par, 0x2a, xs >> 8, xs & 0xff, xe >> 8, xe & 0xff); 86 | 87 | /* row adress */ 88 | write_reg(par, 0x2b, ys >> 8, ys & 0xff, ye >> 8, ye & 0xff); 89 | 90 | /* memory write */ 91 | write_reg(par, 0x2c); 92 | } 93 | 94 | #define my (1 << 7) 95 | #define mx (1 << 6) 96 | #define mv (1 << 5) 97 | static int set_var(struct fbtft_par *par) 98 | { 99 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 100 | 101 | /* madctl - memory data access control 102 | rgb/bgr: 103 | 1. mode selection pin srgb 104 | rgb h/w pin for color filter setting: 0=rgb, 1=bgr 105 | 2. madctl rgb bit 106 | rgb-bgr order color filter panel: 0=rgb, 1=bgr */ 107 | switch (par->info->var.rotate) { 108 | case 0: 109 | write_reg(par, 0x36, mx | my | (par->bgr << 3)); 110 | break; 111 | case 270: 112 | write_reg(par, 0x36, my | mv | (par->bgr << 3)); 113 | break; 114 | case 180: 115 | write_reg(par, 0x36, (par->bgr << 3)); 116 | break; 117 | case 90: 118 | write_reg(par, 0x36, mx | mv | (par->bgr << 3)); 119 | break; 120 | } 121 | 122 | return 0; 123 | } 124 | 125 | /* 126 | gamma string format: 127 | */ 128 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 129 | { 130 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 131 | 132 | write_reg(par, 0xE0, 133 | curves[0], curves[1], curves[2], curves[3], 134 | curves[4], curves[5], curves[6], curves[7], 135 | curves[8], curves[9], curves[10], curves[11], 136 | curves[12], curves[13], curves[14], curves[15], 137 | curves[16], curves[17], curves[18]); 138 | 139 | return 0; 140 | } 141 | 142 | 143 | static struct fbtft_display display = { 144 | .regwidth = 8, 145 | .width = 128, 146 | .height = 160, 147 | .gamma_num = 1, 148 | .gamma_len = 19, 149 | .gamma = DEFAULT_GAMMA, 150 | .fbtftops = { 151 | .init_display = init_display, 152 | .set_addr_win = set_addr_win, 153 | .set_var = set_var, 154 | .set_gamma = set_gamma, 155 | }, 156 | }; 157 | FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8353d", &display); 158 | 159 | MODULE_ALIAS("spi:" DRVNAME); 160 | MODULE_ALIAS("platform:" DRVNAME); 161 | MODULE_ALIAS("spi:hx8353d"); 162 | MODULE_ALIAS("platform:hx8353d"); 163 | 164 | MODULE_DESCRIPTION("FB driver for the HX8353D LCD Controller"); 165 | MODULE_AUTHOR("Petr Olivka"); 166 | MODULE_LICENSE("GPL"); 167 | -------------------------------------------------------------------------------- /fb_ili9320.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the ILI9320 LCD Controller 3 | * 4 | * Copyright (C) 2013 Noralf Tronnes 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "fbtft.h" 29 | 30 | #define DRVNAME "fb_ili9320" 31 | #define WIDTH 240 32 | #define HEIGHT 320 33 | #define DEFAULT_GAMMA "07 07 6 0 0 0 5 5 4 0\n" \ 34 | "07 08 4 7 5 1 2 0 7 7" 35 | 36 | 37 | static unsigned read_devicecode(struct fbtft_par *par) 38 | { 39 | int ret; 40 | u8 rxbuf[8] = {0, }; 41 | 42 | write_reg(par, 0x0000); 43 | ret = par->fbtftops.read(par, rxbuf, 4); 44 | return (rxbuf[2] << 8) | rxbuf[3]; 45 | } 46 | 47 | static int init_display(struct fbtft_par *par) 48 | { 49 | unsigned devcode; 50 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 51 | 52 | par->fbtftops.reset(par); 53 | 54 | devcode = read_devicecode(par); 55 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "Device code: 0x%04X\n", 56 | devcode); 57 | if ((devcode != 0x0000) && (devcode != 0x9320)) 58 | dev_warn(par->info->device, 59 | "Unrecognized Device code: 0x%04X (expected 0x9320)\n", 60 | devcode); 61 | 62 | /* Initialization sequence from ILI9320 Application Notes */ 63 | 64 | /* *********** Start Initial Sequence ********* */ 65 | write_reg(par, 0x00E5, 0x8000); /* Set the Vcore voltage and this setting is must. */ 66 | write_reg(par, 0x0000, 0x0001); /* Start internal OSC. */ 67 | write_reg(par, 0x0001, 0x0100); /* set SS and SM bit */ 68 | write_reg(par, 0x0002, 0x0700); /* set 1 line inversion */ 69 | write_reg(par, 0x0004, 0x0000); /* Resize register */ 70 | write_reg(par, 0x0008, 0x0202); /* set the back and front porch */ 71 | write_reg(par, 0x0009, 0x0000); /* set non-display area refresh cycle */ 72 | write_reg(par, 0x000A, 0x0000); /* FMARK function */ 73 | write_reg(par, 0x000C, 0x0000); /* RGB interface setting */ 74 | write_reg(par, 0x000D, 0x0000); /* Frame marker Position */ 75 | write_reg(par, 0x000F, 0x0000); /* RGB interface polarity */ 76 | 77 | /* ***********Power On sequence *************** */ 78 | write_reg(par, 0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ 79 | write_reg(par, 0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */ 80 | write_reg(par, 0x0012, 0x0000); /* VREG1OUT voltage */ 81 | write_reg(par, 0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ 82 | mdelay(200); /* Dis-charge capacitor power voltage */ 83 | write_reg(par, 0x0010, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ 84 | write_reg(par, 0x0011, 0x0031); /* R11h=0x0031 at VCI=3.3V DC1[2:0], DC0[2:0], VC[2:0] */ 85 | mdelay(50); 86 | write_reg(par, 0x0012, 0x0138); /* R12h=0x0138 at VCI=3.3V VREG1OUT voltage */ 87 | mdelay(50); 88 | write_reg(par, 0x0013, 0x1800); /* R13h=0x1800 at VCI=3.3V VDV[4:0] for VCOM amplitude */ 89 | write_reg(par, 0x0029, 0x0008); /* R29h=0x0008 at VCI=3.3V VCM[4:0] for VCOMH */ 90 | mdelay(50); 91 | write_reg(par, 0x0020, 0x0000); /* GRAM horizontal Address */ 92 | write_reg(par, 0x0021, 0x0000); /* GRAM Vertical Address */ 93 | 94 | /* ------------------ Set GRAM area --------------- */ 95 | write_reg(par, 0x0050, 0x0000); /* Horizontal GRAM Start Address */ 96 | write_reg(par, 0x0051, 0x00EF); /* Horizontal GRAM End Address */ 97 | write_reg(par, 0x0052, 0x0000); /* Vertical GRAM Start Address */ 98 | write_reg(par, 0x0053, 0x013F); /* Vertical GRAM Start Address */ 99 | write_reg(par, 0x0060, 0x2700); /* Gate Scan Line */ 100 | write_reg(par, 0x0061, 0x0001); /* NDL,VLE, REV */ 101 | write_reg(par, 0x006A, 0x0000); /* set scrolling line */ 102 | 103 | /* -------------- Partial Display Control --------- */ 104 | write_reg(par, 0x0080, 0x0000); 105 | write_reg(par, 0x0081, 0x0000); 106 | write_reg(par, 0x0082, 0x0000); 107 | write_reg(par, 0x0083, 0x0000); 108 | write_reg(par, 0x0084, 0x0000); 109 | write_reg(par, 0x0085, 0x0000); 110 | 111 | /* -------------- Panel Control ------------------- */ 112 | write_reg(par, 0x0090, 0x0010); 113 | write_reg(par, 0x0092, 0x0000); 114 | write_reg(par, 0x0093, 0x0003); 115 | write_reg(par, 0x0095, 0x0110); 116 | write_reg(par, 0x0097, 0x0000); 117 | write_reg(par, 0x0098, 0x0000); 118 | write_reg(par, 0x0007, 0x0173); /* 262K color and display ON */ 119 | 120 | return 0; 121 | } 122 | 123 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 124 | { 125 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 126 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 127 | 128 | switch (par->info->var.rotate) { 129 | /* R20h = Horizontal GRAM Start Address */ 130 | /* R21h = Vertical GRAM Start Address */ 131 | case 0: 132 | write_reg(par, 0x0020, xs); 133 | write_reg(par, 0x0021, ys); 134 | break; 135 | case 180: 136 | write_reg(par, 0x0020, WIDTH - 1 - xs); 137 | write_reg(par, 0x0021, HEIGHT - 1 - ys); 138 | break; 139 | case 270: 140 | write_reg(par, 0x0020, WIDTH - 1 - ys); 141 | write_reg(par, 0x0021, xs); 142 | break; 143 | case 90: 144 | write_reg(par, 0x0020, ys); 145 | write_reg(par, 0x0021, HEIGHT - 1 - xs); 146 | break; 147 | } 148 | write_reg(par, 0x0022); /* Write Data to GRAM */ 149 | } 150 | 151 | static int set_var(struct fbtft_par *par) 152 | { 153 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 154 | 155 | switch (par->info->var.rotate) { 156 | case 0: 157 | write_reg(par, 0x3, (par->bgr << 12) | 0x30); 158 | break; 159 | case 270: 160 | write_reg(par, 0x3, (par->bgr << 12) | 0x28); 161 | break; 162 | case 180: 163 | write_reg(par, 0x3, (par->bgr << 12) | 0x00); 164 | break; 165 | case 90: 166 | write_reg(par, 0x3, (par->bgr << 12) | 0x18); 167 | break; 168 | } 169 | return 0; 170 | } 171 | 172 | /* 173 | Gamma string format: 174 | VRP0 VRP1 RP0 RP1 KP0 KP1 KP2 KP3 KP4 KP5 175 | VRN0 VRN1 RN0 RN1 KN0 KN1 KN2 KN3 KN4 KN5 176 | */ 177 | #define CURVE(num, idx) curves[num*par->gamma.num_values + idx] 178 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 179 | { 180 | unsigned long mask[] = { 181 | 0b11111, 0b11111, 0b111, 0b111, 0b111, 182 | 0b111, 0b111, 0b111, 0b111, 0b111, 183 | 0b11111, 0b11111, 0b111, 0b111, 0b111, 184 | 0b111, 0b111, 0b111, 0b111, 0b111 }; 185 | int i, j; 186 | 187 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 188 | 189 | /* apply mask */ 190 | for (i = 0; i < 2; i++) 191 | for (j = 0; j < 10; j++) 192 | CURVE(i, j) &= mask[i*par->gamma.num_values + j]; 193 | 194 | write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4)); 195 | write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6)); 196 | write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8)); 197 | write_reg(par, 0x0035, CURVE(0, 3) << 8 | CURVE(0, 2)); 198 | write_reg(par, 0x0036, CURVE(0, 1) << 8 | CURVE(0, 0)); 199 | 200 | write_reg(par, 0x0037, CURVE(1, 5) << 8 | CURVE(1, 4)); 201 | write_reg(par, 0x0038, CURVE(1, 7) << 8 | CURVE(1, 6)); 202 | write_reg(par, 0x0039, CURVE(1, 9) << 8 | CURVE(1, 8)); 203 | write_reg(par, 0x003C, CURVE(1, 3) << 8 | CURVE(1, 2)); 204 | write_reg(par, 0x003D, CURVE(1, 1) << 8 | CURVE(1, 0)); 205 | 206 | return 0; 207 | } 208 | #undef CURVE 209 | 210 | 211 | static struct fbtft_display display = { 212 | .regwidth = 16, 213 | .width = WIDTH, 214 | .height = HEIGHT, 215 | .gamma_num = 2, 216 | .gamma_len = 10, 217 | .gamma = DEFAULT_GAMMA, 218 | .fbtftops = { 219 | .init_display = init_display, 220 | .set_addr_win = set_addr_win, 221 | .set_var = set_var, 222 | .set_gamma = set_gamma, 223 | }, 224 | }; 225 | FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9320", &display); 226 | 227 | MODULE_ALIAS("spi:" DRVNAME); 228 | MODULE_ALIAS("platform:" DRVNAME); 229 | MODULE_ALIAS("spi:ili9320"); 230 | MODULE_ALIAS("platform:ili9320"); 231 | 232 | MODULE_DESCRIPTION("FB driver for the ILI9320 LCD Controller"); 233 | MODULE_AUTHOR("Noralf Tronnes"); 234 | MODULE_LICENSE("GPL"); 235 | -------------------------------------------------------------------------------- /fb_ili9325.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the ILI9325 LCD Controller 3 | * 4 | * Copyright (C) 2013 Noralf Tronnes 5 | * 6 | * Based on ili9325.c by Jeroen Domburg 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "fbtft.h" 30 | 31 | #define DRVNAME "fb_ili9325" 32 | #define WIDTH 240 33 | #define HEIGHT 320 34 | #define BPP 16 35 | #define FPS 20 36 | #define DEFAULT_GAMMA "0F 00 7 2 0 0 6 5 4 1\n" \ 37 | "04 16 2 7 6 3 2 1 7 7" 38 | 39 | 40 | static unsigned bt = 6; /* VGL=Vci*4 , VGH=Vci*4 */ 41 | module_param(bt, uint, 0); 42 | MODULE_PARM_DESC(bt, "Sets the factor used in the step-up circuits"); 43 | 44 | static unsigned vc = 0b011; /* Vci1=Vci*0.80 */ 45 | module_param(vc, uint, 0); 46 | MODULE_PARM_DESC(vc, 47 | "Sets the ratio factor of Vci to generate the reference voltages Vci1"); 48 | 49 | static unsigned vrh = 0b1101; /* VREG1OUT=Vci*1.85 */ 50 | module_param(vrh, uint, 0); 51 | MODULE_PARM_DESC(vrh, 52 | "Set the amplifying rate (1.6 ~ 1.9) of Vci applied to output the VREG1OUT"); 53 | 54 | static unsigned vdv = 0b10010; /* VCOMH amplitude=VREG1OUT*0.98 */ 55 | module_param(vdv, uint, 0); 56 | MODULE_PARM_DESC(vdv, 57 | "Select the factor of VREG1OUT to set the amplitude of Vcom"); 58 | 59 | static unsigned vcm = 0b001010; /* VCOMH=VREG1OUT*0.735 */ 60 | module_param(vcm, uint, 0); 61 | MODULE_PARM_DESC(vcm, "Set the internal VcomH voltage"); 62 | 63 | 64 | /* 65 | Verify that this configuration is within the Voltage limits 66 | 67 | Display module configuration: Vcc = IOVcc = Vci = 3.3V 68 | 69 | Voltages 70 | ---------- 71 | Vci = 3.3 72 | Vci1 = Vci * 0.80 = 2.64 73 | DDVDH = Vci1 * 2 = 5.28 74 | VCL = -Vci1 = -2.64 75 | VREG1OUT = Vci * 1.85 = 4.88 76 | VCOMH = VREG1OUT * 0.735 = 3.59 77 | VCOM amplitude = VREG1OUT * 0.98 = 4.79 78 | VGH = Vci * 4 = 13.2 79 | VGL = -Vci * 4 = -13.2 80 | 81 | Limits 82 | -------- 83 | Power supplies 84 | 1.65 < IOVcc < 3.30 => 1.65 < 3.3 < 3.30 85 | 2.40 < Vcc < 3.30 => 2.40 < 3.3 < 3.30 86 | 2.50 < Vci < 3.30 => 2.50 < 3.3 < 3.30 87 | 88 | Source/VCOM power supply voltage 89 | 4.50 < DDVDH < 6.0 => 4.50 < 5.28 < 6.0 90 | -3.0 < VCL < -2.0 => -3.0 < -2.64 < -2.0 91 | VCI - VCL < 6.0 => 5.94 < 6.0 92 | 93 | Gate driver output voltage 94 | 10 < VGH < 20 => 10 < 13.2 < 20 95 | -15 < VGL < -5 => -15 < -13.2 < -5 96 | VGH - VGL < 32 => 26.4 < 32 97 | 98 | VCOM driver output voltage 99 | VCOMH - VCOML < 6.0 => 4.79 < 6.0 100 | */ 101 | 102 | static int init_display(struct fbtft_par *par) 103 | { 104 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 105 | 106 | par->fbtftops.reset(par); 107 | 108 | if (par->gpio.cs != -1) 109 | gpio_set_value(par->gpio.cs, 0); /* Activate chip */ 110 | 111 | bt &= 0b111; 112 | vc &= 0b111; 113 | vrh &= 0b1111; 114 | vdv &= 0b11111; 115 | vcm &= 0b111111; 116 | 117 | /* Initialization sequence from ILI9325 Application Notes */ 118 | 119 | /* ----------- Start Initial Sequence ----------- */ 120 | write_reg(par, 0x00E3, 0x3008); /* Set internal timing */ 121 | write_reg(par, 0x00E7, 0x0012); /* Set internal timing */ 122 | write_reg(par, 0x00EF, 0x1231); /* Set internal timing */ 123 | write_reg(par, 0x0001, 0x0100); /* set SS and SM bit */ 124 | write_reg(par, 0x0002, 0x0700); /* set 1 line inversion */ 125 | write_reg(par, 0x0004, 0x0000); /* Resize register */ 126 | write_reg(par, 0x0008, 0x0207); /* set the back porch and front porch */ 127 | write_reg(par, 0x0009, 0x0000); /* set non-display area refresh cycle */ 128 | write_reg(par, 0x000A, 0x0000); /* FMARK function */ 129 | write_reg(par, 0x000C, 0x0000); /* RGB interface setting */ 130 | write_reg(par, 0x000D, 0x0000); /* Frame marker Position */ 131 | write_reg(par, 0x000F, 0x0000); /* RGB interface polarity */ 132 | 133 | /* ----------- Power On sequence ----------- */ 134 | write_reg(par, 0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ 135 | write_reg(par, 0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */ 136 | write_reg(par, 0x0012, 0x0000); /* VREG1OUT voltage */ 137 | write_reg(par, 0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ 138 | mdelay(200); /* Dis-charge capacitor power voltage */ 139 | write_reg(par, 0x0010, /* SAP, BT[3:0], AP, DSTB, SLP, STB */ 140 | (1 << 12) | (bt << 8) | (1 << 7) | (0b001 << 4)); 141 | write_reg(par, 0x0011, 0x220 | vc); /* DC1[2:0], DC0[2:0], VC[2:0] */ 142 | mdelay(50); /* Delay 50ms */ 143 | write_reg(par, 0x0012, vrh); /* Internal reference voltage= Vci; */ 144 | mdelay(50); /* Delay 50ms */ 145 | write_reg(par, 0x0013, vdv << 8); /* Set VDV[4:0] for VCOM amplitude */ 146 | write_reg(par, 0x0029, vcm); /* Set VCM[5:0] for VCOMH */ 147 | write_reg(par, 0x002B, 0x000C); /* Set Frame Rate */ 148 | mdelay(50); /* Delay 50ms */ 149 | write_reg(par, 0x0020, 0x0000); /* GRAM horizontal Address */ 150 | write_reg(par, 0x0021, 0x0000); /* GRAM Vertical Address */ 151 | 152 | /*------------------ Set GRAM area --------------- */ 153 | write_reg(par, 0x0050, 0x0000); /* Horizontal GRAM Start Address */ 154 | write_reg(par, 0x0051, 0x00EF); /* Horizontal GRAM End Address */ 155 | write_reg(par, 0x0052, 0x0000); /* Vertical GRAM Start Address */ 156 | write_reg(par, 0x0053, 0x013F); /* Vertical GRAM Start Address */ 157 | write_reg(par, 0x0060, 0xA700); /* Gate Scan Line */ 158 | write_reg(par, 0x0061, 0x0001); /* NDL,VLE, REV */ 159 | write_reg(par, 0x006A, 0x0000); /* set scrolling line */ 160 | 161 | /*-------------- Partial Display Control --------- */ 162 | write_reg(par, 0x0080, 0x0000); 163 | write_reg(par, 0x0081, 0x0000); 164 | write_reg(par, 0x0082, 0x0000); 165 | write_reg(par, 0x0083, 0x0000); 166 | write_reg(par, 0x0084, 0x0000); 167 | write_reg(par, 0x0085, 0x0000); 168 | 169 | /*-------------- Panel Control ------------------- */ 170 | write_reg(par, 0x0090, 0x0010); 171 | write_reg(par, 0x0092, 0x0600); 172 | write_reg(par, 0x0007, 0x0133); /* 262K color and display ON */ 173 | 174 | return 0; 175 | } 176 | 177 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 178 | { 179 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 180 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 181 | switch (par->info->var.rotate) { 182 | /* R20h = Horizontal GRAM Start Address */ 183 | /* R21h = Vertical GRAM Start Address */ 184 | case 0: 185 | write_reg(par, 0x0020, xs); 186 | write_reg(par, 0x0021, ys); 187 | break; 188 | case 180: 189 | write_reg(par, 0x0020, WIDTH - 1 - xs); 190 | write_reg(par, 0x0021, HEIGHT - 1 - ys); 191 | break; 192 | case 270: 193 | write_reg(par, 0x0020, WIDTH - 1 - ys); 194 | write_reg(par, 0x0021, xs); 195 | break; 196 | case 90: 197 | write_reg(par, 0x0020, ys); 198 | write_reg(par, 0x0021, HEIGHT - 1 - xs); 199 | break; 200 | } 201 | write_reg(par, 0x0022); /* Write Data to GRAM */ 202 | } 203 | 204 | static int set_var(struct fbtft_par *par) 205 | { 206 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 207 | 208 | switch (par->info->var.rotate) { 209 | /* AM: GRAM update direction */ 210 | case 0: 211 | write_reg(par, 0x03, 0x0030 | (par->bgr << 12)); 212 | break; 213 | case 180: 214 | write_reg(par, 0x03, 0x0000 | (par->bgr << 12)); 215 | break; 216 | case 270: 217 | write_reg(par, 0x03, 0x0028 | (par->bgr << 12)); 218 | break; 219 | case 90: 220 | write_reg(par, 0x03, 0x0018 | (par->bgr << 12)); 221 | break; 222 | } 223 | 224 | return 0; 225 | } 226 | 227 | /* 228 | Gamma string format: 229 | VRP0 VRP1 RP0 RP1 KP0 KP1 KP2 KP3 KP4 KP5 230 | VRN0 VRN1 RN0 RN1 KN0 KN1 KN2 KN3 KN4 KN5 231 | */ 232 | #define CURVE(num, idx) curves[num*par->gamma.num_values + idx] 233 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 234 | { 235 | unsigned long mask[] = { 236 | 0b11111, 0b11111, 0b111, 0b111, 0b111, 237 | 0b111, 0b111, 0b111, 0b111, 0b111, 238 | 0b11111, 0b11111, 0b111, 0b111, 0b111, 239 | 0b111, 0b111, 0b111, 0b111, 0b111 }; 240 | int i, j; 241 | 242 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 243 | 244 | /* apply mask */ 245 | for (i = 0; i < 2; i++) 246 | for (j = 0; j < 10; j++) 247 | CURVE(i, j) &= mask[i*par->gamma.num_values + j]; 248 | 249 | write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4)); 250 | write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6)); 251 | write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8)); 252 | write_reg(par, 0x0035, CURVE(0, 3) << 8 | CURVE(0, 2)); 253 | write_reg(par, 0x0036, CURVE(0, 1) << 8 | CURVE(0, 0)); 254 | 255 | write_reg(par, 0x0037, CURVE(1, 5) << 8 | CURVE(1, 4)); 256 | write_reg(par, 0x0038, CURVE(1, 7) << 8 | CURVE(1, 6)); 257 | write_reg(par, 0x0039, CURVE(1, 9) << 8 | CURVE(1, 8)); 258 | write_reg(par, 0x003C, CURVE(1, 3) << 8 | CURVE(1, 2)); 259 | write_reg(par, 0x003D, CURVE(1, 1) << 8 | CURVE(1, 0)); 260 | 261 | return 0; 262 | } 263 | #undef CURVE 264 | 265 | 266 | static struct fbtft_display display = { 267 | .regwidth = 16, 268 | .width = WIDTH, 269 | .height = HEIGHT, 270 | .bpp = BPP, 271 | .fps = FPS, 272 | .gamma_num = 2, 273 | .gamma_len = 10, 274 | .gamma = DEFAULT_GAMMA, 275 | .fbtftops = { 276 | .init_display = init_display, 277 | .set_addr_win = set_addr_win, 278 | .set_var = set_var, 279 | .set_gamma = set_gamma, 280 | }, 281 | }; 282 | FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9325", &display); 283 | 284 | MODULE_ALIAS("spi:" DRVNAME); 285 | MODULE_ALIAS("platform:" DRVNAME); 286 | MODULE_ALIAS("spi:ili9325"); 287 | MODULE_ALIAS("platform:ili9325"); 288 | 289 | MODULE_DESCRIPTION("FB driver for the ILI9325 LCD Controller"); 290 | MODULE_AUTHOR("Noralf Tronnes"); 291 | MODULE_LICENSE("GPL"); 292 | -------------------------------------------------------------------------------- /fb_ili9340.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the ILI9340 LCD Controller 3 | * 4 | * Copyright (C) 2013 Noralf Tronnes 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "fbtft.h" 28 | 29 | #define DRVNAME "fb_ili9340" 30 | #define WIDTH 240 31 | #define HEIGHT 320 32 | 33 | 34 | /* Init sequence taken from: Arduino Library for the Adafruit 2.2" display */ 35 | static int init_display(struct fbtft_par *par) 36 | { 37 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 38 | 39 | par->fbtftops.reset(par); 40 | 41 | write_reg(par, 0xEF, 0x03, 0x80, 0x02); 42 | write_reg(par, 0xCF, 0x00 , 0XC1 , 0X30); 43 | write_reg(par, 0xED, 0x64 , 0x03 , 0X12 , 0X81); 44 | write_reg(par, 0xE8, 0x85 , 0x00 , 0x78); 45 | write_reg(par, 0xCB, 0x39 , 0x2C , 0x00 , 0x34 , 0x02); 46 | write_reg(par, 0xF7, 0x20); 47 | write_reg(par, 0xEA, 0x00 , 0x00); 48 | 49 | /* Power Control 1 */ 50 | write_reg(par, 0xC0, 0x23); 51 | 52 | /* Power Control 2 */ 53 | write_reg(par, 0xC1, 0x10); 54 | 55 | /* VCOM Control 1 */ 56 | write_reg(par, 0xC5, 0x3e, 0x28); 57 | 58 | /* VCOM Control 2 */ 59 | write_reg(par, 0xC7, 0x86); 60 | 61 | /* COLMOD: Pixel Format Set */ 62 | /* 16 bits/pixel */ 63 | write_reg(par, 0x3A, 0x55); 64 | 65 | /* Frame Rate Control */ 66 | /* Division ratio = fosc, Frame Rate = 79Hz */ 67 | write_reg(par, 0xB1, 0x00, 0x18); 68 | 69 | /* Display Function Control */ 70 | write_reg(par, 0xB6, 0x08, 0x82, 0x27); 71 | 72 | /* Gamma Function Disable */ 73 | write_reg(par, 0xF2, 0x00); 74 | 75 | /* Gamma curve selected */ 76 | write_reg(par, 0x26, 0x01); 77 | 78 | /* Positive Gamma Correction */ 79 | write_reg(par, 0xE0, 80 | 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 81 | 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00); 82 | 83 | /* Negative Gamma Correction */ 84 | write_reg(par, 0xE1, 85 | 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 86 | 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F); 87 | 88 | /* Sleep OUT */ 89 | write_reg(par, 0x11); 90 | 91 | mdelay(120); 92 | 93 | /* Display ON */ 94 | write_reg(par, 0x29); 95 | 96 | return 0; 97 | } 98 | 99 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 100 | { 101 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 102 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 103 | 104 | /* Column address */ 105 | write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); 106 | 107 | /* Row adress */ 108 | write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); 109 | 110 | /* Memory write */ 111 | write_reg(par, 0x2C); 112 | } 113 | 114 | #define ILI9340_MADCTL_MV 0x20 115 | #define ILI9340_MADCTL_MX 0x40 116 | #define ILI9340_MADCTL_MY 0x80 117 | static int set_var(struct fbtft_par *par) 118 | { 119 | u8 val; 120 | 121 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 122 | 123 | switch (par->info->var.rotate) { 124 | case 270: 125 | val = ILI9340_MADCTL_MV; 126 | break; 127 | case 180: 128 | val = ILI9340_MADCTL_MY; 129 | break; 130 | case 90: 131 | val = ILI9340_MADCTL_MV | ILI9340_MADCTL_MY | ILI9340_MADCTL_MX; 132 | break; 133 | default: 134 | val = ILI9340_MADCTL_MX; 135 | break; 136 | } 137 | /* Memory Access Control */ 138 | write_reg(par, 0x36, val | (par->bgr << 3)); 139 | 140 | return 0; 141 | } 142 | 143 | 144 | static struct fbtft_display display = { 145 | .regwidth = 8, 146 | .width = WIDTH, 147 | .height = HEIGHT, 148 | .fbtftops = { 149 | .init_display = init_display, 150 | .set_addr_win = set_addr_win, 151 | .set_var = set_var, 152 | }, 153 | }; 154 | FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9340", &display); 155 | 156 | MODULE_ALIAS("spi:" DRVNAME); 157 | MODULE_ALIAS("platform:" DRVNAME); 158 | MODULE_ALIAS("spi:ili9340"); 159 | MODULE_ALIAS("platform:ili9340"); 160 | 161 | MODULE_DESCRIPTION("FB driver for the ILI9340 LCD Controller"); 162 | MODULE_AUTHOR("Noralf Tronnes"); 163 | MODULE_LICENSE("GPL"); 164 | -------------------------------------------------------------------------------- /fb_ili9341.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the ILI9341 LCD display controller 3 | * 4 | * This display uses 9-bit SPI: Data/Command bit + 8 data bits 5 | * For platforms that doesn't support 9-bit, the driver is capable 6 | * of emulating this using 8-bit transfer. 7 | * This is done by transfering eight 9-bit words in 9 bytes. 8 | * 9 | * Copyright (C) 2013 Christian Vogelgsang 10 | * Based on adafruit22fb.c by Noralf Tronnes 11 | * 12 | * This program is free software; you can redistribute it and/or modify 13 | * it under the terms of the GNU General Public License as published by 14 | * the Free Software Foundation; either version 2 of the License, or 15 | * (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU General Public License 23 | * along with this program; if not, write to the Free Software 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "fbtft.h" 33 | 34 | #define DRVNAME "fb_ili9341" 35 | #define WIDTH 240 36 | #define HEIGHT 320 37 | #define TXBUFLEN (4 * PAGE_SIZE) 38 | #define DEFAULT_GAMMA "1F 1A 18 0A 0F 06 45 87 32 0A 07 02 07 05 00\n" \ 39 | "00 25 27 05 10 09 3A 78 4D 05 18 0D 38 3A 1F" 40 | 41 | 42 | static int init_display(struct fbtft_par *par) 43 | { 44 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 45 | 46 | par->fbtftops.reset(par); 47 | 48 | /* startup sequence for MI0283QT-9A */ 49 | write_reg(par, 0x01); /* software reset */ 50 | mdelay(5); 51 | write_reg(par, 0x28); /* display off */ 52 | /* --------------------------------------------------------- */ 53 | write_reg(par, 0xCF, 0x00, 0x83, 0x30); 54 | write_reg(par, 0xED, 0x64, 0x03, 0x12, 0x81); 55 | write_reg(par, 0xE8, 0x85, 0x01, 0x79); 56 | write_reg(par, 0xCB, 0x39, 0X2C, 0x00, 0x34, 0x02); 57 | write_reg(par, 0xF7, 0x20); 58 | write_reg(par, 0xEA, 0x00, 0x00); 59 | /* ------------power control-------------------------------- */ 60 | write_reg(par, 0xC0, 0x26); 61 | write_reg(par, 0xC1, 0x11); 62 | /* ------------VCOM --------- */ 63 | write_reg(par, 0xC5, 0x35, 0x3E); 64 | write_reg(par, 0xC7, 0xBE); 65 | /* ------------memory access control------------------------ */ 66 | write_reg(par, 0x3A, 0x55); /* 16bit pixel */ 67 | /* ------------frame rate----------------------------------- */ 68 | write_reg(par, 0xB1, 0x00, 0x1B); 69 | /* ------------Gamma---------------------------------------- */ 70 | /* write_reg(par, 0xF2, 0x08); */ /* Gamma Function Disable */ 71 | write_reg(par, 0x26, 0x01); 72 | /* ------------display-------------------------------------- */ 73 | write_reg(par, 0xB7, 0x07); /* entry mode set */ 74 | write_reg(par, 0xB6, 0x0A, 0x82, 0x27, 0x00); 75 | write_reg(par, 0x11); /* sleep out */ 76 | mdelay(100); 77 | write_reg(par, 0x29); /* display on */ 78 | mdelay(20); 79 | 80 | return 0; 81 | } 82 | 83 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 84 | { 85 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 86 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 87 | 88 | /* Column address set */ 89 | write_reg(par, 0x2A, 90 | (xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF); 91 | 92 | /* Row adress set */ 93 | write_reg(par, 0x2B, 94 | (ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF); 95 | 96 | /* Memory write */ 97 | write_reg(par, 0x2C); 98 | } 99 | 100 | #define MEM_Y (7) /* MY row address order */ 101 | #define MEM_X (6) /* MX column address order */ 102 | #define MEM_V (5) /* MV row / column exchange */ 103 | #define MEM_L (4) /* ML vertical refresh order */ 104 | #define MEM_H (2) /* MH horizontal refresh order */ 105 | #define MEM_BGR (3) /* RGB-BGR Order */ 106 | static int set_var(struct fbtft_par *par) 107 | { 108 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 109 | 110 | switch (par->info->var.rotate) { 111 | case 0: 112 | write_reg(par, 0x36, (1 << MEM_X) | (par->bgr << MEM_BGR)); 113 | break; 114 | case 270: 115 | write_reg(par, 0x36, 116 | (1<bgr << MEM_BGR)); 117 | break; 118 | case 180: 119 | write_reg(par, 0x36, (1 << MEM_Y) | (par->bgr << MEM_BGR)); 120 | break; 121 | case 90: 122 | write_reg(par, 0x36, (1 << MEM_Y) | (1 << MEM_X) | 123 | (1 << MEM_V) | (par->bgr << MEM_BGR)); 124 | break; 125 | } 126 | 127 | return 0; 128 | } 129 | 130 | /* 131 | Gamma string format: 132 | Positive: Par1 Par2 [...] Par15 133 | Negative: Par1 Par2 [...] Par15 134 | */ 135 | #define CURVE(num, idx) curves[num*par->gamma.num_values + idx] 136 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 137 | { 138 | int i; 139 | 140 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 141 | 142 | for (i = 0; i < par->gamma.num_curves; i++) 143 | write_reg(par, 0xE0 + i, 144 | CURVE(i, 0), CURVE(i, 1), CURVE(i, 2), 145 | CURVE(i, 3), CURVE(i, 4), CURVE(i, 5), 146 | CURVE(i, 6), CURVE(i, 7), CURVE(i, 8), 147 | CURVE(i, 9), CURVE(i, 10), CURVE(i, 11), 148 | CURVE(i, 12), CURVE(i, 13), CURVE(i, 14)); 149 | 150 | return 0; 151 | } 152 | #undef CURVE 153 | 154 | 155 | static struct fbtft_display display = { 156 | .regwidth = 8, 157 | .width = WIDTH, 158 | .height = HEIGHT, 159 | .txbuflen = TXBUFLEN, 160 | .gamma_num = 2, 161 | .gamma_len = 15, 162 | .gamma = DEFAULT_GAMMA, 163 | .fbtftops = { 164 | .init_display = init_display, 165 | .set_addr_win = set_addr_win, 166 | .set_var = set_var, 167 | .set_gamma = set_gamma, 168 | }, 169 | }; 170 | FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9341", &display); 171 | 172 | MODULE_ALIAS("spi:" DRVNAME); 173 | MODULE_ALIAS("platform:" DRVNAME); 174 | MODULE_ALIAS("spi:ili9341"); 175 | MODULE_ALIAS("platform:ili9341"); 176 | 177 | MODULE_DESCRIPTION("FB driver for the ILI9341 LCD display controller"); 178 | MODULE_AUTHOR("Christian Vogelgsang"); 179 | MODULE_LICENSE("GPL"); 180 | -------------------------------------------------------------------------------- /fb_ili9481.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the ILI9481 LCD Controller 3 | * 4 | * Copyright (c) 2014 Petr Olivka 5 | * Copyright (c) 2013 Noralf Tronnes 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "fbtft.h" 28 | 29 | #define DRVNAME "fb_ili9481" 30 | #define WIDTH 320 31 | #define HEIGHT 480 32 | 33 | static int default_init_sequence[] = { 34 | 35 | /* SLP_OUT - Sleep out */ 36 | -1, 0x11, 37 | -2, 50, 38 | /* Power setting */ 39 | -1, 0xD0, 0x07, 0x42, 0x18, 40 | /* VCOM */ 41 | -1, 0xD1, 0x00, 0x07, 0x10, 42 | /* Power setting for norm. mode */ 43 | -1, 0xD2, 0x01, 0x02, 44 | /* Panel driving setting */ 45 | -1, 0xC0, 0x10, 0x3B, 0x00, 0x02, 0x11, 46 | /* Frame rate & inv. */ 47 | -1, 0xC5, 0x03, 48 | /* Pixel format */ 49 | -1, 0x3A, 0x55, 50 | /* Gamma */ 51 | -1, 0xC8, 0x00, 0x32, 0x36, 0x45, 0x06, 0x16, 52 | 0x37, 0x75, 0x77, 0x54, 0x0C, 0x00, 53 | /* DISP_ON */ 54 | -1, 0x29, 55 | -3 56 | }; 57 | 58 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 59 | { 60 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 61 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 62 | 63 | /* column address */ 64 | write_reg(par, 0x2a, xs >> 8, xs & 0xff, xe >> 8, xe & 0xff); 65 | 66 | /* row adress */ 67 | write_reg(par, 0x2b, ys >> 8, ys & 0xff, ye >> 8, ye & 0xff); 68 | 69 | /* memory write */ 70 | write_reg(par, 0x2c); 71 | } 72 | 73 | #define HFLIP 0x01 74 | #define VFLIP 0x02 75 | #define ROWxCOL 0x20 76 | static int set_var(struct fbtft_par *par) 77 | { 78 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 79 | 80 | switch (par->info->var.rotate) { 81 | case 270: 82 | write_reg(par, 0x36, ROWxCOL | HFLIP | VFLIP | (par->bgr << 3)); 83 | break; 84 | case 180: 85 | write_reg(par, 0x36, VFLIP | (par->bgr << 3)); 86 | break; 87 | case 90: 88 | write_reg(par, 0x36, ROWxCOL | (par->bgr << 3)); 89 | break; 90 | default: 91 | write_reg(par, 0x36, HFLIP | (par->bgr << 3)); 92 | break; 93 | } 94 | 95 | return 0; 96 | } 97 | 98 | static struct fbtft_display display = { 99 | .regwidth = 8, 100 | .width = WIDTH, 101 | .height = HEIGHT, 102 | .init_sequence = default_init_sequence, 103 | .fbtftops = { 104 | .set_addr_win = set_addr_win, 105 | .set_var = set_var, 106 | }, 107 | }; 108 | FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9481", &display); 109 | 110 | MODULE_ALIAS("spi:" DRVNAME); 111 | MODULE_ALIAS("platform:" DRVNAME); 112 | MODULE_ALIAS("spi:ili9481"); 113 | MODULE_ALIAS("platform:ili9481"); 114 | 115 | MODULE_DESCRIPTION("FB driver for the ILI9481 LCD Controller"); 116 | MODULE_AUTHOR("Petr Olivka"); 117 | MODULE_LICENSE("GPL"); 118 | -------------------------------------------------------------------------------- /fb_ili9486.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the ILI9486 LCD Controller 3 | * 4 | * Copyright (C) 2014 Noralf Tronnes 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "fbtft.h" 26 | 27 | #define DRVNAME "fb_ili9486" 28 | #define WIDTH 320 29 | #define HEIGHT 480 30 | 31 | 32 | /* this init sequence matches PiScreen */ 33 | static int default_init_sequence[] = { 34 | /* Interface Mode Control */ 35 | -1, 0xb0, 0x0, 36 | /* Sleep OUT */ 37 | -1, 0x11, 38 | -2, 250, 39 | /* Interface Pixel Format */ 40 | -1, 0x3A, 0x55, 41 | /* Power Control 3 */ 42 | -1, 0xC2, 0x44, 43 | /* VCOM Control 1 */ 44 | -1, 0xC5, 0x00, 0x00, 0x00, 0x00, 45 | /* PGAMCTRL(Positive Gamma Control) */ 46 | -1, 0xE0, 0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98, 47 | 0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x00, 48 | /* NGAMCTRL(Negative Gamma Control) */ 49 | -1, 0xE1, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, 50 | 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00, 51 | /* Digital Gamma Control 1 */ 52 | -1, 0xE2, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75, 53 | 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00, 54 | /* Sleep OUT */ 55 | -1, 0x11, 56 | /* Display ON */ 57 | -1, 0x29, 58 | /* end marker */ 59 | -3 60 | }; 61 | 62 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 63 | { 64 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 65 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 66 | 67 | /* Column address */ 68 | write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); 69 | 70 | /* Row adress */ 71 | write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); 72 | 73 | /* Memory write */ 74 | write_reg(par, 0x2C); 75 | } 76 | 77 | static int set_var(struct fbtft_par *par) 78 | { 79 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 80 | 81 | switch (par->info->var.rotate) { 82 | case 0: 83 | write_reg(par, 0x36, 0x80 | (par->bgr << 3)); 84 | break; 85 | case 90: 86 | write_reg(par, 0x36, 0x20 | (par->bgr << 3)); 87 | break; 88 | case 180: 89 | write_reg(par, 0x36, 0x40 | (par->bgr << 3)); 90 | break; 91 | case 270: 92 | write_reg(par, 0x36, 0xE0 | (par->bgr << 3)); 93 | break; 94 | default: 95 | break; 96 | } 97 | 98 | return 0; 99 | } 100 | 101 | 102 | static struct fbtft_display display = { 103 | .regwidth = 8, 104 | .width = WIDTH, 105 | .height = HEIGHT, 106 | .init_sequence = default_init_sequence, 107 | .fbtftops = { 108 | .set_addr_win = set_addr_win, 109 | .set_var = set_var, 110 | }, 111 | }; 112 | FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9486", &display); 113 | 114 | MODULE_ALIAS("spi:" DRVNAME); 115 | MODULE_ALIAS("platform:" DRVNAME); 116 | MODULE_ALIAS("spi:ili9486"); 117 | MODULE_ALIAS("platform:ili9486"); 118 | 119 | MODULE_DESCRIPTION("FB driver for the ILI9486 LCD Controller"); 120 | MODULE_AUTHOR("Noralf Tronnes"); 121 | MODULE_LICENSE("GPL"); 122 | -------------------------------------------------------------------------------- /fb_pcd8544.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the PCD8544 LCD Controller 3 | * 4 | * The display is monochrome and the video memory is RGB565. 5 | * Any pixel value except 0 turns the pixel on. 6 | * 7 | * Copyright (C) 2013 Noralf Tronnes 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "fbtft.h" 32 | 33 | #define DRVNAME "fb_pcd8544" 34 | #define WIDTH 84 35 | #define HEIGHT 48 36 | #define TXBUFLEN 84*6 37 | #define DEFAULT_GAMMA "40" /* gamma is used to control contrast in this driver */ 38 | 39 | static unsigned tc = 0; 40 | module_param(tc, uint, 0); 41 | MODULE_PARM_DESC(tc, "TC[1:0] Temperature coefficient: 0-3 (default: 0)"); 42 | 43 | static unsigned bs = 4; 44 | module_param(bs, uint, 0); 45 | MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)"); 46 | 47 | 48 | static int init_display(struct fbtft_par *par) 49 | { 50 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 51 | 52 | par->fbtftops.reset(par); 53 | 54 | /* Function set */ 55 | write_reg(par, 0x21); /* 5:1 1 56 | 2:0 PD - Powerdown control: chip is active 57 | 1:0 V - Entry mode: horizontal addressing 58 | 0:1 H - Extended instruction set control: extended 59 | */ 60 | 61 | /* H=1 Temperature control */ 62 | write_reg(par, 0x04 | (tc & 0x3)); /* 63 | 2:1 1 64 | 1:x TC1 - Temperature Coefficient: 0x10 65 | 0:x TC0 66 | */ 67 | 68 | /* H=1 Bias system */ 69 | write_reg(par, 0x10 | (bs & 0x7)); /* 70 | 4:1 1 71 | 3:0 0 72 | 2:x BS2 - Bias System 73 | 1:x BS1 74 | 0:x BS0 75 | */ 76 | 77 | /* Function set */ 78 | write_reg(par, 0x22); /* 5:1 1 79 | 2:0 PD - Powerdown control: chip is active 80 | 1:1 V - Entry mode: vertical addressing 81 | 0:0 H - Extended instruction set control: basic 82 | */ 83 | 84 | /* H=0 Display control */ 85 | write_reg(par, 0x08 | 4); /* 86 | 3:1 1 87 | 2:1 D - DE: 10=normal mode 88 | 1:0 0 89 | 0:0 E 90 | */ 91 | 92 | return 0; 93 | } 94 | 95 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 96 | { 97 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 98 | 99 | /* H=0 Set X address of RAM */ 100 | write_reg(par, 0x80); /* 7:1 1 101 | 6-0: X[6:0] - 0x00 102 | */ 103 | 104 | /* H=0 Set Y address of RAM */ 105 | write_reg(par, 0x40); /* 7:0 0 106 | 6:1 1 107 | 2-0: Y[2:0] - 0x0 108 | */ 109 | } 110 | 111 | static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) 112 | { 113 | u16 *vmem16 = (u16 *)par->info->screen_base; 114 | u8 *buf = par->txbuf.buf; 115 | int x, y, i; 116 | int ret = 0; 117 | 118 | fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); 119 | 120 | for (x=0;x<84;x++) { 121 | for (y=0;y<6;y++) { 122 | *buf = 0x00; 123 | for (i=0;i<8;i++) { 124 | *buf |= (vmem16[(y*8+i)*84+x] ? 1 : 0) << i; 125 | } 126 | buf++; 127 | } 128 | } 129 | 130 | /* Write data */ 131 | gpio_set_value(par->gpio.dc, 1); 132 | ret = par->fbtftops.write(par, par->txbuf.buf, 6*84); 133 | if (ret < 0) 134 | dev_err(par->info->device, "%s: write failed and returned: %d\n", __func__, ret); 135 | 136 | return ret; 137 | } 138 | 139 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 140 | { 141 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 142 | 143 | /* apply mask */ 144 | curves[0] &= 0x7F; 145 | 146 | write_reg(par, 0x23); /* turn on extended instruction set */ 147 | write_reg(par, 0x80 | curves[0]); 148 | write_reg(par, 0x22); /* turn off extended instruction set */ 149 | 150 | return 0; 151 | } 152 | 153 | 154 | static struct fbtft_display display = { 155 | .regwidth = 8, 156 | .width = WIDTH, 157 | .height = HEIGHT, 158 | .txbuflen = TXBUFLEN, 159 | .gamma_num = 1, 160 | .gamma_len = 1, 161 | .gamma = DEFAULT_GAMMA, 162 | .fbtftops = { 163 | .init_display = init_display, 164 | .set_addr_win = set_addr_win, 165 | .write_vmem = write_vmem, 166 | .set_gamma = set_gamma, 167 | }, 168 | .backlight = 1, 169 | }; 170 | FBTFT_REGISTER_DRIVER(DRVNAME, "philips,pdc8544", &display); 171 | 172 | MODULE_ALIAS("spi:" DRVNAME); 173 | MODULE_ALIAS("spi:pdc8544"); 174 | 175 | MODULE_DESCRIPTION("FB driver for the PCD8544 LCD Controller"); 176 | MODULE_AUTHOR("Noralf Tronnes"); 177 | MODULE_LICENSE("GPL"); 178 | -------------------------------------------------------------------------------- /fb_ra8875.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/notro/fbtft/e9fc10a080a6c52e46e004c4c2bc9fd3cf3d7445/fb_ra8875.c -------------------------------------------------------------------------------- /fb_s6d02a1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the S6D02A1 LCD Controller 3 | * 4 | * Based on fb_st7735r.c by Noralf Tronnes 5 | * Init code from UTFT library by Henning Karlsen 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "fbtft.h" 27 | 28 | #define DRVNAME "fb_s6d02a1" 29 | 30 | static int default_init_sequence[] = { 31 | 32 | -1, 0xf0, 0x5a, 0x5a, 33 | 34 | -1, 0xfc, 0x5a, 0x5a, 35 | 36 | -1, 0xfa, 0x02, 0x1f, 0x00, 0x10, 0x22, 0x30, 0x38, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3d, 0x02, 0x01, 37 | 38 | -1, 0xfb, 0x21, 0x00, 0x02, 0x04, 0x07, 0x0a, 0x0b, 0x0c, 0x0c, 0x16, 0x1e, 0x30, 0x3f, 0x01, 0x02, 39 | 40 | /* power setting sequence */ 41 | -1, 0xfd, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x01, 0x01, 0x00, 0x1f, 0x1f, 42 | 43 | -1, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, 44 | 45 | -1, 0xf5, 0x00, 0x70, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x66, 0x06, 46 | 47 | -1, 0xf6, 0x02, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x01, 0x00, 48 | 49 | -1, 0xf2, 0x00, 0x01, 0x03, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x08, 0x08, 50 | 51 | -1, 0xf8, 0x11, 52 | 53 | -1, 0xf7, 0xc8, 0x20, 0x00, 0x00, 54 | 55 | -1, 0xf3, 0x00, 0x00, 56 | 57 | -1, 0x11, 58 | -2, 50, 59 | 60 | -1, 0xf3, 0x00, 0x01, 61 | -2, 50, 62 | -1, 0xf3, 0x00, 0x03, 63 | -2, 50, 64 | -1, 0xf3, 0x00, 0x07, 65 | -2, 50, 66 | -1, 0xf3, 0x00, 0x0f, 67 | -2, 50, 68 | 69 | -1, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, 70 | -2, 50, 71 | 72 | -1, 0xf3, 0x00, 0x1f, 73 | -2, 50, 74 | -1, 0xf3, 0x00, 0x7f, 75 | -2, 50, 76 | 77 | -1, 0xf3, 0x00, 0xff, 78 | -2, 50, 79 | 80 | -1, 0xfd, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x01, 0x00, 0x16, 0x16, 81 | 82 | -1, 0xf4, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, 83 | 84 | /* initializing sequence */ 85 | 86 | -1, 0x36, 0x08, 87 | 88 | -1, 0x35, 0x00, 89 | 90 | -1, 0x3a, 0x05, 91 | 92 | /* gamma setting sequence */ 93 | -1, 0x26, 0x01, /* preset gamma curves, possible values 0x01, 0x02, 0x04, 0x08 */ 94 | 95 | -2, 150, 96 | -1, 0x29, 97 | -1, 0x2c, 98 | /* end marker */ 99 | -3 100 | 101 | }; 102 | 103 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 104 | { 105 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 106 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 107 | 108 | /* Column address */ 109 | write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); 110 | 111 | /* Row adress */ 112 | write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); 113 | 114 | /* Memory write */ 115 | write_reg(par, 0x2C); 116 | } 117 | 118 | #define MY (1 << 7) 119 | #define MX (1 << 6) 120 | #define MV (1 << 5) 121 | static int set_var(struct fbtft_par *par) 122 | { 123 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 124 | 125 | /* MADCTL - Memory data access control 126 | RGB/BGR: 127 | 1. Mode selection pin SRGB 128 | RGB H/W pin for color filter setting: 0=RGB, 1=BGR 129 | 2. MADCTL RGB bit 130 | RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR */ 131 | switch (par->info->var.rotate) { 132 | case 0: 133 | write_reg(par, 0x36, MX | MY | (par->bgr << 3)); 134 | break; 135 | case 270: 136 | write_reg(par, 0x36, MY | MV | (par->bgr << 3)); 137 | break; 138 | case 180: 139 | write_reg(par, 0x36, (par->bgr << 3)); 140 | break; 141 | case 90: 142 | write_reg(par, 0x36, MX | MV | (par->bgr << 3)); 143 | break; 144 | } 145 | 146 | return 0; 147 | } 148 | 149 | static struct fbtft_display display = { 150 | .regwidth = 8, 151 | .width = 128, 152 | .height = 160, 153 | .init_sequence = default_init_sequence, 154 | .fbtftops = { 155 | .set_addr_win = set_addr_win, 156 | .set_var = set_var, 157 | }, 158 | }; 159 | FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d02a1", &display); 160 | 161 | MODULE_ALIAS("spi:" DRVNAME); 162 | MODULE_ALIAS("platform:" DRVNAME); 163 | MODULE_ALIAS("spi:s6d02a1"); 164 | MODULE_ALIAS("platform:s6d02a1"); 165 | 166 | MODULE_DESCRIPTION("FB driver for the S6D02A1 LCD Controller"); 167 | MODULE_AUTHOR("WOLFGANG BUENING"); 168 | MODULE_LICENSE("GPL"); 169 | -------------------------------------------------------------------------------- /fb_s6d1121.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the S6D1121 LCD Controller 3 | * 4 | * Copyright (C) 2013 Roman Rolinsky 5 | * 6 | * Based on fb_ili9325.c by Noralf Tronnes 7 | * Based on ili9325.c by Jeroen Domburg 8 | * Init code from UTFT library by Henning Karlsen 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "fbtft.h" 32 | 33 | #define DRVNAME "fb_s6d1121" 34 | #define WIDTH 240 35 | #define HEIGHT 320 36 | #define BPP 16 37 | #define FPS 20 38 | #define DEFAULT_GAMMA "26 09 24 2C 1F 23 24 25 22 26 25 23 0D 00\n" \ 39 | "1C 1A 13 1D 0B 11 12 10 13 15 36 19 00 0D" 40 | 41 | static int init_display(struct fbtft_par *par) 42 | { 43 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 44 | 45 | par->fbtftops.reset(par); 46 | 47 | if (par->gpio.cs != -1) 48 | gpio_set_value(par->gpio.cs, 0); /* Activate chip */ 49 | 50 | /* Initialization sequence from Lib_UTFT */ 51 | 52 | write_reg(par, 0x0011, 0x2004); 53 | write_reg(par, 0x0013, 0xCC00); 54 | write_reg(par, 0x0015, 0x2600); 55 | write_reg(par, 0x0014, 0x252A); 56 | write_reg(par, 0x0012, 0x0033); 57 | write_reg(par, 0x0013, 0xCC04); 58 | write_reg(par, 0x0013, 0xCC06); 59 | write_reg(par, 0x0013, 0xCC4F); 60 | write_reg(par, 0x0013, 0x674F); 61 | write_reg(par, 0x0011, 0x2003); 62 | write_reg(par, 0x0016, 0x0007); 63 | write_reg(par, 0x0002, 0x0013); 64 | write_reg(par, 0x0003, 0x0003); 65 | write_reg(par, 0x0001, 0x0127); 66 | write_reg(par, 0x0008, 0x0303); 67 | write_reg(par, 0x000A, 0x000B); 68 | write_reg(par, 0x000B, 0x0003); 69 | write_reg(par, 0x000C, 0x0000); 70 | write_reg(par, 0x0041, 0x0000); 71 | write_reg(par, 0x0050, 0x0000); 72 | write_reg(par, 0x0060, 0x0005); 73 | write_reg(par, 0x0070, 0x000B); 74 | write_reg(par, 0x0071, 0x0000); 75 | write_reg(par, 0x0078, 0x0000); 76 | write_reg(par, 0x007A, 0x0000); 77 | write_reg(par, 0x0079, 0x0007); 78 | write_reg(par, 0x0007, 0x0051); 79 | write_reg(par, 0x0007, 0x0053); 80 | write_reg(par, 0x0079, 0x0000); 81 | 82 | write_reg(par, 0x0022); /* Write Data to GRAM */ 83 | 84 | return 0; 85 | } 86 | 87 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 88 | { 89 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 90 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 91 | switch (par->info->var.rotate) { 92 | /* R20h = Horizontal GRAM Start Address */ 93 | /* R21h = Vertical GRAM Start Address */ 94 | case 0: 95 | write_reg(par, 0x0020, xs); 96 | write_reg(par, 0x0021, ys); 97 | break; 98 | case 180: 99 | write_reg(par, 0x0020, WIDTH - 1 - xs); 100 | write_reg(par, 0x0021, HEIGHT - 1 - ys); 101 | break; 102 | case 270: 103 | write_reg(par, 0x0020, WIDTH - 1 - ys); 104 | write_reg(par, 0x0021, xs); 105 | break; 106 | case 90: 107 | write_reg(par, 0x0020, ys); 108 | write_reg(par, 0x0021, HEIGHT - 1 - xs); 109 | break; 110 | } 111 | write_reg(par, 0x0022); /* Write Data to GRAM */ 112 | } 113 | 114 | static int set_var(struct fbtft_par *par) 115 | { 116 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 117 | 118 | switch (par->info->var.rotate) { 119 | /* AM: GRAM update direction */ 120 | case 0: 121 | write_reg(par, 0x03, 0x0003 | (par->bgr << 12)); 122 | break; 123 | case 180: 124 | write_reg(par, 0x03, 0x0000 | (par->bgr << 12)); 125 | break; 126 | case 270: 127 | write_reg(par, 0x03, 0x000A | (par->bgr << 12)); 128 | break; 129 | case 90: 130 | write_reg(par, 0x03, 0x0009 | (par->bgr << 12)); 131 | break; 132 | } 133 | 134 | return 0; 135 | } 136 | 137 | /* 138 | Gamma string format: 139 | PKP0 PKP1 PKP2 PKP3 PKP4 PKP5 PKP6 PKP7 PKP8 PKP9 PKP10 PKP11 VRP0 VRP1 140 | PKN0 PKN1 PKN2 PKN3 PKN4 PKN5 PKN6 PKN7 PRN8 PRN9 PRN10 PRN11 VRN0 VRN1 141 | */ 142 | #define CURVE(num, idx) curves[num*par->gamma.num_values + idx] 143 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 144 | { 145 | unsigned long mask[] = { 146 | 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 147 | 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 148 | 0b11111, 0b11111, 149 | 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 150 | 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 151 | 0b11111, 0b11111 }; 152 | int i, j; 153 | 154 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 155 | 156 | /* apply mask */ 157 | for (i = 0; i < 2; i++) 158 | for (j = 0; j < 14; j++) 159 | CURVE(i, j) &= mask[i*par->gamma.num_values + j]; 160 | 161 | write_reg(par, 0x0030, CURVE(0, 1) << 8 | CURVE(0, 0)); 162 | write_reg(par, 0x0031, CURVE(0, 3) << 8 | CURVE(0, 2)); 163 | write_reg(par, 0x0032, CURVE(0, 5) << 8 | CURVE(0, 3)); 164 | write_reg(par, 0x0033, CURVE(0, 7) << 8 | CURVE(0, 6)); 165 | write_reg(par, 0x0034, CURVE(0, 9) << 8 | CURVE(0, 8)); 166 | write_reg(par, 0x0035, CURVE(0, 11) << 8 | CURVE(0, 10)); 167 | 168 | write_reg(par, 0x0036, CURVE(1, 1) << 8 | CURVE(1, 0)); 169 | write_reg(par, 0x0037, CURVE(1, 3) << 8 | CURVE(1, 2)); 170 | write_reg(par, 0x0038, CURVE(1, 5) << 8 | CURVE(1, 4)); 171 | write_reg(par, 0x0039, CURVE(1, 7) << 8 | CURVE(1, 6)); 172 | write_reg(par, 0x003A, CURVE(1, 9) << 8 | CURVE(1, 8)); 173 | write_reg(par, 0x003B, CURVE(1, 11) << 8 | CURVE(1, 10)); 174 | 175 | write_reg(par, 0x003C, CURVE(0, 13) << 8 | CURVE(0, 12)); 176 | write_reg(par, 0x003D, CURVE(1, 13) << 8 | CURVE(1, 12)); 177 | 178 | return 0; 179 | } 180 | #undef CURVE 181 | 182 | 183 | static struct fbtft_display display = { 184 | .regwidth = 16, 185 | .width = WIDTH, 186 | .height = HEIGHT, 187 | .bpp = BPP, 188 | .fps = FPS, 189 | .gamma_num = 2, 190 | .gamma_len = 14, 191 | .gamma = DEFAULT_GAMMA, 192 | .fbtftops = { 193 | .init_display = init_display, 194 | .set_addr_win = set_addr_win, 195 | .set_var = set_var, 196 | .set_gamma = set_gamma, 197 | }, 198 | }; 199 | FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d1121", &display); 200 | 201 | MODULE_ALIAS("spi:" DRVNAME); 202 | MODULE_ALIAS("platform:" DRVNAME); 203 | MODULE_ALIAS("spi:s6d1121"); 204 | MODULE_ALIAS("platform:s6d1121"); 205 | 206 | MODULE_DESCRIPTION("FB driver for the S6D1121 LCD Controller"); 207 | MODULE_AUTHOR("Roman Rolinsky"); 208 | MODULE_LICENSE("GPL"); 209 | -------------------------------------------------------------------------------- /fb_ssd1289.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the SSD1289 LCD Controller 3 | * 4 | * Copyright (C) 2013 Noralf Tronnes 5 | * 6 | * Init sequence taken from ITDB02_Graph16.cpp - (C)2010-2011 Henning Karlsen 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "fbtft.h" 29 | 30 | #define DRVNAME "fb_ssd1289" 31 | #define WIDTH 240 32 | #define HEIGHT 320 33 | #define DEFAULT_GAMMA "02 03 2 5 7 7 4 2 4 2\n" \ 34 | "02 03 2 5 7 5 4 2 4 2" 35 | 36 | static unsigned reg11 = 0x6040; 37 | module_param(reg11, uint, 0); 38 | MODULE_PARM_DESC(reg11, "Register 11h value"); 39 | 40 | 41 | static int init_display(struct fbtft_par *par) 42 | { 43 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 44 | 45 | par->fbtftops.reset(par); 46 | 47 | if (par->gpio.cs != -1) 48 | gpio_set_value(par->gpio.cs, 0); /* Activate chip */ 49 | 50 | write_reg(par, 0x00, 0x0001); 51 | write_reg(par, 0x03, 0xA8A4); 52 | write_reg(par, 0x0C, 0x0000); 53 | write_reg(par, 0x0D, 0x080C); 54 | write_reg(par, 0x0E, 0x2B00); 55 | write_reg(par, 0x1E, 0x00B7); 56 | write_reg(par, 0x01, 57 | (1 << 13) | (par->bgr << 11) | (1 << 9) | (HEIGHT - 1)); 58 | write_reg(par, 0x02, 0x0600); 59 | write_reg(par, 0x10, 0x0000); 60 | write_reg(par, 0x05, 0x0000); 61 | write_reg(par, 0x06, 0x0000); 62 | write_reg(par, 0x16, 0xEF1C); 63 | write_reg(par, 0x17, 0x0003); 64 | write_reg(par, 0x07, 0x0233); 65 | write_reg(par, 0x0B, 0x0000); 66 | write_reg(par, 0x0F, 0x0000); 67 | write_reg(par, 0x41, 0x0000); 68 | write_reg(par, 0x42, 0x0000); 69 | write_reg(par, 0x48, 0x0000); 70 | write_reg(par, 0x49, 0x013F); 71 | write_reg(par, 0x4A, 0x0000); 72 | write_reg(par, 0x4B, 0x0000); 73 | write_reg(par, 0x44, 0xEF00); 74 | write_reg(par, 0x45, 0x0000); 75 | write_reg(par, 0x46, 0x013F); 76 | write_reg(par, 0x23, 0x0000); 77 | write_reg(par, 0x24, 0x0000); 78 | write_reg(par, 0x25, 0x8000); 79 | write_reg(par, 0x4f, 0x0000); 80 | write_reg(par, 0x4e, 0x0000); 81 | write_reg(par, 0x22); 82 | return 0; 83 | } 84 | 85 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 86 | { 87 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 88 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 89 | 90 | switch (par->info->var.rotate) { 91 | /* R4Eh - Set GDDRAM X address counter */ 92 | /* R4Fh - Set GDDRAM Y address counter */ 93 | case 0: 94 | write_reg(par, 0x4e, xs); 95 | write_reg(par, 0x4f, ys); 96 | break; 97 | case 180: 98 | write_reg(par, 0x4e, par->info->var.xres - 1 - xs); 99 | write_reg(par, 0x4f, par->info->var.yres - 1 - ys); 100 | break; 101 | case 270: 102 | write_reg(par, 0x4e, par->info->var.yres - 1 - ys); 103 | write_reg(par, 0x4f, xs); 104 | break; 105 | case 90: 106 | write_reg(par, 0x4e, ys); 107 | write_reg(par, 0x4f, par->info->var.xres - 1 - xs); 108 | break; 109 | } 110 | 111 | /* R22h - RAM data write */ 112 | write_reg(par, 0x22); 113 | } 114 | 115 | static int set_var(struct fbtft_par *par) 116 | { 117 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 118 | 119 | if (par->fbtftops.init_display != init_display) { 120 | /* don't risk messing up register 11h */ 121 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, 122 | "%s: skipping since custom init_display() is used\n", 123 | __func__); 124 | return 0; 125 | } 126 | 127 | switch (par->info->var.rotate) { 128 | case 0: 129 | write_reg(par, 0x11, reg11 | 0b110000); 130 | break; 131 | case 270: 132 | write_reg(par, 0x11, reg11 | 0b101000); 133 | break; 134 | case 180: 135 | write_reg(par, 0x11, reg11 | 0b000000); 136 | break; 137 | case 90: 138 | write_reg(par, 0x11, reg11 | 0b011000); 139 | break; 140 | } 141 | 142 | return 0; 143 | } 144 | 145 | /* 146 | Gamma string format: 147 | VRP0 VRP1 PRP0 PRP1 PKP0 PKP1 PKP2 PKP3 PKP4 PKP5 148 | VRN0 VRN1 PRN0 PRN1 PKN0 PKN1 PKN2 PKN3 PKN4 PKN5 149 | */ 150 | #define CURVE(num, idx) curves[num*par->gamma.num_values + idx] 151 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 152 | { 153 | unsigned long mask[] = { 154 | 0b11111, 0b11111, 0b111, 0b111, 0b111, 155 | 0b111, 0b111, 0b111, 0b111, 0b111, 156 | 0b11111, 0b11111, 0b111, 0b111, 0b111, 157 | 0b111, 0b111, 0b111, 0b111, 0b111 }; 158 | int i, j; 159 | 160 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 161 | 162 | /* apply mask */ 163 | for (i = 0; i < 2; i++) 164 | for (j = 0; j < 10; j++) 165 | CURVE(i, j) &= mask[i*par->gamma.num_values + j]; 166 | 167 | write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4)); 168 | write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6)); 169 | write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8)); 170 | write_reg(par, 0x0033, CURVE(0, 3) << 8 | CURVE(0, 2)); 171 | write_reg(par, 0x0034, CURVE(1, 5) << 8 | CURVE(1, 4)); 172 | write_reg(par, 0x0035, CURVE(1, 7) << 8 | CURVE(1, 6)); 173 | write_reg(par, 0x0036, CURVE(1, 9) << 8 | CURVE(1, 8)); 174 | write_reg(par, 0x0037, CURVE(1, 3) << 8 | CURVE(1, 2)); 175 | write_reg(par, 0x003A, CURVE(0, 1) << 8 | CURVE(0, 0)); 176 | write_reg(par, 0x003B, CURVE(1, 1) << 8 | CURVE(1, 0)); 177 | 178 | return 0; 179 | } 180 | #undef CURVE 181 | 182 | 183 | static struct fbtft_display display = { 184 | .regwidth = 16, 185 | .width = WIDTH, 186 | .height = HEIGHT, 187 | .gamma_num = 2, 188 | .gamma_len = 10, 189 | .gamma = DEFAULT_GAMMA, 190 | .fbtftops = { 191 | .init_display = init_display, 192 | .set_addr_win = set_addr_win, 193 | .set_var = set_var, 194 | .set_gamma = set_gamma, 195 | }, 196 | }; 197 | FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1289", &display); 198 | 199 | MODULE_ALIAS("spi:" DRVNAME); 200 | MODULE_ALIAS("platform:" DRVNAME); 201 | MODULE_ALIAS("spi:ssd1289"); 202 | MODULE_ALIAS("platform:ssd1289"); 203 | 204 | MODULE_DESCRIPTION("FB driver for the SSD1289 LCD Controller"); 205 | MODULE_AUTHOR("Noralf Tronnes"); 206 | MODULE_LICENSE("GPL"); 207 | -------------------------------------------------------------------------------- /fb_ssd1306.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the SSD1306 OLED Controller 3 | * 4 | * Copyright (C) 2013 Noralf Tronnes 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "fbtft.h" 28 | 29 | #define DRVNAME "fb_ssd1306" 30 | #define WIDTH 128 31 | #define HEIGHT 64 32 | 33 | 34 | /* 35 | write_reg() caveat: 36 | 37 | This doesn't work because D/C has to be LOW for both values: 38 | write_reg(par, val1, val2); 39 | 40 | Do it like this: 41 | write_reg(par, val1); 42 | write_reg(par, val2); 43 | */ 44 | 45 | /* Init sequence taken from the Adafruit SSD1306 Arduino library */ 46 | static int init_display(struct fbtft_par *par) 47 | { 48 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 49 | 50 | par->fbtftops.reset(par); 51 | 52 | if (par->gamma.curves[0] == 0) { 53 | mutex_lock(&par->gamma.lock); 54 | if (par->info->var.yres == 64) 55 | par->gamma.curves[0] = 0xCF; 56 | else 57 | par->gamma.curves[0] = 0x8F; 58 | mutex_unlock(&par->gamma.lock); 59 | } 60 | 61 | /* Set Display OFF */ 62 | write_reg(par, 0xAE); 63 | 64 | /* Set Display Clock Divide Ratio/ Oscillator Frequency */ 65 | write_reg(par, 0xD5); 66 | write_reg(par, 0x80); 67 | 68 | /* Set Multiplex Ratio */ 69 | write_reg(par, 0xA8); 70 | if (par->info->var.yres == 64) 71 | write_reg(par, 0x3F); 72 | else 73 | write_reg(par, 0x1F); 74 | 75 | /* Set Display Offset */ 76 | write_reg(par, 0xD3); 77 | write_reg(par, 0x0); 78 | 79 | /* Set Display Start Line */ 80 | write_reg(par, 0x40 | 0x0); 81 | 82 | /* Charge Pump Setting */ 83 | write_reg(par, 0x8D); 84 | /* A[2] = 1b, Enable charge pump during display on */ 85 | write_reg(par, 0x14); 86 | 87 | /* Set Memory Addressing Mode */ 88 | write_reg(par, 0x20); 89 | /* Vertical addressing mode */ 90 | write_reg(par, 0x01); 91 | 92 | /*Set Segment Re-map */ 93 | /* column address 127 is mapped to SEG0 */ 94 | write_reg(par, 0xA0 | 0x1); 95 | 96 | /* Set COM Output Scan Direction */ 97 | /* remapped mode. Scan from COM[N-1] to COM0 */ 98 | write_reg(par, 0xC8); 99 | 100 | /* Set COM Pins Hardware Configuration */ 101 | write_reg(par, 0xDA); 102 | if (par->info->var.yres == 64) 103 | /* A[4]=1b, Alternative COM pin configuration */ 104 | write_reg(par, 0x12); 105 | else 106 | /* A[4]=0b, Sequential COM pin configuration */ 107 | write_reg(par, 0x02); 108 | 109 | /* Set Pre-charge Period */ 110 | write_reg(par, 0xD9); 111 | write_reg(par, 0xF1); 112 | 113 | /* Set VCOMH Deselect Level */ 114 | write_reg(par, 0xDB); 115 | /* according to the datasheet, this value is out of bounds */ 116 | write_reg(par, 0x40); 117 | 118 | /* Entire Display ON */ 119 | /* Resume to RAM content display. Output follows RAM content */ 120 | write_reg(par, 0xA4); 121 | 122 | /* Set Normal Display 123 | 0 in RAM: OFF in display panel 124 | 1 in RAM: ON in display panel */ 125 | write_reg(par, 0xA6); 126 | 127 | /* Set Display ON */ 128 | write_reg(par, 0xAF); 129 | 130 | return 0; 131 | } 132 | 133 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 134 | { 135 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 136 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 137 | 138 | /* Set Lower Column Start Address for Page Addressing Mode */ 139 | write_reg(par, 0x00 | 0x0); 140 | /* Set Higher Column Start Address for Page Addressing Mode */ 141 | write_reg(par, 0x10 | 0x0); 142 | /* Set Display Start Line */ 143 | write_reg(par, 0x40 | 0x0); 144 | } 145 | 146 | static int blank(struct fbtft_par *par, bool on) 147 | { 148 | fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", 149 | __func__, on ? "true" : "false"); 150 | 151 | if (on) 152 | write_reg(par, 0xAE); 153 | else 154 | write_reg(par, 0xAF); 155 | return 0; 156 | } 157 | 158 | /* Gamma is used to control Contrast */ 159 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 160 | { 161 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 162 | 163 | /* apply mask */ 164 | curves[0] &= 0xFF; 165 | 166 | /* Set Contrast Control for BANK0 */ 167 | write_reg(par, 0x81); 168 | write_reg(par, curves[0]); 169 | 170 | return 0; 171 | } 172 | 173 | static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) 174 | { 175 | u16 *vmem16 = (u16 *)par->info->screen_base; 176 | u8 *buf = par->txbuf.buf; 177 | int x, y, i; 178 | int ret = 0; 179 | 180 | fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); 181 | 182 | for (x = 0; x < par->info->var.xres; x++) { 183 | for (y = 0; y < par->info->var.yres/8; y++) { 184 | *buf = 0x00; 185 | for (i = 0; i < 8; i++) 186 | *buf |= (vmem16[(y*8+i)*par->info->var.xres+x] ? 1 : 0) << i; 187 | buf++; 188 | } 189 | } 190 | 191 | /* Write data */ 192 | gpio_set_value(par->gpio.dc, 1); 193 | ret = par->fbtftops.write(par, par->txbuf.buf, 194 | par->info->var.xres*par->info->var.yres/8); 195 | if (ret < 0) 196 | dev_err(par->info->device, 197 | "%s: write failed and returned: %d\n", __func__, ret); 198 | 199 | return ret; 200 | } 201 | 202 | 203 | static struct fbtft_display display = { 204 | .regwidth = 8, 205 | .width = WIDTH, 206 | .height = HEIGHT, 207 | .gamma_num = 1, 208 | .gamma_len = 1, 209 | .gamma = "00", 210 | .fbtftops = { 211 | .write_vmem = write_vmem, 212 | .init_display = init_display, 213 | .set_addr_win = set_addr_win, 214 | .blank = blank, 215 | .set_gamma = set_gamma, 216 | }, 217 | }; 218 | 219 | 220 | FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1306", &display); 221 | 222 | MODULE_ALIAS("spi:" DRVNAME); 223 | MODULE_ALIAS("platform:" DRVNAME); 224 | MODULE_ALIAS("spi:ssd1306"); 225 | MODULE_ALIAS("platform:ssd1306"); 226 | 227 | MODULE_DESCRIPTION("SSD1306 OLED Driver"); 228 | MODULE_AUTHOR("Noralf Tronnes"); 229 | MODULE_LICENSE("GPL"); 230 | -------------------------------------------------------------------------------- /fb_ssd1331.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "fbtft.h" 9 | 10 | #define DRVNAME "fb_ssd1331" 11 | #define WIDTH 96 12 | #define HEIGHT 64 13 | #define GAMMA_NUM 1 14 | #define GAMMA_LEN 63 15 | #define DEFAULT_GAMMA "0 2 2 2 2 2 2 2 " \ 16 | "2 2 2 2 2 2 2 2 " \ 17 | "2 2 2 2 2 2 2 2 " \ 18 | "2 2 2 2 2 2 2 2 " \ 19 | "2 2 2 2 2 2 2 2 " \ 20 | "2 2 2 2 2 2 2 2 " \ 21 | "2 2 2 2 2 2 2 2 " \ 22 | "2 2 2 2 2 2 2" \ 23 | 24 | static int init_display(struct fbtft_par *par) 25 | { 26 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 27 | 28 | par->fbtftops.reset(par); 29 | 30 | write_reg(par, 0xae); /* Display Off */ 31 | write_reg(par, 0xa0, 0x70 | (par->bgr << 2)); /* Set Colour Depth */ 32 | write_reg(par, 0x72); // RGB colour 33 | write_reg(par, 0xa1, 0x00); /* Set Display Start Line */ 34 | write_reg(par, 0xa2, 0x00); /* Set Display Offset */ 35 | write_reg(par, 0xa4); /* NORMALDISPLAY */ 36 | write_reg(par, 0xa8, 0x3f); // Set multiplex 37 | write_reg(par, 0xad, 0x8e); // Set master 38 | // write_reg(par, 0xb0, 0x0b); // Set power mode 39 | write_reg(par, 0xb1, 0x31); // Precharge 40 | write_reg(par, 0xb3, 0xf0); // Clock div 41 | write_reg(par, 0x8a, 0x64); // Precharge A 42 | write_reg(par, 0x8b, 0x78); // Precharge B 43 | write_reg(par, 0x8c, 0x64); // Precharge C 44 | write_reg(par, 0xbb, 0x3a); // Precharge level 45 | write_reg(par, 0xbe, 0x3e); // vcomh 46 | write_reg(par, 0x87, 0x06); // Master current 47 | write_reg(par, 0x81, 0x91); // Contrast A 48 | write_reg(par, 0x82, 0x50); // Contrast B 49 | write_reg(par, 0x83, 0x7d); // Contrast C 50 | write_reg(par, 0xaf); /* Set Sleep Mode Display On */ 51 | 52 | return 0; 53 | } 54 | 55 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 56 | { 57 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 58 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 59 | 60 | write_reg(par, 0x15, xs, xe); 61 | write_reg(par, 0x75, ys, ye); 62 | } 63 | 64 | static void write_reg8_bus8(struct fbtft_par *par, int len, ...) 65 | { 66 | va_list args; 67 | int i, ret; 68 | u8 *buf = (u8 *)par->buf; 69 | 70 | if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { 71 | va_start(args, len); 72 | for (i = 0; i < len; i++) { 73 | buf[i] = (u8)va_arg(args, unsigned int); 74 | } 75 | va_end(args); 76 | fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, u8, buf, len, "%s: ", __func__); 77 | } 78 | 79 | va_start(args, len); 80 | 81 | *buf = (u8)va_arg(args, unsigned int); 82 | if (par->gpio.dc != -1) 83 | gpio_set_value(par->gpio.dc, 0); 84 | ret = par->fbtftops.write(par, par->buf, sizeof(u8)); 85 | if (ret < 0) { 86 | va_end(args); 87 | dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); 88 | return; 89 | } 90 | len--; 91 | 92 | if (len) { 93 | i = len; 94 | while (i--) { 95 | *buf++ = (u8)va_arg(args, unsigned int); 96 | } 97 | ret = par->fbtftops.write(par, par->buf, len * (sizeof(u8))); 98 | if (ret < 0) { 99 | va_end(args); 100 | dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); 101 | return; 102 | } 103 | } 104 | if (par->gpio.dc != -1) 105 | gpio_set_value(par->gpio.dc, 1); 106 | va_end(args); 107 | } 108 | 109 | /* 110 | Grayscale Lookup Table 111 | GS1 - GS63 112 | The driver Gamma curve contains the relative values between the entries 113 | in the Lookup table. 114 | 115 | From datasheet: 116 | 8.8 Gray Scale Decoder 117 | 118 | there are total 180 Gamma Settings (Setting 0 to Setting 180) 119 | available for the Gray Scale table. 120 | 121 | The gray scale is defined in incremental way, with reference 122 | to the length of previous table entry: 123 | Setting of GS1 has to be >= 0 124 | Setting of GS2 has to be > Setting of GS1 +1 125 | Setting of GS3 has to be > Setting of GS2 +1 126 | : 127 | Setting of GS63 has to be > Setting of GS62 +1 128 | 129 | 130 | */ 131 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 132 | { 133 | unsigned long tmp[GAMMA_NUM * GAMMA_LEN]; 134 | int i, acc = 0; 135 | 136 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 137 | 138 | for (i = 0; i < 63; i++) { 139 | if (i > 0 && curves[i] < 2) { 140 | dev_err(par->info->device, 141 | "Illegal value in Grayscale Lookup Table at index %d. " \ 142 | "Must be greater than 1\n", i); 143 | return -EINVAL; 144 | } 145 | acc += curves[i]; 146 | tmp[i] = acc; 147 | if (acc > 180) { 148 | dev_err(par->info->device, 149 | "Illegal value(s) in Grayscale Lookup Table. " \ 150 | "At index=%d, the accumulated value has exceeded 180\n", i); 151 | return -EINVAL; 152 | } 153 | } 154 | 155 | write_reg(par, 0xB8, 156 | tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], 157 | tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15], 158 | tmp[16], tmp[17], tmp[18], tmp[19], tmp[20], tmp[21], tmp[22], tmp[23], 159 | tmp[24], tmp[25], tmp[26], tmp[27], tmp[28], tmp[29], tmp[30], tmp[31], 160 | tmp[32], tmp[33], tmp[34], tmp[35], tmp[36], tmp[37], tmp[38], tmp[39], 161 | tmp[40], tmp[41], tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47], 162 | tmp[48], tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55], 163 | tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61], tmp[62]); 164 | 165 | return 0; 166 | } 167 | 168 | static int blank(struct fbtft_par *par, bool on) 169 | { 170 | fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", 171 | __func__, on ? "true" : "false"); 172 | if (on) 173 | write_reg(par, 0xAE); 174 | else 175 | write_reg(par, 0xAF); 176 | return 0; 177 | } 178 | 179 | 180 | static struct fbtft_display display = { 181 | .regwidth = 8, 182 | .width = WIDTH, 183 | .height = HEIGHT, 184 | .gamma_num = GAMMA_NUM, 185 | .gamma_len = GAMMA_LEN, 186 | .gamma = DEFAULT_GAMMA, 187 | .fbtftops = { 188 | .write_register = write_reg8_bus8, 189 | .init_display = init_display, 190 | .set_addr_win = set_addr_win, 191 | .set_gamma = set_gamma, 192 | .blank = blank, 193 | }, 194 | }; 195 | 196 | FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1331", &display); 197 | 198 | MODULE_ALIAS("spi:" DRVNAME); 199 | MODULE_ALIAS("platform:" DRVNAME); 200 | MODULE_ALIAS("spi:ssd1331"); 201 | MODULE_ALIAS("platform:ssd1331"); 202 | 203 | MODULE_DESCRIPTION("SSD1331 OLED Driver"); 204 | MODULE_AUTHOR("Alec Smecher (adapted from SSD1351 by James Davies)"); 205 | MODULE_LICENSE("GPL"); 206 | -------------------------------------------------------------------------------- /fb_ssd1351.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "fbtft.h" 9 | 10 | #define DRVNAME "fb_ssd1351" 11 | #define WIDTH 128 12 | #define HEIGHT 128 13 | #define GAMMA_NUM 1 14 | #define GAMMA_LEN 63 15 | #define DEFAULT_GAMMA "0 2 2 2 2 2 2 2 " \ 16 | "2 2 2 2 2 2 2 2 " \ 17 | "2 2 2 2 2 2 2 2 " \ 18 | "2 2 2 2 2 2 2 2 " \ 19 | "2 2 2 2 2 2 2 2 " \ 20 | "2 2 2 2 2 2 2 2 " \ 21 | "2 2 2 2 2 2 2 2 " \ 22 | "2 2 2 2 2 2 2" \ 23 | 24 | static void register_onboard_backlight(struct fbtft_par *par); 25 | 26 | static int init_display(struct fbtft_par *par) 27 | { 28 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 29 | 30 | if (par->pdata 31 | && par->pdata->display.backlight == FBTFT_ONBOARD_BACKLIGHT) { 32 | /* module uses onboard GPIO for panel power */ 33 | par->fbtftops.register_backlight = register_onboard_backlight; 34 | } 35 | 36 | par->fbtftops.reset(par); 37 | 38 | write_reg(par, 0xfd, 0x12); /* Command Lock */ 39 | write_reg(par, 0xfd, 0xb1); /* Command Lock */ 40 | write_reg(par, 0xae); /* Display Off */ 41 | write_reg(par, 0xb3, 0xf1); /* Front Clock Div */ 42 | write_reg(par, 0xca, 0x7f); /* Set Mux Ratio */ 43 | write_reg(par, 0x15, 0x00, 0x7f); /* Set Column Address */ 44 | write_reg(par, 0x75, 0x00, 0x7f); /* Set Row Address */ 45 | write_reg(par, 0xa1, 0x00); /* Set Display Start Line */ 46 | write_reg(par, 0xa2, 0x00); /* Set Display Offset */ 47 | write_reg(par, 0xb5, 0x00); /* Set GPIO */ 48 | write_reg(par, 0xab, 0x01); /* Set Function Selection */ 49 | write_reg(par, 0xb1, 0x32); /* Set Phase Length */ 50 | write_reg(par, 0xb4, 0xa0, 0xb5, 0x55); /* Set Segment Low Voltage */ 51 | write_reg(par, 0xbb, 0x17); /* Set Precharge Voltage */ 52 | write_reg(par, 0xbe, 0x05); /* Set VComH Voltage */ 53 | write_reg(par, 0xc1, 0xc8, 0x80, 0xc8); /* Set Contrast */ 54 | write_reg(par, 0xc7, 0x0f); /* Set Master Contrast */ 55 | write_reg(par, 0xb6, 0x01); /* Set Second Precharge Period */ 56 | write_reg(par, 0xa6); /* Set Display Mode Reset */ 57 | write_reg(par, 0xaf); /* Set Sleep Mode Display On */ 58 | 59 | return 0; 60 | } 61 | 62 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 63 | { 64 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 65 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 66 | 67 | write_reg(par, 0x15, xs, xe); 68 | write_reg(par, 0x75, ys, ye); 69 | write_reg(par, 0x5c); 70 | } 71 | 72 | static int set_var(struct fbtft_par *par) 73 | { 74 | unsigned remap; 75 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 76 | 77 | if (par->fbtftops.init_display != init_display) { 78 | /* don't risk messing up register A0h */ 79 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, 80 | "%s: skipping since custom init_display() is used\n", 81 | __func__); 82 | return 0; 83 | } 84 | 85 | remap = 0x60 | (par->bgr << 2); /* Set Colour Depth */ 86 | 87 | switch (par->info->var.rotate) { 88 | case 0: 89 | write_reg(par, 0xA0, remap | 0b00 | 1<<4); 90 | break; 91 | case 270: 92 | write_reg(par, 0xA0, remap | 0b11 | 1<<4); 93 | break; 94 | case 180: 95 | write_reg(par, 0xA0, remap | 0b10); 96 | break; 97 | case 90: 98 | write_reg(par, 0xA0, remap | 0b01); 99 | break; 100 | } 101 | 102 | return 0; 103 | } 104 | 105 | /* 106 | Grayscale Lookup Table 107 | GS1 - GS63 108 | The driver Gamma curve contains the relative values between the entries 109 | in the Lookup table. 110 | 111 | From datasheet: 112 | 8.8 Gray Scale Decoder 113 | 114 | there are total 180 Gamma Settings (Setting 0 to Setting 180) 115 | available for the Gray Scale table. 116 | 117 | The gray scale is defined in incremental way, with reference 118 | to the length of previous table entry: 119 | Setting of GS1 has to be >= 0 120 | Setting of GS2 has to be > Setting of GS1 +1 121 | Setting of GS3 has to be > Setting of GS2 +1 122 | : 123 | Setting of GS63 has to be > Setting of GS62 +1 124 | 125 | 126 | */ 127 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 128 | { 129 | unsigned long tmp[GAMMA_NUM * GAMMA_LEN]; 130 | int i, acc = 0; 131 | 132 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 133 | 134 | for (i = 0; i < 63; i++) { 135 | if (i > 0 && curves[i] < 2) { 136 | dev_err(par->info->device, 137 | "Illegal value in Grayscale Lookup Table at index %d. " \ 138 | "Must be greater than 1\n", i); 139 | return -EINVAL; 140 | } 141 | acc += curves[i]; 142 | tmp[i] = acc; 143 | if (acc > 180) { 144 | dev_err(par->info->device, 145 | "Illegal value(s) in Grayscale Lookup Table. " \ 146 | "At index=%d, the accumulated value has exceeded 180\n", i); 147 | return -EINVAL; 148 | } 149 | } 150 | 151 | write_reg(par, 0xB8, 152 | tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], 153 | tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15], 154 | tmp[16], tmp[17], tmp[18], tmp[19], tmp[20], tmp[21], tmp[22], tmp[23], 155 | tmp[24], tmp[25], tmp[26], tmp[27], tmp[28], tmp[29], tmp[30], tmp[31], 156 | tmp[32], tmp[33], tmp[34], tmp[35], tmp[36], tmp[37], tmp[38], tmp[39], 157 | tmp[40], tmp[41], tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47], 158 | tmp[48], tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55], 159 | tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61], tmp[62]); 160 | 161 | return 0; 162 | } 163 | 164 | static int blank(struct fbtft_par *par, bool on) 165 | { 166 | fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", 167 | __func__, on ? "true" : "false"); 168 | if (on) 169 | write_reg(par, 0xAE); 170 | else 171 | write_reg(par, 0xAF); 172 | return 0; 173 | } 174 | 175 | 176 | static struct fbtft_display display = { 177 | .regwidth = 8, 178 | .width = WIDTH, 179 | .height = HEIGHT, 180 | .gamma_num = GAMMA_NUM, 181 | .gamma_len = GAMMA_LEN, 182 | .gamma = DEFAULT_GAMMA, 183 | .fbtftops = { 184 | .init_display = init_display, 185 | .set_addr_win = set_addr_win, 186 | .set_var = set_var, 187 | .set_gamma = set_gamma, 188 | .blank = blank, 189 | }, 190 | }; 191 | 192 | #ifdef CONFIG_FB_BACKLIGHT 193 | static int update_onboard_backlight(struct backlight_device *bd) 194 | { 195 | struct fbtft_par *par = bl_get_data(bd); 196 | bool on; 197 | 198 | fbtft_par_dbg(DEBUG_BACKLIGHT, par, 199 | "%s: power=%d, fb_blank=%d\n", 200 | __func__, bd->props.power, bd->props.fb_blank); 201 | 202 | on = (bd->props.power == FB_BLANK_UNBLANK) 203 | && (bd->props.fb_blank == FB_BLANK_UNBLANK); 204 | /* Onboard backlight connected to GPIO0 on SSD1351, GPIO1 unused */ 205 | write_reg(par, 0xB5, on ? 0x03 : 0x02); 206 | 207 | return 0; 208 | } 209 | 210 | static void register_onboard_backlight(struct fbtft_par *par) 211 | { 212 | struct backlight_device *bd; 213 | struct backlight_properties bl_props = { 0, }; 214 | struct backlight_ops *bl_ops; 215 | 216 | fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__); 217 | 218 | bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops), 219 | GFP_KERNEL); 220 | if (!bl_ops) { 221 | dev_err(par->info->device, 222 | "%s: could not allocate memory for backlight operations.\n", 223 | __func__); 224 | return; 225 | } 226 | 227 | bl_ops->update_status = update_onboard_backlight; 228 | bl_props.type = BACKLIGHT_RAW; 229 | bl_props.power = FB_BLANK_POWERDOWN; 230 | 231 | bd = backlight_device_register(dev_driver_string(par->info->device), 232 | par->info->device, par, bl_ops, &bl_props); 233 | if (IS_ERR(bd)) { 234 | dev_err(par->info->device, 235 | "cannot register backlight device (%ld)\n", 236 | PTR_ERR(bd)); 237 | return; 238 | } 239 | par->info->bl_dev = bd; 240 | 241 | if (!par->fbtftops.unregister_backlight) 242 | par->fbtftops.unregister_backlight = fbtft_unregister_backlight; 243 | } 244 | #else 245 | static void register_onboard_backlight(struct fbtft_par *par) { }; 246 | #endif 247 | 248 | 249 | FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1351", &display); 250 | 251 | MODULE_ALIAS("spi:" DRVNAME); 252 | MODULE_ALIAS("platform:" DRVNAME); 253 | MODULE_ALIAS("spi:ssd1351"); 254 | MODULE_ALIAS("platform:ssd1351"); 255 | 256 | MODULE_DESCRIPTION("SSD1351 OLED Driver"); 257 | MODULE_AUTHOR("James Davies"); 258 | MODULE_LICENSE("GPL"); 259 | -------------------------------------------------------------------------------- /fb_st7735r.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the ST7735R LCD Controller 3 | * 4 | * Copyright (C) 2013 Noralf Tronnes 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "fbtft.h" 26 | 27 | #define DRVNAME "fb_st7735r" 28 | #define DEFAULT_GAMMA "0F 1A 0F 18 2F 28 20 22 1F 1B 23 37 00 07 02 10\n" \ 29 | "0F 1B 0F 17 33 2C 29 2E 30 30 39 3F 00 07 03 10" 30 | 31 | 32 | static int default_init_sequence[] = { 33 | /* SWRESET - Software reset */ 34 | -1, 0x01, 35 | -2, 150, /* delay */ 36 | 37 | /* SLPOUT - Sleep out & booster on */ 38 | -1, 0x11, 39 | -2, 500, /* delay */ 40 | 41 | /* FRMCTR1 - frame rate control: normal mode 42 | frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D) */ 43 | -1, 0xB1, 0x01, 0x2C, 0x2D, 44 | 45 | /* FRMCTR2 - frame rate control: idle mode 46 | frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D) */ 47 | -1, 0xB2, 0x01, 0x2C, 0x2D, 48 | 49 | /* FRMCTR3 - frame rate control - partial mode 50 | dot inversion mode, line inversion mode */ 51 | -1, 0xB3, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D, 52 | 53 | /* INVCTR - display inversion control 54 | no inversion */ 55 | -1, 0xB4, 0x07, 56 | 57 | /* PWCTR1 - Power Control 58 | -4.6V, AUTO mode */ 59 | -1, 0xC0, 0xA2, 0x02, 0x84, 60 | 61 | /* PWCTR2 - Power Control 62 | VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD */ 63 | -1, 0xC1, 0xC5, 64 | 65 | /* PWCTR3 - Power Control 66 | Opamp current small, Boost frequency */ 67 | -1, 0xC2, 0x0A, 0x00, 68 | 69 | /* PWCTR4 - Power Control 70 | BCLK/2, Opamp current small & Medium low */ 71 | -1, 0xC3,0x8A,0x2A, 72 | 73 | /* PWCTR5 - Power Control */ 74 | -1, 0xC4, 0x8A, 0xEE, 75 | 76 | /* VMCTR1 - Power Control */ 77 | -1, 0xC5, 0x0E, 78 | 79 | /* INVOFF - Display inversion off */ 80 | -1, 0x20, 81 | 82 | /* COLMOD - Interface pixel format */ 83 | -1, 0x3A, 0x05, 84 | 85 | /* DISPON - Display On */ 86 | -1, 0x29, 87 | -2, 100, /* delay */ 88 | 89 | /* NORON - Partial off (Normal) */ 90 | -1, 0x13, 91 | -2, 10, /* delay */ 92 | 93 | /* end marker */ 94 | -3 95 | }; 96 | 97 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 98 | { 99 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 100 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 101 | 102 | /* Column address */ 103 | write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); 104 | 105 | /* Row adress */ 106 | write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); 107 | 108 | /* Memory write */ 109 | write_reg(par, 0x2C); 110 | } 111 | 112 | #define MY (1 << 7) 113 | #define MX (1 << 6) 114 | #define MV (1 << 5) 115 | static int set_var(struct fbtft_par *par) 116 | { 117 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 118 | 119 | /* MADCTL - Memory data access control 120 | RGB/BGR: 121 | 1. Mode selection pin SRGB 122 | RGB H/W pin for color filter setting: 0=RGB, 1=BGR 123 | 2. MADCTL RGB bit 124 | RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR */ 125 | switch (par->info->var.rotate) { 126 | case 0: 127 | write_reg(par, 0x36, MX | MY | (par->bgr << 3)); 128 | break; 129 | case 270: 130 | write_reg(par, 0x36, MY | MV | (par->bgr << 3)); 131 | break; 132 | case 180: 133 | write_reg(par, 0x36, (par->bgr << 3)); 134 | break; 135 | case 90: 136 | write_reg(par, 0x36, MX | MV | (par->bgr << 3)); 137 | break; 138 | } 139 | 140 | return 0; 141 | } 142 | 143 | /* 144 | Gamma string format: 145 | VRF0P VOS0P PK0P PK1P PK2P PK3P PK4P PK5P PK6P PK7P PK8P PK9P SELV0P SELV1P SELV62P SELV63P 146 | VRF0N VOS0N PK0N PK1N PK2N PK3N PK4N PK5N PK6N PK7N PK8N PK9N SELV0N SELV1N SELV62N SELV63N 147 | */ 148 | #define CURVE(num, idx) curves[num*par->gamma.num_values + idx] 149 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 150 | { 151 | int i,j; 152 | 153 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 154 | 155 | /* apply mask */ 156 | for (i = 0; i < par->gamma.num_curves; i++) 157 | for (j = 0; j < par->gamma.num_values; j++) 158 | CURVE(i,j) &= 0b111111; 159 | 160 | for (i = 0; i < par->gamma.num_curves; i++) 161 | write_reg(par, 0xE0 + i, 162 | CURVE(i, 0), CURVE(i, 1), CURVE(i, 2), CURVE(i, 3), 163 | CURVE(i, 4), CURVE(i, 5), CURVE(i, 6), CURVE(i, 7), 164 | CURVE(i, 8), CURVE(i, 9), CURVE(i, 10), CURVE(i, 11), 165 | CURVE(i, 12), CURVE(i, 13), CURVE(i, 14), CURVE(i,15)); 166 | 167 | return 0; 168 | } 169 | #undef CURVE 170 | 171 | 172 | static struct fbtft_display display = { 173 | .regwidth = 8, 174 | .width = 128, 175 | .height = 160, 176 | .init_sequence = default_init_sequence, 177 | .gamma_num = 2, 178 | .gamma_len = 16, 179 | .gamma = DEFAULT_GAMMA, 180 | .fbtftops = { 181 | .set_addr_win = set_addr_win, 182 | .set_var = set_var, 183 | .set_gamma = set_gamma, 184 | }, 185 | }; 186 | FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7735r", &display); 187 | 188 | MODULE_ALIAS("spi:" DRVNAME); 189 | MODULE_ALIAS("platform:" DRVNAME); 190 | MODULE_ALIAS("spi:st7735r"); 191 | MODULE_ALIAS("platform:st7735r"); 192 | 193 | MODULE_DESCRIPTION("FB driver for the ST7735R LCD Controller"); 194 | MODULE_AUTHOR("Noralf Tronnes"); 195 | MODULE_LICENSE("GPL"); 196 | -------------------------------------------------------------------------------- /fb_tinylcd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Custom FB driver for tinylcd.com display 3 | * 4 | * Copyright (C) 2013 Noralf Tronnes 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "fbtft.h" 27 | 28 | #define DRVNAME "fb_tinylcd" 29 | #define WIDTH 320 30 | #define HEIGHT 480 31 | 32 | 33 | static int init_display(struct fbtft_par *par) 34 | { 35 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 36 | 37 | par->fbtftops.reset(par); 38 | 39 | write_reg(par, 0xB0, 0x80); 40 | write_reg(par, 0xC0, 0x0A, 0x0A); 41 | write_reg(par, 0xC1, 0x45, 0x07); 42 | write_reg(par, 0xC2, 0x33); 43 | write_reg(par, 0xC5, 0x00, 0x42, 0x80); 44 | write_reg(par, 0xB1, 0xD0, 0x11); 45 | write_reg(par, 0xB4, 0x02); 46 | write_reg(par, 0xB6, 0x00, 0x22, 0x3B); 47 | write_reg(par, 0xB7, 0x07); 48 | write_reg(par, 0x36, 0x58); 49 | write_reg(par, 0xF0, 0x36, 0xA5, 0xD3); 50 | write_reg(par, 0xE5, 0x80); 51 | write_reg(par, 0xE5, 0x01); 52 | write_reg(par, 0xB3, 0x00); 53 | write_reg(par, 0xE5, 0x00); 54 | write_reg(par, 0xF0, 0x36, 0xA5, 0x53); 55 | write_reg(par, 0xE0, 0x00, 0x35, 0x33, 0x00, 0x00, 0x00, 56 | 0x00, 0x35, 0x33, 0x00, 0x00, 0x00); 57 | write_reg(par, 0x3A, 0x55); 58 | write_reg(par, 0x11); 59 | udelay(250); 60 | write_reg(par, 0x29); 61 | 62 | return 0; 63 | } 64 | 65 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 66 | { 67 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 68 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 69 | 70 | /* Column address */ 71 | write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); 72 | 73 | /* Row adress */ 74 | write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); 75 | 76 | /* Memory write */ 77 | write_reg(par, 0x2C); 78 | } 79 | 80 | static int set_var(struct fbtft_par *par) 81 | { 82 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 83 | 84 | switch (par->info->var.rotate) { 85 | case 270: 86 | write_reg(par, 0xB6, 0x00, 0x02, 0x3B); 87 | write_reg(par, 0x36, 0x28); 88 | break; 89 | case 180: 90 | write_reg(par, 0xB6, 0x00, 0x22, 0x3B); 91 | write_reg(par, 0x36, 0x58); 92 | break; 93 | case 90: 94 | write_reg(par, 0xB6, 0x00, 0x22, 0x3B); 95 | write_reg(par, 0x36, 0x38); 96 | break; 97 | default: 98 | write_reg(par, 0xB6, 0x00, 0x22, 0x3B); 99 | write_reg(par, 0x36, 0x08); 100 | break; 101 | } 102 | 103 | return 0; 104 | } 105 | 106 | 107 | static struct fbtft_display display = { 108 | .regwidth = 8, 109 | .width = WIDTH, 110 | .height = HEIGHT, 111 | .fbtftops = { 112 | .init_display = init_display, 113 | .set_addr_win = set_addr_win, 114 | .set_var = set_var, 115 | }, 116 | }; 117 | FBTFT_REGISTER_DRIVER(DRVNAME, "neosec,tinylcd", &display); 118 | 119 | MODULE_ALIAS("spi:" DRVNAME); 120 | MODULE_ALIAS("spi:tinylcd"); 121 | 122 | MODULE_DESCRIPTION("Custom FB driver for tinylcd.com display"); 123 | MODULE_AUTHOR("Noralf Tronnes"); 124 | MODULE_LICENSE("GPL"); 125 | -------------------------------------------------------------------------------- /fb_tls8204.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the TLS8204 LCD Controller 3 | * 4 | * The display is monochrome and the video memory is RGB565. 5 | * Any pixel value except 0 turns the pixel on. 6 | * 7 | * Copyright (C) 2013 Noralf Tronnes 8 | * Copyright (C) 2014 Michael Hope (adapted for the TLS8204) 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "fbtft.h" 33 | 34 | #define DRVNAME "fb_tls8204" 35 | #define WIDTH 84 36 | #define HEIGHT 48 37 | #define TXBUFLEN WIDTH 38 | #define DEFAULT_GAMMA "40" /* gamma is used to control contrast in this driver */ 39 | 40 | static unsigned bs = 4; 41 | module_param(bs, uint, 0); 42 | MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)"); 43 | 44 | static int init_display(struct fbtft_par *par) 45 | { 46 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 47 | 48 | par->fbtftops.reset(par); 49 | 50 | /* Enter extended command mode */ 51 | write_reg(par, 0x21); /* 5:1 1 52 | 2:0 PD - Powerdown control: chip is active 53 | 1:0 V - Entry mode: horizontal addressing 54 | 0:1 H - Extended instruction set control: extended 55 | */ 56 | 57 | /* H=1 Bias system */ 58 | write_reg(par, 0x10 | (bs & 0x7)); /* 59 | 4:1 1 60 | 3:0 0 61 | 2:x BS2 - Bias System 62 | 1:x BS1 63 | 0:x BS0 64 | */ 65 | 66 | /* Set the address of the first display line. */ 67 | write_reg(par, 0x04 | (64 >> 6)); 68 | write_reg(par, 0x40 | (64 & 0x3F)); 69 | 70 | /* Enter H=0 standard command mode */ 71 | write_reg(par, 0x20); 72 | 73 | /* H=0 Display control */ 74 | write_reg(par, 0x08 | 4); /* 75 | 3:1 1 76 | 2:1 D - DE: 10=normal mode 77 | 1:0 0 78 | 0:0 E 79 | */ 80 | 81 | return 0; 82 | } 83 | 84 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 85 | { 86 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 87 | 88 | /* H=0 Set X address of RAM */ 89 | write_reg(par, 0x80); /* 7:1 1 90 | 6-0: X[6:0] - 0x00 91 | */ 92 | 93 | /* H=0 Set Y address of RAM */ 94 | write_reg(par, 0x40); /* 7:0 0 95 | 6:1 1 96 | 2-0: Y[2:0] - 0x0 97 | */ 98 | } 99 | 100 | static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) 101 | { 102 | u16 *vmem16 = (u16 *)par->info->screen_base; 103 | int x, y, i; 104 | int ret = 0; 105 | 106 | fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); 107 | 108 | for (y = 0; y < HEIGHT/8; y++) { 109 | u8 *buf = par->txbuf.buf; 110 | /* The display is 102x68 but the LCD is 84x48. Set 111 | the write pointer at the start of each row. */ 112 | gpio_set_value(par->gpio.dc, 0); 113 | write_reg(par, 0x80 | 0); 114 | write_reg(par, 0x40 | y); 115 | 116 | for (x = 0; x < WIDTH; x++) { 117 | u8 ch = 0; 118 | for (i = 0; i < 8*WIDTH; i += WIDTH) { 119 | ch >>= 1; 120 | if (vmem16[(y*8*WIDTH)+i+x]) 121 | ch |= 0x80; 122 | } 123 | *buf++ = ch; 124 | } 125 | /* Write the row */ 126 | gpio_set_value(par->gpio.dc, 1); 127 | ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH); 128 | if (ret < 0) { 129 | dev_err(par->info->device, 130 | "%s: write failed and returned: %d\n", __func__, ret); 131 | break; 132 | } 133 | } 134 | 135 | return ret; 136 | } 137 | 138 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) 139 | { 140 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 141 | 142 | /* apply mask */ 143 | curves[0] &= 0x7F; 144 | 145 | write_reg(par, 0x21); /* turn on extended instruction set */ 146 | write_reg(par, 0x80 | curves[0]); 147 | write_reg(par, 0x20); /* turn off extended instruction set */ 148 | 149 | return 0; 150 | } 151 | 152 | 153 | static struct fbtft_display display = { 154 | .regwidth = 8, 155 | .width = WIDTH, 156 | .height = HEIGHT, 157 | .txbuflen = TXBUFLEN, 158 | .gamma_num = 1, 159 | .gamma_len = 1, 160 | .gamma = DEFAULT_GAMMA, 161 | .fbtftops = { 162 | .init_display = init_display, 163 | .set_addr_win = set_addr_win, 164 | .write_vmem = write_vmem, 165 | .set_gamma = set_gamma, 166 | }, 167 | .backlight = 1, 168 | }; 169 | FBTFT_REGISTER_DRIVER(DRVNAME, "teralane,tls8204", &display); 170 | 171 | MODULE_ALIAS("spi:" DRVNAME); 172 | MODULE_ALIAS("spi:tls8204"); 173 | 174 | MODULE_DESCRIPTION("FB driver for the TLS8204 LCD Controller"); 175 | MODULE_AUTHOR("Michael Hope"); 176 | MODULE_LICENSE("GPL"); 177 | -------------------------------------------------------------------------------- /fb_uc1701.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the UC1701 LCD Controller 3 | * 4 | * The display is monochrome and the video memory is RGB565. 5 | * Any pixel value except 0 turns the pixel on. 6 | * 7 | * Copyright (C) 2014 Juergen Holzmann 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "fbtft.h" 32 | 33 | #define DRVNAME "fb_uc1701" 34 | #define WIDTH 102 35 | #define HEIGHT 64 36 | #define PAGES (HEIGHT/8) 37 | 38 | /* 1: Display on/off */ 39 | #define LCD_DISPLAY_ENABLE 0xAE 40 | /* 2: display start line set */ 41 | #define LCD_START_LINE 0x40 42 | /* 3: Page address set (lower 4 bits select one of the pages) */ 43 | #define LCD_PAGE_ADDRESS 0xB0 44 | /* 4: column address */ 45 | #define LCD_COL_ADDRESS 0x10 46 | /* 8: select orientation */ 47 | #define LCD_BOTTOMVIEW 0xA0 48 | /* 9: inverted display */ 49 | #define LCD_DISPLAY_INVERT 0xA6 50 | /* 10: show memory content or switch all pixels on */ 51 | #define LCD_ALL_PIXEL 0xA4 52 | /* 11: lcd bias set */ 53 | #define LCD_BIAS 0xA2 54 | /* 14: Reset Controller */ 55 | #define LCD_RESET_CMD 0xE2 56 | /* 15: output mode select (turns display upside-down) */ 57 | #define LCD_SCAN_DIR 0xC0 58 | /* 16: power control set */ 59 | #define LCD_POWER_CONTROL 0x28 60 | /* 17: voltage regulator resistor ratio set */ 61 | #define LCD_VOLTAGE 0x20 62 | /* 18: Volume mode set */ 63 | #define LCD_VOLUME_MODE 0x81 64 | /* 22: NOP command */ 65 | #define LCD_NO_OP 0xE3 66 | /* 25: advanced program control */ 67 | #define LCD_ADV_PROG_CTRL 0xFA 68 | /* 25: advanced program control2 */ 69 | #define LCD_ADV_PROG_CTRL2 0x10 70 | #define LCD_TEMPCOMP_HIGH 0x80 71 | /* column offset for normal orientation */ 72 | #define SHIFT_ADDR_NORMAL 0 73 | /* column offset for bottom view orientation */ 74 | #define SHIFT_ADDR_TOPVIEW 30 75 | 76 | 77 | static int init_display(struct fbtft_par *par) 78 | { 79 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 80 | 81 | par->fbtftops.reset(par); 82 | 83 | /* softreset of LCD */ 84 | write_reg(par, LCD_RESET_CMD); 85 | mdelay(10); 86 | 87 | /* set startpoint */ 88 | /* LCD_START_LINE | (pos & 0x3F) */ 89 | write_reg(par, LCD_START_LINE); 90 | 91 | /* select orientation BOTTOMVIEW */ 92 | write_reg(par, LCD_BOTTOMVIEW | 1); 93 | /* output mode select (turns display upside-down) */ 94 | write_reg(par, LCD_SCAN_DIR | 0x00); 95 | 96 | /* Normal Pixel mode */ 97 | write_reg(par, LCD_ALL_PIXEL | 0); 98 | 99 | /* positive display */ 100 | write_reg(par, LCD_DISPLAY_INVERT | 0); 101 | 102 | /* bias 1/9 */ 103 | write_reg(par, LCD_BIAS | 0); 104 | 105 | /* power control mode: all features on */ 106 | /* LCD_POWER_CONTROL | (val&0x07) */ 107 | write_reg(par, LCD_POWER_CONTROL | 0x07); 108 | 109 | /* set voltage regulator R/R */ 110 | /* LCD_VOLTAGE | (val&0x07) */ 111 | write_reg(par, LCD_VOLTAGE | 0x07); 112 | 113 | /* volume mode set */ 114 | /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */ 115 | write_reg(par, LCD_VOLUME_MODE); 116 | /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */ 117 | write_reg(par, 0x09); 118 | /* ???? */ 119 | /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */ 120 | write_reg(par, LCD_NO_OP); 121 | 122 | /* advanced program control */ 123 | write_reg(par, LCD_ADV_PROG_CTRL); 124 | write_reg(par, LCD_ADV_PROG_CTRL2|LCD_TEMPCOMP_HIGH); 125 | 126 | /* enable display */ 127 | write_reg(par, LCD_DISPLAY_ENABLE | 1); 128 | 129 | return 0; 130 | } 131 | 132 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 133 | { 134 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 135 | 136 | /* goto address */ 137 | /* LCD_PAGE_ADDRESS | ((page) & 0x1F), 138 | (((col)+SHIFT_ADDR_NORMAL) & 0x0F), 139 | LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ 140 | write_reg(par, LCD_PAGE_ADDRESS); 141 | /* LCD_PAGE_ADDRESS | ((page) & 0x1F), 142 | (((col)+SHIFT_ADDR_NORMAL) & 0x0F), 143 | LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ 144 | write_reg(par, 0x00); 145 | /* LCD_PAGE_ADDRESS | ((page) & 0x1F), 146 | (((col)+SHIFT_ADDR_NORMAL) & 0x0F), 147 | LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ 148 | write_reg(par, LCD_COL_ADDRESS); 149 | } 150 | 151 | static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) 152 | { 153 | u16 *vmem16 = (u16 *)par->info->screen_base; 154 | u8 *buf = par->txbuf.buf; 155 | int x, y, i; 156 | int ret = 0; 157 | 158 | fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); 159 | 160 | for (y = 0; y < PAGES; y++) { 161 | buf = par->txbuf.buf; 162 | for (x = 0; x < WIDTH; x++) { 163 | *buf = 0x00; 164 | for (i = 0; i < 8; i++) 165 | *buf |= (vmem16[((y*8*WIDTH)+(i*WIDTH))+x] ? 1 : 0) << i; 166 | buf++; 167 | } 168 | /* LCD_PAGE_ADDRESS | ((page) & 0x1F), 169 | (((col)+SHIFT_ADDR_NORMAL) & 0x0F), 170 | LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ 171 | write_reg(par, LCD_PAGE_ADDRESS|(u8)y); 172 | /* LCD_PAGE_ADDRESS | ((page) & 0x1F), 173 | (((col)+SHIFT_ADDR_NORMAL) & 0x0F), 174 | LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ 175 | write_reg(par, 0x00); 176 | /* LCD_PAGE_ADDRESS | ((page) & 0x1F), 177 | (((col)+SHIFT_ADDR_NORMAL) & 0x0F), 178 | LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ 179 | write_reg(par, LCD_COL_ADDRESS); 180 | gpio_set_value(par->gpio.dc, 1); 181 | ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH); 182 | gpio_set_value(par->gpio.dc, 0); 183 | } 184 | 185 | if (ret < 0) 186 | dev_err(par->info->device, "%s: write failed and returned: %d\n", __func__, ret); 187 | 188 | return ret; 189 | } 190 | 191 | 192 | static struct fbtft_display display = { 193 | .regwidth = 8, 194 | .width = WIDTH, 195 | .height = HEIGHT, 196 | .fbtftops = { 197 | .init_display = init_display, 198 | .set_addr_win = set_addr_win, 199 | .write_vmem = write_vmem, 200 | }, 201 | .backlight = 1, 202 | }; 203 | FBTFT_REGISTER_DRIVER(DRVNAME, "UltraChip,uc1701", &display); 204 | 205 | MODULE_ALIAS("spi:" DRVNAME); 206 | MODULE_ALIAS("spi:uc1701"); 207 | 208 | MODULE_DESCRIPTION("FB driver for the UC1701 LCD Controller"); 209 | MODULE_AUTHOR("Juergen Holzmann"); 210 | MODULE_LICENSE("GPL"); 211 | -------------------------------------------------------------------------------- /fb_upd161704.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the uPD161704 LCD Controller 3 | * 4 | * Copyright (C) 2014 Seong-Woo Kim 5 | * 6 | * Based on fb_ili9325.c by Noralf Tronnes 7 | * Based on ili9325.c by Jeroen Domburg 8 | * Init code from UTFT library by Henning Karlsen 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "fbtft.h" 32 | 33 | #define DRVNAME "fb_upd161704" 34 | #define WIDTH 240 35 | #define HEIGHT 320 36 | #define BPP 16 37 | 38 | static int init_display(struct fbtft_par *par) 39 | { 40 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 41 | 42 | par->fbtftops.reset(par); 43 | 44 | if (par->gpio.cs != -1) 45 | gpio_set_value(par->gpio.cs, 0); /* Activate chip */ 46 | 47 | /* Initialization sequence from Lib_UTFT */ 48 | 49 | /* register reset */ 50 | write_reg(par, 0x0003,0x0001); /* Soft reset */ 51 | 52 | /* oscillator start */ 53 | write_reg(par, 0x003A,0x0001); /*Oscillator 0: stop, 1: operation */ 54 | udelay(100); 55 | 56 | /* y-setting */ 57 | write_reg(par, 0x0024,0x007B); /* amplitude setting */ 58 | udelay(10); 59 | write_reg(par, 0x0025,0x003B); /* amplitude setting */ 60 | write_reg(par, 0x0026,0x0034); /* amplitude setting */ 61 | udelay(10); 62 | write_reg(par, 0x0027,0x0004); /* amplitude setting */ 63 | write_reg(par, 0x0052,0x0025); /* circuit setting 1 */ 64 | udelay(10); 65 | write_reg(par, 0x0053,0x0033); /* circuit setting 2 */ 66 | write_reg(par, 0x0061,0x001C); /* adjustment V10 positive polarity */ 67 | udelay(10); 68 | write_reg(par, 0x0062,0x002C); /* adjustment V9 negative polarity */ 69 | write_reg(par, 0x0063,0x0022); /* adjustment V34 positive polarity */ 70 | udelay(10); 71 | write_reg(par, 0x0064,0x0027); /* adjustment V31 negative polarity */ 72 | udelay(10); 73 | write_reg(par, 0x0065,0x0014); /* adjustment V61 negative polarity */ 74 | udelay(10); 75 | write_reg(par, 0x0066,0x0010); /* adjustment V61 negative polarity */ 76 | 77 | /* Basical clock for 1 line (BASECOUNT[7:0]) number specified */ 78 | write_reg(par, 0x002E,0x002D); 79 | 80 | /* Power supply setting */ 81 | write_reg(par, 0x0019,0x0000); /* DC/DC output setting */ 82 | udelay(200); 83 | write_reg(par, 0x001A,0x1000); /* DC/DC frequency setting */ 84 | write_reg(par, 0x001B,0x0023); /* DC/DC rising setting */ 85 | write_reg(par, 0x001C,0x0C01); /* Regulator voltage setting */ 86 | write_reg(par, 0x001D,0x0000); /* Regulator current setting */ 87 | write_reg(par, 0x001E,0x0009); /* VCOM output setting */ 88 | write_reg(par, 0x001F,0x0035); /* VCOM amplitude setting */ 89 | write_reg(par, 0x0020,0x0015); /* VCOMM cencter setting */ 90 | write_reg(par, 0x0018,0x1E7B); /* DC/DC operation setting */ 91 | 92 | /* windows setting */ 93 | write_reg(par, 0x0008,0x0000); /* Minimum X address */ 94 | write_reg(par, 0x0009,0x00EF); /* Maximum X address */ 95 | write_reg(par, 0x000a,0x0000); /* Minimum Y address */ 96 | write_reg(par, 0x000b,0x013F); /* Maximum Y address */ 97 | 98 | /* LCD display area setting */ 99 | write_reg(par, 0x0029,0x0000); /* [LCDSIZE] X MIN. size set */ 100 | write_reg(par, 0x002A,0x0000); /* [LCDSIZE] Y MIN. size set */ 101 | write_reg(par, 0x002B,0x00EF); /* [LCDSIZE] X MAX. size set */ 102 | write_reg(par, 0x002C,0x013F); /* [LCDSIZE] Y MAX. size set */ 103 | 104 | /* Gate scan setting */ 105 | write_reg(par, 0x0032,0x0002); 106 | 107 | /* n line inversion line number */ 108 | write_reg(par, 0x0033,0x0000); 109 | 110 | /* Line inversion/frame inversion/interlace setting */ 111 | write_reg(par, 0x0037,0x0000); 112 | 113 | /* Gate scan operation setting register */ 114 | write_reg(par, 0x003B,0x0001); 115 | 116 | /* Color mode */ 117 | /*GS = 0: 260-k color (64 gray scale), GS = 1: 8 color (2 gray scale) */ 118 | write_reg(par, 0x0004,0x0000); 119 | 120 | /* RAM control register */ 121 | write_reg(par, 0x0005,0x0000); /*Window access 00:Normal, 10:Window */ 122 | 123 | /* Display setting register 2 */ 124 | write_reg(par, 0x0001,0x0000); 125 | 126 | /* display setting */ 127 | write_reg(par, 0x0000,0x0000); /* display on */ 128 | 129 | return 0; 130 | } 131 | 132 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 133 | { 134 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 135 | "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 136 | switch (par->info->var.rotate) { 137 | /* R20h = Horizontal GRAM Start Address */ 138 | /* R21h = Vertical GRAM Start Address */ 139 | case 0: 140 | write_reg(par, 0x0006, xs); 141 | write_reg(par, 0x0007, ys); 142 | break; 143 | case 180: 144 | write_reg(par, 0x0006, WIDTH - 1 - xs); 145 | write_reg(par, 0x0007, HEIGHT - 1 - ys); 146 | break; 147 | case 270: 148 | write_reg(par, 0x0006, WIDTH - 1 - ys); 149 | write_reg(par, 0x0007, xs); 150 | break; 151 | case 90: 152 | write_reg(par, 0x0006, ys); 153 | write_reg(par, 0x0007, HEIGHT - 1 - xs); 154 | break; 155 | } 156 | 157 | write_reg(par, 0x0e); /* Write Data to GRAM */ 158 | } 159 | 160 | static int set_var(struct fbtft_par *par) 161 | { 162 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 163 | 164 | switch (par->info->var.rotate) { 165 | /* AM: GRAM update direction */ 166 | case 0: 167 | write_reg(par, 0x01, 0x0000); 168 | write_reg(par, 0x05, 0x0000); 169 | break; 170 | case 180: 171 | write_reg(par, 0x01, 0x00C0); 172 | write_reg(par, 0x05, 0x0000); 173 | break; 174 | case 270: 175 | write_reg(par, 0x01, 0x0080); 176 | write_reg(par, 0x05, 0x0001); 177 | break; 178 | case 90: 179 | write_reg(par, 0x01, 0x0040); 180 | write_reg(par, 0x05, 0x0001); 181 | break; 182 | } 183 | 184 | return 0; 185 | } 186 | 187 | static struct fbtft_display display = { 188 | .regwidth = 16, 189 | .width = WIDTH, 190 | .height = HEIGHT, 191 | .fbtftops = { 192 | .init_display = init_display, 193 | .set_addr_win = set_addr_win, 194 | .set_var = set_var, 195 | }, 196 | }; 197 | FBTFT_REGISTER_DRIVER(DRVNAME, "nec,upd161704", &display); 198 | 199 | MODULE_ALIAS("spi:" DRVNAME); 200 | MODULE_ALIAS("platform:" DRVNAME); 201 | MODULE_ALIAS("spi:upd161704"); 202 | MODULE_ALIAS("platform:upd161704"); 203 | 204 | MODULE_DESCRIPTION("FB driver for the uPD161704 LCD Controller"); 205 | MODULE_AUTHOR("Seong-Woo Kim"); 206 | MODULE_LICENSE("GPL"); 207 | -------------------------------------------------------------------------------- /fb_watterott.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FB driver for the Watterott LCD Controller 3 | * 4 | * Copyright (C) 2013 Noralf Tronnes 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "fbtft.h" 28 | 29 | #define DRVNAME "fb_watterott" 30 | #define WIDTH 320 31 | #define HEIGHT 240 32 | #define FPS 5 33 | #define TXBUFLEN 1024 34 | #define DEFAULT_BRIGHTNESS 50 35 | 36 | #define CMD_VERSION 0x01 37 | #define CMD_LCD_LED 0x10 38 | #define CMD_LCD_RESET 0x11 39 | #define CMD_LCD_ORIENTATION 0x20 40 | #define CMD_LCD_DRAWIMAGE 0x27 41 | #define COLOR_RGB323 8 42 | #define COLOR_RGB332 9 43 | #define COLOR_RGB233 10 44 | #define COLOR_RGB565 16 45 | 46 | 47 | static short mode = 565; 48 | module_param(mode, short, 0); 49 | MODULE_PARM_DESC(mode, "RGB color transfer mode: 332, 565 (default)"); 50 | 51 | static void write_reg8_bus8(struct fbtft_par *par, int len, ...) 52 | { 53 | va_list args; 54 | int i, ret; 55 | u8 *buf = par->buf; 56 | 57 | va_start(args, len); 58 | for (i = 0; i < len; i++) 59 | *buf++ = (u8)va_arg(args, unsigned int); 60 | va_end(args); 61 | 62 | fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, 63 | par->info->device, u8, par->buf, len, "%s: ", __func__); 64 | 65 | ret = par->fbtftops.write(par, par->buf, len); 66 | if (ret < 0) { 67 | dev_err(par->info->device, 68 | "%s: write() failed and returned %d\n", __func__, ret); 69 | return; 70 | } 71 | } 72 | 73 | static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) 74 | { 75 | unsigned start_line, end_line; 76 | u16 *vmem16 = (u16 *)(par->info->screen_base + offset); 77 | u16 *pos = par->txbuf.buf + 1; 78 | u16 *buf16 = par->txbuf.buf + 10; 79 | int i, j; 80 | int ret = 0; 81 | 82 | fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); 83 | 84 | start_line = offset / par->info->fix.line_length; 85 | end_line = start_line + (len / par->info->fix.line_length) - 1; 86 | 87 | /* Set command header. pos: x, y, w, h */ 88 | ((u8 *)par->txbuf.buf)[0] = CMD_LCD_DRAWIMAGE; 89 | pos[0] = 0; 90 | pos[2] = cpu_to_be16(par->info->var.xres); 91 | pos[3] = cpu_to_be16(1); 92 | ((u8 *)par->txbuf.buf)[9] = COLOR_RGB565; 93 | 94 | for (i = start_line; i <= end_line; i++) { 95 | pos[1] = cpu_to_be16(i); 96 | for (j = 0; j < par->info->var.xres; j++) 97 | buf16[j] = cpu_to_be16(*vmem16++); 98 | ret = par->fbtftops.write(par, 99 | par->txbuf.buf, 10 + par->info->fix.line_length); 100 | if (ret < 0) 101 | return ret; 102 | udelay(300); 103 | } 104 | 105 | return 0; 106 | } 107 | 108 | #define RGB565toRGB323(c) (((c&0xE000)>>8) | ((c&0600)>>6) | ((c&0x001C)>>2)) 109 | #define RGB565toRGB332(c) (((c&0xE000)>>8) | ((c&0700)>>6) | ((c&0x0018)>>3)) 110 | #define RGB565toRGB233(c) (((c&0xC000)>>8) | ((c&0700)>>5) | ((c&0x001C)>>2)) 111 | 112 | static int write_vmem_8bit(struct fbtft_par *par, size_t offset, size_t len) 113 | { 114 | unsigned start_line, end_line; 115 | u16 *vmem16 = (u16 *)(par->info->screen_base + offset); 116 | u16 *pos = par->txbuf.buf + 1; 117 | u8 *buf8 = par->txbuf.buf + 10; 118 | int i, j; 119 | int ret = 0; 120 | 121 | fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); 122 | 123 | start_line = offset / par->info->fix.line_length; 124 | end_line = start_line + (len / par->info->fix.line_length) - 1; 125 | 126 | /* Set command header. pos: x, y, w, h */ 127 | ((u8 *)par->txbuf.buf)[0] = CMD_LCD_DRAWIMAGE; 128 | pos[0] = 0; 129 | pos[2] = cpu_to_be16(par->info->var.xres); 130 | pos[3] = cpu_to_be16(1); 131 | ((u8 *)par->txbuf.buf)[9] = COLOR_RGB332; 132 | 133 | for (i = start_line; i <= end_line; i++) { 134 | pos[1] = cpu_to_be16(i); 135 | for (j = 0; j < par->info->var.xres; j++) { 136 | buf8[j] = RGB565toRGB332(*vmem16); 137 | vmem16++; 138 | } 139 | ret = par->fbtftops.write(par, 140 | par->txbuf.buf, 10 + par->info->var.xres); 141 | if (ret < 0) 142 | return ret; 143 | udelay(700); 144 | } 145 | 146 | return 0; 147 | } 148 | 149 | static unsigned firmware_version(struct fbtft_par *par) 150 | { 151 | u8 rxbuf[4] = {0, }; 152 | 153 | write_reg(par, CMD_VERSION); 154 | par->fbtftops.read(par, rxbuf, 4); 155 | if (rxbuf[1] != '.') 156 | return 0; 157 | 158 | return (rxbuf[0] - '0') << 8 | (rxbuf[2] - '0') << 4 | (rxbuf[3] - '0'); 159 | } 160 | 161 | static int init_display(struct fbtft_par *par) 162 | { 163 | int ret; 164 | unsigned version; 165 | u8 save_mode; 166 | 167 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 168 | 169 | /* enable SPI interface by having CS and MOSI low during reset */ 170 | save_mode = par->spi->mode; 171 | par->spi->mode |= SPI_CS_HIGH; 172 | ret = par->spi->master->setup(par->spi); /* set CS inactive low */ 173 | if (ret) { 174 | dev_err(par->info->device, "Could not set SPI_CS_HIGH\n"); 175 | return ret; 176 | } 177 | write_reg(par, 0x00); /* make sure mode is set */ 178 | 179 | mdelay(50); 180 | par->fbtftops.reset(par); 181 | mdelay(1000); 182 | par->spi->mode = save_mode; 183 | ret = par->spi->master->setup(par->spi); 184 | if (ret) { 185 | dev_err(par->info->device, "Could not restore SPI mode\n"); 186 | return ret; 187 | } 188 | write_reg(par, 0x00); 189 | 190 | version = firmware_version(par); 191 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "Firmware version: %x.%02x\n", 192 | version >> 8, version & 0xFF); 193 | 194 | if (mode == 332) 195 | par->fbtftops.write_vmem = write_vmem_8bit; 196 | return 0; 197 | } 198 | 199 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 200 | { 201 | /* not used on this controller */ 202 | } 203 | 204 | static int set_var(struct fbtft_par *par) 205 | { 206 | u8 rotate; 207 | 208 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 209 | 210 | /* this controller rotates clock wise */ 211 | switch (par->info->var.rotate) { 212 | case 90: 213 | rotate = 27; 214 | break; 215 | case 180: 216 | rotate = 18; 217 | break; 218 | case 270: 219 | rotate = 9; 220 | break; 221 | default: 222 | rotate = 0; 223 | } 224 | write_reg(par, CMD_LCD_ORIENTATION, rotate); 225 | 226 | return 0; 227 | } 228 | 229 | static int verify_gpios(struct fbtft_par *par) 230 | { 231 | if (par->gpio.reset < 0) { 232 | dev_err(par->info->device, "Missing 'reset' gpio. Aborting.\n"); 233 | return -EINVAL; 234 | } 235 | return 0; 236 | } 237 | 238 | #ifdef CONFIG_FB_BACKLIGHT 239 | static int backlight_chip_update_status(struct backlight_device *bd) 240 | { 241 | struct fbtft_par *par = bl_get_data(bd); 242 | int brightness = bd->props.brightness; 243 | 244 | fbtft_par_dbg(DEBUG_BACKLIGHT, par, 245 | "%s: brightness=%d, power=%d, fb_blank=%d\n", 246 | __func__, bd->props.brightness, bd->props.power, 247 | bd->props.fb_blank); 248 | 249 | if (bd->props.power != FB_BLANK_UNBLANK) 250 | brightness = 0; 251 | 252 | if (bd->props.fb_blank != FB_BLANK_UNBLANK) 253 | brightness = 0; 254 | 255 | write_reg(par, CMD_LCD_LED, brightness); 256 | 257 | return 0; 258 | } 259 | 260 | static void register_chip_backlight(struct fbtft_par *par) 261 | { 262 | struct backlight_device *bd; 263 | struct backlight_properties bl_props = { 0, }; 264 | struct backlight_ops *bl_ops; 265 | 266 | fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__); 267 | 268 | bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops), 269 | GFP_KERNEL); 270 | if (!bl_ops) { 271 | dev_err(par->info->device, 272 | "%s: could not allocate memory for backlight operations.\n", 273 | __func__); 274 | return; 275 | } 276 | 277 | bl_ops->update_status = backlight_chip_update_status; 278 | bl_props.type = BACKLIGHT_RAW; 279 | bl_props.power = FB_BLANK_POWERDOWN; 280 | bl_props.max_brightness = 100; 281 | bl_props.brightness = DEFAULT_BRIGHTNESS; 282 | 283 | bd = backlight_device_register(dev_driver_string(par->info->device), 284 | par->info->device, par, bl_ops, &bl_props); 285 | if (IS_ERR(bd)) { 286 | dev_err(par->info->device, 287 | "cannot register backlight device (%ld)\n", 288 | PTR_ERR(bd)); 289 | return; 290 | } 291 | par->info->bl_dev = bd; 292 | 293 | if (!par->fbtftops.unregister_backlight) 294 | par->fbtftops.unregister_backlight = fbtft_unregister_backlight; 295 | } 296 | #else 297 | #define register_chip_backlight NULL 298 | #endif 299 | 300 | 301 | static struct fbtft_display display = { 302 | .regwidth = 8, 303 | .buswidth = 8, 304 | .width = WIDTH, 305 | .height = HEIGHT, 306 | .fps = FPS, 307 | .txbuflen = TXBUFLEN, 308 | .fbtftops = { 309 | .write_register = write_reg8_bus8, 310 | .write_vmem = write_vmem, 311 | .init_display = init_display, 312 | .set_addr_win = set_addr_win, 313 | .set_var = set_var, 314 | .verify_gpios = verify_gpios, 315 | .register_backlight = register_chip_backlight, 316 | }, 317 | }; 318 | FBTFT_REGISTER_DRIVER(DRVNAME, "watterott,openlcd", &display); 319 | 320 | MODULE_ALIAS("spi:" DRVNAME); 321 | 322 | MODULE_DESCRIPTION("FB driver for the Watterott LCD Controller"); 323 | MODULE_AUTHOR("Noralf Tronnes"); 324 | MODULE_LICENSE("GPL"); 325 | -------------------------------------------------------------------------------- /fbtft-bus.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "fbtft.h" 6 | 7 | 8 | 9 | 10 | /***************************************************************************** 11 | * 12 | * void (*write_reg)(struct fbtft_par *par, int len, ...); 13 | * 14 | *****************************************************************************/ 15 | 16 | #define define_fbtft_write_reg(func, type, modifier) \ 17 | void func(struct fbtft_par *par, int len, ...) \ 18 | { \ 19 | va_list args; \ 20 | int i, ret; \ 21 | int offset = 0; \ 22 | type *buf = (type *)par->buf; \ 23 | \ 24 | if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { \ 25 | va_start(args, len); \ 26 | for (i = 0; i < len; i++) { \ 27 | buf[i] = (type)va_arg(args, unsigned int); \ 28 | } \ 29 | va_end(args); \ 30 | fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, type, buf, len, "%s: ", __func__); \ 31 | } \ 32 | \ 33 | va_start(args, len); \ 34 | \ 35 | if (par->startbyte) { \ 36 | *(u8 *)par->buf = par->startbyte; \ 37 | buf = (type *)(par->buf + 1); \ 38 | offset = 1; \ 39 | } \ 40 | \ 41 | *buf = modifier((type)va_arg(args, unsigned int)); \ 42 | if (par->gpio.dc != -1) \ 43 | gpio_set_value(par->gpio.dc, 0); \ 44 | ret = par->fbtftops.write(par, par->buf, sizeof(type)+offset); \ 45 | if (ret < 0) { \ 46 | va_end(args); \ 47 | dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); \ 48 | return; \ 49 | } \ 50 | len--; \ 51 | \ 52 | if (par->startbyte) \ 53 | *(u8 *)par->buf = par->startbyte | 0x2; \ 54 | \ 55 | if (len) { \ 56 | i = len; \ 57 | while (i--) { \ 58 | *buf++ = modifier((type)va_arg(args, unsigned int)); \ 59 | } \ 60 | if (par->gpio.dc != -1) \ 61 | gpio_set_value(par->gpio.dc, 1); \ 62 | ret = par->fbtftops.write(par, par->buf, len * (sizeof(type)+offset)); \ 63 | if (ret < 0) { \ 64 | va_end(args); \ 65 | dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); \ 66 | return; \ 67 | } \ 68 | } \ 69 | va_end(args); \ 70 | } \ 71 | EXPORT_SYMBOL(func); 72 | 73 | define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, ) 74 | define_fbtft_write_reg(fbtft_write_reg16_bus8, u16, cpu_to_be16) 75 | define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, ) 76 | 77 | void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...) 78 | { 79 | va_list args; 80 | int i, ret; 81 | int pad = 0; 82 | u16 *buf = (u16 *)par->buf; 83 | 84 | if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { 85 | va_start(args, len); 86 | for (i = 0; i < len; i++) 87 | *(((u8 *)buf) + i) = (u8)va_arg(args, unsigned int); 88 | va_end(args); 89 | fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, 90 | par->info->device, u8, buf, len, "%s: ", __func__); 91 | } 92 | if (len <= 0) 93 | return; 94 | 95 | if (par->spi && (par->spi->bits_per_word == 8)) { 96 | /* we're emulating 9-bit, pad start of buffer with no-ops 97 | (assuming here that zero is a no-op) */ 98 | pad = (len % 4) ? 4 - (len % 4) : 0; 99 | for (i = 0; i < pad; i++) 100 | *buf++ = 0x000; 101 | } 102 | 103 | va_start(args, len); 104 | *buf++ = (u8)va_arg(args, unsigned int); 105 | i = len - 1; 106 | while (i--) { 107 | *buf = (u8)va_arg(args, unsigned int); 108 | *buf++ |= 0x100; /* dc=1 */ 109 | } 110 | va_end(args); 111 | ret = par->fbtftops.write(par, par->buf, (len + pad) * sizeof(u16)); 112 | if (ret < 0) { 113 | dev_err(par->info->device, 114 | "%s: write() failed and returned %d\n", __func__, ret); 115 | return; 116 | } 117 | } 118 | EXPORT_SYMBOL(fbtft_write_reg8_bus9); 119 | 120 | 121 | 122 | 123 | /***************************************************************************** 124 | * 125 | * int (*write_vmem)(struct fbtft_par *par); 126 | * 127 | *****************************************************************************/ 128 | 129 | /* 16 bit pixel over 8-bit databus */ 130 | int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len) 131 | { 132 | u16 *vmem16; 133 | u16 *txbuf16 = (u16 *)par->txbuf.buf; 134 | size_t remain; 135 | size_t to_copy; 136 | size_t tx_array_size; 137 | int i; 138 | int ret = 0; 139 | size_t startbyte_size = 0; 140 | 141 | fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", 142 | __func__, offset, len); 143 | 144 | remain = len / 2; 145 | vmem16 = (u16 *)(par->info->screen_base + offset); 146 | 147 | if (par->gpio.dc != -1) 148 | gpio_set_value(par->gpio.dc, 1); 149 | 150 | /* non buffered write */ 151 | if (!par->txbuf.buf) 152 | return par->fbtftops.write(par, vmem16, len); 153 | 154 | /* buffered write */ 155 | tx_array_size = par->txbuf.len / 2; 156 | 157 | if (par->startbyte) { 158 | txbuf16 = (u16 *)(par->txbuf.buf + 1); 159 | tx_array_size -= 2; 160 | *(u8 *)(par->txbuf.buf) = par->startbyte | 0x2; 161 | startbyte_size = 1; 162 | } 163 | 164 | while (remain) { 165 | to_copy = remain > tx_array_size ? tx_array_size : remain; 166 | dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n", 167 | to_copy, remain - to_copy); 168 | 169 | for (i = 0; i < to_copy; i++) 170 | txbuf16[i] = cpu_to_be16(vmem16[i]); 171 | 172 | vmem16 = vmem16 + to_copy; 173 | ret = par->fbtftops.write(par, par->txbuf.buf, 174 | startbyte_size + to_copy * 2); 175 | if (ret < 0) 176 | return ret; 177 | remain -= to_copy; 178 | } 179 | 180 | return ret; 181 | } 182 | EXPORT_SYMBOL(fbtft_write_vmem16_bus8); 183 | 184 | /* 16 bit pixel over 9-bit SPI bus: dc + high byte, dc + low byte */ 185 | int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len) 186 | { 187 | u8 *vmem8; 188 | u16 *txbuf16 = par->txbuf.buf; 189 | size_t remain; 190 | size_t to_copy; 191 | size_t tx_array_size; 192 | int i; 193 | int ret = 0; 194 | 195 | fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", 196 | __func__, offset, len); 197 | 198 | if (!par->txbuf.buf) { 199 | dev_err(par->info->device, "%s: txbuf.buf is NULL\n", __func__); 200 | return -1; 201 | } 202 | 203 | remain = len; 204 | vmem8 = par->info->screen_base + offset; 205 | 206 | tx_array_size = par->txbuf.len / 2; 207 | 208 | while (remain) { 209 | to_copy = remain > tx_array_size ? tx_array_size : remain; 210 | dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n", 211 | to_copy, remain - to_copy); 212 | 213 | #ifdef __LITTLE_ENDIAN 214 | for (i = 0; i < to_copy; i += 2) { 215 | txbuf16[i] = 0x0100 | vmem8[i+1]; 216 | txbuf16[i+1] = 0x0100 | vmem8[i]; 217 | } 218 | #else 219 | for (i = 0; i < to_copy; i++) 220 | txbuf16[i] = 0x0100 | vmem8[i]; 221 | #endif 222 | vmem8 = vmem8 + to_copy; 223 | ret = par->fbtftops.write(par, par->txbuf.buf, to_copy*2); 224 | if (ret < 0) 225 | return ret; 226 | remain -= to_copy; 227 | } 228 | 229 | return ret; 230 | } 231 | EXPORT_SYMBOL(fbtft_write_vmem16_bus9); 232 | 233 | int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len) 234 | { 235 | dev_err(par->info->device, "%s: function not implemented\n", __func__); 236 | return -1; 237 | } 238 | EXPORT_SYMBOL(fbtft_write_vmem8_bus8); 239 | 240 | /* 16 bit pixel over 16-bit databus */ 241 | int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len) 242 | { 243 | u16 *vmem16; 244 | 245 | fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n", 246 | __func__, offset, len); 247 | 248 | vmem16 = (u16 *)(par->info->screen_base + offset); 249 | 250 | if (par->gpio.dc != -1) 251 | gpio_set_value(par->gpio.dc, 1); 252 | 253 | /* no need for buffered write with 16-bit bus */ 254 | return par->fbtftops.write(par, vmem16, len); 255 | } 256 | EXPORT_SYMBOL(fbtft_write_vmem16_bus16); 257 | -------------------------------------------------------------------------------- /fbtft-io.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #ifdef CONFIG_ARCH_BCM2708 6 | #include 7 | #endif 8 | #include "fbtft.h" 9 | 10 | int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len) 11 | { 12 | struct spi_transfer t = { 13 | .tx_buf = buf, 14 | .len = len, 15 | }; 16 | struct spi_message m; 17 | 18 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, 19 | "%s(len=%d): ", __func__, len); 20 | 21 | if (!par->spi) { 22 | dev_err(par->info->device, 23 | "%s: par->spi is unexpectedly NULL\n", __func__); 24 | return -1; 25 | } 26 | 27 | spi_message_init(&m); 28 | if (par->txbuf.dma && buf == par->txbuf.buf) { 29 | t.tx_dma = par->txbuf.dma; 30 | m.is_dma_mapped = 1; 31 | } 32 | spi_message_add_tail(&t, &m); 33 | return spi_sync(par->spi, &m); 34 | } 35 | EXPORT_SYMBOL(fbtft_write_spi); 36 | 37 | /** 38 | * fbtft_write_spi_emulate_9() - write SPI emulating 9-bit 39 | * @par: Driver data 40 | * @buf: Buffer to write 41 | * @len: Length of buffer (must be divisible by 8) 42 | * 43 | * When 9-bit SPI is not available, this function can be used to emulate that. 44 | * par->extra must hold a transformation buffer used for transfer. 45 | */ 46 | int fbtft_write_spi_emulate_9(struct fbtft_par *par, void *buf, size_t len) 47 | { 48 | u16 *src = buf; 49 | u8 *dst = par->extra; 50 | size_t size = len / 2; 51 | size_t added = 0; 52 | int bits, i, j; 53 | u64 val, dc, tmp; 54 | 55 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, 56 | "%s(len=%d): ", __func__, len); 57 | 58 | if (!par->extra) { 59 | dev_err(par->info->device, "%s: error: par->extra is NULL\n", 60 | __func__); 61 | return -EINVAL; 62 | } 63 | if ((len % 8) != 0) { 64 | dev_err(par->info->device, 65 | "%s: error: len=%d must be divisible by 8\n", 66 | __func__, len); 67 | return -EINVAL; 68 | } 69 | 70 | for (i = 0; i < size; i += 8) { 71 | tmp = 0; 72 | bits = 63; 73 | for (j = 0; j < 7; j++) { 74 | dc = (*src & 0x0100) ? 1 : 0; 75 | val = *src & 0x00FF; 76 | tmp |= dc << bits; 77 | bits -= 8; 78 | tmp |= val << bits--; 79 | src++; 80 | } 81 | tmp |= ((*src & 0x0100) ? 1 : 0); 82 | *(u64 *)dst = cpu_to_be64(tmp); 83 | dst += 8; 84 | *dst++ = (u8)(*src++ & 0x00FF); 85 | added++; 86 | } 87 | 88 | return spi_write(par->spi, par->extra, size + added); 89 | } 90 | EXPORT_SYMBOL(fbtft_write_spi_emulate_9); 91 | 92 | int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len) 93 | { 94 | int ret; 95 | u8 txbuf[32] = { 0, }; 96 | struct spi_transfer t = { 97 | .speed_hz = 2000000, 98 | .rx_buf = buf, 99 | .len = len, 100 | }; 101 | struct spi_message m; 102 | 103 | if (!par->spi) { 104 | dev_err(par->info->device, 105 | "%s: par->spi is unexpectedly NULL\n", __func__); 106 | return -ENODEV; 107 | } 108 | 109 | if (par->startbyte) { 110 | if (len > 32) { 111 | dev_err(par->info->device, 112 | "%s: len=%d can't be larger than 32 when using 'startbyte'\n", 113 | __func__, len); 114 | return -EINVAL; 115 | } 116 | txbuf[0] = par->startbyte | 0x3; 117 | t.tx_buf = txbuf; 118 | fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, 119 | txbuf, len, "%s(len=%d) txbuf => ", __func__, len); 120 | } 121 | 122 | spi_message_init(&m); 123 | spi_message_add_tail(&t, &m); 124 | ret = spi_sync(par->spi, &m); 125 | fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len, 126 | "%s(len=%d) buf <= ", __func__, len); 127 | 128 | return ret; 129 | } 130 | EXPORT_SYMBOL(fbtft_read_spi); 131 | 132 | 133 | #ifdef CONFIG_ARCH_BCM2708 134 | 135 | /* 136 | * Raspberry Pi 137 | * - writing directly to the registers is 40-50% faster than 138 | * optimized use of gpiolib 139 | */ 140 | 141 | #define GPIOSET(no, ishigh) \ 142 | do { \ 143 | if (ishigh) \ 144 | set |= (1 << (no)); \ 145 | else \ 146 | reset |= (1 << (no)); \ 147 | } while (0) 148 | 149 | int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len) 150 | { 151 | unsigned int set = 0; 152 | unsigned int reset = 0; 153 | u8 data; 154 | 155 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, 156 | "%s(len=%d): ", __func__, len); 157 | 158 | while (len--) { 159 | data = *(u8 *) buf; 160 | buf++; 161 | 162 | /* Set data */ 163 | GPIOSET(par->gpio.db[0], (data&0x01)); 164 | GPIOSET(par->gpio.db[1], (data&0x02)); 165 | GPIOSET(par->gpio.db[2], (data&0x04)); 166 | GPIOSET(par->gpio.db[3], (data&0x08)); 167 | GPIOSET(par->gpio.db[4], (data&0x10)); 168 | GPIOSET(par->gpio.db[5], (data&0x20)); 169 | GPIOSET(par->gpio.db[6], (data&0x40)); 170 | GPIOSET(par->gpio.db[7], (data&0x80)); 171 | writel(set, __io_address(GPIO_BASE+0x1C)); 172 | writel(reset, __io_address(GPIO_BASE+0x28)); 173 | 174 | /* Pulse /WR low */ 175 | writel((1<gpio.wr), __io_address(GPIO_BASE+0x28)); 176 | writel(0, __io_address(GPIO_BASE+0x28)); /* used as a delay */ 177 | writel((1<gpio.wr), __io_address(GPIO_BASE+0x1C)); 178 | 179 | set = 0; 180 | reset = 0; 181 | } 182 | 183 | return 0; 184 | } 185 | EXPORT_SYMBOL(fbtft_write_gpio8_wr); 186 | 187 | int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len) 188 | { 189 | unsigned int set = 0; 190 | unsigned int reset = 0; 191 | u16 data; 192 | 193 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, 194 | "%s(len=%d): ", __func__, len); 195 | 196 | while (len) { 197 | len -= 2; 198 | data = *(u16 *) buf; 199 | buf += 2; 200 | 201 | /* Start writing by pulling down /WR */ 202 | gpio_set_value(par->gpio.wr, 0); 203 | 204 | /* Set data */ 205 | GPIOSET(par->gpio.db[0], (data&0x0001)); 206 | GPIOSET(par->gpio.db[1], (data&0x0002)); 207 | GPIOSET(par->gpio.db[2], (data&0x0004)); 208 | GPIOSET(par->gpio.db[3], (data&0x0008)); 209 | GPIOSET(par->gpio.db[4], (data&0x0010)); 210 | GPIOSET(par->gpio.db[5], (data&0x0020)); 211 | GPIOSET(par->gpio.db[6], (data&0x0040)); 212 | GPIOSET(par->gpio.db[7], (data&0x0080)); 213 | 214 | GPIOSET(par->gpio.db[8], (data&0x0100)); 215 | GPIOSET(par->gpio.db[9], (data&0x0200)); 216 | GPIOSET(par->gpio.db[10], (data&0x0400)); 217 | GPIOSET(par->gpio.db[11], (data&0x0800)); 218 | GPIOSET(par->gpio.db[12], (data&0x1000)); 219 | GPIOSET(par->gpio.db[13], (data&0x2000)); 220 | GPIOSET(par->gpio.db[14], (data&0x4000)); 221 | GPIOSET(par->gpio.db[15], (data&0x8000)); 222 | 223 | writel(set, __io_address(GPIO_BASE+0x1C)); 224 | writel(reset, __io_address(GPIO_BASE+0x28)); 225 | 226 | /* Pullup /WR */ 227 | gpio_set_value(par->gpio.wr, 1); 228 | 229 | set = 0; 230 | reset = 0; 231 | } 232 | 233 | return 0; 234 | } 235 | EXPORT_SYMBOL(fbtft_write_gpio16_wr); 236 | 237 | int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len) 238 | { 239 | unsigned int set = 0; 240 | unsigned int reset = 0; 241 | u16 data; 242 | 243 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, 244 | "%s(len=%d): ", __func__, len); 245 | 246 | while (len) { 247 | len -= 2; 248 | data = *(u16 *) buf; 249 | buf += 2; 250 | 251 | /* Start writing by pulling down /WR */ 252 | gpio_set_value(par->gpio.wr, 0); 253 | 254 | /* Low byte */ 255 | GPIOSET(par->gpio.db[0], (data&0x0001)); 256 | GPIOSET(par->gpio.db[1], (data&0x0002)); 257 | GPIOSET(par->gpio.db[2], (data&0x0004)); 258 | GPIOSET(par->gpio.db[3], (data&0x0008)); 259 | GPIOSET(par->gpio.db[4], (data&0x0010)); 260 | GPIOSET(par->gpio.db[5], (data&0x0020)); 261 | GPIOSET(par->gpio.db[6], (data&0x0040)); 262 | GPIOSET(par->gpio.db[7], (data&0x0080)); 263 | writel(set, __io_address(GPIO_BASE+0x1C)); 264 | writel(reset, __io_address(GPIO_BASE+0x28)); 265 | 266 | /* Pulse 'latch' high */ 267 | gpio_set_value(par->gpio.latch, 1); 268 | gpio_set_value(par->gpio.latch, 0); 269 | 270 | /* High byte */ 271 | GPIOSET(par->gpio.db[0], (data&0x0100)); 272 | GPIOSET(par->gpio.db[1], (data&0x0200)); 273 | GPIOSET(par->gpio.db[2], (data&0x0400)); 274 | GPIOSET(par->gpio.db[3], (data&0x0800)); 275 | GPIOSET(par->gpio.db[4], (data&0x1000)); 276 | GPIOSET(par->gpio.db[5], (data&0x2000)); 277 | GPIOSET(par->gpio.db[6], (data&0x4000)); 278 | GPIOSET(par->gpio.db[7], (data&0x8000)); 279 | writel(set, __io_address(GPIO_BASE+0x1C)); 280 | writel(reset, __io_address(GPIO_BASE+0x28)); 281 | 282 | /* Pullup /WR */ 283 | gpio_set_value(par->gpio.wr, 1); 284 | 285 | set = 0; 286 | reset = 0; 287 | } 288 | 289 | return 0; 290 | } 291 | EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched); 292 | 293 | #undef GPIOSET 294 | 295 | #else 296 | 297 | /* 298 | * Optimized use of gpiolib is twice as fast as no optimization 299 | * only one driver can use the optimized version at a time 300 | */ 301 | int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len) 302 | { 303 | u8 data; 304 | int i; 305 | #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 306 | static u8 prev_data; 307 | #endif 308 | 309 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, 310 | "%s(len=%d): ", __func__, len); 311 | 312 | while (len--) { 313 | data = *(u8 *) buf; 314 | 315 | /* Start writing by pulling down /WR */ 316 | gpio_set_value(par->gpio.wr, 0); 317 | 318 | /* Set data */ 319 | #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 320 | if (data == prev_data) { 321 | gpio_set_value(par->gpio.wr, 0); /* used as delay */ 322 | } else { 323 | for (i = 0; i < 8; i++) { 324 | if ((data & 1) != (prev_data & 1)) 325 | gpio_set_value(par->gpio.db[i], 326 | (data & 1)); 327 | data >>= 1; 328 | prev_data >>= 1; 329 | } 330 | } 331 | #else 332 | for (i = 0; i < 8; i++) { 333 | gpio_set_value(par->gpio.db[i], (data & 1)); 334 | data >>= 1; 335 | } 336 | #endif 337 | 338 | /* Pullup /WR */ 339 | gpio_set_value(par->gpio.wr, 1); 340 | 341 | #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 342 | prev_data = *(u8 *) buf; 343 | #endif 344 | buf++; 345 | } 346 | 347 | return 0; 348 | } 349 | EXPORT_SYMBOL(fbtft_write_gpio8_wr); 350 | 351 | int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len) 352 | { 353 | u16 data; 354 | int i; 355 | #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 356 | static u16 prev_data; 357 | #endif 358 | 359 | fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, 360 | "%s(len=%d): ", __func__, len); 361 | 362 | while (len) { 363 | data = *(u16 *) buf; 364 | 365 | /* Start writing by pulling down /WR */ 366 | gpio_set_value(par->gpio.wr, 0); 367 | 368 | /* Set data */ 369 | #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 370 | if (data == prev_data) { 371 | gpio_set_value(par->gpio.wr, 0); /* used as delay */ 372 | } else { 373 | for (i = 0; i < 16; i++) { 374 | if ((data & 1) != (prev_data & 1)) 375 | gpio_set_value(par->gpio.db[i], 376 | (data & 1)); 377 | data >>= 1; 378 | prev_data >>= 1; 379 | } 380 | } 381 | #else 382 | for (i = 0; i < 16; i++) { 383 | gpio_set_value(par->gpio.db[i], (data & 1)); 384 | data >>= 1; 385 | } 386 | #endif 387 | 388 | /* Pullup /WR */ 389 | gpio_set_value(par->gpio.wr, 1); 390 | 391 | #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO 392 | prev_data = *(u16 *) buf; 393 | #endif 394 | buf += 2; 395 | len -= 2; 396 | } 397 | 398 | return 0; 399 | } 400 | EXPORT_SYMBOL(fbtft_write_gpio16_wr); 401 | 402 | int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len) 403 | { 404 | dev_err(par->info->device, "%s: function not implemented\n", __func__); 405 | return -1; 406 | } 407 | EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched); 408 | 409 | #endif /* CONFIG_ARCH_BCM2708 */ 410 | -------------------------------------------------------------------------------- /fbtft-sysfs.c: -------------------------------------------------------------------------------- 1 | #include "fbtft.h" 2 | 3 | 4 | static int get_next_ulong(char **str_p, unsigned long *val, char *sep, int base) 5 | { 6 | char *p_val; 7 | int ret; 8 | 9 | if (!str_p || !(*str_p)) 10 | return -EINVAL; 11 | 12 | p_val = strsep(str_p, sep); 13 | 14 | if (!p_val) 15 | return -EINVAL; 16 | 17 | ret = kstrtoul(p_val, base, val); 18 | if (ret) 19 | return -EINVAL; 20 | 21 | return 0; 22 | } 23 | 24 | int fbtft_gamma_parse_str(struct fbtft_par *par, unsigned long *curves, 25 | const char *str, int size) 26 | { 27 | char *str_p, *curve_p = NULL; 28 | char *tmp; 29 | unsigned long val = 0; 30 | int ret = 0; 31 | int curve_counter, value_counter; 32 | 33 | fbtft_par_dbg(DEBUG_SYSFS, par, "%s() str=\n", __func__); 34 | 35 | if (!str || !curves) 36 | return -EINVAL; 37 | 38 | fbtft_par_dbg(DEBUG_SYSFS, par, "%s\n", str); 39 | 40 | tmp = kmalloc(size+1, GFP_KERNEL); 41 | if (!tmp) 42 | return -ENOMEM; 43 | memcpy(tmp, str, size+1); 44 | 45 | /* replace optional separators */ 46 | str_p = tmp; 47 | while (*str_p) { 48 | if (*str_p == ',') 49 | *str_p = ' '; 50 | if (*str_p == ';') 51 | *str_p = '\n'; 52 | str_p++; 53 | } 54 | 55 | str_p = strim(tmp); 56 | 57 | curve_counter = 0; 58 | while (str_p) { 59 | if (curve_counter == par->gamma.num_curves) { 60 | dev_err(par->info->device, "Gamma: Too many curves\n"); 61 | ret = -EINVAL; 62 | goto out; 63 | } 64 | curve_p = strsep(&str_p, "\n"); 65 | value_counter = 0; 66 | while (curve_p) { 67 | if (value_counter == par->gamma.num_values) { 68 | dev_err(par->info->device, 69 | "Gamma: Too many values\n"); 70 | ret = -EINVAL; 71 | goto out; 72 | } 73 | ret = get_next_ulong(&curve_p, &val, " ", 16); 74 | if (ret) 75 | goto out; 76 | curves[curve_counter * par->gamma.num_values + value_counter] = val; 77 | value_counter++; 78 | } 79 | if (value_counter != par->gamma.num_values) { 80 | dev_err(par->info->device, "Gamma: Too few values\n"); 81 | ret = -EINVAL; 82 | goto out; 83 | } 84 | curve_counter++; 85 | } 86 | if (curve_counter != par->gamma.num_curves) { 87 | dev_err(par->info->device, "Gamma: Too few curves\n"); 88 | ret = -EINVAL; 89 | goto out; 90 | } 91 | 92 | out: 93 | kfree(tmp); 94 | return ret; 95 | } 96 | 97 | static ssize_t 98 | sprintf_gamma(struct fbtft_par *par, unsigned long *curves, char *buf) 99 | { 100 | ssize_t len = 0; 101 | unsigned int i, j; 102 | 103 | mutex_lock(&par->gamma.lock); 104 | for (i = 0; i < par->gamma.num_curves; i++) { 105 | for (j = 0; j < par->gamma.num_values; j++) 106 | len += scnprintf(&buf[len], PAGE_SIZE, 107 | "%04lx ", curves[i*par->gamma.num_values + j]); 108 | buf[len-1] = '\n'; 109 | } 110 | mutex_unlock(&par->gamma.lock); 111 | 112 | return len; 113 | } 114 | 115 | static ssize_t store_gamma_curve(struct device *device, 116 | struct device_attribute *attr, 117 | const char *buf, size_t count) 118 | { 119 | struct fb_info *fb_info = dev_get_drvdata(device); 120 | struct fbtft_par *par = fb_info->par; 121 | unsigned long tmp_curves[FBTFT_GAMMA_MAX_VALUES_TOTAL]; 122 | int ret; 123 | 124 | ret = fbtft_gamma_parse_str(par, tmp_curves, buf, count); 125 | if (ret) 126 | return ret; 127 | 128 | ret = par->fbtftops.set_gamma(par, tmp_curves); 129 | if (ret) 130 | return ret; 131 | 132 | mutex_lock(&par->gamma.lock); 133 | memcpy(par->gamma.curves, tmp_curves, 134 | par->gamma.num_curves * par->gamma.num_values * sizeof(tmp_curves[0])); 135 | mutex_unlock(&par->gamma.lock); 136 | 137 | return count; 138 | } 139 | 140 | static ssize_t show_gamma_curve(struct device *device, 141 | struct device_attribute *attr, char *buf) 142 | { 143 | struct fb_info *fb_info = dev_get_drvdata(device); 144 | struct fbtft_par *par = fb_info->par; 145 | 146 | return sprintf_gamma(par, par->gamma.curves, buf); 147 | } 148 | 149 | static struct device_attribute gamma_device_attrs[] = { 150 | __ATTR(gamma, 0660, show_gamma_curve, store_gamma_curve), 151 | }; 152 | 153 | 154 | void fbtft_expand_debug_value(unsigned long *debug) 155 | { 156 | switch (*debug & 0b111) { 157 | case 1: 158 | *debug |= DEBUG_LEVEL_1; 159 | break; 160 | case 2: 161 | *debug |= DEBUG_LEVEL_2; 162 | break; 163 | case 3: 164 | *debug |= DEBUG_LEVEL_3; 165 | break; 166 | case 4: 167 | *debug |= DEBUG_LEVEL_4; 168 | break; 169 | case 5: 170 | *debug |= DEBUG_LEVEL_5; 171 | break; 172 | case 6: 173 | *debug |= DEBUG_LEVEL_6; 174 | break; 175 | case 7: 176 | *debug = 0xFFFFFFFF; 177 | break; 178 | } 179 | } 180 | 181 | static ssize_t store_debug(struct device *device, 182 | struct device_attribute *attr, 183 | const char *buf, size_t count) 184 | { 185 | struct fb_info *fb_info = dev_get_drvdata(device); 186 | struct fbtft_par *par = fb_info->par; 187 | int ret; 188 | 189 | ret = kstrtoul(buf, 10, &par->debug); 190 | if (ret) 191 | return ret; 192 | fbtft_expand_debug_value(&par->debug); 193 | 194 | return count; 195 | } 196 | 197 | static ssize_t show_debug(struct device *device, 198 | struct device_attribute *attr, char *buf) 199 | { 200 | struct fb_info *fb_info = dev_get_drvdata(device); 201 | struct fbtft_par *par = fb_info->par; 202 | 203 | return snprintf(buf, PAGE_SIZE, "%lu\n", par->debug); 204 | } 205 | 206 | static struct device_attribute debug_device_attr = \ 207 | __ATTR(debug, 0660, show_debug, store_debug); 208 | 209 | 210 | void fbtft_sysfs_init(struct fbtft_par *par) 211 | { 212 | device_create_file(par->info->dev, &debug_device_attr); 213 | if (par->gamma.curves && par->fbtftops.set_gamma) 214 | device_create_file(par->info->dev, &gamma_device_attrs[0]); 215 | } 216 | 217 | void fbtft_sysfs_exit(struct fbtft_par *par) 218 | { 219 | device_remove_file(par->info->dev, &debug_device_attr); 220 | if (par->gamma.curves && par->fbtftops.set_gamma) 221 | device_remove_file(par->info->dev, &gamma_device_attrs[0]); 222 | } 223 | --------------------------------------------------------------------------------