1 /* 2 * FB driver for the HX8357D LCD Controller 3 * Copyright (C) 2015 Adafruit Industries 4 * 5 * Based on the HX8347D FB driver 6 * Copyright (C) 2013 Christian Vogelgsang 7 * 8 * Based on driver code found here: https://github.com/watterott/r61505u-Adapter 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 21 #include <linux/module.h> 22 #include <linux/kernel.h> 23 #include <linux/init.h> 24 #include <linux/delay.h> 25 #include <video/mipi_display.h> 26 27 #include "fbtft.h" 28 #include "fb_hx8357d.h" 29 30 #define DRVNAME "fb_hx8357d" 31 #define WIDTH 320 32 #define HEIGHT 480 33 34 static int init_display(struct fbtft_par *par) 35 { 36 par->fbtftops.reset(par); 37 38 /* Reset things like Gamma */ 39 write_reg(par, MIPI_DCS_SOFT_RESET); 40 usleep_range(5000, 7000); 41 42 /* setextc */ 43 write_reg(par, HX8357D_SETC, 0xFF, 0x83, 0x57); 44 msleep(150); 45 46 /* setRGB which also enables SDO */ 47 write_reg(par, HX8357_SETRGB, 0x00, 0x00, 0x06, 0x06); 48 49 /* -1.52V */ 50 write_reg(par, HX8357D_SETCOM, 0x25); 51 52 /* Normal mode 70Hz, Idle mode 55 Hz */ 53 write_reg(par, HX8357_SETOSC, 0x68); 54 55 /* Set Panel - BGR, Gate direction swapped */ 56 write_reg(par, HX8357_SETPANEL, 0x05); 57 58 write_reg(par, HX8357_SETPWR1, 59 0x00, /* Not deep standby */ 60 0x15, /* BT */ 61 0x1C, /* VSPR */ 62 0x1C, /* VSNR */ 63 0x83, /* AP */ 64 0xAA); /* FS */ 65 66 write_reg(par, HX8357D_SETSTBA, 67 0x50, /* OPON normal */ 68 0x50, /* OPON idle */ 69 0x01, /* STBA */ 70 0x3C, /* STBA */ 71 0x1E, /* STBA */ 72 0x08); /* GEN */ 73 74 write_reg(par, HX8357D_SETCYC, 75 0x02, /* NW 0x02 */ 76 0x40, /* RTN */ 77 0x00, /* DIV */ 78 0x2A, /* DUM */ 79 0x2A, /* DUM */ 80 0x0D, /* GDON */ 81 0x78); /* GDOFF */ 82 83 write_reg(par, HX8357D_SETGAMMA, 84 0x02, 85 0x0A, 86 0x11, 87 0x1d, 88 0x23, 89 0x35, 90 0x41, 91 0x4b, 92 0x4b, 93 0x42, 94 0x3A, 95 0x27, 96 0x1B, 97 0x08, 98 0x09, 99 0x03, 100 0x02, 101 0x0A, 102 0x11, 103 0x1d, 104 0x23, 105 0x35, 106 0x41, 107 0x4b, 108 0x4b, 109 0x42, 110 0x3A, 111 0x27, 112 0x1B, 113 0x08, 114 0x09, 115 0x03, 116 0x00, 117 0x01); 118 119 /* 16 bit */ 120 write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, 0x55); 121 122 write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, 0xC0); 123 124 /* TE off */ 125 write_reg(par, MIPI_DCS_SET_TEAR_ON, 0x00); 126 127 /* tear line */ 128 write_reg(par, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02); 129 130 /* Exit Sleep */ 131 write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); 132 msleep(150); 133 134 /* display on */ 135 write_reg(par, MIPI_DCS_SET_DISPLAY_ON); 136 usleep_range(5000, 7000); 137 138 return 0; 139 } 140 141 static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 142 { 143 write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS, 144 xs >> 8, xs & 0xff, /* XSTART */ 145 xe >> 8, xe & 0xff); /* XEND */ 146 147 write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS, 148 ys >> 8, ys & 0xff, /* YSTART */ 149 ye >> 8, ye & 0xff); /* YEND */ 150 151 write_reg(par, MIPI_DCS_WRITE_MEMORY_START); 152 } 153 154 #define HX8357D_MADCTL_MY 0x80 155 #define HX8357D_MADCTL_MX 0x40 156 #define HX8357D_MADCTL_MV 0x20 157 #define HX8357D_MADCTL_ML 0x10 158 #define HX8357D_MADCTL_RGB 0x00 159 #define HX8357D_MADCTL_BGR 0x08 160 #define HX8357D_MADCTL_MH 0x04 161 static int set_var(struct fbtft_par *par) 162 { 163 u8 val; 164 165 switch (par->info->var.rotate) { 166 case 270: 167 val = HX8357D_MADCTL_MV | HX8357D_MADCTL_MX; 168 break; 169 case 180: 170 val = 0; 171 break; 172 case 90: 173 val = HX8357D_MADCTL_MV | HX8357D_MADCTL_MY; 174 break; 175 default: 176 val = HX8357D_MADCTL_MX | HX8357D_MADCTL_MY; 177 break; 178 } 179 180 val |= (par->bgr ? HX8357D_MADCTL_RGB : HX8357D_MADCTL_BGR); 181 182 /* Memory Access Control */ 183 write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, val); 184 185 return 0; 186 } 187 188 static struct fbtft_display display = { 189 .regwidth = 8, 190 .width = WIDTH, 191 .height = HEIGHT, 192 .gamma_num = 2, 193 .gamma_len = 14, 194 .fbtftops = { 195 .init_display = init_display, 196 .set_addr_win = set_addr_win, 197 .set_var = set_var, 198 }, 199 }; 200 201 FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8357d", &display); 202 203 MODULE_ALIAS("spi:" DRVNAME); 204 MODULE_ALIAS("platform:" DRVNAME); 205 MODULE_ALIAS("spi:hx8357d"); 206 MODULE_ALIAS("platform:hx8357d"); 207 208 MODULE_DESCRIPTION("FB driver for the HX8357D LCD Controller"); 209 MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); 210 MODULE_LICENSE("GPL"); 211