Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * FB driver for the HX8340BN LCD Controller
0004  *
0005  * This display uses 9-bit SPI: Data/Command bit + 8 data bits
0006  * For platforms that doesn't support 9-bit, the driver is capable
0007  * of emulating this using 8-bit transfer.
0008  * This is done by transferring eight 9-bit words in 9 bytes.
0009  *
0010  * Copyright (C) 2013 Noralf Tronnes
0011  */
0012 
0013 #include <linux/module.h>
0014 #include <linux/kernel.h>
0015 #include <linux/init.h>
0016 #include <linux/vmalloc.h>
0017 #include <linux/spi/spi.h>
0018 #include <linux/delay.h>
0019 #include <video/mipi_display.h>
0020 
0021 #include "fbtft.h"
0022 
0023 #define DRVNAME     "fb_hx8340bn"
0024 #define WIDTH       176
0025 #define HEIGHT      220
0026 #define TXBUFLEN    (4 * PAGE_SIZE)
0027 #define DEFAULT_GAMMA   "1 3 0E 5 0 2 09 0 6 1 7 1 0 2 2\n" \
0028             "3 3 17 8 4 7 05 7 6 0 3 1 6 0 0 "
0029 
0030 static bool emulate;
0031 module_param(emulate, bool, 0000);
0032 MODULE_PARM_DESC(emulate, "Force emulation in 9-bit mode");
0033 
0034 static int init_display(struct fbtft_par *par)
0035 {
0036     par->fbtftops.reset(par);
0037 
0038     /* BTL221722-276L startup sequence, from datasheet */
0039 
0040     /*
0041      * SETEXTCOM: Set extended command set (C1h)
0042      * This command is used to set extended command set access enable.
0043      * Enable: After command (C1h), must write: ffh,83h,40h
0044      */
0045     write_reg(par, 0xC1, 0xFF, 0x83, 0x40);
0046 
0047     /*
0048      * Sleep out
0049      * This command turns off sleep mode.
0050      * In this mode the DC/DC converter is enabled, Internal oscillator
0051      * is started, and panel scanning is started.
0052      */
0053     write_reg(par, 0x11);
0054     mdelay(150);
0055 
0056     /* Undoc'd register? */
0057     write_reg(par, 0xCA, 0x70, 0x00, 0xD9);
0058 
0059     /*
0060      * SETOSC: Set Internal Oscillator (B0h)
0061      * This command is used to set internal oscillator related settings
0062      *  OSC_EN: Enable internal oscillator
0063      *  Internal oscillator frequency: 125% x 2.52MHz
0064      */
0065     write_reg(par, 0xB0, 0x01, 0x11);
0066 
0067     /* Drive ability setting */
0068     write_reg(par, 0xC9, 0x90, 0x49, 0x10, 0x28, 0x28, 0x10, 0x00, 0x06);
0069     mdelay(20);
0070 
0071     /*
0072      * SETPWCTR5: Set Power Control 5(B5h)
0073      * This command is used to set VCOM Low and VCOM High Voltage
0074      * VCOMH 0110101 :  3.925
0075      * VCOML 0100000 : -1.700
0076      * 45h=69  VCOMH: "VMH" + 5d   VCOML: "VMH" + 5d
0077      */
0078     write_reg(par, 0xB5, 0x35, 0x20, 0x45);
0079 
0080     /*
0081      * SETPWCTR4: Set Power Control 4(B4h)
0082      *  VRH[4:0]:   Specify the VREG1 voltage adjusting.
0083      *          VREG1 voltage is for gamma voltage setting.
0084      *  BT[2:0]:    Switch the output factor of step-up circuit 2
0085      *          for VGH and VGL voltage generation.
0086      */
0087     write_reg(par, 0xB4, 0x33, 0x25, 0x4C);
0088     mdelay(10);
0089 
0090     /*
0091      * Interface Pixel Format (3Ah)
0092      * This command is used to define the format of RGB picture data,
0093      * which is to be transfer via the system and RGB interface.
0094      * RGB interface: 16 Bit/Pixel
0095      */
0096     write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
0097 
0098     /*
0099      * Display on (29h)
0100      * This command is used to recover from DISPLAY OFF mode.
0101      * Output from the Frame Memory is enabled.
0102      */
0103     write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
0104     mdelay(10);
0105 
0106     return 0;
0107 }
0108 
0109 static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
0110 {
0111     write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS, 0x00, xs, 0x00, xe);
0112     write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS, 0x00, ys, 0x00, ye);
0113     write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
0114 }
0115 
0116 static int set_var(struct fbtft_par *par)
0117 {
0118     /* MADCTL - Memory data access control */
0119     /* RGB/BGR can be set with H/W pin SRGB and MADCTL BGR bit */
0120 #define MY BIT(7)
0121 #define MX BIT(6)
0122 #define MV BIT(5)
0123     switch (par->info->var.rotate) {
0124     case 0:
0125         write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, par->bgr << 3);
0126         break;
0127     case 270:
0128         write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
0129               MX | MV | (par->bgr << 3));
0130         break;
0131     case 180:
0132         write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
0133               MX | MY | (par->bgr << 3));
0134         break;
0135     case 90:
0136         write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
0137               MY | MV | (par->bgr << 3));
0138         break;
0139     }
0140 
0141     return 0;
0142 }
0143 
0144 /*
0145  * Gamma Curve selection, GC (only GC0 can be customized):
0146  *   0 = 2.2, 1 = 1.8, 2 = 2.5, 3 = 1.0
0147  * Gamma string format:
0148  *   OP0 OP1 CP0 CP1 CP2 CP3 CP4 MP0 MP1 MP2 MP3 MP4 MP5 CGM0 CGM1
0149  *   ON0 ON1 CN0 CN1 CN2 CN3 CN4 MN0 MN1 MN2 MN3 MN4 MN5 XXXX  GC
0150  */
0151 #define CURVE(num, idx)  curves[(num) * par->gamma.num_values + (idx)]
0152 static int set_gamma(struct fbtft_par *par, u32 *curves)
0153 {
0154     static const unsigned long mask[] = {
0155         0x0f, 0x0f, 0x1f, 0x0f, 0x0f, 0x0f, 0x1f, 0x07, 0x07, 0x07,
0156         0x07, 0x07, 0x07, 0x03, 0x03, 0x0f, 0x0f, 0x1f, 0x0f, 0x0f,
0157         0x0f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00,
0158     };
0159     int i, j;
0160 
0161     /* apply mask */
0162     for (i = 0; i < par->gamma.num_curves; i++)
0163         for (j = 0; j < par->gamma.num_values; j++)
0164             CURVE(i, j) &= mask[i * par->gamma.num_values + j];
0165 
0166     /* Gamma Set (26h) */
0167     write_reg(par, MIPI_DCS_SET_GAMMA_CURVE, 1 << CURVE(1, 14));
0168 
0169     if (CURVE(1, 14))
0170         return 0; /* only GC0 can be customized */
0171 
0172     write_reg(par, 0xC2,
0173           (CURVE(0, 8) << 4) | CURVE(0, 7),
0174           (CURVE(0, 10) << 4) | CURVE(0, 9),
0175           (CURVE(0, 12) << 4) | CURVE(0, 11),
0176           CURVE(0, 2),
0177           (CURVE(0, 4) << 4) | CURVE(0, 3),
0178           CURVE(0, 5),
0179           CURVE(0, 6),
0180           (CURVE(0, 1) << 4) | CURVE(0, 0),
0181           (CURVE(0, 14) << 2) | CURVE(0, 13));
0182 
0183     write_reg(par, 0xC3,
0184           (CURVE(1, 8) << 4) | CURVE(1, 7),
0185           (CURVE(1, 10) << 4) | CURVE(1, 9),
0186           (CURVE(1, 12) << 4) | CURVE(1, 11),
0187           CURVE(1, 2),
0188           (CURVE(1, 4) << 4) | CURVE(1, 3),
0189           CURVE(1, 5),
0190           CURVE(1, 6),
0191           (CURVE(1, 1) << 4) | CURVE(1, 0));
0192 
0193     mdelay(10);
0194 
0195     return 0;
0196 }
0197 
0198 #undef CURVE
0199 
0200 static struct fbtft_display display = {
0201     .regwidth = 8,
0202     .width = WIDTH,
0203     .height = HEIGHT,
0204     .txbuflen = TXBUFLEN,
0205     .gamma_num = 2,
0206     .gamma_len = 15,
0207     .gamma = DEFAULT_GAMMA,
0208     .fbtftops = {
0209         .init_display = init_display,
0210         .set_addr_win = set_addr_win,
0211         .set_var = set_var,
0212         .set_gamma = set_gamma,
0213     },
0214 };
0215 
0216 FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8340bn", &display);
0217 
0218 MODULE_ALIAS("spi:" DRVNAME);
0219 MODULE_ALIAS("platform:" DRVNAME);
0220 MODULE_ALIAS("spi:hx8340bn");
0221 MODULE_ALIAS("platform:hx8340bn");
0222 
0223 MODULE_DESCRIPTION("FB driver for the HX8340BN LCD Controller");
0224 MODULE_AUTHOR("Noralf Tronnes");
0225 MODULE_LICENSE("GPL");