aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/accessory
diff options
context:
space:
mode:
authorcodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
committercodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
commitc6da2cfeb05178a11c6d062a06f8078150ee492f (patch)
treef3b4021d252c52d6463a9b3c1bb7245e399b009c /drivers/accessory
parentc6d7c4dbff353eac7919342ae6b3299a378160a6 (diff)
downloadkernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2
samsung update 1
Diffstat (limited to 'drivers/accessory')
-rw-r--r--drivers/accessory/30pin_con.c737
-rw-r--r--drivers/accessory/Kconfig38
-rw-r--r--drivers/accessory/MHD_SiI9234.c543
-rw-r--r--drivers/accessory/MHD_SiI9234.h78
-rw-r--r--drivers/accessory/Makefile7
-rw-r--r--drivers/accessory/sec_keyboard.c500
-rw-r--r--drivers/accessory/sec_keyboard.h208
-rw-r--r--drivers/accessory/sii9234.c339
-rw-r--r--drivers/accessory/sii9234.h191
-rw-r--r--drivers/accessory/sii9234_tpi_regs.h381
10 files changed, 3022 insertions, 0 deletions
diff --git a/drivers/accessory/30pin_con.c b/drivers/accessory/30pin_con.c
new file mode 100644
index 0000000..7052ed2
--- /dev/null
+++ b/drivers/accessory/30pin_con.c
@@ -0,0 +1,737 @@
+
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/30pin_con.h>
+#include <linux/switch.h>
+#include <linux/wakelock.h>
+#include <plat/adc.h>
+#include <linux/earlysuspend.h>
+
+#include <asm/irq.h>
+#include <linux/mfd/tps6586x.h>
+
+#ifdef CONFIG_REGULATOR
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#endif
+
+#ifdef CONFIG_MHL_SII9234
+#include "sii9234.h"
+#endif
+
+#define SUBJECT "ACCESSORY"
+
+#define ACC_CONDEV_DBG(format, ...) \
+ pr_info("[ "SUBJECT " (%s,%d) ] " format "\n", \
+ __func__, __LINE__, ## __VA_ARGS__);
+
+#define DETECTION_INTR_DELAY (get_jiffies_64() + (HZ*15)) /* 20s */
+
+enum accessory_type {
+ ACCESSORY_NONE = 0,
+ ACCESSORY_OTG,
+ ACCESSORY_LINEOUT,
+ ACCESSORY_CARMOUNT,
+ ACCESSORY_UNKNOWN,
+};
+
+enum dock_type {
+ DOCK_NONE = 0,
+ DOCK_DESK,
+ DOCK_KEYBOARD,
+};
+
+enum uevent_dock_type {
+ UEVENT_DOCK_NONE = 0,
+ UEVENT_DOCK_DESK,
+ UEVENT_DOCK_CAR,
+ UEVENT_DOCK_KEYBOARD = 9,
+};
+
+struct acc_con_info {
+ struct device *acc_dev;
+ struct acc_con_platform_data *pdata;
+ struct delayed_work acc_dwork;
+ struct delayed_work acc_id_dwork;
+ struct switch_dev dock_switch;
+ struct switch_dev ear_jack_switch;
+ struct wake_lock wake_lock;
+ struct s3c_adc_client *padc;
+ enum accessory_type current_accessory;
+ enum dock_type current_dock;
+ int accessory_irq;
+ int dock_irq;
+#if defined(CONFIG_MHL_SII9234) || defined(CONFIG_SAMSUNG_MHL_9290)
+ int mhl_irq;
+ bool mhl_pwr_state;
+#endif
+ struct early_suspend early_suspend;
+ struct delayed_work acc_con_work;
+ struct mutex lock;
+};
+
+#if defined(CONFIG_STMPE811_ADC)
+#ifdef CONFIG_MACH_P4NOTE
+#define ACCESSORY_ID_ADC_CH 7
+#else
+#define ACCESSORY_ID_ADC_CH 0
+#endif
+#else
+#define ACCESSORY_ID_ADC_CH 4
+#endif
+
+#ifdef CONFIG_SAMSUNG_MHL_9290
+static BLOCKING_NOTIFIER_HEAD(acc_notifier);
+
+int acc_register_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&acc_notifier, nb);
+}
+
+int acc_unregister_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&acc_notifier, nb);
+}
+
+static int acc_notify(int event)
+{
+ pr_info("notifier: mhl callback\n");
+ return blocking_notifier_call_chain(&acc_notifier, event, NULL);
+}
+#endif
+static int acc_get_adc_accessroy_id(struct s3c_adc_client *padc)
+{
+ int adc_data;
+
+#if defined(CONFIG_STMPE811_ADC)
+ adc_data = stmpe811_get_adc_data(ACCESSORY_ID_ADC_CH);
+#else
+ adc_data = s3c_adc_read(padc, ACCESSORY_ID_ADC_CH);
+#endif
+/* ACC_CONDEV_DBG("[ACC] adc_data = %d..\n",adc_data); */
+ return adc_data;
+}
+
+static int acc_get_accessory_id(struct acc_con_info *acc)
+{
+ int i;
+ u32 adc = 0, adc_sum = 0;
+ u32 adc_buff[5] = {0};
+ u32 adc_val = 0;
+ u32 adc_min = 0;
+ u32 adc_max = 0;
+
+ if (!acc) {
+ pr_err("adc client is not registered!\n");
+ return -1;
+ }
+
+ for (i = 0; i < 5; i++) {
+ adc_val = acc_get_adc_accessroy_id(acc->padc);
+ adc_buff[i] = adc_val;
+ adc_sum += adc_buff[i];
+ if (i == 0) {
+ adc_min = adc_buff[0];
+ adc_max = adc_buff[0];
+ } else {
+ if (adc_max < adc_buff[i])
+ adc_max = adc_buff[i];
+ else if (adc_min > adc_buff[i])
+ adc_min = adc_buff[i];
+ }
+ msleep(20);
+ }
+ adc = (adc_sum - adc_max - adc_min)/3;
+ ACC_CONDEV_DBG("ACCESSORY_ID ADC value = %d", adc);
+ return (int)adc;
+}
+
+#ifdef CONFIG_MHL_SII9234
+static ssize_t MHD_check_read(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ int count;
+ int res;
+ /*TVout_LDO_ctrl(true);*/
+ if (!MHD_HW_IsOn()) {
+ sii9234_tpi_init();
+ res = MHD_Read_deviceID();
+ MHD_HW_Off();
+ } else {
+ sii9234_tpi_init();
+ res = MHD_Read_deviceID();
+ }
+
+ count = sprintf(buf, "%d\n", res);
+ /*TVout_LDO_ctrl(false);*/
+ return count;
+}
+
+static ssize_t MHD_check_write(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t size)
+{
+ printk(KERN_INFO"input data --> %s\n", buf);
+
+ return size;
+}
+
+static CLASS_ATTR(test_result, S_IRUGO, MHD_check_read, MHD_check_write);
+#endif /* CONFIG_MHL_SII9234 */
+
+static ssize_t acc_read_acc_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct acc_con_info *acc = dev_get_drvdata(dev);
+ int adc_val = 0 ;
+ int jig_uart_off = 0 ;
+ int count = 0 ;
+ adc_val = acc_get_accessory_id(acc);
+
+ if ((3540 < adc_val) && (adc_val < 3920))
+ jig_uart_off = 28 ;
+ else
+ jig_uart_off = 0 ;
+
+ ACC_CONDEV_DBG("jig_uart_off : %d", jig_uart_off);
+
+ count = sprintf(buf, "%x\n", jig_uart_off);
+
+ return count;
+}
+
+static DEVICE_ATTR(adc, S_IRUGO, acc_read_acc_id, NULL);
+
+
+void acc_accessory_uevent(struct acc_con_info *acc, int acc_adc)
+{
+ char *env_ptr;
+ char *stat_ptr;
+ char *envp[3];
+
+ /* value is changed for PxLTE
+ 3 pole earjack 1.00 V ( 0.90~1.10V) adc: 797~1002
+ Car mount 1.38 V (1.24~1.45V) adc: 1134~1352
+ 4 pole earjack just bundles is supported . adc :1360~1449
+ OTG 2.2 V (2.00~2.35V) adc: 1903~2248 */
+
+ if (acc_adc != false) {
+ if ((1100 < acc_adc) && (1400 > acc_adc)) {
+ /* 3 pole earjack 1220 */
+ env_ptr = "ACCESSORY=lineout";
+ acc->current_accessory = ACCESSORY_LINEOUT;
+ switch_set_state(&acc->ear_jack_switch, 1);
+#if 0
+ } else if ((1134 < acc_adc) && (1352 > acc_adc)) {
+ /* car mount */
+ env_ptr = "ACCESSORY=carmount";
+ acc->current_accessory = ACCESSORY_CARMOUNT;
+#endif
+ } else if ((1800 < acc_adc) && (2350 > acc_adc)) {
+ /* 4 pole earjack, No warranty 2000 */
+ env_ptr = "ACCESSORY=lineout";
+ acc->current_accessory = ACCESSORY_LINEOUT;
+ switch_set_state(&acc->ear_jack_switch, 1);
+ } else if ((2450 < acc_adc) && (2850 > acc_adc)) {
+ /* otg 2730 */
+ env_ptr = "ACCESSORY=OTG";
+ acc->current_accessory = ACCESSORY_OTG;
+ } else {
+ env_ptr = "ACCESSORY=unknown";
+ acc->current_accessory = ACCESSORY_UNKNOWN;
+ }
+
+ stat_ptr = "STATE=online";
+ envp[0] = env_ptr;
+ envp[1] = stat_ptr;
+ envp[2] = NULL;
+ if (acc->current_accessory == ACCESSORY_OTG) {
+ if (acc->pdata->usb_ldo_en)
+ acc->pdata->usb_ldo_en(1);
+ if (acc->pdata->otg_en)
+ acc->pdata->otg_en(1);
+ }
+ kobject_uevent_env(&acc->acc_dev->kobj, KOBJ_CHANGE, envp);
+ ACC_CONDEV_DBG("%s : %s", env_ptr, stat_ptr);
+ } else {
+ if (acc->current_accessory == ACCESSORY_OTG)
+ env_ptr = "ACCESSORY=OTG";
+ else if (acc->current_accessory == ACCESSORY_LINEOUT) {
+ env_ptr = "ACCESSORY=lineout";
+ switch_set_state(&acc->ear_jack_switch,
+ UEVENT_DOCK_NONE);
+ } else if (acc->current_accessory == ACCESSORY_CARMOUNT)
+ env_ptr = "ACCESSORY=carmount";
+ else
+ env_ptr = "ACCESSORY=unknown";
+
+ stat_ptr = "STATE=offline";
+ envp[0] = env_ptr;
+ envp[1] = stat_ptr;
+ envp[2] = NULL;
+ kobject_uevent_env(&acc->acc_dev->kobj, KOBJ_CHANGE, envp);
+ if ((acc->current_accessory == ACCESSORY_OTG) &&
+ acc->pdata->otg_en)
+ acc->pdata->otg_en(0);
+
+ acc->current_accessory = ACCESSORY_NONE;
+ ACC_CONDEV_DBG("%s : %s", env_ptr, stat_ptr);
+ }
+}
+
+static void acc_dock_uevent(struct acc_con_info *acc, bool connected)
+{
+ char *env_ptr;
+ char *stat_ptr;
+ char *envp[3];
+
+ if (acc->current_dock == DOCK_KEYBOARD)
+ env_ptr = "DOCK=keyboard";
+ else if (acc->current_dock == DOCK_DESK)
+ env_ptr = "DOCK=desk";
+ else
+ env_ptr = "DOCK=unknown";
+
+ if (!connected) {
+ stat_ptr = "STATE=offline";
+ acc->current_dock = DOCK_NONE;
+ } else {
+ stat_ptr = "STATE=online";
+ }
+
+ envp[0] = env_ptr;
+ envp[1] = stat_ptr;
+ envp[2] = NULL;
+ kobject_uevent_env(&acc->acc_dev->kobj, KOBJ_CHANGE, envp);
+ ACC_CONDEV_DBG("%s : %s", env_ptr, stat_ptr);
+}
+
+
+static void acc_check_dock_detection(struct acc_con_info *acc)
+{
+ if (NULL == acc->pdata->get_dock_state) {
+ ACC_CONDEV_DBG("[30PIN] failed to get acc state!!!");
+ return;
+ }
+
+ if (!acc->pdata->get_dock_state()) {
+#ifdef CONFIG_SEC_KEYBOARD_DOCK
+ if (acc->pdata->check_keyboard &&
+ acc->pdata->check_keyboard(true)) {
+ acc->current_dock = DOCK_KEYBOARD;
+ ACC_CONDEV_DBG
+ ("[30PIN] keyboard dock station attached!!!");
+ switch_set_state(&acc->dock_switch,
+ UEVENT_DOCK_KEYBOARD);
+ } else
+#endif
+ {
+ ACC_CONDEV_DBG
+ ("[30PIN] desktop dock station attached!!!");
+ switch_set_state(&acc->dock_switch, UEVENT_DOCK_DESK);
+ acc->current_dock = DOCK_DESK;
+
+#if defined(CONFIG_MHL_SII9234) || defined(CONFIG_SAMSUNG_MHL_9290)
+ mutex_lock(&acc->lock);
+ if (!acc->mhl_pwr_state) {
+#if defined(CONFIG_MHL_SII9234)
+ sii9234_tpi_init();
+#elif defined(CONFIG_SAMSUNG_MHL_9290)
+ acc_notify(1);
+#endif
+ acc->mhl_pwr_state = true;
+ }
+ mutex_unlock(&acc->lock);
+#endif
+ }
+ acc_dock_uevent(acc, true);
+ } else {
+
+ ACC_CONDEV_DBG("[30PIN] dock station detached!!!");
+
+ switch_set_state(&acc->dock_switch, UEVENT_DOCK_NONE);
+#ifdef CONFIG_SEC_KEYBOARD_DOCK
+ if (acc->pdata->check_keyboard)
+ acc->pdata->check_keyboard(false);
+#endif
+#if defined(CONFIG_MHL_SII9234) || defined(CONFIG_SAMSUNG_MHL_9290)
+ /*call MHL deinit */
+ if (acc->mhl_pwr_state) {
+#if defined(CONFIG_MHL_SII9234)
+ MHD_HW_Off();
+#elif defined(CONFIG_SAMSUNG_MHL_9290)
+ acc_notify(0);
+#endif
+ acc->mhl_pwr_state = false;
+ }
+#endif
+ /*TVout_LDO_ctrl(false); */
+ acc_dock_uevent(acc, false);
+
+ }
+}
+
+static irqreturn_t acc_dock_isr(int irq, void *ptr)
+{
+ struct acc_con_info *acc = ptr;
+ wake_lock(&acc->wake_lock);
+ acc_check_dock_detection(acc);
+ wake_unlock(&acc->wake_lock);
+ return IRQ_HANDLED;
+}
+
+#define DETECTION_DELAY_MS 200
+
+static irqreturn_t acc_accessory_isr(int irq, void *dev_id)
+{
+ struct acc_con_info *acc = (struct acc_con_info *)dev_id;
+ ACC_CONDEV_DBG("");
+ cancel_delayed_work_sync(&acc->acc_id_dwork);
+ schedule_delayed_work(&acc->acc_id_dwork,
+ msecs_to_jiffies(DETECTION_DELAY_MS));
+ return IRQ_HANDLED;
+}
+
+static int acc_init_dock_int(struct acc_con_info *acc)
+{
+ int ret = 0;
+ acc->accessory_irq = gpio_to_irq(acc->pdata->accessory_irq_gpio);
+ ret = request_threaded_irq(acc->accessory_irq, NULL, acc_dock_isr,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "accessory_detect", acc);
+ if (ret)
+ ACC_CONDEV_DBG("request_irq(accessory_irq) return : %d\n", ret);
+
+ ret = enable_irq_wake(acc->accessory_irq);
+ if (ret)
+ ACC_CONDEV_DBG("enable_irq_wake(accessory_irq) return : %d\n",
+ ret);
+
+ return ret;
+}
+
+static int acc_init_accessory_int(struct acc_con_info *acc)
+{
+ int ret = 0;
+ acc->dock_irq = gpio_to_irq(acc->pdata->dock_irq_gpio);
+ ret = request_threaded_irq(acc->dock_irq, NULL, acc_accessory_isr,
+ IRQF_ONESHOT |
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "dock_detect", acc);
+ if (ret)
+ ACC_CONDEV_DBG("request_irq(dock_irq) return : %d\n", ret);
+
+ ret = enable_irq_wake(acc->dock_irq);
+ if (ret)
+ ACC_CONDEV_DBG("enable_irq_wake(dock_irq) return : %d\n", ret);
+
+ return ret;
+}
+
+static void acc_dwork_int_init(struct work_struct *work)
+{
+ struct acc_con_info *acc = container_of(work,
+ struct acc_con_info, acc_dwork.work);
+ int retval;
+
+ ACC_CONDEV_DBG("");
+
+ retval = acc_init_dock_int(acc);
+ if (retval) {
+ ACC_CONDEV_DBG("failed to initialize dock_int irq");
+ goto err_irq_dock;
+ }
+
+ retval = acc_init_accessory_int(acc);
+ if (retval) {
+ ACC_CONDEV_DBG(" failed to initialize accessory_int irq");
+ goto err_irq_acc;
+ }
+
+ if (acc->pdata->get_dock_state) {
+ if (!acc->pdata->get_dock_state())
+ acc_check_dock_detection(acc);
+ }
+
+ if (acc->pdata->get_acc_state) {
+ if (!acc->pdata->get_acc_state())
+ schedule_delayed_work(&acc->acc_id_dwork,
+ msecs_to_jiffies(DETECTION_DELAY_MS));
+ }
+
+ return ;
+
+err_irq_acc:
+ free_irq(acc->accessory_irq, acc);
+err_irq_dock:
+ switch_dev_unregister(&acc->ear_jack_switch);
+ return ;
+}
+
+static void acc_dwork_accessory_detect(struct work_struct *work)
+{
+ struct acc_con_info *acc = container_of(work,
+ struct acc_con_info, acc_id_dwork.work);
+
+ int adc_val = 0;
+ int acc_state = 0;
+
+ acc_state = acc->pdata->get_acc_state();
+
+ if (acc_state) {
+ ACC_CONDEV_DBG("Accessory detached");
+ acc_accessory_uevent(acc, false);
+ } else {
+ ACC_CONDEV_DBG("Accessory attached");
+ adc_val = acc_get_accessory_id(acc);
+ acc_accessory_uevent(acc, adc_val);
+ }
+}
+
+static int acc_con_probe(struct platform_device *pdev)
+{
+ struct acc_con_info *acc;
+ struct acc_con_platform_data *pdata = pdev->dev.platform_data;
+ struct regulator *vadc_regulator;
+
+ int retval;
+#ifdef CONFIG_MHL_SII9234
+ struct class *sec_mhl;
+#endif
+ ACC_CONDEV_DBG("");
+
+ if (pdata == NULL) {
+ pr_err("%s: no pdata\n", __func__);
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_REGULATOR
+#ifndef CONFIG_MACH_P4NOTE
+ /* LDO1 regulator ON */
+ vadc_regulator = regulator_get(&pdev->dev, "vadc_3.3v");
+ if (IS_ERR(vadc_regulator)) {
+ printk(KERN_ERR "failed to get resource %s\n",
+ "vadc_3.3v");
+ return PTR_ERR(vadc_regulator);
+ }
+ regulator_enable(vadc_regulator);
+#endif
+#endif
+
+ acc = kzalloc(sizeof(*acc), GFP_KERNEL);
+ if (!acc)
+ return -ENOMEM;
+
+ acc->pdata = pdata;
+ acc->current_dock = DOCK_NONE;
+ acc->current_accessory = ACCESSORY_NONE;
+#if defined(CONFIG_MHL_SII9234) || defined(CONFIG_SAMSUNG_MHL_9290)
+ acc->mhl_irq = gpio_to_irq(pdata->mhl_irq_gpio);
+ acc->mhl_pwr_state = false;
+#endif
+
+ mutex_init(&acc->lock);
+ dev_set_drvdata(&pdev->dev, acc);
+
+ acc->acc_dev = &pdev->dev;
+
+ /* Register adc client */
+#if defined(CONFIG_STMPE811_ADC)
+ /* Do nothing */
+#elif defined(CONFIG_S3C_ADC)
+ acc->padc = s3c_adc_register(pdev, NULL, NULL, 0);
+#endif
+
+#ifdef CONFIG_MHL_SII9234
+ retval = i2c_add_driver(&SII9234A_i2c_driver);
+ if (retval) {
+ pr_err("[MHL SII9234A] can't add i2c driver\n");
+ goto err_i2c_a;
+ } else {
+ pr_info("[MHL SII9234A] add i2c driver\n");
+ }
+
+ retval = i2c_add_driver(&SII9234B_i2c_driver);
+ if (retval) {
+ pr_err("[MHL SII9234B] can't add i2c driver\n");
+ goto err_i2c_b;
+ } else {
+ pr_info("[MHL SII9234B] add i2c driver\n");
+ }
+
+ retval = i2c_add_driver(&SII9234C_i2c_driver);
+ if (retval) {
+ pr_err("[MHL SII9234C] can't add i2c driver\n");
+ goto err_i2c_c;
+ } else {
+ pr_info("[MHL SII9234C] add i2c driver\n");
+ }
+
+ retval = i2c_add_driver(&SII9234_i2c_driver);
+ if (retval) {
+ pr_err("[MHL SII9234] can't add i2c driver\n");
+ goto err_i2c;
+ } else {
+ pr_info("[MHL SII9234] add i2c driver\n");
+ }
+#endif
+ acc->dock_switch.name = "dock";
+ retval = switch_dev_register(&acc->dock_switch);
+ if (retval < 0)
+ goto err_sw_dock;
+
+ acc->ear_jack_switch.name = "usb_audio";
+ retval = switch_dev_register(&acc->ear_jack_switch);
+ if (retval < 0)
+ goto err_sw_jack;
+
+ wake_lock_init(&acc->wake_lock, WAKE_LOCK_SUSPEND, "30pin_con");
+
+ INIT_DELAYED_WORK(&acc->acc_dwork, acc_dwork_int_init);
+ schedule_delayed_work(&acc->acc_dwork, msecs_to_jiffies(10000));
+ INIT_DELAYED_WORK(&acc->acc_id_dwork, acc_dwork_accessory_detect);
+#ifdef CONFIG_MHL_SII9234
+ sec_mhl = class_create(THIS_MODULE, "mhl");
+ if (IS_ERR(sec_mhl)) {
+ pr_err("Failed to create class(sec_mhl)!\n");
+ retval = -ENOMEM;
+ }
+
+ retval = class_create_file(sec_mhl, &class_attr_test_result);
+ if (retval) {
+ pr_err("Failed to create device file in sysfs entries!\n");
+ retval = -ENOMEM;
+ }
+#endif
+
+#ifndef CONFIG_MACH_P10
+ if (device_create_file(sec_switch_dev, &dev_attr_adc) < 0)
+ pr_err("Failed to create device file(%s)!\n",
+ dev_attr_adc .attr.name);
+ dev_set_drvdata(sec_switch_dev, acc);
+#endif
+
+ return 0;
+
+#ifndef CONFIG_SEC_KEYBOARD_DOCK
+err_irq_acc:
+ free_irq(acc->accessory_irq, acc);
+err_irq_dock:
+ switch_dev_unregister(&acc->ear_jack_switch);
+#endif
+err_sw_jack:
+ switch_dev_unregister(&acc->dock_switch);
+err_sw_dock:
+#ifdef CONFIG_MHL_SII9234
+ i2c_del_driver(&SII9234_i2c_driver);
+err_i2c:
+ i2c_del_driver(&SII9234C_i2c_driver);
+err_i2c_c:
+ i2c_del_driver(&SII9234B_i2c_driver);
+err_i2c_b:
+ i2c_del_driver(&SII9234A_i2c_driver);
+err_i2c_a:
+#endif
+
+ kfree(acc);
+
+ return retval;
+}
+
+static int acc_con_remove(struct platform_device *pdev)
+{
+ struct acc_con_info *acc = platform_get_drvdata(pdev);
+ ACC_CONDEV_DBG("");
+
+ free_irq(acc->accessory_irq, acc);
+ free_irq(acc->dock_irq, acc);
+#ifdef CONFIG_MHL_SII9234
+ i2c_del_driver(&SII9234A_i2c_driver);
+ i2c_del_driver(&SII9234B_i2c_driver);
+ i2c_del_driver(&SII9234C_i2c_driver);
+ i2c_del_driver(&SII9234_i2c_driver);
+#endif
+
+ switch_dev_unregister(&acc->dock_switch);
+ switch_dev_unregister(&acc->ear_jack_switch);
+ kfree(acc);
+ return 0;
+}
+
+static int acc_con_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct acc_con_info *acc = platform_get_drvdata(pdev);
+ ACC_CONDEV_DBG("");
+#if defined(CONFIG_MHL_SII9234) || defined(CONFIG_SAMSUNG_MHL_9290)
+ if (acc->mhl_pwr_state) {
+ pr_err("%s::MHL off\n", __func__);
+#if defined(CONFIG_MHL_SII9234)
+ MHD_HW_Off();
+#elif defined(CONFIG_SAMSUNG_MHL_9290)
+ acc_notify(0);
+#endif
+ acc->mhl_pwr_state = false;
+ }
+#endif
+ return 0;
+}
+
+static int acc_con_resume(struct platform_device *pdev)
+{
+ struct acc_con_info *acc = platform_get_drvdata(pdev);
+ ACC_CONDEV_DBG("");
+
+ mutex_lock(&acc->lock);
+#if defined(CONFIG_MHL_SII9234) || defined(CONFIG_SAMSUNG_MHL_9290)
+ if (acc->current_dock == DOCK_DESK && !acc->mhl_pwr_state) {
+ pr_err("%s::MHL init\n", __func__);
+#if defined(CONFIG_MHL_SII9234)
+ sii9234_tpi_init(); /* call MHL init */
+#elif defined(CONFIG_SAMSUNG_MHL_9290)
+ acc_notify(1);
+#endif
+ acc->mhl_pwr_state = true;
+ }
+#endif
+ mutex_unlock(&acc->lock);
+
+ return 0;
+}
+
+static struct platform_driver acc_con_driver = {
+ .probe = acc_con_probe,
+ .remove = acc_con_remove,
+ .suspend = acc_con_suspend,
+ .resume = acc_con_resume,
+ .driver = {
+ .name = "acc_con",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init acc_con_init(void)
+{
+ ACC_CONDEV_DBG("");
+
+ return platform_driver_register(&acc_con_driver);
+}
+
+static void __exit acc_con_exit(void)
+{
+ platform_driver_unregister(&acc_con_driver);
+}
+
+late_initcall(acc_con_init);
+module_exit(acc_con_exit);
+
+MODULE_AUTHOR("Kyungrok Min <gyoungrok.min@samsung.com>");
+MODULE_DESCRIPTION("acc connector driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/accessory/Kconfig b/drivers/accessory/Kconfig
new file mode 100644
index 0000000..1bd8af0
--- /dev/null
+++ b/drivers/accessory/Kconfig
@@ -0,0 +1,38 @@
+#
+# Accessory Configuration
+#
+
+menuconfig ACCESSORY
+ bool "Accessory devices"
+ default y
+ ---help---
+ Say Y here to get to see options for Samsung Accessories
+ If you say N, all options in this submenu will be skipped and disabled.
+
+if ACCESSORY
+
+config 30PIN_CONN
+ tristate "Accessory detection driver"
+ depends on I2C
+ help
+ Provides support for detecting Accessory,such as TA, Keyboard
+
+config MHL_SII9234
+ tristate "SiI9234 MHL(Mobile HD Link) Transmitter support"
+ depends on I2C
+ ---help---
+ Mobile HD Link Transmitter driver for SiI9234
+
+config SEC_KEYBOARD_DOCK
+ tristate "sec keyboard dock support"
+
+config HPD_PULL
+ tristate "HPD pull up by PMIC LDO"
+
+config SAMSUNG_MHL_9290
+ tristate "support 9290 dongle and 9292 dongle"
+
+endif # ACCESSORY
+
+
+
diff --git a/drivers/accessory/MHD_SiI9234.c b/drivers/accessory/MHD_SiI9234.c
new file mode 100644
index 0000000..bb3effd
--- /dev/null
+++ b/drivers/accessory/MHD_SiI9234.c
@@ -0,0 +1,543 @@
+/*
+ * MHD_SiI9234.c - Driver for Silicon Image MHD SiI9234 Transmitter driver
+ *
+ * Copyright 2010 Philju Lee (Daniel Lee)
+ *
+ * Based on preview driver from Silicon Image.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * 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.
+ *
+ */
+
+static int MYDRV_MAJOR;
+
+static int MHDDRV_MAJOR;
+
+static bool tclkStable;
+static bool mobileHdCableConnected;
+static bool hdmiCableConnected;
+static bool dsRxPoweredUp;
+static byte tmdsPoweredUp;
+static byte txPowerState;
+static bool checkTclkStable;
+
+
+/*===========================================================================*/
+
+static void InitCBusRegs(void);
+static byte ReadIndexedRegister(byte PageNum, byte Offset);
+void MHD_HW_Reset(void);
+void MHD_HW_Off(void);
+void MHD_OUT_EN(void);
+void MHD_INT_clear(void);
+
+static void I2C_WriteByte(byte deviceID, byte offset, byte value);
+static byte I2C_ReadByte(byte deviceID, byte offset);
+static byte ReadByteTPI(byte Offset);
+static void WriteByteTPI(byte Offset, byte Data);
+static void ReadModifyWriteTPI(byte Offset, byte Mask, byte Data);
+static void WriteIndexedRegister(byte PageNum, byte Offset, byte Data);
+static void sii9234_initializeStateVariables(void);
+
+static void sii9234_enable_interrupts(void);
+static byte ReadByteCBUS(byte Offset);
+static void WriteByteCBUS(byte Offset, byte Data);
+static byte ReadIndexedRegister(byte PageNum, byte Offset);
+static void ReadModifyWriteIndexedRegister(byte PageNum, byte Offset,
+ byte Mask, byte Data);
+static void TxPowerStateD3(void);
+static void TxPowerStateD0(void);
+static void CheckTxFifoStable(void);
+static void HotPlugService(void);
+static void ReadModifyWriteCBUS(byte Offset, byte Mask, byte Value);
+static void OnMHDCableConnected(void) ;
+static void OnDownstreamRxPoweredDown(void);
+static void OnHdmiCableDisconnected(void);
+static void OnDownstreamRxPoweredUp(void);
+static void OnHdmiCableConnected(void);
+
+void sii9234_tpi_init(void);
+static void sii9234_register_init(void);
+static void mhd_tx_fifo_stable(void);
+int MHD_Read_deviceID(void);
+
+/*===========================================================================*/
+
+
+bool delay_ms(int msec)
+{
+ mdelay(msec);
+ return 0;
+}
+
+void MHD_HW_Reset(void)
+{
+ pr_info("[SIMG]MHD_HW_Reset == Start ==\n");
+ SII9234_HW_Reset(SII9234_i2c_client);
+ pr_info("[SIMG] MHD_HW_Reset == End ==\n");
+}
+EXPORT_SYMBOL(MHD_HW_Reset);
+
+void MHD_HW_Off(void)
+{
+ SII9234_HW_Off(SII9234_i2c_client);
+#ifdef CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE
+ mhl_hpd_handler(false);
+#endif
+}
+EXPORT_SYMBOL(MHD_HW_Off);
+
+int MHD_HW_IsOn(void)
+{
+ return SII9234_HW_IsOn();
+}
+EXPORT_SYMBOL(MHD_HW_IsOn);
+
+void MHD_OUT_EN(void)
+{
+ byte state , int_stat;
+ int_stat = ReadIndexedRegister(INDEXED_PAGE_0, 0x74);
+ pr_info("[HDMI]MHD_OUT_EN INT register value is: 0x%02x\n", int_stat);
+ state = ReadIndexedRegister(INDEXED_PAGE_0, 0x81);
+ pr_info("[HDMI]MHD_OUT_EN register 0x81 value is: 0x%02x\n", state);
+
+ if ((state & 0x02) && (int_stat & 0x01)) {
+ pr_info("[HDMI]MHD_OUT_EN :: enable output\n");
+ ReadModifyWriteIndexedRegister(INDEXED_PAGE_0, 0x80, SI_BIT_4,
+ 0x0);
+ msleep(20);
+ ReadModifyWriteIndexedRegister(INDEXED_PAGE_0, 0x80, SI_BIT_4,
+ SI_BIT_4);
+ msleep(60);
+ /* set mhd power active mode */
+ ReadModifyWriteTPI(TPI_DEVICE_POWER_STATE_CTRL_REG,
+ TX_POWER_STATE_MASK, 0x00);
+
+ mhd_tx_fifo_stable(); /*fifo clear*/
+ }
+ MHD_INT_clear();
+}
+EXPORT_SYMBOL(MHD_OUT_EN);
+
+void MHD_INT_clear(void)
+{
+ byte Int_state;
+ Int_state = ReadIndexedRegister(INDEXED_PAGE_0, 0x74);
+ WriteIndexedRegister(INDEXED_PAGE_0, 0x74, Int_state);
+}
+EXPORT_SYMBOL(MHD_INT_clear);
+
+void I2C_WriteByte(byte deviceID, byte offset, byte value)
+{
+ if (deviceID == 0x72)
+ SII9234_i2c_write(SII9234_i2c_client, offset, value);
+ else if (deviceID == 0x7A)
+ SII9234_i2c_write(SII9234A_i2c_client, offset, value);
+ else if (deviceID == 0x92)
+ SII9234_i2c_write(SII9234B_i2c_client, offset, value);
+ else if (deviceID == 0xC8)
+ SII9234_i2c_write(SII9234C_i2c_client, offset, value);
+ else
+ pr_err("[MHL]I2C_WriteByte error %x\n", deviceID);
+}
+
+byte I2C_ReadByte(byte deviceID, byte offset)
+{
+ byte number = 0;
+ /*pr_err("[MHL]I2C_ReadByte called ID%x Offset%x\n",deviceID,offset);*/
+ if (deviceID == 0x72)
+ number = SII9234_i2c_read(SII9234_i2c_client, offset);
+ else if (deviceID == 0x7A)
+ number = SII9234_i2c_read(SII9234A_i2c_client, offset);
+ else if (deviceID == 0x92)
+ number = SII9234_i2c_read(SII9234B_i2c_client, offset);
+ else if (deviceID == 0xC8)
+ number = SII9234_i2c_read(SII9234C_i2c_client, offset);
+ else
+ pr_err("[MHL]I2C_ReadByte error %x\n", deviceID);
+ /*pr_err("[MHL]I2C_ReadByte ID:%x Offset:%x data:%x\n",
+ deviceID,offset,number); */
+ return number;
+}
+
+byte ReadByteTPI(byte Offset)
+{
+ return I2C_ReadByte(TPI_SLAVE_ADDR, Offset);
+}
+
+void WriteByteTPI(byte Offset, byte Data)
+{
+ I2C_WriteByte(TPI_SLAVE_ADDR, Offset, Data);
+}
+
+void ReadModifyWriteTPI(byte Offset, byte Mask, byte Data)
+{
+
+ byte Temp;
+
+ Temp = ReadByteTPI(Offset);
+ /* Read the current value of the register.*/
+ Temp &= ~Mask;
+ /*Clear the bits that are set in Mask.*/
+ Temp |= (Data & Mask);
+ /*OR in new value. Apply Mask to Value for safety.*/
+ WriteByteTPI(Offset, Temp);
+ /*Write new value back to register.*/
+}
+
+
+void WriteIndexedRegister(byte PageNum, byte Offset, byte Data)
+{
+ WriteByteTPI(TPI_INDEXED_PAGE_REG, PageNum); /*Indexed page*/
+ WriteByteTPI(TPI_INDEXED_OFFSET_REG, Offset); /*Indexed register*/
+ WriteByteTPI(TPI_INDEXED_VALUE_REG, Data); /*Write value*/
+}
+
+
+static void sii9234_initializeStateVariables(void)
+{
+
+ tclkStable = FALSE;
+ checkTclkStable = TRUE;
+ tmdsPoweredUp = FALSE;
+ mobileHdCableConnected = FALSE;
+ hdmiCableConnected = FALSE;
+ dsRxPoweredUp = FALSE;
+}
+
+static void InitCBusRegs(void)
+{
+ I2C_WriteByte(0xC8, 0x1F, 0x02);
+ /*Heartbeat Max Fail Enable*/
+ I2C_WriteByte(0xC8, 0x07, DDC_XLTN_TIMEOUT_MAX_VAL | 0x06);
+ /*Increase DDC translation layer timer*/
+ I2C_WriteByte(0xC8, 0x40, 0x03);
+ /*CBUS Drive Strength*/
+ I2C_WriteByte(0xC8, 0x42, 0x06);
+ /*CBUS DDC interface ignore segment pointer*/
+ I2C_WriteByte(0xC8, 0x36, 0x0C);
+ /*I2C_WriteByte(0xC8, 0x44, 0x02);*/
+ I2C_WriteByte(0xC8, 0x3D, 0xFD);
+ I2C_WriteByte(0xC8, 0x1C, 0x00);
+ I2C_WriteByte(0xC8, 0x44, 0x00);
+ /*I2C_WriteByte(0xC8, 0x09, 0x60);*/
+ /* Enable PVC Xfer aborted / follower aborted*/
+}
+
+void sii9234_enable_interrupts(void)
+{
+ ReadModifyWriteTPI(TPI_INTERRUPT_ENABLE_REG, HOT_PLUG_EVENT_MASK,
+ HOT_PLUG_EVENT_MASK);
+ WriteIndexedRegister(INDEXED_PAGE_0, 0x75, SI_BIT_5); /* Enable */
+}
+
+static byte ReadByteCBUS(byte Offset)
+{
+ return I2C_ReadByte(CBUS_SLAVE_ADDR, Offset);
+}
+
+
+static void WriteByteCBUS(byte Offset, byte Data)
+{
+ I2C_WriteByte(CBUS_SLAVE_ADDR, Offset, Data);
+}
+
+static byte ReadIndexedRegister(byte PageNum, byte Offset)
+{
+ WriteByteTPI(TPI_INDEXED_PAGE_REG, PageNum); /* Indexed page */
+ WriteByteTPI(TPI_INDEXED_OFFSET_REG, Offset); /* Indexed register */
+ return ReadByteTPI(TPI_INDEXED_VALUE_REG); /* Return read value */
+}
+
+static void ReadModifyWriteIndexedRegister(byte PageNum, byte Offset,
+ byte Mask, byte Data)
+{
+ byte Temp;
+
+ /* Read the current value of the register. */
+ Temp = ReadIndexedRegister(PageNum, Offset);
+ /* Clear the bits that are set in Mask. */
+ Temp &= ~Mask;
+ /* OR in new value. Apply Mask to Value for safety. */
+ Temp |= (Data & Mask);
+ /* Write new value back to register. */
+ WriteByteTPI(TPI_INDEXED_VALUE_REG, Temp);
+}
+
+static void TxPowerStateD3(void)
+{
+
+ ReadModifyWriteIndexedRegister(INDEXED_PAGE_1, 0x3D, SI_BIT_0, 0x00);
+ pr_info("[SIMG] TX Power State D3\n");
+ txPowerState = TX_POWER_STATE_D3;
+}
+
+static void TxPowerStateD0(void)
+{
+ ReadModifyWriteTPI(TPI_DEVICE_POWER_STATE_CTRL_REG,
+ TX_POWER_STATE_MASK, 0x00);
+ TPI_DEBUG_PRINT(("[SIMG] TX Power State D0\n"));
+ txPowerState = TX_POWER_STATE_D0;
+}
+
+static void CheckTxFifoStable(void)
+{
+ byte bTemp;
+
+ bTemp = ReadIndexedRegister(INDEXED_PAGE_0, 0x3E);
+ if ((bTemp & (SI_BIT_7 | SI_BIT_6)) != 0x00) {
+ TPI_DEBUG_PRINT(("[SIMG] FIFO Overrun / Underrun\n"));
+ /* Assert MHD FIFO Reset */
+ WriteIndexedRegister(INDEXED_PAGE_0, 0x05,
+ SI_BIT_4 | ASR_VALUE);
+ mdelay(1);
+ /* Deassert MHD FIFO Reset */
+ WriteIndexedRegister(INDEXED_PAGE_0, 0x05, ASR_VALUE);
+ }
+}
+
+static void HotPlugService(void)
+{
+ /* disable interrupts */
+ ReadModifyWriteTPI(TPI_INTERRUPT_ENABLE_REG,
+ RECEIVER_SENSE_EVENT_MASK, 0x00);
+
+ /* enable TMDS */
+ pr_info("[SIMG] TMDS -> Enabled\n");
+ ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG,
+ TMDS_OUTPUT_CONTROL_MASK, TMDS_OUTPUT_CONTROL_ACTIVE);
+ tmdsPoweredUp = TRUE;
+
+ TxPowerStateD0();
+
+ /* enable interrupts */
+ WriteIndexedRegister(INDEXED_PAGE_0, 0x78, 0x01);
+
+ CheckTxFifoStable();
+}
+
+static void ReadModifyWriteCBUS(byte Offset, byte Mask, byte Value)
+{
+ byte Temp = ReadByteCBUS(Offset);
+ Temp &= ~Mask;
+ Temp |= (Value & Mask);
+ WriteByteCBUS(Offset, Temp);
+}
+
+static void OnMHDCableConnected(void)
+{
+
+ TPI_DEBUG_PRINT(("[SIMG] MHD Connected\n"));
+
+ if (txPowerState == TX_POWER_STATE_D3) {
+ /* start tpi */
+ WriteByteTPI(TPI_ENABLE, 0x00); /* Write "0" to 72:C7 to
+ start HW TPI mode */
+ /* enable interrupts */
+ WriteIndexedRegister(INDEXED_PAGE_0, 0x78, 0x01);
+
+ TxPowerStateD0();
+ }
+
+ mobileHdCableConnected = TRUE;
+
+ WriteIndexedRegister(INDEXED_PAGE_0, 0xA0, 0x10);
+
+ TPI_DEBUG_PRINT(("[SIMG] Setting DDC Burst Mode\n"));
+ /* Increase DDC translation layer timer (burst mode) */
+ WriteByteCBUS(0x07, DDC_XLTN_TIMEOUT_MAX_VAL | 0x0E);
+ WriteByteCBUS(0x47, 0x03);
+ WriteByteCBUS(0x21, 0x01); /* Heartbeat Disable */
+}
+
+void OnDownstreamRxPoweredDown(void)
+{
+
+ TPI_DEBUG_PRINT(("[SIMG] DSRX -> Powered Down\n"));
+
+ dsRxPoweredUp = FALSE;
+
+ /* disable TMDS */
+ TPI_DEBUG_PRINT(("[SIMG] TMDS -> Disabled\n"));
+ ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG,
+ TMDS_OUTPUT_CONTROL_MASK,
+ TMDS_OUTPUT_CONTROL_POWER_DOWN);
+ tmdsPoweredUp = FALSE;
+}
+
+void OnHdmiCableDisconnected(void)
+{
+
+ TPI_DEBUG_PRINT(("[SIMG] HDMI Disconnected\n"));
+
+ hdmiCableConnected = FALSE;
+ OnDownstreamRxPoweredDown();
+}
+
+
+void sii9234_tpi_init(void)
+{
+ MHD_HW_Reset();
+
+ pr_info("[HDMI]9234 init ++\n");
+
+ sii9234_register_init();
+
+ /* start tpi */
+ WriteByteTPI(TPI_ENABLE, 0x00); /* Write "0" to 72:C7 to
+ start HW TPI mode */
+
+ /* enable interrupts */
+ WriteIndexedRegister(INDEXED_PAGE_0, 0x78, 0x01);
+
+ /* mhd rx connected */
+ WriteIndexedRegister(INDEXED_PAGE_0,
+ 0xA0, 0x10); /* TX termination enable */
+ WriteByteCBUS(0x07, DDC_XLTN_TIMEOUT_MAX_VAL |
+ 0x0E); /* Increase DDC translation layer timer (burst mode) */
+ WriteByteCBUS(0x47, 0x03);
+ WriteByteCBUS(0x21, 0x01); /* Heartbeat Disable */
+
+ /* enable mhd tx */
+ ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG,
+ TMDS_OUTPUT_CONTROL_MASK, TMDS_OUTPUT_CONTROL_ACTIVE);
+
+ /* set mhd power active mode */
+ ReadModifyWriteTPI(TPI_DEVICE_POWER_STATE_CTRL_REG,
+ TX_POWER_STATE_MASK, 0x00);
+
+ mhd_tx_fifo_stable(); /*fifo clear*/
+#ifdef CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE
+ mhl_hpd_handler(true);
+#endif
+ pr_info("[HDMI]9234 init --\n");
+}
+EXPORT_SYMBOL(sii9234_tpi_init);
+
+
+int MHD_Read_deviceID(void)
+{
+
+ byte devID;
+ word wID;
+
+ devID = ReadIndexedRegister(0x00, 0x03);
+ wID = devID << 8;
+ devID = ReadIndexedRegister(0x00, 0x02);
+ wID |= devID;
+
+ devID = ReadByteTPI(TPI_DEVICE_ID);
+
+ pr_err("SiI %04X\n", (int) wID);
+
+ if (devID == SiI_DEVICE_ID)
+ return TRUE;
+
+ pr_err("Unsupported TX\n");
+ return FALSE;
+
+}
+EXPORT_SYMBOL(MHD_Read_deviceID);
+
+
+void mhd_tx_fifo_stable(void)
+{
+ byte tmp = ReadIndexedRegister(INDEXED_PAGE_0, 0x3E);
+ if ((tmp & (SI_BIT_7 | SI_BIT_6)) != 0x00) {
+ /* Assert Mobile HD FIFO Reset */
+ WriteIndexedRegister(INDEXED_PAGE_0, 0x05,
+ SI_BIT_4 | ASR_VALUE);
+ mdelay(1);
+ /* Deassert Mobile HD FIFO Reset */
+ WriteIndexedRegister(INDEXED_PAGE_0, 0x05, ASR_VALUE);
+ }
+}
+
+
+
+static void sii9234_register_init(void)
+{
+ /*Power Up*/
+ I2C_WriteByte(0x7A, 0x3D, 0x3F); /* Power up CVCC 1.2V core */
+ I2C_WriteByte(0x92, 0x11, 0x01); /* Enable TxPLL Clock*/
+ I2C_WriteByte(0x92, 0x12, 0x15); /* Enable Tx Clock Path & Equalizer*/
+ I2C_WriteByte(0x72, 0x08, 0x35); /* Power Up TMDS Tx Core*/
+
+ I2C_WriteByte(0x92, 0x00, 0x00); /* SIMG: correcting HW default*/
+ I2C_WriteByte(0x92, 0x13, 0x60); /* SIMG: Set termination value*/
+ I2C_WriteByte(0x92, 0x14, 0xF0); /* SIMG: Change CKDT level*/
+ I2C_WriteByte(0x92, 0x4B, 0x06); /* SIMG: Correcting HW default*/
+
+ /*Analog PLL Control*/
+ I2C_WriteByte(0x92, 0x17, 0x07); /* SIMG: PLL Calrefsel*/
+ I2C_WriteByte(0x92, 0x1A, 0x20); /* VCO Cal*/
+ I2C_WriteByte(0x92, 0x22, 0xE0); /* SIMG: Auto EQ*/
+ I2C_WriteByte(0x92, 0x23, 0xC0); /* SIMG: Auto EQ*/
+ I2C_WriteByte(0x92, 0x24, 0xA0); /* SIMG: Auto EQ*/
+ I2C_WriteByte(0x92, 0x25, 0x80); /* SIMG: Auto EQ*/
+ I2C_WriteByte(0x92, 0x26, 0x60); /* SIMG: Auto EQ*/
+ I2C_WriteByte(0x92, 0x27, 0x40); /* SIMG: Auto EQ*/
+ I2C_WriteByte(0x92, 0x28, 0x20); /* SIMG: Auto EQ*/
+ I2C_WriteByte(0x92, 0x29, 0x00); /* SIMG: Auto EQ*/
+
+ /*I2C_WriteByte(0x92, 0x10, 0xF1);*/
+ I2C_WriteByte(0x92, 0x4D, 0x02); /* SIMG: PLL Mode Value (order is important)*/
+ /*I2C_WriteByte(0x92, 0x4D, 0x00);*/
+ I2C_WriteByte(0x92, 0x4C, 0xA0); /* Manual zone control*/
+
+ /*I2C_WriteByte(0x72, 0x80, 0x14);*/ /* Enable Rx PLL Clock Value*/
+ I2C_WriteByte(0x72, 0x80, 0x34);
+
+ I2C_WriteByte(0x92, 0x31, 0x0B); /* SIMG: Rx PLL BW value from I2C BW ~ 4MHz*/
+ I2C_WriteByte(0x92, 0x45, 0x06); /* SIMG: DPLL Mode*/
+ I2C_WriteByte(0x72, 0xA0, 0xD0); /* SIMG: Term mode*/
+ I2C_WriteByte(0x72, 0xA1, 0xFC); /* Disable internal Mobile HD driver*/
+
+
+ I2C_WriteByte(0x72, 0xA3, 0xEB); /* SIMG: Output Swing default EB*/
+ I2C_WriteByte(0x72, 0xA6, 0x00); /* SIMG: Swing Offset*/
+
+ I2C_WriteByte(0x72, 0x2B, 0x01); /* Enable HDCP Compliance workaround*/
+
+ /*CBUS & Discovery*/
+ ReadModifyWriteTPI(0x90, SI_BIT_3 | SI_BIT_2, SI_BIT_3);/* CBUS discovery cycle time for each drive and float = 150us*/
+
+ I2C_WriteByte(0x72, 0x91, 0xE5); /* Skip RGND detection*/
+
+ I2C_WriteByte(0x72, 0x94, 0x66); /* 1.8V CBUS VTH & GND threshold*/
+
+ /*set bit 2 and 3, which is Initiator Timeout*/
+ I2C_WriteByte(CBUS_SLAVE_ADDR, 0x31, I2C_ReadByte(CBUS_SLAVE_ADDR, 0x31) | 0x0c);
+
+ /*original 3x config*/
+ I2C_WriteByte(0x72, 0xA5, 0x80); /* SIMG: RGND Hysterisis, 3x mode for Beast*/
+ I2C_WriteByte(0x72, 0x95, 0x31); /* RGND & single discovery attempt (RGND blocking)*/
+ I2C_WriteByte(0x72, 0x96, 0x22); /* use 1K and 2K setting*/
+
+ ReadModifyWriteTPI(0x95, SI_BIT_6, SI_BIT_6); /* Force USB ID switch to open*/
+
+ WriteByteTPI(0x92, 0x46); /* Force MHD mode*/
+ WriteByteTPI(0x93, 0xDC); /* Disable CBUS pull-up during RGND measurement*/
+
+ ReadModifyWriteTPI(0x79, SI_BIT_1 | SI_BIT_2, 0); /*daniel test...MHL_INT*/
+
+ mdelay(25);
+ ReadModifyWriteTPI(0x95, SI_BIT_6, 0x00); /* Release USB ID switch*/
+
+ I2C_WriteByte(0x72, 0x90, 0x27); /* Enable CBUS discovery*/
+
+ InitCBusRegs();
+
+ I2C_WriteByte(0x72, 0x05, ASR_VALUE); /* Enable Auto soft reset on SCDT = 0*/
+
+ I2C_WriteByte(0x72, 0x0D, 0x1C); /* HDMI Transcode mode enable*/
+}
+
diff --git a/drivers/accessory/MHD_SiI9234.h b/drivers/accessory/MHD_SiI9234.h
new file mode 100644
index 0000000..3bd52da
--- /dev/null
+++ b/drivers/accessory/MHD_SiI9234.h
@@ -0,0 +1,78 @@
+/*
+*/
+
+
+#ifndef __MHD_SiI9234_H
+#define __MHD_SiI9234_H
+
+
+/*typedef unsigned char bool;*/
+typedef unsigned char byte;
+typedef unsigned short word;
+
+
+
+#define DRV_NAME "MHD_sii9234"
+#define DRV_VERSION "0.1"
+#define MHD_MAX_LENGTH 4096
+#define GPIO_LOW 0
+#define GPIO_HIGH 1
+#define TX_HW_RESET_PERIOD 10
+#define TPI_SLAVE_ADDR 0x72
+
+#define ENABLE_AUTO_SOFT_RESET 0x04
+#define ASR_VALUE ENABLE_AUTO_SOFT_RESET
+
+/*TPI Identification Registers*/
+/*=============================*/
+
+#define TPI_DEVICE_ID (0x1B)
+#define TPI_DEVICE_REV_ID (0x1C)
+#define TPI_RESERVED2 (0x1D)
+
+#define SiI_DEVICE_ID 0xB0
+
+#define RSEN 0x04
+
+
+/*Indexed access defines*/
+#define TPI_INDEXED_PAGE_REG 0xBC
+#define TPI_INDEXED_OFFSET_REG 0xBD
+#define TPI_INDEXED_VALUE_REG 0xBE
+
+/*Generic Masks*/
+#define SI_ZERO 0x00
+#define SI_BIT_0 0x01
+#define SI_BIT_1 0x02
+#define SI_BIT_2 0x04
+#define SI_BIT_3 0x08
+#define SI_BIT_4 0x10
+#define SI_BIT_5 0x20
+#define SI_BIT_6 0x40
+#define SI_BIT_7 0x80
+
+#define DDC_XLTN_TIMEOUT_MAX_VAL 0x30
+
+/*Indexed register access*/
+
+#define INDEXED_PAGE_0 0x01
+#define INDEXED_PAGE_1 0x02
+#define INDEXED_PAGE_2 0x03
+
+
+#define NON_MASKABLE_INT 0xFF
+#define CBUS_SLAVE_ADDR 0xC8
+#define CEC_SLAVE_ADDR 0xC0
+
+#define FALSE 0
+#define TRUE 1
+
+typedef enum {
+ TX_HW_RESET,
+ GPIO_MAX
+} GPIO_SignalType;
+
+#define TPI_DEBUG_PRINT(x) printk x
+
+
+#endif/*__MHD_SiI9234_H*/
diff --git a/drivers/accessory/Makefile b/drivers/accessory/Makefile
new file mode 100644
index 0000000..aa8a336
--- /dev/null
+++ b/drivers/accessory/Makefile
@@ -0,0 +1,7 @@
+#
+# makefile for accessory
+#
+
+obj-$(CONFIG_30PIN_CONN) += 30pin_con.o
+obj-$(CONFIG_MHL_SII9234) += sii9234.o
+obj-$(CONFIG_SEC_KEYBOARD_DOCK) += sec_keyboard.o \ No newline at end of file
diff --git a/drivers/accessory/sec_keyboard.c b/drivers/accessory/sec_keyboard.c
new file mode 100644
index 0000000..1fbcc65
--- /dev/null
+++ b/drivers/accessory/sec_keyboard.c
@@ -0,0 +1,500 @@
+
+#include "sec_keyboard.h"
+
+static void sec_keyboard_tx(struct sec_keyboard_drvdata *data, u8 cmd)
+{
+ if (data->pre_connected && data->tx_ready)
+ serio_write(data->serio, cmd);
+}
+
+static void sec_keyboard_power(struct work_struct *work)
+{
+ struct sec_keyboard_drvdata *data = container_of(work,
+ struct sec_keyboard_drvdata, power_dwork.work);
+
+ if (UNKOWN_KEYLAYOUT == data->kl) {
+ data->acc_power(1, false);
+ data->pre_connected = false;
+
+ if (data->check_uart_path)
+ data->check_uart_path(false);
+ }
+}
+
+static void forced_wakeup(struct sec_keyboard_drvdata *data)
+{
+ input_report_key(data->input_dev,
+ KEY_WAKEUP, 1);
+ input_report_key(data->input_dev,
+ KEY_WAKEUP, 0);
+ input_sync(data->input_dev);
+}
+
+static void sec_keyboard_remapkey(struct work_struct *work)
+{
+ unsigned int keycode = 0;
+ struct sec_keyboard_drvdata *data = container_of(work,
+ struct sec_keyboard_drvdata, remap_dwork.work);
+
+ if (data->pressed[0x45] || data->pressed[0x48]) {
+ keycode = data->keycode[data->remap_key];
+ input_report_key(data->input_dev, keycode, 1);
+ input_sync(data->input_dev);
+ }
+ data->remap_key = 0;
+}
+
+static void release_all_keys(struct sec_keyboard_drvdata *data)
+{
+ int i;
+ printk(KERN_DEBUG "[Keyboard] Release the pressed keys.\n");
+ for (i = 0; i < KEYBOARD_MAX; i++) {
+ if (data->pressed[i]) {
+ input_report_key(data->input_dev, data->keycode[i], 0);
+ data->pressed[i] = false;
+ }
+ input_sync(data->input_dev);
+ }
+}
+
+static void sec_keyboard_process_data(
+ struct sec_keyboard_drvdata *data, u8 scan_code)
+{
+ bool press;
+ unsigned int keycode;
+
+ /* keyboard driver need the contry code*/
+ if (data->kl == UNKOWN_KEYLAYOUT) {
+ switch (scan_code) {
+ case US_KEYBOARD:
+ data->kl = US_KEYLAYOUT;
+ data->keycode[49] = KEY_BACKSLASH;
+ /* for the wakeup state*/
+ data->pre_kl = data->kl;
+ printk(KERN_DEBUG "[Keyboard] US keyboard is attacted.\n");
+ break;
+
+ case UK_KEYBOARD:
+ data->kl = UK_KEYLAYOUT;
+ data->keycode[49] = KEY_NUMERIC_POUND;
+ /* for the wakeup state*/
+ data->pre_kl = data->kl;
+ printk(KERN_DEBUG "[Keyboard] UK keyboard is attacted.\n");
+ break;
+
+ default:
+ printk(KERN_DEBUG "[Keyboard] Unkown layout : %x\n",
+ scan_code);
+ break;
+ }
+ } else {
+ switch (scan_code) {
+ case 0x0:
+ release_all_keys(data);
+ break;
+
+ case 0xca: /* Caps lock on */
+ case 0xcb: /* Caps lock off */
+ case 0xeb: /* US keyboard */
+ case 0xec: /* UK keyboard */
+ break; /* Ignore */
+
+ case 0x45:
+ case 0x48:
+ data->remap_key = scan_code;
+ data->pressed[scan_code] = true;
+ schedule_delayed_work(&data->remap_dwork, HZ/3);
+ break;
+
+ case 0xc5:
+ case 0xc8:
+ keycode = (scan_code & 0x7f);
+ data->pressed[keycode] = false;
+ if (0 == data->remap_key) {
+ input_report_key(data->input_dev,
+ data->keycode[keycode], 0);
+ input_sync(data->input_dev);
+ } else {
+ cancel_delayed_work_sync(&data->remap_dwork);
+ if (0x48 == keycode)
+ keycode = KEY_NEXTSONG;
+ else
+ keycode = KEY_PREVIOUSSONG;
+
+ input_report_key(data->input_dev,
+ keycode, 1);
+ input_report_key(data->input_dev,
+ keycode, 0);
+ input_sync(data->input_dev);
+ }
+ break;
+
+ default:
+ keycode = (scan_code & 0x7f);
+ press = ((scan_code & 0x80) != 0x80);
+
+ if (keycode >= KEYBOARD_MIN
+ || keycode <= KEYBOARD_MAX) {
+ data->pressed[keycode] = press;
+ input_report_key(data->input_dev,
+ data->keycode[keycode], press);
+ input_sync(data->input_dev);
+ }
+ break;
+ }
+ }
+}
+
+static int check_keyboard_dock(struct sec_keyboard_callbacks *cb, bool val)
+{
+ struct sec_keyboard_drvdata *data =
+ container_of(cb, struct sec_keyboard_drvdata, callbacks);
+ int try_cnt = 0;
+ int max_cnt = 14;
+
+ if (NULL == data->serio)
+ return 0;
+
+ if (!val)
+ data->dockconnected = false;
+ else {
+ cancel_delayed_work_sync(&data->power_dwork);
+ /* wakeup by keyboard dock */
+ if (data->pre_connected) {
+ if (UNKOWN_KEYLAYOUT != data->pre_kl) {
+ data->kl = data->pre_kl;
+ data->acc_power(1, true);
+ forced_wakeup(data);
+ printk(KERN_DEBUG "[Keyboard] kl : %d\n",
+ data->pre_kl);
+ return 1;
+ }
+ } else
+ data->pre_kl = UNKOWN_KEYLAYOUT;
+
+ data->pre_connected = true;
+
+ /* to prevent the over current issue */
+ data->acc_power(0, false);
+
+ if (data->check_uart_path)
+ data->check_uart_path(true);
+
+ msleep(200);
+ data->acc_power(1, true);
+
+ /* try to get handshake data */
+ for (try_cnt = 0; try_cnt < max_cnt; try_cnt++) {
+ msleep(50);
+ if (data->kl != UNKOWN_KEYLAYOUT) {
+ data->dockconnected = true;
+ break;
+ }
+ if (gpio_get_value(data->acc_int_gpio)) {
+ printk(KERN_DEBUG "[Keyboard] acc is disconnected.\n");
+ break;
+ }
+ }
+ }
+
+ if (data->dockconnected) {
+ forced_wakeup(data);
+ return 1;
+ } else {
+ if (data->pre_connected) {
+ data->dockconnected = false;
+ schedule_delayed_work(&data->power_dwork, HZ/2);
+
+ data->kl = UNKOWN_KEYLAYOUT;
+ release_all_keys(data);
+ }
+ return 0;
+ }
+}
+
+static int sec_keyboard_event(struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
+{
+ struct sec_keyboard_drvdata *data = input_get_drvdata(dev);
+
+ switch (type) {
+ case EV_LED:
+ if (value)
+ sec_keyboard_tx(data, 0xca);
+ else
+ sec_keyboard_tx(data, 0xcb);
+ return 0;
+ }
+ return -1;
+}
+
+static ssize_t check_keyboard_connection(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct sec_keyboard_drvdata *ddata = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", ddata->dockconnected);
+}
+
+static DEVICE_ATTR(attached, S_IRUGO, check_keyboard_connection, NULL);
+
+static struct attribute *sec_keyboard_attributes[] = {
+ &dev_attr_attached.attr,
+ NULL,
+};
+
+static struct attribute_group attr_group = {
+ .attrs = sec_keyboard_attributes,
+};
+
+static irqreturn_t sec_keyboard_interrupt(struct serio *serio,
+ unsigned char data, unsigned int flags)
+{
+ struct sec_keyboard_drvdata *ddata = serio_get_drvdata(serio);
+ if (ddata->pre_connected)
+ sec_keyboard_process_data(ddata, data);
+ return IRQ_HANDLED;
+}
+
+static int sec_keyboard_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct sec_keyboard_drvdata *data = container_of(drv,
+ struct sec_keyboard_drvdata, serio_driver);
+ printk(KERN_DEBUG "[Keyboard] %s", __func__);
+ data->serio = serio;
+ serio_set_drvdata(serio, data);
+ if (serio_open(serio, drv))
+ printk(KERN_ERR "[Keyboard] failed to open serial port\n");
+ else
+ data->tx_ready = true;
+ return 0;
+}
+
+static void sec_keyboard_disconnect(struct serio *serio)
+{
+ struct sec_keyboard_drvdata *data = serio_get_drvdata(serio);
+ printk(KERN_DEBUG "[Keyboard] %s", __func__);
+ data->tx_ready = false;
+ serio_close(serio);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void keyboard_early_suspend(struct early_suspend *early_sus)
+{
+ struct sec_keyboard_drvdata *data = container_of(early_sus,
+ struct sec_keyboard_drvdata, early_suspend);
+
+ if (data->kl != UNKOWN_KEYLAYOUT) {
+ /*
+ if the command of the caps lock off is needed,
+ this command should be sent.
+ sec_keyboard_tx(0xcb);
+ msleep(20);
+ */
+ sec_keyboard_tx(data, 0x10); /* the idle mode */
+ }
+}
+
+static void keyboard_late_resume(struct early_suspend *early_sus)
+{
+ struct sec_keyboard_drvdata *data = container_of(early_sus,
+ struct sec_keyboard_drvdata, early_suspend);
+
+ if (data->kl != UNKOWN_KEYLAYOUT)
+ printk(KERN_DEBUG "[Keyboard] %s\n", __func__);
+
+}
+#endif
+static int __devinit sec_keyboard_probe(struct platform_device *pdev)
+{
+ struct sec_keyboard_platform_data *pdata = pdev->dev.platform_data;
+ struct sec_keyboard_drvdata *ddata;
+ struct input_dev *input;
+ int i, error;
+
+ if (pdata == NULL) {
+ printk(KERN_ERR "%s: no pdata\n", __func__);
+ return -ENODEV;
+ }
+
+ ddata = kzalloc(sizeof(struct sec_keyboard_drvdata), GFP_KERNEL);
+ if (NULL == ddata) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ input = input_allocate_device();
+ if (NULL == input) {
+ printk(KERN_ERR "[Keyboard] failed to allocate input device.\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ ddata->input_dev = input;
+ ddata->acc_power = pdata->acc_power;
+ ddata->check_uart_path = pdata->check_uart_path;
+ ddata->acc_int_gpio = pdata->accessory_irq_gpio;
+ ddata->led_on = false;
+ ddata->dockconnected = false;
+ ddata->pre_connected = false;
+ ddata->remap_key = 0;
+ ddata->kl = UNKOWN_KEYLAYOUT;
+ ddata->callbacks.check_keyboard_dock = check_keyboard_dock;
+ if (pdata->register_cb)
+ pdata->register_cb(&ddata->callbacks);
+
+ memcpy(ddata->keycode, sec_keycodes, sizeof(sec_keycodes));
+
+ INIT_DELAYED_WORK(&ddata->remap_dwork, sec_keyboard_remapkey);
+ INIT_DELAYED_WORK(&ddata->power_dwork, sec_keyboard_power);
+
+ platform_set_drvdata(pdev, ddata);
+ input_set_drvdata(input, ddata);
+
+ input->name = pdev->name;
+ input->dev.parent = &pdev->dev;
+ input->id.bustype = BUS_RS232;
+ input->event = sec_keyboard_event;
+
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(EV_LED, input->evbit);
+ __set_bit(LED_CAPSL, input->ledbit);
+ /* framework doesn't use repeat event */
+ /* __set_bit(EV_REP, input->evbit); */
+
+ for (i = 0; i < KEYBOARD_SIZE; i++) {
+ if (KEY_RESERVED != ddata->keycode[i])
+ input_set_capability(input, EV_KEY, ddata->keycode[i]);
+ }
+
+ /* for the UK keyboard */
+ input_set_capability(input, EV_KEY, KEY_NUMERIC_POUND);
+
+ /* for the remaped keys */
+ input_set_capability(input, EV_KEY, KEY_NEXTSONG);
+ input_set_capability(input, EV_KEY, KEY_PREVIOUSSONG);
+
+ /* for the wakeup key */
+ input_set_capability(input, EV_KEY, KEY_WAKEUP);
+
+ error = input_register_device(input);
+ if (error < 0) {
+ printk(KERN_ERR "[Keyboard] failed to register input device.\n");
+ error = -ENOMEM;
+ goto err_input_allocate_device;
+ }
+
+ ddata->serio_driver.driver.name = pdev->name;
+ ddata->serio_driver.id_table = sec_serio_ids;
+ ddata->serio_driver.interrupt = sec_keyboard_interrupt,
+ ddata->serio_driver.connect = sec_keyboard_connect,
+ ddata->serio_driver.disconnect = sec_keyboard_disconnect,
+
+ error = serio_register_driver(&ddata->serio_driver);
+ if (error < 0) {
+ printk(KERN_ERR "[Keyboard] failed to register serio\n");
+ error = -ENOMEM;
+ goto err_reg_serio;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ ddata->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ ddata->early_suspend.suspend = keyboard_early_suspend;
+ ddata->early_suspend.resume = keyboard_late_resume;
+ register_early_suspend(&ddata->early_suspend);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+ ddata->keyboard_dev = device_create(sec_class, NULL, 0,
+ ddata, "sec_keyboard");
+ if (IS_ERR(ddata->keyboard_dev)) {
+ printk(KERN_ERR "[Keyboard] failed to create device for the sysfs\n");
+ error = -ENODEV;
+ goto err_sysfs_create_group;
+ }
+
+ error = sysfs_create_group(&ddata->keyboard_dev->kobj, &attr_group);
+ if (error) {
+ printk(KERN_ERR "[Keyboard] failed to create sysfs group\n");
+ goto err_sysfs_create_group;
+ }
+
+ return 0;
+
+err_sysfs_create_group:
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&ddata->early_suspend);
+#endif
+ serio_unregister_driver(&ddata->serio_driver);
+err_reg_serio:
+err_input_allocate_device:
+ input_free_device(input);
+ del_timer_sync(&ddata->remap_dwork.timer);
+ del_timer_sync(&ddata->power_dwork.timer);
+err_free_mem:
+ kfree(ddata);
+ return error;
+
+}
+
+static int __devexit sec_keyboard_remove(struct platform_device *pdev)
+{
+ struct sec_keyboard_drvdata *data = platform_get_drvdata(pdev);
+ input_unregister_device(data->input_dev);
+ serio_unregister_driver(&data->serio_driver);
+ return 0;
+}
+
+#ifndef CONFIG_HAS_EARLYSUSPEND
+static int sec_keyboard_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct sec_keyboard_drvdata *data = platform_get_drvdata(pdev);
+
+ if (data->kl != UNKOWN_KEYLAYOUT)
+ sec_keyboard_tx(data, 0x10);
+
+ return 0;
+}
+
+static int sec_keyboard_resume(struct platform_device *pdev)
+{
+ struct sec_keyboard_platform_data *pdata = pdev->dev.platform_data;
+ struct sec_keyboard_drvdata *data = platform_get_drvdata(pdev);
+ if (pdata->wakeup_key) {
+ if (KEY_WAKEUP == pdata->wakeup_key())
+ forced_wakeup(data);
+ }
+
+ return 0;
+}
+#endif
+
+static struct platform_driver sec_keyboard_driver = {
+ .probe = sec_keyboard_probe,
+ .remove = __devexit_p(sec_keyboard_remove),
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = sec_keyboard_suspend,
+ .resume = sec_keyboard_resume,
+#endif
+ .driver = {
+ .name = "sec_keyboard",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init sec_keyboard_init(void)
+{
+ return platform_driver_register(&sec_keyboard_driver);
+}
+
+static void __exit sec_keyboard_exit(void)
+{
+ platform_driver_unregister(&sec_keyboard_driver);
+}
+
+module_init(sec_keyboard_init);
+module_exit(sec_keyboard_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SEC Keyboard Dock driver");
diff --git a/drivers/accessory/sec_keyboard.h b/drivers/accessory/sec_keyboard.h
new file mode 100644
index 0000000..7a30b58
--- /dev/null
+++ b/drivers/accessory/sec_keyboard.h
@@ -0,0 +1,208 @@
+
+#ifndef _SEC_KEYBOARD_H_
+#define _SEC_KEYBOARD_H_
+
+#include <linux/input.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/earlysuspend.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/30pin_con.h>
+#include <linux/serio.h>
+
+#define KEYBOARD_SIZE 128
+#define US_KEYBOARD 0xeb
+#define UK_KEYBOARD 0xec
+
+#define KEYBOARD_MIN 0x4
+#define KEYBOARD_MAX 0x7f
+
+enum KEY_LAYOUT {
+ UNKOWN_KEYLAYOUT = 0,
+ US_KEYLAYOUT,
+ UK_KEYLAYOUT,
+};
+
+extern struct class *sec_class;
+
+static struct serio_device_id sec_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = 0x3c,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, sec_serio_ids);
+
+struct sec_keyboard_drvdata {
+ struct input_dev *input_dev;
+ struct device *keyboard_dev;
+ struct delayed_work remap_dwork;
+ struct delayed_work power_dwork;
+ struct sec_keyboard_callbacks callbacks;
+ struct serio *serio;
+ struct serio_driver serio_driver;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+ void (*acc_power)(u8 token, bool active);
+ void (*check_uart_path)(bool en);
+ bool led_on;
+ bool dockconnected;
+ bool pre_connected;
+ bool pressed[KEYBOARD_SIZE];
+ bool pre_uart_path;
+ bool tx_ready;
+ int acc_int_gpio;
+ unsigned int remap_key;
+ unsigned int kl;
+ unsigned int pre_kl;
+ unsigned short keycode[KEYBOARD_SIZE];
+ unsigned long connected_time;
+ unsigned long disconnected_time;
+};
+
+static const unsigned short sec_keycodes[KEYBOARD_SIZE] = {
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_A,
+ KEY_B,
+ KEY_C,
+ KEY_D,
+ KEY_E,
+ KEY_F,
+ KEY_G,
+ KEY_H,
+ KEY_I,
+ KEY_J,
+ KEY_K,
+ KEY_L,
+ KEY_M,
+ KEY_N,
+ KEY_O,
+ KEY_P,
+ KEY_Q,
+ KEY_R,
+ KEY_S,
+ KEY_T,
+ KEY_U,
+ KEY_V,
+ KEY_W,
+ KEY_X,
+ KEY_Y,
+ KEY_Z,
+ KEY_1,
+ KEY_2,
+ KEY_3,
+ KEY_4,
+ KEY_5,
+ KEY_6,
+ KEY_7,
+ KEY_8,
+ KEY_9,
+ KEY_0,
+ KEY_ENTER,
+ KEY_BACK,
+ KEY_BACKSPACE,
+ KEY_TAB,
+ KEY_SPACE,
+ KEY_MINUS,
+ KEY_EQUAL,
+ KEY_LEFTBRACE,
+ KEY_RIGHTBRACE,
+ KEY_HOME,
+ KEY_RESERVED,
+ KEY_SEMICOLON,
+ KEY_APOSTROPHE,
+ KEY_GRAVE,
+ KEY_COMMA,
+ KEY_DOT,
+ KEY_SLASH,
+ KEY_CAPSLOCK,
+ KEY_TIME,
+ KEY_F3,
+ KEY_WWW,
+ KEY_EMAIL,
+ KEY_SCREENLOCK,
+ KEY_BRIGHTNESSDOWN,
+ KEY_BRIGHTNESSUP,
+ KEY_MUTE,
+ KEY_VOLUMEDOWN,
+ KEY_VOLUMEUP,
+ KEY_PLAY,
+ KEY_REWIND,
+ KEY_F15,
+ KEY_RESERVED,
+ KEY_FASTFORWARD,
+ KEY_MENU,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_DELETE,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RIGHT,
+ KEY_LEFT,
+ KEY_DOWN,
+ KEY_UP,
+ KEY_NUMLOCK,
+ KEY_KPSLASH,
+ KEY_APOSTROPHE,
+ KEY_KPMINUS,
+ KEY_KPPLUS,
+ KEY_KPENTER,
+ KEY_KP1,
+ KEY_KP2,
+ KEY_KP3,
+ KEY_KP4,
+ KEY_KP5,
+ KEY_KP6,
+ KEY_KP7,
+ KEY_KP8,
+ KEY_KP9,
+ KEY_KPDOT,
+ KEY_RESERVED,
+ KEY_BACKSLASH,
+ KEY_F22,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_HANGEUL,
+ KEY_HANJA,
+ KEY_LEFTCTRL,
+ KEY_LEFTSHIFT,
+ KEY_F20,
+ KEY_SEARCH,
+ KEY_RIGHTALT,
+ KEY_RIGHTSHIFT,
+ KEY_F21,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_F17,
+};
+#endif /*_SEC_KEYBOARD_H_*/
+
diff --git a/drivers/accessory/sii9234.c b/drivers/accessory/sii9234.c
new file mode 100644
index 0000000..d8c0408
--- /dev/null
+++ b/drivers/accessory/sii9234.c
@@ -0,0 +1,339 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <asm/irq.h>
+#include <linux/delay.h>
+#include <linux/mhd9234.h>
+
+#include "MHD_SiI9234.h"
+#include "sii9234_tpi_regs.h"
+
+
+#include <linux/syscalls.h>
+#include <linux/fcntl.h>
+#include <linux/uaccess.h>
+
+#include <linux/slab.h>
+
+
+#define SUBJECT "MHL_DRIVER"
+
+#define SII_DEV_DBG(format, ...)\
+ pr_info("[ "SUBJECT " (%s,%d) ] " format "\n",\
+ __func__, __LINE__, ## __VA_ARGS__);
+
+struct i2c_client *SII9234_i2c_client;
+struct i2c_client *SII9234A_i2c_client;
+struct i2c_client *SII9234B_i2c_client;
+struct i2c_client *SII9234C_i2c_client;
+
+static struct i2c_device_id SII9234_id[] = {
+ {"SII9234", 0},
+ {}
+};
+
+static struct i2c_device_id SII9234A_id[] = {
+ {"SII9234A", 0},
+ {}
+};
+
+static struct i2c_device_id SII9234B_id[] = {
+ {"SII9234B", 0},
+ {}
+};
+
+static struct i2c_device_id SII9234C_id[] = {
+ {"SII9234C", 0},
+ {}
+};
+
+struct SII9234_state {
+ struct i2c_client *client;
+};
+
+static struct timer_list MHL_reg_check;
+
+static u8 SII9234_i2c_read(struct i2c_client *client, u8 reg)
+{
+ u8 ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0) {
+ SII_DEV_DBG("i2c read fail");
+ return -EIO;
+ }
+ return ret;
+
+}
+
+
+static int SII9234_i2c_write(struct i2c_client *client, u8 reg, u8 data)
+{
+ return i2c_smbus_write_byte_data(client, reg, data);
+}
+
+void SII9234_HW_Reset(struct i2c_client *client)
+{
+ struct sii9234_platform_data *pdata = client->dev.platform_data;
+ SII_DEV_DBG("");
+ pdata->hw_reset();
+}
+
+void SII9234_HW_Off(struct i2c_client *client)
+{
+ struct sii9234_platform_data *pdata = client->dev.platform_data;
+ SII_DEV_DBG("");
+ pdata->hw_off();
+}
+
+int SII9234_HW_IsOn(void)
+{
+/* #warning - this needs fixing */
+/* int IsOn = gpio_get_value(GPIO_HDMI_EN1); */
+/* if(IsOn) */
+ return true;
+/* else */
+ return false;
+}
+
+#include "MHD_SiI9234.c"
+
+void sii_9234_monitor(unsigned long arg)
+{
+ SII_DEV_DBG("");
+ /*sii9234_polling(); */
+ ReadIndexedRegister(INDEXED_PAGE_0, 0x81);
+#if 0
+ pr_info("SII9234_i2c_read INDEXED_PAGE_0: 0x%02x\n", data);
+
+ MHL_reg_check.expires = get_jiffies_64() + (HZ*3);
+ add_timer(&MHL_reg_check);
+#endif
+}
+
+static void check_HDMI_signal(unsigned long arg)
+{
+ SII_DEV_DBG("");
+
+#if 0
+ u8 data;
+
+ MHL_HW_Reset();
+ sii9234_initial_registers_set();
+ startTPI();
+ mhl_output_enable();
+#endif
+ sii9234_tpi_init();
+
+ MHL_reg_check.function = sii_9234_monitor;
+ MHL_reg_check.expires = get_jiffies_64() + (HZ*3);
+ add_timer(&MHL_reg_check);
+#if 0
+ data = ReadIndexedRegister(INDEXED_PAGE_0, 0x81);
+ pr_info("SII9234_i2c_read INDEXED_PAGE_0: 0x%02x\n", data);
+#endif
+}
+
+
+
+#if 0
+static DECLARE_DELAYED_WORK(init_sii9234, sii92324_init_sequance);
+#endif
+
+static int SII9234_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct SII9234_state *state;
+
+ SII_DEV_DBG("");
+
+ state = kzalloc(sizeof(struct SII9234_state), GFP_KERNEL);
+ if (!state) {
+ pr_err("failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ state->client = client;
+ i2c_set_clientdata(client, state);
+
+ /* rest of the initialisation goes here. */
+
+ pr_info("SII9234 attach success!!!\n");
+
+ SII9234_i2c_client = client;
+
+#if 0
+ schedule_delayed_work(&init_sii9234, 5000);
+
+ init_timer(&MHL_reg_check);
+ MHL_reg_check.function = check_HDMI_signal;
+ MHL_reg_check.expires = get_jiffies_64() + (HZ*10);
+ add_timer(&MHL_reg_check);
+
+ MHL_HW_Reset();
+ sii9234_initial_registers_set();
+ startTPI();
+ mhl_output_enable();
+#endif
+
+ return 0;
+}
+
+
+
+static int __devexit SII9234_remove(struct i2c_client *client)
+{
+ struct SII9234_state *state = i2c_get_clientdata(client);
+ kfree(state);
+
+ return 0;
+}
+
+static int SII9234A_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct SII9234_state *state;
+
+ SII_DEV_DBG("");
+
+ state = kzalloc(sizeof(struct SII9234_state), GFP_KERNEL);
+ if (!state) {
+ pr_err("failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ state->client = client;
+ i2c_set_clientdata(client, state);
+
+ /* rest of the initialisation goes here. */
+
+ pr_info("SII9234A attach success!!!\n");
+
+ SII9234A_i2c_client = client;
+
+ return 0;
+
+}
+
+
+
+static int __devexit SII9234A_remove(struct i2c_client *client)
+{
+ struct SII9234_state *state = i2c_get_clientdata(client);
+ kfree(state);
+ return 0;
+}
+
+static int SII9234B_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct SII9234_state *state;
+
+ SII_DEV_DBG("");
+
+ state = kzalloc(sizeof(struct SII9234_state), GFP_KERNEL);
+ if (!state) {
+ pr_err("failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ state->client = client;
+ i2c_set_clientdata(client, state);
+
+ /* rest of the initialisation goes here. */
+
+ pr_info("SII9234B attach success!!!\n");
+
+ SII9234B_i2c_client = client;
+
+ return 0;
+}
+
+
+
+static int __devexit SII9234B_remove(struct i2c_client *client)
+{
+ struct SII9234_state *state = i2c_get_clientdata(client);
+ kfree(state);
+ return 0;
+}
+
+static int SII9234C_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct SII9234_state *state;
+
+ SII_DEV_DBG("");
+
+ state = kzalloc(sizeof(struct SII9234_state), GFP_KERNEL);
+ if (!state) {
+ pr_err("failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ state->client = client;
+ i2c_set_clientdata(client, state);
+
+ /* rest of the initialisation goes here. */
+ pr_info("SII9234C attach success!!!\n");
+
+ SII9234C_i2c_client = client;
+
+ return 0;
+
+}
+
+
+
+static int __devexit SII9234C_remove(struct i2c_client *client)
+{
+ struct SII9234_state *state = i2c_get_clientdata(client);
+ kfree(state);
+ return 0;
+}
+
+
+struct i2c_driver SII9234_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "SII9234",
+ },
+ .id_table = SII9234_id,
+ .probe = SII9234_i2c_probe,
+ .remove = __devexit_p(SII9234_remove),
+ .command = NULL,
+};
+
+struct i2c_driver SII9234A_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "SII9234A",
+ },
+ .id_table = SII9234A_id,
+ .probe = SII9234A_i2c_probe,
+ .remove = __devexit_p(SII9234A_remove),
+ .command = NULL,
+};
+
+struct i2c_driver SII9234B_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "SII9234B",
+ },
+ .id_table = SII9234B_id,
+ .probe = SII9234B_i2c_probe,
+ .remove = __devexit_p(SII9234B_remove),
+ .command = NULL,
+};
+
+struct i2c_driver SII9234C_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "SII9234C",
+ },
+ .id_table = SII9234C_id,
+ .probe = SII9234C_i2c_probe,
+ .remove = __devexit_p(SII9234C_remove),
+ .command = NULL,
+};
+
+
diff --git a/drivers/accessory/sii9234.h b/drivers/accessory/sii9234.h
new file mode 100644
index 0000000..faa1227
--- /dev/null
+++ b/drivers/accessory/sii9234.h
@@ -0,0 +1,191 @@
+/*
+ * Silicon Image MHL(Mobile HD Link) Transmitter device driver
+ *
+ * Copyright (c) by Dongsoo Kim <dongsoo45.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <linux/types.h>
+
+#define SII9234_I2C_CHECK_RETRY 50
+#define SII9234_SEC(a) ((a*HZ/10) * 10)
+
+#define TRUE 1
+#define FALSE 0
+
+/*
+ * regset item mode ID
+ */
+#define SII_W 0x01
+#define SII_R 0x02
+#define SII_M 0x03
+#define SII_D 0x04
+
+/*
+ * Local register define
+ */
+#define TX_SLAVE_ADDR (0x72 >> 1)
+#define SII9234_ES_P1 (0x7A >> 1)
+#define SII9234_ES_P2 (0x92 >> 1)
+#define CBUS_SLAVE_ADDR (0xC8 >> 1)
+
+/* BIT MASK */
+#define BIT_0 0x01
+#define BIT_1 0x02
+#define BIT_2 0x04
+#define BIT_3 0x08
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+
+/* power state */
+#define TX_POWER_STATE_D0 0x00
+#define TX_POWER_STATE_D1 0x01
+#define TX_POWER_STATE_D2 0x02
+#define TX_POWER_STATE_D3 0x03
+
+/*
+ * @sii9234_regset
+ * mode : 0x01(write), 0x02(read), 0x03(mask)
+ * addr : TX_SLAVE_ADDR, SII9234_ES_P1,
+ * SII9234_ES_P2, CBUS_SLAVE_ADDR
+ * reg : address of register
+ * val : expecting value
+ */
+struct sii9234_regset {
+ unsigned char mode;
+ unsigned char addr;
+ unsigned char reg;
+ unsigned char val;
+};
+
+/* TPI System Control Register ================= */
+
+#define TPI_SYSTEM_CONTROL_DATA_REG (0x1A)
+
+#define LINK_INTEGRITY_MODE_MASK (BIT_6)
+#define LINK_INTEGRITY_STATIC (0x00)
+#define LINK_INTEGRITY_DYNAMIC (0x40)
+
+#define TMDS_OUTPUT_CONTROL_MASK (BIT_4)
+#define TMDS_OUTPUT_CONTROL_ACTIVE (0x00)
+#define TMDS_OUTPUT_CONTROL_POWER_DOWN (0x10)
+
+#define AV_MUTE_MASK (BIT_3)
+#define AV_MUTE_NORMAL (0x00)
+#define AV_MUTE_MUTED (0x08)
+
+#define DDC_BUS_REQUEST_MASK (BIT_2)
+#define DDC_BUS_REQUEST_NOT_USING (0x00)
+#define DDC_BUS_REQUEST_REQUESTED (0x04)
+
+#define DDC_BUS_GRANT_MASK (BIT_1)
+#define DDC_BUS_GRANT_NOT_AVAILABLE (0x00)
+#define DDC_BUS_GRANT_GRANTED (0x02)
+
+#define OUTPUT_MODE_MASK (BIT_0)
+#define OUTPUT_MODE_DVI (0x00)
+#define OUTPUT_MODE_HDMI (0x01)
+
+/* Interrupt Enable Register =================== */
+
+#define TPI_INTERRUPT_ENABLE_REG (0x3C)
+
+#define HDCP_AUTH_STATUS_CHANGE_EN_MASK (BIT_7)
+#define HDCP_AUTH_STATUS_CHANGE_DISABLE (0x00)
+#define HDCP_AUTH_STATUS_CHANGE_ENABLE (0x80)
+
+#define HDCP_VPRIME_VALUE_READY_EN_MASK (BIT_6)
+#define HDCP_VPRIME_VALUE_READY_DISABLE (0x00)
+#define HDCP_VPRIME_VALUE_READY_ENABLE (0x40)
+
+#define HDCP_SECURITY_CHANGE_EN_MASK (BIT_5)
+#define HDCP_SECURITY_CHANGE_DISABLE (0x00)
+#define HDCP_SECURITY_CHANGE_ENABLE (0x20)
+
+#define AUDIO_ERROR_EVENT_EN_MASK (BIT_4)
+#define AUDIO_ERROR_EVENT_DISABLE (0x00)
+#define AUDIO_ERROR_EVENT_ENABLE (0x10)
+
+#define CPI_EVENT_NO_RX_SENSE_MASK (BIT_3)
+#define CPI_EVENT_NO_RX_SENSE_DISABLE (0x00)
+#define CPI_EVENT_NO_RX_SENSE_ENABLE (0x08)
+
+#define RECEIVER_SENSE_EVENT_EN_MASK (BIT_1)
+#define RECEIVER_SENSE_EVENT_DISABLE (0x00)
+#define RECEIVER_SENSE_EVENT_ENABLE (0x02)
+
+#define HOT_PLUG_EVENT_EN_MASK (BIT_0)
+#define HOT_PLUG_EVENT_DISABLE (0x00)
+#define HOT_PLUG_EVENT_ENABLE (0x01)
+
+/* Interrupt status register ==================== */
+#define TPI_INTERRUPT_STATUS_REG (0x3D)
+
+#define HDCP_AUTH_STATUS_CHANGE_EVENT_MASK (BIT_7)
+#define HDCP_AUTH_STATUS_CHANGE_EVENT_NO (0x00)
+#define HDCP_AUTH_STATUS_CHANGE_EVENT_YES (0x80)
+
+#define HDCP_VPRIME_VALUE_READY_EVENT_MASK (BIT_6)
+#define HDCP_VPRIME_VALUE_READY_EVENT_NO (0x00)
+#define HDCP_VPRIME_VALUE_READY_EVENT_YES (0x40)
+
+#define HDCP_SECURITY_CHANGE_EVENT_MASK (BIT_5)
+#define HDCP_SECURITY_CHANGE_EVENT_NO (0x00)
+#define HDCP_SECURITY_CHANGE_EVENT_YES (0x20)
+
+#define AUDIO_ERROR_EVENT_MASK (BIT_4)
+#define AUDIO_ERROR_EVENT_NO (0x00)
+#define AUDIO_ERROR_EVENT_YES (0x10)
+
+#define CPI_EVENT_MASK (BIT_3)
+#define CPI_EVENT_NO (0x00)
+#define CPI_EVENT_YES (0x08)
+/* This bit is dual purpose depending on the value of 0x3C[3] */
+#define RX_SENSE_MASK (BIT_3)
+#define RX_SENSE_NOT_ATTACHED (0x00)
+#define RX_SENSE_ATTACHED (0x08)
+
+#define HOT_PLUG_PIN_STATE_MASK (BIT_2)
+#define HOT_PLUG_PIN_STATE_LOW (0x00)
+#define HOT_PLUG_PIN_STATE_HIGH (0x04)
+
+#define RECEIVER_SENSE_EVENT_MASK (BIT_1)
+#define RECEIVER_SENSE_EVENT_NO (0x00)
+#define RECEIVER_SENSE_EVENT_YES (0x02)
+
+#define HOT_PLUG_EVENT_MASK (BIT_0)
+#define HOT_PLUG_EVENT_NO (0x00)
+#define HOT_PLUG_EVENT_YES (0x01)
+
+/* ===================================================== */
+
+extern void sii9234_tpi_init(void);
+extern void MHD_HW_Reset(void);
+extern void MHD_HW_Off(void);
+extern int MHD_HW_IsOn(void);
+extern int MHD_Read_deviceID(void);
+extern void MHD_INT_clear(void);
+extern void MHD_OUT_EN(void);
+
+/*I2C driver add 20100614 kyungrok */
+extern struct i2c_driver SII9234_i2c_driver;
+extern struct i2c_driver SII9234A_i2c_driver;
+extern struct i2c_driver SII9234B_i2c_driver;
+extern struct i2c_driver SII9234C_i2c_driver;
+
+
diff --git a/drivers/accessory/sii9234_tpi_regs.h b/drivers/accessory/sii9234_tpi_regs.h
new file mode 100644
index 0000000..7e0a71f
--- /dev/null
+++ b/drivers/accessory/sii9234_tpi_regs.h
@@ -0,0 +1,381 @@
+/*
+ * MHD_SiI9234.c - Driver for Silicon Image MHD SiI9234 Transmitter driver
+ *
+ * Copyright 2010 Philju Lee (Daniel Lee)
+ *
+ * Based on preview driver from Silicon Image.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * 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.
+ *
+ */
+
+/*TPI Video Mode Data*/
+
+#define TPI_PIX_CLK_LSB (0x00)
+#define TPI_PIX_CLK_MSB (0x01)
+
+#define TPI_VERT_FREQ_LSB (0x02)
+#define TPI_VERT_FREQ_MSB (0x03)
+
+#define TPI_TOTAL_PIX_LSB (0x04)
+#define TPI_TOTAL_PIX_MSB (0x05)
+
+#define TPI_TOTAL_LINES_LSB (0x06)
+#define TPI_TOTAL_LINES_MSB (0x07)
+
+/*Pixel Repetition Data*/
+
+#define TPI_PIX_REPETITION (0x08)
+
+/*TPI AVI Input and Output Format Data*/
+
+/* AVI Input Format Data =====================================*/
+
+#define TPI_INPUT_FORMAT_REG (0x09)
+
+#define INPUT_COLOR_SPACE_MASK (SI_BIT_1 | SI_BIT_0)
+#define INPUT_COLOR_SPACE_RGB (SI_ZERO)
+#define INPUT_COLOR_SPACE_YCBCR444 (SI_BIT_0)
+#define INPUT_COLOR_SPACE_YCBCR422 (SI_BIT_1)
+#define INPUT_COLOR_SPACE_BLACK_MODE (SI_BIT_1 | SI_BIT_0)
+
+/* AVI Output Format Data =============================================== */
+
+#define TPI_OUTPUT_FORMAT_REG (0x0A)
+
+#define TPI_YC_Input_Mode (0x0B)
+
+/*TPI AVI InfoFrame Data*/
+
+#define TPI_AVI_BYTE_0 (0x0C)
+#define TPI_AVI_BYTE_1 (0x0D)
+#define TPI_AVI_BYTE_2 (0x0E)
+#define TPI_AVI_BYTE_3 (0x0F)
+#define TPI_AVI_BYTE_4 (0x10)
+#define TPI_AVI_BYTE_5 (0x11)
+
+#define TPI_AUDIO_BYTE_0 (0xBF)
+
+#define TPI_END_TOP_BAR_LSB (0x12)
+#define TPI_END_TOP_BAR_MSB (0x13)
+
+#define TPI_START_BTM_BAR_LSB (0x14)
+#define TPI_START_BTM_BAR_MSB (0x15)
+
+#define TPI_END_LEFT_BAR_LSB (0x16)
+#define TPI_END_LEFT_BAR_MSB (0x17)
+
+#define TPI_END_RIGHT_BAR_LSB (0x18)
+#define TPI_END_RIGHT_BAR_MSB (0x19)
+
+/* Colorimetry*/
+
+#define SET_EX_COLORIMETRY 0x0C
+/*Set TPI_AVI_BYTE_2 to extended colorimetry and use*/
+
+
+/*===================================================== */
+
+#define TPI_SYSTEM_CONTROL_DATA_REG (0x1A)
+
+#define LINK_INTEGRITY_MODE_MASK (SI_BIT_6)
+#define LINK_INTEGRITY_STATIC (SI_ZERO)
+#define LINK_INTEGRITY_DYNAMIC (SI_BIT_6)
+
+#define TMDS_OUTPUT_CONTROL_MASK (SI_BIT_4)
+#define TMDS_OUTPUT_CONTROL_ACTIVE (SI_ZERO)
+#define TMDS_OUTPUT_CONTROL_POWER_DOWN (SI_BIT_4)
+
+#define AV_MUTE_MASK (SI_BIT_3)
+#define AV_MUTE_NORMAL (SI_ZERO)
+#define AV_MUTE_MUTED (SI_BIT_3)
+
+#define DDC_BUS_REQUEST_MASK (SI_BIT_2)
+#define DDC_BUS_REQUEST_NOT_USING (SI_ZERO)
+#define DDC_BUS_REQUEST_REQUESTED (SI_BIT_2)
+
+#define DDC_BUS_GRANT_MASK (SI_BIT_1)
+#define DDC_BUS_GRANT_NOT_AVAILABLE (SI_ZERO)
+#define DDC_BUS_GRANT_GRANTED (SI_BIT_1)
+
+#define OUTPUT_MODE_MASK (SI_BIT_0)
+#define OUTPUT_MODE_DVI (SI_ZERO)
+#define OUTPUT_MODE_HDMI (SI_BIT_0)
+
+
+/*TPI Identification Registers*/
+/*=============================*/
+
+#define TPI_DEVICE_ID (0x1B)
+#define TPI_DEVICE_REV_ID (0x1C)
+#define TPI_RESERVED2 (0x1D)
+
+/* ============================================== */
+
+#define TPI_DEVICE_POWER_STATE_CTRL_REG (0x1E)
+
+#define CTRL_PIN_CONTROL_MASK (SI_BIT_4)
+#define CTRL_PIN_TRISTATE (SI_ZERO)
+#define CTRL_PIN_DRIVEN_TX_BRIDGE (0x10)
+
+#define TX_POWER_STATE_MASK (SI_BIT_1 | SI_BIT_0)
+#define TX_POWER_STATE_D0 (SI_ZERO)
+#define TX_POWER_STATE_D1 (SI_BIT_0)
+#define TX_POWER_STATE_D2 (SI_BIT_1)
+#define TX_POWER_STATE_D3 (SI_BIT_1 | SI_BIT_0)
+
+/*Configuration of I2S Interface*/
+
+#define TPI_I2S_EN (0x1F)
+#define TPI_I2S_IN_CFG (0x20)
+
+/* Available only when TPI 0x26[7:6]=10 to select I2S input*/
+#define TPI_I2S_CHST_0 (0x21)
+#define TPI_I2S_CHST_1 (0x22)
+#define TPI_I2S_CHST_2 (0x23)
+#define TPI_I2S_CHST_3 (0x24)
+#define TPI_I2S_CHST_4 (0x25)
+
+/* Available only when 0x26[7:6]=01*/
+#define TPI_SPDIF_HEADER (0x24)
+#define TPI_AUDIO_HANDLING (0x25)
+
+
+/*Audio Configuration Regiaters*/
+#define TPI_AUDIO_INTERFACE_REG (0x26)
+
+
+#define AUDIO_MUTE_MASK (SI_BIT_4)
+#define AUDIO_MUTE_NORMAL (SI_ZERO)
+#define AUDIO_MUTE_MUTED (SI_BIT_4)
+
+#define TPI_AUDIO_SAMPLE_CTRL (0x27)
+
+#define TPI_SPEAKER_CFG (0xC7)
+#define TPI_CHANNEL_COUNT (0xC4)
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/*
+* HDCP Implementation
+*
+* HDCP link security logic is implemented in certain transmitters; unique
+* keys are embedded in each chip as part of the solution. The security
+* scheme is fully automatic and handled completely by the hardware.
+*/
+
+/* HDCP Query Data Register ============================================== */
+
+#define TPI_HDCP_QUERY_DATA_REG (0x29)
+
+#define EXTENDED_LINK_PROTECTION_MASK (SI_BIT_7)
+#define EXTENDED_LINK_PROTECTION_NONE (SI_ZERO)
+#define EXTENDED_LINK_PROTECTION_SECURE (SI_BIT_7)
+
+#define LOCAL_LINK_PROTECTION_MASK (SI_BIT_6)
+#define LOCAL_LINK_PROTECTION_NONE (SI_ZERO)
+#define LOCAL_LINK_PROTECTION_SECURE (SI_BIT_6)
+
+#define LINK_STATUS_MASK (SI_BIT_5 | SI_BIT_4)
+#define LINK_STATUS_NORMAL (SI_ZERO)
+#define LINK_STATUS_LINK_LOST (SI_BIT_4)
+#define LINK_STATUS_RENEGOTIATION_REQ (SI_BIT_5)
+#define LINK_STATUS_LINK_SUSPENDED (SI_BIT_5 | SI_BIT_4)
+
+#define HDCP_REPEATER_MASK (SI_BIT_3)
+#define HDCP_REPEATER_NO (SI_ZERO)
+#define HDCP_REPEATER_YES (SI_BIT_3)
+
+#define CONNECTOR_TYPE_MASK (SI_BIT_2 | SI_BIT_0)
+#define CONNECTOR_TYPE_DVI (SI_ZERO)
+#define CONNECTOR_TYPE_RSVD (SI_BIT_0)
+#define CONNECTOR_TYPE_HDMI (SI_BIT_2)
+#define CONNECTOR_TYPE_FUTURE (SI_BIT_2 | SI_BIT_0)
+
+#define PROTECTION_TYPE_MASK (SI_BIT_1)
+#define PROTECTION_TYPE_NONE (SI_ZERO)
+#define PROTECTION_TYPE_HDCP (SI_BIT_1)
+
+/*HDCP Control Data Register ============================================ */
+
+#define TPI_HDCP_CONTROL_DATA_REG (0x2A)
+
+#define PROTECTION_LEVEL_MASK (SI_BIT_0)
+#define PROTECTION_LEVEL_MIN (0x00)
+#define PROTECTION_LEVEL_MAX (0x01)
+
+/*HDCP BKSV Registers =================================================== */
+
+#define TPI_BKSV_1_REG (0x2B)
+#define TPI_BKSV_2_REG (0x2C)
+#define TPI_BKSV_3_REG (0x2D)
+#define TPI_BKSV_4_REG (0x2E)
+#define TPI_BKSV_5_REG (0x2F)
+
+/* HDCP Revision Data Register =========================================== */
+
+#define TPI_HDCP_REVISION_DATA_REG (0x30)
+
+#define HDCP_MAJOR_REVISION_MASK (SI_BIT_7 | SI_BIT_6 | SI_BIT_5 | SI_BIT_4)
+#define HDCP_MAJOR_REVISION_VALUE (0x10)
+
+#define HDCP_MINOR_REVISION_MASK (SI_BIT_3 | SI_BIT_2 | SI_BIT_1 | SI_BIT_0)
+#define HDCP_MINOR_REVISION_VALUE (0x02)
+
+/* HDCP KSV and V' Value Data Register =================================== */
+
+#define TPI_V_PRIME_SELECTOR_REG (0x31)
+
+/* V' Value Readback Registers =========================================== */
+
+#define TPI_V_PRIME_7_0_REG (0x32)
+#define TPI_V_PRIME_15_9_REG (0x33)
+#define TPI_V_PRIME_23_16_REG (0x34)
+#define TPI_V_PRIME_31_24_REG (0x35)
+
+/* HDCP AKSV Registers =================================================== */
+
+#define TPI_AKSV_1_REG (0x36)
+#define TPI_AKSV_2_REG (0x37)
+#define TPI_AKSV_3_REG (0x38)
+#define TPI_AKSV_4_REG (0x39)
+#define TPI_AKSV_5_REG (0x3A)
+
+/*
+* Interrupt Service
+*
+* TPI can be configured to generate an interrupt to the host to notify it of
+* various events. The host can either poll for activity or use an interrupt
+* handler routine. TPI generates on a single interrupt (INT) to the host.
+*/
+
+/* Interrupt Enable Register ============================================= */
+
+#define TPI_INTERRUPT_ENABLE_REG (0x3C)
+
+#define HDCP_AUTH_STATUS_CHANGE_EN_MASK (SI_BIT_7)
+#define HDCP_AUTH_STATUS_CHANGE_DISABLE (0x00)
+#define HDCP_AUTH_STATUS_CHANGE_ENABLE (0x80)
+
+#define HDCP_VPRIME_VALUE_READY_EN_MASK (SI_BIT_6)
+#define HDCP_VPRIME_VALUE_READY_DISABLE (0x00)
+#define HDCP_VPRIME_VALUE_READY_ENABLE (0x40)
+
+#define HDCP_SECURITY_CHANGE_EN_MASK (SI_BIT_5)
+#define HDCP_SECURITY_CHANGE_DISABLE (0x00)
+#define HDCP_SECURITY_CHANGE_ENABLE (0x20)
+
+#define AUDIO_ERROR_EVENT_EN_MASK (SI_BIT_4)
+#define AUDIO_ERROR_EVENT_DISABLE (0x00)
+#define AUDIO_ERROR_EVENT_ENABLE (0x10)
+
+#define CPI_EVENT_NO_RX_SENSE_MASK (SI_BIT_3)
+#define CPI_EVENT_NO_RX_SENSE_DISABLE (0x00)
+#define CPI_EVENT_NO_RX_SENSE_ENABLE (0x08)
+
+#define RECEIVER_SENSE_EVENT_EN_MASK (SI_BIT_1)
+#define RECEIVER_SENSE_EVENT_DISABLE (0x00)
+#define RECEIVER_SENSE_EVENT_ENABLE (0x02)
+
+#define HOT_PLUG_EVENT_EN_MASK (SI_BIT_0)
+#define HOT_PLUG_EVENT_DISABLE (0x00)
+#define HOT_PLUG_EVENT_ENABLE (0x01)
+
+/* Interrupt Status Register ============================================= */
+
+#define TPI_INTERRUPT_STATUS_REG (0x3D)
+
+#define HDCP_AUTH_STATUS_CHANGE_EVENT_MASK (SI_BIT_7)
+#define HDCP_AUTH_STATUS_CHANGE_EVENT_NO (0x00)
+#define HDCP_AUTH_STATUS_CHANGE_EVENT_YES (0x80)
+
+#define HDCP_VPRIME_VALUE_READY_EVENT_MASK (SI_BIT_6)
+#define HDCP_VPRIME_VALUE_READY_EVENT_NO (0x00)
+#define HDCP_VPRIME_VALUE_READY_EVENT_YES (0x40)
+
+#define HDCP_SECURITY_CHANGE_EVENT_MASK (SI_BIT_5)
+#define HDCP_SECURITY_CHANGE_EVENT_NO (0x00)
+#define HDCP_SECURITY_CHANGE_EVENT_YES (0x20)
+
+#define AUDIO_ERROR_EVENT_MASK (SI_BIT_4)
+#define AUDIO_ERROR_EVENT_NO (0x00)
+#define AUDIO_ERROR_EVENT_YES (0x10)
+
+#define CPI_EVENT_MASK (SI_BIT_3)
+#define CPI_EVENT_NO (0x00)
+#define CPI_EVENT_YES (0x08)
+#define RX_SENSE_MASK (SI_BIT_3)
+#define RX_SENSE_NOT_ATTACHED (0x00)
+#define RX_SENSE_ATTACHED (0x08)
+
+#define HOT_PLUG_PIN_STATE_MASK (SI_BIT_2)
+#define HOT_PLUG_PIN_STATE_LOW (0x00)
+#define HOT_PLUG_PIN_STATE_HIGH (0x04)
+
+#define RECEIVER_SENSE_EVENT_MASK (SI_BIT_1)
+#define RECEIVER_SENSE_EVENT_NO (0x00)
+#define RECEIVER_SENSE_EVENT_YES (0x02)
+
+#define HOT_PLUG_EVENT_MASK (SI_BIT_0)
+#define HOT_PLUG_EVENT_NO (0x00)
+#define HOT_PLUG_EVENT_YES (0x01)
+
+
+/* Sync Register Configuration and Sync Monitoring Registers*/
+/*==========================================================*/
+
+#define TPI_SYNC_GEN_CTRL (0x60)
+#define TPI_SYNC_POLAR_DETECT (0x61)
+
+/*Explicit Sync DE Generator Registers (TPI 0x60[7]=0)*/
+/*=====================================================*/
+
+#define TPI_DE_DLY (0x62)
+#define TPI_DE_CTRL (0x63)
+#define TPI_DE_TOP (0x64)
+
+#define TPI_RESERVED4 (0x65)
+
+#define TPI_DE_CNT_7_0 (0x66)
+#define TPI_DE_CNT_11_8 (0x67)
+
+#define TPI_DE_LIN_7_0 (0x68)
+#define TPI_DE_LIN_10_8 (0x69)
+
+#define TPI_DE_H_RES_7_0 (0x6A)
+#define TPI_DE_H_RES_10_8 (0x6B)
+
+#define TPI_DE_V_RES_7_0 (0x6C)
+#define TPI_DE_V_RES_10_8 (0x6D)
+
+/* Embedded Sync Register Set (TPI 0x60[7]=1)*/
+/*===========================================*/
+
+#define TPI_HBIT_TO_HSYNC_7_0 (0x62)
+#define TPI_HBIT_TO_HSYNC_9_8 (0x63)
+#define TPI_FIELD_2_OFFSET_7_0 (0x64)
+#define TPI_FIELD_2_OFFSET_11_8 (0x65)
+#define TPI_HWIDTH_7_0 (0x66)
+#define TPI_HWIDTH_8_9 (0x67)
+#define TPI_VBIT_TO_VSYNC (0x68)
+#define TPI_VWIDTH (0x69)
+
+/*TPI Enable Register*/
+
+
+#define TPI_ENABLE (0xC7)
+
+/* Misc InfoFrames*/
+#define MISC_INFO_FRAMES_CTRL (0xBF)
+#define MISC_INFO_FRAMES_TYPE (0xC0)
+#define MISC_INFO_FRAMES_VER (0xC1)
+#define MISC_INFO_FRAMES_LEN (0xC2)
+#define MISC_INFO_FRAMES_CHKSUM (0xC3)