1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * linux/drivers/video/mmp/panel/tpo_tj032md01bw.c
4  * active panel using spi interface to do init
5  *
6  * Copyright (C) 2012 Marvell Technology Group Ltd.
7  * Authors:  Guoqing Li <ligq@marvell.com>
8  *          Lisa Du <cldu@marvell.com>
9  *          Zhou Zhu <zzhu3@marvell.com>
10  */
11 
12 #include <linux/module.h>
13 #include <linux/moduleparam.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/string.h>
17 #include <linux/delay.h>
18 #include <linux/platform_device.h>
19 #include <linux/err.h>
20 #include <linux/spi/spi.h>
21 #include <video/mmp_disp.h>
22 
23 static u16 init[] = {
24 	0x0801,
25 	0x0800,
26 	0x0200,
27 	0x0304,
28 	0x040e,
29 	0x0903,
30 	0x0b18,
31 	0x0c53,
32 	0x0d01,
33 	0x0ee0,
34 	0x0f01,
35 	0x1058,
36 	0x201e,
37 	0x210a,
38 	0x220a,
39 	0x231e,
40 	0x2400,
41 	0x2532,
42 	0x2600,
43 	0x27ac,
44 	0x2904,
45 	0x2aa2,
46 	0x2b45,
47 	0x2c45,
48 	0x2d15,
49 	0x2e5a,
50 	0x2fff,
51 	0x306b,
52 	0x310d,
53 	0x3248,
54 	0x3382,
55 	0x34bd,
56 	0x35e7,
57 	0x3618,
58 	0x3794,
59 	0x3801,
60 	0x395d,
61 	0x3aae,
62 	0x3bff,
63 	0x07c9,
64 };
65 
66 static u16 poweroff[] = {
67 	0x07d9,
68 };
69 
70 struct tpohvga_plat_data {
71 	void (*plat_onoff)(int status);
72 	struct spi_device *spi;
73 };
74 
75 static void tpohvga_onoff(struct mmp_panel *panel, int status)
76 {
77 	struct tpohvga_plat_data *plat = panel->plat_data;
78 	int ret;
79 
80 	if (status) {
81 		plat->plat_onoff(1);
82 
83 		ret = spi_write(plat->spi, init, sizeof(init));
84 		if (ret < 0)
85 			dev_warn(panel->dev, "init cmd failed(%d)\n", ret);
86 	} else {
87 		ret = spi_write(plat->spi, poweroff, sizeof(poweroff));
88 		if (ret < 0)
89 			dev_warn(panel->dev, "poweroff cmd failed(%d)\n", ret);
90 
91 		plat->plat_onoff(0);
92 	}
93 }
94 
95 static struct mmp_mode mmp_modes_tpohvga[] = {
96 	[0] = {
97 		.pixclock_freq = 10394400,
98 		.refresh = 60,
99 		.xres = 320,
100 		.yres = 480,
101 		.hsync_len = 10,
102 		.left_margin = 15,
103 		.right_margin = 10,
104 		.vsync_len = 2,
105 		.upper_margin = 4,
106 		.lower_margin = 2,
107 		.invert_pixclock = 1,
108 		.pix_fmt_out = PIXFMT_RGB565,
109 	},
110 };
111 
112 static int tpohvga_get_modelist(struct mmp_panel *panel,
113 		struct mmp_mode **modelist)
114 {
115 	*modelist = mmp_modes_tpohvga;
116 	return 1;
117 }
118 
119 static struct mmp_panel panel_tpohvga = {
120 	.name = "tpohvga",
121 	.panel_type = PANELTYPE_ACTIVE,
122 	.get_modelist = tpohvga_get_modelist,
123 	.set_onoff = tpohvga_onoff,
124 };
125 
126 static int tpohvga_probe(struct spi_device *spi)
127 {
128 	struct mmp_mach_panel_info *mi;
129 	int ret;
130 	struct tpohvga_plat_data *plat_data;
131 
132 	/* get configs from platform data */
133 	mi = spi->dev.platform_data;
134 	if (mi == NULL) {
135 		dev_err(&spi->dev, "%s: no platform data defined\n", __func__);
136 		return -EINVAL;
137 	}
138 
139 	/* setup spi related info */
140 	spi->bits_per_word = 16;
141 	ret = spi_setup(spi);
142 	if (ret < 0) {
143 		dev_err(&spi->dev, "spi setup failed %d", ret);
144 		return ret;
145 	}
146 
147 	plat_data = kzalloc(sizeof(*plat_data), GFP_KERNEL);
148 	if (plat_data == NULL)
149 		return -ENOMEM;
150 
151 	plat_data->spi = spi;
152 	plat_data->plat_onoff = mi->plat_set_onoff;
153 	panel_tpohvga.plat_data = plat_data;
154 	panel_tpohvga.plat_path_name = mi->plat_path_name;
155 	panel_tpohvga.dev = &spi->dev;
156 
157 	mmp_register_panel(&panel_tpohvga);
158 
159 	return 0;
160 }
161 
162 static struct spi_driver panel_tpohvga_driver = {
163 	.driver		= {
164 		.name	= "tpo-hvga",
165 	},
166 	.probe		= tpohvga_probe,
167 };
168 module_spi_driver(panel_tpohvga_driver);
169 
170 MODULE_AUTHOR("Lisa Du<cldu@marvell.com>");
171 MODULE_DESCRIPTION("Panel driver for tpohvga");
172 MODULE_LICENSE("GPL");
173