aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/msm/mddi_client_toshiba.c
diff options
context:
space:
mode:
authorPavel Machek <pavel@ucw.cz>2009-09-22 19:47:03 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:50 -0400
commitd480ace08d5b59133575e672a0bd1c97b0f8400f (patch)
tree3e2e0edd582d7f511544ad87a6095c6227d280aa /drivers/video/msm/mddi_client_toshiba.c
parent689620100172e24fdf0981e9978a9559e8769258 (diff)
fbdev: framebuffer support for HTC Dream
Add a framebuffer driver for Qualcomm MSM/QSD SoCs, tested on HTC Dream smartphone (aka T-Mobile G1, aka ADP1). Brian said: I did the original quick and dirty version for bringup. Rebecca took over and (re)wrote the bulk of the driver, getting things stable for production ship of Dream and Sapphire, and Dima is currently adding support for later Qualcomm chipsets (QSD8x50, etc). Signed-off-by: Pavel Machek <pavel@ucw.cz> Cc: Brian Swetland <swetland@google.com> Cc: Krzysztof Helt <krzysztof.h1@poczta.fm> Cc: Rebecca Schultz Zavin <rebecca@android.com> Cc: Dima Zavin <dima@android.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/msm/mddi_client_toshiba.c')
-rw-r--r--drivers/video/msm/mddi_client_toshiba.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/drivers/video/msm/mddi_client_toshiba.c b/drivers/video/msm/mddi_client_toshiba.c
new file mode 100644
index 00000000000..80d0f5fdf0b
--- /dev/null
+++ b/drivers/video/msm/mddi_client_toshiba.c
@@ -0,0 +1,283 @@
1/* drivers/video/msm_fb/mddi_client_toshiba.c
2 *
3 * Support for Toshiba TC358720XBG mddi client devices which require no
4 * special initialization code.
5 *
6 * Copyright (C) 2007 Google Incorporated
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <linux/module.h>
19#include <linux/kernel.h>
20#include <linux/platform_device.h>
21#include <linux/interrupt.h>
22#include <linux/gpio.h>
23#include <mach/msm_fb.h>
24
25
26#define LCD_CONTROL_BLOCK_BASE 0x110000
27#define CMN (LCD_CONTROL_BLOCK_BASE|0x10)
28#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18)
29#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34)
30#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C)
31#define VPOS (LCD_CONTROL_BLOCK_BASE|0xC0)
32#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20)
33#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54)
34#define WSYN_DLY (LCD_CONTROL_BLOCK_BASE|0x58)
35#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C)
36
37#define BASE5 0x150000
38#define BASE6 0x160000
39#define BASE7 0x170000
40
41#define GPIOIEV (BASE5 + 0x10)
42#define GPIOIE (BASE5 + 0x14)
43#define GPIORIS (BASE5 + 0x18)
44#define GPIOMIS (BASE5 + 0x1C)
45#define GPIOIC (BASE5 + 0x20)
46
47#define INTMASK (BASE6 + 0x0C)
48#define INTMASK_VWAKEOUT (1U << 0)
49#define INTMASK_VWAKEOUT_ACTIVE_LOW (1U << 8)
50#define GPIOSEL (BASE7 + 0x00)
51#define GPIOSEL_VWAKEINT (1U << 0)
52
53static DECLARE_WAIT_QUEUE_HEAD(toshiba_vsync_wait);
54
55struct panel_info {
56 struct msm_mddi_client_data *client_data;
57 struct platform_device pdev;
58 struct msm_panel_data panel_data;
59 struct msmfb_callback *toshiba_callback;
60 int toshiba_got_int;
61};
62
63
64static void toshiba_request_vsync(struct msm_panel_data *panel_data,
65 struct msmfb_callback *callback)
66{
67 struct panel_info *panel = container_of(panel_data, struct panel_info,
68 panel_data);
69 struct msm_mddi_client_data *client_data = panel->client_data;
70
71 panel->toshiba_callback = callback;
72 if (panel->toshiba_got_int) {
73 panel->toshiba_got_int = 0;
74 client_data->activate_link(client_data);
75 }
76}
77
78static void toshiba_clear_vsync(struct msm_panel_data *panel_data)
79{
80 struct panel_info *panel = container_of(panel_data, struct panel_info,
81 panel_data);
82 struct msm_mddi_client_data *client_data = panel->client_data;
83
84 client_data->activate_link(client_data);
85}
86
87static void toshiba_wait_vsync(struct msm_panel_data *panel_data)
88{
89 struct panel_info *panel = container_of(panel_data, struct panel_info,
90 panel_data);
91 struct msm_mddi_client_data *client_data = panel->client_data;
92
93 if (panel->toshiba_got_int) {
94 panel->toshiba_got_int = 0;
95 client_data->activate_link(client_data); /* clears interrupt */
96 }
97 if (wait_event_timeout(toshiba_vsync_wait, panel->toshiba_got_int,
98 HZ/2) == 0)
99 printk(KERN_ERR "timeout waiting for VSYNC\n");
100 panel->toshiba_got_int = 0;
101 /* interrupt clears when screen dma starts */
102}
103
104static int toshiba_suspend(struct msm_panel_data *panel_data)
105{
106 struct panel_info *panel = container_of(panel_data, struct panel_info,
107 panel_data);
108 struct msm_mddi_client_data *client_data = panel->client_data;
109
110 struct msm_mddi_bridge_platform_data *bridge_data =
111 client_data->private_client_data;
112 int ret;
113
114 ret = bridge_data->uninit(bridge_data, client_data);
115 if (ret) {
116 printk(KERN_INFO "mddi toshiba client: non zero return from "
117 "uninit\n");
118 return ret;
119 }
120 client_data->suspend(client_data);
121 return 0;
122}
123
124static int toshiba_resume(struct msm_panel_data *panel_data)
125{
126 struct panel_info *panel = container_of(panel_data, struct panel_info,
127 panel_data);
128 struct msm_mddi_client_data *client_data = panel->client_data;
129
130 struct msm_mddi_bridge_platform_data *bridge_data =
131 client_data->private_client_data;
132 int ret;
133
134 client_data->resume(client_data);
135 ret = bridge_data->init(bridge_data, client_data);
136 if (ret)
137 return ret;
138 return 0;
139}
140
141static int toshiba_blank(struct msm_panel_data *panel_data)
142{
143 struct panel_info *panel = container_of(panel_data, struct panel_info,
144 panel_data);
145 struct msm_mddi_client_data *client_data = panel->client_data;
146 struct msm_mddi_bridge_platform_data *bridge_data =
147 client_data->private_client_data;
148
149 return bridge_data->blank(bridge_data, client_data);
150}
151
152static int toshiba_unblank(struct msm_panel_data *panel_data)
153{
154 struct panel_info *panel = container_of(panel_data, struct panel_info,
155 panel_data);
156 struct msm_mddi_client_data *client_data = panel->client_data;
157 struct msm_mddi_bridge_platform_data *bridge_data =
158 client_data->private_client_data;
159
160 return bridge_data->unblank(bridge_data, client_data);
161}
162
163irqreturn_t toshiba_vsync_interrupt(int irq, void *data)
164{
165 struct panel_info *panel = data;
166
167 panel->toshiba_got_int = 1;
168 if (panel->toshiba_callback) {
169 panel->toshiba_callback->func(panel->toshiba_callback);
170 panel->toshiba_callback = 0;
171 }
172 wake_up(&toshiba_vsync_wait);
173 return IRQ_HANDLED;
174}
175
176static int setup_vsync(struct panel_info *panel,
177 int init)
178{
179 int ret;
180 int gpio = 97;
181 unsigned int irq;
182
183 if (!init) {
184 ret = 0;
185 goto uninit;
186 }
187 ret = gpio_request(gpio, "vsync");
188 if (ret)
189 goto err_request_gpio_failed;
190
191 ret = gpio_direction_input(gpio);
192 if (ret)
193 goto err_gpio_direction_input_failed;
194
195 ret = irq = gpio_to_irq(gpio);
196 if (ret < 0)
197 goto err_get_irq_num_failed;
198
199 ret = request_irq(irq, toshiba_vsync_interrupt, IRQF_TRIGGER_RISING,
200 "vsync", panel);
201 if (ret)
202 goto err_request_irq_failed;
203 printk(KERN_INFO "vsync on gpio %d now %d\n",
204 gpio, gpio_get_value(gpio));
205 return 0;
206
207uninit:
208 free_irq(gpio_to_irq(gpio), panel);
209err_request_irq_failed:
210err_get_irq_num_failed:
211err_gpio_direction_input_failed:
212 gpio_free(gpio);
213err_request_gpio_failed:
214 return ret;
215}
216
217static int mddi_toshiba_probe(struct platform_device *pdev)
218{
219 int ret;
220 struct msm_mddi_client_data *client_data = pdev->dev.platform_data;
221 struct msm_mddi_bridge_platform_data *bridge_data =
222 client_data->private_client_data;
223 struct panel_info *panel =
224 kzalloc(sizeof(struct panel_info), GFP_KERNEL);
225 if (!panel)
226 return -ENOMEM;
227 platform_set_drvdata(pdev, panel);
228
229 /* mddi_remote_write(mddi, 0, WAKEUP); */
230 client_data->remote_write(client_data, GPIOSEL_VWAKEINT, GPIOSEL);
231 client_data->remote_write(client_data, INTMASK_VWAKEOUT, INTMASK);
232
233 ret = setup_vsync(panel, 1);
234 if (ret) {
235 dev_err(&pdev->dev, "mddi_bridge_setup_vsync failed\n");
236 return ret;
237 }
238
239 panel->client_data = client_data;
240 panel->panel_data.suspend = toshiba_suspend;
241 panel->panel_data.resume = toshiba_resume;
242 panel->panel_data.wait_vsync = toshiba_wait_vsync;
243 panel->panel_data.request_vsync = toshiba_request_vsync;
244 panel->panel_data.clear_vsync = toshiba_clear_vsync;
245 panel->panel_data.blank = toshiba_blank;
246 panel->panel_data.unblank = toshiba_unblank;
247 panel->panel_data.fb_data = &bridge_data->fb_data;
248 panel->panel_data.caps = MSMFB_CAP_PARTIAL_UPDATES;
249
250 panel->pdev.name = "msm_panel";
251 panel->pdev.id = pdev->id;
252 panel->pdev.resource = client_data->fb_resource;
253 panel->pdev.num_resources = 1;
254 panel->pdev.dev.platform_data = &panel->panel_data;
255 bridge_data->init(bridge_data, client_data);
256 platform_device_register(&panel->pdev);
257
258 return 0;
259}
260
261static int mddi_toshiba_remove(struct platform_device *pdev)
262{
263 struct panel_info *panel = platform_get_drvdata(pdev);
264
265 setup_vsync(panel, 0);
266 kfree(panel);
267 return 0;
268}
269
270static struct platform_driver mddi_client_d263_0000 = {
271 .probe = mddi_toshiba_probe,
272 .remove = mddi_toshiba_remove,
273 .driver = { .name = "mddi_c_d263_0000" },
274};
275
276static int __init mddi_client_toshiba_init(void)
277{
278 platform_driver_register(&mddi_client_d263_0000);
279 return 0;
280}
281
282module_init(mddi_client_toshiba_init);
283