blob: f78102aab2e64b71107cfb41687d8df6dc1b611d [file] [log] [blame]
Tomi Valkeinen2e1def02013-05-31 13:13:44 +03001/*
2 * TPO TD043MTEA1 Panel driver
3 *
4 * Author: Gražvydas Ignotas <notasas@gmail.com>
5 * Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <linux/module.h>
14#include <linux/delay.h>
15#include <linux/spi/spi.h>
16#include <linux/regulator/consumer.h>
Arnd Bergmannd0196c82016-05-11 18:05:39 +020017#include <linux/gpio/consumer.h>
Tomi Valkeinen2e1def02013-05-31 13:13:44 +030018#include <linux/err.h>
19#include <linux/slab.h>
Tomi Valkeinen597cc1e2014-05-16 12:28:36 +030020#include <linux/of_gpio.h>
Tomi Valkeinen2e1def02013-05-31 13:13:44 +030021
Peter Ujfalusi32043da2016-05-27 14:40:49 +030022#include "../dss/omapdss.h"
Tomi Valkeinen2e1def02013-05-31 13:13:44 +030023
24#define TPO_R02_MODE(x) ((x) & 7)
25#define TPO_R02_MODE_800x480 7
26#define TPO_R02_NCLK_RISING BIT(3)
27#define TPO_R02_HSYNC_HIGH BIT(4)
28#define TPO_R02_VSYNC_HIGH BIT(5)
29
30#define TPO_R03_NSTANDBY BIT(0)
31#define TPO_R03_EN_CP_CLK BIT(1)
32#define TPO_R03_EN_VGL_PUMP BIT(2)
33#define TPO_R03_EN_PWM BIT(3)
34#define TPO_R03_DRIVING_CAP_100 BIT(4)
35#define TPO_R03_EN_PRE_CHARGE BIT(6)
36#define TPO_R03_SOFTWARE_CTL BIT(7)
37
38#define TPO_R04_NFLIP_H BIT(0)
39#define TPO_R04_NFLIP_V BIT(1)
40#define TPO_R04_CP_CLK_FREQ_1H BIT(2)
41#define TPO_R04_VGL_FREQ_1H BIT(4)
42
43#define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \
44 TPO_R03_EN_VGL_PUMP | TPO_R03_EN_PWM | \
45 TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \
46 TPO_R03_SOFTWARE_CTL)
47
48#define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \
49 TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL)
50
51static const u16 tpo_td043_def_gamma[12] = {
52 105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023
53};
54
55struct panel_drv_data {
56 struct omap_dss_device dssdev;
57 struct omap_dss_device *in;
58
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +030059 struct videomode vm;
Tomi Valkeinen2e1def02013-05-31 13:13:44 +030060
61 int data_lines;
62
63 struct spi_device *spi;
64 struct regulator *vcc_reg;
65 int nreset_gpio;
66 u16 gamma[12];
67 u32 mode;
68 u32 hmirror:1;
69 u32 vmirror:1;
70 u32 powered_on:1;
71 u32 spi_suspended:1;
72 u32 power_on_resume:1;
73};
74
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +030075static const struct videomode tpo_td043_vm = {
Peter Ujfalusi81899062016-09-22 14:06:46 +030076 .hactive = 800,
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +030077 .vactive = 480,
Tomi Valkeinen2e1def02013-05-31 13:13:44 +030078
Tomi Valkeinend8d789412013-04-10 14:12:14 +030079 .pixelclock = 36000000,
Tomi Valkeinen2e1def02013-05-31 13:13:44 +030080
Peter Ujfalusi4dc22502016-09-22 14:06:48 +030081 .hsync_len = 1,
Peter Ujfalusi0a30e152016-09-22 14:06:49 +030082 .hfront_porch = 68,
Peter Ujfalusia85f4a82016-09-22 14:06:50 +030083 .hback_porch = 214,
Tomi Valkeinen2e1def02013-05-31 13:13:44 +030084
Peter Ujfalusid5bcf0a2016-09-22 14:06:51 +030085 .vsync_len = 1,
Peter Ujfalusi0996c682016-09-22 14:06:52 +030086 .vfront_porch = 39,
Peter Ujfalusi458540c2016-09-22 14:06:53 +030087 .vback_porch = 34,
Tomi Valkeinen2e1def02013-05-31 13:13:44 +030088
Peter Ujfalusi3fa3ab42016-09-22 14:06:58 +030089 .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
Peter Ujfalusid34afb72016-09-22 14:07:01 +030090 DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE |
91 DISPLAY_FLAGS_PIXDATA_NEGEDGE,
Tomi Valkeinen2e1def02013-05-31 13:13:44 +030092};
93
94#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
95
96static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
97{
98 struct spi_message m;
99 struct spi_transfer xfer;
100 u16 w;
101 int r;
102
103 spi_message_init(&m);
104
105 memset(&xfer, 0, sizeof(xfer));
106
107 w = ((u16)addr << 10) | (1 << 8) | data;
108 xfer.tx_buf = &w;
109 xfer.bits_per_word = 16;
110 xfer.len = 2;
111 spi_message_add_tail(&xfer, &m);
112
113 r = spi_sync(spi, &m);
114 if (r < 0)
115 dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r);
116 return r;
117}
118
119static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12])
120{
121 u8 i, val;
122
123 /* gamma bits [9:8] */
124 for (val = i = 0; i < 4; i++)
125 val |= (gamma[i] & 0x300) >> ((i + 1) * 2);
126 tpo_td043_write(spi, 0x11, val);
127
128 for (val = i = 0; i < 4; i++)
129 val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2);
130 tpo_td043_write(spi, 0x12, val);
131
132 for (val = i = 0; i < 4; i++)
133 val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2);
134 tpo_td043_write(spi, 0x13, val);
135
136 /* gamma bits [7:0] */
137 for (val = i = 0; i < 12; i++)
138 tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff);
139}
140
141static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v)
142{
143 u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V |
144 TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H;
145 if (h)
146 reg4 &= ~TPO_R04_NFLIP_H;
147 if (v)
148 reg4 &= ~TPO_R04_NFLIP_V;
149
150 return tpo_td043_write(spi, 4, reg4);
151}
152
153static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
154{
155 struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
156
157 ddata->hmirror = enable;
158 return tpo_td043_write_mirror(ddata->spi, ddata->hmirror,
159 ddata->vmirror);
160}
161
162static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev)
163{
164 struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
165
166 return ddata->hmirror;
167}
168
169static ssize_t tpo_td043_vmirror_show(struct device *dev,
170 struct device_attribute *attr, char *buf)
171{
172 struct panel_drv_data *ddata = dev_get_drvdata(dev);
173
174 return snprintf(buf, PAGE_SIZE, "%d\n", ddata->vmirror);
175}
176
177static ssize_t tpo_td043_vmirror_store(struct device *dev,
178 struct device_attribute *attr, const char *buf, size_t count)
179{
180 struct panel_drv_data *ddata = dev_get_drvdata(dev);
181 int val;
182 int ret;
183
184 ret = kstrtoint(buf, 0, &val);
185 if (ret < 0)
186 return ret;
187
188 val = !!val;
189
190 ret = tpo_td043_write_mirror(ddata->spi, ddata->hmirror, val);
191 if (ret < 0)
192 return ret;
193
194 ddata->vmirror = val;
195
196 return count;
197}
198
199static ssize_t tpo_td043_mode_show(struct device *dev,
200 struct device_attribute *attr, char *buf)
201{
202 struct panel_drv_data *ddata = dev_get_drvdata(dev);
203
204 return snprintf(buf, PAGE_SIZE, "%d\n", ddata->mode);
205}
206
207static ssize_t tpo_td043_mode_store(struct device *dev,
208 struct device_attribute *attr, const char *buf, size_t count)
209{
210 struct panel_drv_data *ddata = dev_get_drvdata(dev);
211 long val;
212 int ret;
213
214 ret = kstrtol(buf, 0, &val);
215 if (ret != 0 || val & ~7)
216 return -EINVAL;
217
218 ddata->mode = val;
219
220 val |= TPO_R02_NCLK_RISING;
221 tpo_td043_write(ddata->spi, 2, val);
222
223 return count;
224}
225
226static ssize_t tpo_td043_gamma_show(struct device *dev,
227 struct device_attribute *attr, char *buf)
228{
229 struct panel_drv_data *ddata = dev_get_drvdata(dev);
230 ssize_t len = 0;
231 int ret;
232 int i;
233
234 for (i = 0; i < ARRAY_SIZE(ddata->gamma); i++) {
235 ret = snprintf(buf + len, PAGE_SIZE - len, "%u ",
236 ddata->gamma[i]);
237 if (ret < 0)
238 return ret;
239 len += ret;
240 }
241 buf[len - 1] = '\n';
242
243 return len;
244}
245
246static ssize_t tpo_td043_gamma_store(struct device *dev,
247 struct device_attribute *attr, const char *buf, size_t count)
248{
249 struct panel_drv_data *ddata = dev_get_drvdata(dev);
250 unsigned int g[12];
251 int ret;
252 int i;
253
254 ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u",
255 &g[0], &g[1], &g[2], &g[3], &g[4], &g[5],
256 &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
257
258 if (ret != 12)
259 return -EINVAL;
260
261 for (i = 0; i < 12; i++)
262 ddata->gamma[i] = g[i];
263
264 tpo_td043_write_gamma(ddata->spi, ddata->gamma);
265
266 return count;
267}
268
269static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR,
270 tpo_td043_vmirror_show, tpo_td043_vmirror_store);
271static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
272 tpo_td043_mode_show, tpo_td043_mode_store);
273static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR,
274 tpo_td043_gamma_show, tpo_td043_gamma_store);
275
276static struct attribute *tpo_td043_attrs[] = {
277 &dev_attr_vmirror.attr,
278 &dev_attr_mode.attr,
279 &dev_attr_gamma.attr,
280 NULL,
281};
282
283static struct attribute_group tpo_td043_attr_group = {
284 .attrs = tpo_td043_attrs,
285};
286
287static int tpo_td043_power_on(struct panel_drv_data *ddata)
288{
289 int r;
290
291 if (ddata->powered_on)
292 return 0;
293
294 r = regulator_enable(ddata->vcc_reg);
295 if (r != 0)
296 return r;
297
298 /* wait for panel to stabilize */
299 msleep(160);
300
301 if (gpio_is_valid(ddata->nreset_gpio))
302 gpio_set_value(ddata->nreset_gpio, 1);
303
304 tpo_td043_write(ddata->spi, 2,
305 TPO_R02_MODE(ddata->mode) | TPO_R02_NCLK_RISING);
306 tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_NORMAL);
307 tpo_td043_write(ddata->spi, 0x20, 0xf0);
308 tpo_td043_write(ddata->spi, 0x21, 0xf0);
309 tpo_td043_write_mirror(ddata->spi, ddata->hmirror,
310 ddata->vmirror);
311 tpo_td043_write_gamma(ddata->spi, ddata->gamma);
312
313 ddata->powered_on = 1;
314 return 0;
315}
316
317static void tpo_td043_power_off(struct panel_drv_data *ddata)
318{
319 if (!ddata->powered_on)
320 return;
321
322 tpo_td043_write(ddata->spi, 3,
323 TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
324
325 if (gpio_is_valid(ddata->nreset_gpio))
326 gpio_set_value(ddata->nreset_gpio, 0);
327
328 /* wait for at least 2 vsyncs before cutting off power */
329 msleep(50);
330
331 tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_STANDBY);
332
333 regulator_disable(ddata->vcc_reg);
334
335 ddata->powered_on = 0;
336}
337
338static int tpo_td043_connect(struct omap_dss_device *dssdev)
339{
340 struct panel_drv_data *ddata = to_panel_data(dssdev);
341 struct omap_dss_device *in = ddata->in;
342 int r;
343
344 if (omapdss_device_is_connected(dssdev))
345 return 0;
346
347 r = in->ops.dpi->connect(in, dssdev);
348 if (r)
349 return r;
350
351 return 0;
352}
353
354static void tpo_td043_disconnect(struct omap_dss_device *dssdev)
355{
356 struct panel_drv_data *ddata = to_panel_data(dssdev);
357 struct omap_dss_device *in = ddata->in;
358
359 if (!omapdss_device_is_connected(dssdev))
360 return;
361
362 in->ops.dpi->disconnect(in, dssdev);
363}
364
365static int tpo_td043_enable(struct omap_dss_device *dssdev)
366{
367 struct panel_drv_data *ddata = to_panel_data(dssdev);
368 struct omap_dss_device *in = ddata->in;
369 int r;
370
371 if (!omapdss_device_is_connected(dssdev))
372 return -ENODEV;
373
374 if (omapdss_device_is_enabled(dssdev))
375 return 0;
376
Tomi Valkeinen597cc1e2014-05-16 12:28:36 +0300377 if (ddata->data_lines)
378 in->ops.dpi->set_data_lines(in, ddata->data_lines);
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +0300379 in->ops.dpi->set_timings(in, &ddata->vm);
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300380
381 r = in->ops.dpi->enable(in);
382 if (r)
383 return r;
384
385 /*
386 * If we are resuming from system suspend, SPI clocks might not be
387 * enabled yet, so we'll program the LCD from SPI PM resume callback.
388 */
389 if (!ddata->spi_suspended) {
390 r = tpo_td043_power_on(ddata);
391 if (r) {
392 in->ops.dpi->disable(in);
393 return r;
394 }
395 }
396
397 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
398
399 return 0;
400}
401
402static void tpo_td043_disable(struct omap_dss_device *dssdev)
403{
404 struct panel_drv_data *ddata = to_panel_data(dssdev);
405 struct omap_dss_device *in = ddata->in;
406
407 if (!omapdss_device_is_enabled(dssdev))
408 return;
409
410 in->ops.dpi->disable(in);
411
412 if (!ddata->spi_suspended)
413 tpo_td043_power_off(ddata);
414
415 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
416}
417
418static void tpo_td043_set_timings(struct omap_dss_device *dssdev,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +0300419 struct videomode *vm)
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300420{
421 struct panel_drv_data *ddata = to_panel_data(dssdev);
422 struct omap_dss_device *in = ddata->in;
423
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +0300424 ddata->vm = *vm;
425 dssdev->panel.vm = *vm;
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300426
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +0300427 in->ops.dpi->set_timings(in, vm);
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300428}
429
430static void tpo_td043_get_timings(struct omap_dss_device *dssdev,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +0300431 struct videomode *vm)
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300432{
433 struct panel_drv_data *ddata = to_panel_data(dssdev);
434
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +0300435 *vm = ddata->vm;
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300436}
437
438static int tpo_td043_check_timings(struct omap_dss_device *dssdev,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +0300439 struct videomode *vm)
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300440{
441 struct panel_drv_data *ddata = to_panel_data(dssdev);
442 struct omap_dss_device *in = ddata->in;
443
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +0300444 return in->ops.dpi->check_timings(in, vm);
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300445}
446
447static struct omap_dss_driver tpo_td043_ops = {
448 .connect = tpo_td043_connect,
449 .disconnect = tpo_td043_disconnect,
450
451 .enable = tpo_td043_enable,
452 .disable = tpo_td043_disable,
453
454 .set_timings = tpo_td043_set_timings,
455 .get_timings = tpo_td043_get_timings,
456 .check_timings = tpo_td043_check_timings,
457
458 .set_mirror = tpo_td043_set_hmirror,
459 .get_mirror = tpo_td043_get_hmirror,
460
461 .get_resolution = omapdss_default_get_resolution,
462};
463
Tomi Valkeinen597cc1e2014-05-16 12:28:36 +0300464static int tpo_td043_probe_of(struct spi_device *spi)
465{
466 struct device_node *node = spi->dev.of_node;
467 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
468 struct omap_dss_device *in;
469 int gpio;
470
471 gpio = of_get_named_gpio(node, "reset-gpios", 0);
472 if (!gpio_is_valid(gpio)) {
473 dev_err(&spi->dev, "failed to parse enable gpio\n");
474 return gpio;
475 }
476 ddata->nreset_gpio = gpio;
477
478 in = omapdss_of_find_source_for_first_ep(node);
479 if (IS_ERR(in)) {
480 dev_err(&spi->dev, "failed to find video source\n");
481 return PTR_ERR(in);
482 }
483
484 ddata->in = in;
485
486 return 0;
487}
488
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300489static int tpo_td043_probe(struct spi_device *spi)
490{
491 struct panel_drv_data *ddata;
492 struct omap_dss_device *dssdev;
493 int r;
494
495 dev_dbg(&spi->dev, "%s\n", __func__);
496
497 spi->bits_per_word = 16;
498 spi->mode = SPI_MODE_0;
499
500 r = spi_setup(spi);
501 if (r < 0) {
502 dev_err(&spi->dev, "spi_setup failed: %d\n", r);
503 return r;
504 }
505
506 ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
507 if (ddata == NULL)
508 return -ENOMEM;
509
510 dev_set_drvdata(&spi->dev, ddata);
511
512 ddata->spi = spi;
513
Tomi Valkeinen33c06b62016-02-22 18:14:52 +0200514 if (!spi->dev.of_node)
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300515 return -ENODEV;
Tomi Valkeinen33c06b62016-02-22 18:14:52 +0200516
517 r = tpo_td043_probe_of(spi);
518 if (r)
519 return r;
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300520
521 ddata->mode = TPO_R02_MODE_800x480;
522 memcpy(ddata->gamma, tpo_td043_def_gamma, sizeof(ddata->gamma));
523
524 ddata->vcc_reg = devm_regulator_get(&spi->dev, "vcc");
525 if (IS_ERR(ddata->vcc_reg)) {
526 dev_err(&spi->dev, "failed to get LCD VCC regulator\n");
527 r = PTR_ERR(ddata->vcc_reg);
528 goto err_regulator;
529 }
530
531 if (gpio_is_valid(ddata->nreset_gpio)) {
532 r = devm_gpio_request_one(&spi->dev,
533 ddata->nreset_gpio, GPIOF_OUT_INIT_LOW,
534 "lcd reset");
535 if (r < 0) {
536 dev_err(&spi->dev, "couldn't request reset GPIO\n");
537 goto err_gpio_req;
538 }
539 }
540
541 r = sysfs_create_group(&spi->dev.kobj, &tpo_td043_attr_group);
542 if (r) {
543 dev_err(&spi->dev, "failed to create sysfs files\n");
544 goto err_sysfs;
545 }
546
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +0300547 ddata->vm = tpo_td043_vm;
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300548
549 dssdev = &ddata->dssdev;
550 dssdev->dev = &spi->dev;
551 dssdev->driver = &tpo_td043_ops;
552 dssdev->type = OMAP_DISPLAY_TYPE_DPI;
553 dssdev->owner = THIS_MODULE;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +0300554 dssdev->panel.vm = ddata->vm;
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300555
556 r = omapdss_register_display(dssdev);
557 if (r) {
558 dev_err(&spi->dev, "Failed to register panel\n");
559 goto err_reg;
560 }
561
562 return 0;
563
564err_reg:
565 sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
566err_sysfs:
567err_gpio_req:
568err_regulator:
569 omap_dss_put_device(ddata->in);
570 return r;
571}
572
573static int tpo_td043_remove(struct spi_device *spi)
574{
575 struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
576 struct omap_dss_device *dssdev = &ddata->dssdev;
577 struct omap_dss_device *in = ddata->in;
578
579 dev_dbg(&ddata->spi->dev, "%s\n", __func__);
580
581 omapdss_unregister_display(dssdev);
582
583 tpo_td043_disable(dssdev);
584 tpo_td043_disconnect(dssdev);
585
586 omap_dss_put_device(in);
587
588 sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
589
590 return 0;
591}
592
593#ifdef CONFIG_PM_SLEEP
594static int tpo_td043_spi_suspend(struct device *dev)
595{
596 struct panel_drv_data *ddata = dev_get_drvdata(dev);
597
598 dev_dbg(dev, "tpo_td043_spi_suspend, tpo %p\n", ddata);
599
600 ddata->power_on_resume = ddata->powered_on;
601 tpo_td043_power_off(ddata);
602 ddata->spi_suspended = 1;
603
604 return 0;
605}
606
607static int tpo_td043_spi_resume(struct device *dev)
608{
609 struct panel_drv_data *ddata = dev_get_drvdata(dev);
610 int ret;
611
612 dev_dbg(dev, "tpo_td043_spi_resume\n");
613
614 if (ddata->power_on_resume) {
615 ret = tpo_td043_power_on(ddata);
616 if (ret)
617 return ret;
618 }
619 ddata->spi_suspended = 0;
620
621 return 0;
622}
623#endif
624
625static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm,
626 tpo_td043_spi_suspend, tpo_td043_spi_resume);
627
Tomi Valkeinen597cc1e2014-05-16 12:28:36 +0300628static const struct of_device_id tpo_td043_of_match[] = {
629 { .compatible = "omapdss,tpo,td043mtea1", },
630 {},
631};
632
633MODULE_DEVICE_TABLE(of, tpo_td043_of_match);
634
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300635static struct spi_driver tpo_td043_spi_driver = {
636 .driver = {
637 .name = "panel-tpo-td043mtea1",
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300638 .pm = &tpo_td043_spi_pm,
Tomi Valkeinen597cc1e2014-05-16 12:28:36 +0300639 .of_match_table = tpo_td043_of_match,
Tomi Valkeinen422ccbd2014-10-16 09:54:25 +0300640 .suppress_bind_attrs = true,
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300641 },
642 .probe = tpo_td043_probe,
643 .remove = tpo_td043_remove,
644};
645
646module_spi_driver(tpo_td043_spi_driver);
647
Tomi Valkeinen597cc1e2014-05-16 12:28:36 +0300648MODULE_ALIAS("spi:tpo,td043mtea1");
Tomi Valkeinen2e1def02013-05-31 13:13:44 +0300649MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
650MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver");
651MODULE_LICENSE("GPL");