xref: /linux/drivers/gpu/drm/panel/panel-samsung-s6d27a1.c (revision 34f7c6e7d4396090692a09789db231e12cb4762b)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Panel driver for the Samsung S6D27A1 480x800 DPI RGB panel.
4  * Found in the Samsung Galaxy Ace 2 GT-I8160 mobile phone.
5  */
6 
7 #include <drm/drm_mipi_dbi.h>
8 #include <drm/drm_modes.h>
9 #include <drm/drm_panel.h>
10 
11 #include <linux/delay.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/init.h>
14 #include <linux/kernel.h>
15 #include <linux/media-bus-format.h>
16 #include <linux/module.h>
17 #include <linux/of.h>
18 #include <linux/regulator/consumer.h>
19 #include <linux/spi/spi.h>
20 
21 #include <video/mipi_display.h>
22 
23 #define S6D27A1_PASSWD_L2	0xF0	/* Password Command for Level 2 Control */
24 #define S6D27A1_RESCTL		0xB3	/* Resolution Select Control */
25 #define S6D27A1_PANELCTL2	0xB4	/* ASG Signal Control */
26 #define S6D27A1_READID1		0xDA	/* Read panel ID 1 */
27 #define S6D27A1_READID2		0xDB	/* Read panel ID 2 */
28 #define S6D27A1_READID3		0xDC	/* Read panel ID 3 */
29 #define S6D27A1_DISPCTL		0xF2	/* Display Control */
30 #define S6D27A1_MANPWR		0xF3	/* Manual Control */
31 #define S6D27A1_PWRCTL1		0xF4	/* Power Control */
32 #define S6D27A1_SRCCTL		0xF6	/* Source Control */
33 #define S6D27A1_PANELCTL	0xF7	/* Panel Control*/
34 
35 static const u8 s6d27a1_dbi_read_commands[] = {
36 	S6D27A1_READID1,
37 	S6D27A1_READID2,
38 	S6D27A1_READID3,
39 	0, /* sentinel */
40 };
41 
42 struct s6d27a1 {
43 	struct device *dev;
44 	struct mipi_dbi dbi;
45 	struct drm_panel panel;
46 	struct gpio_desc *reset;
47 	struct regulator_bulk_data regulators[2];
48 };
49 
50 static const struct drm_display_mode s6d27a1_480_800_mode = {
51 	/*
52 	 * The vendor driver states that the S6D27A1 panel
53 	 * has a pixel clock frequency of 49920000 Hz / 2 = 24960000 Hz.
54 	 */
55 	.clock = 24960,
56 	.hdisplay = 480,
57 	.hsync_start = 480 + 63,
58 	.hsync_end = 480 + 63 + 2,
59 	.htotal = 480 + 63 + 2 + 63,
60 	.vdisplay = 800,
61 	.vsync_start = 800 + 11,
62 	.vsync_end = 800 + 11 + 2,
63 	.vtotal = 800 + 11 + 2 + 10,
64 	.width_mm = 50,
65 	.height_mm = 84,
66 	.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
67 };
68 
69 static inline struct s6d27a1 *to_s6d27a1(struct drm_panel *panel)
70 {
71 	return container_of(panel, struct s6d27a1, panel);
72 }
73 
74 static void s6d27a1_read_mtp_id(struct s6d27a1 *ctx)
75 {
76 	struct mipi_dbi *dbi = &ctx->dbi;
77 	u8 id1, id2, id3;
78 	int ret;
79 
80 	ret = mipi_dbi_command_read(dbi, S6D27A1_READID1, &id1);
81 	if (ret) {
82 		dev_err(ctx->dev, "unable to read MTP ID 1\n");
83 		return;
84 	}
85 	ret = mipi_dbi_command_read(dbi, S6D27A1_READID2, &id2);
86 	if (ret) {
87 		dev_err(ctx->dev, "unable to read MTP ID 2\n");
88 		return;
89 	}
90 	ret = mipi_dbi_command_read(dbi, S6D27A1_READID3, &id3);
91 	if (ret) {
92 		dev_err(ctx->dev, "unable to read MTP ID 3\n");
93 		return;
94 	}
95 	dev_info(ctx->dev, "MTP ID: %02x %02x %02x\n", id1, id2, id3);
96 }
97 
98 static int s6d27a1_power_on(struct s6d27a1 *ctx)
99 {
100 	struct mipi_dbi *dbi = &ctx->dbi;
101 	int ret;
102 
103 	/* Power up */
104 	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->regulators),
105 				    ctx->regulators);
106 	if (ret) {
107 		dev_err(ctx->dev, "failed to enable regulators: %d\n", ret);
108 		return ret;
109 	}
110 
111 	msleep(20);
112 
113 	/* Assert reset >=1 ms */
114 	gpiod_set_value_cansleep(ctx->reset, 1);
115 	usleep_range(1000, 5000);
116 	/* De-assert reset */
117 	gpiod_set_value_cansleep(ctx->reset, 0);
118 	/* Wait >= 10 ms */
119 	msleep(20);
120 
121 	/*
122 	 * Exit sleep mode and initialize display - some hammering is
123 	 * necessary.
124 	 */
125 	mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
126 	mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
127 	msleep(120);
128 
129 	/* Magic to unlock level 2 control of the display */
130 	mipi_dbi_command(dbi, S6D27A1_PASSWD_L2, 0x5A, 0x5A);
131 
132 	/* Configure resolution to 480RGBx800 */
133 	mipi_dbi_command(dbi, S6D27A1_RESCTL, 0x22);
134 
135 	mipi_dbi_command(dbi, S6D27A1_PANELCTL2, 0x00, 0x02, 0x03, 0x04, 0x05, 0x08, 0x00, 0x0c);
136 
137 	mipi_dbi_command(dbi, S6D27A1_MANPWR, 0x01, 0x00, 0x00, 0x08, 0x08, 0x02, 0x00);
138 
139 	mipi_dbi_command(dbi, S6D27A1_DISPCTL, 0x19, 0x00, 0x08, 0x0D, 0x03, 0x41, 0x3F);
140 
141 	mipi_dbi_command(dbi, S6D27A1_PWRCTL1, 0x00, 0x00, 0x00, 0x00, 0x55,
142 					0x44, 0x05, 0x88, 0x4B, 0x50);
143 
144 	mipi_dbi_command(dbi, S6D27A1_SRCCTL, 0x03, 0x09, 0x8A, 0x00, 0x01, 0x16);
145 
146 	mipi_dbi_command(dbi, S6D27A1_PANELCTL, 0x00, 0x05, 0x06, 0x07, 0x08,
147 					0x01, 0x09, 0x0D, 0x0A, 0x0E,
148 					0x0B, 0x0F, 0x0C, 0x10, 0x01,
149 					0x11, 0x12, 0x13, 0x14, 0x05,
150 					0x06, 0x07, 0x08, 0x01, 0x09,
151 					0x0D, 0x0A, 0x0E, 0x0B, 0x0F,
152 					0x0C, 0x10, 0x01, 0x11, 0x12,
153 					0x13, 0x14);
154 
155 	/* lock the level 2 control */
156 	mipi_dbi_command(dbi, S6D27A1_PASSWD_L2, 0xA5, 0xA5);
157 
158 	s6d27a1_read_mtp_id(ctx);
159 
160 	return 0;
161 }
162 
163 static int s6d27a1_power_off(struct s6d27a1 *ctx)
164 {
165 	/* Go into RESET and disable regulators */
166 	gpiod_set_value_cansleep(ctx->reset, 1);
167 	return regulator_bulk_disable(ARRAY_SIZE(ctx->regulators),
168 				      ctx->regulators);
169 }
170 
171 static int s6d27a1_unprepare(struct drm_panel *panel)
172 {
173 	struct s6d27a1 *ctx = to_s6d27a1(panel);
174 	struct mipi_dbi *dbi = &ctx->dbi;
175 
176 	mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE);
177 	msleep(120);
178 	return s6d27a1_power_off(to_s6d27a1(panel));
179 }
180 
181 static int s6d27a1_disable(struct drm_panel *panel)
182 {
183 	struct s6d27a1 *ctx = to_s6d27a1(panel);
184 	struct mipi_dbi *dbi = &ctx->dbi;
185 
186 	mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
187 	msleep(25);
188 
189 	return 0;
190 }
191 
192 static int s6d27a1_prepare(struct drm_panel *panel)
193 {
194 	return s6d27a1_power_on(to_s6d27a1(panel));
195 }
196 
197 static int s6d27a1_enable(struct drm_panel *panel)
198 {
199 	struct s6d27a1 *ctx = to_s6d27a1(panel);
200 	struct mipi_dbi *dbi = &ctx->dbi;
201 
202 	mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
203 
204 	return 0;
205 }
206 
207 static int s6d27a1_get_modes(struct drm_panel *panel,
208 			    struct drm_connector *connector)
209 {
210 	struct s6d27a1 *ctx = to_s6d27a1(panel);
211 	struct drm_display_mode *mode;
212 	static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
213 
214 	mode = drm_mode_duplicate(connector->dev, &s6d27a1_480_800_mode);
215 	if (!mode) {
216 		dev_err(ctx->dev, "failed to add mode\n");
217 		return -ENOMEM;
218 	}
219 
220 	connector->display_info.bpc = 8;
221 	connector->display_info.width_mm = mode->width_mm;
222 	connector->display_info.height_mm = mode->height_mm;
223 	connector->display_info.bus_flags =
224 		DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
225 	drm_display_info_set_bus_formats(&connector->display_info,
226 					 &bus_format, 1);
227 
228 	drm_mode_set_name(mode);
229 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
230 
231 	drm_mode_probed_add(connector, mode);
232 
233 	return 1;
234 }
235 
236 static const struct drm_panel_funcs s6d27a1_drm_funcs = {
237 	.disable = s6d27a1_disable,
238 	.unprepare = s6d27a1_unprepare,
239 	.prepare = s6d27a1_prepare,
240 	.enable = s6d27a1_enable,
241 	.get_modes = s6d27a1_get_modes,
242 };
243 
244 static int s6d27a1_probe(struct spi_device *spi)
245 {
246 	struct device *dev = &spi->dev;
247 	struct s6d27a1 *ctx;
248 	int ret;
249 
250 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
251 	if (!ctx)
252 		return -ENOMEM;
253 
254 	ctx->dev = dev;
255 
256 	/*
257 	 * VCI   is the analog voltage supply
258 	 * VCCIO is the digital I/O voltage supply
259 	 */
260 	ctx->regulators[0].supply = "vci";
261 	ctx->regulators[1].supply = "vccio";
262 	ret = devm_regulator_bulk_get(dev,
263 				      ARRAY_SIZE(ctx->regulators),
264 				      ctx->regulators);
265 	if (ret)
266 		return dev_err_probe(dev, ret, "failed to get regulators\n");
267 
268 	ctx->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
269 	if (IS_ERR(ctx->reset)) {
270 		ret = PTR_ERR(ctx->reset);
271 		return dev_err_probe(dev, ret, "no RESET GPIO\n");
272 	}
273 
274 	ret = mipi_dbi_spi_init(spi, &ctx->dbi, NULL);
275 	if (ret)
276 		return dev_err_probe(dev, ret, "MIPI DBI init failed\n");
277 
278 	ctx->dbi.read_commands = s6d27a1_dbi_read_commands;
279 
280 	drm_panel_init(&ctx->panel, dev, &s6d27a1_drm_funcs,
281 		       DRM_MODE_CONNECTOR_DPI);
282 
283 	ret = drm_panel_of_backlight(&ctx->panel);
284 	if (ret)
285 		return dev_err_probe(dev, ret, "failed to add backlight\n");
286 
287 	spi_set_drvdata(spi, ctx);
288 
289 	drm_panel_add(&ctx->panel);
290 
291 	return 0;
292 }
293 
294 static void s6d27a1_remove(struct spi_device *spi)
295 {
296 	struct s6d27a1 *ctx = spi_get_drvdata(spi);
297 
298 	drm_panel_remove(&ctx->panel);
299 }
300 
301 static const struct of_device_id s6d27a1_match[] = {
302 	{ .compatible = "samsung,s6d27a1", },
303 	{ /* sentinel */ },
304 };
305 MODULE_DEVICE_TABLE(of, s6d27a1_match);
306 
307 static struct spi_driver s6d27a1_driver = {
308 	.probe		= s6d27a1_probe,
309 	.remove		= s6d27a1_remove,
310 	.driver		= {
311 		.name	= "s6d27a1-panel",
312 		.of_match_table = s6d27a1_match,
313 	},
314 };
315 module_spi_driver(s6d27a1_driver);
316 
317 MODULE_AUTHOR("Markuss Broks <markuss.broks@gmail.com>");
318 MODULE_DESCRIPTION("Samsung S6D27A1 panel driver");
319 MODULE_LICENSE("GPL v2");
320