]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/video/mxc/mxc_lcdif.c
video: mxc: remove pinctrl setup which is already done by device framework
[karo-tx-linux.git] / drivers / video / mxc / mxc_lcdif.c
1 /*
2  * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
3  */
4
5 /*
6  * The code contained herein is licensed under the GNU General Public
7  * License. You may obtain a copy of the GNU General Public License
8  * Version 2 or later at the following locations:
9  *
10  * http://www.opensource.org/licenses/gpl-license.html
11  * http://www.gnu.org/copyleft/gpl.html
12  */
13
14 #include <linux/init.h>
15 #include <linux/ipu.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/mxcfb.h>
19 #include <linux/of_device.h>
20 #include <linux/platform_device.h>
21 #include <video/of_display_timing.h>
22 #include <video/of_videomode.h>
23 #include <video/videomode.h>
24
25 #include "mxc_dispdrv.h"
26
27 struct mxc_lcd_platform_data {
28         u32 default_ifmt;
29         u32 ipu_id;
30         u32 disp_id;
31         enum display_flags disp_flags;
32 };
33
34 struct mxc_lcdif_data {
35         struct device *dev;
36         struct mxc_dispdrv_handle *disp_lcdif;
37 };
38
39 #define DISPDRV_LCD     "lcd"
40
41 static struct fb_videomode lcdif_modedb[] = {
42         {
43                 /* 800x480 @ 57 Hz , pixel clk @ 27MHz */
44                 "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10,
45                 FB_SYNC_CLK_LAT_FALL,
46                 FB_VMODE_NONINTERLACED,
47                 0,
48         },
49         {
50                 /* 800x480 @ 60 Hz , pixel clk @ 32MHz */
51                 "SEIKO-WVGA", 60, 800, 480, 29850, 89, 164, 23, 10, 10, 10,
52                 FB_SYNC_CLK_LAT_FALL,
53                 FB_VMODE_NONINTERLACED,
54                 0,
55         },
56         {
57                 .name = "VGA",
58                 .pixclock = KHZ2PICOS(25200),
59                 .xres = 640,
60                 .yres = 480,
61                 .left_margin = 48,
62                 .hsync_len = 96,
63                 .right_margin = 16,
64                 .upper_margin = 31,
65                 .vsync_len = 2,
66                 .lower_margin = 12,
67         },
68         {
69                 .name = "ETV570",
70                 .pixclock = KHZ2PICOS(25200),
71                 .xres = 640,
72                 .yres = 480,
73                 .left_margin = 114,
74                 .hsync_len = 30,
75                 .right_margin = 16,
76                 .upper_margin = 32,
77                 .vsync_len = 3,
78                 .lower_margin = 10,
79         },
80         {
81                 .name = "ET0350",
82                 .pixclock = KHZ2PICOS(6413760 / 1000),
83                 .xres = 320,
84                 .yres = 240,
85                 .left_margin = 34,
86                 .hsync_len = 34,
87                 .right_margin = 20,
88                 .upper_margin = 15,
89                 .vsync_len = 3,
90                 .lower_margin = 4,
91         },
92         {
93                 .name = "ET0430",
94                 .pixclock = KHZ2PICOS(9009),
95                 .xres = 480,
96                 .yres = 272,
97                 .left_margin = 2,
98                 .hsync_len = 41,
99                 .right_margin = 2,
100                 .upper_margin = 2,
101                 .vsync_len = 10,
102                 .lower_margin = 2,
103                 .sync = FB_SYNC_CLK_LAT_FALL,
104         },
105         {
106                 .name = "ET0500",
107                 .pixclock = KHZ2PICOS(33264),
108                 .xres = 800,
109                 .yres = 480,
110                 .left_margin = 88,
111                 .hsync_len = 128,
112                 .right_margin = 40,
113                 .upper_margin = 33,
114                 .vsync_len = 2,
115                 .lower_margin = 10,
116         },
117         {
118                 .name = "ET0700", /* same as ET0500 */
119                 .pixclock = KHZ2PICOS(33264),
120                 .xres = 800,
121                 .yres = 480,
122                 .left_margin = 88,
123                 .hsync_len = 128,
124                 .right_margin = 40,
125                 .upper_margin = 33,
126                 .vsync_len = 2,
127                 .lower_margin = 10,
128         },
129         {
130                 .name = "ETQ570",
131                 .pixclock = KHZ2PICOS(6596040 / 1000),
132                 .xres = 320,
133                 .yres = 240,
134                 .left_margin = 38,
135                 .hsync_len = 30,
136                 .right_margin = 30,
137                 .upper_margin = 16,
138                 .vsync_len = 3,
139                 .lower_margin = 4,
140         },
141 };
142 static int lcdif_modedb_sz = ARRAY_SIZE(lcdif_modedb);
143
144 static int lcdif_init(struct mxc_dispdrv_handle *disp,
145         struct mxc_dispdrv_setting *setting)
146 {
147         int ret, i;
148         struct mxc_lcdif_data *lcdif = mxc_dispdrv_getdata(disp);
149         struct mxc_lcd_platform_data *plat_data = lcdif->dev->platform_data;
150         struct fb_videomode *modedb = lcdif_modedb;
151         int modedb_sz = lcdif_modedb_sz;
152
153         /* use platform defined ipu/di */
154         setting->dev_id = plat_data->ipu_id;
155         setting->disp_id = plat_data->disp_id;
156
157         if (setting->fbmode) {
158                 modedb[0] = *setting->fbmode;
159                 modedb_sz = 1;
160         } else {
161                 setting->disp_flags = plat_data->disp_flags;
162         }
163
164         ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,
165                                 modedb, modedb_sz, NULL, setting->default_bpp);
166         if (!ret) {
167                 fb_videomode_to_var(&setting->fbi->var, &modedb[0]);
168                 setting->if_fmt = plat_data->default_ifmt;
169         }
170
171         INIT_LIST_HEAD(&setting->fbi->modelist);
172         for (i = 0; i < modedb_sz; i++) {
173                 struct fb_videomode m;
174                 fb_var_to_videomode(&m, &setting->fbi->var);
175                 if (fb_mode_is_equal(&m, &modedb[i])) {
176                         fb_add_videomode(&modedb[i],
177                                         &setting->fbi->modelist);
178                         break;
179                 }
180         }
181
182         return ret;
183 }
184
185 void lcdif_deinit(struct mxc_dispdrv_handle *disp)
186 {
187         /*TODO*/
188 }
189
190 static struct mxc_dispdrv_driver lcdif_drv = {
191         .name   = DISPDRV_LCD,
192         .init   = lcdif_init,
193         .deinit = lcdif_deinit,
194 };
195
196 static int lcd_get_of_property(struct device *dev,
197                                 struct mxc_lcd_platform_data *plat_data)
198 {
199         struct device_node *np = dev->of_node;
200         int err;
201         u32 ipu_id, disp_id;
202         const char *default_ifmt;
203
204         err = of_property_read_string(np, "default_ifmt", &default_ifmt);
205         if (err) {
206                 dev_err(dev, "get of property default_ifmt fail\n");
207                 return err;
208         }
209         err = of_property_read_u32(np, "ipu_id", &ipu_id);
210         if (err) {
211                 dev_err(dev, "get of property ipu_id fail\n");
212                 return err;
213         }
214         err = of_property_read_u32(np, "disp_id", &disp_id);
215         if (err) {
216                 dev_err(dev, "get of property disp_id fail\n");
217                 return err;
218         }
219
220         plat_data->ipu_id = ipu_id;
221         plat_data->disp_id = disp_id;
222         if (!strncmp(default_ifmt, "RGB24", 5))
223                 plat_data->default_ifmt = IPU_PIX_FMT_RGB24;
224         else if (!strncmp(default_ifmt, "BGR24", 5))
225                 plat_data->default_ifmt = IPU_PIX_FMT_BGR24;
226         else if (!strncmp(default_ifmt, "GBR24", 5))
227                 plat_data->default_ifmt = IPU_PIX_FMT_GBR24;
228         else if (!strncmp(default_ifmt, "RGB565", 6))
229                 plat_data->default_ifmt = IPU_PIX_FMT_RGB565;
230         else if (!strncmp(default_ifmt, "RGB666", 6))
231                 plat_data->default_ifmt = IPU_PIX_FMT_RGB666;
232         else if (!strncmp(default_ifmt, "YUV444", 6))
233                 plat_data->default_ifmt = IPU_PIX_FMT_YUV444;
234         else if (!strncmp(default_ifmt, "LVDS666", 7))
235                 plat_data->default_ifmt = IPU_PIX_FMT_LVDS666;
236         else if (!strncmp(default_ifmt, "YUYV16", 6))
237                 plat_data->default_ifmt = IPU_PIX_FMT_YUYV;
238         else if (!strncmp(default_ifmt, "UYVY16", 6))
239                 plat_data->default_ifmt = IPU_PIX_FMT_UYVY;
240         else if (!strncmp(default_ifmt, "YVYU16", 6))
241                 plat_data->default_ifmt = IPU_PIX_FMT_YVYU;
242         else if (!strncmp(default_ifmt, "VYUY16", 6))
243                                 plat_data->default_ifmt = IPU_PIX_FMT_VYUY;
244         else {
245                 dev_err(dev, "err default_ifmt!\n");
246                 return -ENOENT;
247         }
248
249         return err;
250 }
251
252 static int mxc_lcdif_probe(struct platform_device *pdev)
253 {
254         int ret;
255         struct mxc_lcdif_data *lcdif;
256         struct mxc_lcd_platform_data *plat_data;
257
258         dev_dbg(&pdev->dev, "%s enter\n", __func__);
259         lcdif = devm_kzalloc(&pdev->dev, sizeof(struct mxc_lcdif_data),
260                                 GFP_KERNEL);
261         if (!lcdif)
262                 return -ENOMEM;
263         plat_data = devm_kzalloc(&pdev->dev,
264                                 sizeof(struct mxc_lcd_platform_data),
265                                 GFP_KERNEL);
266         if (!plat_data)
267                 return -ENOMEM;
268         pdev->dev.platform_data = plat_data;
269
270         ret = lcd_get_of_property(&pdev->dev, plat_data);
271         if (ret < 0) {
272                 dev_err(&pdev->dev, "get lcd of property fail\n");
273                 return ret;
274         }
275
276         lcdif->dev = &pdev->dev;
277         lcdif->disp_lcdif = mxc_dispdrv_register(&lcdif_drv);
278         mxc_dispdrv_setdata(lcdif->disp_lcdif, lcdif);
279
280         dev_set_drvdata(&pdev->dev, lcdif);
281         dev_dbg(&pdev->dev, "%s exit\n", __func__);
282
283         return ret;
284 }
285
286 static int mxc_lcdif_remove(struct platform_device *pdev)
287 {
288         struct mxc_lcdif_data *lcdif = platform_get_drvdata(pdev);
289
290         mxc_dispdrv_puthandle(lcdif->disp_lcdif);
291         mxc_dispdrv_unregister(lcdif->disp_lcdif);
292         kfree(lcdif);
293         return 0;
294 }
295
296 static const struct of_device_id imx_lcd_dt_ids[] = {
297         { .compatible = "fsl,lcd"},
298         { /* sentinel */ }
299 };
300 static struct platform_driver mxc_lcdif_driver = {
301         .driver = {
302                 .name = "mxc_lcdif",
303                 .of_match_table = imx_lcd_dt_ids,
304         },
305         .probe = mxc_lcdif_probe,
306         .remove = mxc_lcdif_remove,
307 };
308
309 static int __init mxc_lcdif_init(void)
310 {
311         return platform_driver_register(&mxc_lcdif_driver);
312 }
313
314 static void __exit mxc_lcdif_exit(void)
315 {
316         platform_driver_unregister(&mxc_lcdif_driver);
317 }
318
319 module_init(mxc_lcdif_init);
320 module_exit(mxc_lcdif_exit);
321
322 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
323 MODULE_DESCRIPTION("i.MX ipuv3 LCD extern port driver");
324 MODULE_LICENSE("GPL");