/* linux/arch/arm/mach-msm/board-supersonic-panel.c * * Copyright (C) 2008 HTC Corporation. * Author: Jay Tu * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include /* #include */ #include "board-supersonic.h" #include "devices.h" #include "proc_comm.h" #if 1 #define B(s...) printk(s) #else #define B(s...) do {} while(0) #endif extern int panel_type; enum { PANEL_SHARP, PANEL_AUO, }; static struct cabc_t { struct led_classdev lcd_backlight; struct msm_mddi_client_data *client_data; struct mutex lock; unsigned long status; } cabc; enum { GATE_ON = 1 << 0, }; static struct vreg *vreg_lcd_2v8; static struct vreg *vreg_lcd_1v8; #define REG_WAIT (0xffff) struct nov_regs { unsigned reg; unsigned val; } nov_init_seq[] = { {0xc000, 0x86}, {0xc001, 0x00}, {0xc002, 0x86}, {0xc003, 0x00}, {0xc100, 0x40}, {0xc200, 0x02}, {0xc202, 0x32}, {0xe000, 0x0e}, {0xe001, 0x34}, {0xe002, 0x3F}, {0xe003, 0x49}, {0xe004, 0x1D}, {0xe005, 0x2C}, {0xe006, 0x5F}, {0xe007, 0x3A}, {0xe008, 0x20}, {0xe009, 0x28}, {0xe00a, 0x80}, {0xe00b, 0x13}, {0xe00c, 0x32}, {0xe00d, 0x56}, {0xe00e, 0x79}, {0xe00f, 0xB8}, {0xe010, 0x55}, {0xe011, 0x57}, {0xe100, 0x0e}, {0xe101, 0x34}, {0xe102, 0x3F}, {0xe103, 0x49}, {0xe104, 0x1D}, {0xe105, 0x2C}, {0xe106, 0x5F}, {0xe107, 0x3A}, {0xe108, 0x20}, {0xe109, 0x28}, {0xe10a, 0x80}, {0xe10b, 0x13}, {0xe10c, 0x32}, {0xe10d, 0x56}, {0xe10e, 0x79}, {0xe10f, 0xB8}, {0xe110, 0x55}, {0xe111, 0x57}, {0xe200, 0x0E}, {0xe201, 0x34}, {0xe202, 0x3F}, {0xe203, 0x49}, {0xe204, 0x1D}, {0xe205, 0x2C}, {0xe206, 0x5F}, {0xe207, 0x3A}, {0xe208, 0x20}, {0xe209, 0x28}, {0xe20A, 0x80}, {0xe20B, 0x13}, {0xe20C, 0x32}, {0xe20D, 0x56}, {0xe20E, 0x79}, {0xe20F, 0xB8}, {0xe210, 0x55}, {0xe211, 0x57}, {0xe300, 0x0E}, {0xe301, 0x34}, {0xe302, 0x3F}, {0xe303, 0x49}, {0xe304, 0x1D}, {0xe305, 0x2C}, {0xe306, 0x5F}, {0xe307, 0x3A}, {0xe308, 0x20}, {0xe309, 0x28}, {0xe30A, 0x80}, {0xe30B, 0x13}, {0xe30C, 0x32}, {0xe30D, 0x56}, {0xe30E, 0x79}, {0xe30F, 0xB8}, {0xe310, 0x55}, {0xe311, 0x57}, {0xe400, 0x0E}, {0xe401, 0x34}, {0xe402, 0x3F}, {0xe403, 0x49}, {0xe404, 0x1D}, {0xe405, 0x2C}, {0xe406, 0x5F}, {0xe407, 0x3A}, {0xe408, 0x20}, {0xe409, 0x28}, {0xe40A, 0x80}, {0xe40B, 0x13}, {0xe40C, 0x32}, {0xe40D, 0x56}, {0xe40E, 0x79}, {0xe40F, 0xB8}, {0xe410, 0x55}, {0xe411, 0x57}, {0xe500, 0x0E}, {0xe501, 0x34}, {0xe502, 0x3F}, {0xe503, 0x49}, {0xe504, 0x1D}, {0xe505, 0x2C}, {0xe506, 0x5F}, {0xe507, 0x3A}, {0xe508, 0x20}, {0xe509, 0x28}, {0xe50A, 0x80}, {0xe50B, 0x13}, {0xe50C, 0x32}, {0xe50D, 0x56}, {0xe50E, 0x79}, {0xe50F, 0xB8}, {0xe510, 0x55}, {0xe511, 0x57}, {0x3a00, 0x05}, /* cabc */ {0x4e00, 0x00}, {0x5e00, 0x00}, {0x6a01, 0x00}, {0x6a02, 0x03}, {0x5100, 0xff}, {0x5301, 0x10}, {0x6A18, 0xff}, {0x6A17, 0x01}, {0xF402, 0x14}, {0x3500, 0x00}, {0x1100, 0x0}, {REG_WAIT, 120}, }; struct s1d_regs { unsigned reg; unsigned val; } s1d13775_init_seq[] = { {0x001C, 0x1500}, {0x0020, 0x3047}, {0x0024, 0x401A}, {0x0028, 0x031A}, {0x002C, 0x0001}, {REG_WAIT, 0x0004}, /* increase delay 1ms -> 4ms */ {0x0084, 0x0215}, {0x0088, 0x0038}, {0x008C, 0x2113}, {0x002C, 0x0002}, {REG_WAIT, 0x0004}, /* increase delay 1ms -> 4ms */ {0x002C, 0x0003}, {0x0100, 0x3702}, {0x0104, 0x0180}, {0x0140, 0x003F}, {0x0144, 0x00EF}, {0x0148, 0x0016}, {0x014C, 0x0005}, {0x0150, 0x0006}, {0x0154, 0x032B}, {0x0158, 0x031F}, {0x015C, 0x0009}, {0x0160, 0x0002}, {0x0164, 0x0003}, {0x0168, 0x00A2}, {0x0180, 0x0057}, {0x0184, 0x00DB}, {0x0188, 0x00E3}, {0x018C, 0x0000}, {0x0190, 0x0000}, {0x0280, 0x0000}, {0x0284, 0x0002}, {0x0288, 0x0000}, {0x028C, 0x0001}, {0x0294, 0x0000}, {0x0400, 0x8000}, {0x0404, 0x1001}, {0x0480, 0x0001}, {0x0500, 0x0000}, {0x0504, 0x0011}, {0x0508, 0x0000}, {0x0510, 0x0000}, {0x0518, 0x002E}, {0x051C, 0x00c7}, {0x0520, 0x01DF}, {0x0524, 0x031f}, {0x0528, 0x0000}, {0x052C, 0x0000}, {0x0530, 0x0000}, {0x0534, 0x0000}, {0x0604, 0x0108}, {0x060C, 0x0000}, {0x0610, 0x00ff}, {0x0648, 0x0020}, {0x0800, 0x0000}, {0x0804, 0x000A}, {0x0808, 0x0400}, {0x080C, 0x0400}, {0x0814, 0x0000}, {0x081C, 0x0000}, {0x0824, 0x002E}, {0x0828, 0x00C7}, {0x082C, 0x01DF}, {0x0830, 0x031F}, {0x0834, 0x0000}, {0x0838, 0x0000}, {0x083C, 0x0000}, {0x0840, 0x0000}, {0x0844, 0x01DF}, {0x0848, 0x031F}, {0x0870, 0x0064}, {0x0874, 0x0064}, {0x0878, 0x00C7}, {0x087C, 0x00C7}, {0x1410, 0x0004}, {0x1414, 0x00FF}, {0x1420, 0x0000}, {0x1424, 0x0000}, {0x1428, 0x01DF}, {0x142C, 0x031F}, {0x1430, 0xDC00}, {0x1434, 0x0005}, {0x1440, 0x0000}, {0x1444, 0x0000}, {0x1448, 0x01DF}, {0x144C, 0x031F}, {0x1450, 0x0000}, {0x1454, 0x0000}, {0x1458, 0x01DF}, {0x145C, 0x031F}, {0x1460, 0x0000}, {0x1464, 0x0000}, {0x1468, 0x01DF}, {0x146C, 0x031F}, {0x1470, 0x0000}, {0x1474, 0x0000}, {0x1478, 0x01DF}, {0x147C, 0x031F}, {0x14A4, 0x0110}, {0x14A8, 0xAFC8}, {0x14AC, 0x0FF0}, {0x14B0, 0x0202}, {0x14B4, 0x0080}, {0x14A0, 0x0002}, {0x1508, 0x0000}, {0x150C, 0x0000}, {0x1510, 0x0000}, {0x1514, 0x0000}, {0x1520, 0x0000}, {0x1524, 0x0000}, {0x1528, 0x0000}, {0x152C, 0x0000}, {0x1530, 0x0000}, {0x1534, 0x0000}, {0x1538, 0x0000}, {0x153C, 0x0000}, {0x1540, 0x0000}, {0x1544, 0x0000}, {0x1548, 0x0000}, {0x154C, 0x0000}, {0x1550, 0x0000}, {0x1554, 0x0000}, {0x1558, 0x0000}, {0x1600, 0x0000}, {0x1604, 0x0020}, {0x1608, 0x0040}, {0x160C, 0x0060}, {0x1610, 0x0080}, {0x1614, 0x00A0}, {0x1618, 0x00C0}, {0x161C, 0x00E0}, {0x1620, 0x0100}, {0x1624, 0x0000}, {0x1628, 0x0020}, {0x162C, 0x0040}, {0x1630, 0x0060}, {0x1634, 0x0080}, {0x1638, 0x00A0}, {0x163C, 0x00C0}, {0x1640, 0x00E0}, {0x1644, 0x0100}, {0x1648, 0x0000}, {0x164C, 0x0020}, {0x1650, 0x0040}, {0x1654, 0x0060}, {0x1658, 0x0080}, {0x165C, 0x00A0}, {0x1660, 0x00C0}, {0x1664, 0x00E0}, {0x1668, 0x0100}, {0x1680, 0x0000}, {0x1684, 0x0000}, {0x1688, 0x0000}, {0x168C, 0x0000}, {0x1694, 0x0000}, {0x16A0, 0x0000}, {0x16A4, 0x0000}, {0x16A8, 0x0000}, {0x16AC, 0x0000}, {0x16B4, 0x0000}, {0x16C0, 0x0000}, {0x16C4, 0x0000}, {0x16C8, 0x0000}, {0x16CC, 0x0000}, {0x16D4, 0x0000}, {0x16E0, 0x0000}, {0x16E4, 0x0000}, {0x16E8, 0x0000}, {0x16EC, 0x0000}, {0x16F4, 0x0000}, {0x1700, 0x0000}, {0x1704, 0x0000}, {0x1708, 0x0000}, {0x170C, 0x0000}, {0x1714, 0x0000}, {0x1720, 0x0000}, {0x1724, 0x0000}, {0x1728, 0x0000}, {0x172C, 0x0000}, {0x1734, 0x0000}, {0x1740, 0x0000}, {0x1744, 0x0000}, {0x1748, 0x0000}, {0x174C, 0x0000}, {0x1754, 0x0000}, {0x1760, 0x0000}, {0x1764, 0x0000}, {0x1768, 0x0000}, {0x176C, 0x0000}, {0x1774, 0x0000}, {0x0300, 0x7000}, {0x0304, 0x0000}, {0x0308, 0x0000}, {0x030C, 0x0000}, {0x0310, 0x0000}, {0x0314, 0x0000}, {0x0318, 0xF7FF}, {0x031C, 0xFFFF}, {0x0320, 0x000F}, {0x0324, 0x0000}, {0x0328, 0x0000}, {0x032C, 0x0000}, }; struct s1d_regs pwm_seq[] = { {0x001C, 0x0010}, {0x14A0, 0x0001}, {0x14A4, 0x0110}, {0x14B0, 0x3030}, {0x14A8, 0x09C4}, {0x14AC, 0x0FF0}, }; extern int qspi_send_9bit(unsigned char id, unsigned data); extern int qspi_send_16bit(unsigned char id, unsigned data); static void suc_set_brightness(struct led_classdev *led_cdev, enum led_brightness val) { struct msm_mddi_client_data *client = cabc.client_data; unsigned int shrink_br = val; printk(KERN_DEBUG "set brightness = %d\n", val); if (test_bit(GATE_ON, &cabc.status) == 0) return; if (val < 30) shrink_br = 5; else if ((val >= 30) && (val <= 143)) shrink_br = 104 * (val - 30) / 113 + 5; else shrink_br = 145 * (val - 144) / 111 + 110; mutex_lock(&cabc.lock); if (panel_type == PANEL_SHARP) { int i, reg, val; for (i = 0; i < ARRAY_SIZE(pwm_seq); i++) { reg = pwm_seq[i].reg; val = pwm_seq[i].val; if (reg == REG_WAIT) hr_msleep(val); else client->remote_write(client, cpu_to_le32(val), reg); } client->remote_write(client, shrink_br, 0x14B4); } else { qspi_send_16bit(0x1, 0x55); qspi_send_16bit(0x0, 0x00); qspi_send_16bit(0x2, 0x00); qspi_send_16bit(0x1, 0x51); qspi_send_16bit(0x0, 0x00); qspi_send_16bit(0x2, shrink_br); } mutex_unlock(&cabc.lock); } static enum led_brightness suc_get_brightness(struct led_classdev *led_cdev) { struct msm_mddi_client_data *client = cabc.client_data; if (panel_type == PANEL_SHARP) return client->remote_read(client, 0x14B4); else return client->remote_read(client, 0x5100); } #define DEFAULT_BRIGHTNESS 100 static void suc_backlight_switch(int on) { enum led_brightness val; if (on) { printk(KERN_DEBUG "turn on backlight\n"); set_bit(GATE_ON, &cabc.status); val = cabc.lcd_backlight.brightness; /* LED core uses get_brightness for default value * If the physical layer is not ready, we should * not count on it */ if (val == 0) val = DEFAULT_BRIGHTNESS; suc_set_brightness(&cabc.lcd_backlight, val); } else { clear_bit(GATE_ON, &cabc.status); suc_set_brightness(&cabc.lcd_backlight, 0); } } static int suc_backlight_probe(struct platform_device *pdev) { int err = -EIO; mutex_init(&cabc.lock); cabc.client_data = pdev->dev.platform_data; cabc.lcd_backlight.name = "lcd-backlight"; cabc.lcd_backlight.brightness_set = suc_set_brightness; cabc.lcd_backlight.brightness_get = suc_get_brightness; err = led_classdev_register(&pdev->dev, &cabc.lcd_backlight); if (err) goto err_register_lcd_bl; return 0; err_register_lcd_bl: led_classdev_unregister(&cabc.lcd_backlight); return err; } /* ------------------------------------------------------------------- */ static struct resource resources_msm_fb[] = { { .start = MSM_FB_BASE, .end = MSM_FB_BASE + MSM_FB_SIZE - 1, .flags = IORESOURCE_MEM, }, }; static int supersonic_mddi_init(struct msm_mddi_bridge_platform_data *bridge_data, struct msm_mddi_client_data *client_data) { int i = 0, ret; unsigned reg, val; if (panel_type == PANEL_SHARP) { client_data->auto_hibernate(client_data, 0); for (i = 0; i < ARRAY_SIZE(s1d13775_init_seq); i++) { reg = s1d13775_init_seq[i].reg; val = s1d13775_init_seq[i].val; if (reg == REG_WAIT) hr_msleep(val); else client_data->remote_write(client_data, cpu_to_le32(val), reg); } client_data->auto_hibernate(client_data, 1); struct spi_cmd { unsigned char reg; unsigned char val; unsigned int delay; } sharp_spi[] = { {0x0, 0x11, 100}, {0x0, 0xB9, 0}, {0x1, 0xFF, 0}, {0x1, 0x83, 0}, {0x1, 0x63, 0}, {0x0, 0x3A, 0}, {0x1, 0x50, 0}, }; /* FIXME */ for (i = 0; i < ARRAY_SIZE(sharp_spi); i++) { ret = qspi_send_9bit(sharp_spi[i].reg, sharp_spi[i].val); if (ret < 0) printk("%s: spi_write fail!\n", __func__); else if (sharp_spi[i].delay) hr_msleep(sharp_spi[i].delay); } } else { client_data->auto_hibernate(client_data, 0); for (i = 0; i < ARRAY_SIZE(nov_init_seq); i++) { reg = cpu_to_le32(nov_init_seq[i].reg); val = cpu_to_le32(nov_init_seq[i].val); if (reg == REG_WAIT) msleep(val); else client_data->remote_write(client_data, val, reg); } client_data->auto_hibernate(client_data, 1); } return 0; } static int supersonic_mddi_uninit(struct msm_mddi_bridge_platform_data *bridge_data, struct msm_mddi_client_data *client_data) { if (panel_type == PANEL_SHARP) { int i, ret; struct spi_cmd { unsigned char reg; unsigned char val; unsigned int delay; } sharp_spi[] = { {0x0, 0x28, 0}, {0x0, 0x10, 100}, }; /* FIXME */ for (i = 0; i < ARRAY_SIZE(sharp_spi); i++) { ret = qspi_send_9bit(sharp_spi[i].reg, sharp_spi[i].val); if (ret < 0) printk("%s: spi_write fail!\n", __func__); else if (sharp_spi[i].delay) hr_msleep(sharp_spi[i].delay); } } else client_data->remote_write(client_data, 0, 0x2800); return 0; } /* FIXME: remove after XA03 */ static int backlight_control(int on) { struct i2c_adapter *adap = i2c_get_adapter(0); struct i2c_msg msg; u8 buf[] = {0x90, 0x00, 0x00, 0x08}; int ret = -EIO, max_retry = 3; msg.addr = 0xcc >> 1; msg.flags = 0; msg.len = sizeof(buf); msg.buf = buf; if (on == 0) buf[0] = 0x91; while (max_retry--) { ret = i2c_transfer(adap, &msg, 1); if (ret != 1) msleep(1); else { ret = 0; break; } ret = -EIO; } if (ret) printk(KERN_ERR "backlight control fail\n"); return 0; } static int supersonic_panel_blank(struct msm_mddi_bridge_platform_data *bridge_data, struct msm_mddi_client_data *client_data) { B(KERN_DEBUG "%s\n", __func__); suc_backlight_switch(LED_OFF); backlight_control(0); return 0; } static int supersonic_panel_unblank(struct msm_mddi_bridge_platform_data *bridge_data, struct msm_mddi_client_data *client_data) { B(KERN_DEBUG "%s\n", __func__); if (panel_type == PANEL_AUO) { suc_backlight_switch(LED_FULL); client_data->remote_write(client_data, 0x00, 0x2900); msleep(100); client_data->remote_write(client_data, 0x24, 0x5300); } else { suc_backlight_switch(LED_FULL); client_data->remote_write(client_data, 0x4000, 0x0600); msleep(10); qspi_send_9bit(0x0, 0x29); client_data->remote_write(client_data, 0x7000, 0x0324); client_data->remote_write(client_data, 0x4000, 0x0600); } backlight_control(1); return 0; } static struct msm_mddi_bridge_platform_data novatec_client_data = { .init = supersonic_mddi_init, .uninit = supersonic_mddi_uninit, .blank = supersonic_panel_blank, .unblank = supersonic_panel_unblank, .fb_data = { .xres = 480, .yres = 800, .width = 48, .height = 80, .output_format = 0, }, .panel_conf = { .caps = MSMFB_CAP_CABC, }, }; static struct msm_mddi_bridge_platform_data epson_client_data = { .init = supersonic_mddi_init, .uninit = supersonic_mddi_uninit, .blank = supersonic_panel_blank, .unblank = supersonic_panel_unblank, .fb_data = { .xres = 480, .yres = 800, .width = 48, .height = 80, .output_format = 0, }, .panel_conf = { .caps = MSMFB_CAP_CABC, }, }; #define SPI_CLK 17 #define SPI_DO 18 #define SPI_DI 19 #define SPI_CS 20 #define LCM_GPIO_CFG(gpio, func) \ PCOM_GPIO_CFG(gpio, func, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_16MA) static uint32_t spi_on_gpio_table[] = { LCM_GPIO_CFG(SPI_CLK, 1), LCM_GPIO_CFG(SPI_CS, 1), LCM_GPIO_CFG(SPI_DO, 1), PCOM_GPIO_CFG(SPI_DI, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_16MA), }; static uint32_t spi_off_gpio_table[] = { LCM_GPIO_CFG(SPI_CLK, 0), LCM_GPIO_CFG(SPI_CS, 0), LCM_GPIO_CFG(SPI_DO, 0), PCOM_GPIO_CFG(SPI_DI, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_16MA), }; static int spi_gpio_switch(int on) { config_gpio_table( !!on ? spi_on_gpio_table : spi_off_gpio_table, ARRAY_SIZE(spi_on_gpio_table)); return 0; } static void mddi_novatec_power(struct msm_mddi_client_data *client_data, int on) { unsigned id, on_off = 1; B(KERN_DEBUG "%s: power %s.\n", __func__, on ? "on" : "off"); if (on) { on_off = 1; /* 2V8 */ id = PM_VREG_PDOWN_SYNT_ID; msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); vreg_enable(vreg_lcd_2v8); /* 1V8 */ id = PM_VREG_PDOWN_AUX_ID; msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); vreg_enable(vreg_lcd_1v8); hr_msleep(15); gpio_set_value(SUPERSONIC_LCD_RST, 1); hr_msleep(1); gpio_set_value(SUPERSONIC_LCD_RST, 0); hr_msleep(5); gpio_set_value(SUPERSONIC_LCD_RST, 1); hr_msleep(50); spi_gpio_switch(1); } else { on_off = 0; gpio_set_value(SUPERSONIC_LCD_RST, 0); hr_msleep(120); /* 1V8 */ id = PM_VREG_PDOWN_AUX_ID; msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); vreg_disable(vreg_lcd_1v8); /* 2V8 */ id = PM_VREG_PDOWN_SYNT_ID; msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); vreg_disable(vreg_lcd_2v8); spi_gpio_switch(0); } } static void mddi_epson_power(struct msm_mddi_client_data *client_data, int on) { unsigned id, on_off = 1; B(KERN_DEBUG "%s: power %s.\n", __func__, on ? "on" : "off"); if (on) { on_off = 1; /* 2V8 */ gpio_set_value(149, 1); id = PM_VREG_PDOWN_SYNT_ID; msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); vreg_enable(vreg_lcd_2v8); hr_msleep(5); /* 1V8 */ gpio_set_value(16, 1); id = PM_VREG_PDOWN_AUX_ID; msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); vreg_enable(vreg_lcd_1v8); hr_msleep(10); gpio_set_value(151, 1); hr_msleep(2); gpio_set_value(SUPERSONIC_LCD_RST, 1); hr_msleep(1); gpio_set_value(SUPERSONIC_LCD_RST, 0); hr_msleep(5); gpio_set_value(SUPERSONIC_LCD_RST, 1); hr_msleep(50); spi_gpio_switch(1); } else { on_off = 0; gpio_set_value(SUPERSONIC_LCD_RST, 0); hr_msleep(2); gpio_set_value(151, 0); hr_msleep(120); /* 1V8 */ gpio_set_value(16, 0); id = PM_VREG_PDOWN_AUX_ID; msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); vreg_disable(vreg_lcd_1v8); hr_msleep(5); /* 2V8 */ gpio_set_value(149, 0); id = PM_VREG_PDOWN_SYNT_ID; msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); vreg_disable(vreg_lcd_2v8); spi_gpio_switch(0); } } static struct msm_mddi_platform_data mddi_pdata = { .clk_rate = 384000000, .fb_resource = resources_msm_fb, .num_clients = 2, .client_platform_data = { { .product_id = (0xb9f6 << 16 | 0x5582), .name = "mddi_c_b9f6_5582", .id = 1, .client_data = &novatec_client_data, .clk_rate = 0, }, { .product_id = (0x4ca3 << 16 | 0x0000), .name = "mddi_c_4ca3_0000", .id = 0, .client_data = &epson_client_data, .clk_rate = 0, }, }, }; static struct platform_driver suc_backlight_driver = { .probe = suc_backlight_probe, .driver = { .owner = THIS_MODULE, }, }; static struct msm_mdp_platform_data mdp_pdata = { .dma_channel = MDP_DMA_S, }; int __init supersonic_init_panel(void) { int rc; B(KERN_INFO "%s: enter.\n", __func__); vreg_lcd_1v8 = vreg_get(0, "gp4"); if (IS_ERR(vreg_lcd_1v8)) return PTR_ERR(vreg_lcd_1v8); vreg_lcd_2v8 = vreg_get(0, "synt"); if (IS_ERR(vreg_lcd_2v8)) return PTR_ERR(vreg_lcd_2v8); if (panel_type == PANEL_SHARP) mdp_pdata.overrides |= MSM_MDP_PANEL_IGNORE_PIXEL_DATA; else mdp_pdata.overrides &= ~MSM_MDP_PANEL_IGNORE_PIXEL_DATA; msm_device_mdp.dev.platform_data = &mdp_pdata; rc = platform_device_register(&msm_device_mdp); if (rc) return rc; if (panel_type) mddi_pdata.power_client = mddi_novatec_power; else mddi_pdata.power_client = mddi_epson_power; msm_device_mddi0.dev.platform_data = &mddi_pdata; rc = platform_device_register(&msm_device_mddi0); if (rc) return rc; if (panel_type) suc_backlight_driver.driver.name = "nov_cabc"; else suc_backlight_driver.driver.name = "eps_cabc"; rc = platform_driver_register(&suc_backlight_driver); if (rc) return rc; return 0; }