diff options
Diffstat (limited to 'drivers/video/samsung_duallcd/s5p-dsim.c')
-rw-r--r-- | drivers/video/samsung_duallcd/s5p-dsim.c | 1597 |
1 files changed, 0 insertions, 1597 deletions
diff --git a/drivers/video/samsung_duallcd/s5p-dsim.c b/drivers/video/samsung_duallcd/s5p-dsim.c deleted file mode 100644 index 05f4658..0000000 --- a/drivers/video/samsung_duallcd/s5p-dsim.c +++ /dev/null @@ -1,1597 +0,0 @@ -/* linux/drivers/video/samsung/s5p-dsim.c - * - * Samsung MIPI-DSIM driver. - * - * InKi Dae, <inki.dae@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Modified by Samsung Electronics (UK) on May 2010 - * -*/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/clk.h> -#include <linux/mutex.h> -#include <linux/wait.h> -#include <linux/fs.h> -#include <linux/mm.h> -#include <linux/fb.h> -#include <linux/ctype.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/memory.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/kthread.h> -#include <linux/workqueue.h> -#include <linux/regulator/consumer.h> -#include <linux/gpio.h> -#include <plat/clock.h> -#include <plat/regs-dsim.h> -#include <plat/gpio-cfg.h> -#include <mach/map.h> -#include <mach/dsim.h> -#include <mach/mipi_ddi.h> -#include <mach/irqs.h> - -#include "s5p-dsim.h" -#include "s5p_dsim_lowlevel.h" -#include "s3cfb.h" - -#ifdef CONFIG_HAS_WAKELOCK -#include <linux/wakelock.h> -#include <linux/earlysuspend.h> -#include <linux/suspend.h> -#endif - -struct mipi_lcd_info { - struct list_head list; - struct mipi_lcd_driver *mipi_drv; -}; - -static DEFINE_MUTEX(dsim_rd_wr_mutex); -static DECLARE_COMPLETION(dsim_rd_comp); -static DECLARE_COMPLETION(dsim_wr_comp); - -#define MIPI_RESP_ERR 0x02 -#define MIPI_RESP_EOTP 0x08 -#define MIPI_RESP_GENERIC_RD_1 0x11 -#define MIPI_RESP_GENERIC_RD_2 0x12 -#define MIPI_RESP_GENERIC_RD_LONG 0x1A -#define MIPI_RESP_DCS_RD_LONG 0x1C -#define MIPI_RESP_DCS_RD_1 0x21 -#define MIPI_RESP_DCS_RD_2 0x22 - -#define MIPI_CMD_GENERIC_WR_0 0x03 -#define MIPI_CMD_GENERIC_WR_1 0x13 -#define MIPI_CMD_GENERIC_WR_2 0x23 -#define MIPI_CMD_GENERIC_WR_LONG 0x29 - -#define MIPI_CMD_DSI_WR_0 0x05 -#define MIPI_CMD_DSI_WR_1 0x15 -#define MIPI_CMD_DSI_WR_LONG 0x39 - -#define MIPI_CMD_GENERIC_RD_0 0x04 -#define MIPI_CMD_GENERIC_RD_1 0x14 -#define MIPI_CMD_GENERIC_RD_2 0x24 - -#define MIPI_CMD_DSI_RD_0 0x06 - -#define MIPI_CMD_DSI_SET_PKT_SZ 0x37 - -#define DSIM_TIMEOUT msecs_to_jiffies(250) -#define DSIM_RX_FIFO_READ_DONE 0x30800002 -#define DSIM_MAX_RX_FIFO 20 - -#define S5P_DSIM_INT_SFR_FIFO_EMPTY 29 -#define S5P_DSIM_INT_BTA 25 -#define S5P_DSIM_INT_MSK_FRAME_DONE 24 -#define S5P_DSIM_INT_RX_TIMEOUT 21 -#define S5P_DSIM_INT_BTA_TIMEOUT 20 -#define S5P_DSIM_INT_RX_DONE 18 -#define S5P_DSIM_INT_RX_TE 17 -#define S5P_DSIM_INT_RX_ACK 16 -#define S5P_DSIM_INT_RX_ECC_ERR 15 -#define S5P_DSIM_IMT_RX_CRC_ERR 14 - -static LIST_HEAD(lcd_info_list); -static DEFINE_MUTEX(mipi_lock); -static struct dsim_global *g_dsim; - -static struct s5p_platform_dsim *to_dsim_plat(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - - return (struct s5p_platform_dsim *)pdev->dev.platform_data; -} - -static void s5p_dsim_frame_done_interrupt_enable(struct dsim_global *dsim, u8 enable) -{ - u32 intmsk; - u8 state = !enable; - - if (!dsim->mipi_ddi_pd->resume_complete) - return; - - intmsk = readl(dsim->reg_base + S5P_DSIM_INTMSK); - - if (state == 0) /* enable Frame Done interrupts */ - intmsk &= ~(0x01 << S5P_DSIM_INT_MSK_FRAME_DONE); - else /* disable Frame Done interrupts */ - intmsk |= (0x01 << S5P_DSIM_INT_MSK_FRAME_DONE); - - writel(intmsk, dsim->reg_base + S5P_DSIM_INTMSK); -} - -void set_dsim_lcd_enabled(u8 enable) -{ - struct dsim_global *dsim = g_dsim; - - dsim->dsim_lcd_info->lcd_enabled = enable; - if (dsim->dsim_info->hs_toggle) - s5p_dsim_frame_done_interrupt_enable(dsim, enable); -} - -void set_dsim_hs_clk_toggle_count(u8 count) -{ - struct dsim_global *dsim = g_dsim; - - dsim->dsim_toggle_per_frame_count = count; - if (dsim->dsim_lcd_info->lcd_enabled) - s5p_dsim_frame_done_interrupt_enable(dsim, count ? 1 : 0); -} - -static void dsim_work_q_handler(struct work_struct *work) -{ - struct dsim_global *dsim = - container_of(work, struct dsim_global, dsim_work.work); - - s5p_dsim_frame_done_interrupt_enable(dsim, 1); -} - -static void dsim_check_hs_toggle_work_q_handler(struct work_struct *work) -{ - struct dsim_global *dsim = - container_of(work, struct dsim_global, check_hs_toggle_work.work); - - if (dsim->dsim_info->hs_toggle) { - dev_info(dsim->dev, "check_hs_toggle\n"); - schedule_delayed_work(&dsim->check_hs_toggle_work, msecs_to_jiffies(120000)); - } -} - -unsigned char s5p_dsim_wr_data(void *ptr, - unsigned int data_id, unsigned int data0, unsigned int data1) -{ - struct dsim_global *dsim = ptr; - unsigned int dsim_base = dsim->reg_base; - - if (dsim->state == DSIM_STATE_ULPS) { - dev_err(dsim->dev, "DSIM state: ULPS\n"); - return DSIM_FALSE; - } - - if (dsim->mipi_ddi_pd->resume_complete == 0) { - dev_err(dsim->dev, "DSIM Status: SUSPEND\n"); - return DSIM_FALSE; - } - - mutex_lock(&dsim_rd_wr_mutex); - - switch (data_id) { - /* short packet types of packet types for command. */ - case GEN_SHORT_WR_NO_PARA: - case GEN_SHORT_WR_1_PARA: - case GEN_SHORT_WR_2_PARA: - case DCS_WR_NO_PARA: - case DCS_WR_1_PARA: - case SET_MAX_RTN_PKT_SIZE: - s5p_dsim_wr_tx_header(dsim_base, (unsigned char) data_id, - (unsigned char) data0, (unsigned char) data1); - mutex_unlock(&dsim_rd_wr_mutex); - return DSIM_TRUE; /* response should be implemented */ - /* general command */ - case CMD_OFF: - case CMD_ON: - case SHUT_DOWN: - case TURN_ON: - s5p_dsim_wr_tx_header(dsim_base, (unsigned char) data_id, - (unsigned char) data0, (unsigned char) data1); - mutex_unlock(&dsim_rd_wr_mutex); - return DSIM_TRUE; /* response should be implemented. */ - /* packet types for video data */ - case VSYNC_START: - case VSYNC_END: - case HSYNC_START: - case HSYNC_END: - case EOT_PKT: - mutex_unlock(&dsim_rd_wr_mutex); - return DSIM_TRUE; - - /* short and response packet types for command */ - case GEN_RD_1_PARA: - case GEN_RD_2_PARA: - case GEN_RD_NO_PARA: - case DCS_RD_NO_PARA: - s5p_dsim_clear_interrupt(dsim_base, 0xffffffff); - s5p_dsim_wr_tx_header(dsim_base, (unsigned char) data_id, - (unsigned char) data0, (unsigned char) data1); - mutex_unlock(&dsim_rd_wr_mutex); - return DSIM_FALSE; /* response should be implemented. */ - - /* long packet type and null packet */ - case NULL_PKT: - case BLANKING_PKT: - mutex_unlock(&dsim_rd_wr_mutex); - return DSIM_TRUE; - case GEN_LONG_WR: - case DCS_LONG_WR: - { - u32 uCnt = 0; - u32* pWordPtr = (u32 *)data0; - INIT_COMPLETION(dsim_wr_comp); - - do { - s5p_dsim_wr_tx_data(dsim_base, pWordPtr[uCnt]); - } while (((data1-1) / 4) > uCnt++); - - /* put data into header fifo */ - s5p_dsim_wr_tx_header(dsim_base, (unsigned char) data_id, - (unsigned char) (((unsigned short) data1) & 0xff), - (unsigned char) ((((unsigned short) data1) & 0xff00) >> 8)); - - if (!wait_for_completion_interruptible_timeout(&dsim_wr_comp, DSIM_TIMEOUT)) { - dev_err(dsim->dev, "[DSIM:ERROR] %s Timeout\n", __func__); - mutex_unlock(&dsim_rd_wr_mutex); - return DSIM_FALSE; - } - mutex_unlock(&dsim_rd_wr_mutex); - return DSIM_TRUE; - } - /* packet typo for video data */ - case RGB565_PACKED: - case RGB666_PACKED: - case RGB666_LOOSLY: - case RGB888_PACKED: - mutex_unlock(&dsim_rd_wr_mutex); - return DSIM_TRUE; /* response should be implemented. */ - default: - dev_warn(dsim->dev, "data id %x is not supported current DSI spec\n", data_id); - mutex_unlock(&dsim_rd_wr_mutex); - return DSIM_FALSE; - } -} - -int s5p_dsim_rd_data(void *ptr, u8 addr, u16 count, u8 *buf) -{ - u32 i, temp; - u8 response = 0; - u16 rxsize; - u32 txhd; - u32 rxhd; - int j; - struct dsim_global *dsim = ptr; - unsigned int reg_base = dsim->reg_base; - - if (dsim->mipi_ddi_pd->resume_complete == 0) { - dev_err(dsim->dev, "DSIM Status: SUSPEND\n"); - return DSIM_FALSE; - } - - mutex_lock(&dsim_rd_wr_mutex); - INIT_COMPLETION(dsim_rd_comp); - - switch (count) { - case 1: -#if defined(CONFIG_FB_S5P_S6E63M0) - response = MIPI_RESP_DCS_RD_1; -#else - response = MIPI_RESP_GENERIC_RD_1; -#endif /* CONFIG_FB_S5P_S6E63M0 */ - break; - case 2: -#if defined(CONFIG_FB_S5P_S6E63M0) - response = MIPI_RESP_DCS_RD_2; -#else - response = MIPI_RESP_GENERIC_RD_2; -#endif /* CONFIG_FB_S5P_S6E63M0 */ - break; - default: - response = MIPI_RESP_GENERIC_RD_LONG; - break; - } - - /* set return packet size */ - txhd = MIPI_CMD_DSI_SET_PKT_SZ | count << 8; - - writel(txhd, reg_base + S5P_DSIM_PKTHDR); - - /* set address to read */ -#if defined(CONFIG_FB_S5P_S6E63M0) - txhd = MIPI_CMD_DSI_RD_0 | addr << 8; -#else - txhd = MIPI_CMD_GENERIC_RD_1 | addr << 8; -#endif /* CONFIG_FB_S5P_S6E63M0 */ - - writel(txhd, reg_base + S5P_DSIM_PKTHDR); - - if (!wait_for_completion_interruptible_timeout(&dsim_rd_comp, DSIM_TIMEOUT)) { - dev_err(dsim->dev, "ERROR:%s timout\n", __func__); - mutex_unlock(&dsim_rd_wr_mutex); - return 0; - } - - rxhd = readl(reg_base + S5P_DSIM_RXFIFO); - dev_info(dsim->dev, "rxhd : %x\n", rxhd); - if ((u8)(rxhd & 0xff) != response) { - dev_err(dsim->dev, "[DSIM:ERROR]:%s wrong response rxhd : %x, response:%x\n" - , __func__, rxhd, response); - goto clear_rx_fifo; - } - /* for short packet */ - if (count <= 2) { - for (i = 0; i < count; i++) - buf[i] = (rxhd >> (8+(i*8))) & 0xff; - rxsize = count; - } else { - /* for long packet */ - rxsize = (u16)((rxhd & 0x00ffff00) >> 8); - dev_info(dsim->dev, "rcv size : %d\n", rxsize); - if (rxsize != count) { - dev_err(dsim->dev, "[DSIM:ERROR]:%s received data size mismatch received : %d, requested : %d\n", - __func__, rxsize, count); - goto clear_rx_fifo; - } - - for (i = 0; i < rxsize>>2; i++) { - temp = readl(reg_base + S5P_DSIM_RXFIFO); - dev_info(dsim->dev, "pkt : %08x\n", temp); - for (j = 0; j < 4; j++) { - buf[(i*4)+j] = (u8)(temp>>(j*8))&0xff; - /* printk("Value : %02x\n",(temp>>(j*8))&0xff); */ - } - } - if (rxsize % 4) { - temp = readl(reg_base + S5P_DSIM_RXFIFO); - dev_info(dsim->dev, "pkt-l : %08x\n", temp); - for (j = 0; j < rxsize%4; j++) { - buf[(i*4)+j] = (u8)(temp>>(j*8))&0xff; - /* printk("Value : %02x\n",(temp>>(j*8))&0xff); */ - } - } - } - - temp = readl(reg_base + S5P_DSIM_RXFIFO); - -#if !defined(CONFIG_FB_S5P_S6E63M0) - if (temp != DSIM_RX_FIFO_READ_DONE) { - dev_warn(dsim->dev, "[DSIM:WARN]:%s Can't found RX FIFO READ DONE FLAG : %x\n", __func__, temp); - goto clear_rx_fifo; - } -#endif - - mutex_unlock(&dsim_rd_wr_mutex); - return rxsize; - -clear_rx_fifo: - i = 0; - while (1) { - temp = readl(reg_base+S5P_DSIM_RXFIFO); - if ((temp == DSIM_RX_FIFO_READ_DONE) || (i > DSIM_MAX_RX_FIFO)) - break; - dev_info(dsim->dev, "[DSIM:INFO] : %s clear rx fifo : %08x\n", __func__, temp); - i++; - } - dev_info(dsim->dev, "[DSIM:INFO] : %s done count : %d, temp : %08x\n", __func__, i, temp); - - mutex_unlock(&dsim_rd_wr_mutex); - return 0; - -} - -static irqreturn_t s5p_dsim_isr(int irq, void *dev_id) -{ - int i; - unsigned int intsrc = 0; - unsigned int intmsk = 0; - struct dsim_global *dsim = NULL; - - dsim = (struct dsim_global *)dev_id; - if (!dsim) { - printk(KERN_ERR "%s:error:wrong parameter\n", __func__); - return IRQ_HANDLED; - } - - intsrc = readl(dsim->reg_base + S5P_DSIM_INTSRC); - intmsk = readl(dsim->reg_base + S5P_DSIM_INTMSK); - - intmsk = ~(intmsk) & intsrc; - - for (i = 0; i < 32; i++) { - if (intmsk & (0x01<<i)) { - switch (i) { - case S5P_DSIM_INT_BTA: - /* printk("S5P_DSIM_INT_BTA\n"); */ - break; - case S5P_DSIM_INT_RX_TIMEOUT: - /* printk("S5P_DSIM_INT_RX_TIMEOUT\n"); */ - break; - case S5P_DSIM_INT_BTA_TIMEOUT: - /* printk("S5P_DSIM_INT_BTA_TIMEOUT\n"); */ - break; - case S5P_DSIM_INT_RX_DONE: - complete_all(&dsim_rd_comp); - /* printk("S5P_DSIM_INT_RX_DONE\n"); */ - break; - case S5P_DSIM_INT_RX_TE: - /* printk("S5P_DSIM_INT_RX_TE\n"); */ - break; - case S5P_DSIM_INT_RX_ACK: - /* printk("S5P_DSIM_INT_RX_ACK\n"); */ - break; - case S5P_DSIM_INT_RX_ECC_ERR: - /* printk("S5P_DSIM_INT_RX_ECC_ERR\n"); */ - break; - case S5P_DSIM_IMT_RX_CRC_ERR: - /* printk("S5P_DSIM_IMT_RX_CRC_ERR\n"); */ - break; - case S5P_DSIM_INT_SFR_FIFO_EMPTY: - /* printk("S5P_DSIM_INT_SFR_FIFO_EMPTY\n"); */ - complete_all(&dsim_wr_comp); - break; - case S5P_DSIM_INT_MSK_FRAME_DONE: - /* printk("S5P_DSIM_INT_MSK_FRAME_DONE\n"); */ - if (dsim->dsim_lcd_info->lcd_enabled && dsim->mipi_ddi_pd->resume_complete) { - if (completion_done(&dsim_wr_comp) && completion_done(&dsim_rd_comp)) { - if (s3cfb_vsync_status_check()) { - s5p_dsim_toggle_hs_clock(dsim->reg_base); - if (!dsim->dsim_toggle_per_frame_count) { - s5p_dsim_frame_done_interrupt_enable(dsim, 0); - if (likely(dsim->dsim_info->hs_toggle - 1)) - schedule_delayed_work(&dsim->dsim_work, dsim->dsim_info->hs_toggle); - } - if (dsim->dsim_toggle_per_frame_count) - dsim->dsim_toggle_per_frame_count--; - } - } - } - break; - } - } - } - /* clear irq */ - writel(intsrc, dsim->reg_base + S5P_DSIM_INTSRC); - return IRQ_HANDLED; -} - -static void s5p_dsim_init_header_fifo(struct dsim_global *dsim) -{ - unsigned int cnt; - - for (cnt = 0; cnt < DSIM_HEADER_FIFO_SZ; cnt++) - dsim->header_fifo_index[cnt] = -1; - return; -} - -static unsigned char s5p_dsim_pll_on(unsigned int dsim_base, unsigned char enable) -{ - if (enable) { - int sw_timeout = 1000; - s5p_dsim_clear_interrupt(dsim_base, DSIM_PLL_STABLE); - s5p_dsim_enable_pll(dsim_base, 1); - while (1) { - sw_timeout--; - if (s5p_dsim_is_pll_stable(dsim_base)) - return DSIM_TRUE; - if (sw_timeout == 0) - return DSIM_FALSE; - } - } else - s5p_dsim_enable_pll(dsim_base, 0); - - return DSIM_TRUE; -} - -static unsigned long s5p_dsim_change_pll(struct dsim_global *dsim, unsigned char pre_divider, - unsigned short main_divider, unsigned char scaler) -{ - unsigned long dfin_pll, dfvco, dpll_out; - unsigned char freq_band; - unsigned char temp0 = 0, temp1 = 0; - unsigned int dsim_base = dsim->reg_base; - - dfin_pll = (MIPI_FIN / pre_divider); - - if (dfin_pll < 6 * 1000 * 1000 || dfin_pll > 12 * 1000 * 1000) { - dev_warn(dsim->dev, "warning!!\n"); - dev_warn(dsim->dev, "fin_pll range is 6MHz ~ 12MHz\n"); - dev_warn(dsim->dev, "fin_pll of mipi dphy pll is %luMHz\n", (dfin_pll / 1000000)); - - s5p_dsim_enable_afc(dsim_base, 0, 0); - } else { - if (dfin_pll < 7 * 1000000) - s5p_dsim_enable_afc(dsim_base, 1, 0x1); - else if (dfin_pll < 8 * 1000000) - s5p_dsim_enable_afc(dsim_base, 1, 0x0); - else if (dfin_pll < 9 * 1000000) - s5p_dsim_enable_afc(dsim_base, 1, 0x3); - else if (dfin_pll < 10 * 1000000) - s5p_dsim_enable_afc(dsim_base, 1, 0x2); - else if (dfin_pll < 11 * 1000000) - s5p_dsim_enable_afc(dsim_base, 1, 0x5); - else - s5p_dsim_enable_afc(dsim_base, 1, 0x4); - } - - dfvco = dfin_pll * main_divider; - dev_dbg(dsim->dev, "dfvco = %lu, dfin_pll = %lu, main_divider = %d\n", - dfvco, dfin_pll, main_divider); - if (dfvco < 500000000 || dfvco > 1000000000) { - dev_warn(dsim->dev, "Caution!!\n"); - dev_warn(dsim->dev, "fvco range is 500MHz ~ 1000MHz\n"); - dev_warn(dsim->dev, "fvco of mipi dphy pll is %luMHz\n", (dfvco / 1000000)); - } - - dpll_out = dfvco / (1 << scaler); - dev_dbg(dsim->dev, "dpll_out = %lu, dfvco = %lu, scaler = %d\n", - dpll_out, dfvco, scaler); - if (dpll_out < 100 * 1000000) - freq_band = 0x0; - else if (dpll_out < 120 * 1000000) - freq_band = 0x1; - else if (dpll_out < 170 * 1000000) - freq_band = 0x2; - else if (dpll_out < 220 * 1000000) - freq_band = 0x3; - else if (dpll_out < 270 * 1000000) - freq_band = 0x4; - else if (dpll_out < 320 * 1000000) - freq_band = 0x5; - else if (dpll_out < 390 * 1000000) - freq_band = 0x6; - else if (dpll_out < 450 * 1000000) - freq_band = 0x7; - else if (dpll_out < 510 * 1000000) - freq_band = 0x8; - else if (dpll_out < 560 * 1000000) - freq_band = 0x9; - else if (dpll_out < 640 * 1000000) - freq_band = 0xa; - else if (dpll_out < 690 * 1000000) - freq_band = 0xb; - else if (dpll_out < 770 * 1000000) - freq_band = 0xc; - else if (dpll_out < 870 * 1000000) - freq_band = 0xd; - else if (dpll_out < 950 * 1000000) - freq_band = 0xe; - else - freq_band = 0xf; - - dev_dbg(dsim->dev, "freq_band = %d\n", freq_band); - - s5p_dsim_pll_freq(dsim_base, pre_divider, main_divider, scaler); - - s5p_dsim_hs_zero_ctrl(dsim_base, temp0); - s5p_dsim_prep_ctrl(dsim_base, temp1); - - /* Freq Band */ - s5p_dsim_pll_freq_band(dsim_base, freq_band); - - /* Stable time */ - s5p_dsim_pll_stable_time(dsim_base, dsim->dsim_info->pll_stable_time); - - /* Enable PLL */ - dev_dbg(dsim->dev, "FOUT of mipi dphy pll is %luMHz\n", (dpll_out / 1000000)); - - return dpll_out; -} - -static void s5p_dsim_set_clock(struct dsim_global *dsim, - unsigned char byte_clk_sel, unsigned char enable) -{ - unsigned int esc_div; - unsigned long esc_clk_error_rate; - unsigned int dsim_base = dsim->reg_base; - - if (enable) { - dsim->e_clk_src = byte_clk_sel; - - /* Escape mode clock and byte clock source */ - s5p_dsim_set_byte_clock_src(dsim_base, byte_clk_sel); - - /* DPHY, DSIM Link : D-PHY clock out */ - if (byte_clk_sel == DSIM_PLL_OUT_DIV8) { - dsim->hs_clk = s5p_dsim_change_pll(dsim, dsim->dsim_info->p, - dsim->dsim_info->m, dsim->dsim_info->s); - dsim->byte_clk = dsim->hs_clk / 8; - s5p_dsim_enable_pll_bypass(dsim_base, 0); - s5p_dsim_pll_on(dsim_base, 1); - usleep_range(1000, 1000); - /* DPHY : D-PHY clock out, DSIM link : external clock out */ - } else if (byte_clk_sel == DSIM_EXT_CLK_DIV8) - dev_warn(dsim->dev, "this project is not supported external clock source for MIPI DSIM\n"); - else if (byte_clk_sel == DSIM_EXT_CLK_BYPASS) - dev_warn(dsim->dev, "this project is not supported external clock source for MIPI DSIM\n"); - - /* escape clock divider */ - esc_div = dsim->byte_clk / (dsim->dsim_info->esc_clk); - dev_dbg(dsim->dev, "esc_div = %d, byte_clk = %lu, esc_clk = %lu\n", - esc_div, dsim->byte_clk, dsim->dsim_info->esc_clk); - if ((dsim->byte_clk / esc_div) >= 20000000 || - (dsim->byte_clk / esc_div) > dsim->dsim_info->esc_clk) - esc_div += 1; - - dsim->escape_clk = dsim->byte_clk / esc_div; - dev_dbg(dsim->dev, "escape_clk = %lu, byte_clk = %lu, esc_div = %d\n", - dsim->escape_clk, dsim->byte_clk, esc_div); - - /* - * enable escclk on lane - */ - s5p_dsim_enable_byte_clock(dsim_base, DSIM_TRUE); - - /* enable byte clk and escape clock */ - s5p_dsim_set_esc_clk_prs(dsim_base, 1, esc_div); - /* escape clock on lane */ - s5p_dsim_enable_esc_clk_on_lane(dsim_base, (DSIM_LANE_CLOCK | dsim->data_lane), 1); - - dev_dbg(dsim->dev, "byte clock is %luMHz\n", (dsim->byte_clk / 1000000)); - dev_dbg(dsim->dev, "escape clock that user's need is %lu\n", (dsim->dsim_info->esc_clk / 1000000)); - dev_dbg(dsim->dev, "escape clock divider is %x\n", esc_div); - dev_dbg(dsim->dev, "escape clock is %luMHz\n", ((dsim->byte_clk / esc_div) / 1000000)); - - if ((dsim->byte_clk / esc_div) > dsim->escape_clk) { - esc_clk_error_rate = dsim->escape_clk / (dsim->byte_clk / esc_div); - dev_warn(dsim->dev, "error rate is %lu over\n", (esc_clk_error_rate / 100)); - } else if ((dsim->byte_clk / esc_div) < (dsim->escape_clk)) { - esc_clk_error_rate = (dsim->byte_clk / esc_div) / dsim->escape_clk; - dev_warn(dsim->dev, "error rate is %lu under\n", (esc_clk_error_rate / 100)); - } - } else { - s5p_dsim_enable_esc_clk_on_lane(dsim_base, (DSIM_LANE_CLOCK | dsim->data_lane), 0); - s5p_dsim_set_esc_clk_prs(dsim_base, 0, 0); - - s5p_dsim_enable_byte_clock(dsim_base, DSIM_FALSE); - - if (byte_clk_sel == DSIM_PLL_OUT_DIV8) - s5p_dsim_pll_on(dsim_base, 0); - } -} - -static int s5p_dsim_late_resume_init_dsim(struct dsim_global *dsim) -{ - unsigned int dsim_base = dsim->reg_base; - - if (dsim->pd->init_d_phy) - dsim->pd->init_d_phy(dsim->reg_base); - - dsim->state = DSIM_STATE_RESET; - - switch (dsim->dsim_info->e_no_data_lane) { - case DSIM_DATA_LANE_1: - dsim->data_lane = DSIM_LANE_DATA0; - break; - case DSIM_DATA_LANE_2: - dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1; - break; - case DSIM_DATA_LANE_3: - dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 | - DSIM_LANE_DATA2; - break; - case DSIM_DATA_LANE_4: - dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 | - DSIM_LANE_DATA2 | DSIM_LANE_DATA3; - break; - default: - dev_info(dsim->dev, "data lane is invalid\n"); - return -1; - }; - - s5p_dsim_init_header_fifo(dsim); - s5p_dsim_sw_reset(dsim_base); - s5p_dsim_dp_dn_swap(dsim_base, dsim->dsim_info->e_lane_swap); - - /* enable only frame done interrupt */ - /* s5p_dsim_clear_interrupt(dsim_base, AllDsimIntr); */ - /* s5p_dsim_set_interrupt_mask(dsim->reg_base, AllDsimIntr, 1); */ - - return 0; -} - -#if 0 -static int s5p_dsim_init_dsim(struct dsim_global *dsim) -{ - unsigned int dsim_base = dsim->reg_base; - - if (dsim->pd->init_d_phy) - dsim->pd->init_d_phy(dsim->reg_base); - - dsim->state = DSIM_STATE_RESET; - - switch (dsim->dsim_info->e_no_data_lane) { - case DSIM_DATA_LANE_1: - dsim->data_lane = DSIM_LANE_DATA0; - break; - case DSIM_DATA_LANE_2: - dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1; - break; - case DSIM_DATA_LANE_3: - dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 | - DSIM_LANE_DATA2; - break; - case DSIM_DATA_LANE_4: - dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 | - DSIM_LANE_DATA2 | DSIM_LANE_DATA3; - break; - default: - dev_info(dsim->dev, "data lane is invalid\n"); - return -1; - }; - - s5p_dsim_init_header_fifo(dsim); - s5p_dsim_dp_dn_swap(dsim_base, dsim->dsim_info->e_lane_swap); - - /* enable only frame done interrupt */ - /* s5p_dsim_clear_interrupt(dsim_base, AllDsimIntr); */ - /* s5p_dsim_set_interrupt_mask(dsim->reg_base, AllDsimIntr, 1); */ - - return 0; -} -#endif - -static void s5p_dsim_set_display_mode(struct dsim_global *dsim, - struct dsim_lcd_config *main_lcd, struct dsim_lcd_config *sub_lcd) -{ - struct s3cfb_lcd *main_lcd_panel_info = NULL, *sub_lcd_panel_info = NULL; - struct s3cfb_lcd_timing *main_timing = NULL; - unsigned int dsim_base = dsim->reg_base; - - if (main_lcd != NULL) { - if (main_lcd->lcd_panel_info != NULL) { - main_lcd_panel_info = - (struct s3cfb_lcd *) main_lcd->lcd_panel_info; - - s5p_dsim_set_main_disp_resol(dsim_base, - main_lcd_panel_info->height, - main_lcd_panel_info->width); - } else - dev_warn(dsim->dev, "lcd panel info of main lcd is NULL\n"); - } else { - dev_err(dsim->dev, "main lcd is NULL\n"); - return; - } - - /* in case of VIDEO MODE (RGB INTERFACE) */ - if (dsim->dsim_lcd_info->e_interface == (u32)DSIM_VIDEO) { - - main_timing = &main_lcd_panel_info->timing; - if (main_timing == NULL) { - dev_err(dsim->dev, "main_timing is NULL\n"); - return; - } - - s5p_dsim_set_main_disp_vporch(dsim_base, - main_timing->cmd_allow_len, - main_timing->stable_vfp, (u16) main_timing->v_bp); - s5p_dsim_set_main_disp_hporch(dsim_base, - main_timing->h_fp, (u16) main_timing->h_bp); - s5p_dsim_set_main_disp_sync_area(dsim_base, - main_timing->v_sw, (u16) main_timing->h_sw); - - /* in case of COMMAND MODE (CPU or I80 INTERFACE) */ - } else { - if (sub_lcd != NULL) { - if (sub_lcd->lcd_panel_info != NULL) { - sub_lcd_panel_info = - (struct s3cfb_lcd *) - sub_lcd->lcd_panel_info; - - s5p_dsim_set_sub_disp_resol(dsim_base, - sub_lcd_panel_info->height, - sub_lcd_panel_info->width); - } else - dev_warn(dsim->dev, "lcd panel info of sub lcd is NULL\n"); - } - } - - s5p_dsim_display_config(dsim_base, dsim->dsim_lcd_info, NULL); -} - -static int s5p_dsim_init_link(struct dsim_global *dsim) -{ - unsigned int time_out = 100; - unsigned int dsim_base = dsim->reg_base; - - switch (dsim->state) { - case DSIM_STATE_RESET: - case DSIM_STATE_INIT: - s5p_dsim_init_fifo_pointer(dsim_base, 0x0); - usleep_range(10000, 10000); - s5p_dsim_init_fifo_pointer(dsim_base, 0x1f); - - /* dsi configuration */ - s5p_dsim_init_config(dsim_base, dsim->dsim_lcd_info, NULL, dsim->dsim_info); - s5p_dsim_enable_lane(dsim_base, DSIM_LANE_CLOCK, 1); - s5p_dsim_enable_lane(dsim_base, dsim->data_lane, 1); - - /* set clock configuration */ - s5p_dsim_set_clock(dsim, dsim->dsim_info->e_byte_clk, 1); - usleep_range(5000, 5000); - /* check clock and data lane state is stop state */ - while (!(s5p_dsim_is_lane_state(dsim_base, DSIM_LANE_CLOCK) == DSIM_LANE_STATE_STOP) && - !(s5p_dsim_is_lane_state(dsim_base, dsim->data_lane) == DSIM_LANE_STATE_STOP)) { - time_out--; - if (time_out == 0) { - dev_info(dsim->dev, "DSI Master state is not stop state!!!\n"); - dev_info(dsim->dev, "Please check initialization process\n"); - - return DSIM_FALSE; - } - } - - if (time_out != 0) { - /* dev_info(dsim->dev, "initialization of DSI Master is successful\n"); */ - /* dev_info(dsim->dev, "DSI Master state is stop state\n"); */ - } - - dsim->state = DSIM_STATE_STOP; - - /* BTA sequence counters */ - s5p_dsim_set_stop_state_counter(dsim_base, dsim->dsim_info->stop_holding_cnt); - s5p_dsim_set_bta_timeout(dsim_base, dsim->dsim_info->bta_timeout); - s5p_dsim_set_lpdr_timeout(dsim_base, dsim->dsim_info->rx_timeout); - - /* default LPDT by both cpu and lcd controller */ - s5p_dsim_set_data_mode(dsim_base, DSIM_TRANSFER_BOTH, DSIM_STATE_STOP); - - return DSIM_TRUE; - default: - dev_info(dsim->dev, "DSI Master is already init\n"); - - return DSIM_FALSE; - } -} - -static unsigned char s5p_dsim_set_hs_enable(struct dsim_global *dsim) -{ - u8 ret = DSIM_FALSE; - unsigned int dsim_base = dsim->reg_base; - - if (dsim->state == DSIM_STATE_STOP) { - if (dsim->e_clk_src != DSIM_EXT_CLK_BYPASS) { - dsim->state = DSIM_STATE_HSCLKEN; -#if defined(CONFIG_FB_S5P_S6E63M0) - s5p_dsim_set_data_mode(dsim_base, - DSIM_TRANSFER_BYLCDC, DSIM_STATE_HSCLKEN); -#else - s5p_dsim_set_data_mode(dsim_base, - DSIM_TRANSFER_BOTH, DSIM_STATE_HSCLKEN); -#endif - s5p_dsim_enable_hs_clock(dsim_base, 1); - - ret = DSIM_TRUE; - } else - dev_warn(dsim->dev, "clock source is external bypass\n"); - } else - dev_warn(dsim->dev, "DSIM is not stop state\n"); - - return ret; -} - -#if 0 -static unsigned char s5p_dsim_set_stopstate(struct dsim_global *dsim) -{ - u8 ret = DSIM_FALSE; - unsigned int dsim_base = dsim->reg_base; - - if (dsim->state == DSIM_STATE_HSCLKEN) { - if (dsim->e_clk_src != DSIM_EXT_CLK_BYPASS) { - dsim->state = DSIM_STATE_STOP; - s5p_dsim_enable_hs_clock(dsim_base, 0); - ret = DSIM_TRUE; - } else - dev_warn(dsim->dev, "clock source is external bypass\n"); - } else if (dsim->state == DSIM_STATE_ULPS) { - /* will be update for exiting ulps */ - ret = DSIM_TRUE; - } else if (dsim->state == DSIM_STATE_STOP) { - dev_warn(dsim->dev, "DSIM is already stop state\n"); - ret = DSIM_TRUE; - } else - dev_warn(dsim->dev, "DSIM is not stop state\n"); - - return ret; -} -#endif - -static unsigned char s5p_dsim_set_data_transfer_mode(struct dsim_global *dsim, - unsigned char data_path, unsigned char hs_enable) -{ - u8 ret = DSIM_FALSE; - unsigned int dsim_base = dsim->reg_base; - - if (hs_enable) { - if (dsim->state == DSIM_STATE_HSCLKEN) { - s5p_dsim_set_data_mode(dsim_base, data_path, DSIM_STATE_HSCLKEN); - ret = DSIM_TRUE; - } else { - dev_err(dsim->dev, "HS Clock lane is not enabled\n"); - ret = DSIM_FALSE; - } - } else { - if (dsim->state == DSIM_STATE_INIT || dsim->state == DSIM_STATE_ULPS) { - dev_err(dsim->dev, "DSI Master is not STOP or HSDT state\n"); - ret = DSIM_FALSE; - } else { - s5p_dsim_set_data_mode(dsim_base, data_path, DSIM_STATE_STOP); - ret = DSIM_TRUE; - } - } - - return ret; -} - -int s5p_dsim_register_lcd_driver(struct mipi_lcd_driver *lcd_drv) -{ - struct mipi_lcd_info *lcd_info = NULL; - struct dsim_global *dsim = g_dsim; - - lcd_info = kmalloc(sizeof(struct mipi_lcd_info), GFP_KERNEL); - if (lcd_info == NULL) - return -ENOMEM; - - lcd_info->mipi_drv = kmalloc(sizeof(struct mipi_lcd_driver), GFP_KERNEL); - if (lcd_info->mipi_drv == NULL) { - kfree(lcd_info); - return -ENOMEM; - } - - memcpy(lcd_info->mipi_drv, lcd_drv, sizeof(struct mipi_lcd_driver)); - - mutex_lock(&mipi_lock); - list_add_tail(&lcd_info->list, &lcd_info_list); - mutex_unlock(&mipi_lock); - - dev_dbg(dsim->dev, "registered lcd panel driver(%s) to mipi-dsi driver\n", lcd_drv->name); - - return 0; -} - -static struct mipi_lcd_driver *scan_mipi_driver(struct dsim_global *dsim, const char *name) -{ - struct mipi_lcd_info *lcd_info; - struct mipi_lcd_driver *mipi_drv = NULL; - - mutex_lock(&mipi_lock); - - dev_dbg(dsim->dev, "find lcd panel driver(%s)\n", name); - - list_for_each_entry(lcd_info, &lcd_info_list, list) { - mipi_drv = lcd_info->mipi_drv; - - if ((strcmp(mipi_drv->name, name)) == 0) { - mutex_unlock(&mipi_lock); - dev_dbg(dsim->dev, "found!!!(%s)\n", mipi_drv->name); - return mipi_drv; - } - } - - dev_warn(dsim->dev, "failed to find lcd panel driver(%s)\n", name); - - mutex_unlock(&mipi_lock); - - return NULL; -} - -static void s5p_dsim_interrupt_mask_set(struct dsim_global *dsim) -{ - u32 int_stat; - - int_stat = readl(dsim->reg_base + S5P_DSIM_INTMSK); - - int_stat &= ~((0x01<<S5P_DSIM_INT_BTA) | (0x01<<S5P_DSIM_INT_RX_TIMEOUT) | - (0x01<<S5P_DSIM_INT_BTA_TIMEOUT) | (0x01 << S5P_DSIM_INT_RX_DONE) | - (0x01<<S5P_DSIM_INT_RX_TE) | (0x01<<S5P_DSIM_INT_RX_ACK) | - (0x01<<S5P_DSIM_INT_RX_ECC_ERR) | (0x01<<S5P_DSIM_IMT_RX_CRC_ERR) | - (0x01<<S5P_DSIM_INT_SFR_FIFO_EMPTY)); - - writel(int_stat, dsim->reg_base + S5P_DSIM_INTMSK); -} - -int s5p_dsim_fifo_clear(void) -{ - int dsim_count = 0, ret; - struct dsim_global *dsim = g_dsim; - - writel(SwRstRelease, dsim->reg_base + S5P_DSIM_INTSRC); - - writel(DSIM_FUNCRST, dsim->reg_base + S5P_DSIM_SWRST); - - do { - if (++dsim_count > 90000) { - dev_err(dsim->dev, "dsim fifo clear fail re_try dsim resume\n"); - ret = 0; - break; - } - - if (readl(dsim->reg_base + S5P_DSIM_INTSRC) & SwRstRelease) { - s5p_dsim_interrupt_mask_set(dsim); - ret = 1; - break; - } - } while (1); - - return ret; -} - -#if defined(CONFIG_S5P_DSIM_SWITCHABLE_DUAL_LCD) -int s5p_dsim_get_panel_sel_value(void) -{ - /*Temporary provided*/ - struct dsim_global *dsim = g_dsim; - unsigned int lcd_sel_pin = dsim->mipi_ddi_pd->lcd_sel_pin; - int sel; - - if (!lcd_sel_pin) { - printk(KERN_ERR "lcd_sel_pin is NULL\n"); - return -EINVAL; - } - sel = gpio_get_value(lcd_sel_pin); - dsim->panel_select = sel; - - return sel; - /*Temporary provided*/ -} - -int s5p_dsim_get_lcd_sel_value(void) -{ - struct dsim_global *dsim = g_dsim; - unsigned int lcd_sel_pin = dsim->mipi_ddi_pd->lcd_sel_pin; - int sel; - - if (!lcd_sel_pin) { - printk(KERN_ERR "lcd_sel_pin is NULL\n"); - return -EINVAL; - } - sel = gpio_get_value(lcd_sel_pin); - dsim->panel_select = sel; - - return sel; -} - -int s5p_dsim_set_lcd_sel_value(unsigned int lcd_sel) -{ - struct dsim_global *dsim = g_dsim; - unsigned int lcd_sel_pin = dsim->mipi_ddi_pd->lcd_sel_pin; - int prev_lcd_sel = s5p_dsim_get_lcd_sel_value(); - - if (!lcd_sel_pin) { - printk(KERN_ERR "lcd_sel_pin is NULL\n"); - return -EINVAL; - } - - gpio_set_value(lcd_sel_pin, lcd_sel); - return prev_lcd_sel; -} - -int s5p_dsim_toggle_lcd(void) -{ - struct dsim_global *dsim = g_dsim; - int prev_lcd_sel = s5p_dsim_get_lcd_sel_value(); - int new_lcd_sel = prev_lcd_sel ^ 1; - - if (prev_lcd_sel < 0) { - printk(KERN_ERR "previous lcd sel value is invalid\n"); - return -EINVAL; - } - - prev_lcd_sel = s5p_dsim_set_lcd_sel_value(new_lcd_sel); - if (dsim->mipi_ddi_pd->resume_complete) { - if (s5p_dsim_fifo_clear() == 0) { - s5p_dsim_early_suspend(); - mdelay(10); - s5p_dsim_late_resume(); - if (s5p_dsim_fifo_clear() == 0) - printk(KERN_ERR "dsim resume fail!!\n"); - } - mdelay(10); - } - return 0; -} - -int s5p_dsim_select_lcd(unsigned int lcd_sel) -{ - struct dsim_global *dsim = g_dsim; - int prev_lcd_sel; - - if ((lcd_sel != DDI_MAIN_LCD) && - (lcd_sel != DDI_SUB_LCD)) { - printk(KERN_ERR "lcd_sel(%d) is invalid value\n", lcd_sel); - return -EINVAL; - } - prev_lcd_sel = s5p_dsim_set_lcd_sel_value(lcd_sel); - if (dsim->mipi_ddi_pd->resume_complete) { - if (s5p_dsim_fifo_clear() == 0) { - s5p_dsim_early_suspend(); - mdelay(10); - s5p_dsim_late_resume(); - if (s5p_dsim_fifo_clear() == 0) - printk(KERN_ERR "dsim resume fail!!\n"); - } - mdelay(10); - } - return 0; -} -#endif /* CONFIG_S5P_DSIM_SWITCHABLE_DUAL_LCD */ - -#ifdef CONFIG_HAS_EARLYSUSPEND -void s5p_dsim_early_suspend(void) -{ - u32 int_stat = 0; - pm_message_t state; - struct dsim_global *dsim = g_dsim; - - dev_info(dsim->dev, "+%s\n", __func__); - - if (dsim->mipi_ddi_pd->resume_complete == 0) - return; - - dsim->mipi_ddi_pd->resume_complete = 0; - dsim->dsim_lcd_info->lcd_enabled = 0; - - /* int_stat = readl(dsim->reg_base + S5P_DSIM_INTMSK); */ - - int_stat |= ((0x01<<S5P_DSIM_INT_BTA) | (0x01<<S5P_DSIM_INT_RX_TIMEOUT) | - (0x01<<S5P_DSIM_INT_BTA_TIMEOUT) | (0x01 << S5P_DSIM_INT_RX_DONE) | - (0x01<<S5P_DSIM_INT_RX_TE) | (0x01<<S5P_DSIM_INT_RX_ACK) | - (0x01<<S5P_DSIM_INT_RX_ECC_ERR) | (0x01<<S5P_DSIM_IMT_RX_CRC_ERR) | - (0x01<<S5P_DSIM_INT_SFR_FIFO_EMPTY) | (0x01 << S5P_DSIM_INT_MSK_FRAME_DONE)); - - writel(int_stat, dsim->reg_base + S5P_DSIM_INTMSK); - - /* disable_irq(dsim->irq); */ - state.event = PM_EVENT_SUSPEND; - - if (dsim->mipi_drv->suspend) - dsim->mipi_drv->suspend(dsim->dev, state); - - if (dsim->mipi_ddi_pd->lcd_power_on) - dsim->mipi_ddi_pd->lcd_power_on(dsim->dev, 0); - - s5p_dsim_enable_hs_clock(dsim->reg_base, 0); - s5p_dsim_set_clock(dsim, dsim->dsim_info->e_byte_clk, 0); - -#if defined(CONFIG_CPU_EXYNOS4210) - writel(0x1, dsim->reg_base + S5P_DSIM_SWRST); -#endif - - if (dsim->pd->exit_d_phy) - dsim->pd->exit_d_phy(dsim->reg_base); - - clk_disable(dsim->clock); - - if (dsim->pd->mipi_power) - dsim->pd->mipi_power(0); - - dev_info(dsim->dev, "-%s\n", __func__); - - return; -} - -void s5p_dsim_late_resume(void) -{ - struct dsim_global *dsim = g_dsim; - - dev_info(dsim->dev, "+%s\n", __func__); - - /* MIPI SIGNAL ON */ - if (dsim->pd->mipi_power) - dsim->pd->mipi_power(1); - - clk_enable(dsim->clock); - usleep_range(10000, 10000); - - if (dsim->mipi_ddi_pd->lcd_power_on) - dsim->mipi_ddi_pd->lcd_power_on(dsim->dev, 1); - usleep_range(25000, 25000); - - if (dsim->mipi_ddi_pd->lcd_reset) - dsim->mipi_ddi_pd->lcd_reset(); - usleep_range(5000, 5000); - - s5p_dsim_late_resume_init_dsim(dsim); - s5p_dsim_init_link(dsim); - usleep_range(10000, 10000); - s5p_dsim_set_hs_enable(dsim); -#if defined(CONFIG_FB_S5P_S6E63M0) - s5p_dsim_set_data_transfer_mode(dsim, DSIM_TRANSFER_BYCPU, 0); -#else - s5p_dsim_set_data_transfer_mode(dsim, DSIM_TRANSFER_BYCPU, 1); -#endif - s5p_dsim_set_display_mode(dsim, dsim->dsim_lcd_info, NULL); - s5p_dsim_set_data_transfer_mode(dsim, DSIM_TRANSFER_BYLCDC, 1); - /* s5p_dsim_set_interrupt_mask(dsim->reg_base, AllDsimIntr, 0); */ - - dsim->mipi_ddi_pd->resume_complete = 1; - - dev_info(dsim->dev, "-%s\n", __func__); - - return; -} - -#else -#ifdef CONFIG_PM -static int s5p_dsim_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct dsim_global *dsim = platform_get_drvdata(pdev); - - dev_info(&pdev->dev, "%s\n", __func__); - - dsim->mipi_ddi_pd->resume_complete = 0; - - if (dsim->mipi_drv->suspend) - dsim->mipi_drv->suspend(&pdev->dev, state); - else - dev_warn(&pdev->dev, "suspend func is null\n"); - - clk_disable(dsim->clock); - - if (dsim->pd->mipi_power) - dsim->pd->mipi_power(0); - else - dev_warn(&pdev->dev, "mipi_power func is null\n"); - - return 0; -} - -static int s5p_dsim_resume(struct platform_device *pdev) -{ - u32 int_stat; - - struct dsim_global *dsim = platform_get_drvdata(pdev); - - dev_info(&pdev->dev, "%s\n", __func__); - - if (dsim->pd->mipi_power) - dsim->pd->mipi_power(1); - else - dev_warn(&pdev->dev, "mipi_power func is null\n"); - - usleep_range(10000, 10000); - - clk_enable(dsim->clock); - - if (dsim->mipi_drv->resume) - dsim->mipi_drv->resume(&pdev->dev); - else - dev_warn(&pdev->dev, "resume func is null\n"); - - s5p_dsim_init_dsim(dsim); - s5p_dsim_init_link(dsim); - - s5p_dsim_set_hs_enable(dsim); - s5p_dsim_set_data_transfer_mode(dsim, DSIM_TRANSFER_BYCPU, 1); - - msleep(120); - - /* initialize lcd panel */ - if (dsim->mipi_drv->init) - dsim->mipi_drv->init(&pdev->dev); - else - dev_warn(&pdev->dev, "init func is null\n"); - - s5p_dsim_set_display_mode(dsim, dsim->dsim_lcd_info, NULL); - - s5p_dsim_set_data_transfer_mode(dsim, DSIM_TRANSFER_BYLCDC, 1); - - int_stat = readl(dsim->reg_base + S5P_DSIM_INTMSK); - - int_stat &= ~((0x01<<S5P_DSIM_INT_BTA) | (0x01<<S5P_DSIM_INT_RX_TIMEOUT) | - (0x01<<S5P_DSIM_INT_BTA_TIMEOUT) | (0x01 << S5P_DSIM_INT_RX_DONE) | - (0x01<<S5P_DSIM_INT_RX_TE) | (0x01<<S5P_DSIM_INT_RX_ACK) | - (0x01<<S5P_DSIM_INT_RX_ECC_ERR) | (0x01<<S5P_DSIM_IMT_RX_CRC_ERR) | - (0x01<<S5P_DSIM_INT_SFR_FIFO_EMPTY)); - - writel(int_stat, dsim->reg_base + S5P_DSIM_INTMSK); - - dsim->mipi_ddi_pd->resume_complete = 1; - - return 0; -} -#else -#define s5p_dsim_suspend NULL -#define s5p_dsim_resume NULL -#endif -#endif - -u32 read_dsim_register(u32 num) -{ - struct dsim_global *dsim = g_dsim; - - return readl(dsim->reg_base + (num*4)); -} - -static ssize_t hs_toggle_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - char temp[3]; - struct dsim_global *dsim = container_of(dev, struct dsim_global, panel); - - sprintf(temp, "%d\n", jiffies_to_msecs(dsim->dsim_info->hs_toggle)); - strcpy(buf, temp); - - return strlen(buf); -} - -static int hs_toggle_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int value; - int rc; - struct dsim_global *dsim = container_of(dev, struct dsim_global, panel); - - rc = strict_strtoul(buf, (unsigned int)0, (unsigned long *)&value); - if (rc < 0) - return rc; - else { - dev_info(dev, "%s - %d, %d\n", __func__, jiffies_to_msecs(dsim->dsim_info->hs_toggle), value); - - if (value == 1) { - dsim->dsim_info->hs_toggle = msecs_to_jiffies(3000); - s5p_dsim_frame_done_interrupt_enable(dsim, 1); - schedule_delayed_work(&dsim->check_hs_toggle_work, msecs_to_jiffies(120000)); - } else { - dsim->dsim_info->hs_toggle = 0; - s5p_dsim_frame_done_interrupt_enable(dsim, 0); - cancel_delayed_work(&dsim->check_hs_toggle_work); - } - } - return size; -} - -static DEVICE_ATTR(hs_toggle, 0644, hs_toggle_show, hs_toggle_store); - -static ssize_t dsim_dump_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int reg_val, i; - char temp[50]; - struct dsim_global *dsim = dev_get_drvdata(dev); - - for (i = 0; i < 25; i++) { - reg_val = readl(dsim->reg_base + i*4); - sprintf(temp, "[DSIM]0x11C8_00%02X = 0x%08X\n", (i*4), reg_val); - strcat(buf, temp); - } - - return strlen(buf); -} -static DEVICE_ATTR(dsim_dump, 0444, dsim_dump_show, NULL); - -static struct dsim_ops s5p_dsim_ops = { - .cmd_write = s5p_dsim_wr_data, - .cmd_read = s5p_dsim_rd_data, - .suspend = s5p_dsim_early_suspend, - .resume = s5p_dsim_late_resume, -}; - -static int s5p_dsim_probe(struct platform_device *pdev) -{ - struct resource *res; - int ret = -1; - u32 int_stat; - struct dsim_global *dsim; - - dsim = kzalloc(sizeof(struct dsim_global), GFP_KERNEL); - if (!dsim) { - pr_err("failed to allocate for dsim_global\n"); - ret = -ENOMEM; - goto err_alloc; - } - - g_dsim = dsim; - - dsim->pd = to_dsim_plat(&pdev->dev); - if (!dsim->pd) { - dev_err(&pdev->dev, "platform data is NULL\n"); - return -EINVAL; - } - - dsim->dev = &pdev->dev; - - /* set dsim config data, dsim lcd config data and lcd panel data. */ - dsim->dsim_info = dsim->pd->dsim_info; - dsim->dsim_lcd_info = dsim->pd->dsim_lcd_info; - dsim->lcd_panel_info = (struct s3cfb_lcd *) dsim->dsim_lcd_info->lcd_panel_info; - dsim->mipi_ddi_pd = (struct mipi_ddi_platform_data *) dsim->dsim_lcd_info->mipi_ddi_pd; - dsim->mipi_ddi_pd->te_irq = dsim->pd->te_irq; - - if (dsim->pd->mipi_power) - dsim->pd->mipi_power(1); - - strcpy(dsim->pd->lcd_panel_name, dsim->lcd_panel_info->name); - - /* clock */ - dsim->clock = clk_get(&pdev->dev, dsim->pd->clk_name); - if (IS_ERR(dsim->clock)) { - dev_err(&pdev->dev, "failed to get dsim clock source\n"); - return -EINVAL; - } - - clk_enable(dsim->clock); - - /* io memory */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get io memory region\n"); - ret = -EINVAL; - goto err_clk_disable; - } - - /* request mem region */ - res = request_mem_region(res->start, - res->end - res->start + 1, pdev->name); - if (!res) { - dev_err(&pdev->dev, "failed to request io memory region\n"); - ret = -EINVAL; - goto err_clk_disable; - } - - /* ioremap for register block */ - dsim->reg_base = (unsigned int)ioremap(res->start, - res->end - res->start + 1); - if (!dsim->reg_base) { - dev_err(&pdev->dev, "failed to remap io region\n"); - ret = -EINVAL; - goto err_clk_disable; - } - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&pdev->dev, "failed to request dsim irq resource\n"); - ret = -EINVAL; - goto err_clk_disable; - } - /* dsim->irq = res->start; */ - - /* clear interrupt */ - /* int_stat = readl(dsim->reg_base + S5P_DSIM_INTSRC); */ - int_stat = 0xffffffff; - writel(int_stat, dsim->reg_base + S5P_DSIM_INTSRC); - - /* enable interrupts */ - int_stat = readl(dsim->reg_base + S5P_DSIM_INTMSK); - - int_stat &= ~((0x01<<S5P_DSIM_INT_BTA) | (0x01<<S5P_DSIM_INT_RX_TIMEOUT) | - (0x01<<S5P_DSIM_INT_BTA_TIMEOUT) | (0x01 << S5P_DSIM_INT_RX_DONE) | - (0x01<<S5P_DSIM_INT_RX_TE) | (0x01<<S5P_DSIM_INT_RX_ACK) | - (0x01<<S5P_DSIM_INT_RX_ECC_ERR) | (0x01<<S5P_DSIM_IMT_RX_CRC_ERR) | - (0x01<<S5P_DSIM_INT_SFR_FIFO_EMPTY)); - - writel(int_stat, dsim->reg_base + S5P_DSIM_INTMSK); - - init_completion(&dsim_rd_comp); - init_completion(&dsim_wr_comp); - mutex_init(&dsim_rd_wr_mutex); - - dsim->mipi_ddi_pd->resume_complete = 1; - dsim->dsim_lcd_info->lcd_enabled = 1; - - ret = request_irq(res->start, (void *)s5p_dsim_isr, IRQF_DISABLED, pdev->name, dsim); - if (ret != 0) { - dev_err(&pdev->dev, "failed to request dsim irq\n"); - ret = -EINVAL; - goto err_clk_disable; - } - - INIT_DELAYED_WORK(&dsim->dsim_work, dsim_work_q_handler); - INIT_DELAYED_WORK(&dsim->check_hs_toggle_work, dsim_check_hs_toggle_work_q_handler); - - dsim->ops = &s5p_dsim_ops; - - platform_set_drvdata(pdev, dsim); - - dsim->panel.parent = &pdev->dev; - dev_set_name(&dsim->panel, dsim->pd->lcd_panel_name); - ret = device_register(&dsim->panel); - if (ret < 0) { - dev_err(&pdev->dev, "faild device register\n"); - ret = -EINVAL; - goto mipi_drv_err; - } - - /* find lcd panel driver registered to mipi-dsi driver. */ - dsim->mipi_drv = scan_mipi_driver(dsim, dsim->pd->lcd_panel_name); - if (dsim->mipi_drv == NULL) { - dev_err(&pdev->dev, "mipi_drv is NULL\n"); - ret = -EINVAL; - goto mipi_drv_err; - } - - ret = dsim->mipi_drv->probe(&dsim->panel); - if (ret < 0) { - dev_err(&pdev->dev, "faild probe\n"); - ret = -EINVAL; - goto mipi_drv_err; - } - - dsim->state = DSIM_STATE_HSCLKEN; - - ret = device_create_file(&(pdev->dev), &dev_attr_dsim_dump); - if (ret < 0) - dev_err(&pdev->dev, "failed to add sysfs entries, %d\n", __LINE__); - - if (!dsim->dsim_info->hs_toggle) { - ret = device_create_file(&dsim->panel, &dev_attr_hs_toggle); - if (ret < 0) - dev_err(&pdev->dev, "failed to add sysfs entries, %d\n", __LINE__); - } - - if (dsim->dsim_info->hs_toggle) - s5p_dsim_frame_done_interrupt_enable(dsim, 1); - - dev_info(&pdev->dev, "mipi-dsi driver has been probed\n"); - -#if 0 -#ifdef CONFIG_HAS_WAKELOCK -#ifdef CONFIG_HAS_EARLYSUSPEND - dsim->early_suspend.suspend = s5p_dsim_early_suspend; - dsim->early_suspend.resume = s5p_dsim_late_resume; - dsim->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1; - register_early_suspend(&dsim->early_suspend); -#endif -#endif -#endif - return 0; - -mipi_drv_err: - free_irq(res->start, &dsim); - dsim->pd->mipi_power(0); - -err_clk_disable: - clk_disable(dsim->clock); -err_alloc: - return ret; -} - -static int s5p_dsim_remove(struct platform_device *pdev) -{ - return 0; -} - -static struct platform_driver s5p_dsim_driver = { - .probe = s5p_dsim_probe, - .remove = s5p_dsim_remove, -#ifndef CONFIG_HAS_EARLYSUSPEND - .suspend = s5p_dsim_suspend, - .resume = s5p_dsim_resume, -#endif - .driver = { - .name = "s5p-dsim", - .owner = THIS_MODULE, - }, -}; - -static int s5p_dsim_register(void) -{ - return platform_driver_register(&s5p_dsim_driver); -} - -static void s5p_dsim_unregister(void) -{ - platform_driver_unregister(&s5p_dsim_driver); -} - -module_init(s5p_dsim_register); -module_exit(s5p_dsim_unregister); - -MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>"); -MODULE_DESCRIPTION("Samusung MIPI-DSIM driver"); -MODULE_LICENSE("GPL"); |