~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/video/omap2/displays/panel-dvi.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DVI output support
 
3
 *
 
4
 * Copyright (C) 2011 Texas Instruments Inc
 
5
 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify it
 
8
 * under the terms of the GNU General Public License version 2 as published by
 
9
 * the Free Software Foundation.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
 
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
14
 * more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License along with
 
17
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include <linux/module.h>
 
21
#include <linux/slab.h>
 
22
#include <video/omapdss.h>
 
23
#include <linux/i2c.h>
 
24
#include <drm/drm_edid.h>
 
25
 
 
26
#include <video/omap-panel-dvi.h>
 
27
 
 
28
static const struct omap_video_timings panel_dvi_default_timings = {
 
29
        .x_res          = 640,
 
30
        .y_res          = 480,
 
31
 
 
32
        .pixel_clock    = 23500,
 
33
 
 
34
        .hfp            = 48,
 
35
        .hsw            = 32,
 
36
        .hbp            = 80,
 
37
 
 
38
        .vfp            = 3,
 
39
        .vsw            = 4,
 
40
        .vbp            = 7,
 
41
};
 
42
 
 
43
struct panel_drv_data {
 
44
        struct omap_dss_device *dssdev;
 
45
 
 
46
        struct mutex lock;
 
47
};
 
48
 
 
49
static inline struct panel_dvi_platform_data
 
50
*get_pdata(const struct omap_dss_device *dssdev)
 
51
{
 
52
        return dssdev->data;
 
53
}
 
54
 
 
55
static int panel_dvi_power_on(struct omap_dss_device *dssdev)
 
56
{
 
57
        struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
 
58
        int r;
 
59
 
 
60
        if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
 
61
                return 0;
 
62
 
 
63
        r = omapdss_dpi_display_enable(dssdev);
 
64
        if (r)
 
65
                goto err0;
 
66
 
 
67
        if (pdata->platform_enable) {
 
68
                r = pdata->platform_enable(dssdev);
 
69
                if (r)
 
70
                        goto err1;
 
71
        }
 
72
 
 
73
        return 0;
 
74
err1:
 
75
        omapdss_dpi_display_disable(dssdev);
 
76
err0:
 
77
        return r;
 
78
}
 
79
 
 
80
static void panel_dvi_power_off(struct omap_dss_device *dssdev)
 
81
{
 
82
        struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
 
83
 
 
84
        if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
 
85
                return;
 
86
 
 
87
        if (pdata->platform_disable)
 
88
                pdata->platform_disable(dssdev);
 
89
 
 
90
        omapdss_dpi_display_disable(dssdev);
 
91
}
 
92
 
 
93
static int panel_dvi_probe(struct omap_dss_device *dssdev)
 
94
{
 
95
        struct panel_drv_data *ddata;
 
96
 
 
97
        ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
 
98
        if (!ddata)
 
99
                return -ENOMEM;
 
100
 
 
101
        dssdev->panel.timings = panel_dvi_default_timings;
 
102
        dssdev->panel.config = OMAP_DSS_LCD_TFT;
 
103
 
 
104
        ddata->dssdev = dssdev;
 
105
        mutex_init(&ddata->lock);
 
106
 
 
107
        dev_set_drvdata(&dssdev->dev, ddata);
 
108
 
 
109
        return 0;
 
110
}
 
111
 
 
112
static void __exit panel_dvi_remove(struct omap_dss_device *dssdev)
 
113
{
 
114
        struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
 
115
 
 
116
        mutex_lock(&ddata->lock);
 
117
 
 
118
        dev_set_drvdata(&dssdev->dev, NULL);
 
119
 
 
120
        mutex_unlock(&ddata->lock);
 
121
 
 
122
        kfree(ddata);
 
123
}
 
124
 
 
125
static int panel_dvi_enable(struct omap_dss_device *dssdev)
 
