linux/drivers/staging/fbtft/fb_hx8340bn.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * FB driver for the HX8340BN LCD Controller
   4 *
   5 * This display uses 9-bit SPI: Data/Command bit + 8 data bits
   6 * For platforms that doesn't support 9-bit, the driver is capable
   7 * of emulating this using 8-bit transfer.
   8 * This is done by transferring eight 9-bit words in 9 bytes.
   9 *
  10 * Copyright (C) 2013 Noralf Tronnes
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/kernel.h>
  15#include <linux/init.h>
  16#include <linux/vmalloc.h>
  17#include <linux/spi/spi.h>
  18#include <linux/delay.h>
  19#include <video/mipi_display.h>
  20
  21#include "fbtft.h"
  22
  23#define DRVNAME         "fb_hx8340bn"
  24#define WIDTH           176
  25#define HEIGHT          220
  26#define TXBUFLEN        (4 * PAGE_SIZE)
  27#define DEFAULT_GAMMA   "1 3 0E 5 0 2 09 0 6 1 7 1 0 2 2\n" \
  28                        "3 3 17 8 4 7 05 7 6 0 3 1 6 0 0 "
  29
  30static bool emulate;
  31module_param(emulate, bool, 0000);
  32MODULE_PARM_DESC(emulate, "Force emulation in 9-bit mode");
  33
  34static int init_display(struct fbtft_par *par)
  35{
  36        par->fbtftops.reset(par);
  37
  38        /* BTL221722-276L startup sequence, from datasheet */
  39
  40        /*
  41         * SETEXTCOM: Set extended command set (C1h)
  42         * This command is used to set extended command set access enable.
  43         * Enable: After command (C1h), must write: ffh,83h,40h
  44         */
  45        write_reg(par, 0xC1, 0xFF, 0x83, 0x40);
  46
  47        /*
  48         * Sleep out
  49         * This command turns off sleep mode.
  50         * In this mode the DC/DC converter is enabled, Internal oscillator
  51         * is started, and panel scanning is started.
  52         */
  53        write_reg(par, 0x11);
  54        mdelay(150);
  55
  56        /* Undoc'd register? */
  57        write_reg(par, 0xCA, 0x70, 0x00, 0xD9);
  58
  59        /*
  60         * SETOSC: Set Internal Oscillator (B0h)
  61         * This command is used to set internal oscillator related settings
  62         *      OSC_EN: Enable internal oscillator
  63         *      Internal oscillator frequency: 125% x 2.52MHz
  64         */
  65        write_reg(par, 0xB0, 0x01, 0x11);
  66
  67        /* Drive ability setting */
  68        write_reg(par, 0xC9, 0x90, 0x49, 0x10, 0x28, 0x28, 0x10, 0x00, 0x06);
  69        mdelay(20);
  70
  71        /*
  72         * SETPWCTR5: Set Power Control 5(B5h)
  73         * This command is used to set VCOM Low and VCOM High Voltage
  74         * VCOMH 0110101 :  3.925
  75         * VCOML 0100000 : -1.700
  76         * 45h=69  VCOMH: "VMH" + 5d   VCOML: "VMH" + 5d
  77         */
  78        write_reg(par, 0xB5, 0x35, 0x20, 0x45);
  79
  80        /*
  81         * SETPWCTR4: Set Power Control 4(B4h)
  82         *      VRH[4:0]:       Specify the VREG1 voltage adjusting.
  83         *                      VREG1 voltage is for gamma voltage setting.
  84         *      BT[2:0]:        Switch the output factor of step-up circuit 2
  85         *                      for VGH and VGL voltage generation.
  86         */
  87        write_reg(par, 0xB4, 0x33, 0x25, 0x4C);
  88        mdelay(10);
  89
  90        /*
  91         * Interface Pixel Format (3Ah)
  92         * This command is used to define the format of RGB picture data,
  93         * which is to be transfer via the system and RGB interface.
  94         * RGB interface: 16 Bit/Pixel
  95         */
  96        write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
  97
  98        /*
  99         * Display on (29h)
 100         * This command is used to recover from DISPLAY OFF mode.
 101         * Output from the Frame Memory is enabled.
 102         */
 103        write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
 104        mdelay(10);
 105
 106        return 0;
 107}
 108
 109static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
 110{
 111        write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS, 0x00, xs, 0x00, xe);
 112        write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS, 0x00, ys, 0x00, ye);
 113        write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
 114}
 115
 116static int set_var(struct fbtft_par *par)
 117{
 118        /* MADCTL - Memory data access control */
 119        /* RGB/BGR can be set with H/W pin SRGB and MADCTL BGR bit */
 120#define MY BIT(7)
 121#define MX BIT(6)
 122#define MV BIT(5)
 123        switch (par->info->var.rotate) {
 124        case 0:
 125                write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, par->bgr << 3);
 126                break;
 127        case 270:
 128                write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
 129                          MX | MV | (par->bgr << 3));
 130                break;
 131        case 180:
 132                write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
 133                          MX | MY | (par->bgr << 3));
 134                break;
 135        case 90:
 136                write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
 137                          MY | MV | (par->bgr << 3));
 138                break;
 139        }
 140
 141        return 0;
 142}
 143
 144/*
 145 * Gamma Curve selection, GC (only GC0 can be customized):
 146 *   0 = 2.2, 1 = 1.8, 2 = 2.5, 3 = 1.0
 147 * Gamma string format:
 148 *   OP0 OP1 CP0 CP1 CP2 CP3 CP4 MP0 MP1 MP2 MP3 MP4 MP5 CGM0 CGM1
 149 *   ON0 ON1 CN0 CN1 CN2 CN3 CN4 MN0 MN1 MN2 MN3 MN4 MN5 XXXX  GC
 150 */
 151#define CURVE(num, idx)  curves[(num) * par->gamma.num_values + (idx)]
 152static int set_gamma(struct fbtft_par *par, u32 *curves)
 153{
 154        static const unsigned long mask[] = {
 155                0x0f, 0x0f, 0x1f, 0x0f, 0x0f, 0x0f, 0x1f, 0x07, 0x07, 0x07,
 156                0x07, 0x07, 0x07, 0x03, 0x03, 0x0f, 0x0f, 0x1f, 0x0f, 0x0f,
 157                0x0f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00,
 158        };
 159        int i, j;
 160
 161        /* apply mask */
 162        for (i = 0; i < par->gamma.num_curves; i++)
 163                for (j = 0; j < par->gamma.num_values; j++)
 164                        CURVE(i, j) &= mask[i * par->gamma.num_values + j];
 165
 166        /* Gamma Set (26h) */
 167        write_reg(par, MIPI_DCS_SET_GAMMA_CURVE, 1 << CURVE(1, 14));
 168
 169        if (CURVE(1, 14))
 170                return 0; /* only GC0 can be customized */
 171
 172        write_reg(par, 0xC2,
 173                  (CURVE(0, 8) << 4) | CURVE(0, 7),
 174                  (CURVE(0, 10) << 4) | CURVE(0, 9),
 175                  (CURVE(0, 12) << 4) | CURVE(0, 11),
 176                  CURVE(0, 2),
 177                  (CURVE(0, 4) << 4) | CURVE(0, 3),
 178                  CURVE(0, 5),
 179                  CURVE(0, 6),
 180                  (CURVE(0, 1) << 4) | CURVE(0, 0),
 181                  (CURVE(0, 14) << 2) | CURVE(0, 13));
 182
 183        write_reg(par, 0xC3,
 184                  (CURVE(1, 8) << 4) | CURVE(1, 7),
 185                  (CURVE(1, 10) << 4) | CURVE(1, 9),
 186                  (CURVE(1, 12) << 4) | CURVE(1, 11),
 187                  CURVE(1, 2),
 188                  (CURVE(1, 4) << 4) | CURVE(1, 3),
 189                  CURVE(1, 5),
 190                  CURVE(1, 6),
 191                  (CURVE(1, 1) << 4) | CURVE(1, 0));
 192
 193        mdelay(10);
 194
 195        return 0;
 196}
 197
 198#undef CURVE
 199
 200static struct fbtft_display display = {
 201        .regwidth = 8,
 202        .width = WIDTH,
 203        .height = HEIGHT,
 204        .txbuflen = TXBUFLEN,
 205        .gamma_num = 2,
 206        .gamma_len = 15,
 207        .gamma = DEFAULT_GAMMA,
 208        .fbtftops = {
 209                .init_display = init_display,
 210                .set_addr_win = set_addr_win,
 211                .set_var = set_var,
 212                .set_gamma = set_gamma,
 213        },
 214};
 215
 216FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8340bn", &display);
 217
 218MODULE_ALIAS("spi:" DRVNAME);
 219MODULE_ALIAS("platform:" DRVNAME);
 220MODULE_ALIAS("spi:hx8340bn");
 221MODULE_ALIAS("platform:hx8340bn");
 222
 223MODULE_DESCRIPTION("FB driver for the HX8340BN LCD Controller");
 224MODULE_AUTHOR("Noralf Tronnes");
 225MODULE_LICENSE("GPL");
 226