1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Panel driver for the TPO TPG110 400CH LTPS TFT LCD Single Chip |
4 | * Digital Driver. |
5 | * |
6 | * This chip drives a TFT LCD, so it does not know what kind of |
7 | * display is actually connected to it, so the width and height of that |
8 | * display needs to be supplied from the machine configuration. |
9 | * |
10 | * Author: |
11 | * Linus Walleij <linus.walleij@linaro.org> |
12 | */ |
13 | #include <drm/drm_modes.h> |
14 | #include <drm/drm_panel.h> |
15 | |
16 | #include <linux/bitops.h> |
17 | #include <linux/delay.h> |
18 | #include <linux/gpio/consumer.h> |
19 | #include <linux/init.h> |
20 | #include <linux/kernel.h> |
21 | #include <linux/module.h> |
22 | #include <linux/of.h> |
23 | #include <linux/platform_device.h> |
24 | #include <linux/spi/spi.h> |
25 | |
26 | #define TPG110_TEST 0x00 |
27 | #define TPG110_CHIPID 0x01 |
28 | #define TPG110_CTRL1 0x02 |
29 | #define TPG110_RES_MASK GENMASK(2, 0) |
30 | #define TPG110_RES_800X480 0x07 |
31 | #define TPG110_RES_640X480 0x06 |
32 | #define TPG110_RES_480X272 0x05 |
33 | #define TPG110_RES_480X640 0x04 |
34 | #define TPG110_RES_480X272_D 0x01 /* Dual scan: outputs 800x480 */ |
35 | #define TPG110_RES_400X240_D 0x00 /* Dual scan: outputs 800x480 */ |
36 | #define TPG110_CTRL2 0x03 |
37 | #define TPG110_CTRL2_PM BIT(0) |
38 | #define TPG110_CTRL2_RES_PM_CTRL BIT(7) |
39 | |
40 | /** |
41 | * struct tpg110_panel_mode - lookup struct for the supported modes |
42 | */ |
43 | struct tpg110_panel_mode { |
44 | /** |
45 | * @name: the name of this panel |
46 | */ |
47 | const char *name; |
48 | /** |
49 | * @magic: the magic value from the detection register |
50 | */ |
51 | u32 magic; |
52 | /** |
53 | * @mode: the DRM display mode for this panel |
54 | */ |
55 | struct drm_display_mode mode; |
56 | /** |
57 | * @bus_flags: the DRM bus flags for this panel e.g. inverted clock |
58 | */ |
59 | u32 bus_flags; |
60 | }; |
61 | |
62 | /** |
63 | * struct tpg110 - state container for the TPG110 panel |
64 | */ |
65 | struct tpg110 { |
66 | /** |
67 | * @dev: the container device |
68 | */ |
69 | struct device *dev; |
70 | /** |
71 | * @spi: the corresponding SPI device |
72 | */ |
73 | struct spi_device *spi; |
74 | /** |
75 | * @panel: the DRM panel instance for this device |
76 | */ |
77 | struct drm_panel panel; |
78 | /** |
79 | * @panel_mode: the panel mode as detected |
80 | */ |
81 | const struct tpg110_panel_mode *panel_mode; |
82 | /** |
83 | * @width: the width of this panel in mm |
84 | */ |
85 | u32 width; |
86 | /** |
87 | * @height: the height of this panel in mm |
88 | */ |
89 | u32 height; |
90 | /** |
91 | * @grestb: reset GPIO line |
92 | */ |
93 | struct gpio_desc *grestb; |
94 | }; |
95 | |
96 | /* |
97 | * TPG110 modes, these are the simple modes, the dualscan modes that |
98 | * take 400x240 or 480x272 in and display as 800x480 are not listed. |
99 | */ |
100 | static const struct tpg110_panel_mode tpg110_modes[] = { |
101 | { |
102 | .name = "800x480 RGB" , |
103 | .magic = TPG110_RES_800X480, |
104 | .mode = { |
105 | .clock = 33200, |
106 | .hdisplay = 800, |
107 | .hsync_start = 800 + 40, |
108 | .hsync_end = 800 + 40 + 1, |
109 | .htotal = 800 + 40 + 1 + 216, |
110 | .vdisplay = 480, |
111 | .vsync_start = 480 + 10, |
112 | .vsync_end = 480 + 10 + 1, |
113 | .vtotal = 480 + 10 + 1 + 35, |
114 | }, |
115 | .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, |
116 | }, |
117 | { |
118 | .name = "640x480 RGB" , |
119 | .magic = TPG110_RES_640X480, |
120 | .mode = { |
121 | .clock = 25200, |
122 | .hdisplay = 640, |
123 | .hsync_start = 640 + 24, |
124 | .hsync_end = 640 + 24 + 1, |
125 | .htotal = 640 + 24 + 1 + 136, |
126 | .vdisplay = 480, |
127 | .vsync_start = 480 + 18, |
128 | .vsync_end = 480 + 18 + 1, |
129 | .vtotal = 480 + 18 + 1 + 27, |
130 | }, |
131 | .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, |
132 | }, |
133 | { |
134 | .name = "480x272 RGB" , |
135 | .magic = TPG110_RES_480X272, |
136 | .mode = { |
137 | .clock = 9000, |
138 | .hdisplay = 480, |
139 | .hsync_start = 480 + 2, |
140 | .hsync_end = 480 + 2 + 1, |
141 | .htotal = 480 + 2 + 1 + 43, |
142 | .vdisplay = 272, |
143 | .vsync_start = 272 + 2, |
144 | .vsync_end = 272 + 2 + 1, |
145 | .vtotal = 272 + 2 + 1 + 12, |
146 | }, |
147 | .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, |
148 | }, |
149 | { |
150 | .name = "480x640 RGB" , |
151 | .magic = TPG110_RES_480X640, |
152 | .mode = { |
153 | .clock = 20500, |
154 | .hdisplay = 480, |
155 | .hsync_start = 480 + 2, |
156 | .hsync_end = 480 + 2 + 1, |
157 | .htotal = 480 + 2 + 1 + 43, |
158 | .vdisplay = 640, |
159 | .vsync_start = 640 + 4, |
160 | .vsync_end = 640 + 4 + 1, |
161 | .vtotal = 640 + 4 + 1 + 8, |
162 | }, |
163 | .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, |
164 | }, |
165 | { |
166 | .name = "400x240 RGB" , |
167 | .magic = TPG110_RES_400X240_D, |
168 | .mode = { |
169 | .clock = 8300, |
170 | .hdisplay = 400, |
171 | .hsync_start = 400 + 20, |
172 | .hsync_end = 400 + 20 + 1, |
173 | .htotal = 400 + 20 + 1 + 108, |
174 | .vdisplay = 240, |
175 | .vsync_start = 240 + 2, |
176 | .vsync_end = 240 + 2 + 1, |
177 | .vtotal = 240 + 2 + 1 + 20, |
178 | }, |
179 | .bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, |
180 | }, |
181 | }; |
182 | |
183 | static inline struct tpg110 * |
184 | to_tpg110(struct drm_panel *panel) |
185 | { |
186 | return container_of(panel, struct tpg110, panel); |
187 | } |
188 | |
189 | static u8 tpg110_readwrite_reg(struct tpg110 *tpg, bool write, |
190 | u8 address, u8 outval) |
191 | { |
192 | struct spi_message m; |
193 | struct spi_transfer t[2]; |
194 | u8 buf[2]; |
195 | int ret; |
196 | |
197 | spi_message_init(m: &m); |
198 | memset(t, 0, sizeof(t)); |
199 | |
200 | if (write) { |
201 | /* |
202 | * Clear address bit 0, 1 when writing, just to be sure |
203 | * The actual bit indicating a write here is bit 1, bit |
204 | * 0 is just surplus to pad it up to 8 bits. |
205 | */ |
206 | buf[0] = address << 2; |
207 | buf[0] &= ~0x03; |
208 | buf[1] = outval; |
209 | |
210 | t[0].bits_per_word = 8; |
211 | t[0].tx_buf = &buf[0]; |
212 | t[0].len = 1; |
213 | |
214 | t[1].tx_buf = &buf[1]; |
215 | t[1].len = 1; |
216 | t[1].bits_per_word = 8; |
217 | } else { |
218 | /* Set address bit 0 to 1 to read */ |
219 | buf[0] = address << 1; |
220 | buf[0] |= 0x01; |
221 | |
222 | /* |
223 | * The last bit/clock is Hi-Z turnaround cycle, so we need |
224 | * to send only 7 bits here. The 8th bit is the high impedance |
225 | * turn-around cycle. |
226 | */ |
227 | t[0].bits_per_word = 7; |
228 | t[0].tx_buf = &buf[0]; |
229 | t[0].len = 1; |
230 | |
231 | t[1].rx_buf = &buf[1]; |
232 | t[1].len = 1; |
233 | t[1].bits_per_word = 8; |
234 | } |
235 | |
236 | spi_message_add_tail(t: &t[0], m: &m); |
237 | spi_message_add_tail(t: &t[1], m: &m); |
238 | ret = spi_sync(spi: tpg->spi, message: &m); |
239 | if (ret) { |
240 | dev_err(tpg->dev, "SPI message error %d\n" , ret); |
241 | return ret; |
242 | } |
243 | if (write) |
244 | return 0; |
245 | /* Read */ |
246 | return buf[1]; |
247 | } |
248 | |
249 | static u8 tpg110_read_reg(struct tpg110 *tpg, u8 address) |
250 | { |
251 | return tpg110_readwrite_reg(tpg, write: false, address, outval: 0); |
252 | } |
253 | |
254 | static void tpg110_write_reg(struct tpg110 *tpg, u8 address, u8 outval) |
255 | { |
256 | tpg110_readwrite_reg(tpg, write: true, address, outval); |
257 | } |
258 | |
259 | static int tpg110_startup(struct tpg110 *tpg) |
260 | { |
261 | u8 val; |
262 | int i; |
263 | |
264 | /* De-assert the reset signal */ |
265 | gpiod_set_value_cansleep(desc: tpg->grestb, value: 0); |
266 | usleep_range(min: 1000, max: 2000); |
267 | dev_dbg(tpg->dev, "de-asserted GRESTB\n" ); |
268 | |
269 | /* Test display communication */ |
270 | tpg110_write_reg(tpg, TPG110_TEST, outval: 0x55); |
271 | val = tpg110_read_reg(tpg, TPG110_TEST); |
272 | if (val != 0x55) { |
273 | dev_err(tpg->dev, "failed communication test\n" ); |
274 | return -ENODEV; |
275 | } |
276 | |
277 | val = tpg110_read_reg(tpg, TPG110_CHIPID); |
278 | dev_info(tpg->dev, "TPG110 chip ID: %d version: %d\n" , |
279 | val >> 4, val & 0x0f); |
280 | |
281 | /* Show display resolution */ |
282 | val = tpg110_read_reg(tpg, TPG110_CTRL1); |
283 | val &= TPG110_RES_MASK; |
284 | switch (val) { |
285 | case TPG110_RES_400X240_D: |
286 | dev_info(tpg->dev, "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n" ); |
287 | break; |
288 | case TPG110_RES_480X272_D: |
289 | dev_info(tpg->dev, "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n" ); |
290 | break; |
291 | case TPG110_RES_480X640: |
292 | dev_info(tpg->dev, "480x640 RGB\n" ); |
293 | break; |
294 | case TPG110_RES_480X272: |
295 | dev_info(tpg->dev, "480x272 RGB\n" ); |
296 | break; |
297 | case TPG110_RES_640X480: |
298 | dev_info(tpg->dev, "640x480 RGB\n" ); |
299 | break; |
300 | case TPG110_RES_800X480: |
301 | dev_info(tpg->dev, "800x480 RGB\n" ); |
302 | break; |
303 | default: |
304 | dev_err(tpg->dev, "ILLEGAL RESOLUTION 0x%02x\n" , val); |
305 | break; |
306 | } |
307 | |
308 | /* From the producer side, this is the same resolution */ |
309 | if (val == TPG110_RES_480X272_D) |
310 | val = TPG110_RES_480X272; |
311 | |
312 | for (i = 0; i < ARRAY_SIZE(tpg110_modes); i++) { |
313 | const struct tpg110_panel_mode *pm; |
314 | |
315 | pm = &tpg110_modes[i]; |
316 | if (pm->magic == val) { |
317 | tpg->panel_mode = pm; |
318 | break; |
319 | } |
320 | } |
321 | if (i == ARRAY_SIZE(tpg110_modes)) { |
322 | dev_err(tpg->dev, "unsupported mode (%02x) detected\n" , val); |
323 | return -ENODEV; |
324 | } |
325 | |
326 | val = tpg110_read_reg(tpg, TPG110_CTRL2); |
327 | dev_info(tpg->dev, "resolution and standby is controlled by %s\n" , |
328 | (val & TPG110_CTRL2_RES_PM_CTRL) ? "software" : "hardware" ); |
329 | /* Take control over resolution and standby */ |
330 | val |= TPG110_CTRL2_RES_PM_CTRL; |
331 | tpg110_write_reg(tpg, TPG110_CTRL2, outval: val); |
332 | |
333 | return 0; |
334 | } |
335 | |
336 | static int tpg110_disable(struct drm_panel *panel) |
337 | { |
338 | struct tpg110 *tpg = to_tpg110(panel); |
339 | u8 val; |
340 | |
341 | /* Put chip into standby */ |
342 | val = tpg110_read_reg(tpg, TPG110_CTRL2_PM); |
343 | val &= ~TPG110_CTRL2_PM; |
344 | tpg110_write_reg(tpg, TPG110_CTRL2_PM, outval: val); |
345 | |
346 | return 0; |
347 | } |
348 | |
349 | static int tpg110_enable(struct drm_panel *panel) |
350 | { |
351 | struct tpg110 *tpg = to_tpg110(panel); |
352 | u8 val; |
353 | |
354 | /* Take chip out of standby */ |
355 | val = tpg110_read_reg(tpg, TPG110_CTRL2_PM); |
356 | val |= TPG110_CTRL2_PM; |
357 | tpg110_write_reg(tpg, TPG110_CTRL2_PM, outval: val); |
358 | |
359 | return 0; |
360 | } |
361 | |
362 | /** |
363 | * tpg110_get_modes() - return the appropriate mode |
364 | * @panel: the panel to get the mode for |
365 | * @connector: reference to the central DRM connector control structure |
366 | * |
367 | * This currently does not present a forest of modes, instead it |
368 | * presents the mode that is configured for the system under use, |
369 | * and which is detected by reading the registers of the display. |
370 | */ |
371 | static int tpg110_get_modes(struct drm_panel *panel, |
372 | struct drm_connector *connector) |
373 | { |
374 | struct tpg110 *tpg = to_tpg110(panel); |
375 | struct drm_display_mode *mode; |
376 | |
377 | connector->display_info.width_mm = tpg->width; |
378 | connector->display_info.height_mm = tpg->height; |
379 | connector->display_info.bus_flags = tpg->panel_mode->bus_flags; |
380 | |
381 | mode = drm_mode_duplicate(dev: connector->dev, mode: &tpg->panel_mode->mode); |
382 | if (!mode) |
383 | return -ENOMEM; |
384 | drm_mode_set_name(mode); |
385 | mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; |
386 | |
387 | mode->width_mm = tpg->width; |
388 | mode->height_mm = tpg->height; |
389 | |
390 | drm_mode_probed_add(connector, mode); |
391 | |
392 | return 1; |
393 | } |
394 | |
395 | static const struct drm_panel_funcs tpg110_drm_funcs = { |
396 | .disable = tpg110_disable, |
397 | .enable = tpg110_enable, |
398 | .get_modes = tpg110_get_modes, |
399 | }; |
400 | |
401 | static int tpg110_probe(struct spi_device *spi) |
402 | { |
403 | struct device *dev = &spi->dev; |
404 | struct device_node *np = dev->of_node; |
405 | struct tpg110 *tpg; |
406 | int ret; |
407 | |
408 | tpg = devm_kzalloc(dev, size: sizeof(*tpg), GFP_KERNEL); |
409 | if (!tpg) |
410 | return -ENOMEM; |
411 | tpg->dev = dev; |
412 | |
413 | /* We get the physical display dimensions from the DT */ |
414 | ret = of_property_read_u32(np, propname: "width-mm" , out_value: &tpg->width); |
415 | if (ret) |
416 | dev_err(dev, "no panel width specified\n" ); |
417 | ret = of_property_read_u32(np, propname: "height-mm" , out_value: &tpg->height); |
418 | if (ret) |
419 | dev_err(dev, "no panel height specified\n" ); |
420 | |
421 | /* This asserts the GRESTB signal, putting the display into reset */ |
422 | tpg->grestb = devm_gpiod_get(dev, con_id: "grestb" , flags: GPIOD_OUT_HIGH); |
423 | if (IS_ERR(ptr: tpg->grestb)) { |
424 | dev_err(dev, "no GRESTB GPIO\n" ); |
425 | return -ENODEV; |
426 | } |
427 | |
428 | spi->bits_per_word = 8; |
429 | spi->mode |= SPI_3WIRE_HIZ; |
430 | ret = spi_setup(spi); |
431 | if (ret < 0) { |
432 | dev_err(dev, "spi setup failed.\n" ); |
433 | return ret; |
434 | } |
435 | tpg->spi = spi; |
436 | |
437 | ret = tpg110_startup(tpg); |
438 | if (ret) |
439 | return ret; |
440 | |
441 | drm_panel_init(panel: &tpg->panel, dev, funcs: &tpg110_drm_funcs, |
442 | DRM_MODE_CONNECTOR_DPI); |
443 | |
444 | ret = drm_panel_of_backlight(panel: &tpg->panel); |
445 | if (ret) |
446 | return ret; |
447 | |
448 | spi_set_drvdata(spi, data: tpg); |
449 | |
450 | drm_panel_add(panel: &tpg->panel); |
451 | |
452 | return 0; |
453 | } |
454 | |
455 | static void tpg110_remove(struct spi_device *spi) |
456 | { |
457 | struct tpg110 *tpg = spi_get_drvdata(spi); |
458 | |
459 | drm_panel_remove(panel: &tpg->panel); |
460 | } |
461 | |
462 | static const struct of_device_id tpg110_match[] = { |
463 | { .compatible = "tpo,tpg110" , }, |
464 | {}, |
465 | }; |
466 | MODULE_DEVICE_TABLE(of, tpg110_match); |
467 | |
468 | static const struct spi_device_id tpg110_ids[] = { |
469 | { "tpg110" }, |
470 | { }, |
471 | }; |
472 | MODULE_DEVICE_TABLE(spi, tpg110_ids); |
473 | |
474 | static struct spi_driver tpg110_driver = { |
475 | .probe = tpg110_probe, |
476 | .remove = tpg110_remove, |
477 | .id_table = tpg110_ids, |
478 | .driver = { |
479 | .name = "tpo-tpg110-panel" , |
480 | .of_match_table = tpg110_match, |
481 | }, |
482 | }; |
483 | module_spi_driver(tpg110_driver); |
484 | |
485 | MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>" ); |
486 | MODULE_DESCRIPTION("TPO TPG110 panel driver" ); |
487 | MODULE_LICENSE("GPL v2" ); |
488 | |