OMAPDSS: Remove passive matrix LCD support (part 4)
[linux-2.6-block.git] / drivers / video / omap2 / dss / sdi.c
CommitLineData
23c0a7a6
TV
1/*
2 * linux/drivers/video/omap2/dss/sdi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.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#define DSS_SUBSYS_NAME "SDI"
21
22#include <linux/kernel.h>
23c0a7a6
TV
23#include <linux/delay.h>
24#include <linux/err.h>
508886cf 25#include <linux/regulator/consumer.h>
a8a35931 26#include <linux/export.h>
a57dd4fe 27#include <linux/platform_device.h>
23c0a7a6 28
a0b38cc4 29#include <video/omapdss.h>
23c0a7a6
TV
30#include "dss.h"
31
32static struct {
23c0a7a6 33 bool update_enabled;
508886cf 34 struct regulator *vdds_sdi_reg;
23c0a7a6
TV
35} sdi;
36
64ba4f74
SS
37static void sdi_basic_init(struct omap_dss_device *dssdev)
38
23c0a7a6 39{
569969d6
AT
40 dispc_mgr_set_io_pad_mode(DSS_IO_PAD_MODE_BYPASS);
41 dispc_mgr_enable_stallmode(dssdev->manager->id, false);
64ba4f74 42
d21f43bc 43 dispc_mgr_set_lcd_type_tft(dssdev->manager->id);
23c0a7a6 44
26d9dd0d 45 dispc_mgr_set_tft_data_lines(dssdev->manager->id, 24);
23c0a7a6
TV
46 dispc_lcd_enable_signal_polarity(1);
47}
48
37ac60e4 49int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
23c0a7a6
TV
50{
51 struct omap_video_timings *t = &dssdev->panel.timings;
52 struct dss_clock_info dss_cinfo;
53 struct dispc_clock_info dispc_cinfo;
54 u16 lck_div, pck_div;
55 unsigned long fck;
56 unsigned long pck;
57 int r;
58
05e1d606
TV
59 if (dssdev->manager == NULL) {
60 DSSERR("failed to enable display: no manager\n");
61 return -ENODEV;
62 }
63
23c0a7a6
TV
64 r = omap_dss_start_device(dssdev);
65 if (r) {
66 DSSERR("failed to start device\n");
4fbafaf3 67 goto err_start_dev;
23c0a7a6
TV
68 }
69
508886cf
RQ
70 r = regulator_enable(sdi.vdds_sdi_reg);
71 if (r)
4fbafaf3 72 goto err_reg_enable;
508886cf 73
4fbafaf3
TV
74 r = dispc_runtime_get();
75 if (r)
76 goto err_get_dispc;
23c0a7a6 77
64ba4f74 78 sdi_basic_init(dssdev);
23c0a7a6
TV
79
80 /* 15.5.9.1.2 */
81 dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF;
82
a9105cb5 83 dispc_mgr_set_pol_freq(dssdev->manager->id, dssdev->panel.config);
23c0a7a6 84
6d523e7b 85 r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo);
23c0a7a6 86 if (r)
4fbafaf3 87 goto err_calc_clock_div;
23c0a7a6
TV
88
89 fck = dss_cinfo.fck;
90 lck_div = dispc_cinfo.lck_div;
91 pck_div = dispc_cinfo.pck_div;
92
93 pck = fck / lck_div / pck_div / 1000;
94
95 if (pck != t->pixel_clock) {
96 DSSWARN("Could not find exact pixel clock. Requested %d kHz, "
97 "got %lu kHz\n",
98 t->pixel_clock, pck);
99
100 t->pixel_clock = pck;
101 }
102
103
41721163 104 dss_mgr_set_timings(dssdev->manager, t);
23c0a7a6
TV
105
106 r = dss_set_clock_div(&dss_cinfo);
107 if (r)
4fbafaf3 108 goto err_set_dss_clock_div;
23c0a7a6 109
26d9dd0d 110 r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo);
23c0a7a6 111 if (r)
4fbafaf3 112 goto err_set_dispc_clock_div;
23c0a7a6 113
42c9dee8
TV
114 dss_sdi_init(dssdev->phy.sdi.datapairs);
115 r = dss_sdi_enable();
116 if (r)
4fbafaf3 117 goto err_sdi_enable;
42c9dee8 118 mdelay(2);
23c0a7a6 119
33ca237f
TV
120 r = dss_mgr_enable(dssdev->manager);
121 if (r)
122 goto err_mgr_enable;
23c0a7a6 123
23c0a7a6 124 return 0;
4fbafaf3 125
33ca237f
TV
126err_mgr_enable:
127 dss_sdi_disable();
4fbafaf3
TV
128err_sdi_enable:
129err_set_dispc_clock_div:
130err_set_dss_clock_div:
131err_calc_clock_div:
132 dispc_runtime_put();
133err_get_dispc:
508886cf 134 regulator_disable(sdi.vdds_sdi_reg);
4fbafaf3 135err_reg_enable:
23c0a7a6 136 omap_dss_stop_device(dssdev);
4fbafaf3 137err_start_dev:
23c0a7a6
TV
138 return r;
139}
37ac60e4 140EXPORT_SYMBOL(omapdss_sdi_display_enable);
23c0a7a6 141
37ac60e4 142void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
23c0a7a6 143{
7797c6da 144 dss_mgr_disable(dssdev->manager);
23c0a7a6
TV
145
146 dss_sdi_disable();
147
4fbafaf3 148 dispc_runtime_put();
23c0a7a6 149
508886cf
RQ
150 regulator_disable(sdi.vdds_sdi_reg);
151
23c0a7a6
TV
152 omap_dss_stop_device(dssdev);
153}
37ac60e4 154EXPORT_SYMBOL(omapdss_sdi_display_disable);
23c0a7a6 155
9d8232a7 156static int __init sdi_init_display(struct omap_dss_device *dssdev)
23c0a7a6
TV
157{
158 DSSDBG("SDI init\n");
159
5f42f2ce
TV
160 if (sdi.vdds_sdi_reg == NULL) {
161 struct regulator *vdds_sdi;
162
163 vdds_sdi = dss_get_vdds_sdi();
164
165 if (IS_ERR(vdds_sdi)) {
166 DSSERR("can't get VDDS_SDI regulator\n");
167 return PTR_ERR(vdds_sdi);
168 }
169
170 sdi.vdds_sdi_reg = vdds_sdi;
171 }
172
23c0a7a6
TV
173 return 0;
174}
175
38f3daf6 176static void __init sdi_probe_pdata(struct platform_device *pdev)
23c0a7a6 177{
35deca3d
TV
178 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
179 int i, r;
180
181 for (i = 0; i < pdata->num_devices; ++i) {
182 struct omap_dss_device *dssdev = pdata->devices[i];
183
184 if (dssdev->type != OMAP_DISPLAY_TYPE_SDI)
185 continue;
186
9d8232a7
TV
187 r = sdi_init_display(dssdev);
188 if (r) {
189 DSSERR("device %s init failed: %d\n", dssdev->name, r);
190 continue;
191 }
192
35deca3d
TV
193 r = omap_dss_register_device(dssdev, &pdev->dev, i);
194 if (r)
195 DSSERR("device %s register failed: %d\n",
196 dssdev->name, r);
197 }
38f3daf6
TV
198}
199
200static int __init omap_sdi_probe(struct platform_device *pdev)
201{
202 sdi_probe_pdata(pdev);
35deca3d 203
23c0a7a6
TV
204 return 0;
205}
206
6e7e8f06 207static int __exit omap_sdi_remove(struct platform_device *pdev)
23c0a7a6 208{
35deca3d
TV
209 omap_dss_unregister_child_devices(&pdev->dev);
210
a57dd4fe
TV
211 return 0;
212}
213
214static struct platform_driver omap_sdi_driver = {
6e7e8f06 215 .remove = __exit_p(omap_sdi_remove),
a57dd4fe
TV
216 .driver = {
217 .name = "omapdss_sdi",
218 .owner = THIS_MODULE,
219 },
220};
221
6e7e8f06 222int __init sdi_init_platform_driver(void)
a57dd4fe 223{
61055d4b 224 return platform_driver_probe(&omap_sdi_driver, omap_sdi_probe);
a57dd4fe
TV
225}
226
6e7e8f06 227void __exit sdi_uninit_platform_driver(void)
a57dd4fe
TV
228{
229 platform_driver_unregister(&omap_sdi_driver);
23c0a7a6 230}