1 // SPDX-License-Identifier: GPL-2.0 2 /* Driver for ORISE Technology OTM3225A SOC for TFT LCD 3 * Copyright (C) 2017, EETS GmbH, Felix Brack <fb@ltec.ch> 4 * 5 * This driver implements a lcd device for the ORISE OTM3225A display 6 * controller. The control interface to the display is SPI and the display's 7 * memory is updated over the 16-bit RGB interface. 8 * The main source of information for writing this driver was provided by the 9 * OTM3225A datasheet from ORISE Technology. Some information arise from the 10 * ILI9328 datasheet from ILITEK as well as from the datasheets and sample code 11 * provided by Crystalfontz America Inc. who sells the CFAF240320A-032T, a 3.2" 12 * TFT LC display using the OTM3225A controller. 13 */ 14 15 #include <linux/delay.h> 16 #include <linux/device.h> 17 #include <linux/kernel.h> 18 #include <linux/lcd.h> 19 #include <linux/module.h> 20 #include <linux/spi/spi.h> 21 22 #define OTM3225A_INDEX_REG 0x70 23 #define OTM3225A_DATA_REG 0x72 24 25 /* instruction register list */ 26 #define DRIVER_OUTPUT_CTRL_1 0x01 27 #define DRIVER_WAVEFORM_CTRL 0x02 28 #define ENTRY_MODE 0x03 29 #define SCALING_CTRL 0x04 30 #define DISPLAY_CTRL_1 0x07 31 #define DISPLAY_CTRL_2 0x08 32 #define DISPLAY_CTRL_3 0x09 33 #define FRAME_CYCLE_CTRL 0x0A 34 #define EXT_DISP_IFACE_CTRL_1 0x0C 35 #define FRAME_MAKER_POS 0x0D 36 #define EXT_DISP_IFACE_CTRL_2 0x0F 37 #define POWER_CTRL_1 0x10 38 #define POWER_CTRL_2 0x11 39 #define POWER_CTRL_3 0x12 40 #define POWER_CTRL_4 0x13 41 #define GRAM_ADDR_HORIZ_SET 0x20 42 #define GRAM_ADDR_VERT_SET 0x21 43 #define GRAM_READ_WRITE 0x22 44 #define POWER_CTRL_7 0x29 45 #define FRAME_RATE_CTRL 0x2B 46 #define GAMMA_CTRL_1 0x30 47 #define GAMMA_CTRL_2 0x31 48 #define GAMMA_CTRL_3 0x32 49 #define GAMMA_CTRL_4 0x35 50 #define GAMMA_CTRL_5 0x36 51 #define GAMMA_CTRL_6 0x37 52 #define GAMMA_CTRL_7 0x38 53 #define GAMMA_CTRL_8 0x39 54 #define GAMMA_CTRL_9 0x3C 55 #define GAMMA_CTRL_10 0x3D 56 #define WINDOW_HORIZ_RAM_START 0x50 57 #define WINDOW_HORIZ_RAM_END 0x51 58 #define WINDOW_VERT_RAM_START 0x52 59 #define WINDOW_VERT_RAM_END 0x53 60 #define DRIVER_OUTPUT_CTRL_2 0x60 61 #define BASE_IMG_DISPLAY_CTRL 0x61 62 #define VERT_SCROLL_CTRL 0x6A 63 #define PD1_DISPLAY_POS 0x80 64 #define PD1_RAM_START 0x81 65 #define PD1_RAM_END 0x82 66 #define PD2_DISPLAY_POS 0x83 67 #define PD2_RAM_START 0x84 68 #define PD2_RAM_END 0x85 69 #define PANEL_IFACE_CTRL_1 0x90 70 #define PANEL_IFACE_CTRL_2 0x92 71 #define PANEL_IFACE_CTRL_4 0x95 72 #define PANEL_IFACE_CTRL_5 0x97 73 74 struct otm3225a_data { 75 struct spi_device *spi; 76 struct lcd_device *ld; 77 int power; 78 }; 79 80 struct otm3225a_spi_instruction { 81 unsigned char reg; /* register to write */ 82 unsigned short value; /* data to write to 'reg' */ 83 unsigned short delay; /* delay in ms after write */ 84 }; 85 86 static struct otm3225a_spi_instruction display_init[] = { 87 { DRIVER_OUTPUT_CTRL_1, 0x0000, 0 }, 88 { DRIVER_WAVEFORM_CTRL, 0x0700, 0 }, 89 { ENTRY_MODE, 0x50A0, 0 }, 90 { SCALING_CTRL, 0x0000, 0 }, 91 { DISPLAY_CTRL_2, 0x0606, 0 }, 92 { DISPLAY_CTRL_3, 0x0000, 0 }, 93 { FRAME_CYCLE_CTRL, 0x0000, 0 }, 94 { EXT_DISP_IFACE_CTRL_1, 0x0000, 0 }, 95 { FRAME_MAKER_POS, 0x0000, 0 }, 96 { EXT_DISP_IFACE_CTRL_2, 0x0002, 0 }, 97 { POWER_CTRL_2, 0x0007, 0 }, 98 { POWER_CTRL_3, 0x0000, 0 }, 99 { POWER_CTRL_4, 0x0000, 200 }, 100 { DISPLAY_CTRL_1, 0x0101, 0 }, 101 { POWER_CTRL_1, 0x12B0, 0 }, 102 { POWER_CTRL_2, 0x0007, 0 }, 103 { POWER_CTRL_3, 0x01BB, 50 }, 104 { POWER_CTRL_4, 0x0013, 0 }, 105 { POWER_CTRL_7, 0x0010, 50 }, 106 { GAMMA_CTRL_1, 0x000A, 0 }, 107 { GAMMA_CTRL_2, 0x1326, 0 }, 108 { GAMMA_CTRL_3, 0x0A29, 0 }, 109 { GAMMA_CTRL_4, 0x0A0A, 0 }, 110 { GAMMA_CTRL_5, 0x1E03, 0 }, 111 { GAMMA_CTRL_6, 0x031E, 0 }, 112 { GAMMA_CTRL_7, 0x0706, 0 }, 113 { GAMMA_CTRL_8, 0x0303, 0 }, 114 { GAMMA_CTRL_9, 0x010E, 0 }, 115 { GAMMA_CTRL_10, 0x040E, 0 }, 116 { WINDOW_HORIZ_RAM_START, 0x0000, 0 }, 117 { WINDOW_HORIZ_RAM_END, 0x00EF, 0 }, 118 { WINDOW_VERT_RAM_START, 0x0000, 0 }, 119 { WINDOW_VERT_RAM_END, 0x013F, 0 }, 120 { DRIVER_OUTPUT_CTRL_2, 0x2700, 0 }, 121 { BASE_IMG_DISPLAY_CTRL, 0x0001, 0 }, 122 { VERT_SCROLL_CTRL, 0x0000, 0 }, 123 { PD1_DISPLAY_POS, 0x0000, 0 }, 124 { PD1_RAM_START, 0x0000, 0 }, 125 { PD1_RAM_END, 0x0000, 0 }, 126 { PD2_DISPLAY_POS, 0x0000, 0 }, 127 { PD2_RAM_START, 0x0000, 0 }, 128 { PD2_RAM_END, 0x0000, 0 }, 129 { PANEL_IFACE_CTRL_1, 0x0010, 0 }, 130 { PANEL_IFACE_CTRL_2, 0x0000, 0 }, 131 { PANEL_IFACE_CTRL_4, 0x0210, 0 }, 132 { PANEL_IFACE_CTRL_5, 0x0000, 0 }, 133 { DISPLAY_CTRL_1, 0x0133, 0 }, 134 }; 135 136 static struct otm3225a_spi_instruction display_enable_rgb_interface[] = { 137 { ENTRY_MODE, 0x1080, 0 }, 138 { GRAM_ADDR_HORIZ_SET, 0x0000, 0 }, 139 { GRAM_ADDR_VERT_SET, 0x0000, 0 }, 140 { EXT_DISP_IFACE_CTRL_1, 0x0111, 500 }, 141 }; 142 143 static struct otm3225a_spi_instruction display_off[] = { 144 { DISPLAY_CTRL_1, 0x0131, 100 }, 145 { DISPLAY_CTRL_1, 0x0130, 100 }, 146 { DISPLAY_CTRL_1, 0x0100, 0 }, 147 { POWER_CTRL_1, 0x0280, 0 }, 148 { POWER_CTRL_3, 0x018B, 0 }, 149 }; 150 151 static struct otm3225a_spi_instruction display_on[] = { 152 { POWER_CTRL_1, 0x1280, 0 }, 153 { DISPLAY_CTRL_1, 0x0101, 100 }, 154 { DISPLAY_CTRL_1, 0x0121, 0 }, 155 { DISPLAY_CTRL_1, 0x0123, 100 }, 156 { DISPLAY_CTRL_1, 0x0133, 10 }, 157 }; 158 159 static void otm3225a_write(struct spi_device *spi, 160 struct otm3225a_spi_instruction *instruction, 161 unsigned int count) 162 { 163 unsigned char buf[3]; 164 165 while (count--) { 166 /* address register using index register */ 167 buf[0] = OTM3225A_INDEX_REG; 168 buf[1] = 0x00; 169 buf[2] = instruction->reg; 170 spi_write(spi, buf, 3); 171 172 /* write data to addressed register */ 173 buf[0] = OTM3225A_DATA_REG; 174 buf[1] = (instruction->value >> 8) & 0xff; 175 buf[2] = instruction->value & 0xff; 176 spi_write(spi, buf, 3); 177 178 /* execute delay if any */ 179 if (instruction->delay) 180 msleep(instruction->delay); 181 instruction++; 182 } 183 } 184 185 static int otm3225a_set_power(struct lcd_device *ld, int power) 186 { 187 struct otm3225a_data *dd = lcd_get_data(ld); 188 189 if (power == dd->power) 190 return 0; 191 192 if (power > FB_BLANK_UNBLANK) 193 otm3225a_write(dd->spi, display_off, ARRAY_SIZE(display_off)); 194 else 195 otm3225a_write(dd->spi, display_on, ARRAY_SIZE(display_on)); 196 dd->power = power; 197 198 return 0; 199 } 200 201 static int otm3225a_get_power(struct lcd_device *ld) 202 { 203 struct otm3225a_data *dd = lcd_get_data(ld); 204 205 return dd->power; 206 } 207 208 static const struct lcd_ops otm3225a_ops = { 209 .set_power = otm3225a_set_power, 210 .get_power = otm3225a_get_power, 211 }; 212 213 static int otm3225a_probe(struct spi_device *spi) 214 { 215 struct otm3225a_data *dd; 216 struct lcd_device *ld; 217 struct device *dev = &spi->dev; 218 219 dd = devm_kzalloc(dev, sizeof(struct otm3225a_data), GFP_KERNEL); 220 if (dd == NULL) 221 return -ENOMEM; 222 223 ld = devm_lcd_device_register(dev, dev_name(dev), dev, dd, 224 &otm3225a_ops); 225 if (IS_ERR(ld)) 226 return PTR_ERR(ld); 227 228 dd->spi = spi; 229 dd->ld = ld; 230 dev_set_drvdata(dev, dd); 231 232 dev_info(dev, "Initializing and switching to RGB interface"); 233 otm3225a_write(spi, display_init, ARRAY_SIZE(display_init)); 234 otm3225a_write(spi, display_enable_rgb_interface, 235 ARRAY_SIZE(display_enable_rgb_interface)); 236 return 0; 237 } 238 239 static struct spi_driver otm3225a_driver = { 240 .driver = { 241 .name = "otm3225a", 242 }, 243 .probe = otm3225a_probe, 244 }; 245 246 module_spi_driver(otm3225a_driver); 247 248 MODULE_AUTHOR("Felix Brack <fb@ltec.ch>"); 249 MODULE_DESCRIPTION("OTM3225A TFT LCD driver"); 250 MODULE_VERSION("1.0.0"); 251 MODULE_LICENSE("GPL v2"); 252