Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Driver for ORISE Technology OTM3225A SOC for TFT LCD
0003  * Copyright (C) 2017, EETS GmbH, Felix Brack <fb@ltec.ch>
0004  *
0005  * This driver implements a lcd device for the ORISE OTM3225A display
0006  * controller. The control interface to the display is SPI and the display's
0007  * memory is updated over the 16-bit RGB interface.
0008  * The main source of information for writing this driver was provided by the
0009  * OTM3225A datasheet from ORISE Technology. Some information arise from the
0010  * ILI9328 datasheet from ILITEK as well as from the datasheets and sample code
0011  * provided by Crystalfontz America Inc. who sells the CFAF240320A-032T, a 3.2"
0012  * TFT LC display using the OTM3225A controller.
0013  */
0014 
0015 #include <linux/delay.h>
0016 #include <linux/device.h>
0017 #include <linux/kernel.h>
0018 #include <linux/lcd.h>
0019 #include <linux/module.h>
0020 #include <linux/spi/spi.h>
0021 
0022 #define OTM3225A_INDEX_REG  0x70
0023 #define OTM3225A_DATA_REG   0x72
0024 
0025 /* instruction register list */
0026 #define DRIVER_OUTPUT_CTRL_1    0x01
0027 #define DRIVER_WAVEFORM_CTRL    0x02
0028 #define ENTRY_MODE      0x03
0029 #define SCALING_CTRL        0x04
0030 #define DISPLAY_CTRL_1      0x07
0031 #define DISPLAY_CTRL_2      0x08
0032 #define DISPLAY_CTRL_3      0x09
0033 #define FRAME_CYCLE_CTRL    0x0A
0034 #define EXT_DISP_IFACE_CTRL_1   0x0C
0035 #define FRAME_MAKER_POS     0x0D
0036 #define EXT_DISP_IFACE_CTRL_2   0x0F
0037 #define POWER_CTRL_1        0x10
0038 #define POWER_CTRL_2        0x11
0039 #define POWER_CTRL_3        0x12
0040 #define POWER_CTRL_4        0x13
0041 #define GRAM_ADDR_HORIZ_SET 0x20
0042 #define GRAM_ADDR_VERT_SET  0x21
0043 #define GRAM_READ_WRITE     0x22
0044 #define POWER_CTRL_7        0x29
0045 #define FRAME_RATE_CTRL     0x2B
0046 #define GAMMA_CTRL_1        0x30
0047 #define GAMMA_CTRL_2        0x31
0048 #define GAMMA_CTRL_3        0x32
0049 #define GAMMA_CTRL_4        0x35
0050 #define GAMMA_CTRL_5        0x36
0051 #define GAMMA_CTRL_6        0x37
0052 #define GAMMA_CTRL_7        0x38
0053 #define GAMMA_CTRL_8        0x39
0054 #define GAMMA_CTRL_9        0x3C
0055 #define GAMMA_CTRL_10       0x3D
0056 #define WINDOW_HORIZ_RAM_START  0x50
0057 #define WINDOW_HORIZ_RAM_END    0x51
0058 #define WINDOW_VERT_RAM_START   0x52
0059 #define WINDOW_VERT_RAM_END 0x53
0060 #define DRIVER_OUTPUT_CTRL_2    0x60
0061 #define BASE_IMG_DISPLAY_CTRL   0x61
0062 #define VERT_SCROLL_CTRL    0x6A
0063 #define PD1_DISPLAY_POS     0x80
0064 #define PD1_RAM_START       0x81
0065 #define PD1_RAM_END     0x82
0066 #define PD2_DISPLAY_POS     0x83
0067 #define PD2_RAM_START       0x84
0068 #define PD2_RAM_END     0x85
0069 #define PANEL_IFACE_CTRL_1  0x90
0070 #define PANEL_IFACE_CTRL_2  0x92
0071 #define PANEL_IFACE_CTRL_4  0x95
0072 #define PANEL_IFACE_CTRL_5  0x97
0073 
0074 struct otm3225a_data {
0075     struct spi_device *spi;
0076     struct lcd_device *ld;
0077     int power;
0078 };
0079 
0080 struct otm3225a_spi_instruction {
0081     unsigned char reg;  /* register to write */
0082     unsigned short value;   /* data to write to 'reg' */
0083     unsigned short delay;   /* delay in ms after write */
0084 };
0085 
0086 static struct otm3225a_spi_instruction display_init[] = {
0087     { DRIVER_OUTPUT_CTRL_1,     0x0000, 0 },
0088     { DRIVER_WAVEFORM_CTRL,     0x0700, 0 },
0089     { ENTRY_MODE,           0x50A0, 0 },
0090     { SCALING_CTRL,         0x0000, 0 },
0091     { DISPLAY_CTRL_2,       0x0606, 0 },
0092     { DISPLAY_CTRL_3,       0x0000, 0 },
0093     { FRAME_CYCLE_CTRL,     0x0000, 0 },
0094     { EXT_DISP_IFACE_CTRL_1,    0x0000, 0 },
0095     { FRAME_MAKER_POS,      0x0000, 0 },
0096     { EXT_DISP_IFACE_CTRL_2,    0x0002, 0 },
0097     { POWER_CTRL_2,         0x0007, 0 },
0098     { POWER_CTRL_3,         0x0000, 0 },
0099     { POWER_CTRL_4,         0x0000, 200 },
0100     { DISPLAY_CTRL_1,       0x0101, 0 },
0101     { POWER_CTRL_1,         0x12B0, 0 },
0102     { POWER_CTRL_2,         0x0007, 0 },
0103     { POWER_CTRL_3,         0x01BB, 50 },
0104     { POWER_CTRL_4,         0x0013, 0 },
0105     { POWER_CTRL_7,         0x0010, 50 },
0106     { GAMMA_CTRL_1,         0x000A, 0 },
0107     { GAMMA_CTRL_2,         0x1326, 0 },
0108     { GAMMA_CTRL_3,         0x0A29, 0 },
0109     { GAMMA_CTRL_4,         0x0A0A, 0 },
0110     { GAMMA_CTRL_5,         0x1E03, 0 },
0111     { GAMMA_CTRL_6,         0x031E, 0 },
0112     { GAMMA_CTRL_7,         0x0706, 0 },
0113     { GAMMA_CTRL_8,         0x0303, 0 },
0114     { GAMMA_CTRL_9,         0x010E, 0 },
0115     { GAMMA_CTRL_10,        0x040E, 0 },
0116     { WINDOW_HORIZ_RAM_START,   0x0000, 0 },
0117     { WINDOW_HORIZ_RAM_END,     0x00EF, 0 },
0118     { WINDOW_VERT_RAM_START,    0x0000, 0 },
0119     { WINDOW_VERT_RAM_END,      0x013F, 0 },
0120     { DRIVER_OUTPUT_CTRL_2,     0x2700, 0 },
0121     { BASE_IMG_DISPLAY_CTRL,    0x0001, 0 },
0122     { VERT_SCROLL_CTRL,     0x0000, 0 },
0123     { PD1_DISPLAY_POS,      0x0000, 0 },
0124     { PD1_RAM_START,        0x0000, 0 },
0125     { PD1_RAM_END,          0x0000, 0 },
0126     { PD2_DISPLAY_POS,      0x0000, 0 },
0127     { PD2_RAM_START,        0x0000, 0 },
0128     { PD2_RAM_END,          0x0000, 0 },
0129     { PANEL_IFACE_CTRL_1,       0x0010, 0 },
0130     { PANEL_IFACE_CTRL_2,       0x0000, 0 },
0131     { PANEL_IFACE_CTRL_4,       0x0210, 0 },
0132     { PANEL_IFACE_CTRL_5,       0x0000, 0 },
0133     { DISPLAY_CTRL_1,       0x0133, 0 },
0134 };
0135 
0136 static struct otm3225a_spi_instruction display_enable_rgb_interface[] = {
0137     { ENTRY_MODE,           0x1080, 0 },
0138     { GRAM_ADDR_HORIZ_SET,      0x0000, 0 },
0139     { GRAM_ADDR_VERT_SET,       0x0000, 0 },
0140     { EXT_DISP_IFACE_CTRL_1,    0x0111, 500 },
0141 };
0142 
0143 static struct otm3225a_spi_instruction display_off[] = {
0144     { DISPLAY_CTRL_1,   0x0131, 100 },
0145     { DISPLAY_CTRL_1,   0x0130, 100 },
0146     { DISPLAY_CTRL_1,   0x0100, 0 },
0147     { POWER_CTRL_1,     0x0280, 0 },
0148     { POWER_CTRL_3,     0x018B, 0 },
0149 };
0150 
0151 static struct otm3225a_spi_instruction display_on[] = {
0152     { POWER_CTRL_1,     0x1280, 0 },
0153     { DISPLAY_CTRL_1,   0x0101, 100 },
0154     { DISPLAY_CTRL_1,   0x0121, 0 },
0155     { DISPLAY_CTRL_1,   0x0123, 100 },
0156     { DISPLAY_CTRL_1,   0x0133, 10 },
0157 };
0158 
0159 static void otm3225a_write(struct spi_device *spi,
0160                struct otm3225a_spi_instruction *instruction,
0161                unsigned int count)
0162 {
0163     unsigned char buf[3];
0164 
0165     while (count--) {
0166         /* address register using index register */
0167         buf[0] = OTM3225A_INDEX_REG;
0168         buf[1] = 0x00;
0169         buf[2] = instruction->reg;
0170         spi_write(spi, buf, 3);
0171 
0172         /* write data to addressed register */
0173         buf[0] = OTM3225A_DATA_REG;
0174         buf[1] = (instruction->value >> 8) & 0xff;
0175         buf[2] = instruction->value & 0xff;
0176         spi_write(spi, buf, 3);
0177 
0178         /* execute delay if any */
0179         if (instruction->delay)
0180             msleep(instruction->delay);
0181         instruction++;
0182     }
0183 }
0184 
0185 static int otm3225a_set_power(struct lcd_device *ld, int power)
0186 {
0187     struct otm3225a_data *dd = lcd_get_data(ld);
0188 
0189     if (power == dd->power)
0190         return 0;
0191 
0192     if (power > FB_BLANK_UNBLANK)
0193         otm3225a_write(dd->spi, display_off, ARRAY_SIZE(display_off));
0194     else
0195         otm3225a_write(dd->spi, display_on, ARRAY_SIZE(display_on));
0196     dd->power = power;
0197 
0198     return 0;
0199 }
0200 
0201 static int otm3225a_get_power(struct lcd_device *ld)
0202 {
0203     struct otm3225a_data *dd = lcd_get_data(ld);
0204 
0205     return dd->power;
0206 }
0207 
0208 static struct lcd_ops otm3225a_ops = {
0209     .set_power = otm3225a_set_power,
0210     .get_power = otm3225a_get_power,
0211 };
0212 
0213 static int otm3225a_probe(struct spi_device *spi)
0214 {
0215     struct otm3225a_data *dd;
0216     struct lcd_device *ld;
0217     struct device *dev = &spi->dev;
0218 
0219     dd = devm_kzalloc(dev, sizeof(struct otm3225a_data), GFP_KERNEL);
0220     if (dd == NULL)
0221         return -ENOMEM;
0222 
0223     ld = devm_lcd_device_register(dev, dev_name(dev), dev, dd,
0224                       &otm3225a_ops);
0225     if (IS_ERR(ld))
0226         return PTR_ERR(ld);
0227 
0228     dd->spi = spi;
0229     dd->ld = ld;
0230     dev_set_drvdata(dev, dd);
0231 
0232     dev_info(dev, "Initializing and switching to RGB interface");
0233     otm3225a_write(spi, display_init, ARRAY_SIZE(display_init));
0234     otm3225a_write(spi, display_enable_rgb_interface,
0235                ARRAY_SIZE(display_enable_rgb_interface));
0236     return 0;
0237 }
0238 
0239 static struct spi_driver otm3225a_driver = {
0240     .driver = {
0241         .name = "otm3225a",
0242         .owner = THIS_MODULE,
0243     },
0244     .probe = otm3225a_probe,
0245 };
0246 
0247 module_spi_driver(otm3225a_driver);
0248 
0249 MODULE_AUTHOR("Felix Brack <fb@ltec.ch>");
0250 MODULE_DESCRIPTION("OTM3225A TFT LCD driver");
0251 MODULE_VERSION("1.0.0");
0252 MODULE_LICENSE("GPL v2");