126
{
 
127
        struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
 
128
        int r;
 
129
 
 
130
        mutex_lock(&ddata->lock);
 
131
 
 
132
        r = panel_dvi_power_on(dssdev);
 
133
        if (r == 0)
 
134
                dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
135
 
 
136
        mutex_unlock(&ddata->lock);
 
137
 
 
138
        return r;
 
139
}
 
140
 
 
141
static void panel_dvi_disable(struct omap_dss_device *dssdev)
 
142
{
 
143
        struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
 
144
 
 
145
        mutex_lock(&ddata->lock);
 
146
 
 
147
        panel_dvi_power_off(dssdev);
 
148
 
 
149
        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 
150
 
 
151
        mutex_unlock(&ddata->lock);
 
152
}
 
153
 
 
154
static int panel_dvi_suspend(struct omap_dss_device *dssdev)
 
155
{
 
156
        struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
 
157
 
 
158
        mutex_lock(&ddata->lock);
 
159
 
 
160
        panel_dvi_power_off(dssdev);
 
161
 
 
162
        dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
 
163
 
 
164
        mutex_unlock(&ddata->lock);
 
165
 
 
166
        return 0;
 
167
}
 
168
 
 
169
static int panel_dvi_resume(struct omap_dss_device *dssdev)
 
170
{
 
171
        struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
 
172
        int r;
 
173
 
 
174
        mutex_lock(&ddata->lock);
 
175
 
 
176
        r = panel_dvi_power_on(dssdev);
 
177
        if (r == 0)
 
178
                dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
179
 
 
180
        mutex_unlock(&ddata->lock);
 
181
 
 
182
        return r;
 
183
}
 
184
 
 
185
static void panel_dvi_set_timings(struct omap_dss_device *dssdev,
 
186
                struct omap_video_timings *timings)
 
187
{
 
188
        struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
 
189
 
 
190
        mutex_lock(&ddata->lock);
 
191
        dpi_set_timings(dssdev, timings);
 
192
        mutex_unlock(&ddata->lock);
 
193
}
 
194
 
 
195
static void panel_dvi_get_timings(struct omap_dss_device *dssdev,
 
196
                struct omap_video_timings *timings)
 
197
{
 
198
        struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
 
199
 
 
200
        mutex_lock(&ddata->lock);
 
201
        *timings = dssdev->panel.timings;
 
202
        mutex_unlock(&ddata->lock);
 
203
}
 
204
 
 
205
static int panel_dvi_check_timings(struct omap_dss_device *dssdev,
 
206
                struct omap_video_timings *timings)
 
207
{
 
208
        struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
 
209
        int r;
 
210
 
 
211
        mutex_lock(&ddata->lock);
 
212
        r = dpi_check_timings(dssdev, timings);
 
213
        mutex_unlock(&ddata->lock);
 
214
 
 
215
        return r;
 
216
}
 
217
 
 
218
 
 
219
static int panel_dvi_ddc_read(struct i2c_adapter *adapter,
 
220
                unsigned char *buf, u16 count, u8 offset)
 
221
{
 
222
        int r, retries;
 
223
 
 
224
        for (retries = 3; retries > 0; retries--) {
 
225
                struct i2c_msg msgs[] = {
 
226
                        {
 
227
                                .addr   = DDC_ADDR,
 
228
                                .flags  = 0,
 
229
                                .len    = 1,
 
230
                                .buf    = &offset,
 
231
                        }, {
 
232
                                .addr   = DDC_ADDR,
 
233
                                .flags  = I2C_M_RD,
 
234
                                .len    = count,
 
235
                                .buf    = buf,
 
236
                        }
 
237
                };
 
238
 
 
239
                r = i2c_transfer(adapter, msgs, 2);
 
240
                if (r == 2)
 
241
                        return 0;
 
242
 
 
243
                if (r != -EAGAIN)
 
244
                        break;
 
245
        }
 
246
 
 
247
        return r < 0 ? r : -EIO;
 
248
}
 
249
 
 
250
static int panel_dvi_read_edid(struct omap_dss_device *dssdev,
 
251
                u8 *edid, int len)
 
