otm3225a.c (7174B)
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 74struct otm3225a_data { 75 struct spi_device *spi; 76 struct lcd_device *ld; 77 int power; 78}; 79 80struct 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 86static 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 136static 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 143static 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 151static 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 159static 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 185static 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 201static 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 208static struct lcd_ops otm3225a_ops = { 209 .set_power = otm3225a_set_power, 210 .get_power = otm3225a_get_power, 211}; 212 213static 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 239static struct spi_driver otm3225a_driver = { 240 .driver = { 241 .name = "otm3225a", 242 .owner = THIS_MODULE, 243 }, 244 .probe = otm3225a_probe, 245}; 246 247module_spi_driver(otm3225a_driver); 248 249MODULE_AUTHOR("Felix Brack <fb@ltec.ch>"); 250MODULE_DESCRIPTION("OTM3225A TFT LCD driver"); 251MODULE_VERSION("1.0.0"); 252MODULE_LICENSE("GPL v2");