From mboxrd@z Thu Jan 1 00:00:00 1970 From: kmpark@infradead.org (Kyungmin Park) Date: Fri, 15 Apr 2011 09:22:57 +0900 Subject: [PATCH 1/2] video: add Samsung SoC MIPI-DSI controller driver. In-Reply-To: <1302783320-31230-1-git-send-email-inki.dae@samsung.com> References: <1302783320-31230-1-git-send-email-inki.dae@samsung.com> Message-ID: To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Mr. Dae, If only MIPI header files are used at video, just place it under video directory. regardless this issue, how about the make a generic mipi dsi interface at video? then other soc will be helpful also. e.g., one generic MIPI DSI framework and each SoCs register the operations or override the functions or better way. No need to think/consider the samsung SOCs only. Thank you, Kyungmin Park On Thu, Apr 14, 2011 at 9:15 PM, Inki Dae wrote: > Samsung S5PV210 and EXYNOS4 SoC platform have one or two MIPI-DSI controller. > MIPI-DSI based LCD Panel could be used with MIPI-DSI controller driver. > this patch adds the MIPI-DSI controller driver and also this driver would > support both platforms. > > to use MIPI-DSI based LCD Panel driver, mipi_dsim_lcd_device should be > registered to MIPI-DSI Driver through s5p_mipi_dsi_register_lcd_device() call > in machine code or machine specific somewhere first, and mipi_dsim_lcd_driver > should be registered when s5p_mipi_dsi_register_lcd_driver() is called at init > function of lcd driver, and then probe() of that driver would be called by > MIPI-DSI controller driver if lcd panel name and id of mipi_dsim_lcd_device > are same as ones of mipi_dsim_lcd_driver. > > for this, you can refer to sample lcd panel driver. > please see "Documentation/s5p_mipi_dsim/dsim_sample_lcd.c" > > Signed-off-by: Inki Dae > Signed-off-by: Kyungmin Park > --- > ?arch/arm/plat-s5p/include/plat/mipi_dsim.h | ?345 +++++++++++++++ > ?arch/arm/plat-s5p/include/plat/regs-dsim.h | ?143 ++++++ > ?drivers/video/Kconfig ? ? ? ? ? ? ? ? ? ? ?| ? ?7 + > ?drivers/video/Makefile ? ? ? ? ? ? ? ? ? ? | ? ?2 + > ?drivers/video/s5p_mipi_dsi.c ? ? ? ? ? ? ? | ?481 ++++++++++++++++++++ > ?drivers/video/s5p_mipi_dsi_common.c ? ? ? ?| ?655 ++++++++++++++++++++++++++++ > ?drivers/video/s5p_mipi_dsi_common.h ? ? ? ?| ? 39 ++ > ?drivers/video/s5p_mipi_dsi_lowlevel.c ? ? ?| ?558 +++++++++++++++++++++++ > ?drivers/video/s5p_mipi_dsi_lowlevel.h ? ? ?| ?100 +++++ > ?9 files changed, 2330 insertions(+), 0 deletions(-) > ?create mode 100644 arch/arm/plat-s5p/include/plat/mipi_dsim.h > ?create mode 100644 arch/arm/plat-s5p/include/plat/regs-dsim.h > ?create mode 100644 drivers/video/s5p_mipi_dsi.c > ?create mode 100644 drivers/video/s5p_mipi_dsi_common.c > ?create mode 100644 drivers/video/s5p_mipi_dsi_common.h > ?create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.c > ?create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.h > > diff --git a/arch/arm/plat-s5p/include/plat/mipi_dsim.h b/arch/arm/plat-s5p/include/plat/mipi_dsim.h > new file mode 100644 > index 0000000..0fa2d7e > --- /dev/null > +++ b/arch/arm/plat-s5p/include/plat/mipi_dsim.h > @@ -0,0 +1,345 @@ > +/* linux/arm/arch/plat-s5p/include/plat/mipi_dsim.h > + * > + * Platform data header for Samsung SoC MIPI-DSIM. > + * > + * Copyright (c) 2011 Samsung Electronics Co., Ltd > + * > + * InKi Dae > + * > + * 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. > +*/ > + > +#ifndef _DSIM_H > +#define _DSIM_H > + > +#include > +#include > + > +#define PANEL_NAME_SIZE ? ? ? ? ? ? ? ?(32) > + > +enum mipi_dsim_interface_type { > + ? ? ? DSIM_COMMAND, > + ? ? ? DSIM_VIDEO > +}; > + > +enum mipi_dsim_virtual_ch_no { > + ? ? ? DSIM_VIRTUAL_CH_0, > + ? ? ? DSIM_VIRTUAL_CH_1, > + ? ? ? DSIM_VIRTUAL_CH_2, > + ? ? ? DSIM_VIRTUAL_CH_3 > +}; > + > +enum mipi_dsim_burst_mode_type { > + ? ? ? DSIM_NON_BURST_SYNC_EVENT, > + ? ? ? DSIM_NON_BURST_SYNC_PULSE = 2, > + ? ? ? DSIM_BURST, > + ? ? ? DSIM_NON_VIDEO_MODE > +}; > + > +enum mipi_dsim_no_of_data_lane { > + ? ? ? DSIM_DATA_LANE_1, > + ? ? ? DSIM_DATA_LANE_2, > + ? ? ? DSIM_DATA_LANE_3, > + ? ? ? DSIM_DATA_LANE_4 > +}; > + > +enum mipi_dsim_byte_clk_src { > + ? ? ? DSIM_PLL_OUT_DIV8, > + ? ? ? DSIM_EXT_CLK_DIV8, > + ? ? ? DSIM_EXT_CLK_BYPASS > +}; > + > +enum mipi_dsim_pixel_format { > + ? ? ? DSIM_CMD_3BPP, > + ? ? ? DSIM_CMD_8BPP, > + ? ? ? DSIM_CMD_12BPP, > + ? ? ? DSIM_CMD_16BPP, > + ? ? ? DSIM_VID_16BPP_565, > + ? ? ? DSIM_VID_18BPP_666PACKED, > + ? ? ? DSIM_18BPP_666LOOSELYPACKED, > + ? ? ? DSIM_24BPP_888 > +}; > + > +/** > + * struct mipi_dsim_config - interface for configuring mipi-dsi controller. > + * > + * @auto_flush: enable or disable Auto flush of MD FIFO using VSYNC pulse. > + * @eot_disable: enable or disable EoT packet in HS mode. > + * @auto_vertical_cnt: specifies auto vertical count mode. > + * ? ? in Video mode, the vertical line transition uses line counter > + * ? ? configured by VSA, VBP, and Vertical resolution. > + * ? ? If this bit is set to '1', the line counter does not use VSA and VBP > + * ? ? registers.(in command mode, this variable is ignored) > + * @hse: set horizontal sync event mode. > + * ? ? In VSYNC pulse and Vporch area, MIPI DSI master transfers only HSYNC > + * ? ? start packet to MIPI DSI slave at MIPI DSI spec1.1r02. > + * ? ? this bit transfers HSYNC end packet in VSYNC pulse and Vporch area > + * ? ? (in mommand mode, this variable is ignored) > + * @hfp: specifies HFP disable mode. > + * ? ? if this variable is set, DSI master ignores HFP area in VIDEO mode. > + * ? ? (in command mode, this variable is ignored) > + * @hbp: specifies HBP disable mode. > + * ? ? if this variable is set, DSI master ignores HBP area in VIDEO mode. > + * ? ? (in command mode, this variable is ignored) > + * @hsa: specifies HSA disable mode. > + * ? ? if this variable is set, DSI master ignores HSA area in VIDEO mode. > + * ? ? (in command mode, this variable is ignored) > + * @e_interface: specifies interface to be used.(CPU or RGB interface) > + * @e_virtual_ch: specifies virtual channel number that main or > + * ? ? sub diaplsy uses. > + * @e_pixel_format: specifies pixel stream format for main or sub display. > + * @e_burst_mode: selects Burst mode in Video mode. > + * ? ? in Non-burst mode, RGB data area is filled with RGB data and NULL > + * ? ? packets, according to input bandwidth of RGB interface. > + * ? ? In Burst mode, RGB data area is filled with RGB data only. > + * @e_no_data_lane: specifies data lane count to be used by Master. > + * @e_byte_clk: select byte clock source. (it must be DSIM_PLL_OUT_DIV8) > + * ? ? DSIM_EXT_CLK_DIV8 and DSIM_EXT_CLK_BYPASSS are not supported. > + * @pll_stable_time: specifies the PLL Timer for stability of the ganerated > + * ? ? clock(System clock cycle base) > + * ? ? if the timer value goes to 0x00000000, the clock stable bit of status > + * ? ? and interrupt register is set. > + * @esc_clk: specifies escape clock frequency for getting the escape clock > + * ? ? prescaler value. > + * @stop_holding_cnt: specifies the interval value between transmitting > + * ? ? read packet(or write "set_tear_on" command) and BTA request. > + * ? ? after transmitting read packet or write "set_tear_on" command, > + * ? ? BTA requests to D-PHY automatically. this counter value specifies > + * ? ? the interval between them. > + * @bta_timeout: specifies the timer for BTA. > + * ? ? this register specifies time out from BTA request to change > + * ? ? the direction with respect to Tx escape clock. > + * @rx_timeout: specifies the timer for LP Rx mode timeout. > + * ? ? this register specifies time out on how long RxValid deasserts, > + * ? ? after RxLpdt asserts with respect to Tx escape clock. > + * ? ? - RxValid specifies Rx data valid indicator. > + * ? ? - RxLpdt specifies an indicator that D-PHY is under RxLpdt mode. > + * ? ? - RxValid and RxLpdt specifies signal from D-PHY. > + */ > +struct mipi_dsim_config { > + ? ? ? unsigned char ? ? ? ? ? ? ? ? ? auto_flush; > + ? ? ? unsigned char ? ? ? ? ? ? ? ? ? eot_disable; > + > + ? ? ? unsigned char ? ? ? ? ? ? ? ? ? auto_vertical_cnt; > + ? ? ? unsigned char ? ? ? ? ? ? ? ? ? hse; > + ? ? ? unsigned char ? ? ? ? ? ? ? ? ? hfp; > + ? ? ? unsigned char ? ? ? ? ? ? ? ? ? hbp; > + ? ? ? unsigned char ? ? ? ? ? ? ? ? ? hsa; > + > + ? ? ? enum mipi_dsim_interface_type ? e_interface; > + ? ? ? enum mipi_dsim_virtual_ch_no ? ?e_virtual_ch; > + ? ? ? enum mipi_dsim_pixel_format ? ? e_pixel_format; > + ? ? ? enum mipi_dsim_burst_mode_type ?e_burst_mode; > + ? ? ? enum mipi_dsim_no_of_data_lane ?e_no_data_lane; > + ? ? ? enum mipi_dsim_byte_clk_src ? ? e_byte_clk; > + > + ? ? ? /* > + ? ? ? ?* =========================================== > + ? ? ? ?* | ? ?P ? ?| ? ?M ? ?| ? ?S ? ?| ? ?MHz ? ?| > + ? ? ? ?* ------------------------------------------- > + ? ? ? ?* | ? ?3 ? ?| ? 100 ? | ? ?3 ? ?| ? ?100 ? ?| > + ? ? ? ?* | ? ?3 ? ?| ? 100 ? | ? ?2 ? ?| ? ?200 ? ?| > + ? ? ? ?* | ? ?3 ? ?| ? ?63 ? | ? ?1 ? ?| ? ?252 ? ?| > + ? ? ? ?* | ? ?4 ? ?| ? 100 ? | ? ?1 ? ?| ? ?300 ? ?| > + ? ? ? ?* | ? ?4 ? ?| ? 110 ? | ? ?1 ? ?| ? ?330 ? ?| > + ? ? ? ?* | ? 12 ? ?| ? 350 ? | ? ?1 ? ?| ? ?350 ? ?| > + ? ? ? ?* | ? ?3 ? ?| ? 100 ? | ? ?1 ? ?| ? ?400 ? ?| > + ? ? ? ?* | ? ?4 ? ?| ? 150 ? | ? ?1 ? ?| ? ?450 ? ?| > + ? ? ? ?* | ? ?3 ? ?| ? 118 ? | ? ?1 ? ?| ? ?472 ? ?| > + ? ? ? ?* | ? 12 ? ?| ? 250 ? | ? ?0 ? ?| ? ?500 ? ?| > + ? ? ? ?* | ? ?4 ? ?| ? 100 ? | ? ?0 ? ?| ? ?600 ? ?| > + ? ? ? ?* | ? ?3 ? ?| ? ?81 ? | ? ?0 ? ?| ? ?648 ? ?| > + ? ? ? ?* | ? ?3 ? ?| ? ?88 ? | ? ?0 ? ?| ? ?704 ? ?| > + ? ? ? ?* | ? ?3 ? ?| ? ?90 ? | ? ?0 ? ?| ? ?720 ? ?| > + ? ? ? ?* | ? ?3 ? ?| ? 100 ? | ? ?0 ? ?| ? ?800 ? ?| > + ? ? ? ?* | ? 12 ? ?| ? 425 ? | ? ?0 ? ?| ? ?850 ? ?| > + ? ? ? ?* | ? ?4 ? ?| ? 150 ? | ? ?0 ? ?| ? ?900 ? ?| > + ? ? ? ?* | ? 12 ? ?| ? 475 ? | ? ?0 ? ?| ? ?950 ? ?| > + ? ? ? ?* | ? ?6 ? ?| ? 250 ? | ? ?0 ? ?| ? 1000 ? ?| > + ? ? ? ?* ------------------------------------------- > + ? ? ? ?*/ > + ? ? ? unsigned char ? ? ? ? ? ? ? ? ? p; > + ? ? ? unsigned short ? ? ? ? ? ? ? ? ?m; > + ? ? ? unsigned char ? ? ? ? ? ? ? ? ? s; > + > + ? ? ? unsigned int ? ? ? ? ? ? ? ? ? ?pll_stable_time; > + ? ? ? unsigned long ? ? ? ? ? ? ? ? ? esc_clk; > + > + ? ? ? unsigned short ? ? ? ? ? ? ? ? ?stop_holding_cnt; > + ? ? ? unsigned char ? ? ? ? ? ? ? ? ? bta_timeout; > + ? ? ? unsigned short ? ? ? ? ? ? ? ? ?rx_timeout; > +}; > + > +/** > + * struct mipi_dsim_device - global interface for mipi-dsi driver. > + * > + * @dev: driver model representation of the device. > + * @id: unique device id. > + * @clock: pointer to MIPI-DSI clock of clock framework. > + * @irq: interrupt number to MIPI-DSI controller. > + * @reg_base: base address to memory mapped SRF of MIPI-DSI controller. > + * ? ? (virtual address) > + * @lock: the mutex protecting this data structure. > + * @dsim_info: infomation for configuring mipi-dsi controller. > + * @master_ops: callbacks to mipi-dsi operations. > + * @dsim_lcd_dev: pointer to activated ddi device. > + * ? ? (it would be registered by mipi-dsi driver.) > + * @dsim_lcd_drv: pointer to activated_ddi driver. > + * ? ? (it would be registered by mipi-dsi driver.) > + * @lcd_info: pointer to mipi_lcd_info structure. > + * @state: specifies status of MIPI-DSI controller. > + * ? ? the status could be RESET, INIT, STOP, HSCLKEN and ULPS. > + * @resume_complete: indicates whether resume operation is completed or not. > + * @data_lane: specifiec enabled data lane number. > + * ? ? this variable would be set by driver according to e_no_data_lane > + * ? ? automatically. > + * @e_clk_src: select byte clock source. > + * @pd: pointer to MIPI-DSI driver platform data. > + */ > +struct mipi_dsim_device { > + ? ? ? struct device ? ? ? ? ? ? ? ? ? *dev; > + ? ? ? int ? ? ? ? ? ? ? ? ? ? ? ? ? ? id; > + ? ? ? struct resource ? ? ? ? ? ? ? ? *res; > + ? ? ? struct clk ? ? ? ? ? ? ? ? ? ? ?*clock; > + ? ? ? unsigned int ? ? ? ? ? ? ? ? ? ?irq; > + ? ? ? void __iomem ? ? ? ? ? ? ? ? ? ?*reg_base; > + ? ? ? struct mutex ? ? ? ? ? ? ? ? ? ?lock; > + > + ? ? ? struct mipi_dsim_config ? ? ? ? *dsim_config; > + ? ? ? struct mipi_dsim_master_ops ? ? *master_ops; > + ? ? ? struct mipi_dsim_lcd_device ? ? *dsim_lcd_dev; > + ? ? ? struct mipi_dsim_lcd_driver ? ? *dsim_lcd_drv; > + > + ? ? ? unsigned int ? ? ? ? ? ? ? ? ? ?state; > + ? ? ? unsigned int ? ? ? ? ? ? ? ? ? ?resume_complete; > + ? ? ? unsigned int ? ? ? ? ? ? ? ? ? ?data_lane; > + ? ? ? enum mipi_dsim_byte_clk_src ? ? e_clk_src; > + > + ? ? ? struct s5p_platform_mipi_dsim ? *pd; > +}; > + > +/** > + * struct s5p_platform_mipi_dsim - interface to platform data > + * ? ? for mipi-dsi driver. > + * > + * @lcd_panel_name: specifies lcd panel name registered to mipi-dsi driver. > + * ? ? lcd panel driver searched would be actived. > + * @dsim_config: pointer of structure for configuring mipi-dsi controller. > + * @lcd_panel_info: pointer for lcd panel specific structure. > + * ? ? this structure specifies width, height, timing and polarity and so on. > + * @mipi_power: callback pointer for enabling or disabling mipi power. > + * @phy_enable: pointer to a callback controlling D-PHY enable/reset > + */ > +struct s5p_platform_mipi_dsim { > + ? ? ? char ? ? ? ? ? ? ? ? ? ? ? ? ? ?lcd_panel_name[PANEL_NAME_SIZE]; > + > + ? ? ? struct mipi_dsim_config ? ? ? ? *dsim_config; > + ? ? ? void ? ? ? ? ? ? ? ? ? ? ? ? ? ?*lcd_panel_info; > + > + ? ? ? int (*mipi_power)(struct platform_device *pdev, unsigned int enable); > + ? ? ? int (*phy_enable)(struct platform_device *pdev, bool on); > +}; > +/** > + * struct mipi_dsim_master_ops - callbacks to mipi-dsi operations. > + * > + * @cmd_write: transfer command to lcd panel at LP mode. > + * @cmd_read: read command from rx register. > + * @get_dsim_frame_done: get the status that all screen data have been > + * ? ? transferred to mipi-dsi. > + * @clear_dsim_frame_done: clear frame done status. > + * @get_fb_frame_done: get frame done status of display controller. > + * @trigger: trigger display controller. > + * ? ? - this one would be used only in case of CPU mode. > + */ > + > +struct mipi_dsim_master_ops { > + ? ? ? int (*cmd_write)(struct mipi_dsim_device *dsim, unsigned int data_id, > + ? ? ? ? ? ? ? unsigned int data0, unsigned int data1); > + ? ? ? int (*cmd_read)(struct mipi_dsim_device *dsim, unsigned int data_id, > + ? ? ? ? ? ? ? unsigned int data0, unsigned int data1); > + ? ? ? int (*get_dsim_frame_done)(struct mipi_dsim_device *dsim); > + ? ? ? int (*clear_dsim_frame_done)(struct mipi_dsim_device *dsim); > + > + ? ? ? int (*get_fb_frame_done)(struct fb_info *info); > + ? ? ? void (*trigger)(struct fb_info *info); > +}; > + > +/** > + * device structure for mipi-dsi based lcd panel. > + * > + * @name: name of the device to use with this device, or an > + * ? ? alias for that name. > + * @dev: driver model representation of the device. > + * @id: id of device to be registered. > + * @bus_id: bus id for identifing connected bus > + * ? ? and this bus id should be same as id of mipi_dsim_device. > + * @irq: irq number for signaling when framebuffer transfer of > + * ? ? lcd panel module is completed. > + * ? ? this irq would be used only for MIPI-DSI based CPU mode lcd panel. > + * @master: pointer to mipi-dsi master device object. > + * @platform_data: lcd panel specific platform data. > + */ > +struct mipi_dsim_lcd_device { > + ? ? ? char ? ? ? ? ? ? ? ? ? ?*name; > + ? ? ? struct device ? ? ? ? ? dev; > + ? ? ? int ? ? ? ? ? ? ? ? ? ? id; > + ? ? ? int ? ? ? ? ? ? ? ? ? ? bus_id; > + ? ? ? int ? ? ? ? ? ? ? ? ? ? irq; > + > + ? ? ? struct mipi_dsim_device *master; > + ? ? ? void ? ? ? ? ? ? ? ? ? ?*platform_data; > +}; > + > +/** > + * driver structure for mipi-dsi based lcd panel. > + * > + * this structure should be registered by lcd panel driver. > + * mipi-dsi driver seeks lcd panel registered through name field > + * and calls these callback functions in appropriate time. > + * > + * @name: name of the driver to use with this device, or an > + * ? ? alias for that name. > + * @id: id of driver to be registered. > + * ? ? this id would be used for finding device object registered. > + */ > +struct mipi_dsim_lcd_driver { > + ? ? ? char ? ? ? ? ? ? ? ? ? ?*name; > + ? ? ? int ? ? ? ? ? ? ? ? ? ? id; > + > + ? ? ? int ? ? (*probe)(struct mipi_dsim_lcd_device *dsim_dev); > + ? ? ? int ? ? (*remove)(struct mipi_dsim_lcd_device *dsim_dev); > + ? ? ? void ? ?(*shutdown)(struct mipi_dsim_lcd_device *dsim_dev); > + ? ? ? int ? ? (*suspend)(struct mipi_dsim_lcd_device *dsim_dev); > + ? ? ? int ? ? (*resume)(struct mipi_dsim_lcd_device *dsim_dev); > +}; > + > +/** > + * register mipi_dsim_lcd_driver object defined by lcd panel driver > + * to mipi-dsi driver. > + */ > +int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *lcd_drv); > + > +/** > + * register mipi_dsim_lcd_device to mipi-dsi master. > + */ > +int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *lcd_dev); > + > +/** > + * enable regulators to MIPI-DSI power. > + */ > +int s5p_mipi_dsi_dphy_power(struct mipi_dsim_device *dsim, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned int enable); > + > +/** > + * s5p_dsim_phy_enable - global MIPI-DSI receiver D-PHY control > + * @pdev: MIPI-DSIM platform device > + * @on: true to enable D-PHY and deassert its reset > + * ? ? false to disable D-PHY > + */ > +int s5p_dsim_phy_enable(struct platform_device *pdev, bool on); > + > +#endif /* _DSIM_H */ > diff --git a/arch/arm/plat-s5p/include/plat/regs-dsim.h b/arch/arm/plat-s5p/include/plat/regs-dsim.h > new file mode 100644 > index 0000000..5f0e4fa > --- /dev/null > +++ b/arch/arm/plat-s5p/include/plat/regs-dsim.h > @@ -0,0 +1,143 @@ > +/* linux/arch/arm/plat-s5p/include/plat/regs-dsim.h > + * > + * Register definition file for Samsung MIPI-DSIM driver > + * > + * Copyright (c) 2011 Samsung Electronics Co., Ltd > + * > + * InKi Dae > + * > + * 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. > +*/ > + > +#ifndef _REGS_DSIM_H > +#define _REGS_DSIM_H > + > +#define S5P_DSIM_STATUS ? ? ? ? ? ? ? ?(0x0) ? /* Status register */ > +#define S5P_DSIM_SWRST ? ? ? ? (0x4) ? /* Software reset register */ > +#define S5P_DSIM_CLKCTRL ? ? ? (0x8) ? /* Clock control register */ > +#define S5P_DSIM_TIMEOUT ? ? ? (0xc) ? /* Time out register */ > +#define S5P_DSIM_CONFIG ? ? ? ? ? ? ? ?(0x10) ?/* Configuration register */ > +#define S5P_DSIM_ESCMODE ? ? ? (0x14) ?/* Escape mode register */ > + > +/* Main display image resolution register */ > +#define S5P_DSIM_MDRESOL ? ? ? (0x18) > +#define S5P_DSIM_MVPORCH ? ? ? (0x1c) ?/* Main display Vporch register */ > +#define S5P_DSIM_MHPORCH ? ? ? (0x20) ?/* Main display Hporch register */ > +#define S5P_DSIM_MSYNC ? ? ? ? (0x24) ?/* Main display sync area register */ > + > +/* Sub display image resolution register */ > +#define S5P_DSIM_SDRESOL ? ? ? (0x28) > +#define S5P_DSIM_INTSRC ? ? ? ? ? ? ? ?(0x2c) ?/* Interrupt source register */ > +#define S5P_DSIM_INTMSK ? ? ? ? ? ? ? ?(0x30) ?/* Interrupt mask register */ > +#define S5P_DSIM_PKTHDR ? ? ? ? ? ? ? ?(0x34) ?/* Packet Header FIFO register */ > +#define S5P_DSIM_PAYLOAD ? ? ? (0x38) ?/* Payload FIFO register */ > +#define S5P_DSIM_RXFIFO ? ? ? ? ? ? ? ?(0x3c) ?/* Read FIFO register */ > +#define S5P_DSIM_FIFOTHLD ? ? ?(0x40) ?/* FIFO threshold level register */ > +#define S5P_DSIM_FIFOCTRL ? ? ?(0x44) ?/* FIFO status and control register */ > + > +/* FIFO memory AC characteristic register */ > +#define S5P_DSIM_PLLCTRL ? ? ? (0x4c) ?/* PLL control register */ > +#define S5P_DSIM_PLLTMR ? ? ? ? ? ? ? ?(0x50) ?/* PLL timer register */ > +#define S5P_DSIM_PHYACCHR ? ? ?(0x54) ?/* D-PHY AC characteristic register */ > +#define S5P_DSIM_PHYACCHR1 ? ? (0x58) ?/* D-PHY AC characteristic register1 */ > + > +/* DSIM_STATUS */ > +#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) > +#define DSIM_STOP_STATE_CLK ? ?(1 << 8) > +#define DSIM_TX_READY_HS_CLK ? (1 << 10) > + > +/* DSIM_SWRST */ > +#define DSIM_FUNCRST ? ? ? ? ? (1 << 16) > +#define DSIM_SWRST ? ? ? ? ? ? (1 << 0) > + > +/* S5P_DSIM_TIMEOUT */ > +#define DSIM_LPDR_TOUT_SHIFT ? (0) > +#define DSIM_BTA_TOUT_SHIFT ? ?(16) > + > +/* S5P_DSIM_CLKCTRL */ > +#define DSIM_LANE_ESC_CLKEN_SHIFT ? ? ?(19) > +#define DSIM_BYTE_CLKEN_SHIFT ? ? ? ? ?(24) > +#define DSIM_BYTE_CLK_SRC_SHIFT ? ? ? ? ? ? ? ?(25) > +#define DSIM_PLL_BYPASS_SHIFT ? ? ? ? ?(27) > +#define DSIM_ESC_CLKEN_SHIFT ? ? ? ? ? (28) > +#define DSIM_TX_REQUEST_HSCLK_SHIFT ? ?(31) > +#define DSIM_LANE_ESC_CLKEN(x) ? ? ? ? (((x) & 0x1f) << \ > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DSIM_LANE_ESC_CLKEN_SHIFT) > +#define DSIM_BYTE_CLK_ENABLE ? ? ? ? ? (1 << DSIM_BYTE_CLKEN_SHIFT) > +#define DSIM_BYTE_CLK_DISABLE ? ? ? ? ?(0 << DSIM_BYTE_CLKEN_SHIFT) > +#define DSIM_PLL_BYPASS_EXTERNAL ? ? ? (1 << DSIM_PLL_BYPASS_SHIFT) > +#define DSIM_ESC_CLKEN_ENABLE ? ? ? ? ?(1 << DSIM_ESC_CLKEN_SHIFT) > +#define DSIM_ESC_CLKEN_DISABLE ? ? ? ? (0 << DSIM_ESC_CLKEN_SHIFT) > + > +/* S5P_DSIM_CONFIG */ > +#define DSIM_NUM_OF_DATALANE_SHIFT ? ? (5) > +#define DSIM_HSA_MODE_SHIFT ? ? ? ? ? ?(20) > +#define DSIM_HBP_MODE_SHIFT ? ? ? ? ? ?(21) > +#define DSIM_HFP_MODE_SHIFT ? ? ? ? ? ?(22) > +#define DSIM_HSE_MODE_SHIFT ? ? ? ? ? ?(23) > +#define DSIM_AUTO_MODE_SHIFT ? ? ? ? ? (24) > +#define DSIM_LANE_ENx(x) ? ? ? ? ? ? ? (((x) & 0x1f) << 0) > + > +#define DSIM_NUM_OF_DATA_LANE(x) ? ? ? ((x) << DSIM_NUM_OF_DATALANE_SHIFT) > + > +/* S5P_DSIM_ESCMODE */ > +#define DSIM_TX_LPDT_SHIFT ? ? ? ? ? ? (6) > +#define DSIM_CMD_LPDT_SHIFT ? ? ? ? ? ?(7) > +#define DSIM_TX_LPDT_LP ? ? ? ? ? ? ? ? ? ? ? ?(1 << DSIM_TX_LPDT_SHIFT) > +#define DSIM_CMD_LPDT_LP ? ? ? ? ? ? ? (1 << DSIM_CMD_LPDT_SHIFT) > +#define DSIM_STOP_STATE_CNT_SHIFT ? ? ?(21) > +#define DSIM_FORCE_STOP_STATE_SHIFT ? ?(20) > + > +/* S5P_DSIM_MDRESOL */ > +#define DSIM_MAIN_STAND_BY ? ? ? ? ? ? (1 << 31) > +#define DSIM_MAIN_VRESOL(x) ? ? ? ? ? ?(((x) & 0x7ff) << 16) > +#define DSIM_MAIN_HRESOL(x) ? ? ? ? ? ?(((x) & 0X7ff) << 0) > + > +/* S5P_DSIM_MVPORCH */ > +#define DSIM_CMD_ALLOW_SHIFT ? ? ? ? ? (28) > +#define DSIM_STABLE_VFP_SHIFT ? ? ? ? ?(16) > +#define DSIM_MAIN_VBP_SHIFT ? ? ? ? ? ?(0) > +#define DSIM_CMD_ALLOW_MASK ? ? ? ? ? ?(0xf << DSIM_CMD_ALLOW_SHIFT) > +#define DSIM_STABLE_VFP_MASK ? ? ? ? ? (0x7ff << DSIM_STABLE_VFP_SHIFT) > +#define DSIM_MAIN_VBP_MASK ? ? ? ? ? ? (0x7ff << DSIM_MAIN_VBP_SHIFT) > + > +/* S5P_DSIM_MHPORCH */ > +#define DSIM_MAIN_HFP_SHIFT ? ? ? ? ? ?(16) > +#define DSIM_MAIN_HBP_SHIFT ? ? ? ? ? ?(0) > +#define DSIM_MAIN_HFP_MASK ? ? ? ? ? ? ((0xffff) << DSIM_MAIN_HFP_SHIFT) > +#define DSIM_MAIN_HBP_MASK ? ? ? ? ? ? ((0xffff) << DSIM_MAIN_HBP_SHIFT) > + > +/* S5P_DSIM_MSYNC */ > +#define DSIM_MAIN_VSA_SHIFT ? ? ? ? ? ?(22) > +#define DSIM_MAIN_HSA_SHIFT ? ? ? ? ? ?(0) > +#define DSIM_MAIN_VSA_MASK ? ? ? ? ? ? ((0x3ff) << DSIM_MAIN_VSA_SHIFT) > +#define DSIM_MAIN_HSA_MASK ? ? ? ? ? ? ((0xffff) << DSIM_MAIN_HSA_SHIFT) > + > +/* S5P_DSIM_SDRESOL */ > +#define DSIM_SUB_STANDY_SHIFT ? ? ? ? ?(31) > +#define DSIM_SUB_VRESOL_SHIFT ? ? ? ? ?(16) > +#define DSIM_SUB_HRESOL_SHIFT ? ? ? ? ?(0) > +#define DSIM_SUB_STANDY_MASK ? ? ? ? ? ((0x1) << DSIM_SUB_STANDY_SHIFT) > +#define DSIM_SUB_VRESOL_MASK ? ? ? ? ? ((0x7ff) << DSIM_SUB_VRESOL_SHIFT) > +#define DSIM_SUB_HRESOL_MASK ? ? ? ? ? ((0x7ff) << DSIM_SUB_HRESOL_SHIFT) > + > +/* S5P_DSIM_INTSRC */ > +#define INTSRC_FRAME_DONE ? ? ? ? ? ? ?(1 << 24) > +#define INTSRC_PLL_STABLE ? ? ? ? ? ? ?(1 << 31) > + > +/* S5P_DSIM_INTMSK */ > +#define INTMSK_FRAME_DONE ? ? ? ? ? ? ?(1 << 24) > + > +/* S5P_DSIM_FIFOCTRL */ > +#define SFR_HEADER_EMPTY ? ? ? ? ? ? ? (1 << 22) > + > +/* S5P_DSIM_PHYACCHR */ > +#define DSIM_AFC_CTL(x) ? ? ? ? ? ? ? ? ? ? ? ?(((x) & 0x7) << 5) > + > +/* S5P_DSIM_PLLCTRL */ > +#define DSIM_PLL_EN_SHIFT ? ? ? ? ? ? ?(23) > +#define DSIM_FREQ_BAND_SHIFT ? ? ? ? ? (24) > + > +#endif /* _REGS_DSIM_H */ > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig > index e6a8d8c..1e71a54 100644 > --- a/drivers/video/Kconfig > +++ b/drivers/video/Kconfig > @@ -2044,6 +2044,13 @@ config FB_S3C2410_DEBUG > ? ? ? ? ?Turn on debugging messages. Note that you can set/unset at run time > ? ? ? ? ?through sysfs > > +config S5P_MIPI_DSI > + ? ? ? tristate "Samsung SoC MIPI-DSI support." > + ? ? ? depends on FB_S3C && (ARCH_S5PV210 || ARCH_EXYNOS4) > + ? ? ? default n > + ? ? ? ---help--- > + ? ? ? ? This enables support for MIPI-DSI device. > + > ?config FB_NUC900 > ? ? ? ? bool "NUC900 LCD framebuffer support" > ? ? ? ? depends on FB && ARCH_W90X900 > diff --git a/drivers/video/Makefile b/drivers/video/Makefile > index 2ea44b6..ee5a1d5 100644 > --- a/drivers/video/Makefile > +++ b/drivers/video/Makefile > @@ -119,6 +119,8 @@ obj-$(CONFIG_FB_SH7760) ? ? ? ? ? ? ? += sh7760fb.o > ?obj-$(CONFIG_FB_IMX) ? ? ? ? ? ? ?+= imxfb.o > ?obj-$(CONFIG_FB_S3C) ? ? ? ? ? ? += s3c-fb.o > ?obj-$(CONFIG_FB_S3C2410) ? ? ? ? += s3c2410fb.o > +obj-$(CONFIG_S5P_MIPI_DSI) ? ? ? += s5p_mipi_dsi.o s5p_mipi_dsi_common.o \ > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? s5p_mipi_dsi_lowlevel.o > ?obj-$(CONFIG_FB_FSL_DIU) ? ? ? ? += fsl-diu-fb.o > ?obj-$(CONFIG_FB_COBALT) ? ? ? ? ? += cobalt_lcdfb.o > ?obj-$(CONFIG_FB_PNX4008_DUM) ? ? += pnx4008/ > diff --git a/drivers/video/s5p_mipi_dsi.c b/drivers/video/s5p_mipi_dsi.c > new file mode 100644 > index 0000000..50fc00e > --- /dev/null > +++ b/drivers/video/s5p_mipi_dsi.c > @@ -0,0 +1,481 @@ > +/* linux/drivers/video/s5p_mipi_dsi.c > + * > + * Samsung SoC MIPI-DSIM driver. > + * > + * Copyright (c) 2011 Samsung Electronics Co., Ltd > + * > + * InKi Dae, > + * > + * 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. > +*/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +#include "s5p_mipi_dsi_common.h" > + > +#define master_to_driver(a) ? ?(a->dsim_lcd_drv) > +#define master_to_device(a) ? ?(a->dsim_lcd_dev) > + > +struct mipi_dsim_ddi { > + ? ? ? int ? ? ? ? ? ? ? ? ? ? ? ? ? ? bus_id; > + ? ? ? struct list_head ? ? ? ? ? ? ? ?list; > + ? ? ? struct mipi_dsim_lcd_device ? ? *dsim_lcd_dev; > + ? ? ? struct mipi_dsim_lcd_driver ? ? *dsim_lcd_drv; > +}; > + > +static LIST_HEAD(dsim_ddi_list); > +static LIST_HEAD(dsim_lcd_dev_list); > + > +static DEFINE_MUTEX(mipi_dsim_lock); > + > +static struct s5p_platform_mipi_dsim *to_dsim_plat(struct platform_device *pdev) > +{ > + ? ? ? return (struct s5p_platform_mipi_dsim *)pdev->dev.platform_data; > +} > + > +static irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id) > +{ > + ? ? ? return IRQ_HANDLED; > +} > + > +int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev) > +{ > + ? ? ? struct mipi_dsim_ddi *dsim_ddi; > + > + ? ? ? if (!lcd_dev) { > + ? ? ? ? ? ? ? printk(KERN_ERR "mipi_dsim_lcd_device is NULL.\n"); > + ? ? ? ? ? ? ? return -EFAULT; > + ? ? ? } > + > + ? ? ? if (!lcd_dev->name) { > + ? ? ? ? ? ? ? printk(KERN_ERR "dsim_lcd_device name is NULL.\n"); > + ? ? ? ? ? ? ? return -EFAULT; > + ? ? ? } > + > + ? ? ? dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL); > + ? ? ? if (!dsim_ddi) { > + ? ? ? ? ? ? ? printk(KERN_ERR "failed to allocate dsim_ddi object.\n"); > + ? ? ? ? ? ? ? return -EFAULT; > + ? ? ? } > + > + ? ? ? dsim_ddi->dsim_lcd_dev = lcd_dev; > + > + ? ? ? mutex_lock(&mipi_dsim_lock); > + ? ? ? list_add_tail(&dsim_ddi->list, &dsim_ddi_list); > + ? ? ? mutex_unlock(&mipi_dsim_lock); > + > + ? ? ? return 0; > +} > + > +struct mipi_dsim_ddi > + ? ? ? *s5p_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv) > +{ > + ? ? ? struct mipi_dsim_ddi *dsim_ddi; > + ? ? ? struct mipi_dsim_lcd_device *lcd_dev; > + > + ? ? ? mutex_lock(&mipi_dsim_lock); > + > + ? ? ? list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) { > + ? ? ? ? ? ? ? lcd_dev = dsim_ddi->dsim_lcd_dev; > + ? ? ? ? ? ? ? if (!lcd_dev) > + ? ? ? ? ? ? ? ? ? ? ? continue; > + > + ? ? ? ? ? ? ? if (lcd_drv->id >= 0) { > + ? ? ? ? ? ? ? ? ? ? ? if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0 && > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? lcd_drv->id == lcd_dev->id) { > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /** > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* bus_id would be used to identify > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* connected bus. > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/ > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dsim_ddi->bus_id = lcd_dev->bus_id; > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mutex_unlock(&mipi_dsim_lock); > + > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return dsim_ddi; > + ? ? ? ? ? ? ? ? ? ? ? } > + ? ? ? ? ? ? ? } else { > + ? ? ? ? ? ? ? ? ? ? ? if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) { > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /** > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* bus_id would be used to identify > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* connected bus. > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/ > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dsim_ddi->bus_id = lcd_dev->bus_id; > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mutex_unlock(&mipi_dsim_lock); > + > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return dsim_ddi; > + ? ? ? ? ? ? ? ? ? ? ? } > + ? ? ? ? ? ? ? } > + > + ? ? ? ? ? ? ? kfree(dsim_ddi); > + ? ? ? ? ? ? ? list_del(&dsim_ddi_list); > + ? ? ? } > + > + ? ? ? mutex_unlock(&mipi_dsim_lock); > + > + ? ? ? return NULL; > +} > + > +int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv) > +{ > + ? ? ? struct mipi_dsim_ddi *dsim_ddi; > + > + ? ? ? if (!lcd_drv) { > + ? ? ? ? ? ? ? printk(KERN_ERR "mipi_dsim_lcd_driver is NULL.\n"); > + ? ? ? ? ? ? ? return -EFAULT; > + ? ? ? } > + > + ? ? ? if (!lcd_drv->name) { > + ? ? ? ? ? ? ? printk(KERN_ERR "dsim_lcd_driver name is NULL.\n"); > + ? ? ? ? ? ? ? return -EFAULT; > + ? ? ? } > + > + ? ? ? dsim_ddi = s5p_mipi_dsi_find_lcd_device(lcd_drv); > + ? ? ? if (!dsim_ddi) { > + ? ? ? ? ? ? ? printk(KERN_ERR "mipi_dsim_ddi object not found.\n"); > + ? ? ? ? ? ? ? return -EFAULT; > + ? ? ? } > + > + ? ? ? dsim_ddi->dsim_lcd_drv = lcd_drv; > + > + ? ? ? printk(KERN_INFO "registered panel driver(%s) to mipi-dsi driver.\n", > + ? ? ? ? ? ? ? lcd_drv->name); > + > + ? ? ? return 0; > + > +} > + > +struct mipi_dsim_ddi > + ? ? ? *s5p_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim, > + ? ? ? ? ? ? ? ? ? ? ? const char *name) > +{ > + ? ? ? struct mipi_dsim_ddi *dsim_ddi; > + ? ? ? struct mipi_dsim_lcd_driver *lcd_drv; > + ? ? ? struct mipi_dsim_lcd_device *lcd_dev; > + ? ? ? int ret; > + > + ? ? ? mutex_lock(&dsim->lock); > + > + ? ? ? list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) { > + ? ? ? ? ? ? ? lcd_drv = dsim_ddi->dsim_lcd_drv; > + ? ? ? ? ? ? ? lcd_dev = dsim_ddi->dsim_lcd_dev; > + ? ? ? ? ? ? ? if (!lcd_drv || !lcd_dev || > + ? ? ? ? ? ? ? ? ? ? ? (dsim->id != dsim_ddi->bus_id)) > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue; > + > + ? ? ? ? ? ? ? dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n", > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? lcd_drv->id, lcd_dev->id); > + ? ? ? ? ? ? ? dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n", > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? lcd_dev->bus_id, dsim->id); > + > + ? ? ? ? ? ? ? if ((strcmp(lcd_drv->name, name) == 0)) { > + ? ? ? ? ? ? ? ? ? ? ? lcd_dev->master = dsim; > + > + ? ? ? ? ? ? ? ? ? ? ? lcd_dev->dev.parent = dsim->dev; > + ? ? ? ? ? ? ? ? ? ? ? dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name); > + > + ? ? ? ? ? ? ? ? ? ? ? ret = device_register(&lcd_dev->dev); > + ? ? ? ? ? ? ? ? ? ? ? if (ret < 0) { > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev_err(dsim->dev, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "can't register %s, status %d\n", > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev_name(&lcd_dev->dev), ret); > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mutex_unlock(&dsim->lock); > + > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return NULL; > + ? ? ? ? ? ? ? ? ? ? ? } > + > + ? ? ? ? ? ? ? ? ? ? ? dsim->dsim_lcd_dev = lcd_dev; > + ? ? ? ? ? ? ? ? ? ? ? dsim->dsim_lcd_drv = lcd_drv; > + > + ? ? ? ? ? ? ? ? ? ? ? mutex_unlock(&dsim->lock); > + > + ? ? ? ? ? ? ? ? ? ? ? return dsim_ddi; > + ? ? ? ? ? ? ? } > + ? ? ? } > + > + ? ? ? mutex_unlock(&dsim->lock); > + > + ? ? ? return NULL; > +} > + > +/* define MIPI-DSI Master operations. */ > +static struct mipi_dsim_master_ops master_ops = { > + ? ? ? .cmd_write ? ? ? ? ? ? ? ? ? ? ?= s5p_mipi_dsi_wr_data, > + ? ? ? .get_dsim_frame_done ? ? ? ? ? ?= s5p_mipi_dsi_get_frame_done_status, > + ? ? ? .clear_dsim_frame_done ? ? ? ? ?= s5p_mipi_dsi_clear_frame_done, > +}; > + > +static int s5p_mipi_dsi_probe(struct platform_device *pdev) > +{ > + ? ? ? struct resource *res; > + ? ? ? struct mipi_dsim_device *dsim; > + ? ? ? struct mipi_dsim_config *dsim_config; > + ? ? ? struct s5p_platform_mipi_dsim *dsim_pd; > + ? ? ? struct mipi_dsim_ddi *dsim_ddi; > + ? ? ? int ret = -1; > + > + ? ? ? dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL); > + ? ? ? if (!dsim) { > + ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to allocate dsim object.\n"); > + ? ? ? ? ? ? ? return -EFAULT; > + ? ? ? } > + > + ? ? ? dsim->pd = to_dsim_plat(pdev); > + ? ? ? dsim->dev = &pdev->dev; > + ? ? ? dsim->id = pdev->id; > + ? ? ? dsim->resume_complete = 0; > + > + ? ? ? /* get s5p_platform_mipi_dsim. */ > + ? ? ? dsim_pd = (struct s5p_platform_mipi_dsim *)dsim->pd; > + ? ? ? if (dsim_pd == NULL) { > + ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to get platform data for dsim.\n"); > + ? ? ? ? ? ? ? return -EFAULT; > + ? ? ? } > + ? ? ? /* get mipi_dsim_config. */ > + ? ? ? dsim_config = dsim_pd->dsim_config; > + ? ? ? if (dsim_config == NULL) { > + ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to get dsim config data.\n"); > + ? ? ? ? ? ? ? return -EFAULT; > + ? ? ? } > + > + ? ? ? dsim->dsim_config = dsim_config; > + ? ? ? dsim->master_ops = &master_ops; > + > + ? ? ? dsim->clock = clk_get(&pdev->dev, "dsim"); > + ? ? ? if (IS_ERR(dsim->clock)) { > + ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to get dsim clock source\n"); > + ? ? ? ? ? ? ? goto err_clock_get; > + ? ? ? } > + > + ? ? ? clk_enable(dsim->clock); > + > + ? ? ? 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_platform_get; > + ? ? ? } > + > + ? ? ? res = request_mem_region(res->start, resource_size(res), > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev_name(&pdev->dev)); > + ? ? ? if (!res) { > + ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to request io memory region\n"); > + ? ? ? ? ? ? ? ret = -EINVAL; > + ? ? ? ? ? ? ? goto err_mem_region; > + ? ? ? } > + > + ? ? ? dsim->res = res; > + > + ? ? ? dsim->reg_base = ioremap(res->start, resource_size(res)); > + ? ? ? if (!dsim->reg_base) { > + ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to remap io region\n"); > + ? ? ? ? ? ? ? ret = -EINVAL; > + ? ? ? ? ? ? ? goto err_mem_region; > + ? ? ? } > + > + ? ? ? /* > + ? ? ? ?* in case of MIPI Video mode, > + ? ? ? ?* frame done interrupt handler would be used. > + ? ? ? ?*/ > + ? ? ? if (dsim_config->e_interface == DSIM_VIDEO) { > + ? ? ? ? ? ? ? dsim->irq = platform_get_irq(pdev, 0); > + ? ? ? ? ? ? ? if (request_irq(dsim->irq, s5p_mipi_dsi_interrupt_handler, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IRQF_DISABLED, "mipi-dsi", dsim)) { > + ? ? ? ? ? ? ? ? ? ? ? dev_err(&pdev->dev, "request_irq failed.\n"); > + ? ? ? ? ? ? ? ? ? ? ? goto err_request_irq; > + ? ? ? ? ? ? ? } > + ? ? ? } > + > + ? ? ? mutex_init(&dsim->lock); > + > + ? ? ? if (dsim->pd->mipi_power) > + ? ? ? ? ? ? ? dsim->pd->mipi_power(pdev, 1); > + ? ? ? else { > + ? ? ? ? ? ? ? dev_err(&pdev->dev, "mipi_power is NULL.\n"); > + ? ? ? ? ? ? ? goto err_request_irq; > + ? ? ? } > + > + ? ? ? /* bind lcd ddi matched with panel name. */ > + ? ? ? dsim_ddi = s5p_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name); > + ? ? ? if (!dsim_ddi) { > + ? ? ? ? ? ? ? dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n"); > + ? ? ? ? ? ? ? goto err_bind; > + ? ? ? } > + > + ? ? ? /* enable MIPI-DSI PHY. */ > + ? ? ? if (dsim->pd->phy_enable) > + ? ? ? ? ? ? ? dsim->pd->phy_enable(pdev, true); > + > + ? ? ? s5p_mipi_dsi_init_dsim(dsim); > + ? ? ? s5p_mipi_dsi_init_link(dsim); > + > + ? ? ? s5p_mipi_dsi_set_hs_enable(dsim); > + > + ? ? ? /* set display timing. */ > + ? ? ? s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config); > + > + ? ? ? platform_set_drvdata(pdev, dsim); > + > + ? ? ? /* initialize mipi-dsi client(lcd panel). */ > + ? ? ? if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe) > + ? ? ? ? ? ? ? dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev); > + > + ? ? ? dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n", > + ? ? ? ? ? ? ? (dsim_config->e_interface == DSIM_COMMAND) ? > + ? ? ? ? ? ? ? ? ? ? ? "CPU" : "RGB"); > + > + ? ? ? return 0; > + > +err_bind: > + ? ? ? dsim->pd->mipi_power(pdev, 0); > + > +err_request_irq: > + ? ? ? release_resource(dsim->res); > + ? ? ? kfree(dsim->res); > + > + ? ? ? iounmap((void __iomem *) dsim->reg_base); > + > +err_mem_region: > +err_platform_get: > + ? ? ? clk_disable(dsim->clock); > + > +err_clock_get: > + ? ? ? clk_put(dsim->clock); > + ? ? ? kfree(dsim); > + > + ? ? ? return ret; > + > +} > + > +static int __devexit s5p_mipi_dsi_remove(struct platform_device *pdev) > +{ > + ? ? ? struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); > + ? ? ? struct mipi_dsim_ddi *dsim_ddi = NULL; > + > + ? ? ? if (dsim->dsim_config->e_interface == DSIM_VIDEO) > + ? ? ? ? ? ? ? free_irq(dsim->irq, dsim); > + > + ? ? ? iounmap(dsim->reg_base); > + > + ? ? ? clk_disable(dsim->clock); > + ? ? ? clk_put(dsim->clock); > + > + ? ? ? release_resource(dsim->res); > + ? ? ? kfree(dsim->res); > + > + ? ? ? list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) { > + ? ? ? ? ? ? ? if (dsim_ddi) { > + ? ? ? ? ? ? ? ? ? ? ? if (dsim->id == dsim_ddi->bus_id) { > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? kfree(dsim_ddi); > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dsim_ddi = NULL; > + ? ? ? ? ? ? ? ? ? ? ? } > + ? ? ? ? ? ? ? } > + ? ? ? } > + > + ? ? ? kfree(dsim); > + > + ? ? ? return 0; > +} > + > +#ifdef CONFIG_PM > +static int s5p_mipi_dsi_suspend(struct platform_device *pdev, > + ? ? ? ? ? ? ? pm_message_t state) > +{ > + ? ? ? struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); > + > + ? ? ? dsim->resume_complete = 0; > + > + ? ? ? if (master_to_driver(dsim) && (master_to_driver(dsim))->suspend) > + ? ? ? ? ? ? ? (master_to_driver(dsim))->suspend(master_to_device(dsim)); > + > + ? ? ? clk_disable(dsim->clock); > + > + ? ? ? if (dsim->pd->mipi_power) > + ? ? ? ? ? ? ? dsim->pd->mipi_power(pdev, 0); > + > + ? ? ? return 0; > +} > + > +static int s5p_mipi_dsi_resume(struct platform_device *pdev) > +{ > + ? ? ? struct mipi_dsim_device *dsim = platform_get_drvdata(pdev); > + > + ? ? ? if (dsim->pd->mipi_power) > + ? ? ? ? ? ? ? dsim->pd->mipi_power(pdev, 1); > + > + ? ? ? clk_enable(dsim->clock); > + > + ? ? ? s5p_mipi_dsi_init_dsim(dsim); > + ? ? ? s5p_mipi_dsi_init_link(dsim); > + > + ? ? ? s5p_mipi_dsi_set_hs_enable(dsim); > + > + ? ? ? /* change cpu command transfer mode to hs. */ > + ? ? ? s5p_mipi_dsi_set_data_transfer_mode(dsim, 0); > + > + ? ? ? if (master_to_driver(dsim) && (master_to_driver(dsim))->resume) > + ? ? ? ? ? ? ? (master_to_driver(dsim))->resume(master_to_device(dsim)); > + > + ? ? ? s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config); > + > + ? ? ? /* change lcdc data transfer mode to hs. */ > + ? ? ? s5p_mipi_dsi_set_data_transfer_mode(dsim, 1); > + > + ? ? ? dsim->resume_complete = 1; > + > + ? ? ? return 0; > +} > +#else > +#define s5p_mipi_dsi_suspend NULL > +#define s5p_mipi_dsi_resume NULL > +#endif > + > +static struct platform_driver s5p_mipi_dsi_driver = { > + ? ? ? .probe = s5p_mipi_dsi_probe, > + ? ? ? .remove = __devexit_p(s5p_mipi_dsi_remove), > + ? ? ? .suspend = s5p_mipi_dsi_suspend, > + ? ? ? .resume = s5p_mipi_dsi_resume, > + ? ? ? .driver = { > + ? ? ? ? ? ? ? ? ?.name = "s5p-mipi-dsim", > + ? ? ? ? ? ? ? ? ?.owner = THIS_MODULE, > + ? ? ? }, > +}; > + > +static int s5p_mipi_dsi_register(void) > +{ > + ? ? ? platform_driver_register(&s5p_mipi_dsi_driver); > + > + ? ? ? return 0; > +} > + > +static void s5p_mipi_dsi_unregister(void) > +{ > + ? ? ? platform_driver_unregister(&s5p_mipi_dsi_driver); > +} > + > +module_init(s5p_mipi_dsi_register); > +module_exit(s5p_mipi_dsi_unregister); > + > +MODULE_AUTHOR("InKi Dae "); > +MODULE_DESCRIPTION("Samusung SoC MIPI-DSI driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/video/s5p_mipi_dsi_common.c b/drivers/video/s5p_mipi_dsi_common.c > new file mode 100644 > index 0000000..51ee4ed > --- /dev/null > +++ b/drivers/video/s5p_mipi_dsi_common.c > @@ -0,0 +1,655 @@ > +/* linux/drivers/video/s5p_mipi_dsi_common.c > + * > + * Samsung SoC MIPI-DSI common driver. > + * > + * Copyright (c) 2011 Samsung Electronics Co., Ltd > + * > + * InKi Dae, > + * > + * 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. > +*/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include