Commit 9d200153 authored by Stepan Moskovchenko's avatar Stepan Moskovchenko Committed by Greg Kroah-Hartman

Staging: add MSM framebuffer driver

Qualcomm development of the MSM SOC framebuffer driver has
diverged significantly from the driver used by Android. This
is a snapshot of our current driver, in all it's agony. We are
putting this in staging to help with the process of converging
the two drivers.

At this point, the driver has been tested only in dumb
framebuffer mode.
Signed-off-by: default avatarStepan Moskovchenko <stepanm@codeaurora.org>
Signed-off-by: default avatarDavid Brown <davidb@codeaurora.org>
Signed-off-by: default avatarAbhijeet Dharmapurikar <adharmap@codeaurora.org>
[dwalker@codeaurora.org: added a small compile fix and TODO.]
Signed-off-by: default avatarDaniel Walker <dwalker@codeaurora.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 34ef545a
......@@ -145,5 +145,7 @@ source "drivers/staging/xgifb/Kconfig"
source "drivers/staging/mrst-touchscreen/Kconfig"
source "drivers/staging/msm/Kconfig"
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING
......@@ -53,3 +53,4 @@ obj-$(CONFIG_TI_ST) += ti-st/
obj-$(CONFIG_ADIS16255) += adis16255/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/
obj-$(CONFIG_MSM_STAGING) += msm/
config MSM_STAGING
tristate "MSM Frame Buffer Support"
depends on FB && ARCH_MSM && !FB_MSM
select FB_BACKLIGHT if FB_MSM_BACKLIGHT
select NEW_LEDS
select LEDS_CLASS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
---help---
Support for MSM Framebuffer.
if MSM_STAGING
config FB_MSM_LCDC_HW
bool
default n
choice
prompt "MDP HW version"
default FB_MSM_MDP31
config FB_MSM_MDP31
select FB_MSM_LCDC_HW
bool "MDP HW ver3.1"
---help---
Support for MSM MDP HW revision 3.1
Say Y here if this is msm8x50 variant platform.
endchoice
config FB_MSM_LCDC
bool
default n
config FB_MSM_TVOUT
bool
default n
config FB_MSM_LCDC_PANEL
bool
select FB_MSM_LCDC
default n
config FB_MSM_LCDC_PRISM_WVGA
bool
select FB_MSM_LCDC_PANEL
default n
config FB_MSM_LCDC_ST1_WXGA
bool
select FB_MSM_LCDC_PANEL
default n
config FB_MSM_LCDC_ST15_WXGA
bool
select FB_MSM_LCDC_PANEL
default n
config FB_MSM_LCDC_WXGA
bool
select FB_MSM_LCDC_PANEL
default n
choice
prompt "LCD Panel"
default FB_MSM_LCDC_ST15_PANEL
config FB_MSM_LCDC_PRISM_WVGA_PANEL
depends on FB_MSM_LCDC_HW
bool "LCDC Prism WVGA Panel"
select FB_MSM_LCDC_PRISM_WVGA
---help---
Support for LCDC Prism WVGA (800x480) panel
config FB_MSM_LCDC_ST15_PANEL
depends on FB_MSM_LCDC_HW
bool "LCDC ST1.5 Panel"
select FB_MSM_LCDC_ST15_WXGA
---help---
Support for ST1.5 WXGA (1366x768) panel
config FB_MSM_PANEL_NONE
bool "NONE"
---help---
This will disable LCD panel
endchoice
choice
prompt "Secondary LCD Panel"
depends on FB_MSM_MDP31
default FB_MSM_SECONDARY_PANEL_NONE
config FB_MSM_SECONDARY_PANEL_NONE
bool "NONE"
---help---
No secondary panel
endchoice
config FB_MSM_TVOUT_NTSC
bool
select FB_MSM_TVOUT
default n
config FB_MSM_TVOUT_PAL
bool
select FB_MSM_TVOUT
default n
choice
depends on (FB_MSM_MDP22 || FB_MSM_MDP31)
prompt "TVOut Region"
default FB_MSM_TVOUT_NTSC_M
config FB_MSM_TVOUT_NTSC_M
bool "NTSC M"
select FB_MSM_TVOUT_NTSC
---help---
Support for NTSC M region (North American and Korea)
config FB_MSM_TVOUT_NONE
bool "NONE"
---help---
This will disable TV Out functionality.
endchoice
config PMEM_KERNEL_SIZE
int "PMEM for kernel components (in MB)"
default 2
depends on ARCH_QSD8X50
help
Configures the amount of PMEM for use by kernel components
(in MB; minimum 2MB)
endif
obj-y := msm_fb.o staging-devices.o memory.o
obj-$(CONFIG_FB_MSM_LOGO) += logo.o
obj-$(CONFIG_FB_BACKLIGHT) += msm_fb_bl.o
# MDP
obj-y += mdp.o
ifeq ($(CONFIG_FB_MSM_MDP40),y)
obj-y += mdp4_util.o
obj-$(CONFIG_DEBUG_FS) += mdp4_debugfs.o
else
obj-y += mdp_hw_init.o
obj-y += mdp_ppp.o
ifeq ($(CONFIG_FB_MSM_MDP31),y)
obj-y += mdp_ppp_v31.o
obj-$(CONFIG_MDP_PPP_ASYNC_OP) += mdp_ppp_dq.o
else
obj-y += mdp_ppp_v20.o
endif
endif
ifeq ($(CONFIG_FB_MSM_OVERLAY),y)
obj-y += mdp4_overlay.o
obj-y += mdp4_overlay_lcdc.o
obj-y += mdp4_overlay_mddi.o
else
obj-y += mdp_dma_lcdc.o
endif
obj-y += mdp_dma.o
obj-y += mdp_dma_s.o
obj-y += mdp_vsync.o
obj-y += mdp_cursor.o
obj-y += mdp_dma_tv.o
# EBI2
obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o
# LCDC
obj-$(CONFIG_FB_MSM_LCDC) += lcdc.o
# MDDI
msm_mddi-objs := mddi.o mddihost.o mddihosti.o
obj-$(CONFIG_FB_MSM_MDDI) += msm_mddi.o
# External MDDI
msm_mddi_ext-objs := mddihost_e.o mddi_ext.o
obj-$(CONFIG_FB_MSM_EXTMDDI) += msm_mddi_ext.o
# TVEnc
obj-$(CONFIG_FB_MSM_TVOUT) += tvenc.o
# MSM FB Panel
obj-y += msm_fb_panel.o
obj-$(CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF) += ebi2_tmd20.o
obj-$(CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF) += ebi2_l2f.o
ifeq ($(CONFIG_FB_MSM_MDDI_AUTO_DETECT),y)
obj-y += mddi_prism.o
obj-y += mddi_toshiba.o
obj-y += mddi_toshiba_vga.o
obj-y += mddi_toshiba_wvga_pt.o
obj-y += mddi_toshiba_wvga.o
obj-y += mddi_sharp.o
else
obj-$(CONFIG_FB_MSM_MDDI_PRISM_WVGA) += mddi_prism.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON) += mddi_toshiba.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA) += mddi_toshiba_vga.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT) += mddi_toshiba_wvga_pt.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA) += mddi_toshiba_wvga.o
obj-$(CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128) += mddi_sharp.o
endif
obj-$(CONFIG_FB_MSM_LCDC_PANEL) += lcdc_panel.o
obj-$(CONFIG_FB_MSM_LCDC_PRISM_WVGA) += lcdc_prism.o
obj-$(CONFIG_FB_MSM_LCDC_EXTERNAL_WXGA) += lcdc_external.o
obj-$(CONFIG_FB_MSM_LCDC_GORDON_VGA) += lcdc_gordon.o
obj-$(CONFIG_FB_MSM_LCDC_WXGA) += lcdc_wxga.o
obj-$(CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT) += lcdc_toshiba_wvga_pt.o
obj-$(CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT) += lcdc_sharp_wvga_pt.o
obj-$(CONFIG_FB_MSM_LCDC_GRAPEFRUIT_VGA) += lcdc_grapefruit.o
obj-$(CONFIG_FB_MSM_LCDC_ST1_WXGA) += lcdc_st1_wxga.o
obj-$(CONFIG_FB_MSM_LCDC_ST15_WXGA) += lcdc_st15.o
obj-$(CONFIG_FB_MSM_HDMI_SII_EXTERNAL_720P) += hdmi_sii9022.o
obj-$(CONFIG_FB_MSM_TVOUT_NTSC) += tv_ntsc.o
obj-$(CONFIG_FB_MSM_TVOUT_PAL) += tv_pal.o
obj-$(CONFIG_FB_MSM_EXTMDDI_SVGA) += mddi_ext_lcd.o
clean:
rm *.o .*cmd
- Merge this code with the existing MSM framebuffer
- General style clean ups.
This diff is collapsed.
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <linux/debugfs.h>
#include "msm_fb.h"
static int ebi2_lcd_probe(struct platform_device *pdev);
static int ebi2_lcd_remove(struct platform_device *pdev);
static struct platform_driver ebi2_lcd_driver = {
.probe = ebi2_lcd_probe,
.remove = ebi2_lcd_remove,
.suspend = NULL,
.suspend_late = NULL,
.resume_early = NULL,
.resume = NULL,
.shutdown = NULL,
.driver = {
.name = "ebi2_lcd",
},
};
static void *ebi2_base;
static void *ebi2_lcd_cfg0;
static void *ebi2_lcd_cfg1;
static void __iomem *lcd01_base;
static void __iomem *lcd02_base;
static int ebi2_lcd_resource_initialized;
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
static int ebi2_lcd_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
int rc, i;
if (pdev->id == 0) {
for (i = 0; i < pdev->num_resources; i++) {
if (!strncmp(pdev->resource[i].name, "base", 4)) {
ebi2_base = ioremap(pdev->resource[i].start,
pdev->resource[i].end -
pdev->resource[i].start + 1);
if (!ebi2_base) {
printk(KERN_ERR
"ebi2_base ioremap failed!\n");
return -ENOMEM;
}
ebi2_lcd_cfg0 = (void *)(ebi2_base + 0x20);
ebi2_lcd_cfg1 = (void *)(ebi2_base + 0x24);
} else if (!strncmp(pdev->resource[i].name,
"lcd01", 5)) {
lcd01_base = ioremap(pdev->resource[i].start,
pdev->resource[i].end -
pdev->resource[i].start + 1);
if (!lcd01_base) {
printk(KERN_ERR
"lcd01_base ioremap failed!\n");
return -ENOMEM;
}
} else if (!strncmp(pdev->resource[i].name,
"lcd02", 5)) {
lcd02_base = ioremap(pdev->resource[i].start,
pdev->resource[i].end -
pdev->resource[i].start + 1);
if (!lcd02_base) {
printk(KERN_ERR
"lcd02_base ioremap failed!\n");
return -ENOMEM;
}
}
}
ebi2_lcd_resource_initialized = 1;
return 0;
}
if (!ebi2_lcd_resource_initialized)
return -EPERM;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
return -ENOMEM;
if (ebi2_base == NULL)
return -ENOMEM;
mdp_dev = platform_device_alloc("mdp", pdev->id);
if (!mdp_dev)
return -ENOMEM;
/* link to the latest pdev */
mfd->pdev = mdp_dev;
mfd->dest = DISPLAY_LCD;
/* add panel data */
if (platform_device_add_data
(mdp_dev, pdev->dev.platform_data,
sizeof(struct msm_fb_panel_data))) {
printk(KERN_ERR "ebi2_lcd_probe: platform_device_add_data failed!\n");
platform_device_put(mdp_dev);
return -ENOMEM;
}
/* data chain */
pdata = mdp_dev->dev.platform_data;
pdata->on = panel_next_on;
pdata->off = panel_next_off;
pdata->next = pdev;
/* get/set panel specific fb info */
mfd->panel_info = pdata->panel_info;
if (mfd->panel_info.bpp == 24)
mfd->fb_imgType = MDP_RGB_888;
else
mfd->fb_imgType = MDP_RGB_565;
/* config msm ebi2 lcd register */
if (mfd->panel_info.pdest == DISPLAY_1) {
outp32(ebi2_base,
(inp32(ebi2_base) & (~(EBI2_PRIM_LCD_CLR))) |
EBI2_PRIM_LCD_SEL);
/*
* current design has one set of cfg0/1 register to control
* both EBI2 channels. so, we're using the PRIM channel to
* configure both.
*/
outp32(ebi2_lcd_cfg0, mfd->panel_info.wait_cycle);
if (mfd->panel_info.bpp == 18)
outp32(ebi2_lcd_cfg1, 0x01000000);
else
outp32(ebi2_lcd_cfg1, 0x0);
} else {
#ifdef DEBUG_EBI2_LCD
/*
* confliting with QCOM SURF FPGA CS.
* OEM should enable below for their CS mapping
*/
outp32(ebi2_base, (inp32(ebi2_base)&(~(EBI2_SECD_LCD_CLR)))
|EBI2_SECD_LCD_SEL);
#endif
}
/*
* map cs (chip select) address
*/
if (mfd->panel_info.pdest == DISPLAY_1) {
mfd->cmd_port = lcd01_base;
mfd->data_port =
(void *)((uint32) mfd->cmd_port + EBI2_PRIM_LCD_RS_PIN);
mfd->data_port_phys =
(void *)(LCD_PRIM_BASE_PHYS + EBI2_PRIM_LCD_RS_PIN);
} else {
mfd->cmd_port = lcd01_base;
mfd->data_port =
(void *)((uint32) mfd->cmd_port + EBI2_SECD_LCD_RS_PIN);
mfd->data_port_phys =
(void *)(LCD_SECD_BASE_PHYS + EBI2_SECD_LCD_RS_PIN);
}
/*
* set driver data
*/
platform_set_drvdata(mdp_dev, mfd);
/*
* register in mdp driver
*/
rc = platform_device_add(mdp_dev);
if (rc) {
goto ebi2_lcd_probe_err;
}
pdev_list[pdev_list_cnt++] = pdev;
return 0;
ebi2_lcd_probe_err:
platform_device_put(mdp_dev);
return rc;
}
static int ebi2_lcd_remove(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
if (!mfd)
return 0;
if (mfd->key != MFD_KEY)
return 0;
iounmap(mfd->cmd_port);
return 0;
}
static int ebi2_lcd_register_driver(void)
{
return platform_driver_register(&ebi2_lcd_driver);
}
static int __init ebi2_lcd_driver_init(void)
{
return ebi2_lcd_register_driver();
}
module_init(ebi2_lcd_driver_init);
\ No newline at end of file
This diff is collapsed.
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/i2c.h>
#include <linux/delay.h>
#include "msm_fb.h"
#define DEVICE_NAME "sii9022"
#define SII9022_DEVICE_ID 0xB0
struct sii9022_i2c_addr_data{
u8 addr;
u8 data;
};
/* video mode data */
static u8 video_mode_data[] = {
0x00,
0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02,
};
static u8 avi_io_format[] = {
0x09,
0x00, 0x00,
};
/* power state */
static struct sii9022_i2c_addr_data regset0[] = {
{ 0x60, 0x04 },
{ 0x63, 0x00 },
{ 0x1E, 0x00 },
};
static u8 video_infoframe[] = {
0x0C,
0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00,
0xE9, 0x02, 0x04, 0x01, 0x04, 0x06,
};
/* configure audio */
static struct sii9022_i2c_addr_data regset1[] = {
{ 0x26, 0x90 },
{ 0x20, 0x90 },
{ 0x1F, 0x80 },
{ 0x26, 0x80 },
{ 0x24, 0x02 },
{ 0x25, 0x0B },
{ 0xBC, 0x02 },
{ 0xBD, 0x24 },
{ 0xBE, 0x02 },
};
/* enable audio */
static u8 misc_infoframe[] = {
0xBF,
0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/* set HDMI, active */
static struct sii9022_i2c_addr_data regset2[] = {
{ 0x1A, 0x01 },
{ 0x3D, 0x00 },
};
static int send_i2c_data(struct i2c_client *client,
struct sii9022_i2c_addr_data *regset,
int size)
{
int i;
int rc = 0;
for (i = 0; i < size; i++) {
rc = i2c_smbus_write_byte_data(
client,
regset[i].addr, regset[i].data);
if (rc)
break;
}
return rc;
}
static int hdmi_sii_enable(struct i2c_client *client)
{
int rc;
int retries = 10;
int count;
rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00);
if (rc)
goto enable_exit;
do {
msleep(1);
rc = i2c_smbus_read_byte_data(client, 0x1B);
} while ((rc != SII9022_DEVICE_ID) && retries--);
if (rc != SII9022_DEVICE_ID)
return -ENODEV;
rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11);
if (rc)
goto enable_exit;
count = ARRAY_SIZE(video_mode_data);
rc = i2c_master_send(client, video_mode_data, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = i2c_smbus_write_byte_data(client, 0x08, 0x20);
if (rc)
goto enable_exit;
count = ARRAY_SIZE(avi_io_format);
rc = i2c_master_send(client, avi_io_format, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0));
if (rc)
goto enable_exit;
count = ARRAY_SIZE(video_infoframe);
rc = i2c_master_send(client, video_infoframe, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1));
if (rc)
goto enable_exit;
count = ARRAY_SIZE(misc_infoframe);
rc = i2c_master_send(client, misc_infoframe, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2));
if (rc)
goto enable_exit;
return 0;
enable_exit:
printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc);
return rc;
}
static const struct i2c_device_id hmdi_sii_id[] = {
{ DEVICE_NAME, 0 },
{ }
};
static int hdmi_sii_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
return -ENODEV;
rc = hdmi_sii_enable(client);
return rc;
}
static struct i2c_driver hdmi_sii_i2c_driver = {
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
},
.probe = hdmi_sii_probe,
.remove = __exit_p(hdmi_sii_remove),
.id_table = hmdi_sii_id,
};
static int __init hdmi_sii_init(void)
{
int ret;
struct msm_panel_info pinfo;
if (msm_fb_detect_client("hdmi_sii9022"))
return 0;
pinfo.xres = 1280;
pinfo.yres = 720;
pinfo.type = HDMI_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 124;
pinfo.lcdc.h_front_porch = 110;
pinfo.lcdc.h_pulse_width = 136;
pinfo.lcdc.v_back_porch = 19;
pinfo.lcdc.v_front_porch = 5;
pinfo.lcdc.v_pulse_width = 6;
pinfo.lcdc.border_clr = 0;
pinfo.lcdc.underflow_clr = 0xff;
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret) {
printk(KERN_ERR "%s: failed to register device\n", __func__);
goto init_exit;
}
ret = i2c_add_driver(&hdmi_sii_i2c_driver);
if (ret)
printk(KERN_ERR "%s: failed to add i2c driver\n", __func__);
init_exit:
return ret;
}
static void __exit hdmi_sii_exit(void)
{
i2c_del_driver(&hdmi_sii_i2c_driver);
}
module_init(hdmi_sii_init);
module_exit(hdmi_sii_exit);
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.1");
MODULE_AUTHOR("Qualcomm Innovation Center, Inc.");
MODULE_DESCRIPTION("SiI9022 HDMI driver");
MODULE_ALIAS("platform:hdmi-sii9022");
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/pm_qos_params.h>
#include "msm_fb.h"
static int lcdc_probe(struct platform_device *pdev);
static int lcdc_remove(struct platform_device *pdev);
static int lcdc_off(struct platform_device *pdev);
static int lcdc_on(struct platform_device *pdev);
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
static struct clk *mdp_lcdc_pclk_clk;
static struct clk *mdp_lcdc_pad_pclk_clk;
int mdp_lcdc_pclk_clk_rate;
int mdp_lcdc_pad_pclk_clk_rate;
static struct platform_driver lcdc_driver = {
.probe = lcdc_probe,
.remove = lcdc_remove,
.suspend = NULL,
.resume = NULL,
.shutdown = NULL,
.driver = {
.name = "lcdc",
},
};
static struct lcdc_platform_data *lcdc_pdata;
static int lcdc_off(struct platform_device *pdev)
{
int ret = 0;
ret = panel_next_off(pdev);
clk_disable(mdp_lcdc_pclk_clk);
clk_disable(mdp_lcdc_pad_pclk_clk);
if (lcdc_pdata && lcdc_pdata->lcdc_power_save)
lcdc_pdata->lcdc_power_save(0);
if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config)
ret = lcdc_pdata->lcdc_gpio_config(0);
// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc",
// PM_QOS_DEFAULT_VALUE);
return ret;
}
static int lcdc_on(struct platform_device *pdev)
{
int ret = 0;
struct msm_fb_data_type *mfd;
unsigned long panel_pixclock_freq , pm_qos_freq;
mfd = platform_get_drvdata(pdev);
panel_pixclock_freq = mfd->fbi->var.pixclock;
if (panel_pixclock_freq > 58000000)
/* pm_qos_freq should be in Khz */
pm_qos_freq = panel_pixclock_freq / 1000 ;
else
pm_qos_freq = 58000;
// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc",
// pm_qos_freq);
mfd = platform_get_drvdata(pdev);
clk_enable(mdp_lcdc_pclk_clk);
clk_enable(mdp_lcdc_pad_pclk_clk);
if (lcdc_pdata && lcdc_pdata->lcdc_power_save)
lcdc_pdata->lcdc_power_save(1);
if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config)
ret = lcdc_pdata->lcdc_gpio_config(1);
clk_set_rate(mdp_lcdc_pclk_clk, mfd->fbi->var.pixclock);
clk_set_rate(mdp_lcdc_pad_pclk_clk, mfd->fbi->var.pixclock);
mdp_lcdc_pclk_clk_rate = clk_get_rate(mdp_lcdc_pclk_clk);
mdp_lcdc_pad_pclk_clk_rate = clk_get_rate(mdp_lcdc_pad_pclk_clk);
ret = panel_next_on(pdev);
return ret;
}
static int lcdc_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct fb_info *fbi;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
int rc;
if (pdev->id == 0) {
lcdc_pdata = pdev->dev.platform_data;
return 0;
}
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
return -ENOMEM;
mdp_dev = platform_device_alloc("mdp", pdev->id);
if (!mdp_dev)
return -ENOMEM;
/*
* link to the latest pdev
*/
mfd->pdev = mdp_dev;
mfd->dest = DISPLAY_LCDC;
/*
* alloc panel device data
*/
if (platform_device_add_data
(mdp_dev, pdev->dev.platform_data,
sizeof(struct msm_fb_panel_data))) {
printk(KERN_ERR "lcdc_probe: platform_device_add_data failed!\n");
platform_device_put(mdp_dev);
return -ENOMEM;
}
/*
* data chain
*/
pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data;
pdata->on = lcdc_on;
pdata->off = lcdc_off;
pdata->next = pdev;
/*
* get/set panel specific fb info
*/
mfd->panel_info = pdata->panel_info;
mfd->fb_imgType = MDP_RGB_565;
fbi = mfd->fbi;
fbi->var.pixclock = mfd->panel_info.clk_rate;
fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
/*
* set driver data
*/
platform_set_drvdata(mdp_dev, mfd);
/*
* register in mdp driver
*/
rc = platform_device_add(mdp_dev);
if (rc)
goto lcdc_probe_err;
pdev_list[pdev_list_cnt++] = pdev;
return 0;
lcdc_probe_err:
platform_device_put(mdp_dev);
return rc;
}
static int lcdc_remove(struct platform_device *pdev)
{
// pm_qos_remove_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc");
return 0;
}
static int lcdc_register_driver(void)
{
return platform_driver_register(&lcdc_driver);
}
static int __init lcdc_driver_init(void)
{
mdp_lcdc_pclk_clk = clk_get(NULL, "mdp_lcdc_pclk_clk");
if (IS_ERR(mdp_lcdc_pclk_clk)) {
printk(KERN_ERR "error: can't get mdp_lcdc_pclk_clk!\n");
return IS_ERR(mdp_lcdc_pclk_clk);
}
mdp_lcdc_pad_pclk_clk = clk_get(NULL, "mdp_lcdc_pad_pclk_clk");
if (IS_ERR(mdp_lcdc_pad_pclk_clk)) {
printk(KERN_ERR "error: can't get mdp_lcdc_pad_pclk_clk!\n");
return IS_ERR(mdp_lcdc_pad_pclk_clk);
}
// pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc",
// PM_QOS_DEFAULT_VALUE);
return lcdc_register_driver();
}
module_init(lcdc_driver_init);
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
static int __init lcdc_external_init(void)
{
int ret;
struct msm_panel_info pinfo;
if (msm_fb_detect_client("lcdc_external"))
return 0;
pinfo.xres = 1280;
pinfo.yres = 720;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 124;
pinfo.lcdc.h_front_porch = 110;
pinfo.lcdc.h_pulse_width = 136;
pinfo.lcdc.v_back_porch = 19;
pinfo.lcdc.v_front_porch = 5;
pinfo.lcdc.v_pulse_width = 6;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_external_init);
This diff is collapsed.
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
#include "mddihosti.h"
#endif
static int __init lcdc_grapefruit_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
if (msm_fb_detect_client("lcdc_grapefruit_vga"))
return 0;
#endif
pinfo.xres = 1024;
pinfo.yres = 600;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.fb_num = 2;
pinfo.clk_rate = 40000000;
pinfo.lcdc.h_back_porch = 88;
pinfo.lcdc.h_front_porch = 40;
pinfo.lcdc.h_pulse_width = 128;
pinfo.lcdc.v_back_porch = 23;
pinfo.lcdc.v_front_porch = 1;
pinfo.lcdc.v_pulse_width = 4;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_grapefruit_init);
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
static int lcdc_panel_on(struct platform_device *pdev)
{
return 0;
}
static int lcdc_panel_off(struct platform_device *pdev)
{
return 0;
}
static int __init lcdc_panel_probe(struct platform_device *pdev)
{
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = lcdc_panel_probe,
.driver = {
.name = "lcdc_panel",
},
};
static struct msm_fb_panel_data lcdc_panel_data = {
.on = lcdc_panel_on,
.off = lcdc_panel_off,
};
static int lcdc_dev_id;
int lcdc_device_register(struct msm_panel_info *pinfo)
{
struct platform_device *pdev = NULL;
int ret;
pdev = platform_device_alloc("lcdc_panel", ++lcdc_dev_id);
if (!pdev)
return -ENOMEM;
lcdc_panel_data.panel_info = *pinfo;
ret = platform_device_add_data(pdev, &lcdc_panel_data,
sizeof(lcdc_panel_data));
if (ret) {
printk(KERN_ERR
"%s: platform_device_add_data failed!\n", __func__);
goto err_device_put;
}
ret = platform_device_add(pdev);
if (ret) {
printk(KERN_ERR
"%s: platform_device_register failed!\n", __func__);
goto err_device_put;
}
return 0;
err_device_put:
platform_device_put(pdev);
return ret;
}
static int __init lcdc_panel_init(void)
{
return platform_driver_register(&this_driver);
}
module_init(lcdc_panel_init);
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
#include "mddihosti.h"
#endif
static int __init lcdc_prism_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
ret = msm_fb_detect_client("lcdc_prism_wvga");
if (ret == -ENODEV)
return 0;
if (ret && (mddi_get_client_id() != 0))
return 0;
#endif
pinfo.xres = 800;
pinfo.yres = 480;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 38460000;
pinfo.lcdc.h_back_porch = 21;
pinfo.lcdc.h_front_porch = 81;
pinfo.lcdc.h_pulse_width = 60;
pinfo.lcdc.v_back_porch = 18;
pinfo.lcdc.v_front_porch = 27;
pinfo.lcdc.v_pulse_width = 2;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_prism_init);
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/delay.h>
#ifdef CONFIG_ARCH_MSM7X30
#include <linux/mfd/pmic8058.h>
#endif
#include <mach/gpio.h>
#include "msm_fb.h"
static int lcdc_sharp_panel_off(struct platform_device *pdev);
static int spi_cs;
static int spi_sclk;
static int spi_mosi;
static int spi_miso;
static unsigned char bit_shift[8] = { (1 << 7), /* MSB */
(1 << 6),
(1 << 5),
(1 << 4),
(1 << 3),
(1 << 2),
(1 << 1),
(1 << 0) /* LSB */
};
struct sharp_state_type {
boolean disp_initialized;
boolean display_on;
boolean disp_powered_up;
};
struct sharp_spi_data {
u8 addr;
u8 data;
};
static struct sharp_spi_data init_sequence[] = {
{ 15, 0x01 },
{ 5, 0x01 },
{ 7, 0x10 },
{ 9, 0x1E },
{ 10, 0x04 },
{ 17, 0xFF },
{ 21, 0x8A },
{ 22, 0x00 },
{ 23, 0x82 },
{ 24, 0x24 },
{ 25, 0x22 },
{ 26, 0x6D },
{ 27, 0xEB },
{ 28, 0xB9 },
{ 29, 0x3A },
{ 49, 0x1A },
{ 50, 0x16 },
{ 51, 0x05 },
{ 55, 0x7F },
{ 56, 0x15 },
{ 57, 0x7B },
{ 60, 0x05 },
{ 61, 0x0C },
{ 62, 0x80 },
{ 63, 0x00 },
{ 92, 0x90 },
{ 97, 0x01 },
{ 98, 0xFF },
{ 113, 0x11 },
{ 114, 0x02 },
{ 115, 0x08 },
{ 123, 0xAB },
{ 124, 0x04 },
{ 6, 0x02 },
{ 133, 0x00 },
{ 134, 0xFE },
{ 135, 0x22 },
{ 136, 0x0B },
{ 137, 0xFF },
{ 138, 0x0F },
{ 139, 0x00 },
{ 140, 0xFE },
{ 141, 0x22 },
{ 142, 0x0B },
{ 143, 0xFF },
{ 144, 0x0F },
{ 145, 0x00 },
{ 146, 0xFE },
{ 147, 0x22 },
{ 148, 0x0B },
{ 149, 0xFF },
{ 150, 0x0F },
{ 202, 0x30 },
{ 30, 0x01 },
{ 4, 0x01 },
{ 31, 0x41 },
};
static struct sharp_state_type sharp_state = { 0 };
static struct msm_panel_common_pdata *lcdc_sharp_pdata;
static void sharp_spi_write_byte(u8 val)
{
int i;
/* Clock should be Low before entering */
for (i = 0; i < 8; i++) {
/* #1: Drive the Data (High or Low) */
if (val & bit_shift[i])
gpio_set_value(spi_mosi, 1);
else
gpio_set_value(spi_mosi, 0);
/* #2: Drive the Clk High and then Low */
gpio_set_value(spi_sclk, 1);
gpio_set_value(spi_sclk, 0);
}
}
static void serigo(u8 reg, u8 data)
{
/* Enable the Chip Select - low */
gpio_set_value(spi_cs, 0);
udelay(1);
/* Transmit register address first, then data */
sharp_spi_write_byte(reg);
/* Idle state of MOSI is Low */
gpio_set_value(spi_mosi, 0);
udelay(1);
sharp_spi_write_byte(data);
gpio_set_value(spi_mosi, 0);
gpio_set_value(spi_cs, 1);
}
static void sharp_spi_init(void)
{
spi_sclk = *(lcdc_sharp_pdata->gpio_num);
spi_cs = *(lcdc_sharp_pdata->gpio_num + 1);
spi_mosi = *(lcdc_sharp_pdata->gpio_num + 2);
spi_miso = *(lcdc_sharp_pdata->gpio_num + 3);
/* Set the output so that we don't disturb the slave device */
gpio_set_value(spi_sclk, 0);
gpio_set_value(spi_mosi, 0);
/* Set the Chip Select deasserted (active low) */
gpio_set_value(spi_cs, 1);
}
static void sharp_disp_powerup(void)
{
if (!sharp_state.disp_powered_up && !sharp_state.display_on)
sharp_state.disp_powered_up = TRUE;
}
static void sharp_disp_on(void)
{
int i;
if (sharp_state.disp_powered_up && !sharp_state.display_on) {
for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
serigo(init_sequence[i].addr,
init_sequence[i].data);
}
mdelay(10);
serigo(31, 0xC1);
mdelay(10);
serigo(31, 0xD9);
serigo(31, 0xDF);
sharp_state.display_on = TRUE;
}
}
static int lcdc_sharp_panel_on(struct platform_device *pdev)
{
if (!sharp_state.disp_initialized) {
lcdc_sharp_pdata->panel_config_gpio(1);
sharp_spi_init();
sharp_disp_powerup();
sharp_disp_on();
sharp_state.disp_initialized = TRUE;
}
return 0;
}
static int lcdc_sharp_panel_off(struct platform_device *pdev)
{
if (sharp_state.disp_powered_up && sharp_state.display_on) {
serigo(4, 0x00);
mdelay(40);
serigo(31, 0xC1);
mdelay(40);
serigo(31, 0x00);
mdelay(100);
sharp_state.display_on = FALSE;
sharp_state.disp_initialized = FALSE;
}
return 0;
}
static int __init sharp_probe(struct platform_device *pdev)
{
if (pdev->id == 0) {
lcdc_sharp_pdata = pdev->dev.platform_data;
return 0;
}
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = sharp_probe,
.driver = {
.name = "lcdc_sharp_wvga",
},
};
static struct msm_fb_panel_data sharp_panel_data = {
.on = lcdc_sharp_panel_on,
.off = lcdc_sharp_panel_off,
};
static struct platform_device this_device = {
.name = "lcdc_sharp_wvga",
.id = 1,
.dev = {
.platform_data = &sharp_panel_data,
}
};
static int __init lcdc_sharp_panel_init(void)
{
int ret;
struct msm_panel_info *pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
if (msm_fb_detect_client("lcdc_sharp_wvga_pt"))
return 0;
#endif
ret = platform_driver_register(&this_driver);
if (ret)
return ret;
pinfo = &sharp_panel_data.panel_info;
pinfo->xres = 480;
pinfo->yres = 800;
pinfo->type = LCDC_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->wait_cycle = 0;
pinfo->bpp = 18;
pinfo->fb_num = 2;
pinfo->clk_rate = 24500000;
pinfo->bl_max = 4;
pinfo->bl_min = 1;
pinfo->lcdc.h_back_porch = 20;
pinfo->lcdc.h_front_porch = 10;
pinfo->lcdc.h_pulse_width = 10;
pinfo->lcdc.v_back_porch = 2;
pinfo->lcdc.v_front_porch = 2;
pinfo->lcdc.v_pulse_width = 2;
pinfo->lcdc.border_clr = 0;
pinfo->lcdc.underflow_clr = 0xff;
pinfo->lcdc.hsync_skew = 0;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
return ret;
}
module_init(lcdc_sharp_panel_init);
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/i2c.h>
#include <linux/delay.h>
#include "msm_fb.h"
#define DEVICE_NAME "sii9022"
#define SII9022_DEVICE_ID 0xB0
struct sii9022_i2c_addr_data{
u8 addr;
u8 data;
};
/* video mode data */
static u8 video_mode_data[] = {
0x00,
0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02,
};
static u8 avi_io_format[] = {
0x09,
0x00, 0x00,
};
/* power state */
static struct sii9022_i2c_addr_data regset0[] = {
{ 0x60, 0x04 },
{ 0x63, 0x00 },
{ 0x1E, 0x00 },
};
static u8 video_infoframe[] = {
0x0C,
0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00,
0xE9, 0x02, 0x04, 0x01, 0x04, 0x06,
};
/* configure audio */
static struct sii9022_i2c_addr_data regset1[] = {
{ 0x26, 0x90 },
{ 0x20, 0x90 },
{ 0x1F, 0x80 },
{ 0x26, 0x80 },
{ 0x24, 0x02 },
{ 0x25, 0x0B },
{ 0xBC, 0x02 },
{ 0xBD, 0x24 },
{ 0xBE, 0x02 },
};
/* enable audio */
static u8 misc_infoframe[] = {
0xBF,
0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/* set HDMI, active */
static struct sii9022_i2c_addr_data regset2[] = {
{ 0x1A, 0x01 },
{ 0x3D, 0x00 },
};
static int send_i2c_data(struct i2c_client *client,
struct sii9022_i2c_addr_data *regset,
int size)
{
int i;
int rc = 0;
for (i = 0; i < size; i++) {
rc = i2c_smbus_write_byte_data(
client,
regset[i].addr, regset[i].data);
if (rc)
break;
}
return rc;
}
static int hdmi_sii_enable(struct i2c_client *client)
{
int rc;
int retries = 10;
int count;
rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00);
if (rc)
goto enable_exit;
do {
msleep(1);
rc = i2c_smbus_read_byte_data(client, 0x1B);
} while ((rc != SII9022_DEVICE_ID) && retries--);
if (rc != SII9022_DEVICE_ID)
return -ENODEV;
rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11);
if (rc)
goto enable_exit;
count = ARRAY_SIZE(video_mode_data);
rc = i2c_master_send(client, video_mode_data, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = i2c_smbus_write_byte_data(client, 0x08, 0x20);
if (rc)
goto enable_exit;
count = ARRAY_SIZE(avi_io_format);
rc = i2c_master_send(client, avi_io_format, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0));
if (rc)
goto enable_exit;
count = ARRAY_SIZE(video_infoframe);
rc = i2c_master_send(client, video_infoframe, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1));
if (rc)
goto enable_exit;
count = ARRAY_SIZE(misc_infoframe);
rc = i2c_master_send(client, misc_infoframe, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2));
if (rc)
goto enable_exit;
return 0;
enable_exit:
printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc);
return rc;
}
static const struct i2c_device_id hmdi_sii_id[] = {
{ DEVICE_NAME, 0 },
{ }
};
static int hdmi_sii_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
return -ENODEV;
rc = hdmi_sii_enable(client);
return rc;
}
static struct i2c_driver hdmi_sii_i2c_driver = {
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
},
.probe = hdmi_sii_probe,
.remove = __exit_p(hdmi_sii_remove),
.id_table = hmdi_sii_id,
};
static int __init lcdc_st15_init(void)
{
int ret;
struct msm_panel_info pinfo;
if (msm_fb_detect_client("lcdc_st15"))
return 0;
pinfo.xres = 1366;
pinfo.yres = 768;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 120;
pinfo.lcdc.h_front_porch = 20;
pinfo.lcdc.h_pulse_width = 40;
pinfo.lcdc.v_back_porch = 25;
pinfo.lcdc.v_front_porch = 1;
pinfo.lcdc.v_pulse_width = 7;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret) {
printk(KERN_ERR "%s: failed to register device!\n", __func__);
goto init_exit;
}
ret = i2c_add_driver(&hdmi_sii_i2c_driver);
if (ret)
printk(KERN_ERR "%s: failed to add i2c driver\n", __func__);
init_exit:
return ret;
}
module_init(lcdc_st15_init);
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
static int __init lcdc_st1_wxga_init(void)
{
int ret;
struct msm_panel_info pinfo;
if (msm_fb_detect_client("lcdc_st1_wxga"))
return 0;
pinfo.xres = 1280;
pinfo.yres = 720;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 124;
pinfo.lcdc.h_front_porch = 110;
pinfo.lcdc.h_pulse_width = 136;
pinfo.lcdc.v_back_porch = 19;
pinfo.lcdc.v_front_porch = 5;
pinfo.lcdc.v_pulse_width = 6;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_st1_wxga_init);
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <mach/gpio.h>
#include <mach/pmic.h>
#include "msm_fb.h"
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
#include "mddihosti.h"
#endif
static int spi_cs;
static int spi_sclk;
static int spi_mosi;
static int spi_miso;
struct toshiba_state_type{
boolean disp_initialized;
boolean display_on;
boolean disp_powered_up;
};
static struct toshiba_state_type toshiba_state = { 0 };
static struct msm_panel_common_pdata *lcdc_toshiba_pdata;
static void toshiba_spi_write_byte(char dc, uint8 data)
{
uint32 bit;
int bnum;
gpio_set_value(spi_sclk, 0); /* clk low */
/* dc: 0 for command, 1 for parameter */
gpio_set_value(spi_mosi, dc);
udelay(1); /* at least 20 ns */
gpio_set_value(spi_sclk, 1); /* clk high */
udelay(1); /* at least 20 ns */
bnum = 8; /* 8 data bits */
bit = 0x80;
while (bnum) {
gpio_set_value(spi_sclk, 0); /* clk low */
if (data & bit)
gpio_set_value(spi_mosi, 1);
else
gpio_set_value(spi_mosi, 0);
udelay(1);
gpio_set_value(spi_sclk, 1); /* clk high */
udelay(1);
bit >>= 1;
bnum--;
}
}
static void toshiba_spi_write(char cmd, uint32 data, int num)
{
char *bp;
gpio_set_value(spi_cs, 1); /* cs high */
/* command byte first */
toshiba_spi_write_byte(0, cmd);
/* followed by parameter bytes */
if (num) {
bp = (char *)&data;;
bp += (num - 1);
while (num) {
toshiba_spi_write_byte(1, *bp);
num--;
bp--;
}
}
gpio_set_value(spi_cs, 0); /* cs low */
udelay(1);
}
void toshiba_spi_read_bytes(char cmd, uint32 *data, int num)
{
uint32 dbit, bits;
int bnum;
gpio_set_value(spi_cs, 1); /* cs high */
/* command byte first */
toshiba_spi_write_byte(0, cmd);
if (num > 1) {
/* extra dc bit */
gpio_set_value(spi_sclk, 0); /* clk low */
udelay(1);
dbit = gpio_get_value(spi_miso);/* dc bit */
udelay(1);
gpio_set_value(spi_sclk, 1); /* clk high */
}
/* followed by data bytes */
bnum = num * 8; /* number of bits */
bits = 0;
while (bnum) {
bits <<= 1;
gpio_set_value(spi_sclk, 0); /* clk low */
udelay(1);
dbit = gpio_get_value(spi_miso);
udelay(1);
gpio_set_value(spi_sclk, 1); /* clk high */
bits |= dbit;
bnum--;
}
*data = bits;
udelay(1);
gpio_set_value(spi_cs, 0); /* cs low */
udelay(1);
}
static void spi_pin_assign(void)
{
/* Setting the Default GPIO's */
spi_sclk = *(lcdc_toshiba_pdata->gpio_num);
spi_cs = *(lcdc_toshiba_pdata->gpio_num + 1);
spi_mosi = *(lcdc_toshiba_pdata->gpio_num + 2);
spi_miso = *(lcdc_toshiba_pdata->gpio_num + 3);
}
static void toshiba_disp_powerup(void)
{
if (!toshiba_state.disp_powered_up && !toshiba_state.display_on) {
/* Reset the hardware first */
/* Include DAC power up implementation here */
toshiba_state.disp_powered_up = TRUE;
}
}
static void toshiba_disp_on(void)
{
uint32 data;
gpio_set_value(spi_cs, 0); /* low */
gpio_set_value(spi_sclk, 1); /* high */
gpio_set_value(spi_mosi, 0);
gpio_set_value(spi_miso, 0);
if (toshiba_state.disp_powered_up && !toshiba_state.display_on) {
toshiba_spi_write(0, 0, 0);
mdelay(7);
toshiba_spi_write(0, 0, 0);
mdelay(7);
toshiba_spi_write(0, 0, 0);
mdelay(7);
toshiba_spi_write(0xba, 0x11, 1);
toshiba_spi_write(0x36, 0x00, 1);
mdelay(1);
toshiba_spi_write(0x3a, 0x60, 1);
toshiba_spi_write(0xb1, 0x5d, 1);
mdelay(1);
toshiba_spi_write(0xb2, 0x33, 1);
toshiba_spi_write(0xb3, 0x22, 1);
mdelay(1);
toshiba_spi_write(0xb4, 0x02, 1);
toshiba_spi_write(0xb5, 0x1e, 1); /* vcs -- adjust brightness */
mdelay(1);
toshiba_spi_write(0xb6, 0x27, 1);
toshiba_spi_write(0xb7, 0x03, 1);
mdelay(1);
toshiba_spi_write(0xb9, 0x24, 1);
toshiba_spi_write(0xbd, 0xa1, 1);
mdelay(1);
toshiba_spi_write(0xbb, 0x00, 1);
toshiba_spi_write(0xbf, 0x01, 1);
mdelay(1);
toshiba_spi_write(0xbe, 0x00, 1);
toshiba_spi_write(0xc0, 0x11, 1);
mdelay(1);
toshiba_spi_write(0xc1, 0x11, 1);
toshiba_spi_write(0xc2, 0x11, 1);
mdelay(1);
toshiba_spi_write(0xc3, 0x3232, 2);
mdelay(1);
toshiba_spi_write(0xc4, 0x3232, 2);
mdelay(1);
toshiba_spi_write(0xc5, 0x3232, 2);
mdelay(1);
toshiba_spi_write(0xc6, 0x3232, 2);
mdelay(1);
toshiba_spi_write(0xc7, 0x6445, 2);
mdelay(1);
toshiba_spi_write(0xc8, 0x44, 1);
toshiba_spi_write(0xc9, 0x52, 1);
mdelay(1);
toshiba_spi_write(0xca, 0x00, 1);
mdelay(1);
toshiba_spi_write(0xec, 0x02a4, 2); /* 0x02a4 */
mdelay(1);
toshiba_spi_write(0xcf, 0x01, 1);
mdelay(1);
toshiba_spi_write(0xd0, 0xc003, 2); /* c003 */
mdelay(1);
toshiba_spi_write(0xd1, 0x01, 1);
mdelay(1);
toshiba_spi_write(0xd2, 0x0028, 2);
mdelay(1);
toshiba_spi_write(0xd3, 0x0028, 2);
mdelay(1);
toshiba_spi_write(0xd4, 0x26a4, 2);
mdelay(1);
toshiba_spi_write(0xd5, 0x20, 1);
mdelay(1);
toshiba_spi_write(0xef, 0x3200, 2);
mdelay(32);
toshiba_spi_write(0xbc, 0x80, 1); /* wvga pass through */
toshiba_spi_write(0x3b, 0x00, 1);
mdelay(1);
toshiba_spi_write(0xb0, 0x16, 1);
mdelay(1);
toshiba_spi_write(0xb8, 0xfff5, 2);
mdelay(1);
toshiba_spi_write(0x11, 0, 0);
mdelay(5);
toshiba_spi_write(0x29, 0, 0);
mdelay(5);
toshiba_state.display_on = TRUE;
}
data = 0;
toshiba_spi_read_bytes(0x04, &data, 3);
printk(KERN_INFO "toshiba_disp_on: id=%x\n", data);
}
static int lcdc_toshiba_panel_on(struct platform_device *pdev)
{
if (!toshiba_state.disp_initialized) {
/* Configure reset GPIO that drives DAC */
if (lcdc_toshiba_pdata->panel_config_gpio)
lcdc_toshiba_pdata->panel_config_gpio(1);
toshiba_disp_powerup();
toshiba_disp_on();
toshiba_state.disp_initialized = TRUE;
}
return 0;
}
static int lcdc_toshiba_panel_off(struct platform_device *pdev)
{
if (toshiba_state.disp_powered_up && toshiba_state.display_on) {
/* Main panel power off (Deep standby in) */
toshiba_spi_write(0x28, 0, 0); /* display off */
mdelay(1);
toshiba_spi_write(0xb8, 0x8002, 2); /* output control */
mdelay(1);
toshiba_spi_write(0x10, 0x00, 1); /* sleep mode in */
mdelay(85); /* wait 85 msec */
toshiba_spi_write(0xb0, 0x00, 1); /* deep standby in */
mdelay(1);
if (lcdc_toshiba_pdata->panel_config_gpio)
lcdc_toshiba_pdata->panel_config_gpio(0);
toshiba_state.display_on = FALSE;
toshiba_state.disp_initialized = FALSE;
}
return 0;
}
static void lcdc_toshiba_set_backlight(struct msm_fb_data_type *mfd)
{
int bl_level;
int ret = -EPERM;
bl_level = mfd->bl_level;
ret = pmic_set_led_intensity(LED_LCD, bl_level);
if (ret)
printk(KERN_WARNING "%s: can't set lcd backlight!\n",
__func__);
}
static int __init toshiba_probe(struct platform_device *pdev)
{
if (pdev->id == 0) {
lcdc_toshiba_pdata = pdev->dev.platform_data;
spi_pin_assign();
return 0;
}
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = toshiba_probe,
.driver = {
.name = "lcdc_toshiba_wvga",
},
};
static struct msm_fb_panel_data toshiba_panel_data = {
.on = lcdc_toshiba_panel_on,
.off = lcdc_toshiba_panel_off,
.set_backlight = lcdc_toshiba_set_backlight,
};
static struct platform_device this_device = {
.name = "lcdc_toshiba_wvga",
.id = 1,
.dev = {
.platform_data = &toshiba_panel_data,
}
};
static int __init lcdc_toshiba_panel_init(void)
{
int ret;
struct msm_panel_info *pinfo;
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
if (mddi_get_client_id() != 0)
return 0;
ret = msm_fb_detect_client("lcdc_toshiba_wvga_pt");
if (ret)
return 0;
#endif
ret = platform_driver_register(&this_driver);
if (ret)
return ret;
pinfo = &toshiba_panel_data.panel_info;
pinfo->xres = 480;
pinfo->yres = 800;
pinfo->type = LCDC_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->wait_cycle = 0;
pinfo->bpp = 18;
pinfo->fb_num = 2;
/* 30Mhz mdp_lcdc_pclk and mdp_lcdc_pad_pcl */
pinfo->clk_rate = 27648000;
pinfo->bl_max = 15;
pinfo->bl_min = 1;
pinfo->lcdc.h_back_porch = 184; /* hsw = 8 + hbp=184 */
pinfo->lcdc.h_front_porch = 4;
pinfo->lcdc.h_pulse_width = 8;
pinfo->lcdc.v_back_porch = 2; /* vsw=1 + vbp = 2 */
pinfo->lcdc.v_front_porch = 3;
pinfo->lcdc.v_pulse_width = 1;
pinfo->lcdc.border_clr = 0; /* blk */
pinfo->lcdc.underflow_clr = 0xff; /* blue */
pinfo->lcdc.hsync_skew = 0;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
return ret;
}
device_initcall(lcdc_toshiba_panel_init);
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
static int __init lcdc_wxga_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
if (msm_fb_detect_client("lcdc_wxga"))
return 0;
#endif
pinfo.xres = 1280;
pinfo.yres = 720;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 124;
pinfo.lcdc.h_front_porch = 110;
pinfo.lcdc.h_pulse_width = 136;
pinfo.lcdc.v_back_porch = 19;
pinfo.lcdc.v_front_porch = 5;
pinfo.lcdc.v_pulse_width = 6;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_wxga_init);
/* drivers/video/msm/logo.c
*
* Show Logo in RLE 565 format
*
* Copyright (C) 2008 Google Incorporated
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fb.h>
#include <linux/vt_kern.h>
#include <linux/unistd.h>
#include <linux/syscalls.h>
#include <linux/irq.h>
#include <asm/system.h>
#define fb_width(fb) ((fb)->var.xres)
#define fb_height(fb) ((fb)->var.yres)
#define fb_size(fb) ((fb)->var.xres * (fb)->var.yres * 2)
static void memset16(void *_ptr, unsigned short val, unsigned count)
{
unsigned short *ptr = _ptr;
count >>= 1;
while (count--)
*ptr++ = val;
}
/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
int load_565rle_image(char *filename)
{
struct fb_info *info;
int fd, err = 0;
unsigned count, max;
unsigned short *data, *bits, *ptr;
info = registered_fb[0];
if (!info) {
printk(KERN_WARNING "%s: Can not access framebuffer\n",
__func__);
return -ENODEV;
}
fd = sys_open(filename, O_RDONLY, 0);
if (fd < 0) {
printk(KERN_WARNING "%s: Can not open %s\n",
__func__, filename);
return -ENOENT;
}
count = (unsigned)sys_lseek(fd, (off_t)0, 2);
if (count == 0) {
sys_close(fd);
err = -EIO;
goto err_logo_close_file;
}
sys_lseek(fd, (off_t)0, 0);
data = kmalloc(count, GFP_KERNEL);
if (!data) {
printk(KERN_WARNING "%s: Can not alloc data\n", __func__);
err = -ENOMEM;
goto err_logo_close_file;
}
if ((unsigned)sys_read(fd, (char *)data, count) != count) {
err = -EIO;
goto err_logo_free_data;
}
max = fb_width(info) * fb_height(info);
ptr = data;
bits = (unsigned short *)(info->screen_base);
while (count > 3) {
unsigned n = ptr[0];
if (n > max)
break;
memset16(bits, ptr[1], n << 1);
bits += n;
max -= n;
ptr += 2;
count -= 4;
}
err_logo_free_data:
kfree(data);
err_logo_close_file:
sys_close(fd);
return err;
}
EXPORT_SYMBOL(load_565rle_image);
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include "msm_fb.h"
#include "mddihosti.h"
#include "mddihost.h"
#include <mach/gpio.h>
#include <mach/clk.h>
static int mddi_probe(struct platform_device *pdev);
static int mddi_remove(struct platform_device *pdev);
static int mddi_off(struct platform_device *pdev);
static int mddi_on(struct platform_device *pdev);
static int mddi_suspend(struct platform_device *pdev, pm_message_t state);
static int mddi_resume(struct platform_device *pdev);
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mddi_early_suspend(struct early_suspend *h);
static void mddi_early_resume(struct early_suspend *h);
#endif
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
static struct clk *mddi_clk;
static struct clk *mddi_pclk;
static struct mddi_platform_data *mddi_pdata;
static struct platform_driver mddi_driver = {
.probe = mddi_probe,
.remove = mddi_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
#ifdef CONFIG_PM
.suspend = mddi_suspend,
.resume = mddi_resume,
#endif
#endif
.suspend_late = NULL,
.resume_early = NULL,
.shutdown = NULL,
.driver = {
.name = "mddi",
},
};
extern int int_mddi_pri_flag;
static int mddi_off(struct platform_device *pdev)
{
int ret = 0;
ret = panel_next_off(pdev);
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(0);
return ret;
}
static int mddi_on(struct platform_device *pdev)
{
int ret = 0;
u32 clk_rate;
struct msm_fb_data_type *mfd;
mfd = platform_get_drvdata(pdev);
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(1);
clk_rate = mfd->fbi->var.pixclock;
clk_rate = min(clk_rate, mfd->panel_info.clk_max);
if (mddi_pdata &&
mddi_pdata->mddi_sel_clk &&
mddi_pdata->mddi_sel_clk(&clk_rate))
printk(KERN_ERR
"%s: can't select mddi io clk targate rate = %d\n",
__func__, clk_rate);
if (clk_set_min_rate(mddi_clk, clk_rate) < 0)
printk(KERN_ERR "%s: clk_set_min_rate failed\n",
__func__);
ret = panel_next_on(pdev);
return ret;
}
static int mddi_resource_initialized;
static int mddi_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
int rc;
resource_size_t size ;
u32 clk_rate;
if ((pdev->id == 0) && (pdev->num_resources >= 0)) {
mddi_pdata = pdev->dev.platform_data;
size = resource_size(&pdev->resource[0]);
msm_pmdh_base = ioremap(pdev->resource[0].start, size);
MSM_FB_INFO("primary mddi base phy_addr = 0x%x virt = 0x%x\n",
pdev->resource[0].start, (int) msm_pmdh_base);
if (unlikely(!msm_pmdh_base))
return -ENOMEM;
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(1);
mddi_resource_initialized = 1;
return 0;
}
if (!mddi_resource_initialized)
return -EPERM;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
return -ENOMEM;
mdp_dev = platform_device_alloc("mdp", pdev->id);
if (!mdp_dev)
return -ENOMEM;
/*
* link to the latest pdev
*/
mfd->pdev = mdp_dev;
mfd->dest = DISPLAY_LCD;
/*
* alloc panel device data
*/
if (platform_device_add_data
(mdp_dev, pdev->dev.platform_data,
sizeof(struct msm_fb_panel_data))) {
printk(KERN_ERR "mddi_probe: platform_device_add_data failed!\n");
platform_device_put(mdp_dev);
return -ENOMEM;
}
/*
* data chain
*/
pdata = mdp_dev->dev.platform_data;
pdata->on = mddi_on;
pdata->off = mddi_off;
pdata->next = pdev;
/*
* get/set panel specific fb info
*/
mfd->panel_info = pdata->panel_info;
mfd->fb_imgType = MDP_RGB_565;
clk_rate = mfd->panel_info.clk_max;
if (mddi_pdata &&
mddi_pdata->mddi_sel_clk &&
mddi_pdata->mddi_sel_clk(&clk_rate))
printk(KERN_ERR
"%s: can't select mddi io clk targate rate = %d\n",
__func__, clk_rate);
if (clk_set_max_rate(mddi_clk, clk_rate) < 0)
printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__);
mfd->panel_info.clk_rate = mfd->panel_info.clk_min;
/*
* set driver data
*/
platform_set_drvdata(mdp_dev, mfd);
/*
* register in mdp driver
*/
rc = platform_device_add(mdp_dev);
if (rc)
goto mddi_probe_err;
pdev_list[pdev_list_cnt++] = pdev;
#ifdef CONFIG_HAS_EARLYSUSPEND
mfd->mddi_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
mfd->mddi_early_suspend.suspend = mddi_early_suspend;
mfd->mddi_early_suspend.resume = mddi_early_resume;
register_early_suspend(&mfd->mddi_early_suspend);
#endif
return 0;
mddi_probe_err:
platform_device_put(mdp_dev);
return rc;
}
static int mddi_pad_ctrl;
static int mddi_power_locked;
static int mddi_is_in_suspend;
void mddi_disable(int lock)
{
mddi_host_type host_idx = MDDI_HOST_PRIM;
if (mddi_power_locked)
return;
if (lock)
mddi_power_locked = 1;
if (mddi_host_timer.function)
del_timer_sync(&mddi_host_timer);
mddi_pad_ctrl = mddi_host_reg_in(PAD_CTL);
mddi_host_reg_out(PAD_CTL, 0x0);
if (clk_set_min_rate(mddi_clk, 0) < 0)
printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__);
clk_disable(mddi_clk);
if (mddi_pclk)
clk_disable(mddi_pclk);
disable_irq(INT_MDDI_PRI);
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(0);
}
static int mddi_suspend(struct platform_device *pdev, pm_message_t state)
{
if (mddi_is_in_suspend)
return 0;
mddi_is_in_suspend = 1;
mddi_disable(0);
return 0;
}
static int mddi_resume(struct platform_device *pdev)
{
mddi_host_type host_idx = MDDI_HOST_PRIM;
if (!mddi_is_in_suspend)
return 0;
mddi_is_in_suspend = 0;
if (mddi_power_locked)
return 0;
enable_irq(INT_MDDI_PRI);
clk_enable(mddi_clk);
if (mddi_pclk)
clk_enable(mddi_pclk);
mddi_host_reg_out(PAD_CTL, mddi_pad_ctrl);
if (mddi_host_timer.function)
mddi_host_timer_service(0);
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mddi_early_suspend(struct early_suspend *h)
{
pm_message_t state;
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
mddi_early_suspend);
state.event = PM_EVENT_SUSPEND;
mddi_suspend(mfd->pdev, state);
}
static void mddi_early_resume(struct early_suspend *h)
{
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
mddi_early_suspend);
mddi_resume(mfd->pdev);
}
#endif
static int mddi_remove(struct platform_device *pdev)
{
if (mddi_host_timer.function)
del_timer_sync(&mddi_host_timer);
iounmap(msm_pmdh_base);
return 0;
}
static int mddi_register_driver(void)
{
return platform_driver_register(&mddi_driver);
}
static int __init mddi_driver_init(void)
{
int ret;
mddi_clk = clk_get(NULL, "mddi_clk");
if (IS_ERR(mddi_clk)) {
printk(KERN_ERR "can't find mddi_clk \n");
return PTR_ERR(mddi_clk);
}
clk_enable(mddi_clk);
mddi_pclk = clk_get(NULL, "mddi_pclk");
if (IS_ERR(mddi_pclk))
mddi_pclk = NULL;
else
clk_enable(mddi_pclk);
ret = mddi_register_driver();
if (ret) {
clk_disable(mddi_clk);
clk_put(mddi_clk);
if (mddi_pclk) {
clk_disable(mddi_pclk);
clk_put(mddi_pclk);
}
printk(KERN_ERR "mddi_register_driver() failed!\n");
return ret;
}
mddi_init();
return ret;
}
module_init(mddi_driver_init);
This diff is collapsed.
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
static int mddi_ext_lcd_on(struct platform_device *pdev);
static int mddi_ext_lcd_off(struct platform_device *pdev);
static int mddi_ext_lcd_on(struct platform_device *pdev)
{
return 0;
}
static int mddi_ext_lcd_off(struct platform_device *pdev)
{
return 0;
}
static int __init mddi_ext_lcd_probe(struct platform_device *pdev)
{
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = mddi_ext_lcd_probe,
.driver = {
.name = "extmddi_svga",
},
};
static struct msm_fb_panel_data mddi_ext_lcd_panel_data = {
.panel_info.xres = 800,
.panel_info.yres = 600,
.panel_info.type = EXT_MDDI_PANEL,
.panel_info.pdest = DISPLAY_1,
.panel_info.wait_cycle = 0,
.panel_info.bpp = 18,
.panel_info.fb_num = 2,
.panel_info.clk_rate = 122880000,
.panel_info.clk_min = 120000000,
.panel_info.clk_max = 125000000,
.on = mddi_ext_lcd_on,
.off = mddi_ext_lcd_off,
};
static struct platform_device this_device = {
.name = "extmddi_svga",
.id = 0,
.dev = {
.platform_data = &mddi_ext_lcd_panel_data,
}
};
static int __init mddi_ext_lcd_init(void)
{
int ret;
struct msm_panel_info *pinfo;
ret = platform_driver_register(&this_driver);
if (!ret) {
pinfo = &mddi_ext_lcd_panel_data.panel_info;
pinfo->lcd.vsync_enable = FALSE;
pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
}
return ret;
}
module_init(mddi_ext_lcd_init);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment