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> 23#include <linux/clk.h> 24#include <linux/delay.h> 25#include <linux/err.h> 26#include <linux/regulator/consumer.h> 27 28#include <plat/display.h> 29#include <plat/cpu.h> 30#include "dss.h" 31 32static struct { 33 bool skip_init; 34 bool update_enabled; 35 struct regulator *vdds_sdi_reg; 36} sdi; 37 38static void sdi_basic_init(void) 39{ 40 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS); 41 42 dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); 43 dispc_set_tft_data_lines(24); 44 dispc_lcd_enable_signal_polarity(1); 45} 46 47int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) 48{ 49 struct omap_video_timings *t = &dssdev->panel.timings; 50 struct dss_clock_info dss_cinfo; 51 struct dispc_clock_info dispc_cinfo; 52 u16 lck_div, pck_div; 53 unsigned long fck; 54 unsigned long pck; 55 int r; 56 57 r = omap_dss_start_device(dssdev); 58 if (r) { 59 DSSERR("failed to start device\n"); 60 goto err0; 61 } 62 63 r = regulator_enable(sdi.vdds_sdi_reg); 64 if (r) 65 goto err1; 66 67 /* In case of skip_init sdi_init has already enabled the clocks */ 68 if (!sdi.skip_init) 69 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); 70 71 sdi_basic_init(); 72 73 /* 15.5.9.1.2 */ 74 dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF; 75 76 dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi, 77 dssdev->panel.acb); 78 79 if (!sdi.skip_init) { 80 r = dss_calc_clock_div(1, t->pixel_clock * 1000, 81 &dss_cinfo, &dispc_cinfo); 82 } else { 83 r = dss_get_clock_div(&dss_cinfo); 84 r = dispc_get_clock_div(&dispc_cinfo); 85 } 86 87 if (r) 88 goto err2; 89 90 fck = dss_cinfo.fck; 91 lck_div = dispc_cinfo.lck_div; 92 pck_div = dispc_cinfo.pck_div; 93 94 pck = fck / lck_div / pck_div / 1000; 95 96 if (pck != t->pixel_clock) { 97 DSSWARN("Could not find exact pixel clock. Requested %d kHz, " 98 "got %lu kHz\n", 99 t->pixel_clock, pck); 100 101 t->pixel_clock = pck; 102 } 103 104 105 dispc_set_lcd_timings(t); 106 107 r = dss_set_clock_div(&dss_cinfo); 108 if (r) 109 goto err2; 110 111 r = dispc_set_clock_div(&dispc_cinfo); 112 if (r) 113 goto err2; 114 115 if (!sdi.skip_init) { 116 dss_sdi_init(dssdev->phy.sdi.datapairs); 117 r = dss_sdi_enable(); 118 if (r) 119 goto err1; 120 mdelay(2); 121 } 122 123 dssdev->manager->enable(dssdev->manager); 124 125 sdi.skip_init = 0; 126 127 return 0; 128err2: 129 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); 130 regulator_disable(sdi.vdds_sdi_reg); 131err1: 132 omap_dss_stop_device(dssdev); 133err0: 134 return r; 135} 136EXPORT_SYMBOL(omapdss_sdi_display_enable); 137 138void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) 139{ 140 dssdev->manager->disable(dssdev->manager); 141 142 dss_sdi_disable(); 143 144 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); 145 146 regulator_disable(sdi.vdds_sdi_reg); 147 148 omap_dss_stop_device(dssdev); 149} 150EXPORT_SYMBOL(omapdss_sdi_display_disable); 151 152int sdi_init_display(struct omap_dss_device *dssdev) 153{ 154 DSSDBG("SDI init\n"); 155 156 return 0; 157} 158 159int sdi_init(bool skip_init) 160{ 161 /* we store this for first display enable, then clear it */ 162 sdi.skip_init = skip_init; 163 164 sdi.vdds_sdi_reg = dss_get_vdds_sdi(); 165 if (IS_ERR(sdi.vdds_sdi_reg)) { 166 DSSERR("can't get VDDS_SDI regulator\n"); 167 return PTR_ERR(sdi.vdds_sdi_reg); 168 } 169 /* 170 * Enable clocks already here, otherwise there would be a toggle 171 * of them until sdi_display_enable is called. 172 */ 173 if (skip_init) 174 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); 175 return 0; 176} 177 178void sdi_exit(void) 179{ 180} 181