Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
[pandora-kernel.git] / drivers / staging / msm / ebi2_lcd.c
1 /* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 and
5  * only version 2 as published by the Free Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17
18 #include <linux/module.h>
19 #include <linux/moduleparam.h>
20 #include <linux/kernel.h>
21 #include <linux/slab.h>
22 #include <linux/delay.h>
23 #include <linux/mm.h>
24 #include <linux/fb.h>
25 #include <linux/init.h>
26 #include <linux/ioport.h>
27 #include <linux/device.h>
28 #include <linux/dma-mapping.h>
29 #include <linux/uaccess.h>
30 #include <linux/workqueue.h>
31 #include <linux/string.h>
32 #include <linux/version.h>
33 #include <linux/proc_fs.h>
34 #include <linux/vmalloc.h>
35 #include <linux/debugfs.h>
36
37 #include "msm_fb.h"
38
39 static int ebi2_lcd_probe(struct platform_device *pdev);
40 static int ebi2_lcd_remove(struct platform_device *pdev);
41
42 static struct platform_driver ebi2_lcd_driver = {
43         .probe = ebi2_lcd_probe,
44         .remove = ebi2_lcd_remove,
45         .suspend = NULL,
46         .suspend_late = NULL,
47         .resume_early = NULL,
48         .resume = NULL,
49         .shutdown = NULL,
50         .driver = {
51                    .name = "ebi2_lcd",
52                    },
53 };
54
55 static void *ebi2_base;
56 static void *ebi2_lcd_cfg0;
57 static void *ebi2_lcd_cfg1;
58 static void __iomem *lcd01_base;
59 static void __iomem *lcd02_base;
60 static int ebi2_lcd_resource_initialized;
61
62 static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
63 static int pdev_list_cnt;
64
65 static int ebi2_lcd_probe(struct platform_device *pdev)
66 {
67         struct msm_fb_data_type *mfd;
68         struct platform_device *mdp_dev = NULL;
69         struct msm_fb_panel_data *pdata = NULL;
70         int rc, i;
71
72         if (pdev->id == 0) {
73                 for (i = 0; i < pdev->num_resources; i++) {
74                         if (!strncmp(pdev->resource[i].name, "base", 4)) {
75                                 ebi2_base = ioremap(pdev->resource[i].start,
76                                                 pdev->resource[i].end -
77                                                 pdev->resource[i].start + 1);
78                                 if (!ebi2_base) {
79                                         printk(KERN_ERR
80                                                 "ebi2_base ioremap failed!\n");
81                                         return -ENOMEM;
82                                 }
83                                 ebi2_lcd_cfg0 = (void *)(ebi2_base + 0x20);
84                                 ebi2_lcd_cfg1 = (void *)(ebi2_base + 0x24);
85                         } else if (!strncmp(pdev->resource[i].name,
86                                                 "lcd01", 5)) {
87                                 lcd01_base = ioremap(pdev->resource[i].start,
88                                                 pdev->resource[i].end -
89                                                 pdev->resource[i].start + 1);
90                                 if (!lcd01_base) {
91                                         printk(KERN_ERR
92                                                 "lcd01_base ioremap failed!\n");
93                                         return -ENOMEM;
94                                 }
95                         } else if (!strncmp(pdev->resource[i].name,
96                                                 "lcd02", 5)) {
97                                 lcd02_base = ioremap(pdev->resource[i].start,
98                                                 pdev->resource[i].end -
99                                                 pdev->resource[i].start + 1);
100                                 if (!lcd02_base) {
101                                         printk(KERN_ERR
102                                                 "lcd02_base ioremap failed!\n");
103                                         return -ENOMEM;
104                                 }
105                         }
106                 }
107                 ebi2_lcd_resource_initialized = 1;
108                 return 0;
109         }
110
111         if (!ebi2_lcd_resource_initialized)
112                 return -EPERM;
113
114         mfd = platform_get_drvdata(pdev);
115
116         if (!mfd)
117                 return -ENODEV;
118
119         if (mfd->key != MFD_KEY)
120                 return -EINVAL;
121
122         if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
123                 return -ENOMEM;
124
125         if (ebi2_base == NULL)
126                 return -ENOMEM;
127
128         mdp_dev = platform_device_alloc("mdp", pdev->id);
129         if (!mdp_dev)
130                 return -ENOMEM;
131
132         /* link to the latest pdev */
133         mfd->pdev = mdp_dev;
134         mfd->dest = DISPLAY_LCD;
135
136         /* add panel data */
137         if (platform_device_add_data
138             (mdp_dev, pdev->dev.platform_data,
139              sizeof(struct msm_fb_panel_data))) {
140                 printk(KERN_ERR "ebi2_lcd_probe: platform_device_add_data failed!\n");
141                 platform_device_put(mdp_dev);
142                 return -ENOMEM;
143         }
144
145         /* data chain */
146         pdata = mdp_dev->dev.platform_data;
147         pdata->on = panel_next_on;
148         pdata->off = panel_next_off;
149         pdata->next = pdev;
150
151         /* get/set panel specific fb info */
152         mfd->panel_info = pdata->panel_info;
153
154         if (mfd->panel_info.bpp == 24)
155                 mfd->fb_imgType = MDP_RGB_888;
156         else
157                 mfd->fb_imgType = MDP_RGB_565;
158
159         /* config msm ebi2 lcd register */
160         if (mfd->panel_info.pdest == DISPLAY_1) {
161                 outp32(ebi2_base,
162                        (inp32(ebi2_base) & (~(EBI2_PRIM_LCD_CLR))) |
163                        EBI2_PRIM_LCD_SEL);
164                 /*
165                  * current design has one set of cfg0/1 register to control
166                  * both EBI2 channels. so, we're using the PRIM channel to
167                  * configure both.
168                  */
169                 outp32(ebi2_lcd_cfg0, mfd->panel_info.wait_cycle);
170                 if (mfd->panel_info.bpp == 18)
171                         outp32(ebi2_lcd_cfg1, 0x01000000);
172                 else
173                         outp32(ebi2_lcd_cfg1, 0x0);
174         } else {
175 #ifdef DEBUG_EBI2_LCD
176                 /*
177                  * confliting with QCOM SURF FPGA CS.
178                  * OEM should enable below for their CS mapping
179                  */
180                  outp32(ebi2_base, (inp32(ebi2_base)&(~(EBI2_SECD_LCD_CLR)))
181                                         |EBI2_SECD_LCD_SEL);
182 #endif
183         }
184
185         /*
186          * map cs (chip select) address
187          */
188         if (mfd->panel_info.pdest == DISPLAY_1) {
189                 mfd->cmd_port = lcd01_base;
190                 mfd->data_port =
191                     (void *)((uint32) mfd->cmd_port + EBI2_PRIM_LCD_RS_PIN);
192                 mfd->data_port_phys =
193                     (void *)(LCD_PRIM_BASE_PHYS + EBI2_PRIM_LCD_RS_PIN);
194         } else {
195                 mfd->cmd_port = lcd01_base;
196                 mfd->data_port =
197                     (void *)((uint32) mfd->cmd_port + EBI2_SECD_LCD_RS_PIN);
198                 mfd->data_port_phys =
199                     (void *)(LCD_SECD_BASE_PHYS + EBI2_SECD_LCD_RS_PIN);
200         }
201
202         /*
203          * set driver data
204          */
205         platform_set_drvdata(mdp_dev, mfd);
206
207         /*
208          * register in mdp driver
209          */
210         rc = platform_device_add(mdp_dev);
211         if (rc) {
212                 goto ebi2_lcd_probe_err;
213         }
214
215         pdev_list[pdev_list_cnt++] = pdev;
216         return 0;
217
218       ebi2_lcd_probe_err:
219         platform_device_put(mdp_dev);
220         return rc;
221 }
222
223 static int ebi2_lcd_remove(struct platform_device *pdev)
224 {
225         struct msm_fb_data_type *mfd;
226
227         mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
228
229         if (!mfd)
230                 return 0;
231
232         if (mfd->key != MFD_KEY)
233                 return 0;
234
235         iounmap(mfd->cmd_port);
236
237         return 0;
238 }
239
240 static int ebi2_lcd_register_driver(void)
241 {
242         return platform_driver_register(&ebi2_lcd_driver);
243 }
244
245 static int __init ebi2_lcd_driver_init(void)
246 {
247         return ebi2_lcd_register_driver();
248 }
249
250 module_init(ebi2_lcd_driver_init);