2 * Copyright (C) 2009 Nokia Corporation
3 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
18 #define DSS_SUBSYS_NAME "SDI"
20 #include <linux/kernel.h>
21 #include <linux/delay.h>
22 #include <linux/err.h>
23 #include <linux/regulator/consumer.h>
24 #include <linux/export.h>
25 #include <linux/platform_device.h>
26 #include <linux/string.h>
33 struct platform_device
*pdev
;
36 struct regulator
*vdds_sdi_reg
;
38 struct dss_lcd_mgr_config mgr_config
;
42 struct omap_dss_device output
;
44 bool port_initialized
;
47 struct sdi_clk_calc_ctx
{
48 unsigned long pck_min
, pck_max
;
51 struct dispc_clock_info dispc_cinfo
;
54 static bool dpi_calc_dispc_cb(int lckd
, int pckd
, unsigned long lck
,
55 unsigned long pck
, void *data
)
57 struct sdi_clk_calc_ctx
*ctx
= data
;
59 ctx
->dispc_cinfo
.lck_div
= lckd
;
60 ctx
->dispc_cinfo
.pck_div
= pckd
;
61 ctx
->dispc_cinfo
.lck
= lck
;
62 ctx
->dispc_cinfo
.pck
= pck
;
67 static bool dpi_calc_dss_cb(unsigned long fck
, void *data
)
69 struct sdi_clk_calc_ctx
*ctx
= data
;
73 return dispc_div_calc(fck
, ctx
->pck_min
, ctx
->pck_max
,
74 dpi_calc_dispc_cb
, ctx
);
77 static int sdi_calc_clock_div(unsigned long pclk
,
79 struct dispc_clock_info
*dispc_cinfo
)
82 struct sdi_clk_calc_ctx ctx
;
85 * DSS fclk gives us very few possibilities, so finding a good pixel
86 * clock may not be possible. We try multiple times to find the clock,
87 * each time widening the pixel clock range we look for, up to
91 for (i
= 0; i
< 10; ++i
) {
94 memset(&ctx
, 0, sizeof(ctx
));
95 if (pclk
> 1000 * i
* i
* i
)
96 ctx
.pck_min
= max(pclk
- 1000 * i
* i
* i
, 0lu);
99 ctx
.pck_max
= pclk
+ 1000 * i
* i
* i
;
101 ok
= dss_div_calc(pclk
, ctx
.pck_min
, dpi_calc_dss_cb
, &ctx
);
104 *dispc_cinfo
= ctx
.dispc_cinfo
;
112 static void sdi_config_lcd_manager(struct omap_dss_device
*dssdev
)
114 enum omap_channel channel
= dssdev
->dispc_channel
;
116 sdi
.mgr_config
.io_pad_mode
= DSS_IO_PAD_MODE_BYPASS
;
118 sdi
.mgr_config
.stallmode
= false;
119 sdi
.mgr_config
.fifohandcheck
= false;
121 sdi
.mgr_config
.video_port_width
= 24;
122 sdi
.mgr_config
.lcden_sig_polarity
= 1;
124 dss_mgr_set_lcd_config(channel
, &sdi
.mgr_config
);
127 static int sdi_display_enable(struct omap_dss_device
*dssdev
)
129 struct omap_dss_device
*out
= &sdi
.output
;
130 enum omap_channel channel
= dssdev
->dispc_channel
;
131 struct videomode
*vm
= &sdi
.vm
;
133 struct dispc_clock_info dispc_cinfo
;
137 if (!out
->dispc_channel_connected
) {
138 DSSERR("failed to enable display: no output/manager\n");
142 r
= regulator_enable(sdi
.vdds_sdi_reg
);
146 r
= dispc_runtime_get();
151 vm
->flags
|= DISPLAY_FLAGS_PIXDATA_POSEDGE
| DISPLAY_FLAGS_SYNC_POSEDGE
;
153 r
= sdi_calc_clock_div(vm
->pixelclock
, &fck
, &dispc_cinfo
);
155 goto err_calc_clock_div
;
157 sdi
.mgr_config
.clock_info
= dispc_cinfo
;
159 pck
= fck
/ dispc_cinfo
.lck_div
/ dispc_cinfo
.pck_div
;
161 if (pck
!= vm
->pixelclock
) {
162 DSSWARN("Could not find exact pixel clock. Requested %lu Hz, got %lu Hz\n",
163 vm
->pixelclock
, pck
);
165 vm
->pixelclock
= pck
;
169 dss_mgr_set_timings(channel
, vm
);
171 r
= dss_set_fck_rate(fck
);
173 goto err_set_dss_clock_div
;
175 sdi_config_lcd_manager(dssdev
);
178 * LCLK and PCLK divisors are located in shadow registers, and we
179 * normally write them to DISPC registers when enabling the output.
180 * However, SDI uses pck-free as source clock for its PLL, and pck-free
181 * is affected by the divisors. And as we need the PLL before enabling
182 * the output, we need to write the divisors early.
184 * It seems just writing to the DISPC register is enough, and we don't
185 * need to care about the shadow register mechanism for pck-free. The
186 * exact reason for this is unknown.
188 dispc_mgr_set_clock_div(channel
, &sdi
.mgr_config
.clock_info
);
190 dss_sdi_init(sdi
.datapairs
);
191 r
= dss_sdi_enable();
196 r
= dss_mgr_enable(channel
);
205 err_set_dss_clock_div
:
209 regulator_disable(sdi
.vdds_sdi_reg
);
214 static void sdi_display_disable(struct omap_dss_device
*dssdev
)
216 enum omap_channel channel
= dssdev
->dispc_channel
;
218 dss_mgr_disable(channel
);
224 regulator_disable(sdi
.vdds_sdi_reg
);
227 static void sdi_set_timings(struct omap_dss_device
*dssdev
,
228 struct videomode
*vm
)
233 static void sdi_get_timings(struct omap_dss_device
*dssdev
,
234 struct videomode
*vm
)
239 static int sdi_check_timings(struct omap_dss_device
*dssdev
,
240 struct videomode
*vm
)
242 enum omap_channel channel
= dssdev
->dispc_channel
;
244 if (!dispc_mgr_timings_ok(channel
, vm
))
247 if (vm
->pixelclock
== 0)
253 static int sdi_init_regulator(void)
255 struct regulator
*vdds_sdi
;
257 if (sdi
.vdds_sdi_reg
)
260 vdds_sdi
= devm_regulator_get(&sdi
.pdev
->dev
, "vdds_sdi");
261 if (IS_ERR(vdds_sdi
)) {
262 if (PTR_ERR(vdds_sdi
) != -EPROBE_DEFER
)
263 DSSERR("can't get VDDS_SDI regulator\n");
264 return PTR_ERR(vdds_sdi
);
267 sdi
.vdds_sdi_reg
= vdds_sdi
;
272 static int sdi_connect(struct omap_dss_device
*dssdev
,
273 struct omap_dss_device
*dst
)
275 enum omap_channel channel
= dssdev
->dispc_channel
;
278 r
= sdi_init_regulator();
282 r
= dss_mgr_connect(channel
, dssdev
);
286 r
= omapdss_output_set_device(dssdev
, dst
);
288 DSSERR("failed to connect output to new device: %s\n",
290 dss_mgr_disconnect(channel
, dssdev
);
297 static void sdi_disconnect(struct omap_dss_device
*dssdev
,
298 struct omap_dss_device
*dst
)
300 enum omap_channel channel
= dssdev
->dispc_channel
;
302 WARN_ON(dst
!= dssdev
->dst
);
304 if (dst
!= dssdev
->dst
)
307 omapdss_output_unset_device(dssdev
);
309 dss_mgr_disconnect(channel
, dssdev
);
312 static const struct omapdss_sdi_ops sdi_ops
= {
313 .connect
= sdi_connect
,
314 .disconnect
= sdi_disconnect
,
316 .enable
= sdi_display_enable
,
317 .disable
= sdi_display_disable
,
319 .check_timings
= sdi_check_timings
,
320 .set_timings
= sdi_set_timings
,
321 .get_timings
= sdi_get_timings
,
324 static void sdi_init_output(struct platform_device
*pdev
)
326 struct omap_dss_device
*out
= &sdi
.output
;
328 out
->dev
= &pdev
->dev
;
329 out
->id
= OMAP_DSS_OUTPUT_SDI
;
330 out
->output_type
= OMAP_DISPLAY_TYPE_SDI
;
332 out
->dispc_channel
= OMAP_DSS_CHANNEL_LCD
;
333 /* We have SDI only on OMAP3, where it's on port 1 */
335 out
->ops
.sdi
= &sdi_ops
;
336 out
->owner
= THIS_MODULE
;
338 omapdss_register_output(out
);
341 static void sdi_uninit_output(struct platform_device
*pdev
)
343 struct omap_dss_device
*out
= &sdi
.output
;
345 omapdss_unregister_output(out
);
348 int sdi_init_port(struct platform_device
*pdev
, struct device_node
*port
)
350 struct device_node
*ep
;
354 ep
= of_get_next_child(port
, NULL
);
358 r
= of_property_read_u32(ep
, "datapairs", &datapairs
);
360 DSSERR("failed to parse datapairs\n");
364 sdi
.datapairs
= datapairs
;
370 sdi_init_output(pdev
);
372 sdi
.port_initialized
= true;
382 void sdi_uninit_port(struct device_node
*port
)
384 if (!sdi
.port_initialized
)
387 sdi_uninit_output(sdi
.pdev
);