• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* linux/drivers/video/exynos/exynos_mipi_dsi.c
2  *
3  * Samsung SoC MIPI-DSIM driver.
4  *
5  * Copyright (c) 2012 Samsung Electronics Co., Ltd
6  *
7  * InKi Dae, <inki.dae@samsung.com>
8  * Donghwa Lee, <dh09.lee@samsung.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13 */
14 
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/errno.h>
18 #include <linux/clk.h>
19 #include <linux/mutex.h>
20 #include <linux/wait.h>
21 #include <linux/fs.h>
22 #include <linux/mm.h>
23 #include <linux/fb.h>
24 #include <linux/ctype.h>
25 #include <linux/platform_device.h>
26 #include <linux/io.h>
27 #include <linux/irq.h>
28 #include <linux/memory.h>
29 #include <linux/delay.h>
30 #include <linux/interrupt.h>
31 #include <linux/kthread.h>
32 #include <linux/notifier.h>
33 #include <linux/phy/phy.h>
34 #include <linux/regulator/consumer.h>
35 #include <linux/pm_runtime.h>
36 #include <linux/err.h>
37 
38 #include <video/exynos_mipi_dsim.h>
39 
40 #include "exynos_mipi_dsi_common.h"
41 #include "exynos_mipi_dsi_lowlevel.h"
42 
43 struct mipi_dsim_ddi {
44 	int				bus_id;
45 	struct list_head		list;
46 	struct mipi_dsim_lcd_device	*dsim_lcd_dev;
47 	struct mipi_dsim_lcd_driver	*dsim_lcd_drv;
48 };
49 
50 static LIST_HEAD(dsim_ddi_list);
51 
52 static DEFINE_MUTEX(mipi_dsim_lock);
53 
to_dsim_plat(struct platform_device * pdev)54 static struct mipi_dsim_platform_data *to_dsim_plat(struct platform_device
55 							*pdev)
56 {
57 	return pdev->dev.platform_data;
58 }
59 
60 static struct regulator_bulk_data supplies[] = {
61 	{ .supply = "vdd11", },
62 	{ .supply = "vdd18", },
63 };
64 
exynos_mipi_regulator_enable(struct mipi_dsim_device * dsim)65 static int exynos_mipi_regulator_enable(struct mipi_dsim_device *dsim)
66 {
67 	int ret;
68 
69 	mutex_lock(&dsim->lock);
70 	ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
71 	mutex_unlock(&dsim->lock);
72 
73 	return ret;
74 }
75 
exynos_mipi_regulator_disable(struct mipi_dsim_device * dsim)76 static int exynos_mipi_regulator_disable(struct mipi_dsim_device *dsim)
77 {
78 	int ret;
79 
80 	mutex_lock(&dsim->lock);
81 	ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
82 	mutex_unlock(&dsim->lock);
83 
84 	return ret;
85 }
86 
87 /* update all register settings to MIPI DSI controller. */
exynos_mipi_update_cfg(struct mipi_dsim_device * dsim)88 static void exynos_mipi_update_cfg(struct mipi_dsim_device *dsim)
89 {
90 	/*
91 	 * data from Display controller(FIMD) is not transferred in video mode
92 	 * but in case of command mode, all settings is not updated to
93 	 * registers.
94 	 */
95 	exynos_mipi_dsi_stand_by(dsim, 0);
96 
97 	exynos_mipi_dsi_init_dsim(dsim);
98 	exynos_mipi_dsi_init_link(dsim);
99 
100 	exynos_mipi_dsi_set_hs_enable(dsim);
101 
102 	/* set display timing. */
103 	exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
104 
105 	exynos_mipi_dsi_init_interrupt(dsim);
106 
107 	/*
108 	 * data from Display controller(FIMD) is transferred in video mode
109 	 * but in case of command mode, all settings are updated to registers.
110 	 */
111 	exynos_mipi_dsi_stand_by(dsim, 1);
112 }
113 
exynos_mipi_dsi_early_blank_mode(struct mipi_dsim_device * dsim,int power)114 static int exynos_mipi_dsi_early_blank_mode(struct mipi_dsim_device *dsim,
115 		int power)
116 {
117 	struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
118 	struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
119 
120 	switch (power) {
121 	case FB_BLANK_POWERDOWN:
122 		if (dsim->suspended)
123 			return 0;
124 
125 		if (client_drv && client_drv->suspend)
126 			client_drv->suspend(client_dev);
127 
128 		clk_disable(dsim->clock);
129 
130 		exynos_mipi_regulator_disable(dsim);
131 
132 		dsim->suspended = true;
133 
134 		break;
135 	default:
136 		break;
137 	}
138 
139 	return 0;
140 }
141 
exynos_mipi_dsi_blank_mode(struct mipi_dsim_device * dsim,int power)142 static int exynos_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power)
143 {
144 	struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
145 	struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
146 
147 	switch (power) {
148 	case FB_BLANK_UNBLANK:
149 		if (!dsim->suspended)
150 			return 0;
151 
152 		/* lcd panel power on. */
153 		if (client_drv && client_drv->power_on)
154 			client_drv->power_on(client_dev, 1);
155 
156 		exynos_mipi_regulator_enable(dsim);
157 
158 		/* enable MIPI-DSI PHY. */
159 		phy_power_on(dsim->phy);
160 
161 		clk_enable(dsim->clock);
162 
163 		exynos_mipi_update_cfg(dsim);
164 
165 		/* set lcd panel sequence commands. */
166 		if (client_drv && client_drv->set_sequence)
167 			client_drv->set_sequence(client_dev);
168 
169 		dsim->suspended = false;
170 
171 		break;
172 	case FB_BLANK_NORMAL:
173 		/* TODO. */
174 		break;
175 	default:
176 		break;
177 	}
178 
179 	return 0;
180 }
181 
exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device * lcd_dev)182 int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
183 {
184 	struct mipi_dsim_ddi *dsim_ddi;
185 
186 	if (!lcd_dev->name) {
187 		pr_err("dsim_lcd_device name is NULL.\n");
188 		return -EFAULT;
189 	}
190 
191 	dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
192 	if (!dsim_ddi) {
193 		pr_err("failed to allocate dsim_ddi object.\n");
194 		return -ENOMEM;
195 	}
196 
197 	dsim_ddi->dsim_lcd_dev = lcd_dev;
198 
199 	mutex_lock(&mipi_dsim_lock);
200 	list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
201 	mutex_unlock(&mipi_dsim_lock);
202 
203 	return 0;
204 }
205 
exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver * lcd_drv)206 static struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device(
207 					struct mipi_dsim_lcd_driver *lcd_drv)
208 {
209 	struct mipi_dsim_ddi *dsim_ddi, *next;
210 	struct mipi_dsim_lcd_device *lcd_dev;
211 
212 	mutex_lock(&mipi_dsim_lock);
213 
214 	list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
215 		if (!dsim_ddi)
216 			goto out;
217 
218 		lcd_dev = dsim_ddi->dsim_lcd_dev;
219 		if (!lcd_dev)
220 			continue;
221 
222 		if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) {
223 			/**
224 			 * bus_id would be used to identify
225 			 * connected bus.
226 			 */
227 			dsim_ddi->bus_id = lcd_dev->bus_id;
228 			mutex_unlock(&mipi_dsim_lock);
229 
230 			return dsim_ddi;
231 		}
232 
233 		list_del(&dsim_ddi->list);
234 		kfree(dsim_ddi);
235 	}
236 
237 out:
238 	mutex_unlock(&mipi_dsim_lock);
239 
240 	return NULL;
241 }
242 
exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver * lcd_drv)243 int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
244 {
245 	struct mipi_dsim_ddi *dsim_ddi;
246 
247 	if (!lcd_drv->name) {
248 		pr_err("dsim_lcd_driver name is NULL.\n");
249 		return -EFAULT;
250 	}
251 
252 	dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
253 	if (!dsim_ddi) {
254 		pr_err("mipi_dsim_ddi object not found.\n");
255 		return -EFAULT;
256 	}
257 
258 	dsim_ddi->dsim_lcd_drv = lcd_drv;
259 
260 	pr_info("registered panel driver(%s) to mipi-dsi driver.\n",
261 		lcd_drv->name);
262 
263 	return 0;
264 
265 }
266 
exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device * dsim,const char * name)267 static struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(
268 						struct mipi_dsim_device *dsim,
269 						const char *name)
270 {
271 	struct mipi_dsim_ddi *dsim_ddi, *next;
272 	struct mipi_dsim_lcd_driver *lcd_drv;
273 	struct mipi_dsim_lcd_device *lcd_dev;
274 	int ret;
275 
276 	mutex_lock(&dsim->lock);
277 
278 	list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
279 		lcd_drv = dsim_ddi->dsim_lcd_drv;
280 		lcd_dev = dsim_ddi->dsim_lcd_dev;
281 		if (!lcd_drv || !lcd_dev ||
282 			(dsim->id != dsim_ddi->bus_id))
283 				continue;
284 
285 		dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n",
286 				lcd_drv->id, lcd_dev->id);
287 		dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n",
288 				lcd_dev->bus_id, dsim->id);
289 
290 		if ((strcmp(lcd_drv->name, name) == 0)) {
291 			lcd_dev->master = dsim;
292 
293 			lcd_dev->dev.parent = dsim->dev;
294 			dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name);
295 
296 			ret = device_register(&lcd_dev->dev);
297 			if (ret < 0) {
298 				dev_err(dsim->dev,
299 					"can't register %s, status %d\n",
300 					dev_name(&lcd_dev->dev), ret);
301 				mutex_unlock(&dsim->lock);
302 
303 				return NULL;
304 			}
305 
306 			dsim->dsim_lcd_dev = lcd_dev;
307 			dsim->dsim_lcd_drv = lcd_drv;
308 
309 			mutex_unlock(&dsim->lock);
310 
311 			return dsim_ddi;
312 		}
313 	}
314 
315 	mutex_unlock(&dsim->lock);
316 
317 	return NULL;
318 }
319 
320 /* define MIPI-DSI Master operations. */
321 static struct mipi_dsim_master_ops master_ops = {
322 	.cmd_read			= exynos_mipi_dsi_rd_data,
323 	.cmd_write			= exynos_mipi_dsi_wr_data,
324 	.get_dsim_frame_done		= exynos_mipi_dsi_get_frame_done_status,
325 	.clear_dsim_frame_done		= exynos_mipi_dsi_clear_frame_done,
326 	.set_early_blank_mode		= exynos_mipi_dsi_early_blank_mode,
327 	.set_blank_mode			= exynos_mipi_dsi_blank_mode,
328 };
329 
exynos_mipi_dsi_probe(struct platform_device * pdev)330 static int exynos_mipi_dsi_probe(struct platform_device *pdev)
331 {
332 	struct resource *res;
333 	struct mipi_dsim_device *dsim;
334 	struct mipi_dsim_config *dsim_config;
335 	struct mipi_dsim_platform_data *dsim_pd;
336 	struct mipi_dsim_ddi *dsim_ddi;
337 	int ret = -EINVAL;
338 
339 	dsim = devm_kzalloc(&pdev->dev, sizeof(struct mipi_dsim_device),
340 				GFP_KERNEL);
341 	if (!dsim) {
342 		dev_err(&pdev->dev, "failed to allocate dsim object.\n");
343 		return -ENOMEM;
344 	}
345 
346 	dsim->pd = to_dsim_plat(pdev);
347 	dsim->dev = &pdev->dev;
348 	dsim->id = pdev->id;
349 
350 	/* get mipi_dsim_platform_data. */
351 	dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
352 	if (dsim_pd == NULL) {
353 		dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
354 		return -EINVAL;
355 	}
356 	/* get mipi_dsim_config. */
357 	dsim_config = dsim_pd->dsim_config;
358 	if (dsim_config == NULL) {
359 		dev_err(&pdev->dev, "failed to get dsim config data.\n");
360 		return -EINVAL;
361 	}
362 
363 	dsim->dsim_config = dsim_config;
364 	dsim->master_ops = &master_ops;
365 
366 	mutex_init(&dsim->lock);
367 
368 	ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies),
369 					supplies);
370 	if (ret) {
371 		dev_err(&pdev->dev, "Failed to get regulators: %d\n", ret);
372 		return ret;
373 	}
374 
375 	dsim->phy = devm_phy_get(&pdev->dev, "dsim");
376 	if (IS_ERR(dsim->phy))
377 		return PTR_ERR(dsim->phy);
378 
379 	dsim->clock = devm_clk_get(&pdev->dev, "dsim0");
380 	if (IS_ERR(dsim->clock)) {
381 		dev_err(&pdev->dev, "failed to get dsim clock source\n");
382 		return -ENODEV;
383 	}
384 
385 	clk_enable(dsim->clock);
386 
387 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
388 
389 	dsim->reg_base = devm_ioremap_resource(&pdev->dev, res);
390 	if (IS_ERR(dsim->reg_base)) {
391 		ret = PTR_ERR(dsim->reg_base);
392 		goto error;
393 	}
394 
395 	mutex_init(&dsim->lock);
396 
397 	/* bind lcd ddi matched with panel name. */
398 	dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
399 	if (!dsim_ddi) {
400 		dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
401 		ret = -EINVAL;
402 		goto error;
403 	}
404 
405 	dsim->irq = platform_get_irq(pdev, 0);
406 	if (IS_ERR_VALUE(dsim->irq)) {
407 		dev_err(&pdev->dev, "failed to request dsim irq resource\n");
408 		ret = -EINVAL;
409 		goto error;
410 	}
411 
412 	init_completion(&dsim_wr_comp);
413 	init_completion(&dsim_rd_comp);
414 	platform_set_drvdata(pdev, dsim);
415 
416 	ret = devm_request_irq(&pdev->dev, dsim->irq,
417 			exynos_mipi_dsi_interrupt_handler,
418 			IRQF_SHARED, dev_name(&pdev->dev), dsim);
419 	if (ret != 0) {
420 		dev_err(&pdev->dev, "failed to request dsim irq\n");
421 		ret = -EINVAL;
422 		goto error;
423 	}
424 
425 	/* enable interrupts */
426 	exynos_mipi_dsi_init_interrupt(dsim);
427 
428 	/* initialize mipi-dsi client(lcd panel). */
429 	if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe)
430 		dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev);
431 
432 	/* in case mipi-dsi has been enabled by bootloader */
433 	if (dsim_pd->enabled) {
434 		exynos_mipi_regulator_enable(dsim);
435 		goto done;
436 	}
437 
438 	/* lcd panel power on. */
439 	if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->power_on)
440 		dsim_ddi->dsim_lcd_drv->power_on(dsim_ddi->dsim_lcd_dev, 1);
441 
442 	exynos_mipi_regulator_enable(dsim);
443 
444 	/* enable MIPI-DSI PHY. */
445 	phy_power_on(dsim->phy);
446 
447 	exynos_mipi_update_cfg(dsim);
448 
449 	/* set lcd panel sequence commands. */
450 	if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->set_sequence)
451 		dsim_ddi->dsim_lcd_drv->set_sequence(dsim_ddi->dsim_lcd_dev);
452 
453 	dsim->suspended = false;
454 
455 done:
456 	platform_set_drvdata(pdev, dsim);
457 
458 	dev_dbg(&pdev->dev, "%s() completed successfully (%s mode)\n", __func__,
459 		dsim_config->e_interface == DSIM_COMMAND ? "CPU" : "RGB");
460 
461 	return 0;
462 
463 error:
464 	clk_disable(dsim->clock);
465 	return ret;
466 }
467 
exynos_mipi_dsi_remove(struct platform_device * pdev)468 static int exynos_mipi_dsi_remove(struct platform_device *pdev)
469 {
470 	struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
471 	struct mipi_dsim_ddi *dsim_ddi, *next;
472 	struct mipi_dsim_lcd_driver *dsim_lcd_drv;
473 
474 	clk_disable(dsim->clock);
475 
476 	list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
477 		if (dsim_ddi) {
478 			if (dsim->id != dsim_ddi->bus_id)
479 				continue;
480 
481 			dsim_lcd_drv = dsim_ddi->dsim_lcd_drv;
482 
483 			if (dsim_lcd_drv->remove)
484 				dsim_lcd_drv->remove(dsim_ddi->dsim_lcd_dev);
485 
486 			kfree(dsim_ddi);
487 		}
488 	}
489 
490 	return 0;
491 }
492 
493 #ifdef CONFIG_PM_SLEEP
exynos_mipi_dsi_suspend(struct device * dev)494 static int exynos_mipi_dsi_suspend(struct device *dev)
495 {
496 	struct platform_device *pdev = to_platform_device(dev);
497 	struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
498 	struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
499 	struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
500 
501 	disable_irq(dsim->irq);
502 
503 	if (dsim->suspended)
504 		return 0;
505 
506 	if (client_drv && client_drv->suspend)
507 		client_drv->suspend(client_dev);
508 
509 	/* disable MIPI-DSI PHY. */
510 	phy_power_off(dsim->phy);
511 
512 	clk_disable(dsim->clock);
513 
514 	exynos_mipi_regulator_disable(dsim);
515 
516 	dsim->suspended = true;
517 
518 	return 0;
519 }
520 
exynos_mipi_dsi_resume(struct device * dev)521 static int exynos_mipi_dsi_resume(struct device *dev)
522 {
523 	struct platform_device *pdev = to_platform_device(dev);
524 	struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
525 	struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
526 	struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
527 
528 	enable_irq(dsim->irq);
529 
530 	if (!dsim->suspended)
531 		return 0;
532 
533 	/* lcd panel power on. */
534 	if (client_drv && client_drv->power_on)
535 		client_drv->power_on(client_dev, 1);
536 
537 	exynos_mipi_regulator_enable(dsim);
538 
539 	/* enable MIPI-DSI PHY. */
540 	phy_power_on(dsim->phy);
541 
542 	clk_enable(dsim->clock);
543 
544 	exynos_mipi_update_cfg(dsim);
545 
546 	/* set lcd panel sequence commands. */
547 	if (client_drv && client_drv->set_sequence)
548 		client_drv->set_sequence(client_dev);
549 
550 	dsim->suspended = false;
551 
552 	return 0;
553 }
554 #endif
555 
556 static const struct dev_pm_ops exynos_mipi_dsi_pm_ops = {
557 	SET_SYSTEM_SLEEP_PM_OPS(exynos_mipi_dsi_suspend, exynos_mipi_dsi_resume)
558 };
559 
560 static struct platform_driver exynos_mipi_dsi_driver = {
561 	.probe = exynos_mipi_dsi_probe,
562 	.remove = exynos_mipi_dsi_remove,
563 	.driver = {
564 		   .name = "exynos-mipi-dsim",
565 		   .pm = &exynos_mipi_dsi_pm_ops,
566 	},
567 };
568 
569 module_platform_driver(exynos_mipi_dsi_driver);
570 
571 MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
572 MODULE_DESCRIPTION("Samsung SoC MIPI-DSI driver");
573 MODULE_LICENSE("GPL");
574