2 * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * @brief This file contains the LDB driver device interface and fops
27 #include <linux/types.h>
28 #include <linux/init.h>
29 #include <linux/module.h>
30 #include <linux/platform_device.h>
31 #include <linux/err.h>
32 #include <linux/clk.h>
33 #include <linux/console.h>
35 #include <linux/ipu.h>
36 #include <linux/mxcfb.h>
37 #include <linux/regulator/consumer.h>
38 #include <linux/spinlock.h>
39 #include <linux/of_device.h>
40 #include <linux/mod_devicetable.h>
41 #include "mxc_dispdrv.h"
43 #define DISPDRV_LDB "ldb"
45 #define LDB_BGREF_RMODE_MASK 0x00008000
46 #define LDB_BGREF_RMODE_INT 0x00008000
47 #define LDB_BGREF_RMODE_EXT 0x0
49 #define LDB_DI1_VS_POL_MASK 0x00000400
50 #define LDB_DI1_VS_POL_ACT_LOW 0x00000400
51 #define LDB_DI1_VS_POL_ACT_HIGH 0x0
52 #define LDB_DI0_VS_POL_MASK 0x00000200
53 #define LDB_DI0_VS_POL_ACT_LOW 0x00000200
54 #define LDB_DI0_VS_POL_ACT_HIGH 0x0
56 #define LDB_BIT_MAP_CH1_MASK 0x00000100
57 #define LDB_BIT_MAP_CH1_JEIDA 0x00000100
58 #define LDB_BIT_MAP_CH1_SPWG 0x0
59 #define LDB_BIT_MAP_CH0_MASK 0x00000040
60 #define LDB_BIT_MAP_CH0_JEIDA 0x00000040
61 #define LDB_BIT_MAP_CH0_SPWG 0x0
63 #define LDB_DATA_WIDTH_CH1_MASK 0x00000080
64 #define LDB_DATA_WIDTH_CH1_24 0x00000080
65 #define LDB_DATA_WIDTH_CH1_18 0x0
66 #define LDB_DATA_WIDTH_CH0_MASK 0x00000020
67 #define LDB_DATA_WIDTH_CH0_24 0x00000020
68 #define LDB_DATA_WIDTH_CH0_18 0x0
70 #define LDB_CH1_MODE_MASK 0x0000000C
71 #define LDB_CH1_MODE_EN_TO_DI1 0x0000000C
72 #define LDB_CH1_MODE_EN_TO_DI0 0x00000004
73 #define LDB_CH1_MODE_DISABLE 0x0
74 #define LDB_CH0_MODE_MASK 0x00000003
75 #define LDB_CH0_MODE_EN_TO_DI1 0x00000003
76 #define LDB_CH0_MODE_EN_TO_DI0 0x00000001
77 #define LDB_CH0_MODE_DISABLE 0x0
79 #define LDB_SPLIT_MODE_EN 0x00000010
89 struct fsl_mxc_ldb_platform_data {
104 /*only work for separate mode*/
110 struct platform_device *pdev;
111 struct mxc_dispdrv_handle *disp_ldb;
113 uint32_t *control_reg;
115 uint32_t control_reg_data;
116 struct regulator *lvds_bg_reg;
121 struct clk *ldb_di_clk;
122 struct clk *div_3_5_clk;
123 struct clk *div_7_clk;
124 struct clk *div_sel_clk;
132 struct notifier_block nb;
135 static int g_ldb_mode;
137 static struct fb_videomode ldb_modedb[] = {
139 "LDB-WXGA", 60, 1280, 800, 14065,
144 FB_VMODE_NONINTERLACED,
145 FB_MODE_IS_DETAILED,},
147 "LDB-XGA", 60, 1024, 768, 15385,
152 FB_VMODE_NONINTERLACED,
153 FB_MODE_IS_DETAILED,},
155 "LDB-1080P60", 60, 1920, 1080, 7692,
160 FB_VMODE_NONINTERLACED,
161 FB_MODE_IS_DETAILED,},
163 static int ldb_modedb_sz = ARRAY_SIZE(ldb_modedb);
165 static inline int is_imx6_ldb(struct fsl_mxc_ldb_platform_data *plat_data)
167 return (plat_data->devtype == LDB_IMX6);
170 static int bits_per_pixel(int pixel_fmt)
173 case IPU_PIX_FMT_BGR24:
174 case IPU_PIX_FMT_RGB24:
177 case IPU_PIX_FMT_BGR666:
178 case IPU_PIX_FMT_RGB666:
179 case IPU_PIX_FMT_LVDS666:
188 static int valid_mode(int pixel_fmt)
190 return ((pixel_fmt == IPU_PIX_FMT_RGB24) ||
191 (pixel_fmt == IPU_PIX_FMT_BGR24) ||
192 (pixel_fmt == IPU_PIX_FMT_LVDS666) ||
193 (pixel_fmt == IPU_PIX_FMT_RGB666) ||
194 (pixel_fmt == IPU_PIX_FMT_BGR666));
197 static int parse_ldb_mode(char *mode)
201 if (!strcmp(mode, "spl0"))
202 ldb_mode = LDB_SPL_DI0;
203 else if (!strcmp(mode, "spl1"))
204 ldb_mode = LDB_SPL_DI1;
205 else if (!strcmp(mode, "dul0"))
206 ldb_mode = LDB_DUL_DI0;
207 else if (!strcmp(mode, "dul1"))
208 ldb_mode = LDB_DUL_DI1;
209 else if (!strcmp(mode, "sin0"))
211 else if (!strcmp(mode, "sin1"))
213 else if (!strcmp(mode, "sep0"))
215 else if (!strcmp(mode, "sep1"))
225 * "ldb=spl0/1" -- split mode on DI0/1
226 * "ldb=dul0/1" -- dual mode on DI0/1
227 * "ldb=sin0/1" -- single mode on LVDS0/1
228 * "ldb=sep0/1" -- separate mode begin from LVDS0/1
230 * there are two LVDS channels(LVDS0 and LVDS1) which can transfer video
231 * datas, there two channels can be used as split/dual/single/separate mode.
233 * split mode means display data from DI0 or DI1 will send to both channels
235 * dual mode means display data from DI0 or DI1 will be duplicated on LVDS0
236 * and LVDS1, it said, LVDS0 and LVDS1 has the same content.
237 * single mode means only work for DI0/DI1->LVDS0 or DI0/DI1->LVDS1.
238 * separate mode means you can make DI0/DI1->LVDS0 and DI0/DI1->LVDS1 work
241 static int __init ldb_setup(char *options)
243 g_ldb_mode = parse_ldb_mode(options);
244 return (g_ldb_mode < 0) ? 0 : 1;
246 __setup("ldb=", ldb_setup);
249 static int ldb_get_of_property(struct platform_device *pdev,
250 struct fsl_mxc_ldb_platform_data *plat_data)
252 struct device_node *np = pdev->dev.of_node;
255 u32 sec_ipu_id, sec_disp_id;
259 err = of_property_read_string(np, "mode", (const char **)&mode);
261 dev_dbg(&pdev->dev, "get of property mode fail\n");
264 err = of_property_read_u32(np, "ext_ref", &ext_ref);
266 dev_dbg(&pdev->dev, "get of property ext_ref fail\n");
269 err = of_property_read_u32(np, "ipu_id", &ipu_id);
271 dev_dbg(&pdev->dev, "get of property ipu_id fail\n");
274 err = of_property_read_u32(np, "disp_id", &disp_id);
276 dev_dbg(&pdev->dev, "get of property disp_id fail\n");
279 err = of_property_read_u32(np, "sec_ipu_id", &sec_ipu_id);
281 dev_dbg(&pdev->dev, "get of property sec_ipu_id fail\n");
284 err = of_property_read_u32(np, "sec_disp_id", &sec_disp_id);
286 dev_dbg(&pdev->dev, "get of property sec_disp_id fail\n");
290 plat_data->mode = parse_ldb_mode(mode);
291 plat_data->ext_ref = ext_ref;
292 plat_data->ipu_id = ipu_id;
293 plat_data->disp_id = disp_id;
294 plat_data->sec_ipu_id = sec_ipu_id;
295 plat_data->sec_disp_id = sec_disp_id;
300 static int find_ldb_setting(struct ldb_data *ldb, struct fb_info *fbi)
309 for (i = 0; i < 2; i++) {
310 if (ldb->setting[i].active) {
312 memcpy(id, id_di[ldb->setting[i].di],
313 strlen(id_di[ldb->setting[i].di]));
314 id[4] += ldb->setting[i].ipu;
315 if (!strcmp(id, fbi->fix.id))
322 static int ldb_disp_setup(struct mxc_dispdrv_handle *disp, struct fb_info *fbi)
325 uint32_t pixel_clk, rounded_pixel_clk;
326 struct clk *ldb_clk_parent;
327 struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
331 setting_idx = find_ldb_setting(ldb, fbi);
335 di = ldb->setting[setting_idx].di;
337 /* restore channel mode setting */
338 val = readl(ldb->control_reg);
339 val |= ldb->setting[setting_idx].ch_val;
340 writel(val, ldb->control_reg);
341 dev_dbg(&ldb->pdev->dev, "LDB setup, control reg:0x%x\n",
342 readl(ldb->control_reg));
345 reg = readl(ldb->control_reg);
346 if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) {
348 reg = (reg & ~LDB_DI0_VS_POL_MASK)
349 | LDB_DI0_VS_POL_ACT_HIGH;
351 reg = (reg & ~LDB_DI1_VS_POL_MASK)
352 | LDB_DI1_VS_POL_ACT_HIGH;
355 reg = (reg & ~LDB_DI0_VS_POL_MASK)
356 | LDB_DI0_VS_POL_ACT_LOW;
358 reg = (reg & ~LDB_DI1_VS_POL_MASK)
359 | LDB_DI1_VS_POL_ACT_LOW;
361 writel(reg, ldb->control_reg);
364 if (ldb->setting[setting_idx].clk_en)
365 clk_disable_unprepare(ldb->setting[setting_idx].ldb_di_clk);
366 pixel_clk = (PICOS2KHZ(fbi->var.pixclock)) * 1000UL;
367 ldb_clk_parent = clk_get_parent(ldb->setting[setting_idx].ldb_di_clk);
368 if (IS_ERR(ldb_clk_parent)) {
369 dev_err(&ldb->pdev->dev, "get ldb di parent clk fail\n");
370 return PTR_ERR(ldb_clk_parent);
372 if ((ldb->mode == LDB_SPL_DI0) || (ldb->mode == LDB_SPL_DI1))
373 ret = clk_set_rate(ldb_clk_parent, pixel_clk * 7 / 2);
375 ret = clk_set_rate(ldb_clk_parent, pixel_clk * 7);
377 dev_err(&ldb->pdev->dev, "set ldb parent clk fail:%d\n", ret);
380 rounded_pixel_clk = clk_round_rate(ldb->setting[setting_idx].ldb_di_clk,
382 dev_dbg(&ldb->pdev->dev, "pixel_clk:%d, rounded_pixel_clk:%d\n",
383 pixel_clk, rounded_pixel_clk);
384 ret = clk_set_rate(ldb->setting[setting_idx].ldb_di_clk,
387 dev_err(&ldb->pdev->dev, "set ldb di clk fail:%d\n", ret);
390 ret = clk_prepare_enable(ldb->setting[setting_idx].ldb_di_clk);
392 dev_err(&ldb->pdev->dev, "enable ldb di clk fail:%d\n", ret);
396 if (!ldb->setting[setting_idx].clk_en)
397 ldb->setting[setting_idx].clk_en = true;
402 int ldb_fb_event(struct notifier_block *nb, unsigned long val, void *v)
404 struct ldb_data *ldb = container_of(nb, struct ldb_data, nb);
405 struct fb_event *event = v;
406 struct fb_info *fbi = event->info;
410 index = find_ldb_setting(ldb, fbi);
414 fbi->mode = (struct fb_videomode *)fb_match_mode(&fbi->var,
418 dev_warn(&ldb->pdev->dev,
419 "LDB: can not find mode for xres=%d, yres=%d\n",
420 fbi->var.xres, fbi->var.yres);
421 if (ldb->setting[index].clk_en) {
422 clk_disable(ldb->setting[index].ldb_di_clk);
423 ldb->setting[index].clk_en = false;
424 data = readl(ldb->control_reg);
425 data &= ~ldb->setting[index].ch_mask;
426 writel(data, ldb->control_reg);
434 if (*((int *)event->data) == FB_BLANK_UNBLANK) {
435 if (!ldb->setting[index].clk_en) {
436 clk_enable(ldb->setting[index].ldb_di_clk);
437 ldb->setting[index].clk_en = true;
440 if (ldb->setting[index].clk_en) {
441 clk_disable(ldb->setting[index].ldb_di_clk);
442 ldb->setting[index].clk_en = false;
443 data = readl(ldb->control_reg);
444 data &= ~ldb->setting[index].ch_mask;
445 writel(data, ldb->control_reg);
446 dev_dbg(&ldb->pdev->dev,
447 "LDB blank, control reg:0x%x\n",
448 readl(ldb->control_reg));
453 case FB_EVENT_SUSPEND:
454 if (ldb->setting[index].clk_en) {
455 clk_disable(ldb->setting[index].ldb_di_clk);
456 ldb->setting[index].clk_en = false;
465 #define LVDS_MUX_CTL_WIDTH 2
466 #define LVDS_MUX_CTL_MASK 3
467 #define LVDS0_MUX_CTL_OFFS 6
468 #define LVDS1_MUX_CTL_OFFS 8
469 #define LVDS0_MUX_CTL_MASK (LVDS_MUX_CTL_MASK << 6)
470 #define LVDS1_MUX_CTL_MASK (LVDS_MUX_CTL_MASK << 8)
471 #define ROUTE_IPU_DI(ipu, di) (((ipu << 1) | di) & LVDS_MUX_CTL_MASK)
472 static int ldb_ipu_ldb_route(int ipu, int di, struct ldb_data *ldb)
477 int mode = ldb->mode;
479 reg = readl(ldb->gpr3_reg);
480 if (mode < LDB_SIN0) {
481 reg &= ~(LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK);
482 reg |= (ROUTE_IPU_DI(ipu, di) << LVDS0_MUX_CTL_OFFS) |
483 (ROUTE_IPU_DI(ipu, di) << LVDS1_MUX_CTL_OFFS);
484 dev_dbg(&ldb->pdev->dev,
485 "Dual/Split mode both channels route to IPU%d-DI%d\n",
487 } else if ((mode == LDB_SIN0) || (mode == LDB_SIN1)) {
488 reg &= ~(LVDS0_MUX_CTL_MASK | LVDS1_MUX_CTL_MASK);
489 channel = mode - LDB_SIN0;
490 shift = LVDS0_MUX_CTL_OFFS + channel * LVDS_MUX_CTL_WIDTH;
491 reg |= ROUTE_IPU_DI(ipu, di) << shift;
492 dev_dbg(&ldb->pdev->dev,
493 "Single mode channel %d route to IPU%d-DI%d\n",
496 static bool first = true;
499 if (mode == LDB_SEP0) {
500 reg &= ~LVDS0_MUX_CTL_MASK;
503 reg &= ~LVDS1_MUX_CTL_MASK;
508 if (mode == LDB_SEP0) {
509 reg &= ~LVDS1_MUX_CTL_MASK;
512 reg &= ~LVDS0_MUX_CTL_MASK;
517 shift = LVDS0_MUX_CTL_OFFS + channel * LVDS_MUX_CTL_WIDTH;
518 reg |= ROUTE_IPU_DI(ipu, di) << shift;
520 dev_dbg(&ldb->pdev->dev,
521 "Separate mode channel %d route to IPU%d-DI%d\n",
524 writel(reg, ldb->gpr3_reg);
529 static int ldb_disp_init(struct mxc_dispdrv_handle *disp,
530 struct mxc_dispdrv_setting *setting)
532 int ret = 0, i, lvds_channel = 0;
533 struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
534 struct fsl_mxc_ldb_platform_data *plat_data = ldb->pdev->dev.platform_data;
535 struct resource *res;
536 uint32_t reg, setting_idx;
537 uint32_t ch_mask = 0, ch_val = 0;
538 uint32_t ipu_id, disp_id;
539 char di_clk[] = "ipu1_di0_sel";
540 char ldb_clk[] = "ldb_di0";
541 char div_3_5_clk[] = "di0_div_3_5";
542 char div_7_clk[] = "di0_div_7";
543 char div_sel_clk[] = "di0_div_sel";
545 /* if input format not valid, make RGB666 as default*/
546 if (!valid_mode(setting->if_fmt)) {
547 dev_warn(&ldb->pdev->dev, "Input pixel format not valid"
548 " use default RGB666\n");
549 setting->if_fmt = IPU_PIX_FMT_RGB666;
554 res = platform_get_resource(ldb->pdev, IORESOURCE_MEM, 0);
556 dev_err(&ldb->pdev->dev, "get iomem fail.\n");
560 ldb->reg = devm_ioremap(&ldb->pdev->dev, res->start,
562 ldb->control_reg = ldb->reg + 2;
563 ldb->gpr3_reg = ldb->reg + 3;
565 /* ipu selected by platform data setting */
566 setting->dev_id = plat_data->ipu_id;
568 reg = readl(ldb->control_reg);
570 /* refrence resistor select */
571 reg &= ~LDB_BGREF_RMODE_MASK;
572 if (plat_data->ext_ref)
573 reg |= LDB_BGREF_RMODE_EXT;
575 reg |= LDB_BGREF_RMODE_INT;
577 /* TODO: now only use SPWG data mapping for both channel */
578 reg &= ~(LDB_BIT_MAP_CH0_MASK | LDB_BIT_MAP_CH1_MASK);
579 reg |= LDB_BIT_MAP_CH0_SPWG | LDB_BIT_MAP_CH1_SPWG;
581 /* channel mode setting */
582 reg &= ~(LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK);
583 reg &= ~(LDB_DATA_WIDTH_CH0_MASK | LDB_DATA_WIDTH_CH1_MASK);
585 if (bits_per_pixel(setting->if_fmt) == 24)
586 reg |= LDB_DATA_WIDTH_CH0_24 | LDB_DATA_WIDTH_CH1_24;
588 reg |= LDB_DATA_WIDTH_CH0_18 | LDB_DATA_WIDTH_CH1_18;
590 if (g_ldb_mode >= LDB_SPL_DI0)
591 ldb->mode = g_ldb_mode;
593 ldb->mode = plat_data->mode;
595 if ((ldb->mode == LDB_SIN0) || (ldb->mode == LDB_SIN1)) {
596 ret = ldb->mode - LDB_SIN0;
597 if (plat_data->disp_id != ret) {
598 dev_warn(&ldb->pdev->dev,
599 "change IPU DI%d to IPU DI%d for LDB "
601 plat_data->disp_id, ret, ret);
602 plat_data->disp_id = ret;
604 } else if (((ldb->mode == LDB_SEP0) || (ldb->mode == LDB_SEP1))
605 && is_imx6_ldb(plat_data)) {
606 if (plat_data->disp_id == plat_data->sec_disp_id) {
607 dev_err(&ldb->pdev->dev,
608 "For LVDS separate mode,"
609 "two DIs should be different!\n");
613 if (((!plat_data->disp_id) && (ldb->mode == LDB_SEP1))
614 || ((plat_data->disp_id) &&
615 (ldb->mode == LDB_SEP0))) {
616 dev_dbg(&ldb->pdev->dev,
617 "LVDS separate mode:"
618 "swap DI configuration!\n");
619 ipu_id = plat_data->ipu_id;
620 disp_id = plat_data->disp_id;
621 plat_data->ipu_id = plat_data->sec_ipu_id;
622 plat_data->disp_id = plat_data->sec_disp_id;
623 plat_data->sec_ipu_id = ipu_id;
624 plat_data->sec_disp_id = disp_id;
628 if (ldb->mode == LDB_SPL_DI0) {
629 reg |= LDB_SPLIT_MODE_EN | LDB_CH0_MODE_EN_TO_DI0
630 | LDB_CH1_MODE_EN_TO_DI0;
631 setting->disp_id = 0;
632 } else if (ldb->mode == LDB_SPL_DI1) {
633 reg |= LDB_SPLIT_MODE_EN | LDB_CH0_MODE_EN_TO_DI1
634 | LDB_CH1_MODE_EN_TO_DI1;
635 setting->disp_id = 1;
636 } else if (ldb->mode == LDB_DUL_DI0) {
637 reg &= ~LDB_SPLIT_MODE_EN;
638 reg |= LDB_CH0_MODE_EN_TO_DI0 | LDB_CH1_MODE_EN_TO_DI0;
639 setting->disp_id = 0;
640 } else if (ldb->mode == LDB_DUL_DI1) {
641 reg &= ~LDB_SPLIT_MODE_EN;
642 reg |= LDB_CH0_MODE_EN_TO_DI1 | LDB_CH1_MODE_EN_TO_DI1;
643 setting->disp_id = 1;
644 } else if (ldb->mode == LDB_SIN0) {
645 reg &= ~LDB_SPLIT_MODE_EN;
646 setting->disp_id = plat_data->disp_id;
647 if (setting->disp_id == 0)
648 reg |= LDB_CH0_MODE_EN_TO_DI0;
650 reg |= LDB_CH0_MODE_EN_TO_DI1;
651 ch_mask = LDB_CH0_MODE_MASK;
652 ch_val = reg & LDB_CH0_MODE_MASK;
653 } else if (ldb->mode == LDB_SIN1) {
654 reg &= ~LDB_SPLIT_MODE_EN;
655 setting->disp_id = plat_data->disp_id;
656 if (setting->disp_id == 0)
657 reg |= LDB_CH1_MODE_EN_TO_DI0;
659 reg |= LDB_CH1_MODE_EN_TO_DI1;
660 ch_mask = LDB_CH1_MODE_MASK;
661 ch_val = reg & LDB_CH1_MODE_MASK;
662 } else { /* separate mode*/
663 setting->disp_id = plat_data->disp_id;
665 /* first output is LVDS0 or LVDS1 */
666 if (ldb->mode == LDB_SEP0)
671 reg &= ~LDB_SPLIT_MODE_EN;
673 if ((lvds_channel == 0) && (setting->disp_id == 0))
674 reg |= LDB_CH0_MODE_EN_TO_DI0;
675 else if ((lvds_channel == 0) && (setting->disp_id == 1))
676 reg |= LDB_CH0_MODE_EN_TO_DI1;
677 else if ((lvds_channel == 1) && (setting->disp_id == 0))
678 reg |= LDB_CH1_MODE_EN_TO_DI0;
680 reg |= LDB_CH1_MODE_EN_TO_DI1;
681 ch_mask = lvds_channel ? LDB_CH1_MODE_MASK :
683 ch_val = reg & ch_mask;
685 if (bits_per_pixel(setting->if_fmt) == 24) {
686 if (lvds_channel == 0)
687 reg &= ~LDB_DATA_WIDTH_CH1_24;
689 reg &= ~LDB_DATA_WIDTH_CH0_24;
691 if (lvds_channel == 0)
692 reg &= ~LDB_DATA_WIDTH_CH1_18;
694 reg &= ~LDB_DATA_WIDTH_CH0_18;
698 writel(reg, ldb->control_reg);
699 if (ldb->mode < LDB_SIN0) {
700 ch_mask = LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK;
701 ch_val = reg & (LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK);
703 } else { /* second time for separate mode */
704 if ((ldb->mode == LDB_SPL_DI0) ||
705 (ldb->mode == LDB_SPL_DI1) ||
706 (ldb->mode == LDB_DUL_DI0) ||
707 (ldb->mode == LDB_DUL_DI1) ||
708 (ldb->mode == LDB_SIN0) ||
709 (ldb->mode == LDB_SIN1)) {
710 dev_err(&ldb->pdev->dev, "for second ldb disp"
711 "ldb mode should in separate mode\n");
716 if (is_imx6_ldb(plat_data)) {
717 setting->dev_id = plat_data->sec_ipu_id;
718 setting->disp_id = plat_data->sec_disp_id;
720 setting->dev_id = plat_data->ipu_id;
721 setting->disp_id = !plat_data->disp_id;
723 if (setting->disp_id == ldb->setting[0].di) {
724 dev_err(&ldb->pdev->dev, "Err: for second ldb disp in"
725 "separate mode, DI should be different!\n");
729 /* second output is LVDS0 or LVDS1 */
730 if (ldb->mode == LDB_SEP0)
735 reg = readl(ldb->control_reg);
736 if ((lvds_channel == 0) && (setting->disp_id == 0))
737 reg |= LDB_CH0_MODE_EN_TO_DI0;
738 else if ((lvds_channel == 0) && (setting->disp_id == 1))
739 reg |= LDB_CH0_MODE_EN_TO_DI1;
740 else if ((lvds_channel == 1) && (setting->disp_id == 0))
741 reg |= LDB_CH1_MODE_EN_TO_DI0;
743 reg |= LDB_CH1_MODE_EN_TO_DI1;
744 ch_mask = lvds_channel ? LDB_CH1_MODE_MASK :
746 ch_val = reg & ch_mask;
748 if (bits_per_pixel(setting->if_fmt) == 24) {
749 if (lvds_channel == 0)
750 reg |= LDB_DATA_WIDTH_CH0_24;
752 reg |= LDB_DATA_WIDTH_CH1_24;
754 if (lvds_channel == 0)
755 reg |= LDB_DATA_WIDTH_CH0_18;
757 reg |= LDB_DATA_WIDTH_CH1_18;
759 writel(reg, ldb->control_reg);
763 if (is_imx6_ldb(plat_data) &&
764 ((ldb->mode == LDB_SEP0) || (ldb->mode == LDB_SEP1))) {
765 ldb_clk[6] += lvds_channel;
766 div_3_5_clk[2] += lvds_channel;
767 div_7_clk[2] += lvds_channel;
768 div_sel_clk[2] += lvds_channel;
770 ldb_clk[6] += setting->disp_id;
771 div_3_5_clk[2] += setting->disp_id;
772 div_7_clk[2] += setting->disp_id;
773 div_sel_clk[2] += setting->disp_id;
775 ldb->setting[setting_idx].ldb_di_clk = clk_get(&ldb->pdev->dev,
777 if (IS_ERR(ldb->setting[setting_idx].ldb_di_clk)) {
778 dev_err(&ldb->pdev->dev, "get ldb clk failed\n");
779 return PTR_ERR(ldb->setting[setting_idx].ldb_di_clk);
782 ldb->setting[setting_idx].div_3_5_clk = clk_get(&ldb->pdev->dev,
784 if (IS_ERR(ldb->setting[setting_idx].div_3_5_clk)) {
785 dev_err(&ldb->pdev->dev, "get div 3.5 clk failed\n");
786 return PTR_ERR(ldb->setting[setting_idx].div_3_5_clk);
788 ldb->setting[setting_idx].div_7_clk = clk_get(&ldb->pdev->dev,
790 if (IS_ERR(ldb->setting[setting_idx].div_7_clk)) {
791 dev_err(&ldb->pdev->dev, "get div 7 clk failed\n");
792 return PTR_ERR(ldb->setting[setting_idx].div_7_clk);
795 ldb->setting[setting_idx].div_sel_clk = clk_get(&ldb->pdev->dev,
797 if (IS_ERR(ldb->setting[setting_idx].div_sel_clk)) {
798 dev_err(&ldb->pdev->dev, "get div sel clk failed\n");
799 return PTR_ERR(ldb->setting[setting_idx].div_sel_clk);
802 di_clk[3] += setting->dev_id;
803 di_clk[7] += setting->disp_id;
804 ldb->setting[setting_idx].di_clk = clk_get(&ldb->pdev->dev,
806 if (IS_ERR(ldb->setting[setting_idx].di_clk)) {
807 dev_err(&ldb->pdev->dev, "get di clk failed\n");
808 return PTR_ERR(ldb->setting[setting_idx].di_clk);
811 ldb->setting[setting_idx].ch_mask = ch_mask;
812 ldb->setting[setting_idx].ch_val = ch_val;
814 if (is_imx6_ldb(plat_data))
815 ldb_ipu_ldb_route(setting->dev_id, setting->disp_id, ldb);
817 /* must use spec video mode defined by driver */
818 ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,
819 ldb_modedb, ldb_modedb_sz, NULL, setting->default_bpp);
821 fb_videomode_to_var(&setting->fbi->var, &ldb_modedb[0]);
823 INIT_LIST_HEAD(&setting->fbi->modelist);
824 for (i = 0; i < ldb_modedb_sz; i++) {
825 struct fb_videomode m;
826 fb_var_to_videomode(&m, &setting->fbi->var);
827 if (fb_mode_is_equal(&m, &ldb_modedb[i])) {
828 fb_add_videomode(&ldb_modedb[i],
829 &setting->fbi->modelist);
834 ldb->setting[setting_idx].ipu = setting->dev_id;
835 ldb->setting[setting_idx].di = setting->disp_id;
840 static int ldb_post_disp_init(struct mxc_dispdrv_handle *disp,
841 int ipu_id, int disp_id)
843 struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
844 int setting_idx = ldb->inited ? 1 : 0;
848 ldb->nb.notifier_call = ldb_fb_event;
849 fb_register_client(&ldb->nb);
852 ret = clk_set_parent(ldb->setting[setting_idx].di_clk,
853 ldb->setting[setting_idx].ldb_di_clk);
855 dev_err(&ldb->pdev->dev, "fail to set ldb_di clk as"
856 "the parent of ipu_di clk\n");
860 if ((ldb->mode == LDB_SPL_DI0) || (ldb->mode == LDB_SPL_DI1)) {
861 ret = clk_set_parent(ldb->setting[setting_idx].div_sel_clk,
862 ldb->setting[setting_idx].div_3_5_clk);
864 dev_err(&ldb->pdev->dev, "fail to set div 3.5 clk as"
865 "the parent of div sel clk\n");
869 ret = clk_set_parent(ldb->setting[setting_idx].div_sel_clk,
870 ldb->setting[setting_idx].div_7_clk);
872 dev_err(&ldb->pdev->dev, "fail to set div 7 clk as"
873 "the parent of div sel clk\n");
878 /* save active ldb setting for fb notifier */
879 ldb->setting[setting_idx].active = true;
885 static void ldb_disp_deinit(struct mxc_dispdrv_handle *disp)
887 struct ldb_data *ldb = mxc_dispdrv_getdata(disp);
890 writel(0, ldb->control_reg);
892 for (i = 0; i < 2; i++) {
893 clk_disable(ldb->setting[i].ldb_di_clk);
894 clk_put(ldb->setting[i].ldb_di_clk);
895 clk_put(ldb->setting[i].div_3_5_clk);
896 clk_put(ldb->setting[i].div_7_clk);
897 clk_put(ldb->setting[i].div_sel_clk);
900 fb_unregister_client(&ldb->nb);
903 static struct mxc_dispdrv_driver ldb_drv = {
905 .init = ldb_disp_init,
906 .post_init = ldb_post_disp_init,
907 .deinit = ldb_disp_deinit,
908 .setup = ldb_disp_setup,
911 static int ldb_suspend(struct platform_device *pdev, pm_message_t state)
913 struct ldb_data *ldb = dev_get_drvdata(&pdev->dev);
918 data = readl(ldb->control_reg);
919 ldb->control_reg_data = data;
920 data &= ~(LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK);
921 writel(data, ldb->control_reg);
926 static int ldb_resume(struct platform_device *pdev)
928 struct ldb_data *ldb = dev_get_drvdata(&pdev->dev);
932 writel(ldb->control_reg_data, ldb->control_reg);
937 static struct platform_device_id imx_ldb_devtype[] = {
940 .driver_data = LDB_IMX6,
946 static const struct of_device_id imx_ldb_dt_ids[] = {
947 { .compatible = "fsl,imx6q-ldb", .data = &imx_ldb_devtype[IMX6_LDB],},
952 * This function is called by the driver framework to initialize the LDB
955 * @param dev The device structure for the LDB passed in by the
958 * @return Returns 0 on success or negative error code on error
960 static int ldb_probe(struct platform_device *pdev)
963 struct ldb_data *ldb;
964 struct fsl_mxc_ldb_platform_data *plat_data;
965 const struct of_device_id *of_id =
966 of_match_device(imx_ldb_dt_ids, &pdev->dev);
968 dev_dbg(&pdev->dev, "%s enter\n", __func__);
969 ldb = devm_kzalloc(&pdev->dev, sizeof(struct ldb_data), GFP_KERNEL);
973 plat_data = devm_kzalloc(&pdev->dev,
974 sizeof(struct fsl_mxc_ldb_platform_data),
978 pdev->dev.platform_data = plat_data;
980 pdev->id_entry = of_id->data;
981 plat_data->devtype = pdev->id_entry->driver_data;
983 ret = ldb_get_of_property(pdev, plat_data);
985 dev_err(&pdev->dev, "get ldb of property fail\n");
990 ldb->disp_ldb = mxc_dispdrv_register(&ldb_drv);
991 mxc_dispdrv_setdata(ldb->disp_ldb, ldb);
993 dev_set_drvdata(&pdev->dev, ldb);
995 dev_dbg(&pdev->dev, "%s exit\n", __func__);
999 static int ldb_remove(struct platform_device *pdev)
1001 struct ldb_data *ldb = dev_get_drvdata(&pdev->dev);
1005 mxc_dispdrv_puthandle(ldb->disp_ldb);
1006 mxc_dispdrv_unregister(ldb->disp_ldb);
1010 static struct platform_driver mxcldb_driver = {
1013 .of_match_table = imx_ldb_dt_ids,
1016 .remove = ldb_remove,
1017 .suspend = ldb_suspend,
1018 .resume = ldb_resume,
1021 static int __init ldb_init(void)
1023 return platform_driver_register(&mxcldb_driver);
1026 static void __exit ldb_uninit(void)
1028 platform_driver_unregister(&mxcldb_driver);
1031 module_init(ldb_init);
1032 module_exit(ldb_uninit);
1034 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
1035 MODULE_DESCRIPTION("MXC LDB driver");
1036 MODULE_LICENSE("GPL");