252
{
 
253
        struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
 
254
        struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
 
255
        struct i2c_adapter *adapter;
 
256
        int r, l, bytes_read;
 
257
 
 
258
        mutex_lock(&ddata->lock);
 
259
 
 
260
        if (pdata->i2c_bus_num == 0) {
 
261
                r = -ENODEV;
 
262
                goto err;
 
263
        }
 
264
 
 
265
        adapter = i2c_get_adapter(pdata->i2c_bus_num);
 
266
        if (!adapter) {
 
267
                dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
 
268
                                pdata->i2c_bus_num);
 
269
                r = -EINVAL;
 
270
                goto err;
 
271
        }
 
272
 
 
273
        l = min(EDID_LENGTH, len);
 
274
        r = panel_dvi_ddc_read(adapter, edid, l, 0);
 
275
        if (r)
 
276
                goto err;
 
277
 
 
278
        bytes_read = l;
 
279
 
 
280
        /* if there are extensions, read second block */
 
281
        if (len > EDID_LENGTH && edid[0x7e] > 0) {
 
282
                l = min(EDID_LENGTH, len - EDID_LENGTH);
 
283
 
 
284
                r = panel_dvi_ddc_read(adapter, edid + EDID_LENGTH,
 
285
                                l, EDID_LENGTH);
 
286
                if (r)
 
287
                        goto err;
 
288
 
 
289
                bytes_read += l;
 
290
        }
 
291
 
 
292
        mutex_unlock(&ddata->lock);
 
293
 
 
294
        return bytes_read;
 
295
 
 
296
err:
 
297
        mutex_unlock(&ddata->lock);
 
298
        return r;
 
299
}
 
300
 
 
301
static bool panel_dvi_detect(struct omap_dss_device *dssdev)
 
302
{
 
303
        struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
 
304
        struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
 
305
        struct i2c_adapter *adapter;
 
306
        unsigned char out;
 
307
        int r;
 
308
 
 
309
        mutex_lock(&ddata->lock);
 
310
 
 
311
        if (pdata->i2c_bus_num == 0)
 
312
                goto out;
 
313
 
 
314
        adapter = i2c_get_adapter(pdata->i2c_bus_num);
 
315
        if (!adapter)
 
316
                goto out;
 
317
 
 
318
        r = panel_dvi_ddc_read(adapter, &out, 1, 0);
 
319
 
 
320
        mutex_unlock(&ddata->lock);
 
321
 
 
322
        return r == 0;
 
323
 
 
324
out:
 
325
        mutex_unlock(&ddata->lock);
 
326
        return true;
 
327
}
 
328
 
 
329
static struct omap_dss_driver panel_dvi_driver = {
 
330
        .probe          = panel_dvi_probe,
 
331
        .remove         = __exit_p(panel_dvi_remove),
 
332
 
 
333
        .enable         = panel_dvi_enable,
 
334
        .disable        = panel_dvi_disable,
 
335
        .suspend        = panel_dvi_suspend,
 
336
        .resume         = panel_dvi_resume,
 
337
 
 
338
        .set_timings    = panel_dvi_set_timings,
 
339
        .get_timings    = panel_dvi_get_timings,
 
340
        .check_timings  = panel_dvi_check_timings,
 
341
 
 
342
        .read_edid      = panel_dvi_read_edid,
 
343
        .detect         = panel_dvi_detect,
 
344
 
 
345
        .driver         = {
 
346
                .name   = "dvi",
 
347
                .owner  = THIS_MODULE,
 
348
        },
 
349
};
 
350
 
 
351
static int __init panel_dvi_init(void)
 
352
{
 
353
        return omap_dss_register_driver(&panel_dvi_driver);
 
354
}
 
355
 
 
356
static void __exit panel_dvi_exit(void)
 
357
{
 
358
        omap_dss_unregister_driver(&panel_dvi_driver);
 
359
}
 
360
 
 
361
module_init(panel_dvi_init);
 
362
module_exit(panel_dvi_exit);
 
363
MODULE_LICENSE("GPL");