1/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. 2 * 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License version 2 and 5 * only version 2 as published by the Free Software Foundation. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 15 * 02110-1301, USA. 16 */ 17 18#include <linux/i2c.h> 19#include <linux/delay.h> 20#include "msm_fb.h" 21 22#define DEVICE_NAME "sii9022" 23#define SII9022_DEVICE_ID 0xB0 24 25struct sii9022_i2c_addr_data{ 26 u8 addr; 27 u8 data; 28}; 29 30/* video mode data */ 31static u8 video_mode_data[] = { 32 0x00, 33 0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02, 34}; 35 36static u8 avi_io_format[] = { 37 0x09, 38 0x00, 0x00, 39}; 40 41/* power state */ 42static struct sii9022_i2c_addr_data regset0[] = { 43 { 0x60, 0x04 }, 44 { 0x63, 0x00 }, 45 { 0x1E, 0x00 }, 46}; 47 48static u8 video_infoframe[] = { 49 0x0C, 50 0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00, 51 0xE9, 0x02, 0x04, 0x01, 0x04, 0x06, 52}; 53 54/* configure audio */ 55static struct sii9022_i2c_addr_data regset1[] = { 56 { 0x26, 0x90 }, 57 { 0x20, 0x90 }, 58 { 0x1F, 0x80 }, 59 { 0x26, 0x80 }, 60 { 0x24, 0x02 }, 61 { 0x25, 0x0B }, 62 { 0xBC, 0x02 }, 63 { 0xBD, 0x24 }, 64 { 0xBE, 0x02 }, 65}; 66 67/* enable audio */ 68static u8 misc_infoframe[] = { 69 0xBF, 70 0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00, 71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 72}; 73 74/* set HDMI, active */ 75static struct sii9022_i2c_addr_data regset2[] = { 76 { 0x1A, 0x01 }, 77 { 0x3D, 0x00 }, 78}; 79 80static int send_i2c_data(struct i2c_client *client, 81 struct sii9022_i2c_addr_data *regset, 82 int size) 83{ 84 int i; 85 int rc = 0; 86 87 for (i = 0; i < size; i++) { 88 rc = i2c_smbus_write_byte_data( 89 client, 90 regset[i].addr, regset[i].data); 91 if (rc) 92 break; 93 } 94 return rc; 95} 96 97static int hdmi_sii_enable(struct i2c_client *client) 98{ 99 int rc; 100 int retries = 10; 101 int count; 102 103 rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00); 104 if (rc) 105 goto enable_exit; 106 107 do { 108 msleep(1); 109 rc = i2c_smbus_read_byte_data(client, 0x1B); 110 } while ((rc != SII9022_DEVICE_ID) && retries--); 111 112 if (rc != SII9022_DEVICE_ID) 113 return -ENODEV; 114 115 rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11); 116 if (rc) 117 goto enable_exit; 118 119 count = ARRAY_SIZE(video_mode_data); 120 rc = i2c_master_send(client, video_mode_data, count); 121 if (rc != count) { 122 rc = -EIO; 123 goto enable_exit; 124 } 125 126 rc = i2c_smbus_write_byte_data(client, 0x08, 0x20); 127 if (rc) 128 goto enable_exit; 129 count = ARRAY_SIZE(avi_io_format); 130 rc = i2c_master_send(client, avi_io_format, count); 131 if (rc != count) { 132 rc = -EIO; 133 goto enable_exit; 134 } 135 136 rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0)); 137 if (rc) 138 goto enable_exit; 139 140 count = ARRAY_SIZE(video_infoframe); 141 rc = i2c_master_send(client, video_infoframe, count); 142 if (rc != count) { 143 rc = -EIO; 144 goto enable_exit; 145 } 146 147 rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1)); 148 if (rc) 149 goto enable_exit; 150 151 count = ARRAY_SIZE(misc_infoframe); 152 rc = i2c_master_send(client, misc_infoframe, count); 153 if (rc != count) { 154 rc = -EIO; 155 goto enable_exit; 156 } 157 158 rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2)); 159 if (rc) 160 goto enable_exit; 161 162 return 0; 163enable_exit: 164 printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc); 165 return rc; 166} 167 168static const struct i2c_device_id hmdi_sii_id[] = { 169 { DEVICE_NAME, 0 }, 170 { } 171}; 172 173static int hdmi_sii_probe(struct i2c_client *client, 174 const struct i2c_device_id *id) 175{ 176 int rc; 177 178 if (!i2c_check_functionality(client->adapter, 179 I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C)) 180 return -ENODEV; 181 rc = hdmi_sii_enable(client); 182 return rc; 183} 184 185 186static struct i2c_driver hdmi_sii_i2c_driver = { 187 .driver = { 188 .name = DEVICE_NAME, 189 .owner = THIS_MODULE, 190 }, 191 .probe = hdmi_sii_probe, 192 .remove = __exit_p(hdmi_sii_remove), 193 .id_table = hmdi_sii_id, 194}; 195 196static int __init lcdc_st15_init(void) 197{ 198 int ret; 199 struct msm_panel_info pinfo; 200 201 if (msm_fb_detect_client("lcdc_st15")) 202 return 0; 203 204 pinfo.xres = 1366; 205 pinfo.yres = 768; 206 pinfo.type = LCDC_PANEL; 207 pinfo.pdest = DISPLAY_1; 208 pinfo.wait_cycle = 0; 209 pinfo.bpp = 24; 210 pinfo.fb_num = 2; 211 pinfo.clk_rate = 74250000; 212 213 pinfo.lcdc.h_back_porch = 120; 214 pinfo.lcdc.h_front_porch = 20; 215 pinfo.lcdc.h_pulse_width = 40; 216 pinfo.lcdc.v_back_porch = 25; 217 pinfo.lcdc.v_front_porch = 1; 218 pinfo.lcdc.v_pulse_width = 7; 219 pinfo.lcdc.border_clr = 0; /* blk */ 220 pinfo.lcdc.underflow_clr = 0xff; /* blue */ 221 pinfo.lcdc.hsync_skew = 0; 222 223 ret = lcdc_device_register(&pinfo); 224 if (ret) { 225 printk(KERN_ERR "%s: failed to register device!\n", __func__); 226 goto init_exit; 227 } 228 229 ret = i2c_add_driver(&hdmi_sii_i2c_driver); 230 if (ret) 231 printk(KERN_ERR "%s: failed to add i2c driver\n", __func__); 232 233init_exit: 234 return ret; 235} 236 237module_init(lcdc_st15_init); 238