1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * FB driver for the ILI9340 LCD Controller |
4 | * |
5 | * Copyright (C) 2013 Noralf Tronnes |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/kernel.h> |
10 | #include <linux/init.h> |
11 | #include <linux/delay.h> |
12 | #include <video/mipi_display.h> |
13 | |
14 | #include "fbtft.h" |
15 | |
16 | #define DRVNAME "fb_ili9340" |
17 | #define WIDTH 240 |
18 | #define HEIGHT 320 |
19 | |
20 | /* Init sequence taken from: Arduino Library for the Adafruit 2.2" display */ |
21 | static int init_display(struct fbtft_par *par) |
22 | { |
23 | par->fbtftops.reset(par); |
24 | |
25 | write_reg(par, 0xEF, 0x03, 0x80, 0x02); |
26 | write_reg(par, 0xCF, 0x00, 0XC1, 0X30); |
27 | write_reg(par, 0xED, 0x64, 0x03, 0X12, 0X81); |
28 | write_reg(par, 0xE8, 0x85, 0x00, 0x78); |
29 | write_reg(par, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02); |
30 | write_reg(par, 0xF7, 0x20); |
31 | write_reg(par, 0xEA, 0x00, 0x00); |
32 | |
33 | /* Power Control 1 */ |
34 | write_reg(par, 0xC0, 0x23); |
35 | |
36 | /* Power Control 2 */ |
37 | write_reg(par, 0xC1, 0x10); |
38 | |
39 | /* VCOM Control 1 */ |
40 | write_reg(par, 0xC5, 0x3e, 0x28); |
41 | |
42 | /* VCOM Control 2 */ |
43 | write_reg(par, 0xC7, 0x86); |
44 | |
45 | /* COLMOD: Pixel Format Set */ |
46 | /* 16 bits/pixel */ |
47 | write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, 0x55); |
48 | |
49 | /* Frame Rate Control */ |
50 | /* Division ratio = fosc, Frame Rate = 79Hz */ |
51 | write_reg(par, 0xB1, 0x00, 0x18); |
52 | |
53 | /* Display Function Control */ |
54 | write_reg(par, 0xB6, 0x08, 0x82, 0x27); |
55 | |
56 | /* Gamma Function Disable */ |
57 | write_reg(par, 0xF2, 0x00); |
58 | |
59 | /* Gamma curve selection */ |
60 | write_reg(par, MIPI_DCS_SET_GAMMA_CURVE, 0x01); |
61 | |
62 | /* Positive Gamma Correction */ |
63 | write_reg(par, 0xE0, |
64 | 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, |
65 | 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00); |
66 | |
67 | /* Negative Gamma Correction */ |
68 | write_reg(par, 0xE1, |
69 | 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, |
70 | 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F); |
71 | |
72 | write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); |
73 | |
74 | mdelay(120); |
75 | |
76 | write_reg(par, MIPI_DCS_SET_DISPLAY_ON); |
77 | |
78 | return 0; |
79 | } |
80 | |
81 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) |
82 | { |
83 | write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS, |
84 | xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); |
85 | |
86 | write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS, |
87 | ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); |
88 | |
89 | write_reg(par, MIPI_DCS_WRITE_MEMORY_START); |
90 | } |
91 | |
92 | #define ILI9340_MADCTL_MV 0x20 |
93 | #define ILI9340_MADCTL_MX 0x40 |
94 | #define ILI9340_MADCTL_MY 0x80 |
95 | static int set_var(struct fbtft_par *par) |
96 | { |
97 | u8 val; |
98 | |
99 | switch (par->info->var.rotate) { |
100 | case 270: |
101 | val = ILI9340_MADCTL_MV; |
102 | break; |
103 | case 180: |
104 | val = ILI9340_MADCTL_MY; |
105 | break; |
106 | case 90: |
107 | val = ILI9340_MADCTL_MV | ILI9340_MADCTL_MY | ILI9340_MADCTL_MX; |
108 | break; |
109 | default: |
110 | val = ILI9340_MADCTL_MX; |
111 | break; |
112 | } |
113 | /* Memory Access Control */ |
114 | write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, val | (par->bgr << 3)); |
115 | |
116 | return 0; |
117 | } |
118 | |
119 | static struct fbtft_display display = { |
120 | .regwidth = 8, |
121 | .width = WIDTH, |
122 | .height = HEIGHT, |
123 | .fbtftops = { |
124 | .init_display = init_display, |
125 | .set_addr_win = set_addr_win, |
126 | .set_var = set_var, |
127 | }, |
128 | }; |
129 | |
130 | FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9340" , &display); |
131 | |
132 | MODULE_ALIAS("spi:" DRVNAME); |
133 | MODULE_ALIAS("platform:" DRVNAME); |
134 | MODULE_ALIAS("spi:ili9340" ); |
135 | MODULE_ALIAS("platform:ili9340" ); |
136 | |
137 | MODULE_DESCRIPTION("FB driver for the ILI9340 LCD Controller" ); |
138 | MODULE_AUTHOR("Noralf Tronnes" ); |
139 | MODULE_LICENSE("GPL" ); |
140 | |