public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] Add initial support for slimport anx78xx
@ 2015-09-06 21:13 Enric Balletbo i Serra
  2015-09-06 21:14 ` [PATCH 1/3] of: Add vendor prefix for Analogix Semiconductor, Inc Enric Balletbo i Serra
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Enric Balletbo i Serra @ 2015-09-06 21:13 UTC (permalink / raw)
  To: devel, gregkh; +Cc: linux-kernel, sjoerd.simons, javier, span, nathan.chung

Hi all,

The following series add initial support for the Slimport ANX7814 transmitter, a
ultra-low power Full-HD (1080p60) transmitter designed for portable device.

The driver was originally created and based from the work of Junhua Xia from
Analogix. This driver is a refactor of the original driver and fixes different
coding style lines, and different errors/warnings reported by checkpatch. Also
there were thing that I notive that we need to change like:

 - Convert the numbered GPIO API to the new descriptor based GPIO API.
 - Review the DT binding
 - Add missing MODULE_DEVICE_TABLE(of, ...);
 - Fix Makefiles and Kconfig to build conditionally.
 - Use SIMPLE_DEV_PM_OPS() instead of the deprecated i2c .suspend and
  .resume callbacks.
 - Move to use managed device resources.
 - Remove dead/unused code.
 - And others ...

This is the first version so probably will have mistakes so feel free to ping to
incorporate other changes that I need to do in next series.

Best regards,

Enric Balletbo i Serra (3):
  of: Add vendor prefix for Analogix Semiconductor, Inc.
  devicetree: Add new ANX7814 SlimPort transmitter binding.
  staging: slimport: Add anx7814 driver support by analogix.

 .../devicetree/bindings/vendor-prefixes.txt        |    1 +
 .../devicetree/bindings/video/bridge/anx7814.txt   |   22 +
 drivers/staging/Kconfig                            |    2 +
 drivers/staging/Makefile                           |    1 +
 drivers/staging/slimport/Kconfig                   |    7 +
 drivers/staging/slimport/Makefile                  |    4 +
 drivers/staging/slimport/slimport.c                |  301 ++
 drivers/staging/slimport/slimport.h                |   49 +
 drivers/staging/slimport/slimport_tx_drv.c         | 3293 ++++++++++++++++++++
 drivers/staging/slimport/slimport_tx_drv.h         |  254 ++
 drivers/staging/slimport/slimport_tx_reg.h         |  786 +++++
 11 files changed, 4720 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/video/bridge/anx7814.txt
 create mode 100644 drivers/staging/slimport/Kconfig
 create mode 100644 drivers/staging/slimport/Makefile
 create mode 100644 drivers/staging/slimport/slimport.c
 create mode 100644 drivers/staging/slimport/slimport.h
 create mode 100644 drivers/staging/slimport/slimport_tx_drv.c
 create mode 100644 drivers/staging/slimport/slimport_tx_drv.h
 create mode 100644 drivers/staging/slimport/slimport_tx_reg.h

-- 
2.1.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/3] of: Add vendor prefix for Analogix Semiconductor, Inc.
  2015-09-06 21:13 [PATCH 0/3] Add initial support for slimport anx78xx Enric Balletbo i Serra
@ 2015-09-06 21:14 ` Enric Balletbo i Serra
  2015-09-06 21:14 ` [PATCH 2/3] devicetree: Add new ANX7814 SlimPort transmitter binding Enric Balletbo i Serra
  2015-09-06 21:14 ` [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix Enric Balletbo i Serra
  2 siblings, 0 replies; 9+ messages in thread
From: Enric Balletbo i Serra @ 2015-09-06 21:14 UTC (permalink / raw)
  To: devel, gregkh; +Cc: linux-kernel, sjoerd.simons, javier, span, nathan.chung

Analogix Semiconductor develops analog and mixed-signal devices for digital
media and communications interconnect applications.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ac5f0c3..e914a02 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -22,6 +22,7 @@ ampire	Ampire Co., Ltd.
 ams	AMS AG
 amstaos	AMS-Taos Inc.
 apm	Applied Micro Circuits Corporation (APM)
+analogix	Analogix Semiconductor, Inc.
 aptina	Aptina Imaging
 arasan	Arasan Chip Systems
 arm	ARM Ltd.
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/3] devicetree: Add new ANX7814 SlimPort transmitter binding.
  2015-09-06 21:13 [PATCH 0/3] Add initial support for slimport anx78xx Enric Balletbo i Serra
  2015-09-06 21:14 ` [PATCH 1/3] of: Add vendor prefix for Analogix Semiconductor, Inc Enric Balletbo i Serra
@ 2015-09-06 21:14 ` Enric Balletbo i Serra
  2015-09-06 21:14 ` [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix Enric Balletbo i Serra
  2 siblings, 0 replies; 9+ messages in thread
From: Enric Balletbo i Serra @ 2015-09-06 21:14 UTC (permalink / raw)
  To: devel, gregkh; +Cc: linux-kernel, sjoerd.simons, javier, span, nathan.chung

The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter
designed for portable devices.

You can add support to your board with current binding.

Example:

	anx7814: anx7814@38 {
		compatible = "analogix,anx7814";
		reg = <0x38>;
		pd-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
		reset-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
	};

Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
 .../devicetree/bindings/video/bridge/anx7814.txt   | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/video/bridge/anx7814.txt

diff --git a/Documentation/devicetree/bindings/video/bridge/anx7814.txt b/Documentation/devicetree/bindings/video/bridge/anx7814.txt
new file mode 100644
index 0000000..a8cc746
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/bridge/anx7814.txt
@@ -0,0 +1,22 @@
+Analogix ANX7814 SlimPort (Full-HD Transmitter)
+-----------------------------------------------
+
+The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter
+designed for portable devices.
+
+Required properties:
+
+ - compatible	: "analogix,anx7814"
+ - reg		: I2C address of the device
+ - pd-gpios	: Which GPIO to use for power down
+ - reset-gpios	: Which GPIO to use for reset
+
+Example:
+
+	anx7814: anx7814@38 {
+		compatible = "analogix,anx7814";
+		reg = <0x38>;
+		pd-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
+	};
+
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix.
  2015-09-06 21:13 [PATCH 0/3] Add initial support for slimport anx78xx Enric Balletbo i Serra
  2015-09-06 21:14 ` [PATCH 1/3] of: Add vendor prefix for Analogix Semiconductor, Inc Enric Balletbo i Serra
  2015-09-06 21:14 ` [PATCH 2/3] devicetree: Add new ANX7814 SlimPort transmitter binding Enric Balletbo i Serra
@ 2015-09-06 21:14 ` Enric Balletbo i Serra
  2015-09-06 23:27   ` Greg KH
  2 siblings, 1 reply; 9+ messages in thread
From: Enric Balletbo i Serra @ 2015-09-06 21:14 UTC (permalink / raw)
  To: devel, gregkh; +Cc: linux-kernel, sjoerd.simons, javier, span, nathan.chung

The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter
designed for portable devices.

This driver adds initial support and supports HDMI to DP pass-through mode.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
 drivers/staging/Kconfig                    |    2 +
 drivers/staging/Makefile                   |    1 +
 drivers/staging/slimport/Kconfig           |    7 +
 drivers/staging/slimport/Makefile          |    4 +
 drivers/staging/slimport/slimport.c        |  301 +++
 drivers/staging/slimport/slimport.h        |   49 +
 drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
 drivers/staging/slimport/slimport_tx_drv.h |  254 +++
 drivers/staging/slimport/slimport_tx_reg.h |  786 +++++++
 9 files changed, 4697 insertions(+)
 create mode 100644 drivers/staging/slimport/Kconfig
 create mode 100644 drivers/staging/slimport/Makefile
 create mode 100644 drivers/staging/slimport/slimport.c
 create mode 100644 drivers/staging/slimport/slimport.h
 create mode 100644 drivers/staging/slimport/slimport_tx_drv.c
 create mode 100644 drivers/staging/slimport/slimport_tx_drv.h
 create mode 100644 drivers/staging/slimport/slimport_tx_reg.h

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index e29293c..24ccd7c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -110,4 +110,6 @@ source "drivers/staging/wilc1000/Kconfig"
 
 source "drivers/staging/most/Kconfig"
 
+source "drivers/staging/slimport/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 50824dd..942e886 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -47,3 +47,4 @@ obj-$(CONFIG_FB_TFT)		+= fbtft/
 obj-$(CONFIG_FSL_MC_BUS)	+= fsl-mc/
 obj-$(CONFIG_WILC1000)		+= wilc1000/
 obj-$(CONFIG_MOST)		+= most/
+obj-$(CONFIG_SLIMPORT_ANX78XX)	+= slimport/
diff --git a/drivers/staging/slimport/Kconfig b/drivers/staging/slimport/Kconfig
new file mode 100644
index 0000000..f5233ef
--- /dev/null
+++ b/drivers/staging/slimport/Kconfig
@@ -0,0 +1,7 @@
+config SLIMPORT_ANX78XX
+	tristate "Analogix Slimport transmitter ANX78XX support"
+	help
+        	Slimport Transmitter is a HD video transmitter chip
+		over micro-USB connector for smartphone device.
+
+
diff --git a/drivers/staging/slimport/Makefile b/drivers/staging/slimport/Makefile
new file mode 100644
index 0000000..9bb6ce2
--- /dev/null
+++ b/drivers/staging/slimport/Makefile
@@ -0,0 +1,4 @@
+obj-${CONFIG_SLIMPORT_ANX78XX} :=  anx78xx.o
+
+anx78xx-y := slimport.o
+anx78xx-y += slimport_tx_drv.o
diff --git a/drivers/staging/slimport/slimport.c b/drivers/staging/slimport/slimport.c
new file mode 100644
index 0000000..95c5114
--- /dev/null
+++ b/drivers/staging/slimport/slimport.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/async.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+
+#include "slimport.h"
+#include "slimport_tx_drv.h"
+
+/* HDCP switch for external block */
+/* external_block_en = 1: enable, 0: disable */
+int external_block_en = 1;
+
+struct i2c_client *anx7814_client;
+
+int sp_read_reg_byte(uint8_t slave_addr, uint8_t offset)
+{
+	int ret = 0;
+	struct device *dev = &anx7814_client->dev;
+
+	anx7814_client->addr = (slave_addr >> 1);
+	ret = i2c_smbus_read_byte_data(anx7814_client, offset);
+	if (ret < 0) {
+		dev_err(dev, "%s: failed to read i2c addr=%x\n", LOG_TAG,
+		      slave_addr);
+		return ret;
+	}
+	return 0;
+}
+
+int sp_read_reg(uint8_t slave_addr, uint8_t offset, uint8_t *buf)
+{
+	int ret = 0;
+	struct device *dev = &anx7814_client->dev;
+
+	anx7814_client->addr = (slave_addr >> 1);
+	ret = i2c_smbus_read_byte_data(anx7814_client, offset);
+	if (ret < 0) {
+		dev_err(dev, "%s: failed to read i2c addr=%x\n", LOG_TAG,
+		       slave_addr);
+		return ret;
+	}
+	*buf = (uint8_t) ret;
+
+	return 0;
+}
+
+int sp_write_reg(uint8_t slave_addr, uint8_t offset, uint8_t value)
+{
+	int ret = 0;
+	struct device *dev = &anx7814_client->dev;
+
+	anx7814_client->addr = (slave_addr >> 1);
+	ret = i2c_smbus_write_byte_data(anx7814_client, offset, value);
+	if (ret < 0) {
+		dev_err(dev, "%s: failed to write i2c addr=%x\n", LOG_TAG,
+		       slave_addr);
+	}
+	return ret;
+}
+
+void sp_tx_hardware_poweron(struct anx7814_data *data)
+{
+	struct device *dev = &data->client->dev;
+	struct anx7814_platform_data *pdata = data->pdata;
+
+	gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
+	usleep_range(1000, 2000);
+
+	gpiod_set_value_cansleep(pdata->gpiod_pd, 0);
+	usleep_range(1000, 2000);
+
+	gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
+
+	dev_info(dev, "%s: anx7814 power on\n", LOG_TAG);
+}
+
+void sp_tx_hardware_powerdown(struct anx7814_data *data)
+{
+	struct device *dev = &data->client->dev;
+	struct anx7814_platform_data *pdata = data->pdata;
+
+	gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
+	usleep_range(1000, 2000);
+
+	gpiod_set_value_cansleep(pdata->gpiod_pd, 1);
+	usleep_range(1000, 2000);
+
+	dev_info(dev, "%s: anx7814 power down\n", LOG_TAG);
+}
+
+static int anx7814_init_gpio(struct anx7814_data *data)
+{
+	struct device *dev = &data->client->dev;
+	struct anx7814_platform_data *pdata = data->pdata;
+	int ret;
+
+	/* gpio for chip power down */
+	pdata->gpiod_pd = devm_gpiod_get(dev, "pd", GPIOD_OUT_HIGH);
+	if (IS_ERR(pdata->gpiod_pd)) {
+		dev_err(dev, "unable to claim pd gpio\n");
+		ret = PTR_ERR(pdata->gpiod_pd);
+		return ret;
+	}
+
+	/* gpio for chip reset */
+	pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(pdata->gpiod_reset)) {
+		dev_err(dev, "unable to claim reset gpio\n");
+		ret = PTR_ERR(pdata->gpiod_reset);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int anx7814_system_init(struct anx7814_data *data)
+{
+	struct device *dev = &data->client->dev;
+
+	int ret = 0;
+
+	ret = slimport_chip_detect(data);
+	if (ret == 0) {
+		sp_tx_hardware_powerdown(data);
+		dev_err(dev, "failed to detect anx7814\n");
+		return -ENODEV;
+	}
+
+	sp_tx_variable_init();
+	return 0;
+}
+
+static void anx7814_work_func(struct work_struct *work)
+{
+	struct anx7814_data *data = container_of(work, struct anx7814_data,
+					       work.work);
+	int workqueu_timer = 0;
+
+	if (sp_tx_cur_states() >= STATE_PLAY_BACK)
+		workqueu_timer = 500;
+	else
+		workqueu_timer = 100;
+	mutex_lock(&data->lock);
+	slimport_main_process(data);
+	mutex_unlock(&data->lock);
+	queue_delayed_work(data->workqueue, &data->work,
+			   msecs_to_jiffies(workqueu_timer));
+}
+
+static int anx7814_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct anx7814_data *data;
+	struct anx7814_platform_data *pdata;
+	int ret = 0;
+
+	if (!i2c_check_functionality(client->adapter,
+		I2C_FUNC_SMBUS_I2C_BLOCK)) {
+		dev_err(&client->dev, "i2c bus does not support the device\n");
+		return -ENODEV;
+	}
+
+	data = devm_kzalloc(&client->dev,
+			sizeof(struct anx7814_data),
+			GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	pdata = devm_kzalloc(&client->dev,
+			sizeof(struct anx7814_platform_data),
+			GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	data->pdata = pdata;
+
+	data->client = client;
+	anx7814_client = client;
+
+	mutex_init(&data->lock);
+
+	ret = anx7814_init_gpio(data);
+	if (ret) {
+		dev_err(&client->dev, "failed to initialize gpios\n");
+		return ret;
+	}
+
+	INIT_DELAYED_WORK(&data->work, anx7814_work_func);
+
+	data->workqueue = create_singlethread_workqueue("anx7814_work");
+	if (data->workqueue == NULL) {
+		dev_err(&client->dev, "failed to create work queue\n");
+		return -ENOMEM;
+	}
+
+	ret = anx7814_system_init(data);
+	if (ret) {
+		dev_err(&client->dev, "failed to initialize anx7814\n");
+		goto cleanup;
+	}
+
+	i2c_set_clientdata(client, data);
+
+	/* enable driver */
+	queue_delayed_work(data->workqueue, &data->work, 0);
+
+	return 0;
+
+cleanup:
+	destroy_workqueue(data->workqueue);
+	return ret;
+}
+
+static int anx7814_i2c_remove(struct i2c_client *client)
+{
+	struct anx7814_data *data = i2c_get_clientdata(client);
+
+	destroy_workqueue(data->workqueue);
+
+	return 0;
+}
+
+static int anx7814_i2c_suspend(struct device *dev)
+{
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+	struct anx7814_data *data = i2c_get_clientdata(client);
+
+	dev_info(&client->dev, "suspend\n");
+	cancel_delayed_work_sync(&data->work);
+	flush_workqueue(data->workqueue);
+	sp_tx_hardware_powerdown(data);
+	sp_tx_clean_state_machine();
+
+	return 0;
+}
+
+static int anx7814_i2c_resume(struct device *dev)
+{
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+	struct anx7814_data *anx7814 = i2c_get_clientdata(client);
+
+	dev_info(&client->dev, "resume\n");
+	queue_delayed_work(anx7814->workqueue, &anx7814->work, 0);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(anx7814_i2c_pm_ops,
+			anx7814_i2c_suspend, anx7814_i2c_resume);
+
+static const struct i2c_device_id anx7814_id[] = {
+	{"anx7814", 0},
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(i2c, anx7814_id);
+
+static const struct of_device_id anx_match_table[] = {
+	{.compatible = "analogix,anx7814",},
+	{ /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, anx_match_table);
+
+static struct i2c_driver anx7814_driver = {
+	.driver = {
+		   .name = "anx7814",
+		   .pm = &anx7814_i2c_pm_ops,
+		   .of_match_table = of_match_ptr(anx_match_table),
+		   },
+	.probe = anx7814_i2c_probe,
+	.remove = anx7814_i2c_remove,
+	.id_table = anx7814_id,
+};
+
+module_i2c_driver(anx7814_driver);
+
+MODULE_DESCRIPTION("Slimport  transmitter ANX7814 driver");
+MODULE_AUTHOR("Junhua Xia <jxia@analogixsemi.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("1.1");
diff --git a/drivers/staging/slimport/slimport.h b/drivers/staging/slimport/slimport.h
new file mode 100644
index 0000000..614d746
--- /dev/null
+++ b/drivers/staging/slimport/slimport.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _SLIMPORT_H
+#define _SLIMPORT_H
+
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/gpio/consumer.h>
+
+#define AUX_ERR  1
+#define AUX_OK   0
+
+#define LOG_TAG "SlimPort ANX78XX"
+
+struct anx7814_platform_data {
+	struct gpio_desc *gpiod_pd;
+	struct gpio_desc *gpiod_reset;
+	spinlock_t lock;
+};
+
+struct anx7814_data {
+	struct i2c_client *client;
+	struct anx7814_platform_data *pdata;
+	struct delayed_work work;
+	struct workqueue_struct *workqueue;
+	struct mutex lock;
+};
+
+int sp_read_reg(uint8_t slave_addr, uint8_t offset, uint8_t *buf);
+int sp_write_reg(uint8_t slave_addr, uint8_t offset, uint8_t value);
+
+void sp_tx_hardware_poweron(struct anx7814_data *data);
+void sp_tx_hardware_powerdown(struct anx7814_data *data);
+
+#endif
diff --git a/drivers/staging/slimport/slimport_tx_drv.c b/drivers/staging/slimport/slimport_tx_drv.c
new file mode 100644
index 0000000..6fad502
--- /dev/null
+++ b/drivers/staging/slimport/slimport_tx_drv.c
@@ -0,0 +1,3293 @@
+/*
+ * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#include "slimport.h"
+#include "slimport_tx_drv.h"
+
+#define XTAL_CLK_M10	pxtal_data[XTAL_27M].xtal_clk_m10
+#define XTAL_CLK	pxtal_data[XTAL_27M].xtal_clk
+
+static u8 sp_tx_test_bw;
+static bool sp_tx_test_lt;
+static bool sp_tx_test_edid;
+
+static u8 g_changed_bandwidth;
+static u8 g_hdmi_dvi_status;
+
+static u8 g_need_clean_status;
+
+static u8 ds_vid_stb_cntr;
+static u8 hdcp_fail_count;
+
+u8 g_edid_break;
+u8 g_edid_checksum;
+u8 edid_blocks[256];
+static u8 g_read_edid_flag;
+
+static struct packet_avi sp_tx_packet_avi;
+static struct packet_spd sp_tx_packet_spd;
+static struct packet_mpeg sp_tx_packet_mpeg;
+static struct audio_info_frame sp_tx_audioinfoframe;
+
+enum sp_tx_state sp_tx_system_state;
+
+enum audio_output_status sp_tx_ao_state;
+enum video_output_status sp_tx_vo_state;
+enum sink_connection_status sp_tx_sc_state;
+enum sp_tx_lt_status sp_tx_lt_state;
+enum sp_tx_state sp_tx_system_state_bak;
+enum hdcp_status hcdp_state;
+
+const uint chipid_list[] = {
+	0x7818,
+	0x7816,
+	0x7814,
+	0x7812,
+	0x7810,
+	0x7806,
+	0x7802
+};
+
+struct common_int common_int_status;
+struct hdmi_rx_int hdmi_rx_int_status;
+
+static u8 down_sample_en;
+
+static unsigned char sp_i2c_read_byte(unsigned char dev, unsigned char offset);
+static void hdmi_rx_new_vsi_int(void);
+
+#define reg_bit_ctl(addr, offset, data, enable) \
+	do { \
+		u8 c; \
+		sp_read_reg(addr, offset, &c); \
+		if (enable) { \
+			if ((c & data) != data) { \
+				c |= data; \
+				sp_write_reg(addr, offset, c); \
+			} \
+		} else { \
+			if ((c & data) == data) { \
+				c &= ~data; \
+				sp_write_reg(addr, offset, c); \
+			} \
+		} \
+	} while (0)
+
+#define sp_tx_video_mute(enable) \
+	reg_bit_ctl(TX_P2, VID_CTRL1, VIDEO_MUTE, enable)
+
+#define hdmi_rx_mute_audio(enable) \
+	reg_bit_ctl(RX_P0, RX_MUTE_CTRL, AUD_MUTE, enable)
+
+#define hdmi_rx_mute_video(enable) \
+	reg_bit_ctl(RX_P0, RX_MUTE_CTRL, VID_MUTE, enable)
+
+#define sp_tx_addronly_set(enable) \
+	reg_bit_ctl(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT, enable)
+
+#define sp_tx_set_link_bw(bw) \
+	sp_write_reg(TX_P0, SP_TX_LINK_BW_SET_REG, bw)
+
+#define sp_tx_get_link_bw() \
+	sp_i2c_read_byte(TX_P0, SP_TX_LINK_BW_SET_REG)
+
+#define sp_tx_get_pll_lock_status() \
+	((sp_i2c_read_byte(TX_P0, TX_DEBUG1) & DEBUG_PLL_LOCK) != 0 ? 1 : 0)
+
+#define gen_m_clk_with_downspeading() \
+	sp_write_reg_or(TX_P0, SP_TX_M_CALCU_CTRL, M_GEN_CLK_SEL)
+
+#define gen_m_clk_without_downspeading \
+	sp_write_reg_and(TX_P0, SP_TX_M_CALCU_CTRL, (~M_GEN_CLK_SEL))
+
+#define hdmi_rx_set_hpd(enable) do { \
+	if ((bool)enable) \
+		sp_write_reg_or(TX_P2, SP_TX_VID_CTRL3_REG, HPD_OUT); \
+	else \
+		sp_write_reg_and(TX_P2, SP_TX_VID_CTRL3_REG, ~HPD_OUT); \
+	} while (0)
+
+#define hdmi_rx_set_termination(enable) do { \
+	if ((bool)enable) \
+		sp_write_reg_and(RX_P0, HDMI_RX_TMDS_CTRL_REG7, ~TERM_PD); \
+	else \
+		sp_write_reg_or(RX_P0, HDMI_RX_TMDS_CTRL_REG7, TERM_PD); \
+	} while (0)
+
+#define sp_tx_clean_hdcp_status() do { \
+	sp_write_reg(TX_P0, TX_HDCP_CTRL0, 0x03); \
+	sp_write_reg_or(TX_P0, TX_HDCP_CTRL0, RE_AUTH); \
+	usleep_range(2000, 4000); \
+	pr_info("%s %s : sp_tx_clean_hdcp_status\n", LOG_TAG, __func__); \
+	} while (0)
+
+#define reg_hardware_reset() do { \
+	sp_write_reg_or(TX_P2, SP_TX_RST_CTRL_REG, HW_RST); \
+	sp_tx_clean_state_machine(); \
+	sp_tx_set_sys_state(STATE_SP_INITIALIZED); \
+	msleep(500); \
+	} while (0)
+
+#define write_dpcd_addr(addrh, addrm, addrl) \
+	do { \
+		u8 temp; \
+		if (sp_i2c_read_byte(TX_P0, AUX_ADDR_7_0) != (u8)addrl) \
+			sp_write_reg(TX_P0, AUX_ADDR_7_0, (u8)addrl); \
+			if (sp_i2c_read_byte(TX_P0, AUX_ADDR_15_8) \
+						!= (u8)addrm) \
+				sp_write_reg(TX_P0, \
+					AUX_ADDR_15_8, (u8)addrm); \
+		sp_read_reg(TX_P0, AUX_ADDR_19_16, &temp); \
+		if ((u8)(temp & 0x0F)  != ((u8)addrh & 0x0F)) \
+			sp_write_reg(TX_P0, AUX_ADDR_19_16, \
+				(temp  & 0xF0) | ((u8)addrh)); \
+	} while (0)
+
+#define sp_tx_set_sys_state(ss) \
+	do { \
+		pr_info("%s %s : set: clean_status: %x,\n ", \
+				LOG_TAG, __func__, (uint)g_need_clean_status); \
+		if ((sp_tx_system_state >= STATE_LINK_TRAINING) \
+					&& (ss < STATE_LINK_TRAINING)) \
+			sp_write_reg_or(TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD); \
+		sp_tx_system_state_bak = sp_tx_system_state; \
+		sp_tx_system_state = (u8)ss; \
+		g_need_clean_status = 1; \
+		print_sys_state(sp_tx_system_state); \
+	} while (0)
+
+#define goto_next_system_state() \
+	do { \
+		pr_info("%s %s : next: clean_status: %x,\n ", \
+				LOG_TAG, __func__, (uint)g_need_clean_status); \
+		sp_tx_system_state_bak = sp_tx_system_state; \
+		sp_tx_system_state++;\
+		print_sys_state(sp_tx_system_state); \
+	} while (0)
+
+#define redo_cur_system_state() \
+	do { \
+		pr_info("%s %s : redo: clean_status: %x,\n ", \
+				LOG_TAG, __func__, (uint)g_need_clean_status); \
+		g_need_clean_status = 1; \
+		sp_tx_system_state_bak = sp_tx_system_state; \
+		print_sys_state(sp_tx_system_state); \
+	} while (0)
+
+#define system_state_change_with_case(status) \
+	do { \
+		if (sp_tx_system_state >= status) { \
+			pr_info("%s %s : change_case: clean_status: %xm,\n ", \
+				LOG_TAG, __func__, (uint)g_need_clean_status); \
+			if ((sp_tx_system_state >= STATE_LINK_TRAINING) \
+					&& (status < STATE_LINK_TRAINING)) \
+				sp_write_reg_or(TX_P0, \
+						SP_TX_ANALOG_PD_REG, CH0_PD); \
+			g_need_clean_status = 1; \
+			sp_tx_system_state_bak = sp_tx_system_state; \
+			sp_tx_system_state = (u8)status; \
+			print_sys_state(sp_tx_system_state); \
+		} \
+	} while (0)
+
+#define sp_write_reg_or(address, offset, mask) \
+	sp_write_reg(address, offset, \
+		((unsigned char)sp_i2c_read_byte(address, offset) | (mask)))
+
+#define sp_write_reg_and(address, offset, mask) \
+	sp_write_reg(address, offset, \
+		((unsigned char)sp_i2c_read_byte(address, offset) & (mask)))
+
+#define sp_write_reg_and_or(address, offset, and_mask, or_mask) \
+	sp_write_reg(address, offset, \
+		(((unsigned char)sp_i2c_read_byte(address, offset)) \
+		& and_mask) | (or_mask))
+
+#define sp_write_reg_or_and(address, offset, or_mask, and_mask) \
+	sp_write_reg(address, offset, \
+		(((unsigned char)sp_i2c_read_byte(address, offset)) \
+		| or_mask) & (and_mask))
+
+static inline void sp_tx_link_phy_initialization(void)
+{
+	sp_write_reg(TX_P2, SP_TX_ANALOG_CTRL0, 0x02);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG0, 0x01);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG10, 0x00);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG1, 0x03);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG11, 0x00);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG2, 0x07);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG12, 0x00);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG3, 0x7f);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG13, 0x00);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG4, 0x71);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG14, 0x0c);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG5, 0x6b);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG15, 0x42);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG6, 0x7f);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG16, 0x1e);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG7, 0x73);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG17, 0x3e);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG8, 0x7f);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG18, 0x72);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG9, 0x7F);
+	sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG19, 0x7e);
+}
+
+static unsigned char sp_i2c_read_byte(unsigned char dev, unsigned char offset)
+{
+	unsigned char temp;
+
+	sp_read_reg(dev, offset, &temp);
+	return temp;
+}
+
+static void hardware_power_ctl(struct anx7814_data *data, u8 enable)
+{
+	if (enable == 0)
+		sp_tx_hardware_powerdown(data);
+	else
+		sp_tx_hardware_poweron(data);
+}
+
+void wait_aux_op_finish(u8 *err_flag)
+{
+	u8 cnt;
+	u8 c;
+
+	*err_flag = 0;
+	cnt = 150;
+	while (sp_i2c_read_byte(TX_P0, AUX_CTRL2) & AUX_OP_EN) {
+		usleep_range(2000, 4000);
+		if ((cnt--) == 0) {
+			pr_info("%s %s :aux operate failed!\n",
+					LOG_TAG, __func__);
+			*err_flag = 1;
+			break;
+		}
+	}
+
+	sp_read_reg(TX_P0, SP_TX_AUX_STATUS, &c);
+	if (c & 0x0F) {
+		pr_info("%s %s : wait aux operation status %.2x\n",
+				LOG_TAG, __func__, (uint)c);
+		*err_flag = 1;
+	}
+}
+
+void print_sys_state(u8 ss)
+{
+	switch (ss) {
+	case STATE_WAITTING_CABLE_PLUG:
+		pr_info("%s %s : -STATE_WAITTING_CABLE_PLUG-\n",
+				LOG_TAG, __func__);
+		break;
+	case STATE_SP_INITIALIZED:
+		pr_info("%s %s : -STATE_SP_INITIALIZED-\n", LOG_TAG, __func__);
+		break;
+	case STATE_SINK_CONNECTION:
+		pr_info("%s %s : -STATE_SINK_CONNECTION-\n", LOG_TAG, __func__);
+		break;
+	case STATE_PARSE_EDID:
+		pr_info("%s %s : -STATE_PARSE_EDID-\n", LOG_TAG, __func__);
+		break;
+	case STATE_LINK_TRAINING:
+		pr_info("%s %s : -STATE_LINK_TRAINING-\n", LOG_TAG, __func__);
+		break;
+	case STATE_VIDEO_OUTPUT:
+		pr_info("%s %s : -STATE_VIDEO_OUTPUT-\n", LOG_TAG, __func__);
+		break;
+	case STATE_HDCP_AUTH:
+		pr_info("%s %s : -STATE_HDCP_AUTH-\n", LOG_TAG, __func__);
+		break;
+	case STATE_AUDIO_OUTPUT:
+		pr_info("%s %s : -STATE_AUDIO_OUTPUT-\n", LOG_TAG, __func__);
+		break;
+	case STATE_PLAY_BACK:
+		pr_info("%s %s : -STATE_PLAY_BACK-\n", LOG_TAG, __func__);
+		break;
+	default:
+		pr_err("%s %s : system state is error1\n", LOG_TAG, __func__);
+		break;
+	}
+}
+
+void sp_tx_rst_aux(void)
+{
+	sp_write_reg_or(TX_P2, RST_CTRL2, AUX_RST);
+	sp_write_reg_and(TX_P2, RST_CTRL2, ~AUX_RST);
+}
+
+u8 sp_tx_aux_dpcdread_bytes(u8 addrh, u8 addrm,
+		u8 addrl, u8 ccount, u8 *pbuf)
+{
+	u8 c, c1, i;
+	u8 bok;
+
+	sp_write_reg(TX_P0, BUF_DATA_COUNT, 0x80);
+	c = ((ccount - 1) << 4) | 0x09;
+	sp_write_reg(TX_P0, AUX_CTRL, c);
+	write_dpcd_addr(addrh, addrm, addrl);
+	sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN);
+	usleep_range(2000, 4000);
+
+	wait_aux_op_finish(&bok);
+	if (bok == AUX_ERR) {
+		pr_err("%s %s : aux read failed\n", LOG_TAG, __func__);
+		sp_read_reg(TX_P2, SP_TX_INT_STATUS1, &c);
+		sp_read_reg(TX_P0, TX_DEBUG1, &c1);
+		if (c1 & POLLING_EN) {
+			if (c & POLLING_ERR)
+				sp_tx_rst_aux();
+		} else
+			sp_tx_rst_aux();
+		return AUX_ERR;
+	}
+
+	for (i = 0; i < ccount; i++) {
+		sp_read_reg(TX_P0, BUF_DATA_0 + i, &c);
+		*(pbuf + i) = c;
+		if (i >= MAX_BUF_CNT)
+			break;
+	}
+	return AUX_OK;
+}
+
+u8 sp_tx_aux_dpcdwrite_bytes(u8 addrh, u8 addrm,
+		u8 addrl, u8 ccount, u8 *pbuf)
+{
+	u8 c, i, ret;
+
+	c =  ((ccount - 1) << 4) | 0x08;
+	sp_write_reg(TX_P0, AUX_CTRL, c);
+	write_dpcd_addr(addrh, addrm, addrl);
+	for (i = 0; i < ccount; i++) {
+		c = *pbuf;
+		pbuf++;
+		sp_write_reg(TX_P0, BUF_DATA_0 + i, c);
+
+		if (i >= 15)
+			break;
+	}
+	sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN);
+	wait_aux_op_finish(&ret);
+	return ret;
+}
+
+u8 sp_tx_aux_dpcdwrite_byte(u8 addrh, u8 addrm,
+		u8 addrl, u8 data1)
+{
+	u8 ret;
+
+	sp_write_reg(TX_P0, AUX_CTRL, 0x08);
+	write_dpcd_addr(addrh, addrm, addrl);
+	sp_write_reg(TX_P0, BUF_DATA_0, data1);
+	sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN);
+	wait_aux_op_finish(&ret);
+	return ret;
+}
+
+void slimport_block_power_ctrl(enum sp_tx_power_block sp_tx_pd_block,
+		u8 power)
+{
+	if (power == SP_POWER_ON)
+		sp_write_reg_and(TX_P2, SP_POWERD_CTRL_REG, (~sp_tx_pd_block));
+	else
+		sp_write_reg_or(TX_P2, SP_POWERD_CTRL_REG, (sp_tx_pd_block));
+	 pr_info("%s %s : sp_tx_power_on: %.2x\n",
+			LOG_TAG, __func__, (uint)sp_tx_pd_block);
+}
+
+void vbus_power_ctrl(unsigned char on)
+{
+	u8 i;
+
+	if (on == 0) {
+		sp_write_reg_and(TX_P2, TX_PLL_FILTER, ~V33_SWITCH_ON);
+		sp_write_reg_or(TX_P2, TX_PLL_FILTER5,
+					P5V_PROTECT_PD | SHORT_PROTECT_PD);
+		pr_info("%s %s : 3.3V output disabled\n", LOG_TAG, __func__);
+	} else {
+		for (i = 0; i < 5; i++) {
+			sp_write_reg_and(TX_P2, TX_PLL_FILTER5,
+					(~P5V_PROTECT_PD & ~SHORT_PROTECT_PD));
+			sp_write_reg_or(TX_P2, TX_PLL_FILTER, V33_SWITCH_ON);
+			if (!((u8)sp_i2c_read_byte(TX_P2, TX_PLL_FILTER5)
+				& 0xc0)) {
+				pr_info("%s %s : 3.3V output enabled\n",
+						LOG_TAG, __func__);
+				break;
+			}
+
+			pr_info("%s %s : VBUS power can not be supplied\n",
+				LOG_TAG, __func__);
+		}
+	}
+}
+
+void sp_tx_clean_state_machine(void)
+{
+	sp_tx_system_state = STATE_WAITTING_CABLE_PLUG;
+	sp_tx_system_state_bak = STATE_WAITTING_CABLE_PLUG;
+	sp_tx_sc_state = SC_INIT;
+	sp_tx_lt_state = LT_INIT;
+	hcdp_state = HDCP_CAPABLE_CHECK;
+	sp_tx_vo_state = VO_WAIT_VIDEO_STABLE;
+	sp_tx_ao_state = AO_INIT;
+}
+
+u8 sp_tx_cur_states(void)
+{
+	return sp_tx_system_state;
+}
+
+u8 sp_tx_cur_bw(void)
+{
+	return g_changed_bandwidth;
+}
+
+void sp_tx_set_bw(u8 bw)
+{
+	g_changed_bandwidth = bw;
+}
+
+void sp_tx_variable_init(void)
+{
+	uint i;
+
+	sp_tx_system_state = STATE_WAITTING_CABLE_PLUG;
+	sp_tx_system_state_bak = STATE_WAITTING_CABLE_PLUG;
+
+	g_edid_break = 0;
+	g_read_edid_flag = 0;
+	g_edid_checksum = 0;
+	for (i = 0; i < 256; i++)
+		edid_blocks[i] = 0;
+
+	sp_tx_lt_state = LT_INIT;
+	hcdp_state = HDCP_CAPABLE_CHECK;
+	g_need_clean_status = 0;
+	sp_tx_sc_state = SC_INIT;
+	sp_tx_vo_state = VO_WAIT_VIDEO_STABLE;
+	sp_tx_ao_state = AO_INIT;
+	g_changed_bandwidth = LINK_5P4G;
+	g_hdmi_dvi_status = HDMI_MODE;
+
+	sp_tx_test_lt = 0;
+	sp_tx_test_bw = 0;
+	sp_tx_test_edid = 0;
+
+	ds_vid_stb_cntr = 0;
+	hdcp_fail_count = 0;
+
+}
+
+static void hdmi_rx_tmds_phy_initialization(void)
+{
+	sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG2, 0xa9);
+	sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG7, 0x80);
+
+	sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG1, 0x90);
+	sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG6, 0x92);
+	sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG20, 0xf2);
+}
+
+void hdmi_rx_initialization(void)
+{
+	sp_write_reg(RX_P0, RX_MUTE_CTRL, AUD_MUTE | VID_MUTE);
+	sp_write_reg_or(RX_P0, RX_CHIP_CTRL,
+		MAN_HDMI5V_DET | PLLLOCK_CKDT_EN | DIGITAL_CKDT_EN);
+
+	sp_write_reg_or(RX_P0, RX_SRST, HDCP_MAN_RST | SW_MAN_RST |
+		TMDS_RST | VIDEO_RST);
+	sp_write_reg_and(RX_P0, RX_SRST, (~HDCP_MAN_RST) & (~SW_MAN_RST) &
+		(~TMDS_RST) & (~VIDEO_RST));
+
+	sp_write_reg_or(RX_P0, RX_AEC_EN0, AEC_EN06 | AEC_EN05);
+	sp_write_reg_or(RX_P0, RX_AEC_EN2, AEC_EN21);
+	sp_write_reg_or(RX_P0, RX_AEC_CTRL, AVC_EN | AAC_OE | AAC_EN);
+
+	sp_write_reg_and(RX_P0, RX_SYS_PWDN1, ~PWDN_CTRL);
+
+	sp_write_reg_or(RX_P0, RX_VID_DATA_RNG, R2Y_INPUT_LIMIT);
+	sp_write_reg(RX_P0, 0x65, 0xc4);
+	sp_write_reg(RX_P0, 0x66, 0x18);
+
+	sp_write_reg(TX_P0, TX_EXTRA_ADDR, 0x50); /* enable DDC stretch */
+
+	hdmi_rx_tmds_phy_initialization();
+	hdmi_rx_set_hpd(0);
+	hdmi_rx_set_termination(0);
+	pr_info("%s %s : HDMI Rx is initialized...\n", LOG_TAG, __func__);
+}
+
+struct clock_data const pxtal_data[XTAL_CLK_NUM] = {
+	{19, 192},
+	{24, 240},
+	{25, 250},
+	{26, 260},
+	{27, 270},
+	{38, 384},
+	{52, 520},
+	{27, 270},
+};
+
+void xtal_clk_sel(void)
+{
+	pr_info("%s %s : define XTAL_CLK:  %x\n ",
+			LOG_TAG, __func__, (uint)XTAL_27M);
+	sp_write_reg_and_or(TX_P2,
+			TX_ANALOG_DEBUG2, (~0x3c), 0x3c & (XTAL_27M << 2));
+	sp_write_reg(TX_P0, 0xEC, (u8)(((uint)XTAL_CLK_M10)));
+	sp_write_reg(TX_P0, 0xED,
+		(u8)(((uint)XTAL_CLK_M10 & 0xFF00) >> 2) | XTAL_CLK);
+
+	sp_write_reg(TX_P0,
+			I2C_GEN_10US_TIMER0, (u8)(((uint)XTAL_CLK_M10)));
+	sp_write_reg(TX_P0, I2C_GEN_10US_TIMER1,
+			(u8)(((uint)XTAL_CLK_M10 & 0xFF00) >> 8));
+	sp_write_reg(TX_P0, 0xBF, (u8)(((uint)XTAL_CLK - 1)));
+
+	sp_write_reg_and_or(RX_P0, 0x49, 0x07,
+			(u8)(((((uint)XTAL_CLK) >> 1) - 2) << 3));
+
+}
+
+void sp_tx_initialization(void)
+{
+	sp_write_reg(TX_P0, AUX_CTRL2, 0x30);
+	sp_write_reg_or(TX_P0, AUX_CTRL2, 0x08);
+
+	sp_write_reg_and(TX_P0, TX_HDCP_CTRL, (~AUTO_EN) & (~AUTO_START));
+	sp_write_reg(TX_P0, OTP_KEY_PROTECT1, OTP_PSW1);
+	sp_write_reg(TX_P0, OTP_KEY_PROTECT2, OTP_PSW2);
+	sp_write_reg(TX_P0, OTP_KEY_PROTECT3, OTP_PSW3);
+	sp_write_reg_or(TX_P0, HDCP_KEY_CMD, DISABLE_SYNC_HDCP);
+	sp_write_reg(TX_P2, SP_TX_VID_CTRL8_REG, VID_VRES_TH);
+
+	sp_write_reg(TX_P0, HDCP_AUTO_TIMER, HDCP_AUTO_TIMER_VAL);
+	sp_write_reg_or(TX_P0, TX_HDCP_CTRL, LINK_POLLING);
+
+	sp_write_reg_or(TX_P0, TX_LINK_DEBUG, M_VID_DEBUG);
+	sp_write_reg_or(TX_P2, TX_ANALOG_DEBUG2, POWERON_TIME_1P5MS);
+
+	xtal_clk_sel();
+	sp_write_reg(TX_P0, AUX_DEFER_CTRL, 0x8C);
+
+	sp_write_reg_or(TX_P0, TX_DP_POLLING, AUTO_POLLING_DISABLE);
+	/*
+	 * Short the link intergrity check timer to speed up bstatus
+	 * polling for HDCP CTS item 1A-07
+	 */
+	sp_write_reg(TX_P0, SP_TX_LINK_CHK_TIMER, 0x1d);
+	sp_write_reg_or(TX_P0, TX_MISC, EQ_TRAINING_LOOP);
+
+	sp_write_reg_or(TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD);
+
+	sp_write_reg(TX_P2, SP_TX_INT_CTRL_REG, 0X01);
+	/* disable HDCP mismatch function for VGA dongle */
+	sp_tx_link_phy_initialization();
+	gen_m_clk_with_downspeading();
+
+	down_sample_en = 0;
+}
+
+bool slimport_chip_detect(struct anx7814_data *data)
+{
+	uint16_t id;
+	uint8_t idh = 0, idl = 0;
+	int i;
+
+	hardware_power_ctl(data, 1);
+
+	/* check chip id */
+	sp_read_reg(TX_P2, SP_TX_DEV_IDL_REG, &idl);
+	sp_read_reg(TX_P2, SP_TX_DEV_IDH_REG, &idh);
+	id = idl | (idh << 8);
+
+	pr_info("%s %s : CHIPID: ANX%x\n", LOG_TAG, __func__, id & 0xffff);
+	for (i = 0; i < sizeof(chipid_list) / sizeof(uint16_t); i++) {
+		if (id == chipid_list[i])
+			return 1;
+	}
+	return 0;
+}
+
+void slimport_waitting_cable_plug_process(struct anx7814_data *data)
+{
+	sp_tx_variable_init();
+	hardware_power_ctl(data, 1);
+	goto_next_system_state();
+}
+
+/*
+ * Check if it is ANALOGIX dongle.
+ */
+unsigned char ANX_OUI[3] = {0x00, 0x22, 0xB9};
+
+unsigned char is_anx_dongle(void)
+{
+	unsigned char buf[3];
+
+	/* 0x0500~0x0502: BRANCH_IEEE_OUI */
+	sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x00, 3, buf);
+	if (buf[0] == ANX_OUI[0] && buf[1] == ANX_OUI[1]
+	    && buf[2] == ANX_OUI[2])
+		return 1;
+
+	return 0;
+}
+
+void sp_tx_get_rx_bw(unsigned char *bw)
+{
+	u8 data_buf[4];
+	/*
+	 * When ANX dongle connected, if CHIP_ID = 0x7750, bandwidth is 6.75G,
+	 * ecause ANX7750 DPCD 0x052x was not available.
+	 */
+	if (is_anx_dongle()) {
+		sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x03, 0x04, data_buf);
+		if ((data_buf[0] == 0x37) && (data_buf[1] == 0x37)
+			&& (data_buf[2] == 0x35) && (data_buf[3] == 0x30))
+			*bw = LINK_6P75G;
+		else
+			sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x21, 1, bw);
+		/* just for Debug */
+		*bw = LINK_6P75G;
+	} else
+		sp_tx_aux_dpcdread_bytes(0x00, 0x00, DPCD_MAX_LINK_RATE, 1, bw);
+}
+
+static u8 sp_tx_get_cable_type(enum cable_type_status det_cable_type_state)
+{
+	u8 ds_port_preset;
+	u8 aux_status;
+	u8 data_buf[16];
+	u8 cur_cable_type;
+
+	ds_port_preset = 0;
+	cur_cable_type = DWN_STRM_IS_NULL;
+
+	aux_status =
+		sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0x05, 1, &ds_port_preset);
+	pr_info("%s %s : DPCD 0x005: %x\n",
+			LOG_TAG, __func__, (int)ds_port_preset);
+
+	switch (det_cable_type_state) {
+	case CHECK_AUXCH:
+		if (AUX_OK == aux_status) {
+			sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0, 0x0c, data_buf);
+			det_cable_type_state = GETTED_CABLE_TYPE;
+		} else {
+			msleep(50);
+			pr_err("%s %s :  AUX access error\n",
+					LOG_TAG, __func__);
+			break;
+		}
+	case GETTED_CABLE_TYPE:
+		switch ((ds_port_preset  & (_BIT1 | _BIT2)) >> 1) {
+		case 0x00:
+			cur_cable_type = DWN_STRM_IS_DIGITAL;
+			pr_info("%s %s : Downstream is DP dongle.\n",
+					LOG_TAG, __func__);
+			break;
+		case 0x01:
+		case 0x03:
+			cur_cable_type = DWN_STRM_IS_ANALOG;
+			pr_info("%s %s : Downstream is VGA dongle.\n",
+					LOG_TAG, __func__);
+			break;
+		case 0x02:
+			cur_cable_type = DWN_STRM_IS_HDMI;
+			pr_info("%s %s : Downstream is HDMI dongle.\n",
+					LOG_TAG, __func__);
+			break;
+		default:
+			cur_cable_type = DWN_STRM_IS_NULL;
+			pr_err("%s %s : Downstream can not recognized.\n",
+					LOG_TAG, __func__);
+			break;
+		}
+	default:
+		break;
+	}
+	return cur_cable_type;
+}
+
+u8 sp_tx_get_hdmi_connection(void)
+{
+	u8 c;
+
+	if (AUX_OK != sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x18, 1, &c))
+		return 0;
+
+	if ((c & 0x41) == 0x41)
+		return 1;
+	else
+		return 0;
+
+}
+
+u8 sp_tx_get_vga_connection(void)
+{
+	u8 c;
+
+	if (AUX_OK !=
+		sp_tx_aux_dpcdread_bytes(0x00, 0x02, DPCD_SINK_COUNT, 1, &c)) {
+		pr_err("%s %s : aux error.\n", LOG_TAG, __func__);
+		return 0;
+	}
+
+	if (c & 0x01)
+		return 1;
+	else
+		return 0;
+}
+
+u8 sp_tx_get_dp_connection(void)
+{
+	u8 c;
+
+	if (AUX_OK !=
+		sp_tx_aux_dpcdread_bytes(0x00, 0x02, DPCD_SINK_COUNT, 1, &c))
+		return 0;
+
+	if (c & 0x1f) {
+		sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0x04, 1, &c);
+		if (c & 0x20) {
+			sp_tx_aux_dpcdread_bytes(0x00, 0x06, 0x00, 1, &c);
+			/*
+			 * Bit 5 = SET_DN_DEVICE_DP_PWR_5V
+			 * Bit 6 = SET_DN_DEVICE_DP_PWR_12V
+			 *  Bit 7 = SET_DN_DEVICE_DP_PWR_18V
+			 */
+			c = c & 0x1F;
+			sp_tx_aux_dpcdwrite_byte(0x00, 0x06, 0x00, c | 0x20);
+		}
+		return 1;
+	} else
+		return 0;
+}
+
+u8 sp_tx_get_downstream_connection(void)
+{
+	return sp_tx_get_dp_connection();
+}
+
+void slimport_sink_connection(void)
+{
+	switch (sp_tx_sc_state) {
+	case SC_INIT:
+		sp_tx_sc_state++;
+	case SC_CHECK_CABLE_TYPE:
+	case SC_WAITTING_CABLE_TYPE:
+	default:
+		if (sp_tx_get_cable_type(CHECK_AUXCH) == DWN_STRM_IS_NULL) {
+			sp_tx_sc_state++;
+			if (sp_tx_sc_state >= SC_WAITTING_CABLE_TYPE) {
+				sp_tx_sc_state = SC_NOT_CABLE;
+				pr_info("%s %s : Can not get cable type!\n",
+						LOG_TAG, __func__);
+			}
+			break;
+		}
+
+		sp_tx_sc_state = SC_SINK_CONNECTED;
+	case SC_SINK_CONNECTED:
+		if (sp_tx_get_downstream_connection())
+			goto_next_system_state();
+		break;
+	case SC_NOT_CABLE:
+		vbus_power_ctrl(0);
+		reg_hardware_reset();
+		break;
+	}
+}
+
+/******************start EDID process********************/
+void sp_tx_enable_video_input(u8 enable)
+{
+	u8 c;
+
+	sp_read_reg(TX_P2, VID_CTRL1, &c);
+	if (enable) {
+		if ((c & VIDEO_EN) != VIDEO_EN) {
+			c = (c & 0xf7) | VIDEO_EN;
+			sp_write_reg(TX_P2, VID_CTRL1, c);
+			pr_info("%s %s : Slimport Video is enabled!\n",
+					LOG_TAG, __func__);
+		}
+	} else {
+		if ((c & VIDEO_EN) == VIDEO_EN) {
+			c &= ~VIDEO_EN;
+			sp_write_reg(TX_P2, VID_CTRL1, c);
+			pr_info("%s %s : Slimport Video is disabled!\n",
+					LOG_TAG, __func__);
+		}
+	}
+}
+
+static u8 read_dvi_hdmi_mode(void)
+{
+	return 1;
+}
+
+static u8 get_edid_detail(u8 *data_buf)
+{
+	uint pixclock_edid;
+
+	pixclock_edid = ((((uint)data_buf[1] << 8))
+			| ((uint)data_buf[0] & 0xFF));
+	if (pixclock_edid <= 5300)
+		return LINK_1P62G;
+	else if ((5300 < pixclock_edid) && (pixclock_edid <= 8900))
+		return LINK_2P7G;
+	else if ((8900 < pixclock_edid) && (pixclock_edid <= 18000))
+		return LINK_5P4G;
+	else
+		return LINK_6P75G;
+}
+
+static u8 parse_edid_to_get_bandwidth(void)
+{
+	u8 desc_offset = 0;
+	u8 i, bandwidth, temp;
+
+	bandwidth = LINK_1P62G;
+	temp = LINK_1P62G;
+	i = 0;
+	while (4 > i && 0 != edid_blocks[0x36 + desc_offset]) {
+		temp = get_edid_detail(edid_blocks + 0x36 + desc_offset);
+		pr_info("%s %s : bandwidth via EDID : %x\n",
+				LOG_TAG, __func__, (uint)temp);
+		if (bandwidth < temp)
+			bandwidth = temp;
+		if (bandwidth > LINK_5P4G)
+			break;
+		desc_offset += 0x12;
+		++i;
+	}
+	return bandwidth;
+
+}
+
+static void sp_tx_aux_wr(u8 offset)
+{
+	sp_write_reg(TX_P0, BUF_DATA_0, offset);
+	sp_write_reg(TX_P0, AUX_CTRL, 0x04);
+	sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN);
+	wait_aux_op_finish(&g_edid_break);
+}
+
+static void sp_tx_aux_rd(u8 len_cmd)
+{
+	sp_write_reg(TX_P0, AUX_CTRL, len_cmd);
+	sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN);
+	wait_aux_op_finish(&g_edid_break);
+}
+
+u8 sp_tx_get_edid_block(void)
+{
+	u8 c;
+
+	sp_tx_aux_wr(0x7e);
+	sp_tx_aux_rd(0x01);
+	sp_read_reg(TX_P0, BUF_DATA_0, &c);
+	pr_info("%s %s : EDID Block = %d\n", LOG_TAG, __func__, (int)(c + 1));
+
+	if (c > 3)
+		c = 1;
+	return c;
+}
+
+void edid_read(u8 offset, u8 *pblock_buf)
+{
+	u8 data_cnt, cnt;
+	u8 c;
+
+	sp_tx_aux_wr(offset);
+	sp_tx_aux_rd(0xf5);
+	data_cnt = 0;
+	cnt = 0;
+
+	while ((data_cnt) < 16)	{
+		sp_read_reg(TX_P0, BUF_DATA_COUNT, &c);
+
+		if ((c & 0x1f) != 0) {
+			data_cnt = data_cnt + c;
+			do {
+				sp_read_reg(TX_P0, BUF_DATA_0 + c - 1,
+					&(pblock_buf[c - 1]));
+				if (c == 1)
+					break;
+			} while (c--);
+		} else {
+			if (cnt++ <= 2) {
+				sp_tx_rst_aux();
+				c = 0x05 | ((0x0f - data_cnt) << 4);
+				sp_tx_aux_rd(c);
+			} else {
+				 g_edid_break = 1;
+				 break;
+			}
+		}
+	}
+	sp_write_reg(TX_P0, AUX_CTRL, 0x01);
+	sp_write_reg_or(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT | AUX_OP_EN);
+	wait_aux_op_finish(&g_edid_break);
+	sp_tx_addronly_set(0);
+}
+
+void sp_tx_edid_read_initial(void)
+{
+	sp_write_reg(TX_P0, AUX_ADDR_7_0, 0x50);
+	sp_write_reg(TX_P0, AUX_ADDR_15_8, 0);
+	sp_write_reg_and(TX_P0, AUX_ADDR_19_16, 0xf0);
+}
+
+static void segments_edid_read(u8 segment, u8 offset)
+{
+	u8 c, cnt;
+	int i;
+
+	sp_write_reg(TX_P0, AUX_CTRL, 0x04);
+
+	sp_write_reg(TX_P0, AUX_ADDR_7_0, 0x30);
+
+	sp_write_reg_or(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT | AUX_OP_EN);
+
+	sp_read_reg(TX_P0, AUX_CTRL2, &c);
+
+	wait_aux_op_finish(&g_edid_break);
+	sp_read_reg(TX_P0, AUX_CTRL, &c);
+
+	sp_write_reg(TX_P0, BUF_DATA_0, segment);
+
+	sp_write_reg(TX_P0, AUX_CTRL, 0x04);
+
+	sp_write_reg_and_or(TX_P0, AUX_CTRL2, ~ADDR_ONLY_BIT, AUX_OP_EN);
+	cnt = 0;
+	sp_read_reg(TX_P0, AUX_CTRL2, &c);
+	while (c & AUX_OP_EN) {
+		usleep_range(1000, 2000);
+		cnt++;
+		if (cnt == 10) {
+			pr_info("%s %s : write break", LOG_TAG, __func__);
+			sp_tx_rst_aux();
+			cnt = 0;
+			g_edid_break = 1;
+			return;
+		}
+		sp_read_reg(TX_P0, AUX_CTRL2, &c);
+
+	}
+
+	sp_write_reg(TX_P0, AUX_ADDR_7_0, 0x50);
+
+	sp_tx_aux_wr(offset);
+
+	sp_tx_aux_rd(0xf5);
+	cnt = 0;
+	for (i = 0; i < 16; i++) {
+		sp_read_reg(TX_P0, BUF_DATA_COUNT, &c);
+		while ((c & 0x1f) == 0) {
+			usleep_range(2000, 4000);
+			cnt++;
+			sp_read_reg(TX_P0, BUF_DATA_COUNT, &c);
+			if (cnt == 10) {
+				pr_info("%s %s : read break",
+						LOG_TAG, __func__);
+				sp_tx_rst_aux();
+				g_edid_break = 1;
+				return;
+			}
+		}
+
+
+		sp_read_reg(TX_P0, BUF_DATA_0+i, &c);
+	}
+
+	sp_write_reg(TX_P0, AUX_CTRL, 0x01);
+	sp_write_reg_or(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT | AUX_OP_EN);
+	sp_write_reg_and(TX_P0, AUX_CTRL2, ~ADDR_ONLY_BIT);
+	sp_read_reg(TX_P0, AUX_CTRL2, &c);
+	while (c & AUX_OP_EN)
+		sp_read_reg(TX_P0, AUX_CTRL2, &c);
+}
+
+static bool edid_checksum_result(u8 *pbuf)
+{
+	u8 cnt, checksum;
+
+	checksum = 0;
+
+	for (cnt = 0; cnt < 0x80; cnt++)
+		checksum = checksum + pbuf[cnt];
+
+	g_edid_checksum = checksum - pbuf[0x7f];
+	g_edid_checksum = ~g_edid_checksum + 1;
+
+	return checksum == 0 ? 1 : 0;
+}
+
+static void edid_header_result(u8 *pbuf)
+{
+	 if ((pbuf[0] == 0) && (pbuf[7] == 0) && (pbuf[1] == 0xff)
+		&& (pbuf[2] == 0xff) && (pbuf[3] == 0xff)
+		&& (pbuf[4] == 0xff) && (pbuf[5] == 0xff) && (pbuf[6] == 0xff))
+		pr_info("%s %s : Good EDID header!\n", LOG_TAG, __func__);
+	 else
+		pr_err("%s %s : Bad EDID header!\n", LOG_TAG, __func__);
+
+}
+
+void check_edid_data(u8 *pblock_buf)
+{
+	u8 i;
+
+	edid_header_result(pblock_buf);
+	for (i = 0; i <= ((pblock_buf[0x7e] > 1) ? 1 : pblock_buf[0x7e]); i++) {
+		if (!edid_checksum_result(pblock_buf + i * 128))
+			pr_err("%s %s : Block %x edid checksum error\n",
+					LOG_TAG, __func__, (uint)i);
+		else
+			pr_info("%s %s : Block %x edid checksum OK\n",
+					LOG_TAG, __func__, (uint)i);
+	}
+}
+
+bool sp_tx_edid_read(u8 *pedid_blocks_buf)
+{
+	u8 offset = 0;
+	u8 count, blocks_num;
+	u8 pblock_buf[16];
+	u8 i, j, c;
+
+	g_edid_break = 0;
+	sp_tx_edid_read_initial();
+	sp_write_reg(TX_P0, AUX_CTRL, 0x04);
+	sp_write_reg_or(TX_P0, AUX_CTRL2, 0x03);
+	wait_aux_op_finish(&g_edid_break);
+	sp_tx_addronly_set(0);
+
+	blocks_num = sp_tx_get_edid_block();
+
+	count = 0;
+	do {
+		switch (count) {
+		case 0:
+		case 1:
+			for (i = 0; i < 8; i++) {
+				offset = (i + count * 8) * 16;
+				edid_read(offset, pblock_buf);
+				if (g_edid_break == 1)
+					break;
+				for (j = 0; j < 16; j++) {
+					pedid_blocks_buf[offset + j]
+						= pblock_buf[j];
+				}
+			}
+			break;
+		case 2:
+			offset = 0x00;
+			for (j = 0; j < 8; j++) {
+				if (g_edid_break == 1)
+					break;
+				segments_edid_read(count / 2, offset);
+				offset = offset + 0x10;
+			}
+			break;
+		case 3:
+			offset = 0x80;
+			for (j = 0; j < 8; j++) {
+				if (g_edid_break == 1)
+					break;
+				segments_edid_read(count / 2, offset);
+				offset = offset + 0x10;
+			}
+			break;
+		default:
+			break;
+		}
+		count++;
+		if (g_edid_break == 1)
+			break;
+	} while (blocks_num >= count);
+
+	sp_tx_rst_aux();
+	if (g_read_edid_flag == 0) {
+		check_edid_data(pedid_blocks_buf);
+		g_read_edid_flag = 1;
+	}
+	sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x18, 1, &c);
+	if (c & 0x04) {
+		pr_info("%s %s : check sum = %.2x\n",
+				LOG_TAG, __func__,  (uint)g_edid_checksum);
+		c = g_edid_checksum;
+		sp_tx_aux_dpcdwrite_bytes(0x00, 0x02, 0x61, 1, &c);
+		sp_tx_test_edid = 1;
+		c = 0x04;
+		sp_tx_aux_dpcdwrite_bytes(0x00, 0x02, 0x60, 1, &c);
+		pr_info("%s %s : Test EDID done\n", LOG_TAG, __func__);
+
+	}
+
+	return 0;
+}
+
+static bool check_with_pre_edid(u8 *org_buf)
+{
+	u8 i;
+	u8 temp_buf[16];
+	bool return_flag;
+
+	return_flag = 0;
+	g_edid_break = 0;
+	sp_tx_edid_read_initial();
+	sp_write_reg(TX_P0, AUX_CTRL, 0x04);
+	sp_write_reg_or(TX_P0, AUX_CTRL2, 0x03);
+	wait_aux_op_finish(&g_edid_break);
+	sp_tx_addronly_set(0);
+
+	edid_read(0x70, temp_buf);
+
+	if (g_edid_break == 0) {
+
+		for (i = 0; i < 16; i++) {
+			if (org_buf[0x70 + i] != temp_buf[i]) {
+				pr_info("%s %s : %s\n", LOG_TAG, __func__,
+					"different checksum and blocks num\n");
+				return_flag = 1;
+				break;
+			}
+		}
+	} else
+		return_flag = 1;
+
+	if (return_flag)
+		goto return_point;
+
+	edid_read(0x08, temp_buf);
+	if (g_edid_break == 0) {
+		for (i = 0; i < 16; i++) {
+			if (org_buf[i + 8] != temp_buf[i]) {
+				pr_info("%s %s : different edid information\n",
+						LOG_TAG, __func__);
+				return_flag = 1;
+				break;
+			}
+		}
+	} else
+		return_flag = 1;
+
+return_point:
+	sp_tx_rst_aux();
+	return return_flag;
+}
+
+void slimport_edid_process(void)
+{
+	u8 temp_value, temp_value1;
+	u8 i;
+
+	pr_info("%s %s : edid_process\n", LOG_TAG, __func__);
+
+	if (g_read_edid_flag == 1) {
+		if (check_with_pre_edid(edid_blocks))
+			g_read_edid_flag = 0;
+		else
+			pr_info("%s %s : Don`t need to read edid!\n",
+					LOG_TAG, __func__);
+	}
+
+	if (g_read_edid_flag == 0) {
+		sp_tx_edid_read(edid_blocks);
+		if (g_edid_break)
+			pr_err("%s %s : ERR:EDID corruption!\n",
+					LOG_TAG, __func__);
+	}
+
+
+	/* Release the HPD after the OTP loaddown */
+	i = 10;
+	do {
+		if ((sp_i2c_read_byte(TX_P0, HDCP_KEY_STATUS) & 0x01))
+			break;
+
+		pr_info("%s %s : waiting HDCP KEY loaddown\n",
+				LOG_TAG, __func__);
+		usleep_range(1000, 2000);
+	} while (--i);
+	sp_write_reg(RX_P0, HDMI_RX_INT_MASK1_REG, 0xe2);
+	hdmi_rx_set_hpd(1);
+	pr_info("%s %s : hdmi_rx_set_hpd 1 !\n", LOG_TAG, __func__);
+	hdmi_rx_set_termination(1);
+
+	sp_tx_get_rx_bw(&temp_value);
+	pr_info("%s %s : RX BW %x\n", LOG_TAG, __func__, (uint)temp_value);
+	temp_value1 = parse_edid_to_get_bandwidth();
+	if (temp_value <= temp_value1)
+		temp_value1 = temp_value;
+	pr_info("%s %s : set link bw in edid %x\n",
+			LOG_TAG, __func__, (uint)temp_value1);
+	g_changed_bandwidth = temp_value1;
+	goto_next_system_state();
+}
+/******************End EDID process********************/
+
+/******************start Link training process********************/
+static void sp_tx_lvttl_bit_mapping(void)
+{
+	u8 c, colorspace;
+	u8 vid_bit;
+
+	vid_bit = 0;
+	sp_read_reg(RX_P1, HDMI_RX_AVI_DATA00_REG, &colorspace);
+	colorspace &= 0x60;
+
+	switch (((sp_i2c_read_byte(RX_P0, HDMI_RX_VIDEO_STATUS_REG1)
+		& COLOR_DEPTH) >> 4)) {
+	default:
+	case HDMI_LEGACY:
+		c = IN_BPC_8BIT;
+		vid_bit = 0;
+		break;
+	case HDMI_24BIT:
+		c = IN_BPC_8BIT;
+		if (colorspace == 0x20)
+			vid_bit = 5;
+		else
+			vid_bit = 1;
+		break;
+	case HDMI_30BIT:
+		c = IN_BPC_10BIT;
+		if (colorspace == 0x20)
+			vid_bit = 6;
+		else
+			vid_bit = 2;
+		break;
+	case HDMI_36BIT:
+		c = IN_BPC_12BIT;
+		if (colorspace == 0x20)
+			vid_bit = 6;
+		else
+			vid_bit = 3;
+		break;
+
+	}
+	/*
+	 * For down sample video (12bit, 10bit ---> 8bit),
+	 * this register don`t change
+	 */
+	if (down_sample_en == 0)
+		sp_write_reg_and_or(TX_P2,
+			SP_TX_VID_CTRL2_REG, 0x8c, colorspace >> 5 | c);
+
+	/* Patch: for 10bit video must be set this value to 12bit by someone */
+	if (down_sample_en == 1 && c == IN_BPC_10BIT)
+		vid_bit = 3;
+
+	sp_write_reg_and_or(TX_P2,
+		BIT_CTRL_SPECIFIC, 0x00, ENABLE_BIT_CTRL | vid_bit << 1);
+
+	if (sp_tx_test_edid) {
+		sp_write_reg_and(TX_P2, SP_TX_VID_CTRL2_REG, 0x8f);
+		pr_info("%s %s : ***color space is set to 18bit***\n",
+				LOG_TAG, __func__);
+	}
+
+	if (colorspace) {
+		sp_write_reg(TX_P0, SP_TX_VID_BLANK_SET1, 0x80);
+		sp_write_reg(TX_P0, SP_TX_VID_BLANK_SET2, 0x00);
+		sp_write_reg(TX_P0, SP_TX_VID_BLANK_SET3, 0x80);
+	} else {
+		sp_write_reg(TX_P0, SP_TX_VID_BLANK_SET1, 0x0);
+		sp_write_reg(TX_P0, SP_TX_VID_BLANK_SET2, 0x0);
+		sp_write_reg(TX_P0, SP_TX_VID_BLANK_SET3, 0x0);
+	}
+}
+
+ulong sp_tx_pclk_calc(void)
+{
+	ulong str_plck;
+	uint vid_counter;
+	u8 c;
+
+	sp_read_reg(RX_P0, 0x8d, &c);
+	vid_counter = c;
+	vid_counter = vid_counter << 8;
+	sp_read_reg(RX_P0, 0x8c, &c);
+	vid_counter |= c;
+	str_plck = ((ulong)vid_counter * XTAL_CLK_M10)  >> 12;
+	pr_info("%s %s : PCLK = %d.%d\n",
+		LOG_TAG, __func__, (((uint)(str_plck))/10),
+		((uint)str_plck - (((uint)str_plck/10)*10)));
+	return str_plck;
+}
+
+static u8 sp_tx_bw_lc_sel(ulong pclk)
+{
+	ulong pixel_clk;
+	u8 c1;
+
+	switch (((sp_i2c_read_byte(RX_P0, HDMI_RX_VIDEO_STATUS_REG1)
+		& COLOR_DEPTH) >> 4)) {
+	case HDMI_LEGACY:
+	case HDMI_24BIT:
+	default:
+		pixel_clk = pclk;
+		break;
+	case HDMI_30BIT:
+		pixel_clk = (pclk * 5) >> 2;
+		break;
+	case HDMI_36BIT:
+		pixel_clk = (pclk * 3) >> 1;
+		break;
+	}
+	pr_info("%s %s : pixel_clk = %d.%d\n",
+		LOG_TAG, __func__, (((uint)(pixel_clk))/10),
+		((uint)pixel_clk - (((uint)pixel_clk/10)*10)));
+
+	down_sample_en = 0;
+	if (pixel_clk <= 530)
+		c1 = LINK_1P62G;
+	else if ((530 < pixel_clk) && (pixel_clk <= 890))
+		c1 = LINK_2P7G;
+	else if ((890 < pixel_clk) && (pixel_clk <= 1800))
+		c1 = LINK_5P4G;
+	else {
+		 c1 = LINK_6P75G;
+		 if (pixel_clk > 2240)
+			down_sample_en = 1;
+	}
+
+	if (sp_tx_get_link_bw() != c1) {
+		g_changed_bandwidth = c1;
+		pr_info("%s %s : %s! %.2x\n", LOG_TAG, __func__,
+		    "different bandwidth between sink support and cur video",
+		    (uint)c1);
+		return 1;
+	}
+	return 0;
+}
+
+void sp_tx_spread_enable(u8 benable)
+{
+	u8 c;
+
+	sp_read_reg(TX_P0, SP_TX_DOWN_SPREADING_CTRL1, &c);
+
+	if (benable) {
+		c |= SP_TX_SSC_DWSPREAD;
+		sp_write_reg(TX_P0, SP_TX_DOWN_SPREADING_CTRL1, c);
+
+		sp_tx_aux_dpcdread_bytes(0x00, 0x01,
+			DPCD_DOWNSPREAD_CTRL, 1, &c);
+		c |= SPREAD_AMPLITUDE;
+		sp_tx_aux_dpcdwrite_byte(0x00, 0x01, DPCD_DOWNSPREAD_CTRL, c);
+
+	} else {
+		c &= ~SP_TX_SSC_DISABLE;
+		sp_write_reg(TX_P0, SP_TX_DOWN_SPREADING_CTRL1, c);
+
+		sp_tx_aux_dpcdread_bytes(0x00, 0x01,
+			DPCD_DOWNSPREAD_CTRL, 1, &c);
+		c &= ~SPREAD_AMPLITUDE;
+		sp_tx_aux_dpcdwrite_byte(0x00, 0x01, DPCD_DOWNSPREAD_CTRL, c);
+	}
+
+}
+
+void sp_tx_config_ssc(enum sp_ssc_dep sscdep)
+{
+	sp_write_reg(TX_P0, SP_TX_DOWN_SPREADING_CTRL1, 0x0);
+	sp_write_reg(TX_P0, SP_TX_DOWN_SPREADING_CTRL1, sscdep);
+	sp_tx_spread_enable(1);
+}
+
+void sp_tx_enhancemode_set(void)
+{
+	u8 c;
+
+	sp_tx_aux_dpcdread_bytes(0x00, 0x00, DPCD_MAX_LANE_COUNT, 1, &c);
+	if (c & ENHANCED_FRAME_CAP) {
+		sp_write_reg_or(TX_P0, SP_TX_SYS_CTRL4_REG, ENHANCED_MODE);
+
+		sp_tx_aux_dpcdread_bytes(0x00, 0x01,
+			DPCD_LANE_COUNT_SET, 1, &c);
+		c |= ENHANCED_FRAME_EN;
+		sp_tx_aux_dpcdwrite_byte(0x00, 0x01,
+			DPCD_LANE_COUNT_SET, c);
+
+		pr_info("%s %s : Enhance mode enabled\n", LOG_TAG, __func__);
+	} else {
+
+		sp_write_reg_and(TX_P0, SP_TX_SYS_CTRL4_REG, ~ENHANCED_MODE);
+
+		sp_tx_aux_dpcdread_bytes(0x00, 0x01,
+			DPCD_LANE_COUNT_SET, 1, &c);
+		c &= ~ENHANCED_FRAME_EN;
+		sp_tx_aux_dpcdwrite_byte(0x00, 0x01,
+			DPCD_LANE_COUNT_SET, c);
+
+		pr_info("%s %s : Enhance mode disabled\n", LOG_TAG, __func__);
+	}
+}
+
+uint sp_tx_link_err_check(void)
+{
+	uint errl = 0, errh = 0;
+	u8 bytebuf[2];
+
+	sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x10, 2, bytebuf);
+	usleep_range(5000, 10000);
+	sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x10, 2, bytebuf);
+	errh = bytebuf[1];
+
+	if (errh & 0x80) {
+		errl = bytebuf[0];
+		errh = (errh & 0x7f) << 8;
+		errl = errh + errl;
+	}
+
+	pr_err("%s %s :  Err of Lane = %d\n", LOG_TAG, __func__, errl);
+	return errl;
+}
+
+static inline void sp_lt_finish(u8 temp_value)
+{
+	sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x02, 1, &temp_value);
+	if ((temp_value & 0x07) == 0x07) {
+		/*
+		 * if there is link error,
+		 * adjust pre-emphsis to check error again.
+		 * If there is no error,keep the setting,
+		 * otherwise use 400mv0db
+		 */
+		if (!sp_tx_test_lt) {
+			if (sp_tx_link_err_check()) {
+				sp_read_reg(TX_P0,
+					SP_TX_LT_SET_REG, &temp_value);
+				if (!(temp_value & MAX_PRE_REACH)) {
+					sp_write_reg(TX_P0,
+						SP_TX_LT_SET_REG,
+						(temp_value + 0x08));
+					if (sp_tx_link_err_check())
+						sp_write_reg(TX_P0,
+						SP_TX_LT_SET_REG,
+						temp_value);
+				}
+			}
+
+			sp_read_reg(TX_P0,
+				SP_TX_LINK_BW_SET_REG, &temp_value);
+			if (temp_value == g_changed_bandwidth) {
+				pr_info("%s %s : LT succeed, bw: %.2x",
+					LOG_TAG, __func__,
+					(uint) temp_value);
+				pr_info("Lane0 Set: %.2x\n",
+					(uint) sp_i2c_read_byte(TX_P0,
+						SP_TX_LT_SET_REG));
+				sp_tx_lt_state = LT_INIT;
+				goto_next_system_state();
+			} else {
+				pr_info("%s %s : cur:%.2x, per:%.2x\n",
+					LOG_TAG, __func__,
+					(uint)temp_value,
+					(uint)g_changed_bandwidth);
+				sp_tx_lt_state = LT_ERROR;
+			}
+		} else {
+			sp_tx_test_lt = 0;
+			sp_tx_lt_state = LT_INIT;
+			goto_next_system_state();
+		}
+	} else {
+		pr_info("%s %s : LANE0 Status error: %.2x\n",
+			LOG_TAG, __func__, (uint)(temp_value & 0x07));
+		sp_tx_lt_state = LT_ERROR;
+	}
+}
+
+void slimport_link_training(void)
+{
+	u8 temp_value, return_value, c;
+
+	return_value = 1;
+	pr_info("%s %s : sp_tx_lt_state : %x\n",
+			LOG_TAG, __func__, (int)sp_tx_lt_state);
+	switch (sp_tx_lt_state) {
+	case LT_INIT:
+		slimport_block_power_ctrl(SP_TX_PWR_VIDEO, SP_POWER_ON);
+		sp_tx_video_mute(1);
+		sp_tx_enable_video_input(0);
+		sp_tx_lt_state++;
+	/* fallthrough */
+	case LT_WAIT_PLL_LOCK:
+		if (!sp_tx_get_pll_lock_status()) {
+			sp_read_reg(TX_P0, SP_TX_PLL_CTRL_REG, &temp_value);
+			temp_value |= PLL_RST;
+			sp_write_reg(TX_P0, SP_TX_PLL_CTRL_REG, temp_value);
+			temp_value &= ~PLL_RST;
+			sp_write_reg(TX_P0, SP_TX_PLL_CTRL_REG, temp_value);
+			pr_info("%s %s : PLL not lock!\n", LOG_TAG, __func__);
+		} else
+			sp_tx_lt_state = LT_CHECK_LINK_BW;
+		SP_BREAK(LT_WAIT_PLL_LOCK, sp_tx_lt_state);
+	/* fallthrough */
+	case LT_CHECK_LINK_BW:
+		sp_tx_get_rx_bw(&temp_value);
+		if (temp_value < g_changed_bandwidth) {
+			pr_info("%s %s : ****Over bandwidth****\n",
+				LOG_TAG, __func__);
+			g_changed_bandwidth = temp_value;
+		} else
+			sp_tx_lt_state++;
+	/* fallthrough */
+	case LT_START:
+		if (sp_tx_test_lt) {
+			g_changed_bandwidth = sp_tx_test_bw;
+			sp_write_reg_and(TX_P2, SP_TX_VID_CTRL2_REG, 0x8f);
+		} else
+			sp_write_reg(TX_P0, SP_TX_LT_SET_REG, 0x00);
+
+		sp_write_reg_and(TX_P0, SP_TX_ANALOG_PD_REG, ~CH0_PD);
+
+		sp_tx_config_ssc(SSC_DEP_4000PPM);
+		sp_tx_set_link_bw(g_changed_bandwidth);
+		sp_tx_enhancemode_set();
+
+		sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0x00, 0x01, &c);
+		sp_tx_aux_dpcdread_bytes(0x00, 0x06, 0x00, 0x01, &temp_value);
+		if (c >= 0x12)
+			temp_value &= 0xf8;
+		else
+			temp_value &= 0xfc;
+		temp_value |= 0x01;
+		sp_tx_aux_dpcdwrite_byte(0x00, 0x06, 0x00, temp_value);
+
+
+		sp_write_reg(TX_P0, LT_CTRL, SP_TX_LT_EN);
+		sp_tx_lt_state = LT_WAITTING_FINISH;
+	/* fallthrough */
+	case LT_WAITTING_FINISH:
+		/* here : waiting interrupt to change training state. */
+		break;
+
+	case LT_ERROR:
+		sp_write_reg_or(TX_P2, RST_CTRL2, SERDES_FIFO_RST);
+		msleep(20);
+		sp_write_reg_and(TX_P2, RST_CTRL2, (~SERDES_FIFO_RST));
+		pr_err("LT ERROR Status: SERDES FIFO reset.");
+		redo_cur_system_state();
+		sp_tx_lt_state = LT_INIT;
+		break;
+
+	case LT_FINISH:
+		sp_lt_finish(temp_value);
+		break;
+	default:
+		break;
+	}
+
+}
+/******************End Link training process********************/
+
+/******************Start Output video process********************/
+void sp_tx_set_colorspace(void)
+{
+	u8 color_space;
+
+	if (down_sample_en) {
+		sp_read_reg(RX_P1, HDMI_RX_AVI_DATA00_REG, &color_space);
+		color_space &= 0x60;
+		if (color_space == 0x20) {
+			pr_info("%s %s : YCbCr4:2:2 ---> PASS THROUGH.\n",
+				LOG_TAG, __func__);
+			sp_write_reg(TX_P2, SP_TX_VID_CTRL6_REG, 0x00);
+			sp_write_reg(TX_P2, SP_TX_VID_CTRL5_REG, 0x00);
+			sp_write_reg(TX_P2, SP_TX_VID_CTRL2_REG, 0x11);
+		} else if (color_space == 0x40) {
+			pr_info("%s %s : YCbCr4:4:4 ---> YCbCr4:2:2\n",
+				LOG_TAG, __func__);
+			sp_write_reg(TX_P2, SP_TX_VID_CTRL6_REG, 0x41);
+			sp_write_reg(TX_P2, SP_TX_VID_CTRL5_REG, 0x00);
+			sp_write_reg(TX_P2, SP_TX_VID_CTRL2_REG, 0x12);
+		} else if (color_space == 0x00) {
+			pr_info("%s %s : RGB4:4:4 ---> YCbCr4:2:2\n",
+				LOG_TAG, __func__);
+			sp_write_reg(TX_P2, SP_TX_VID_CTRL6_REG, 0x41);
+			sp_write_reg(TX_P2, SP_TX_VID_CTRL5_REG, 0x83);
+			sp_write_reg(TX_P2, SP_TX_VID_CTRL2_REG, 0x10);
+		}
+	} else {
+		sp_write_reg(TX_P2, SP_TX_VID_CTRL6_REG, 0x00);
+		sp_write_reg(TX_P2, SP_TX_VID_CTRL5_REG, 0x00);
+	}
+}
+
+void sp_tx_avi_setup(void)
+{
+	u8 c;
+	int i;
+
+	for (i = 0; i < 13; i++) {
+		sp_read_reg(RX_P1, (HDMI_RX_AVI_DATA00_REG + i), &c);
+		sp_tx_packet_avi.avi_data[i] = c;
+	}
+}
+
+static void sp_tx_load_packet(enum packets_type type)
+{
+	int i;
+	u8 c;
+
+	switch (type) {
+	case AVI_PACKETS:
+		sp_write_reg(TX_P2, SP_TX_AVI_TYPE, 0x82);
+		sp_write_reg(TX_P2, SP_TX_AVI_VER, 0x02);
+		sp_write_reg(TX_P2, SP_TX_AVI_LEN, 0x0d);
+
+		for (i = 0; i < 13; i++) {
+			sp_write_reg(TX_P2, SP_TX_AVI_DB0 + i,
+					sp_tx_packet_avi.avi_data[i]);
+		}
+
+		break;
+
+	case SPD_PACKETS:
+		sp_write_reg(TX_P2, SP_TX_SPD_TYPE, 0x83);
+		sp_write_reg(TX_P2, SP_TX_SPD_VER, 0x01);
+		sp_write_reg(TX_P2, SP_TX_SPD_LEN, 0x19);
+
+		for (i = 0; i < 25; i++) {
+			sp_write_reg(TX_P2, SP_TX_SPD_DB0 + i,
+					sp_tx_packet_spd.spd_data[i]);
+		}
+
+		break;
+
+	case VSI_PACKETS:
+		sp_write_reg(TX_P2, SP_TX_MPEG_TYPE, 0x81);
+		sp_write_reg(TX_P2, SP_TX_MPEG_VER, 0x01);
+		sp_read_reg(RX_P1, HDMI_RX_MPEG_LEN_REG, &c);
+		sp_write_reg(TX_P2, SP_TX_MPEG_LEN, c);
+
+		for (i = 0; i < 10; i++) {
+			sp_write_reg(TX_P2, SP_TX_MPEG_DB0 + i,
+					sp_tx_packet_mpeg.mpeg_data[i]);
+		}
+
+		break;
+	case MPEG_PACKETS:
+		sp_write_reg(TX_P2, SP_TX_MPEG_TYPE, 0x85);
+		sp_write_reg(TX_P2, SP_TX_MPEG_VER, 0x01);
+		sp_write_reg(TX_P2, SP_TX_MPEG_LEN, 0x0d);
+
+		for (i = 0; i < 10; i++) {
+			sp_write_reg(TX_P2, SP_TX_MPEG_DB0 + i,
+					sp_tx_packet_mpeg.mpeg_data[i]);
+		}
+
+		break;
+	case AUDIF_PACKETS:
+		sp_write_reg(TX_P2, SP_TX_AUD_TYPE, 0x84);
+		sp_write_reg(TX_P2, SP_TX_AUD_VER, 0x01);
+		sp_write_reg(TX_P2, SP_TX_AUD_LEN, 0x0a);
+		for (i = 0; i < 10; i++) {
+			sp_write_reg(TX_P2, SP_TX_AUD_DB0 + i,
+					sp_tx_audioinfoframe.pb_byte[i]);
+		}
+
+		break;
+
+	default:
+		break;
+	}
+}
+
+void sp_tx_config_packets(enum packets_type type)
+{
+	u8 c;
+
+	switch (type) {
+	case AVI_PACKETS:
+
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c &= ~AVI_IF_EN;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+		sp_tx_load_packet(AVI_PACKETS);
+
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c |= AVI_IF_UD;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c |= AVI_IF_EN;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+		break;
+
+	case SPD_PACKETS:
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c &= ~SPD_IF_EN;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+		sp_tx_load_packet(SPD_PACKETS);
+
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c |= SPD_IF_UD;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c |=  SPD_IF_EN;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+		break;
+
+	case VSI_PACKETS:
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c &= ~MPEG_IF_EN;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+		sp_tx_load_packet(VSI_PACKETS);
+
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c |= MPEG_IF_UD;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c |= MPEG_IF_EN;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+		break;
+	case MPEG_PACKETS:
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c &= ~MPEG_IF_EN;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+
+		sp_tx_load_packet(MPEG_PACKETS);
+
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c |= MPEG_IF_UD;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c |= MPEG_IF_EN;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+		break;
+	case AUDIF_PACKETS:
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c &= ~AUD_IF_EN;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+
+		sp_tx_load_packet(AUDIF_PACKETS);
+
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c |= AUD_IF_UP;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+		sp_read_reg(TX_P0, SP_TX_PKT_EN_REG, &c);
+		c |= AUD_IF_EN;
+		sp_write_reg(TX_P0, SP_TX_PKT_EN_REG, c);
+
+		break;
+
+	default:
+		break;
+	}
+
+}
+
+void slimport_config_video_output(void)
+{
+	u8 temp_value;
+
+	switch (sp_tx_vo_state) {
+	default:
+	case VO_WAIT_VIDEO_STABLE:
+		sp_read_reg(RX_P0, HDMI_RX_SYS_STATUS_REG, &temp_value);
+		if ((temp_value & (TMDS_DE_DET | TMDS_CLOCK_DET)) == 0x03) {
+			sp_tx_bw_lc_sel(sp_tx_pclk_calc());
+			sp_tx_enable_video_input(0);
+			sp_tx_avi_setup();
+			sp_tx_config_packets(AVI_PACKETS);
+			sp_tx_set_colorspace();
+			sp_tx_lvttl_bit_mapping();
+			if (sp_i2c_read_byte(RX_P0, RX_PACKET_REV_STA)
+			& VSI_RCVD)
+				hdmi_rx_new_vsi_int();
+			sp_tx_enable_video_input(1);
+			sp_tx_vo_state = VO_WAIT_TX_VIDEO_STABLE;
+		} else
+			pr_info("%s %s :HDMI input video not stable!\n",
+					LOG_TAG, __func__);
+		SP_BREAK(VO_WAIT_VIDEO_STABLE, sp_tx_vo_state);
+	/* fallthrough */
+	case VO_WAIT_TX_VIDEO_STABLE:
+		sp_read_reg(TX_P0, SP_TX_SYS_CTRL2_REG, &temp_value);
+		sp_write_reg(TX_P0, SP_TX_SYS_CTRL2_REG, temp_value);
+		sp_read_reg(TX_P0, SP_TX_SYS_CTRL2_REG, &temp_value);
+		if (temp_value & CHA_STA)
+			pr_info("%s %s : Stream clock not stable!\n",
+					LOG_TAG, __func__);
+		else {
+			sp_read_reg(TX_P0, SP_TX_SYS_CTRL3_REG, &temp_value);
+			sp_write_reg(TX_P0, SP_TX_SYS_CTRL3_REG, temp_value);
+			sp_read_reg(TX_P0, SP_TX_SYS_CTRL3_REG, &temp_value);
+			if (!(temp_value & STRM_VALID))
+				pr_err("%s %s : video stream not valid!\n",
+						LOG_TAG, __func__);
+			else
+				sp_tx_vo_state = VO_CHECK_VIDEO_INFO;
+		}
+		SP_BREAK(VO_WAIT_TX_VIDEO_STABLE, sp_tx_vo_state);
+	/* fallthrough */
+	case VO_CHECK_VIDEO_INFO:
+		if (!sp_tx_bw_lc_sel(sp_tx_pclk_calc()))
+			sp_tx_vo_state++;
+		else
+			sp_tx_set_sys_state(STATE_LINK_TRAINING);
+		SP_BREAK(VO_CHECK_VIDEO_INFO, sp_tx_vo_state);
+	/* fallthrough */
+	case VO_FINISH:
+		slimport_block_power_ctrl(SP_TX_PWR_AUDIO, SP_POWER_DOWN);
+		hdmi_rx_mute_video(0);
+		sp_tx_video_mute(0);
+		sp_tx_show_information();
+		goto_next_system_state();
+		break;
+	}
+}
+/******************End Output video process********************/
+
+/******************Start HDCP process********************/
+static void sp_tx_hdcp_encryption_disable(void)
+{
+	sp_write_reg_and(TX_P0, TX_HDCP_CTRL0, ~ENC_EN);
+}
+
+static void sp_tx_hdcp_encryption_enable(void)
+{
+	sp_write_reg_or(TX_P0, TX_HDCP_CTRL0, ENC_EN);
+}
+
+static void sp_tx_hw_hdcp_enable(void)
+{
+	u8 c;
+
+	sp_write_reg_and(TX_P0, TX_HDCP_CTRL0, (~ENC_EN) & (~HARD_AUTH_EN));
+	sp_write_reg_or(TX_P0, TX_HDCP_CTRL0,
+			HARD_AUTH_EN | BKSV_SRM_PASS | KSVLIST_VLD | ENC_EN);
+
+	sp_read_reg(TX_P0, TX_HDCP_CTRL0, &c);
+	pr_info("%s %s : TX_HDCP_CTRL0 = %.2x\n", LOG_TAG, __func__, (uint)c);
+	sp_write_reg(TX_P0, SP_TX_WAIT_R0_TIME, 0xb0);
+	sp_write_reg(TX_P0, SP_TX_WAIT_KSVR_TIME, 0xc8);
+
+	pr_info("%s %s : Hardware HDCP is enabled.\n", LOG_TAG, __func__);
+
+}
+
+void slimport_hdcp_process(void)
+{
+	switch (hcdp_state) {
+	case HDCP_CAPABLE_CHECK:
+		ds_vid_stb_cntr = 0;
+		hdcp_fail_count = 0;
+		if (is_anx_dongle())
+			hcdp_state = HDCP_WAITTING_VID_STB;
+		else
+			hcdp_state = HDCP_HW_ENABLE;
+		if (external_block_en == 0) {
+			if (slimport_hdcp_cap_check() == 0)
+				hcdp_state = HDCP_NOT_SUPPORT;
+		}
+		/*
+		 * Just for debug, pin: P2-2
+		 * There is a switch to disable/enable HDCP.
+		 */
+		hcdp_state = HDCP_NOT_SUPPORT;
+		/*****************************************/
+		SP_BREAK(HDCP_CAPABLE_CHECK, hcdp_state);
+	/* fallthrough */
+	case HDCP_WAITTING_VID_STB:
+		msleep(100);
+		hcdp_state = HDCP_HW_ENABLE;
+		SP_BREAK(HDCP_WAITTING_VID_STB, hcdp_state);
+	/* fallthrough */
+	case HDCP_HW_ENABLE:
+		sp_tx_video_mute(1);
+		sp_tx_clean_hdcp_status();
+		slimport_block_power_ctrl(SP_TX_PWR_HDCP, SP_POWER_DOWN);
+		msleep(20);
+		slimport_block_power_ctrl(SP_TX_PWR_HDCP, SP_POWER_ON);
+		sp_write_reg(TX_P2, SP_COMMON_INT_MASK2, 0x01);
+		msleep(50);
+		sp_tx_hw_hdcp_enable();
+		hcdp_state = HDCP_WAITTING_FINISH;
+	/* fallthrough */
+	case HDCP_WAITTING_FINISH:
+		break;
+	case HDCP_FINISH:
+		sp_tx_hdcp_encryption_enable();
+		hdmi_rx_mute_video(0);
+		sp_tx_video_mute(0);
+		goto_next_system_state();
+		hcdp_state = HDCP_CAPABLE_CHECK;
+		pr_info("%s %s : @@@@@@@hdcp_auth_pass@@@@@@\n",
+				LOG_TAG, __func__);
+		break;
+	case HDCP_FAILE:
+		if (hdcp_fail_count > 5) {
+			vbus_power_ctrl(0);
+			reg_hardware_reset();
+			hcdp_state = HDCP_CAPABLE_CHECK;
+			hdcp_fail_count = 0;
+			pr_info("%s %s : *********hdcp_auth_failed*********\n",
+					LOG_TAG, __func__);
+		} else {
+			hdcp_fail_count++;
+			hcdp_state = HDCP_WAITTING_VID_STB;
+		}
+		break;
+	default:
+	case HDCP_NOT_SUPPORT:
+		pr_info("%s %s : Sink is not capable HDCP\n",
+				LOG_TAG, __func__);
+		slimport_block_power_ctrl(SP_TX_PWR_HDCP, SP_POWER_DOWN);
+		sp_tx_video_mute(0);
+		goto_next_system_state();
+		hcdp_state = HDCP_CAPABLE_CHECK;
+		break;
+	}
+}
+/******************End HDCP process********************/
+
+/******************Start Audio process********************/
+static void sp_tx_audioinfoframe_setup(void)
+{
+	int i;
+	u8 c;
+
+	sp_read_reg(RX_P1, HDMI_RX_AUDIO_TYPE_REG, &c);
+	sp_tx_audioinfoframe.type = c;
+	sp_read_reg(RX_P1, HDMI_RX_AUDIO_VER_REG, &c);
+	sp_tx_audioinfoframe.version = c;
+	sp_read_reg(RX_P1, HDMI_RX_AUDIO_LEN_REG, &c);
+	sp_tx_audioinfoframe.length = c;
+	for (i = 0; i < 11; i++) {
+		sp_read_reg(RX_P1, (HDMI_RX_AUDIO_DATA00_REG + i), &c);
+		sp_tx_audioinfoframe.pb_byte[i] = c;
+	}
+
+}
+
+static void sp_tx_enable_audio_output(u8 benable)
+{
+	u8 c;
+
+	sp_read_reg(TX_P0, SP_TX_AUD_CTRL, &c);
+	if (benable) {
+		if (c & AUD_EN) {
+			c &= ~AUD_EN;
+			sp_write_reg(TX_P0, SP_TX_AUD_CTRL, c);
+		}
+		sp_tx_audioinfoframe_setup();
+		sp_tx_config_packets(AUDIF_PACKETS);
+
+		c |= AUD_EN;
+		sp_write_reg(TX_P0, SP_TX_AUD_CTRL, c);
+
+	} else {
+		c &= ~AUD_EN;
+		sp_write_reg(TX_P0, SP_TX_AUD_CTRL, c);
+		sp_write_reg_and(TX_P0, SP_TX_PKT_EN_REG, ~AUD_IF_EN);
+	}
+
+}
+
+static void sp_tx_config_audio(void)
+{
+	u8 c;
+	int i;
+	ulong M_AUD, LS_Clk = 0;
+	ulong AUD_Freq = 0;
+
+	pr_info("%s %s : **Config audio **\n", LOG_TAG, __func__);
+	slimport_block_power_ctrl(SP_TX_PWR_AUDIO, SP_POWER_ON);
+	sp_read_reg(RX_P0, 0xCA, &c);
+
+	switch (c & 0x0f) {
+	case 0x00:
+		AUD_Freq = 44.1;
+		break;
+	case 0x02:
+		AUD_Freq = 48;
+		break;
+	case 0x03:
+		AUD_Freq = 32;
+		break;
+	case 0x08:
+		AUD_Freq = 88.2;
+		break;
+	case 0x0a:
+		AUD_Freq = 96;
+		break;
+	case 0x0c:
+		AUD_Freq = 176.4;
+		break;
+	case 0x0e:
+		AUD_Freq = 192;
+		break;
+	default:
+		break;
+	}
+
+
+	switch (sp_tx_get_link_bw()) {
+	case LINK_1P62G:
+		LS_Clk = 162000;
+		break;
+	case LINK_2P7G:
+		LS_Clk = 270000;
+		break;
+	case LINK_5P4G:
+		LS_Clk = 540000;
+		break;
+	case LINK_6P75G:
+		LS_Clk = 675000;
+		break;
+	default:
+		break;
+	}
+
+	pr_info("%s %s : AUD_Freq = %ld , LS_CLK = %ld\n",
+			LOG_TAG, __func__, AUD_Freq, LS_Clk);
+
+	M_AUD = ((512 * AUD_Freq) / LS_Clk) * 32768;
+	M_AUD = M_AUD + 0x05;
+	sp_write_reg(TX_P1, SP_TX_AUD_INTERFACE_CTRL4, (M_AUD & 0xff));
+	M_AUD = M_AUD >> 8;
+	sp_write_reg(TX_P1, SP_TX_AUD_INTERFACE_CTRL5, (M_AUD & 0xff));
+	sp_write_reg(TX_P1, SP_TX_AUD_INTERFACE_CTRL6, 0x00);
+
+	sp_write_reg_and(TX_P1, SP_TX_AUD_INTERFACE_CTRL0,
+			~AUD_INTERFACE_DISABLE);
+
+	sp_write_reg_or(TX_P1, SP_TX_AUD_INTERFACE_CTRL2, M_AUD_ADJUST_ST);
+
+	sp_read_reg(RX_P0, HDMI_STATUS, &c);
+	if (c & HDMI_AUD_LAYOUT)
+		sp_write_reg_or(TX_P2, SP_TX_AUD_CH_NUM_REG5,
+				CH_NUM_8 | AUD_LAYOUT);
+	else
+		sp_write_reg_and(TX_P2, SP_TX_AUD_CH_NUM_REG5,
+				(~CH_NUM_8) & (~AUD_LAYOUT));
+
+	/* transfer audio chaneel status from HDMI Rx to Slinmport Tx */
+	for (i = 0; i < 5; i++) {
+		sp_read_reg(RX_P0, (HDMI_RX_AUD_IN_CH_STATUS1_REG + i), &c);
+		sp_write_reg(TX_P2, (SP_TX_AUD_CH_STATUS_REG1 + i), c);
+	}
+
+	/* enable audio */
+	sp_tx_enable_audio_output(1);
+}
+
+void slimport_config_audio_output(void)
+{
+	static u8 count;
+
+	switch (sp_tx_ao_state) {
+	default:
+	case AO_INIT:
+	case AO_CTS_RCV_INT:
+	case AO_AUDIO_RCV_INT:
+		if (!(sp_i2c_read_byte(RX_P0, HDMI_STATUS) & HDMI_MODE)) {
+			sp_tx_ao_state = AO_INIT;
+			goto_next_system_state();
+		}
+		break;
+	case AO_RCV_INT_FINISH:
+		if (count++ > 2)
+			sp_tx_ao_state = AO_OUTPUT;
+		else
+			sp_tx_ao_state = AO_INIT;
+		SP_BREAK(AO_INIT, sp_tx_ao_state);
+	/* fallthrough */
+	case AO_OUTPUT:
+		count = 0;
+		sp_tx_ao_state = AO_INIT;
+		hdmi_rx_mute_audio(0);
+		sp_tx_config_audio();
+		goto_next_system_state();
+		break;
+	}
+
+}
+/******************End Audio process********************/
+
+void slimport_initialization(void)
+{
+	/* Waitting Hot plug event! */
+	if (!(common_int_status.common_int[3] & PLUG))
+		return;
+
+	g_read_edid_flag = 0;
+
+	/* Power on all modules */
+	sp_write_reg(TX_P2, SP_POWERD_CTRL_REG, 0x00);
+	/* Driver Version */
+	sp_write_reg(TX_P1, FW_VER_REG, FW_VERSION);
+	hdmi_rx_initialization();
+	sp_tx_initialization();
+	msleep(200);
+	goto_next_system_state();
+}
+
+void hdcp_external_ctrl_flag_monitor(void)
+{
+	static u8 cur_flag;
+
+	if (external_block_en != cur_flag) {
+		cur_flag = external_block_en;
+		system_state_change_with_case(STATE_HDCP_AUTH);
+	}
+
+}
+
+void slimport_state_process(struct anx7814_data *data)
+{
+	switch (sp_tx_system_state) {
+	case STATE_WAITTING_CABLE_PLUG:
+		slimport_waitting_cable_plug_process(data);
+		SP_BREAK(STATE_WAITTING_CABLE_PLUG, sp_tx_system_state);
+	/* fallthrough */
+	case STATE_SP_INITIALIZED:
+		slimport_initialization();
+		SP_BREAK(STATE_SP_INITIALIZED, sp_tx_system_state);
+	/* fallthrough */
+	case STATE_SINK_CONNECTION:
+		slimport_sink_connection();
+		SP_BREAK(STATE_SINK_CONNECTION, sp_tx_system_state);
+	/* fallthrough */
+	case STATE_PARSE_EDID:
+		slimport_edid_process();
+		SP_BREAK(STATE_PARSE_EDID, sp_tx_system_state);
+	/* fallthrough */
+	case STATE_LINK_TRAINING:
+		slimport_link_training();
+		SP_BREAK(STATE_LINK_TRAINING, sp_tx_system_state);
+	/* fallthrough */
+	case STATE_VIDEO_OUTPUT:
+		slimport_config_video_output();
+		SP_BREAK(STATE_VIDEO_OUTPUT, sp_tx_system_state);
+	/* fallthrough */
+	case STATE_HDCP_AUTH:
+		slimport_hdcp_process();
+		SP_BREAK(STATE_HDCP_AUTH, sp_tx_system_state);
+	/* fallthrough */
+	case STATE_AUDIO_OUTPUT:
+		slimport_config_audio_output();
+		SP_BREAK(STATE_AUDIO_OUTPUT, sp_tx_system_state);
+	/* fallthrough */
+	case STATE_PLAY_BACK:
+		SP_BREAK(STATE_PLAY_BACK, sp_tx_system_state);
+	/* fallthrough */
+	default:
+		break;
+	}
+}
+
+/******************Start INT process********************/
+void sp_tx_int_rec(void)
+{
+	sp_read_reg(TX_P2, SP_COMMON_INT_STATUS1,
+		&common_int_status.common_int[0]);
+	sp_write_reg(TX_P2, SP_COMMON_INT_STATUS1,
+		common_int_status.common_int[0]);
+
+	sp_read_reg(TX_P2, SP_COMMON_INT_STATUS1 + 1,
+		&common_int_status.common_int[1]);
+	sp_write_reg(TX_P2, SP_COMMON_INT_STATUS1 + 1,
+		common_int_status.common_int[1]);
+
+	sp_read_reg(TX_P2, SP_COMMON_INT_STATUS1 + 2,
+		&common_int_status.common_int[2]);
+	sp_write_reg(TX_P2, SP_COMMON_INT_STATUS1 + 2,
+		common_int_status.common_int[2]);
+
+	sp_read_reg(TX_P2, SP_COMMON_INT_STATUS1 + 3,
+		&common_int_status.common_int[3]);
+	sp_write_reg(TX_P2, SP_COMMON_INT_STATUS1 + 3,
+		common_int_status.common_int[3]);
+
+	sp_read_reg(TX_P2, SP_COMMON_INT_STATUS1 + 6,
+		&common_int_status.common_int[4]);
+	sp_write_reg(TX_P2, SP_COMMON_INT_STATUS1 + 6,
+		common_int_status.common_int[4]);
+}
+
+void hdmi_rx_int_rec(void)
+{
+	 sp_read_reg(RX_P0, HDMI_RX_INT_STATUS1_REG,
+		&hdmi_rx_int_status.hdmi_rx_int[0]);
+	 sp_write_reg(RX_P0, HDMI_RX_INT_STATUS1_REG,
+		hdmi_rx_int_status.hdmi_rx_int[0]);
+	 sp_read_reg(RX_P0, HDMI_RX_INT_STATUS2_REG,
+		&hdmi_rx_int_status.hdmi_rx_int[1]);
+	 sp_write_reg(RX_P0, HDMI_RX_INT_STATUS2_REG,
+		hdmi_rx_int_status.hdmi_rx_int[1]);
+	 sp_read_reg(RX_P0, HDMI_RX_INT_STATUS3_REG,
+		&hdmi_rx_int_status.hdmi_rx_int[2]);
+	 sp_write_reg(RX_P0, HDMI_RX_INT_STATUS3_REG,
+		hdmi_rx_int_status.hdmi_rx_int[2]);
+	 sp_read_reg(RX_P0, HDMI_RX_INT_STATUS4_REG,
+		&hdmi_rx_int_status.hdmi_rx_int[3]);
+	 sp_write_reg(RX_P0, HDMI_RX_INT_STATUS4_REG,
+		hdmi_rx_int_status.hdmi_rx_int[3]);
+	 sp_read_reg(RX_P0, HDMI_RX_INT_STATUS5_REG,
+		&hdmi_rx_int_status.hdmi_rx_int[4]);
+	 sp_write_reg(RX_P0, HDMI_RX_INT_STATUS5_REG,
+		hdmi_rx_int_status.hdmi_rx_int[4]);
+	 sp_read_reg(RX_P0, HDMI_RX_INT_STATUS6_REG,
+		&hdmi_rx_int_status.hdmi_rx_int[5]);
+	 sp_write_reg(RX_P0, HDMI_RX_INT_STATUS6_REG,
+		hdmi_rx_int_status.hdmi_rx_int[5]);
+	 sp_read_reg(RX_P0, HDMI_RX_INT_STATUS7_REG,
+		&hdmi_rx_int_status.hdmi_rx_int[6]);
+	 sp_write_reg(RX_P0, HDMI_RX_INT_STATUS7_REG,
+		hdmi_rx_int_status.hdmi_rx_int[6]);
+}
+
+void slimport_int_rec(void)
+{
+	sp_tx_int_rec();
+	hdmi_rx_int_rec();
+}
+/******************End INT process********************/
+
+/******************Start task process********************/
+static void sp_tx_pll_changed_int_handler(void)
+{
+	if (sp_tx_system_state >= STATE_LINK_TRAINING) {
+		if (!sp_tx_get_pll_lock_status()) {
+			pr_info("%s %s : PLL:PLL not lock!\n",
+				LOG_TAG, __func__);
+			sp_tx_set_sys_state(STATE_LINK_TRAINING);
+		}
+	}
+}
+
+static void sp_tx_hdcp_link_chk_fail_handler(void)
+{
+	system_state_change_with_case(STATE_HDCP_AUTH);
+
+	pr_info("%s %s : hdcp_link_chk_fail:HDCP Sync lost!\n",
+		LOG_TAG, __func__);
+}
+
+void link_down_check(void)
+{
+	u8 data_buf[6];
+
+	pr_info("%s %s : link_down_check\n", LOG_TAG, __func__);
+	sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x00, 6, data_buf);
+	if (sp_tx_system_state > STATE_LINK_TRAINING) {
+		if (!(data_buf[4] & 0x01)
+		|| ((data_buf[2] & (0x01 | 0x04)) != 0x05)) {
+			sp_tx_set_sys_state(STATE_LINK_TRAINING);
+			pr_info("%s %s : INT:re-LT request!\n",
+				LOG_TAG, __func__);
+		} else {
+			pr_info("%s %s : Lane align %x\n",
+				LOG_TAG, __func__, (uint)data_buf[4]);
+			pr_info("%s %s : Lane clock recovery %x\n",
+				LOG_TAG, __func__, (uint)data_buf[2]);
+		}
+	}
+}
+
+static void sp_tx_phy_auto_test(void)
+{
+	u8 b_sw;
+	u8 c1;
+	u8 bytebuf[16];
+	u8 link_bw;
+
+	/* DPCD 0x219 TEST_LINK_RATE */
+	sp_tx_aux_dpcdread_bytes(0x0, 0x02, 0x19, 1, bytebuf);
+	pr_info("%s %s : DPCD:0x00219 = %.2x\n",
+			LOG_TAG, __func__, (uint)bytebuf[0]);
+	switch (bytebuf[0]) {
+	case 0x06:
+	case 0x0A:
+	case 0x14:
+	case 0x19:
+		sp_tx_set_link_bw(bytebuf[0]);
+		sp_tx_test_bw = bytebuf[0];
+		break;
+	default:
+		sp_tx_set_link_bw(0x19);
+		sp_tx_test_bw = 0x19;
+		break;
+	}
+
+
+	/* DPCD 0x248 PHY_TEST_PATTERN */
+	sp_tx_aux_dpcdread_bytes(0x0, 0x02, 0x48, 1, bytebuf);
+	pr_info("%s %s : DPCD:0x00248 = %.2x\n",
+			LOG_TAG, __func__, (uint)bytebuf[0]);
+	switch (bytebuf[0]) {
+	case 0:
+		break;
+	case 1:
+		sp_write_reg(TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x04);
+		break;
+	case 2:
+		sp_write_reg(TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x08);
+		break;
+	case 3:
+		sp_write_reg(TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x0c);
+		break;
+	case 4:
+		sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x50, 0xa, bytebuf);
+		sp_write_reg(TX_P1, 0x80, bytebuf[0]);
+		sp_write_reg(TX_P1, 0x81, bytebuf[1]);
+		sp_write_reg(TX_P1, 0x82, bytebuf[2]);
+		sp_write_reg(TX_P1, 0x83, bytebuf[3]);
+		sp_write_reg(TX_P1, 0x84, bytebuf[4]);
+		sp_write_reg(TX_P1, 0x85, bytebuf[5]);
+		sp_write_reg(TX_P1, 0x86, bytebuf[6]);
+		sp_write_reg(TX_P1, 0x87, bytebuf[7]);
+		sp_write_reg(TX_P1, 0x88, bytebuf[8]);
+		sp_write_reg(TX_P1, 0x89, bytebuf[9]);
+		sp_write_reg(TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x30);
+		break;
+	case 5:
+		sp_write_reg(TX_P0, 0xA9, 0x00);
+		sp_write_reg(TX_P0, 0xAA, 0x01);
+		sp_write_reg(TX_P0, SP_TX_TRAINING_PTN_SET_REG, 0x14);
+		break;
+	}
+
+	sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0x03, 1, bytebuf);
+	pr_info("%s %s : DPCD:0x00003 = %.2x\n",
+			LOG_TAG, __func__, (uint)bytebuf[0]);
+	switch (bytebuf[0] & 0x01) {
+	case 0:
+		sp_tx_spread_enable(0);
+		break;
+	case 1:
+		sp_read_reg(TX_P0, SP_TX_LINK_BW_SET_REG, &c1);
+		switch (c1) {
+		case 0x06:
+			link_bw = 0x06;
+			break;
+		case 0x0a:
+			link_bw = 0x0a;
+			break;
+		case 0x14:
+			link_bw = 0x14;
+			break;
+		case 0x19:
+			link_bw = 0x19;
+			break;
+		default:
+			link_bw = 0x00;
+			break;
+		}
+		sp_tx_config_ssc(SSC_DEP_4000PPM);
+		break;
+	}
+
+	/* get swing and emphasis adjust request */
+	sp_read_reg(TX_P0, 0xA3, &b_sw);
+
+	sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x06, 1, bytebuf);
+	pr_info("%s %s : DPCD:0x00206 = %.2x\n",
+			LOG_TAG, __func__, (uint)bytebuf[0]);
+	c1 = bytebuf[0] & 0x0f;
+	switch (c1) {
+	case 0x00:
+		sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x00);
+		break;
+	case 0x01:
+		sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x01);
+		break;
+	case 0x02:
+		sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x02);
+		break;
+	case 0x03:
+		sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x03);
+		break;
+	case 0x04:
+		sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x08);
+		break;
+	case 0x05:
+		sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x09);
+		break;
+	case 0x06:
+		sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x0a);
+		break;
+	case 0x08:
+		sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x10);
+		break;
+	case 0x09:
+		sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x11);
+		break;
+	case 0x0c:
+		sp_write_reg(TX_P0, 0xA3, (b_sw & ~0x1b) | 0x18);
+		break;
+	default:
+		break;
+	}
+}
+
+static void hpd_irq_process(void)
+{
+	u8 c, c1;
+	u8 test_vector;
+	u8 data_buf[6];
+
+	sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x00, 6, data_buf);
+	pr_info("+++++++++++++Get HPD IRQ %x\n", (int)data_buf[1]);
+
+	if (data_buf[1] != 0)
+		sp_tx_aux_dpcdwrite_bytes(0x00, 0x02, DPCD_SERVICE_IRQ_VECTOR,
+					1, &(data_buf[1]));
+
+	/* HDCP IRQ */
+	if (data_buf[1] & CP_IRQ) {
+		if (hcdp_state > HDCP_WAITTING_FINISH
+			|| sp_tx_system_state > STATE_HDCP_AUTH) {
+			sp_tx_aux_dpcdread_bytes(0x06, 0x80, 0x29, 1, &c1);
+			if (c1 & 0x04) {
+				system_state_change_with_case(STATE_HDCP_AUTH);
+				pr_info("%s %s : IRQ:_______HDCP Sync lost!\n",
+					LOG_TAG, __func__);
+			}
+		}
+	}
+
+	/* AUTOMATED TEST IRQ */
+	if (data_buf[1] & TEST_IRQ) {
+		sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x18, 1, &test_vector);
+
+		if (test_vector & 0x01) {
+			sp_tx_test_lt = 1;
+
+			sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x19, 1, &c);
+			switch (c) {
+			case 0x06:
+			case 0x0A:
+			case 0x14:
+			case 0x19:
+				sp_tx_set_link_bw(c);
+				sp_tx_test_bw = c;
+				break;
+			default:
+				sp_tx_set_link_bw(0x19);
+				sp_tx_test_bw = 0x19;
+				break;
+			}
+
+			pr_info("%s %s :  test_bw = %.2x\n",
+					LOG_TAG, __func__, (uint)sp_tx_test_bw);
+
+			sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x60, 1, &c);
+			c = c | TEST_ACK;
+			sp_tx_aux_dpcdwrite_bytes(0x00, 0x02, 0x60, 1, &c);
+
+			pr_info("%s %s : Set TEST_ACK!\n", LOG_TAG, __func__);
+			if (sp_tx_system_state >= STATE_LINK_TRAINING) {
+				sp_tx_lt_state = LT_INIT;
+				sp_tx_set_sys_state(STATE_LINK_TRAINING);
+			}
+			pr_info("%s %s : IRQ:test-LT request!\n",
+					LOG_TAG, __func__);
+		}
+
+		if (test_vector & 0x02) {
+			sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x60, 1, &c);
+			c = c | TEST_ACK;
+			sp_tx_aux_dpcdwrite_bytes(0x00, 0x02, 0x60, 1, &c);
+		}
+		if (test_vector & 0x04) {
+			if (sp_tx_system_state > STATE_PARSE_EDID)
+				sp_tx_set_sys_state(STATE_PARSE_EDID);
+			sp_tx_test_edid = 1;
+			pr_info("%s %s : Test EDID Requested!\n",
+					LOG_TAG, __func__);
+		}
+
+		if (test_vector & 0x08) {
+			sp_tx_test_lt = 1;
+
+			sp_tx_phy_auto_test();
+
+			sp_tx_aux_dpcdread_bytes(0x00, 0x02, 0x60, 1, &c);
+			c = c | 0x01;
+			sp_tx_aux_dpcdwrite_bytes(0x00, 0x02, 0x60, 1, &c);
+		}
+	}
+
+	if (sp_tx_system_state > STATE_LINK_TRAINING) {
+		if (!(data_buf[4] & 0x01)
+		|| ((data_buf[2] & (0x01 | 0x04)) != 0x05)) {
+			sp_tx_set_sys_state(STATE_LINK_TRAINING);
+			pr_info("%s %s : INT:re-LT request!\n",
+				LOG_TAG, __func__);
+			return;
+		}
+
+		pr_info("%s %s : Lane align %x\n",
+			LOG_TAG, __func__, (uint)data_buf[4]);
+		pr_info("%s %s : Lane clock recovery %x\n",
+			LOG_TAG, __func__, (uint)data_buf[2]);
+	}
+}
+
+static void sp_tx_vsi_setup(void)
+{
+	u8 c;
+	int i;
+
+	for (i = 0; i < 10; i++) {
+		sp_read_reg(RX_P1, (HDMI_RX_MPEG_DATA00_REG + i), &c);
+		sp_tx_packet_mpeg.mpeg_data[i] = c;
+	}
+}
+
+static void sp_tx_mpeg_setup(void)
+{
+	u8 c;
+	int i;
+
+	for (i = 0; i < 10; i++) {
+		sp_read_reg(RX_P1, (HDMI_RX_MPEG_DATA00_REG + i), &c);
+		sp_tx_packet_mpeg.mpeg_data[i] = c;
+	}
+}
+
+static void sp_tx_auth_done_int_handler(void)
+{
+	u8 bytebuf[2];
+
+	if (hcdp_state > HDCP_HW_ENABLE
+		&& sp_tx_system_state == STATE_HDCP_AUTH) {
+		sp_read_reg(TX_P0, SP_TX_HDCP_STATUS, bytebuf);
+		if (bytebuf[0] & SP_TX_HDCP_AUTH_PASS) {
+			sp_tx_aux_dpcdread_bytes(0x06, 0x80, 0x2A, 2, bytebuf);
+			if ((bytebuf[1] & 0x08) || (bytebuf[0] & 0x80)) {
+				pr_info("%s %s : max cascade/devs exceeded!\n",
+						LOG_TAG, __func__);
+				sp_tx_hdcp_encryption_disable();
+			} else
+				pr_info("%s %s : %s\n",	LOG_TAG, __func__,
+					"Authentication pass in Auth_Done");
+
+			hcdp_state = HDCP_FINISH;
+		} else {
+			pr_err("%s %s : Authentication failed in AUTH_done\n",
+					LOG_TAG, __func__);
+			sp_tx_video_mute(1);
+			sp_tx_clean_hdcp_status();
+			hcdp_state = HDCP_FAILE;
+		}
+	}
+
+	pr_info("%s %s : sp_tx_auth_done_int_handler\n", LOG_TAG, __func__);
+
+}
+
+static void sp_tx_lt_done_int_handler(void)
+{
+	u8 c;
+
+	if (sp_tx_lt_state == LT_WAITTING_FINISH
+		&& sp_tx_system_state == STATE_LINK_TRAINING) {
+		sp_read_reg(TX_P0, LT_CTRL, &c);
+		if (c & 0x70) {
+			c = (c & 0x70) >> 4;
+			pr_info("%s %s : LT failed in interrupt, ERR = %.2x\n",
+				LOG_TAG, __func__, (uint) c);
+			sp_tx_lt_state = LT_ERROR;
+		} else {
+			pr_info("%s %s : lt_done: LT Finish\n",
+					LOG_TAG, __func__);
+			sp_tx_lt_state = LT_FINISH;
+		}
+	}
+
+}
+
+static void hdmi_rx_clk_det_int(void)
+{
+	pr_info("%s %s : *HDMI_RX Interrupt: Pixel Clock Change.\n",
+			LOG_TAG, __func__);
+	if (sp_tx_system_state > STATE_VIDEO_OUTPUT) {
+		sp_tx_video_mute(1);
+		sp_tx_enable_audio_output(0);
+		sp_tx_set_sys_state(STATE_VIDEO_OUTPUT);
+	}
+}
+
+static void hdmi_rx_sync_det_int(void)
+{
+	pr_info("%s %s : *HDMI_RX Interrupt: Sync Detect.\n",
+			LOG_TAG, __func__);
+}
+
+static void hdmi_rx_hdmi_dvi_int(void)
+{
+	u8 c;
+
+	pr_info("%s %s : hdmi_rx_hdmi_dvi_int.\n", LOG_TAG, __func__);
+	sp_read_reg(RX_P0, HDMI_STATUS, &c);
+	g_hdmi_dvi_status = read_dvi_hdmi_mode();
+	if ((c & _BIT0) != (g_hdmi_dvi_status & _BIT0)) {
+		pr_info("%s %s : hdmi_dvi_int: Is HDMI MODE: %x.\n",
+				LOG_TAG, __func__, (uint)(c & HDMI_MODE));
+		g_hdmi_dvi_status = (c & _BIT0);
+		hdmi_rx_mute_audio(1);
+		system_state_change_with_case(STATE_LINK_TRAINING);
+	}
+}
+
+static void hdmi_rx_new_avi_int(void)
+{
+	pr_info("%s %s : *HDMI_RX Interrupt: New AVI Packet.\n",
+			LOG_TAG, __func__);
+	sp_tx_lvttl_bit_mapping();
+	sp_tx_set_colorspace();
+	sp_tx_avi_setup();
+	sp_tx_config_packets(AVI_PACKETS);
+}
+
+static void hdmi_rx_new_vsi_int(void)
+{
+	u8 hdmi_video_format, v3d_structure;
+
+	pr_info("%s %s : *HDMI_RX Interrupt: NEW VSI packet.\n",
+			LOG_TAG, __func__);
+
+	sp_write_reg_and(TX_P0, SP_TX_3D_VSC_CTRL, ~INFO_FRAME_VSC_EN);
+	/* VSI package header */
+	if ((sp_i2c_read_byte(RX_P1, HDMI_RX_MPEG_TYPE_REG) != 0x81)
+		|| (sp_i2c_read_byte(RX_P1, HDMI_RX_MPEG_VER_REG) != 0x01))
+		return;
+	pr_info("%s %s : Setup VSI package!\n", LOG_TAG, __func__);
+
+	sp_tx_vsi_setup();
+	sp_tx_config_packets(VSI_PACKETS);
+
+	sp_read_reg(RX_P1, HDMI_RX_MPEG_DATA03_REG, &hdmi_video_format);
+	if ((hdmi_video_format & 0xe0) == 0x40) {
+		pr_info("%s %s : 3D VSI packet detected. Config VSC packet\n",
+			LOG_TAG, __func__);
+		sp_read_reg(RX_P1, HDMI_RX_MPEG_DATA05_REG, &v3d_structure);
+		switch (v3d_structure&0xf0) {
+		case 0x00:
+			v3d_structure = 0x02;
+			break;
+		case 0x20:
+			v3d_structure = 0x03;
+			break;
+		case 0x30:
+			v3d_structure = 0x04;
+			break;
+		default:
+			v3d_structure = 0x00;
+			pr_info("%s %s : 3D structure is not supported\n",
+					LOG_TAG, __func__);
+			break;
+		}
+		sp_write_reg(TX_P0, SP_TX_VSC_DB1, v3d_structure);
+	}
+	sp_write_reg_or(TX_P0, SP_TX_3D_VSC_CTRL, INFO_FRAME_VSC_EN);
+	sp_write_reg_and(TX_P0, SP_TX_PKT_EN_REG, ~SPD_IF_EN);
+	sp_write_reg_or(TX_P0, SP_TX_PKT_EN_REG, SPD_IF_UD);
+	sp_write_reg_or(TX_P0, SP_TX_PKT_EN_REG, SPD_IF_EN);
+}
+
+static void hdmi_rx_no_vsi_int(void)
+{
+
+	u8 c;
+
+	sp_read_reg(TX_P0, SP_TX_3D_VSC_CTRL, &c);
+	if (c & INFO_FRAME_VSC_EN) {
+		pr_info("%s %s : No new VSI is received, disable  VSC packet\n",
+				LOG_TAG, __func__);
+		c &= ~INFO_FRAME_VSC_EN;
+		sp_write_reg(TX_P0, SP_TX_3D_VSC_CTRL, c);
+		sp_tx_mpeg_setup();
+		sp_tx_config_packets(MPEG_PACKETS);
+	}
+
+}
+
+static void hdmi_rx_restart_audio_chk(void)
+{
+	pr_info("%s %s : WAIT_AUDIO: hdmi_rx_restart_audio_chk.\n",
+			LOG_TAG, __func__);
+	system_state_change_with_case(STATE_AUDIO_OUTPUT);
+}
+
+static void hdmi_rx_cts_rcv_int(void)
+{
+	if (sp_tx_ao_state == AO_INIT)
+		sp_tx_ao_state = AO_CTS_RCV_INT;
+	else if (sp_tx_ao_state == AO_AUDIO_RCV_INT)
+		sp_tx_ao_state = AO_RCV_INT_FINISH;
+}
+
+static void hdmi_rx_audio_rcv_int(void)
+{
+	if (sp_tx_ao_state == AO_INIT)
+		sp_tx_ao_state = AO_AUDIO_RCV_INT;
+	else if (sp_tx_ao_state == AO_CTS_RCV_INT)
+		sp_tx_ao_state = AO_RCV_INT_FINISH;
+}
+
+static void hdmi_rx_audio_samplechg_int(void)
+{
+	uint i;
+	u8 c;
+	/* transfer audio chaneel status from HDMI Rx to Slinmport Tx */
+	for (i = 0; i < 5; i++) {
+		sp_read_reg(RX_P0, (HDMI_RX_AUD_IN_CH_STATUS1_REG + i), &c);
+		sp_write_reg(TX_P2, (SP_TX_AUD_CH_STATUS_REG1 + i), c);
+	}
+}
+
+static void hdmi_rx_hdcp_error_int(void)
+{
+	static u8 count;
+
+	pr_info("%s %s : *HDMI_RX Interrupt: hdcp error.\n", LOG_TAG, __func__);
+	if (count >= 40) {
+		count = 0;
+		pr_info("%s %s : Lots of hdcp error occurred ...\n",
+				LOG_TAG, __func__);
+		hdmi_rx_mute_audio(1);
+		hdmi_rx_mute_video(1);
+		hdmi_rx_set_hpd(0);
+		usleep_range(10000, 11000);
+		hdmi_rx_set_hpd(1);
+	} else
+		count++;
+}
+
+static void hdmi_rx_new_gcp_int(void)
+{
+	u8 c;
+
+	sp_read_reg(RX_P1, HDMI_RX_GENERAL_CTRL, &c);
+	if (c&SET_AVMUTE) {
+			hdmi_rx_mute_video(1);
+			hdmi_rx_mute_audio(1);
+
+	} else if (c&CLEAR_AVMUTE) {
+			hdmi_rx_mute_video(0);
+			hdmi_rx_mute_audio(0);
+	}
+}
+
+static void sp_tx_hpd_int_handler(u8 hpd_source)
+{
+	pr_info("%s %s : sp_tx_hpd_int_handler\n", LOG_TAG, __func__);
+
+	switch (hpd_source) {
+	case HPD_LOST:
+		hdmi_rx_set_hpd(0);
+		sp_tx_set_sys_state(STATE_WAITTING_CABLE_PLUG);
+		break;
+	case HPD_CHANGE:
+		pr_info("HPD:____________HPD changed!\n");
+		usleep_range(2000, 4000);
+		if (common_int_status.common_int[3] & HPD_IRQ)
+			hpd_irq_process();
+
+		if (sp_i2c_read_byte(TX_P0, SP_TX_SYS_CTRL3_REG) & HPD_STATUS) {
+			if (common_int_status.common_int[3] & HPD_IRQ)
+				hpd_irq_process();
+		} else {
+			if (sp_i2c_read_byte(TX_P0, SP_TX_SYS_CTRL3_REG)
+				& HPD_STATUS) {
+				hdmi_rx_set_hpd(0);
+				sp_tx_set_sys_state(STATE_WAITTING_CABLE_PLUG);
+			}
+		}
+		break;
+	case PLUG:
+		pr_info("HPD:____________HPD changed!\n");
+		if (sp_tx_system_state < STATE_SP_INITIALIZED)
+			sp_tx_set_sys_state(STATE_SP_INITIALIZED);
+		break;
+	default:
+		break;
+	}
+}
+
+void system_isr_handler(void)
+{
+	if (common_int_status.common_int[3] & HPD_CHANGE)
+		sp_tx_hpd_int_handler(HPD_CHANGE);
+	if (common_int_status.common_int[3] & HPD_LOST)
+		sp_tx_hpd_int_handler(HPD_LOST);
+	if (common_int_status.common_int[3] & HPD_IRQ)
+		pr_info("++++++++++++++++========HDCP_IRQ interrupt\n");
+	if (common_int_status.common_int[0] & PLL_LOCK_CHG)
+		sp_tx_pll_changed_int_handler();
+
+	if (common_int_status.common_int[1] & HDCP_AUTH_DONE)
+		sp_tx_auth_done_int_handler();
+
+	if (common_int_status.common_int[2] & HDCP_LINK_CHECK_FAIL)
+		sp_tx_hdcp_link_chk_fail_handler();
+
+	if (common_int_status.common_int[4] & TRAINING_Finish)
+		sp_tx_lt_done_int_handler();
+
+	if (sp_tx_system_state > STATE_SINK_CONNECTION) {
+		if (hdmi_rx_int_status.hdmi_rx_int[5] & NEW_AVI)
+			hdmi_rx_new_avi_int();
+	}
+
+	if (sp_tx_system_state > STATE_VIDEO_OUTPUT) {
+		if (hdmi_rx_int_status.hdmi_rx_int[6] & NEW_VS) {
+			hdmi_rx_int_status.hdmi_rx_int[6] &= ~NO_VSI;
+			hdmi_rx_new_vsi_int();
+		}
+		if (hdmi_rx_int_status.hdmi_rx_int[6] & NO_VSI)
+			hdmi_rx_no_vsi_int();
+	}
+
+	if (sp_tx_system_state >= STATE_VIDEO_OUTPUT) {
+		if (hdmi_rx_int_status.hdmi_rx_int[0] & CKDT_CHANGE)
+			hdmi_rx_clk_det_int();
+
+		if (hdmi_rx_int_status.hdmi_rx_int[0] & SCDT_CHANGE)
+			hdmi_rx_sync_det_int();
+
+		if (hdmi_rx_int_status.hdmi_rx_int[0] & HDMI_DVI)
+			hdmi_rx_hdmi_dvi_int();
+
+		if ((hdmi_rx_int_status.hdmi_rx_int[5] & NEW_AUD)
+		     || (hdmi_rx_int_status.hdmi_rx_int[2] & AUD_MODE_CHANGE))
+			hdmi_rx_restart_audio_chk();
+
+
+		if (hdmi_rx_int_status.hdmi_rx_int[5] & CTS_RCV)
+			hdmi_rx_cts_rcv_int();
+
+		if (hdmi_rx_int_status.hdmi_rx_int[4] & AUDIO_RCV)
+			hdmi_rx_audio_rcv_int();
+
+
+		if (hdmi_rx_int_status.hdmi_rx_int[1] & HDCP_ERR)
+			hdmi_rx_hdcp_error_int();
+
+		if (hdmi_rx_int_status.hdmi_rx_int[5] & NEW_CP)
+			hdmi_rx_new_gcp_int();
+
+		if (hdmi_rx_int_status.hdmi_rx_int[1] & AUDIO_SAMPLE_CHANGE)
+			hdmi_rx_audio_samplechg_int();
+	}
+
+}
+
+void sp_tx_show_information(void)
+{
+	u8 c, c1;
+	uint h_res, h_act, v_res, v_act;
+	uint h_fp, h_sw, h_bp, v_fp, v_sw, v_bp;
+	ulong fresh_rate;
+	ulong pclk;
+
+	pr_info("\n******************SP Video Information*******************\n");
+
+	sp_read_reg(TX_P0, SP_TX_LINK_BW_SET_REG, &c);
+	switch (c) {
+	case 0x06:
+		pr_info("%s %s : BW = 1.62G\n", LOG_TAG, __func__);
+		break;
+	case 0x0a:
+		pr_info("%s %s : BW = 2.7G\n", LOG_TAG, __func__);
+		break;
+	case 0x14:
+		pr_info("%s %s : BW = 5.4G\n", LOG_TAG, __func__);
+		break;
+	case 0x19:
+		pr_info("%s %s : BW = 6.75G\n", LOG_TAG, __func__);
+		break;
+	default:
+		break;
+	}
+
+	pclk = sp_tx_pclk_calc();
+	pclk = pclk / 10;
+
+	sp_read_reg(TX_P2, SP_TX_TOTAL_LINE_STA_L, &c);
+	sp_read_reg(TX_P2, SP_TX_TOTAL_LINE_STA_H, &c1);
+
+	v_res = c1;
+	v_res = v_res << 8;
+	v_res = v_res + c;
+
+
+	sp_read_reg(TX_P2, SP_TX_ACT_LINE_STA_L, &c);
+	sp_read_reg(TX_P2, SP_TX_ACT_LINE_STA_H, &c1);
+
+	v_act = c1;
+	v_act = v_act << 8;
+	v_act = v_act + c;
+
+
+	sp_read_reg(TX_P2, SP_TX_TOTAL_PIXEL_STA_L, &c);
+	sp_read_reg(TX_P2, SP_TX_TOTAL_PIXEL_STA_H, &c1);
+
+	h_res = c1;
+	h_res = h_res << 8;
+	h_res = h_res + c;
+
+
+	sp_read_reg(TX_P2, SP_TX_ACT_PIXEL_STA_L, &c);
+	sp_read_reg(TX_P2, SP_TX_ACT_PIXEL_STA_H, &c1);
+
+	h_act = c1;
+	h_act = h_act << 8;
+	h_act = h_act + c;
+
+	sp_read_reg(TX_P2, SP_TX_H_F_PORCH_STA_L, &c);
+	sp_read_reg(TX_P2, SP_TX_H_F_PORCH_STA_H, &c1);
+
+	h_fp = c1;
+	h_fp = h_fp << 8;
+	h_fp = h_fp + c;
+
+	sp_read_reg(TX_P2, SP_TX_H_SYNC_STA_L, &c);
+	sp_read_reg(TX_P2, SP_TX_H_SYNC_STA_H, &c1);
+
+	h_sw = c1;
+	h_sw = h_sw << 8;
+	h_sw = h_sw + c;
+
+	sp_read_reg(TX_P2, SP_TX_H_B_PORCH_STA_L, &c);
+	sp_read_reg(TX_P2, SP_TX_H_B_PORCH_STA_H, &c1);
+
+	h_bp = c1;
+	h_bp = h_bp << 8;
+	h_bp = h_bp + c;
+
+	sp_read_reg(TX_P2, SP_TX_V_F_PORCH_STA, &c);
+	v_fp = c;
+
+	sp_read_reg(TX_P2, SP_TX_V_SYNC_STA, &c);
+	v_sw = c;
+
+	sp_read_reg(TX_P2, SP_TX_V_B_PORCH_STA, &c);
+	v_bp = c;
+
+	pr_info("%s %s : Total resolution is %d * %d\n",
+			LOG_TAG, __func__, h_res, v_res);
+
+	pr_info("%s %s : HF=%d, HSW=%d, HBP=%d\n",
+			LOG_TAG, __func__, h_fp, h_sw, h_bp);
+	pr_info("%s %s : VF=%d, VSW=%d, VBP=%d\n",
+			LOG_TAG, __func__, v_fp, v_sw, v_bp);
+	pr_info("%s %s : Active resolution is %d * %d",
+			LOG_TAG, __func__, h_act, v_act);
+
+	if (h_res == 0 || v_res == 0)
+		fresh_rate = 0;
+	else {
+		fresh_rate = pclk * 1000;
+		fresh_rate = fresh_rate / h_res;
+		fresh_rate = fresh_rate * 1000;
+		fresh_rate = fresh_rate / v_res;
+	}
+	pr_info("   @ %ldHz\n", fresh_rate);
+
+	sp_read_reg(TX_P0, SP_TX_VID_CTRL, &c);
+
+	if ((c & 0x06) == 0x00)
+		pr_info("%s %s : ColorSpace: RGB,", LOG_TAG, __func__);
+	else if ((c & 0x06) == 0x02)
+		pr_info("%s %s : ColorSpace: YCbCr422,", LOG_TAG, __func__);
+	else if ((c & 0x06) == 0x04)
+		pr_info("%s %s : ColorSpace: YCbCr444,", LOG_TAG, __func__);
+
+	sp_read_reg(TX_P0, SP_TX_VID_CTRL, &c);
+
+	if ((c & 0xe0) == 0x00)
+		pr_info("6 BPC\n");
+	else if ((c & 0xe0) == 0x20)
+		pr_info("8 BPC\n");
+	else if ((c & 0xe0) == 0x40)
+		pr_info("10 BPC\n");
+	else if ((c & 0xe0) == 0x60)
+		pr_info("12 BPC\n");
+
+
+	if (is_anx_dongle()) {
+		sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x23, 1, &c);
+		pr_info("%s %s : Analogix Dongle FW Ver %.2x\n",
+				LOG_TAG, __func__, (uint)(c & 0x7f));
+	}
+
+	pr_info("\n**************************************************\n");
+
+}
+
+void hdmi_rx_show_video_info(void)
+{
+	u8 c, c1;
+	u8 cl, ch;
+	uint n;
+	uint h_res, v_res;
+
+	sp_read_reg(RX_P0, HDMI_RX_HACT_LOW, &cl);
+	sp_read_reg(RX_P0, HDMI_RX_HACT_HIGH, &ch);
+	n = ch;
+	n = (n << 8) + cl;
+	h_res = n;
+
+	sp_read_reg(RX_P0, HDMI_RX_VACT_LOW, &cl);
+	sp_read_reg(RX_P0, HDMI_RX_VACT_HIGH, &ch);
+	n = ch;
+	n = (n << 8) + cl;
+	v_res = n;
+
+	pr_info("%s %s : >HDMI_RX Info<\n", LOG_TAG, __func__);
+	sp_read_reg(RX_P0, HDMI_STATUS, &c);
+	if (c & HDMI_MODE)
+		pr_info("%s %s : HDMI_RX Mode = HDMI Mode.\n",
+				LOG_TAG, __func__);
+	else
+		pr_info("%s %s : HDMI_RX Mode = DVI Mode.\n",
+				LOG_TAG, __func__);
+
+	sp_read_reg(RX_P0, HDMI_RX_VIDEO_STATUS_REG1, &c);
+	if (c & VIDEO_TYPE)
+		v_res += v_res;
+	pr_info("%s %s : HDMI_RX Video Resolution = %d * %d ",
+			LOG_TAG, __func__, h_res, v_res);
+	sp_read_reg(RX_P0, HDMI_RX_VIDEO_STATUS_REG1, &c);
+	if (c & VIDEO_TYPE)
+		pr_info("Interlace Video.\n");
+	else
+		pr_info("Progressive Video.\n");
+
+	sp_read_reg(RX_P0, HDMI_RX_SYS_CTRL1_REG, &c);
+	if ((c & 0x30) == 0x00)
+		pr_info("%s %s : Input Pixel Clock = Not Repeated.\n",
+				LOG_TAG, __func__);
+	else if ((c & 0x30) == 0x10)
+		pr_info("%s %s : Input pclk = 2x Video Clock. Repeated.\n",
+			LOG_TAG, __func__);
+	else if ((c & 0x30) == 0x30)
+		pr_info("%s %s : Input pclk = 4x Vvideo Clock. Repeated.\n",
+			LOG_TAG, __func__);
+
+	if ((c & 0xc0) == 0x00)
+		pr_info("%s %s : Output Video Clock = Not Divided.\n",
+				LOG_TAG, __func__);
+	else if ((c & 0xc0) == 0x40)
+		pr_info("%s %s : Output Video Clock = Divided By 2.\n",
+				LOG_TAG, __func__);
+	else if ((c & 0xc0) == 0xc0)
+		pr_info("%s %s : Output Video Clock = Divided By 4.\n",
+				LOG_TAG, __func__);
+
+	if (c & 0x02)
+		pr_info("%s %s : %s\n", LOG_TAG, __func__,
+			"Output Video Using Rising Edge To Latch Data.\n");
+	else
+		pr_info("%s %s : %s\n", LOG_TAG, __func__,
+			"Output Video Using Falling Edge To Latch Data.\n");
+
+
+	pr_info("Input Video Color Depth = ");
+	sp_read_reg(RX_P0, 0x70, &c1);
+	c1 &= 0xf0;
+	if (c1 == 0x00)
+		pr_info("%s %s : Legacy Mode.\n", LOG_TAG, __func__);
+	else if (c1 == 0x40)
+		pr_info("%s %s : 24 Bit Mode.\n", LOG_TAG, __func__);
+	else if (c1 == 0x50)
+		pr_info("%s %s : 30 Bit Mode.\n", LOG_TAG, __func__);
+	else if (c1 == 0x60)
+		pr_info("%s %s : 36 Bit Mode.\n", LOG_TAG, __func__);
+	else if (c1 == 0x70)
+		pr_info("%s %s : 48 Bit Mode.\n", LOG_TAG, __func__);
+
+	pr_info("%s %s : Input Video Color Space = ", LOG_TAG, __func__);
+	sp_read_reg(RX_P1, HDMI_RX_AVI_DATA00_REG, &c);
+	c &= 0x60;
+	if (c == 0x20)
+		pr_info("YCbCr4:2:2 .\n");
+	else if (c == 0x40)
+		pr_info("YCbCr4:4:4 .\n");
+	else if (c == 0x00)
+		pr_info("RGB.\n");
+	else
+		pr_err("Unknown 0x44 = 0x%.2x\n", (int)c);
+
+	sp_read_reg(RX_P1, HDMI_RX_HDCP_STATUS_REG, &c);
+	if (c & AUTH_EN)
+		pr_info("%s %s : Authentication is attempted.\n",
+				LOG_TAG, __func__);
+	else
+		pr_info("%s %s : Authentication is not attempted.\n",
+				LOG_TAG, __func__);
+
+	for (cl = 0; cl < 20; cl++) {
+		sp_read_reg(RX_P1, HDMI_RX_HDCP_STATUS_REG, &c);
+		if (c & DECRYPT_EN)
+			break;
+
+		usleep_range(10000, 11000);
+	}
+
+	if (cl < 20)
+		pr_info("%s %s : Decryption is active.\n", LOG_TAG, __func__);
+	else
+		pr_info("%s %s : Decryption is not active.\n",
+				LOG_TAG, __func__);
+}
+
+void clean_system_status(void)
+{
+	if (g_need_clean_status) {
+		pr_info("%s %s : clean_system_status. A -> B;\n",
+				LOG_TAG, __func__);
+		pr_info("A:");
+		print_sys_state(sp_tx_system_state_bak);
+		pr_info("B:");
+		print_sys_state(sp_tx_system_state);
+
+		g_need_clean_status = 0;
+		if (sp_tx_system_state_bak >= STATE_LINK_TRAINING) {
+			if (sp_tx_system_state >= STATE_AUDIO_OUTPUT)
+				hdmi_rx_mute_audio(1);
+			else {
+				hdmi_rx_mute_video(1);
+				sp_tx_video_mute(1);
+			}
+		}
+		if (sp_tx_system_state_bak >= STATE_HDCP_AUTH
+			&& sp_tx_system_state <= STATE_HDCP_AUTH) {
+			if (sp_i2c_read_byte(TX_P0, TX_HDCP_CTRL0) & 0xFC)
+				sp_tx_clean_hdcp_status();
+		}
+
+		if (hcdp_state != HDCP_CAPABLE_CHECK)
+			hcdp_state = HDCP_CAPABLE_CHECK;
+
+		if (sp_tx_sc_state != SC_INIT)
+			sp_tx_sc_state = SC_INIT;
+		if (sp_tx_lt_state != LT_INIT)
+			sp_tx_lt_state = LT_INIT;
+		if (sp_tx_vo_state != VO_WAIT_VIDEO_STABLE)
+			sp_tx_vo_state = VO_WAIT_VIDEO_STABLE;
+	}
+}
+
+/******************add for HDCP cap check********************/
+void sp_tx_get_ddc_hdcp_BCAP(u8 *bcap)
+{
+	u8 c;
+
+	sp_write_reg(TX_P0, AUX_ADDR_7_0, 0X3A);
+	sp_write_reg(TX_P0, AUX_ADDR_15_8, 0);
+	sp_read_reg(TX_P0, AUX_ADDR_19_16, &c);
+	c &= 0xf0;
+	sp_write_reg(TX_P0, AUX_ADDR_19_16, c);
+
+	sp_tx_aux_wr(0x00);
+	sp_tx_aux_rd(0x01);
+	sp_read_reg(TX_P0, BUF_DATA_0, &c);
+
+
+	sp_tx_aux_wr(0x40);
+	sp_tx_aux_rd(0x01);
+	sp_read_reg(TX_P0, BUF_DATA_0, bcap);
+
+}
+
+void sp_tx_get_ddc_hdcp_BKSV(u8 *bksv)
+{
+	u8 c;
+
+	sp_write_reg(TX_P0, AUX_ADDR_7_0, 0X3A);
+	sp_write_reg(TX_P0, AUX_ADDR_15_8, 0);
+	sp_read_reg(TX_P0, AUX_ADDR_19_16, &c);
+	c &= 0xf0;
+	sp_write_reg(TX_P0, AUX_ADDR_19_16, c);
+
+	sp_tx_aux_wr(0x00);
+	sp_tx_aux_rd(0x01);
+	sp_read_reg(TX_P0, BUF_DATA_0, &c);
+
+
+	sp_tx_aux_wr(0x00);
+	sp_tx_aux_rd(0x01);
+	sp_read_reg(TX_P0, BUF_DATA_0, bksv);
+
+}
+
+u8 slimport_hdcp_cap_check(void)
+{
+	u8 g_hdcp_cap = 0;
+	u8 temp;
+
+	if (AUX_OK == sp_tx_aux_dpcdread_bytes(0x06, 0x80, 0x28, 1, &temp))
+		g_hdcp_cap = (temp & 0x01) ? 1 : 0;
+	else
+		pr_info("HDCP CAPABLE: read AUX err!\n");
+
+	pr_info("%s %s :hdcp cap check: %s Supported\n",
+		LOG_TAG, __func__, g_hdcp_cap ? "" : "No");
+	return g_hdcp_cap;
+}
+/******************End HDCP cap check********************/
+
+void slimport_tasks_handler(void)
+{
+	system_isr_handler();
+	hdcp_external_ctrl_flag_monitor();
+	clean_system_status();
+	/*clear up backup system state*/
+	if (sp_tx_system_state_bak != sp_tx_system_state)
+		sp_tx_system_state_bak = sp_tx_system_state;
+}
+/******************End task  process********************/
+
+void slimport_main_process(struct anx7814_data *data)
+{
+	slimport_state_process(data);
+	if (sp_tx_system_state > STATE_WAITTING_CABLE_PLUG) {
+		slimport_int_rec();
+		slimport_tasks_handler();
+	}
+}
+
diff --git a/drivers/staging/slimport/slimport_tx_drv.h b/drivers/staging/slimport/slimport_tx_drv.h
new file mode 100644
index 0000000..9aaf47d
--- /dev/null
+++ b/drivers/staging/slimport/slimport_tx_drv.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _SP_TX_DRV_H
+#define _SP_TX_DRV_H
+
+#include "slimport.h"
+#include "slimport_tx_reg.h"
+
+#define FW_VERSION	0x22
+
+#define _BIT0		0x01
+#define _BIT1		0x02
+#define _BIT2		0x04
+#define _BIT3		0x08
+#define _BIT4		0x10
+#define _BIT5		0x20
+#define _BIT6		0x40
+#define _BIT7		0x80
+
+#define DVI_MODE	0x00
+#define HDMI_MODE	0x01
+
+#define SP_POWER_ON	1
+#define SP_POWER_DOWN	0
+
+#define MAX_BUF_CNT	16
+
+#define SP_BREAK(current_status, next_status) \
+	{ if (next_status != (current_status) + 1) break; }
+
+extern u8 edid_blocks[256];
+
+/* HDCP control enable/ disable from AP */
+/* external_block_en = 1: enable, 0: disable*/
+extern int external_block_en;
+
+enum rx_cbl_type {
+	DWN_STRM_IS_NULL,
+	DWN_STRM_IS_HDMI,
+	DWN_STRM_IS_DIGITAL,
+	DWN_STRM_IS_ANALOG,
+	DWN_STRM_NUM
+};
+
+enum sp_tx_state {
+	STATE_WAITTING_CABLE_PLUG,
+	STATE_SP_INITIALIZED,
+	STATE_SINK_CONNECTION,
+	STATE_PARSE_EDID,
+	STATE_LINK_TRAINING,
+	STATE_VIDEO_OUTPUT,
+	STATE_HDCP_AUTH,
+	STATE_AUDIO_OUTPUT,
+	STATE_PLAY_BACK
+};
+
+enum sp_tx_power_block {
+	SP_TX_PWR_REG = REGISTER_PD,
+	SP_TX_PWR_HDCP = HDCP_PD,
+	SP_TX_PWR_AUDIO = AUDIO_PD,
+	SP_TX_PWR_VIDEO = VIDEO_PD,
+	SP_TX_PWR_LINK = LINK_PD,
+	SP_TX_PWR_TOTAL = TOTAL_PD,
+	SP_TX_PWR_NUMS
+};
+
+enum hdmi_color_depth {
+	HDMI_LEGACY = 0x00,
+	HDMI_24BIT = 0x04,
+	HDMI_30BIT = 0x05,
+	HDMI_36BIT = 0x06,
+	HDMI_48BIT = 0x07,
+};
+
+enum sp_tx_send_msg {
+	MSG_OCM_EN,
+	MSG_INPUT_HDMI,
+	MSG_INPUT_DVI,
+	MSG_CLEAR_IRQ,
+};
+
+enum sink_connection_status {
+	SC_INIT,
+	SC_CHECK_CABLE_TYPE,
+	SC_WAITTING_CABLE_TYPE = SC_CHECK_CABLE_TYPE+5,
+	SC_SINK_CONNECTED,
+	SC_NOT_CABLE,
+	SC_STATE_NUM
+};
+
+enum cable_type_status {
+	CHECK_AUXCH,
+	GETTED_CABLE_TYPE,
+	CABLE_TYPE_STATE_NUM
+};
+
+enum sp_tx_lt_status {
+	LT_INIT,
+	LT_WAIT_PLL_LOCK,
+	LT_CHECK_LINK_BW,
+	LT_START,
+	LT_WAITTING_FINISH,
+	LT_ERROR,
+	LT_FINISH,
+	LT_END,
+	LT_STATES_NUM
+};
+
+enum hdcp_status {
+	HDCP_CAPABLE_CHECK,
+	HDCP_WAITTING_VID_STB,
+	HDCP_HW_ENABLE,
+	HDCP_WAITTING_FINISH,
+	HDCP_FINISH,
+	HDCP_FAILE,
+	HDCP_NOT_SUPPORT,
+	HDCP_PROCESS_STATE_NUM
+};
+
+enum video_output_status {
+	VO_WAIT_VIDEO_STABLE,
+	VO_WAIT_TX_VIDEO_STABLE,
+	VO_CHECK_VIDEO_INFO,
+	VO_FINISH,
+	VO_STATE_NUM
+};
+
+enum audio_output_status {
+	AO_INIT,
+	AO_CTS_RCV_INT,
+	AO_AUDIO_RCV_INT,
+	AO_RCV_INT_FINISH,
+	AO_OUTPUT,
+	AO_STATE_NUM
+};
+
+struct packet_avi {
+	u8 avi_data[13];
+};
+
+
+struct packet_spd {
+	u8 spd_data[25];
+};
+
+struct packet_mpeg {
+	u8 mpeg_data[13];
+};
+
+struct audio_info_frame {
+	u8 type;
+	u8 version;
+	u8 length;
+	u8 pb_byte[11];
+};
+
+enum packets_type {
+	AVI_PACKETS,
+	SPD_PACKETS,
+	MPEG_PACKETS,
+	VSI_PACKETS,
+	AUDIF_PACKETS
+};
+
+struct common_int {
+	u8 common_int[5];
+	u8 change_flag;
+};
+
+struct hdmi_rx_int {
+	u8 hdmi_rx_int[7];
+	u8 change_flag;
+};
+
+enum xtal_enum {
+	XTAL_19D2M,
+	XTAL_24M,
+	XTAL_25M,
+	XTAL_26M,
+	XTAL_27M,
+	XTAL_38D4M,
+	XTAL_52M,
+	XTAL_NOT_SUPPORT,
+	XTAL_CLK_NUM
+};
+
+enum sp_ssc_dep {
+	SSC_DEP_DISABLE = 0x0,
+	SSC_DEP_500PPM,
+	SSC_DEP_1000PPM,
+	SSC_DEP_1500PPM,
+	SSC_DEP_2000PPM,
+	SSC_DEP_2500PPM,
+	SSC_DEP_3000PPM,
+	SSC_DEP_3500PPM,
+	SSC_DEP_4000PPM,
+	SSC_DEP_4500PPM,
+	SSC_DEP_5000PPM,
+	SSC_DEP_5500PPM,
+	SSC_DEP_6000PPM
+};
+
+struct clock_data {
+	unsigned char xtal_clk;
+	unsigned int xtal_clk_m10;
+};
+
+void sp_tx_edid_read_initial(void);
+u8 sp_tx_get_edid_block(void);
+void sp_tx_rst_aux(void);
+void edid_read(u8 offset, u8 *pblock_buf);
+bool sp_tx_edid_read(u8 *pbuf);
+void check_edid_data(u8 *pblock_buf);
+
+bool slimport_chip_detect(struct anx7814_data *data);
+
+void slimport_main_process(struct anx7814_data *data);
+
+void sp_tx_variable_init(void);
+
+u8 sp_tx_aux_dpcdread_bytes(u8 addrh, u8 addrm,
+	u8 addrl, u8 cCount, u8 *pBuf);
+u8 sp_tx_aux_dpcdwrite_bytes(u8 addrh, u8 addrm,
+	u8 addrl, u8 cCount, u8 *pBuf);
+u8 sp_tx_aux_dpcdwrite_byte(u8 addrh, u8 addrm,
+	u8 addrl, u8 data1);
+void sp_tx_show_information(void);
+void hdmi_rx_show_video_info(void);
+void slimport_block_power_ctrl(enum sp_tx_power_block sp_tx_pd_block,
+	u8 power);
+void vbus_power_ctrl(unsigned char on);
+void slimport_initialization(void);
+void sp_tx_clean_state_machine(void);
+u8 sp_tx_cur_states(void);
+void print_sys_state(u8 ss);
+u8 slimport_hdcp_cap_check(void);
+
+void sp_tx_initialization(void);
+u8 sp_tx_cur_bw(void);
+void sp_tx_set_bw(u8 bw);
+
+#endif
diff --git a/drivers/staging/slimport/slimport_tx_reg.h b/drivers/staging/slimport/slimport_tx_reg.h
new file mode 100644
index 0000000..ebfa1fc
--- /dev/null
+++ b/drivers/staging/slimport/slimport_tx_reg.h
@@ -0,0 +1,786 @@
+/*
+ * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _SP_TX_REG_DEF_H
+#define _SP_TX_REG_DEF_H
+
+#define TX_P0				0x70
+#define TX_P1				0x7A
+#define TX_P2				0x72
+
+#define RX_P0				0x7e
+#define RX_P1				0x80
+
+/***************************************************************/
+/*Register definition of device address 0x7e*/
+#define HDMI_RX_PORT_SEL_REG		0x10
+#define DDC_EN				0x10
+#define TMDS_EN				0x01
+
+#define RX_SRST				0x11
+#define VIDEO_RST			0x10
+#define HDCP_MAN_RST			0X04
+#define TMDS_RST			0X02
+#define SW_MAN_RST			0X01
+
+#define RX_SW_RST2			0x12
+#define DDC_RST				0x04
+
+#define HDMI_RX_SYS_STATUS_REG		0X14
+#define PWR5V				0X08
+#define TMDS_VSYNC_DET			0X04
+#define TMDS_CLOCK_DET			0X02
+#define TMDS_DE_DET			0X01
+
+#define HDMI_STATUS			0X15
+#define DEEP_COLOR_MODE			0X40
+#define HDMI_AUD_LAYOUT			0X08
+#define MUTE_STAT			0X04
+
+#define RX_MUTE_CTRL			0X16
+#define MUTE_POL			0X04
+#define AUD_MUTE			0X02
+#define VID_MUTE			0X01
+
+#define HDMI_RX_SYS_CTRL1_REG		0X17
+
+#define RX_SYS_PWDN1			0X18
+#define PWDN_CTRL			0X01
+
+#define RX_AEC_CTRL			0X20
+#define AVC_OE				0x80
+#define AAC_OE				0X40
+#define AVC_EN				0X02
+#define AAC_EN				0X01
+
+#define RX_AEC_EN0			0X24
+#define AEC_EN07			0X80
+#define AEC_EN06			0X40
+#define AEC_EN05			0X20
+#define AEC_EN04			0X10
+#define AEC_EN03			0X08
+#define AEC_EN02			0X04
+#define AEC_EN01			0X02
+#define AEC_EN00			0X01
+
+#define RX_AEC_EN1			0X25
+#define AEC_EN15			0X80
+#define AEC_EN14			0X40
+#define AEC_EN13			0X20
+#define AEC_EN12			0X10
+#define AEC_EN11			0X08
+#define AEC_EN10			0X04
+#define AEC_EN09			0X02
+#define AEC_EN08			0X01
+
+#define RX_AEC_EN2			0X26
+#define AEC_EN23			0X80
+#define AEC_EN22			0X40
+#define AEC_EN21			0X20
+#define AEC_EN20			0X10
+#define AEC_EN19			0X08
+#define AEC_EN18			0X04
+#define AEC_EN17			0X02
+#define AEC_EN16			0X01
+
+
+#define HDMI_RX_INT_STATUS1_REG		0X31
+#define HDMI_DVI			0X80
+#define CKDT_CHANGE			0X40
+#define SCDT_CHANGE			0X20
+#define PCLK_CHANGE			0X10
+#define PLL_UNLOCK			0X08
+#define CABLE_UNPLUG			0X04
+#define SET_MUTE			0X02
+#define SW_INTR				0X01
+
+#define HDMI_RX_INT_STATUS2_REG		0X32
+#define AUTH_START			0X80
+#define AUTH_DONE			0X40
+#define HDCP_ERR			0X20
+#define ECC_ERR				0X10
+#define AUDIO_SAMPLE_CHANGE		0X01
+
+#define HDMI_RX_INT_STATUS3_REG		0X33
+#define AUD_MODE_CHANGE			0X01
+
+#define HDMI_RX_INT_STATUS4_REG		0X34
+#define VSYNC_DET			0X80
+#define SYNC_POL_CHANGE			0X40
+#define V_RES_CHANGE			0X20
+#define H_RES_CHANGE			0X10
+#define I_P_CHANGE			0X08
+#define DP_CHANGE			0X04
+#define COLOR_DEPTH_CHANGE		0X02
+#define COLOR_MODE_CHANGE		0X01
+
+#define HDMI_RX_INT_STATUS5_REG		0X35
+#define VFIFO_OVERFLOW			0X80
+#define VFIFO_UNDERFLOW			0X40
+#define CTS_N_ERR			0X08
+#define NO_AVI				0X02
+#define AUDIO_RCV			0X01
+
+#define HDMI_RX_INT_STATUS6_REG		0X36
+#define CTS_RCV				0X80
+#define NEW_UNR_PKT			0X40
+#define NEW_MPEG			0X20
+#define NEW_AUD				0X10
+#define NEW_SPD				0X08
+#define NEW_ACP				0X04
+#define NEW_AVI				0X02
+#define NEW_CP				0X01
+
+#define HDMI_RX_INT_STATUS7_REG		0X37
+#define NO_VSI				0X80
+#define HSYNC_DET			0X20
+#define NEW_VS				0X10
+#define NO_ACP				0X08
+#define REF_CLK_CHG			0X04
+#define CEC_RX_READY			0X02
+#define CEC_TX_DONE			0X01
+
+#define HDMI_RX_PKT_RX_INDU_INT_CTRL	0X3F
+#define NEW_VS_CTRL			0X80
+#define NEW_UNR				0X40
+#define NEW_MPEG			0X20
+#define NEW_AUD				0X10
+#define NEW_SPD				0X08
+#define NEW_ACP				0X04
+#define NEW_AVI				0X02
+
+
+#define HDMI_RX_INT_MASK1_REG		0X41
+#define HDMI_RX_INT_MASK2_REG		0X42
+#define HDMI_RX_INT_MASK3_REG		0X43
+#define HDMI_RX_INT_MASK4_REG		0X44
+#define HDMI_RX_INT_MASK5_REG		0X45
+#define HDMI_RX_INT_MASK6_REG		0X46
+#define HDMI_RX_INT_MASK7_REG		0X47
+
+#define HDMI_RX_TMDS_CTRL_REG1		0X50
+#define HDMI_RX_TMDS_CTRL_REG2		0X51
+#define HDMI_RX_TMDS_CTRL_REG4		0X53
+#define HDMI_RX_TMDS_CTRL_REG5		0X54
+#define HDMI_RX_TMDS_CTRL_REG6		0X55
+#define HDMI_RX_TMDS_CTRL_REG7		0X56
+#define TERM_PD				0x01
+
+#define HDMI_RX_TMDS_CTRL_REG18		0X61
+#define PLL_RESET			0x10
+
+#define HDMI_RX_TMDS_CTRL_REG19		0X62
+#define HDMI_RX_TMDS_CTRL_REG20		0X63
+#define HDMI_RX_TMDS_CTRL_REG21		0X64
+#define HDMI_RX_TMDS_CTRL_REG22		0X65
+
+
+#define HDMI_RX_VIDEO_STATUS_REG1	0x70
+#define COLOR_DEPTH			0xF0
+#define DEFAULT_PHASE			0X08
+#define VIDEO_TYPE			0X04
+
+
+#define HDMI_RX_HTOTAL_LOW		0X71
+#define HDMI_RX_HTOTAL_HIGH		0X72
+#define HDMI_RX_VTOTAL_LOW		0X73
+#define HDMI_RX_VTOTAL_HIGH		0X74
+
+#define HDMI_RX_HACT_LOW		0X75
+#define HDMI_RX_HACT_HIGH		0X76
+#define HDMI_RX_VACT_LOW		0X77
+#define HDMI_RX_VACT_HIGH		0X78
+
+#define HDMI_RX_V_SYNC_WIDTH		0X79
+#define HDMI_RX_V_BACK_PORCH		0X7A
+#define HDMI_RX_H_FRONT_PORCH_LOW	0X7B
+#define HDMI_RX_H_FRONT_PORCH_HIGH	0X7C
+
+#define HDMI_RX_H_SYNC_WIDTH_LOW	0X7D
+#define HDMI_RX_H_SYNC_WIDTH_HIGH	0X7E
+
+#define RX_VID_DATA_RNG			0X83
+#define YC_LIMT				0X10
+#define OUTPUT_LIMIT_EN			0X08
+#define OUTPUT_LIMIT_RANGE		0X04
+#define R2Y_INPUT_LIMIT			0X02
+#define XVYCC_LIMIT			0X01
+
+#define HDMI_RX_VID_OUTPUT_CTRL3_REG	0X86
+
+#define HDMI_RX_VID_PCLK_CNTR_REG	0X8B
+
+#define HDMI_RX_AUD_IN_CH_STATUS1_REG	0xC7
+#define HDMI_RX_AUD_IN_CH_STATUS4_REG	0XCA
+
+#define RX_CEC_CTRL			0XD0
+#define CEC_RX_EN			0X08
+#define CEC_TX_ST			0X04
+#define CEC_PIN_SEL			0X02
+#define CEC_RST				0X01
+
+#define HDMI_RX_CEC_RX_STATUS_REG	0XD1
+#define HDMI_RX_CEC_RX_BUSY		0X80
+#define HDMI_RX_CEC_RX_FULL		0X20
+#define HDMI_RX_CEC_RX_EMP		0X10
+
+#define HDMI_RX_CEC_TX_STATUS_REG	0XD2
+#define HDMI_RX_CEC_TX_BUSY		0X80
+#define HDMI_RX_CEC_TX_FAIL		0X40
+#define HDMI_RX_CEC_TX_FULL		0X20
+#define HDMI_RX_CEC_TX_EMP		0X10
+
+
+#define HDMI_RX_CEC_FIFO_REG		0XD3
+
+#define RX_CEC_SPEED			0XD4
+#define CEC_SPEED_27M			0x40
+
+#define HDMI_RX_HDMI_CRITERIA_REG	0XE1
+
+#define HDMI_RX_HDCP_EN_CRITERIA_REG	0XE2
+#define ENC_EN_MODE			0X20
+
+#define RX_CHIP_CTRL			0XE3
+#define MAN_HDMI5V_DET			0X08
+#define PLLLOCK_CKDT_EN			0X04
+#define ANALOG_CKDT_EN			0X02
+#define DIGITAL_CKDT_EN			0X01
+
+#define RX_PACKET_REV_STA		0XF3
+#define AVI_RCVD			0X40
+#define VSI_RCVD			0X20
+/***************************************************************/
+/*Register definition of device address 0x80*/
+
+
+#define HDMI_RX_HDCP_STATUS_REG		0X3F
+#define ADV_CIPHER			0X80
+#define LOAD_KEY_DONE			0X40
+#define DECRYPT_EN			0X20
+#define AUTH_EN				0X10
+#define BKSV_DISABLE			0X02
+#define CLEAR_RI			0X01
+
+#define HDMI_RX_SPD_TYPE_REG		0X40
+#define HDMI_RX_SPD_VER_REG		0X41
+#define HDMI_RX_SPD_LEN_REG		0X42
+#define HDMI_RX_SPD_CHKSUM_REG		0X43
+#define HDMI_RX_SPD_DATA00_REG		0X44
+
+#define HDMI_RX_ACP_HB0_REG		0X60
+#define HDMI_RX_ACP_HB1_REG		0X61
+#define HDMI_RX_ACP_HB2_REG		0X62
+#define HDMI_RX_ACP_DATA00_REG		0X63
+
+#define HDMI_RX_AVI_TYPE_REG		0XA0
+#define HDMI_RX_AVI_VER_REG		0XA1
+#define HDMI_RX_AVI_LEN_REG		0XA2
+#define HDMI_RX_AVI_CHKSUM_REG		0XA3
+#define HDMI_RX_AVI_DATA00_REG		0XA4
+
+#define HDMI_RX_AUDIO_TYPE_REG		0XC0
+#define HDMI_RX_AUDIO_VER_REG		0XC1
+#define HDMI_RX_AUDIO_LEN_REG		0XC2
+#define HDMI_RX_AUDIO_CHKSUM_REG	0XC3
+#define HDMI_RX_AUDIO_DATA00_REG	0XC4
+
+#define HDMI_RX_MPEG_TYPE_REG		0XE0
+#define HDMI_RX_MPEG_VER_REG		0XE1
+#define HDMI_RX_MPEG_LEN_REG		0XE2
+#define HDMI_RX_MPEG_CHKSUM_REG		0XE3
+#define HDMI_RX_MPEG_DATA00_REG		0XE4
+#define HDMI_RX_MPEG_DATA03_REG		0XE7
+#define HDMI_RX_MPEG_DATA05_REG		0XE9
+
+#define HDMI_RX_SPD_INFO_CTRL		0X5F
+#define HDMI_RX_ACP_INFO_CTRL		0X7F
+
+#define HDMI_RX_GENERAL_CTRL		0X9F
+#define CLEAR_AVMUTE			0x10
+#define SET_AVMUTE			0x01
+
+#define HDMI_RX_MPEG_VS_CTRL		0XDF
+#define HDMI_RX_MPEG_VS_INFO_CTRL	0XFF
+
+
+/***************************************************************/
+/*Register definition of device address 0x70*/
+#define SP_TX_HDCP_STATUS		0x00
+#define SP_TX_HDCP_AUTH_PASS		0x02
+
+#define TX_HDCP_CTRL0			0x01
+#define STORE_AN			0x80
+#define RX_REPEATER			0x40
+#define RE_AUTH				0x20
+#define SW_AUTH_OK			0x10
+#define HARD_AUTH_EN			0x08
+#define ENC_EN				0x04
+#define BKSV_SRM_PASS			0x02
+#define KSVLIST_VLD			0x01
+
+#define SP_TX_HDCP_CTRL1_REG		0x02
+#define AINFO_EN			0x04
+#define RCV_11_EN			0x02
+#define HDCP_11_EN			0x01
+
+#define SP_TX_HDCP_LINK_CHK_FRAME_NUM	0x03
+#define SP_TX_HDCP_CTRL2_REG		0x04
+
+
+#define SP_TX_VID_BLANK_SET1		0X2C
+#define SP_TX_VID_BLANK_SET2		0X2D
+#define SP_TX_VID_BLANK_SET3		0X2E
+
+#define SP_TX_WAIT_R0_TIME		0x40
+#define SP_TX_LINK_CHK_TIMER		0x41
+#define SP_TX_WAIT_KSVR_TIME		0X42
+
+#define HDCP_KEY_STATUS			0x5E
+
+
+#define M_VID_0				0xC0
+#define M_VID_1				0xC1
+#define M_VID_2				0xC2
+#define N_VID_0				0xC3
+#define N_VID_1				0xC4
+#define N_VID_2				0xC5
+#define HDCP_AUTO_TIMER			0x51
+#define HDCP_AUTO_TIMER_VAL		0x00
+
+#define HDCP_KEY_CMD			0x5F
+#define DISABLE_SYNC_HDCP		0x04
+
+#define OTP_KEY_PROTECT1		0x60
+#define OTP_KEY_PROTECT2		0x61
+#define OTP_KEY_PROTECT3		0x62
+#define OTP_PSW1			0xa2
+#define OTP_PSW2			0x7e
+#define OTP_PSW3			0xc6
+
+
+#define SP_TX_SYS_CTRL1_REG		0x80
+#define CHIP_AUTH_RESET			0x80
+#define PD_BYPASS_CHIP_AUTH		0x40
+#define DET_STA				0x04
+#define FORCE_DET			0x02
+#define DET_CTRL			0x01
+
+#define SP_TX_SYS_CTRL2_REG		0x81
+#define CHA_STA				0x04
+#define FORCE_CHA			0x02
+#define CHA_CTRL			0x01
+
+#define SP_TX_SYS_CTRL3_REG		0x82
+#define HPD_STATUS			0x40
+#define F_HPD				0x20
+#define HPD_CTRL			0x10
+#define STRM_VALID			0x04
+#define F_VALID				0x02
+#define VALID_CTRL			0x01
+
+#define SP_TX_SYS_CTRL4_REG		0x83
+#define ENHANCED_MODE			0x08
+
+#define SP_TX_VID_CTRL			0x84
+
+#define SP_TX_AUD_CTRL			0x87
+#define AUD_EN				0x01
+
+#define  I2C_GEN_10US_TIMER0		0x88
+#define  I2C_GEN_10US_TIMER1		0x89
+
+#define SP_TX_PKT_EN_REG		0x90
+#define AUD_IF_UP			0x80
+#define AVI_IF_UD			0x40
+#define MPEG_IF_UD			0x20
+#define SPD_IF_UD			0x10
+#define AUD_IF_EN			0x08
+#define AVI_IF_EN			0x04
+#define MPEG_IF_EN			0x02
+#define SPD_IF_EN			0x01
+
+#define TX_HDCP_CTRL			0x92
+#define AUTO_EN				0x80
+#define AUTO_START			0x20
+#define LINK_POLLING			0x02
+
+#define SP_TX_LINK_BW_SET_REG		0xA0
+#define LINK_6P75G			0x19
+#define LINK_5P4G			0x14
+#define LINK_2P7G			0x0A
+#define LINK_1P62G			0x06
+
+#define SP_TX_TRAINING_PTN_SET_REG	0xA2
+#define SCRAMBLE_DISABLE		0x20
+
+#define SP_TX_LT_SET_REG		0xA3
+#define MAX_PRE_REACH			0x20
+#define MAX_DRIVE_REACH			0x04
+#define DRVIE_CURRENT_LEVEL1		0x01
+#define PRE_EMP_LEVEL1			0x08
+
+
+#define LT_CTRL				0xA8
+#define SP_TX_LT_EN			0x01
+
+#define TX_DEBUG1			0xB0
+#define FORCE_HPD			0X80
+#define HPD_POLLING_DET			0x40
+#define HPD_POLLING_EN			0x20
+#define DEBUG_PLL_LOCK			0x10
+#define FORCE_PLL_LOCK			0X08
+#define POLLING_EN			0x02
+
+#define SP_TX_DP_POLLING_PERIOD		0xB3
+
+#define TX_DP_POLLING			0xB4
+#define AUTO_POLLING_DISABLE		0x01
+
+#define TX_LINK_DEBUG			0xB8
+#define M_VID_DEBUG			0x20
+#define NEW_PRBS7			0x10
+#define INSERT_ER			0x02
+#define PRBS31_EN			0x01
+
+#define DPCD_200			0xB9
+#define DPCD_201			0xBA
+#define DPCD_202			0xBB
+#define DPCD_203			0xBC
+#define DPCD_204			0xBD
+#define DPCD_205			0xBE
+
+#define SP_TX_PLL_CTRL_REG		0xC7
+#define PLL_RST				0x40
+
+#define SP_TX_ANALOG_PD_REG		0xC8
+#define MACRO_PD			0x20
+#define AUX_PD				0x10
+#define CH0_PD				0x01
+
+#define TX_MISC				0xCD
+#define EQ_TRAINING_LOOP		0x40
+
+
+#define SP_TX_DOWN_SPREADING_CTRL1	0xD0
+#define SP_TX_SSC_DISABLE		0xC0
+#define SP_TX_SSC_DWSPREAD		0x40
+
+
+#define SP_TX_M_CALCU_CTRL		0xD9
+#define M_GEN_CLK_SEL			0x01
+
+#define TX_EXTRA_ADDR			0xCE
+#define I2C_STRETCH_DISABLE		0X80
+#define I2C_EXTRA_ADDR			0X50
+
+#define SP_TX_AUX_STATUS		0xE0
+#define AUX_BUSY			0x10
+
+#define AUX_DEFER_CTRL			0xE2
+#define BUF_DATA_COUNT			0xE4
+
+#define AUX_CTRL			0xE5
+#define AUX_ADDR_7_0			0xE6
+#define AUX_ADDR_15_8			0xE7
+#define AUX_ADDR_19_16			0xE8
+
+#define AUX_CTRL2			0xE9
+#define ADDR_ONLY_BIT			0x02
+#define AUX_OP_EN			0x01
+
+#define SP_TX_3D_VSC_CTRL		0xEA
+#define INFO_FRAME_VSC_EN		0x01
+
+#define SP_TX_VSC_DB1			0xEB
+
+#define BUF_DATA_0			0xF0
+
+
+/***************************************************************/
+/*Register definition of device address 0x72*/
+#define SP_TX_VND_IDL_REG		0x00
+#define SP_TX_VND_IDH_REG		0x01
+#define SP_TX_DEV_IDL_REG		0x02
+#define SP_TX_DEV_IDH_REG		0x03
+#define SP_TX_DEV_REV_REG		0x04
+
+#define SP_POWERD_CTRL_REG		0x05
+#define REGISTER_PD			0x80
+#define HDCP_PD				0x20
+#define AUDIO_PD			0x10
+#define VIDEO_PD			0x08
+#define LINK_PD				0x04
+#define TOTAL_PD			0x02
+
+#define SP_TX_RST_CTRL_REG		0x06
+#define MISC_RST			0x80
+#define VIDCAP_RST			0x40
+#define VIDFIF_RST			0x20
+#define AUDFIF_RST			0x10
+#define AUDCAP_RST			0x08
+#define HDCP_RST			0x04
+#define SW_RST				0x02
+#define HW_RST				0x01
+
+#define RST_CTRL2			0x07
+#define AUX_RST				0x04
+#define SERDES_FIFO_RST			0x02
+#define I2C_REG_RST			0x01
+
+#define VID_CTRL1			0x08
+#define VIDEO_EN			0x80
+#define VIDEO_MUTE			0x40
+#define IN_BIT_SEl			0x04
+#define DDR_CTRL			0x02
+#define EDGE_CTRL			0x01
+
+#define SP_TX_VID_CTRL2_REG		0x09
+#define IN_BPC_12BIT			0x30
+#define IN_BPC_10BIT			0x20
+#define IN_BPC_8BIT			0x10
+
+#define SP_TX_VID_CTRL3_REG		0x0A
+#define HPD_OUT				0x40
+
+#define SP_TX_VID_CTRL5_REG		0x0C
+#define CSC_STD_SEL			0x80
+#define RANGE_Y2R			0x20
+#define CSPACE_Y2R			0x10
+
+#define SP_TX_VID_CTRL6_REG		0x0D
+#define VIDEO_PROCESS_EN		0x40
+#define UP_SAMPLE			0x02
+#define DOWN_SAMPLE			0x01
+
+#define SP_TX_VID_CTRL8_REG		0x0F
+#define VID_VRES_TH			0x01
+
+#define SP_TX_TOTAL_LINE_STA_L		0x24
+#define SP_TX_TOTAL_LINE_STA_H		0x25
+#define SP_TX_ACT_LINE_STA_L		0x26
+#define SP_TX_ACT_LINE_STA_H		0x27
+#define SP_TX_V_F_PORCH_STA		0x28
+#define SP_TX_V_SYNC_STA		0x29
+#define SP_TX_V_B_PORCH_STA		0x2A
+#define SP_TX_TOTAL_PIXEL_STA_L		0x2B
+#define SP_TX_TOTAL_PIXEL_STA_H		0x2C
+#define SP_TX_ACT_PIXEL_STA_L		0x2D
+#define SP_TX_ACT_PIXEL_STA_H		0x2E
+#define SP_TX_H_F_PORCH_STA_L		0x2F
+#define SP_TX_H_F_PORCH_STA_H		0x30
+#define SP_TX_H_SYNC_STA_L		0x31
+#define SP_TX_H_SYNC_STA_H		0x32
+#define SP_TX_H_B_PORCH_STA_L		0x33
+#define SP_TX_H_B_PORCH_STA_H		0x34
+
+#define SP_TX_DP_ADDR_REG1		0x3E
+
+#define SP_TX_VID_BIT_CTRL0_REG		0x40
+#define SP_TX_VID_BIT_CTRL10_REG	0x4a
+#define SP_TX_VID_BIT_CTRL20_REG	0x54
+
+#define SP_TX_AVI_TYPE			0x70
+#define SP_TX_AVI_VER			0x71
+#define SP_TX_AVI_LEN			0x72
+#define SP_TX_AVI_DB0			0x73
+
+#define BIT_CTRL_SPECIFIC		0x80
+#define ENABLE_BIT_CTRL			0x01
+
+#define SP_TX_AUD_TYPE			0x83
+#define SP_TX_AUD_VER			0x84
+#define SP_TX_AUD_LEN			0x85
+#define SP_TX_AUD_DB0			0x86
+
+#define SP_TX_SPD_TYPE			0x91
+#define SP_TX_SPD_VER			0x92
+#define SP_TX_SPD_LEN			0x93
+#define SP_TX_SPD_DB0			0x94
+
+#define SP_TX_MPEG_TYPE			0xB0
+#define SP_TX_MPEG_VER			0xB1
+#define SP_TX_MPEG_LEN			0xB2
+#define SP_TX_MPEG_DB0			0xB3
+
+#define SP_TX_AUD_CH_STATUS_REG1	0xD0
+
+#define SP_TX_AUD_CH_NUM_REG5		0xD5
+#define CH_NUM_8			0xE0
+#define AUD_LAYOUT			0x01
+
+#define GPIO_1_CONTROL			0xD6
+#define GPIO_1_PULL_UP			0x04
+#define GPIO_1_OEN			0x02
+#define GPIO_1_DATA			0x01
+
+#define TX_ANALOG_DEBUG2		0xDD
+#define POWERON_TIME_1P5MS		0X03
+
+#define TX_PLL_FILTER			0xDF
+#define PD_RING_OSC			0x40
+#define V33_SWITCH_ON			0x08
+
+#define TX_PLL_FILTER5			0xE0
+#define SP_TX_ANALOG_CTRL0		0xE1
+#define P5V_PROTECT			0X80
+#define SHORT_PROTECT			0X40
+#define P5V_PROTECT_PD			0X20
+#define SHORT_PROTECT_PD		0X10
+
+#define TX_ANALOG_CTRL			0xE5
+#define SHORT_DPDM			0X4
+
+#define SP_COMMON_INT_STATUS1		0xF1
+#define PLL_LOCK_CHG			0x40
+#define VIDEO_FORMAT_CHG		0x08
+#define AUDIO_CLK_CHG			0x04
+#define VIDEO_CLOCK_CHG			0x02
+
+#define SP_COMMON_INT_STATUS2		0xF2
+#define HDCP_AUTH_CHG			0x02
+#define HDCP_AUTH_DONE			0x01
+
+#define SP_COMMON_INT_STATUS3		0xF3
+#define HDCP_LINK_CHECK_FAIL		0x01
+
+#define SP_COMMON_INT_STATUS4		0xF4
+#define PLUG				0x01
+#define ESYNC_ERR			0x10
+#define HPD_LOST			0x02
+#define HPD_CHANGE			0x04
+#define HPD_IRQ				0x40
+
+#define SP_TX_INT_STATUS1		0xF7
+#define DPCD_IRQ_REQUEST		0x80
+#define HPD				0x40
+#define TRAINING_Finish			0x20
+#define POLLING_ERR			0x10
+#define LINK_CHANGE			0x04
+#define SINK_CHG			0x08
+
+#define SP_COMMON_INT_MASK1		0xF8
+#define SP_COMMON_INT_MASK2		0xF9
+#define SP_COMMON_INT_MASK3		0xFA
+#define SP_COMMON_INT_MASK4		0xFB
+#define SP_INT_MASK			0xFE
+#define SP_TX_INT_CTRL_REG		0xFF
+
+
+/***************************************************************/
+/*Register definition of device address 0x7a*/
+
+#define SP_TX_LT_CTRL_REG0		0x30
+#define SP_TX_LT_CTRL_REG1		0x31
+#define SP_TX_LT_CTRL_REG2		0x34
+#define SP_TX_LT_CTRL_REG3		0x35
+#define SP_TX_LT_CTRL_REG4		0x36
+#define SP_TX_LT_CTRL_REG5		0x37
+#define SP_TX_LT_CTRL_REG6		0x38
+#define SP_TX_LT_CTRL_REG7		0x39
+#define SP_TX_LT_CTRL_REG8		0x3A
+#define SP_TX_LT_CTRL_REG9		0x3B
+#define SP_TX_LT_CTRL_REG10		0x40
+#define SP_TX_LT_CTRL_REG11		0x41
+#define SP_TX_LT_CTRL_REG12		0x44
+#define SP_TX_LT_CTRL_REG13		0x45
+#define SP_TX_LT_CTRL_REG14		0x46
+#define SP_TX_LT_CTRL_REG15		0x47
+#define SP_TX_LT_CTRL_REG16		0x48
+#define SP_TX_LT_CTRL_REG17		0x49
+#define SP_TX_LT_CTRL_REG18		0x4A
+#define SP_TX_LT_CTRL_REG19		0x4B
+
+#define SP_TX_AUD_INTERFACE_CTRL0	0x5f
+#define AUD_INTERFACE_DISABLE		0x80
+
+#define SP_TX_AUD_INTERFACE_CTRL2	0x60
+#define M_AUD_ADJUST_ST			0x04
+
+#define SP_TX_AUD_INTERFACE_CTRL3	0x62
+#define SP_TX_AUD_INTERFACE_CTRL4	0x67
+#define SP_TX_AUD_INTERFACE_CTRL5	0x68
+#define SP_TX_AUD_INTERFACE_CTRL6	0x69
+
+#define OCM_REG3			0x96
+#define OCM_RST				0x80
+
+#define FW_VER_REG			0xB7
+
+
+/***************************************************************/
+/*Definition of DPCD*/
+
+
+#define DOWN_R_TERM_DET _BIT6
+#define SRAM_EEPROM_LOAD_DONE _BIT5
+#define SRAM_CRC_CHK_DONE _BIT4
+#define SRAM_CRC_CHK_PASS _BIT3
+#define DOWN_STRM_ENC _BIT2
+#define DOWN_STRM_AUTH _BIT1
+#define DOWN_STRM_HPD _BIT0
+
+
+#define DPCD_DPCD_REV			0x00
+#define DPCD_MAX_LINK_RATE		0x01
+
+#define DPCD_MAX_LANE_COUNT		0x02
+#define ENHANCED_FRAME_CAP		0x80
+
+#define DPCD_MAX_DOWNSPREAD		0x03
+#define DPCD_NORP			0x04
+#define DPCD_DSPORT_PRESENT		0x05
+
+#define DPCD_LINK_BW_SET		0x00
+#define DPCD_LANE_COUNT_SET		0x01
+#define ENHANCED_FRAME_EN		0x80
+
+#define DPCD_TRAINING_PATTERN_SET	0x02
+#define DPCD_TRAINNIG_LANE0_SET		0x03
+
+#define DPCD_DOWNSPREAD_CTRL		0x07
+#define SPREAD_AMPLITUDE		0X10
+
+#define DPCD_SINK_COUNT			0x00
+#define DPCD_SERVICE_IRQ_VECTOR		0x01
+#define TEST_IRQ			0x02
+#define CP_IRQ				0x04
+#define SINK_SPECIFIC_IRQ		0x40
+
+#define DPCD_LANE0_1_STATUS		0x02
+
+#define DPCD_LANE_ALIGN_UD		0x04
+#define DPCD_SINK_STATUS		0x05
+
+#define DPCD_TEST_Response		0x60
+#define TEST_ACK			0x01
+#define DPCD_TEST_EDID_Checksum_Write	0x04
+
+#define DPCD_TEST_EDID_Checksum		0x61
+
+
+#define DPCD_SPECIFIC_INTERRUPT1	0x10
+#define DPCD_USER_COMM1			0x22
+
+#define DPCD_SPECIFIC_INTERRUPT2	0x11
+
+#define DPCD_TEST_REQUEST		0x18
+#define DPCD_TEST_LINK_RATE		0x19
+
+#define DPCD_TEST_LANE_COUNT		0x20
+
+#define DPCD_PHY_TEST_PATTERN		0x48
+
+#endif
+
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix.
  2015-09-06 21:14 ` [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix Enric Balletbo i Serra
@ 2015-09-06 23:27   ` Greg KH
  2015-09-07  5:41     ` Enric Balletbo Serra
  0 siblings, 1 reply; 9+ messages in thread
From: Greg KH @ 2015-09-06 23:27 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: devel, linux-kernel, sjoerd.simons, javier, span, nathan.chung

On Sun, Sep 06, 2015 at 11:14:02PM +0200, Enric Balletbo i Serra wrote:
> The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter
> designed for portable devices.
> 
> This driver adds initial support and supports HDMI to DP pass-through mode.
> 
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> ---
>  drivers/staging/Kconfig                    |    2 +
>  drivers/staging/Makefile                   |    1 +
>  drivers/staging/slimport/Kconfig           |    7 +
>  drivers/staging/slimport/Makefile          |    4 +
>  drivers/staging/slimport/slimport.c        |  301 +++
>  drivers/staging/slimport/slimport.h        |   49 +
>  drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
>  drivers/staging/slimport/slimport_tx_drv.h |  254 +++
>  drivers/staging/slimport/slimport_tx_reg.h |  786 +++++++

Why is this a staging driver?
What prevents it from being merged into the "real" part of the kernel
tree?

All staging drivers need a TODO file, listing what needs to be done and
who is in charge of it.  I can't take this without that added.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix.
  2015-09-06 23:27   ` Greg KH
@ 2015-09-07  5:41     ` Enric Balletbo Serra
  2015-09-07  6:46       ` Greg KH
  0 siblings, 1 reply; 9+ messages in thread
From: Enric Balletbo Serra @ 2015-09-07  5:41 UTC (permalink / raw)
  To: Greg KH
  Cc: devel, linux-kernel, Sjoerd Simons, Javier Martinez Canillas,
	span, nathan.chung

2015-09-07 1:27 GMT+02:00 Greg KH <gregkh@linuxfoundation.org>:
> On Sun, Sep 06, 2015 at 11:14:02PM +0200, Enric Balletbo i Serra wrote:
>> The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter
>> designed for portable devices.
>>
>> This driver adds initial support and supports HDMI to DP pass-through mode.
>>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>> ---
>>  drivers/staging/Kconfig                    |    2 +
>>  drivers/staging/Makefile                   |    1 +
>>  drivers/staging/slimport/Kconfig           |    7 +
>>  drivers/staging/slimport/Makefile          |    4 +
>>  drivers/staging/slimport/slimport.c        |  301 +++
>>  drivers/staging/slimport/slimport.h        |   49 +
>>  drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
>>  drivers/staging/slimport/slimport_tx_drv.h |  254 +++
>>  drivers/staging/slimport/slimport_tx_reg.h |  786 +++++++
>
> Why is this a staging driver?
> What prevents it from being merged into the "real" part of the kernel
> tree?
>

I'll be glad to move the driver to their subsystem if you think it's a
the better place. Basically there are two reasons why I send the
driver to the staging directory. The first one is because my test
environment is a bit limited, with my environment I can only test the
HDMI to DisplayPort pass-through mode so the driver builds but it's
partially tested. The second one is that I expect I'll need to
refactor some code, specially in slimport_tx_drv.c file to be
accepted, I decided not change too much this file from the original to
not break the functionality, so I thought that will be better send
first to the staging driver to have first reviews.

> All staging drivers need a TODO file, listing what needs to be done and
> who is in charge of it.  I can't take this without that added.
>

ok, I'll add in the next series once received some feedback (or move
to the video subsystem)

Thanks,
Enric

> thanks,
>
> greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix.
  2015-09-07  5:41     ` Enric Balletbo Serra
@ 2015-09-07  6:46       ` Greg KH
  2015-09-09  3:38         ` Daniel Kurtz
  0 siblings, 1 reply; 9+ messages in thread
From: Greg KH @ 2015-09-07  6:46 UTC (permalink / raw)
  To: Enric Balletbo Serra
  Cc: devel, linux-kernel, Sjoerd Simons, Javier Martinez Canillas,
	span, nathan.chung

On Mon, Sep 07, 2015 at 07:41:08AM +0200, Enric Balletbo Serra wrote:
> 2015-09-07 1:27 GMT+02:00 Greg KH <gregkh@linuxfoundation.org>:
> > On Sun, Sep 06, 2015 at 11:14:02PM +0200, Enric Balletbo i Serra wrote:
> >> The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter
> >> designed for portable devices.
> >>
> >> This driver adds initial support and supports HDMI to DP pass-through mode.
> >>
> >> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> >> ---
> >>  drivers/staging/Kconfig                    |    2 +
> >>  drivers/staging/Makefile                   |    1 +
> >>  drivers/staging/slimport/Kconfig           |    7 +
> >>  drivers/staging/slimport/Makefile          |    4 +
> >>  drivers/staging/slimport/slimport.c        |  301 +++
> >>  drivers/staging/slimport/slimport.h        |   49 +
> >>  drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
> >>  drivers/staging/slimport/slimport_tx_drv.h |  254 +++
> >>  drivers/staging/slimport/slimport_tx_reg.h |  786 +++++++
> >
> > Why is this a staging driver?
> > What prevents it from being merged into the "real" part of the kernel
> > tree?
> >
> 
> I'll be glad to move the driver to their subsystem if you think it's a
> the better place. Basically there are two reasons why I send the
> driver to the staging directory. The first one is because my test
> environment is a bit limited, with my environment I can only test the
> HDMI to DisplayPort pass-through mode so the driver builds but it's
> partially tested. The second one is that I expect I'll need to
> refactor some code, specially in slimport_tx_drv.c file to be
> accepted, I decided not change too much this file from the original to
> not break the functionality, so I thought that will be better send
> first to the staging driver to have first reviews.
> 
> > All staging drivers need a TODO file, listing what needs to be done and
> > who is in charge of it.  I can't take this without that added.
> >
> 
> ok, I'll add in the next series once received some feedback (or move
> to the video subsystem)

I suggest trying to get it merged "properly" first before having to
fall-back to the staging subsystem.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix.
  2015-09-07  6:46       ` Greg KH
@ 2015-09-09  3:38         ` Daniel Kurtz
  2015-09-09  7:10           ` Enric Balletbo Serra
  0 siblings, 1 reply; 9+ messages in thread
From: Daniel Kurtz @ 2015-09-09  3:38 UTC (permalink / raw)
  To: Enric Balletbo Serra
  Cc: devel, Greg KH, linux-kernel@vger.kernel.org, Sjoerd Simons,
	Javier Martinez Canillas, span, Nathan Chung, dri-devel

Hi Eric,

Thanks for starting to upstream this Analogix Slimport driver!
As Greg says, please move this driver to its intended directory, I presume:
/drivers/gpu/drm/bridge

And when you submit, use get_maintainer.pl to add the proper reviewers
and lists.
At present, you have no DRM folks, nor dri-devel, so you probably
won't receive any additional feedback on this version, since the
relevant folks have not seen your emails.

Some more very detailed feedback inline...

On Sep 7, 2015 05:15, "Enric Balletbo i Serra" <eballetbo@gmail.com> wrote:
>
> The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter
> designed for portable devices.
>
> This driver adds initial support and supports HDMI to DP pass-through mode.
>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> ---
>  drivers/staging/Kconfig                    |    2 +
>  drivers/staging/Makefile                   |    1 +
>  drivers/staging/slimport/Kconfig           |    7 +
>  drivers/staging/slimport/Makefile          |    4 +
>  drivers/staging/slimport/slimport.c        |  301 +++
>  drivers/staging/slimport/slimport.h        |   49 +
>  drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
>  drivers/staging/slimport/slimport_tx_drv.h |  254 +++
>  drivers/staging/slimport/slimport_tx_reg.h |  786 +++++++
>  9 files changed, 4697 insertions(+)
>  create mode 100644 drivers/staging/slimport/Kconfig
>  create mode 100644 drivers/staging/slimport/Makefile
>  create mode 100644 drivers/staging/slimport/slimport.c
>  create mode 100644 drivers/staging/slimport/slimport.h
>  create mode 100644 drivers/staging/slimport/slimport_tx_drv.c
>  create mode 100644 drivers/staging/slimport/slimport_tx_drv.h
>  create mode 100644 drivers/staging/slimport/slimport_tx_reg.h
>
> diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
> index e29293c..24ccd7c 100644
> --- a/drivers/staging/Kconfig
> +++ b/drivers/staging/Kconfig
> @@ -110,4 +110,6 @@ source "drivers/staging/wilc1000/Kconfig"
>
>  source "drivers/staging/most/Kconfig"
>
> +source "drivers/staging/slimport/Kconfig"
> +
>  endif # STAGING
> diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
> index 50824dd..942e886 100644
> --- a/drivers/staging/Makefile
> +++ b/drivers/staging/Makefile
> @@ -47,3 +47,4 @@ obj-$(CONFIG_FB_TFT)          += fbtft/
>  obj-$(CONFIG_FSL_MC_BUS)       += fsl-mc/
>  obj-$(CONFIG_WILC1000)         += wilc1000/
>  obj-$(CONFIG_MOST)             += most/
> +obj-$(CONFIG_SLIMPORT_ANX78XX) += slimport/
> diff --git a/drivers/staging/slimport/Kconfig b/drivers/staging/slimport/Kconfig
> new file mode 100644
> index 0000000..f5233ef
> --- /dev/null
> +++ b/drivers/staging/slimport/Kconfig
> @@ -0,0 +1,7 @@
> +config SLIMPORT_ANX78XX

I think the "SLIMPORT_" here is a bit overkill, and just adds to
confusion over what name to use where.  I'd recommend just
CONFIG_ANX78XX.

Likewise, for consistency, the rename the files as "anx78xx*" instead
of "slimport*".

> +       tristate "Analogix Slimport transmitter ANX78XX support"
> +       help
> +               Slimport Transmitter is a HD video transmitter chip
> +               over micro-USB connector for smartphone device.
> +
> +
> diff --git a/drivers/staging/slimport/Makefile b/drivers/staging/slimport/Makefile
> new file mode 100644
> index 0000000..9bb6ce2
> --- /dev/null
> +++ b/drivers/staging/slimport/Makefile
> @@ -0,0 +1,4 @@
> +obj-${CONFIG_SLIMPORT_ANX78XX} :=  anx78xx.o
> +
> +anx78xx-y := slimport.o
> +anx78xx-y += slimport_tx_drv.o
> diff --git a/drivers/staging/slimport/slimport.c b/drivers/staging/slimport/slimport.c
> new file mode 100644
> index 0000000..95c5114
> --- /dev/null
> +++ b/drivers/staging/slimport/slimport.c
> @@ -0,0 +1,301 @@
> +/*
> + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/err.h>
> +#include <linux/async.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_platform.h>
> +#include <linux/delay.h>
> +
> +#include "slimport.h"
> +#include "slimport_tx_drv.h"
> +
> +/* HDCP switch for external block */
> +/* external_block_en = 1: enable, 0: disable */

This comment is a bit superfluous.

> +int external_block_en = 1;
> +
> +struct i2c_client *anx7814_client;

A single global client isn't going to work.  It is easy to imagine a
machine with more than one anx78xx, requiring multiple instances of
the driver and hence multiple i2c clients.

Also, you'll want to be a bit more consistent with naming; is the
driver for anx78xx?  Or anx7814 only?

> +
> +int sp_read_reg_byte(uint8_t slave_addr, uint8_t offset)
> +{
> +       int ret = 0;
> +       struct device *dev = &anx7814_client->dev;

The use of global anx7814_client has ramifications throughout this
whole driver. direct
Please re-write all of these transaction functions (and their callers)
should to take a context struct pointer as their first parameter.

> +
> +       anx7814_client->addr = (slave_addr >> 1);
> +       ret = i2c_smbus_read_byte_data(anx7814_client, offset);
> +       if (ret < 0) {
> +               dev_err(dev, "%s: failed to read i2c addr=%x\n", LOG_TAG,
> +                     slave_addr);
> +               return ret;
> +       }
> +       return 0;

Don't you need to return the actual byte that was read (ret)?

> +}
> +
> +int sp_read_reg(uint8_t slave_addr, uint8_t offset, uint8_t *buf)
> +{
> +       int ret = 0;
> +       struct device *dev = &anx7814_client->dev;
> +
> +       anx7814_client->addr = (slave_addr >> 1);
> +       ret = i2c_smbus_read_byte_data(anx7814_client, offset);
> +       if (ret < 0) {
> +               dev_err(dev, "%s: failed to read i2c addr=%x\n", LOG_TAG,
> +                      slave_addr);
> +               return ret;
> +       }
> +       *buf = (uint8_t) ret;
> +
> +       return 0;
> +}
> +
> +int sp_write_reg(uint8_t slave_addr, uint8_t offset, uint8_t value)
> +{
> +       int ret = 0;
> +       struct device *dev = &anx7814_client->dev;
> +
> +       anx7814_client->addr = (slave_addr >> 1);
> +       ret = i2c_smbus_write_byte_data(anx7814_client, offset, value);
> +       if (ret < 0) {
> +               dev_err(dev, "%s: failed to write i2c addr=%x\n", LOG_TAG,
> +                      slave_addr);
> +       }
> +       return ret;
> +}
> +
> +void sp_tx_hardware_poweron(struct anx7814_data *data)

nit: another personal preference, I prefer to use the specific device
as the local parameter name, rather than the generic "data".
So it would look something like:

  void anx7814_tx_hardware_poweron(struct anx7814 *anx7814)

> +{
> +       struct device *dev = &data->client->dev;
> +       struct anx7814_platform_data *pdata = data->pdata;
> +
> +       gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
> +       usleep_range(1000, 2000);
> +
> +       gpiod_set_value_cansleep(pdata->gpiod_pd, 0);
> +       usleep_range(1000, 2000);
> +
> +       gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
> +
> +       dev_info(dev, "%s: anx7814 power on\n", LOG_TAG);

This kind of verbose logging should be dev_dbg(

> +}
> +
> +void sp_tx_hardware_powerdown(struct anx7814_data *data)
> +{
> +       struct device *dev = &data->client->dev;
> +       struct anx7814_platform_data *pdata = data->pdata;
> +
> +       gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
> +       usleep_range(1000, 2000);
> +
> +       gpiod_set_value_cansleep(pdata->gpiod_pd, 1);
> +       usleep_range(1000, 2000);
> +
> +       dev_info(dev, "%s: anx7814 power down\n", LOG_TAG);
> +}
> +
> +static int anx7814_init_gpio(struct anx7814_data *data)
> +{
> +       struct device *dev = &data->client->dev;
> +       struct anx7814_platform_data *pdata = data->pdata;
> +       int ret;
> +
> +       /* gpio for chip power down */
> +       pdata->gpiod_pd = devm_gpiod_get(dev, "pd", GPIOD_OUT_HIGH);
> +       if (IS_ERR(pdata->gpiod_pd)) {
> +               dev_err(dev, "unable to claim pd gpio\n");
> +               ret = PTR_ERR(pdata->gpiod_pd);
> +               return ret;
> +       }
> +
> +       /* gpio for chip reset */
> +       pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
> +       if (IS_ERR(pdata->gpiod_reset)) {
> +               dev_err(dev, "unable to claim reset gpio\n");
> +               ret = PTR_ERR(pdata->gpiod_reset);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int anx7814_system_init(struct anx7814_data *data)
> +{
> +       struct device *dev = &data->client->dev;
> +
> +       int ret = 0;
> +
> +       ret = slimport_chip_detect(data);
> +       if (ret == 0) {
> +               sp_tx_hardware_powerdown(data);
> +               dev_err(dev, "failed to detect anx7814\n");
> +               return -ENODEV;
> +       }
> +
> +       sp_tx_variable_init();
> +       return 0;
> +}
> +
> +static void anx7814_work_func(struct work_struct *work)
> +{
> +       struct anx7814_data *data = container_of(work, struct anx7814_data,
> +                                              work.work);
> +       int workqueu_timer = 0;

spelling: workqueue_timer

> +
> +       if (sp_tx_cur_states() >= STATE_PLAY_BACK)
> +               workqueu_timer = 500;
> +       else
> +               workqueu_timer = 100;
> +       mutex_lock(&data->lock);
> +       slimport_main_process(data);
> +       mutex_unlock(&data->lock);
> +       queue_delayed_work(data->workqueue, &data->work,
> +                          msecs_to_jiffies(workqueu_timer));

The use of a periodic workqueue and a state machine like this seems
like the wrong approach.
The driver should be event driven, and any worker should do whatever
work is required until it completes, rather than arbitrarily chopping
up the tasks into ~100 ms chunks.

> +}
> +
> +static int anx7814_i2c_probe(struct i2c_client *client,
> +                            const struct i2c_device_id *id)
> +{
> +       struct anx7814_data *data;
> +       struct anx7814_platform_data *pdata;
> +       int ret = 0;

In general, I prefer not to see 'ret' variables initialized up here to
a default value.  Rather, only set the ret value as needed.
This let's the compiler catch if there were any 'return' paths that
did not explicitly initialize ret.

> +
> +       if (!i2c_check_functionality(client->adapter,
> +               I2C_FUNC_SMBUS_I2C_BLOCK)) {
> +               dev_err(&client->dev, "i2c bus does not support the device\n");
> +               return -ENODEV;
> +       }
> +
> +       data = devm_kzalloc(&client->dev,
> +                       sizeof(struct anx7814_data),
> +                       GFP_KERNEL);
> +       if (!data)
> +               return -ENOMEM;
> +
> +       pdata = devm_kzalloc(&client->dev,
> +                       sizeof(struct anx7814_platform_data),
> +                       GFP_KERNEL);
> +       if (!pdata)
> +               return -ENOMEM;

If you are always explicitly allocating both anyway, might as well
just embed a "struct anx7814_platform_data" directly in "struct
anx7814_data".

> +
> +       data->pdata = pdata;
> +
> +       data->client = client;
> +       anx7814_client = client;
> +
> +       mutex_init(&data->lock);
> +
> +       ret = anx7814_init_gpio(data);
> +       if (ret) {
> +               dev_err(&client->dev, "failed to initialize gpios\n");
> +               return ret;
> +       }
> +
> +       INIT_DELAYED_WORK(&data->work, anx7814_work_func);
> +
> +       data->workqueue = create_singlethread_workqueue("anx7814_work");
> +       if (data->workqueue == NULL) {
> +               dev_err(&client->dev, "failed to create work queue\n");
> +               return -ENOMEM;
> +       }
> +
> +       ret = anx7814_system_init(data);
> +       if (ret) {
> +               dev_err(&client->dev, "failed to initialize anx7814\n");
> +               goto cleanup;
> +       }
> +
> +       i2c_set_clientdata(client, data);
> +
> +       /* enable driver */
> +       queue_delayed_work(data->workqueue, &data->work, 0);
> +
> +       return 0;
> +
> +cleanup:
> +       destroy_workqueue(data->workqueue);
> +       return ret;
> +}
> +
> +static int anx7814_i2c_remove(struct i2c_client *client)
> +{
> +       struct anx7814_data *data = i2c_get_clientdata(client);
> +
> +       destroy_workqueue(data->workqueue);
> +
> +       return 0;
> +}
> +
> +static int anx7814_i2c_suspend(struct device *dev)
> +{
> +       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
> +       struct anx7814_data *data = i2c_get_clientdata(client);
> +
> +       dev_info(&client->dev, "suspend\n");

dev_dbg (or just remove this, since it is a bit redundant with verbose
suspend logging).

> +       cancel_delayed_work_sync(&data->work);
> +       flush_workqueue(data->workqueue);
> +       sp_tx_hardware_powerdown(data);
> +       sp_tx_clean_state_machine();
> +
> +       return 0;
> +}
> +
> +static int anx7814_i2c_resume(struct device *dev)
> +{
> +       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
> +       struct anx7814_data *anx7814 = i2c_get_clientdata(client);
> +
> +       dev_info(&client->dev, "resume\n");
> +       queue_delayed_work(anx7814->workqueue, &anx7814->work, 0);
> +
> +       return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(anx7814_i2c_pm_ops,
> +                       anx7814_i2c_suspend, anx7814_i2c_resume);
> +
> +static const struct i2c_device_id anx7814_id[] = {
> +       {"anx7814", 0},
> +       { /* sentinel */ }
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, anx7814_id);
> +
> +static const struct of_device_id anx_match_table[] = {
> +       {.compatible = "analogix,anx7814",},
> +       { /* sentinel */ },
> +};
> +
> +MODULE_DEVICE_TABLE(of, anx_match_table);
> +
> +static struct i2c_driver anx7814_driver = {
> +       .driver = {
> +                  .name = "anx7814",
> +                  .pm = &anx7814_i2c_pm_ops,
> +                  .of_match_table = of_match_ptr(anx_match_table),
> +                  },
> +       .probe = anx7814_i2c_probe,
> +       .remove = anx7814_i2c_remove,
> +       .id_table = anx7814_id,
> +};
> +
> +module_i2c_driver(anx7814_driver);
> +
> +MODULE_DESCRIPTION("Slimport  transmitter ANX7814 driver");
> +MODULE_AUTHOR("Junhua Xia <jxia@analogixsemi.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_VERSION("1.1");
> diff --git a/drivers/staging/slimport/slimport.h b/drivers/staging/slimport/slimport.h
> new file mode 100644
> index 0000000..614d746
> --- /dev/null
> +++ b/drivers/staging/slimport/slimport.h
> @@ -0,0 +1,49 @@
> +/*
> + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef _SLIMPORT_H
> +#define _SLIMPORT_H
> +
> +#include <linux/i2c.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +#include <linux/gpio/consumer.h>
> +
> +#define AUX_ERR  1
> +#define AUX_OK   0
> +
> +#define LOG_TAG "SlimPort ANX78XX"
> +
> +struct anx7814_platform_data {
> +       struct gpio_desc *gpiod_pd;
> +       struct gpio_desc *gpiod_reset;
> +       spinlock_t lock;
> +};
> +
> +struct anx7814_data {

Nit: my personal preference would be to drop the "_data":

 struct anx7814  (or struct anx78xx, to match the driver name).


> +       struct i2c_client *client;
> +       struct anx7814_platform_data *pdata;
> +       struct delayed_work work;
> +       struct workqueue_struct *workqueue;
> +       struct mutex lock;
> +};
> +
> +int sp_read_reg(uint8_t slave_addr, uint8_t offset, uint8_t *buf);
> +int sp_write_reg(uint8_t slave_addr, uint8_t offset, uint8_t value);
> +
> +void sp_tx_hardware_poweron(struct anx7814_data *data);
> +void sp_tx_hardware_powerdown(struct anx7814_data *data);
> +
> +#endif
> diff --git a/drivers/staging/slimport/slimport_tx_drv.c b/drivers/staging/slimport/slimport_tx_drv.c
> new file mode 100644
> index 0000000..6fad502
> --- /dev/null
> +++ b/drivers/staging/slimport/slimport_tx_drv.c
> @@ -0,0 +1,3293 @@
> +/*
> + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/types.h>
> +
> +#include "slimport.h"
> +#include "slimport_tx_drv.h"
> +
> +#define XTAL_CLK_M10   pxtal_data[XTAL_27M].xtal_clk_m10
> +#define XTAL_CLK       pxtal_data[XTAL_27M].xtal_clk
> +
> +static u8 sp_tx_test_bw;
> +static bool sp_tx_test_lt;
> +static bool sp_tx_test_edid;
> +
> +static u8 g_changed_bandwidth;
> +static u8 g_hdmi_dvi_status;
> +
> +static u8 g_need_clean_status;
> +
> +static u8 ds_vid_stb_cntr;
> +static u8 hdcp_fail_count;
> +
> +u8 g_edid_break;
> +u8 g_edid_checksum;
> +u8 edid_blocks[256];
> +static u8 g_read_edid_flag;
> +
> +static struct packet_avi sp_tx_packet_avi;
> +static struct packet_spd sp_tx_packet_spd;
> +static struct packet_mpeg sp_tx_packet_mpeg;
> +static struct audio_info_frame sp_tx_audioinfoframe;
> +
> +enum sp_tx_state sp_tx_system_state;
> +
> +enum audio_output_status sp_tx_ao_state;
> +enum video_output_status sp_tx_vo_state;
> +enum sink_connection_status sp_tx_sc_state;
> +enum sp_tx_lt_status sp_tx_lt_state;
> +enum sp_tx_state sp_tx_system_state_bak;
> +enum hdcp_status hcdp_state;
> +
> +const uint chipid_list[] = {
> +       0x7818,
> +       0x7816,
> +       0x7814,
> +       0x7812,
> +       0x7810,
> +       0x7806,
> +       0x7802
> +};
> +
> +struct common_int common_int_status;
> +struct hdmi_rx_int hdmi_rx_int_status;
> +
> +static u8 down_sample_en;
> +
> +static unsigned char sp_i2c_read_byte(unsigned char dev, unsigned char offset);
> +static void hdmi_rx_new_vsi_int(void);

... yeah, this driver needs a lot of work.  All of the above global
state variables need to go away.

> +
> +#define reg_bit_ctl(addr, offset, data, enable) \
> +       do { \
> +               u8 c; \
> +               sp_read_reg(addr, offset, &c); \
> +               if (enable) { \
> +                       if ((c & data) != data) { \
> +                               c |= data; \
> +                               sp_write_reg(addr, offset, c); \
> +                       } \
> +               } else { \
> +                       if ((c & data) == data) { \
> +                               c &= ~data; \
> +                               sp_write_reg(addr, offset, c); \
> +                       } \
> +               } \
> +       } while (0)
> +
> +#define sp_tx_video_mute(enable) \
> +       reg_bit_ctl(TX_P2, VID_CTRL1, VIDEO_MUTE, enable)
> +
> +#define hdmi_rx_mute_audio(enable) \
> +       reg_bit_ctl(RX_P0, RX_MUTE_CTRL, AUD_MUTE, enable)
> +
> +#define hdmi_rx_mute_video(enable) \
> +       reg_bit_ctl(RX_P0, RX_MUTE_CTRL, VID_MUTE, enable)
> +
> +#define sp_tx_addronly_set(enable) \
> +       reg_bit_ctl(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT, enable)
> +
> +#define sp_tx_set_link_bw(bw) \
> +       sp_write_reg(TX_P0, SP_TX_LINK_BW_SET_REG, bw)
> +
> +#define sp_tx_get_link_bw() \
> +       sp_i2c_read_byte(TX_P0, SP_TX_LINK_BW_SET_REG)
> +
> +#define sp_tx_get_pll_lock_status() \
> +       ((sp_i2c_read_byte(TX_P0, TX_DEBUG1) & DEBUG_PLL_LOCK) != 0 ? 1 : 0)
> +
> +#define gen_m_clk_with_downspeading() \
> +       sp_write_reg_or(TX_P0, SP_TX_M_CALCU_CTRL, M_GEN_CLK_SEL)
> +
> +#define gen_m_clk_without_downspeading \
> +       sp_write_reg_and(TX_P0, SP_TX_M_CALCU_CTRL, (~M_GEN_CLK_SEL))
> +
> +#define hdmi_rx_set_hpd(enable) do { \
> +       if ((bool)enable) \
> +               sp_write_reg_or(TX_P2, SP_TX_VID_CTRL3_REG, HPD_OUT); \
> +       else \
> +               sp_write_reg_and(TX_P2, SP_TX_VID_CTRL3_REG, ~HPD_OUT); \
> +       } while (0)
> +
> +#define hdmi_rx_set_termination(enable) do { \
> +       if ((bool)enable) \
> +               sp_write_reg_and(RX_P0, HDMI_RX_TMDS_CTRL_REG7, ~TERM_PD); \
> +       else \
> +               sp_write_reg_or(RX_P0, HDMI_RX_TMDS_CTRL_REG7, TERM_PD); \
> +       } while (0)
> +
> +#define sp_tx_clean_hdcp_status() do { \
> +       sp_write_reg(TX_P0, TX_HDCP_CTRL0, 0x03); \
> +       sp_write_reg_or(TX_P0, TX_HDCP_CTRL0, RE_AUTH); \
> +       usleep_range(2000, 4000); \
> +       pr_info("%s %s : sp_tx_clean_hdcp_status\n", LOG_TAG, __func__); \
> +       } while (0)
> +
> +#define reg_hardware_reset() do { \
> +       sp_write_reg_or(TX_P2, SP_TX_RST_CTRL_REG, HW_RST); \
> +       sp_tx_clean_state_machine(); \
> +       sp_tx_set_sys_state(STATE_SP_INITIALIZED); \
> +       msleep(500); \
> +       } while (0)
> +
> +#define write_dpcd_addr(addrh, addrm, addrl) \
> +       do { \
> +               u8 temp; \
> +               if (sp_i2c_read_byte(TX_P0, AUX_ADDR_7_0) != (u8)addrl) \
> +                       sp_write_reg(TX_P0, AUX_ADDR_7_0, (u8)addrl); \
> +                       if (sp_i2c_read_byte(TX_P0, AUX_ADDR_15_8) \
> +                                               != (u8)addrm) \
> +                               sp_write_reg(TX_P0, \
> +                                       AUX_ADDR_15_8, (u8)addrm); \
> +               sp_read_reg(TX_P0, AUX_ADDR_19_16, &temp); \
> +               if ((u8)(temp & 0x0F)  != ((u8)addrh & 0x0F)) \
> +                       sp_write_reg(TX_P0, AUX_ADDR_19_16, \
> +                               (temp  & 0xF0) | ((u8)addrh)); \
> +       } while (0)
> +
> +#define sp_tx_set_sys_state(ss) \
> +       do { \
> +               pr_info("%s %s : set: clean_status: %x,\n ", \
> +                               LOG_TAG, __func__, (uint)g_need_clean_status); \
> +               if ((sp_tx_system_state >= STATE_LINK_TRAINING) \
> +                                       && (ss < STATE_LINK_TRAINING)) \
> +                       sp_write_reg_or(TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD); \
> +               sp_tx_system_state_bak = sp_tx_system_state; \
> +               sp_tx_system_state = (u8)ss; \
> +               g_need_clean_status = 1; \
> +               print_sys_state(sp_tx_system_state); \
> +       } while (0)
> +
> +#define goto_next_system_state() \
> +       do { \
> +               pr_info("%s %s : next: clean_status: %x,\n ", \
> +                               LOG_TAG, __func__, (uint)g_need_clean_status); \
> +               sp_tx_system_state_bak = sp_tx_system_state; \
> +               sp_tx_system_state++;\
> +               print_sys_state(sp_tx_system_state); \
> +       } while (0)
> +
> +#define redo_cur_system_state() \
> +       do { \
> +               pr_info("%s %s : redo: clean_status: %x,\n ", \
> +                               LOG_TAG, __func__, (uint)g_need_clean_status); \
> +               g_need_clean_status = 1; \
> +               sp_tx_system_state_bak = sp_tx_system_state; \
> +               print_sys_state(sp_tx_system_state); \
> +       } while (0)
> +
> +#define system_state_change_with_case(status) \
> +       do { \
> +               if (sp_tx_system_state >= status) { \
> +                       pr_info("%s %s : change_case: clean_status: %xm,\n ", \
> +                               LOG_TAG, __func__, (uint)g_need_clean_status); \
> +                       if ((sp_tx_system_state >= STATE_LINK_TRAINING) \
> +                                       && (status < STATE_LINK_TRAINING)) \
> +                               sp_write_reg_or(TX_P0, \
> +                                               SP_TX_ANALOG_PD_REG, CH0_PD); \
> +                       g_need_clean_status = 1; \
> +                       sp_tx_system_state_bak = sp_tx_system_state; \
> +                       sp_tx_system_state = (u8)status; \
> +                       print_sys_state(sp_tx_system_state); \
> +               } \
> +       } while (0)
> +
> +#define sp_write_reg_or(address, offset, mask) \
> +       sp_write_reg(address, offset, \
> +               ((unsigned char)sp_i2c_read_byte(address, offset) | (mask)))
> +
> +#define sp_write_reg_and(address, offset, mask) \
> +       sp_write_reg(address, offset, \
> +               ((unsigned char)sp_i2c_read_byte(address, offset) & (mask)))
> +
> +#define sp_write_reg_and_or(address, offset, and_mask, or_mask) \
> +       sp_write_reg(address, offset, \
> +               (((unsigned char)sp_i2c_read_byte(address, offset)) \
> +               & and_mask) | (or_mask))
> +
> +#define sp_write_reg_or_and(address, offset, or_mask, and_mask) \
> +       sp_write_reg(address, offset, \
> +               (((unsigned char)sp_i2c_read_byte(address, offset)) \
> +               | or_mask) & (and_mask))

... and all of the above "function-like macros" should be converted to
type-safe static functions, where applicable.


> +
> +static inline void sp_tx_link_phy_initialization(void)
> +{
> +       sp_write_reg(TX_P2, SP_TX_ANALOG_CTRL0, 0x02);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG0, 0x01);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG10, 0x00);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG1, 0x03);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG11, 0x00);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG2, 0x07);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG12, 0x00);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG3, 0x7f);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG13, 0x00);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG4, 0x71);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG14, 0x0c);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG5, 0x6b);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG15, 0x42);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG6, 0x7f);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG16, 0x1e);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG7, 0x73);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG17, 0x3e);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG8, 0x7f);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG18, 0x72);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG9, 0x7F);
> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG19, 0x7e);
> +}
> +
> +static unsigned char sp_i2c_read_byte(unsigned char dev, unsigned char offset)
> +{
> +       unsigned char temp;
> +
> +       sp_read_reg(dev, offset, &temp);
> +       return temp;
> +}
> +
> +static void hardware_power_ctl(struct anx7814_data *data, u8 enable)
> +{
> +       if (enable == 0)
> +               sp_tx_hardware_powerdown(data);
> +       else
> +               sp_tx_hardware_poweron(data);
> +}
> +
> +void wait_aux_op_finish(u8 *err_flag)
> +{
> +       u8 cnt;
> +       u8 c;
> +
> +       *err_flag = 0;
> +       cnt = 150;
> +       while (sp_i2c_read_byte(TX_P0, AUX_CTRL2) & AUX_OP_EN) {
> +               usleep_range(2000, 4000);
> +               if ((cnt--) == 0) {
> +                       pr_info("%s %s :aux operate failed!\n",
> +                                       LOG_TAG, __func__);

dev_err() for all of these error prints.

> +                       *err_flag = 1;
> +                       break;
> +               }
> +       }
> +
> +       sp_read_reg(TX_P0, SP_TX_AUX_STATUS, &c);
> +       if (c & 0x0F) {
> +               pr_info("%s %s : wait aux operation status %.2x\n",
> +                               LOG_TAG, __func__, (uint)c);
> +               *err_flag = 1;
> +       }
> +}
> +
> +void print_sys_state(u8 ss)
> +{
> +       switch (ss) {
> +       case STATE_WAITTING_CABLE_PLUG:
> +               pr_info("%s %s : -STATE_WAITTING_CABLE_PLUG-\n",
> +                               LOG_TAG, __func__);

dev_dbg() for all of these state transitions.

> +               break;
> +       case STATE_SP_INITIALIZED:
> +               pr_info("%s %s : -STATE_SP_INITIALIZED-\n", LOG_TAG, __func__);
> +               break;
> +       case STATE_SINK_CONNECTION:
> +               pr_info("%s %s : -STATE_SINK_CONNECTION-\n", LOG_TAG, __func__);
> +               break;
> +       case STATE_PARSE_EDID:
> +               pr_info("%s %s : -STATE_PARSE_EDID-\n", LOG_TAG, __func__);
> +               break;
> +       case STATE_LINK_TRAINING:
> +               pr_info("%s %s : -STATE_LINK_TRAINING-\n", LOG_TAG, __func__);
> +               break;
> +       case STATE_VIDEO_OUTPUT:
> +               pr_info("%s %s : -STATE_VIDEO_OUTPUT-\n", LOG_TAG, __func__);
> +               break;
> +       case STATE_HDCP_AUTH:
> +               pr_info("%s %s : -STATE_HDCP_AUTH-\n", LOG_TAG, __func__);
> +               break;
> +       case STATE_AUDIO_OUTPUT:
> +               pr_info("%s %s : -STATE_AUDIO_OUTPUT-\n", LOG_TAG, __func__);
> +               break;
> +       case STATE_PLAY_BACK:
> +               pr_info("%s %s : -STATE_PLAY_BACK-\n", LOG_TAG, __func__);
> +               break;
> +       default:
> +               pr_err("%s %s : system state is error1\n", LOG_TAG, __func__);
> +               break;
> +       }
> +}
> +
> +void sp_tx_rst_aux(void)
> +{
> +       sp_write_reg_or(TX_P2, RST_CTRL2, AUX_RST);
> +       sp_write_reg_and(TX_P2, RST_CTRL2, ~AUX_RST);
> +}
> +
> +u8 sp_tx_aux_dpcdread_bytes(u8 addrh, u8 addrm,
> +               u8 addrl, u8 ccount, u8 *pbuf)
> +{
> +       u8 c, c1, i;
> +       u8 bok;
> +
> +       sp_write_reg(TX_P0, BUF_DATA_COUNT, 0x80);
> +       c = ((ccount - 1) << 4) | 0x09;
> +       sp_write_reg(TX_P0, AUX_CTRL, c);
> +       write_dpcd_addr(addrh, addrm, addrl);
> +       sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN);
> +       usleep_range(2000, 4000);
> +
> +       wait_aux_op_finish(&bok);
> +       if (bok == AUX_ERR) {
> +               pr_err("%s %s : aux read failed\n", LOG_TAG, __func__);
> +               sp_read_reg(TX_P2, SP_TX_INT_STATUS1, &c);
> +               sp_read_reg(TX_P0, TX_DEBUG1, &c1);
> +               if (c1 & POLLING_EN) {
> +                       if (c & POLLING_ERR)
> +                               sp_tx_rst_aux();
> +               } else
> +                       sp_tx_rst_aux();
> +               return AUX_ERR;
> +       }
> +
> +       for (i = 0; i < ccount; i++) {
> +               sp_read_reg(TX_P0, BUF_DATA_0 + i, &c);
> +               *(pbuf + i) = c;
> +               if (i >= MAX_BUF_CNT)
> +                       break;
> +       }
> +       return AUX_OK;
> +}
> +
> +u8 sp_tx_aux_dpcdwrite_bytes(u8 addrh, u8 addrm,
> +               u8 addrl, u8 ccount, u8 *pbuf)
> +{
> +       u8 c, i, ret;
> +
> +       c =  ((ccount - 1) << 4) | 0x08;
> +       sp_write_reg(TX_P0, AUX_CTRL, c);
> +       write_dpcd_addr(addrh, addrm, addrl);
> +       for (i = 0; i < ccount; i++) {
> +               c = *pbuf;
> +               pbuf++;
> +               sp_write_reg(TX_P0, BUF_DATA_0 + i, c);
> +
> +               if (i >= 15)
> +                       break;
> +       }
> +       sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN);
> +       wait_aux_op_finish(&ret);
> +       return ret;
> +}
> +
> +u8 sp_tx_aux_dpcdwrite_byte(u8 addrh, u8 addrm,
> +               u8 addrl, u8 data1)
> +{
> +       u8 ret;
> +
> +       sp_write_reg(TX_P0, AUX_CTRL, 0x08);
> +       write_dpcd_addr(addrh, addrm, addrl);
> +       sp_write_reg(TX_P0, BUF_DATA_0, data1);
> +       sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN);
> +       wait_aux_op_finish(&ret);
> +       return ret;
> +}
> +
> +void slimport_block_power_ctrl(enum sp_tx_power_block sp_tx_pd_block,
> +               u8 power)
> +{
> +       if (power == SP_POWER_ON)
> +               sp_write_reg_and(TX_P2, SP_POWERD_CTRL_REG, (~sp_tx_pd_block));
> +       else
> +               sp_write_reg_or(TX_P2, SP_POWERD_CTRL_REG, (sp_tx_pd_block));
> +        pr_info("%s %s : sp_tx_power_on: %.2x\n",
> +                       LOG_TAG, __func__, (uint)sp_tx_pd_block);
> +}
> +
> +void vbus_power_ctrl(unsigned char on)

I'd just split this into two functions:

anx78xx_vbus_power_on() & anx78xx_vbus_power_off()

> +{
> +       u8 i;
> +
> +       if (on == 0) {
> +               sp_write_reg_and(TX_P2, TX_PLL_FILTER, ~V33_SWITCH_ON);
> +               sp_write_reg_or(TX_P2, TX_PLL_FILTER5,
> +                                       P5V_PROTECT_PD | SHORT_PROTECT_PD);
> +               pr_info("%s %s : 3.3V output disabled\n", LOG_TAG, __func__);
> +       } else {
> +               for (i = 0; i < 5; i++) {
> +                       sp_write_reg_and(TX_P2, TX_PLL_FILTER5,
> +                                       (~P5V_PROTECT_PD & ~SHORT_PROTECT_PD));
> +                       sp_write_reg_or(TX_P2, TX_PLL_FILTER, V33_SWITCH_ON);
> +                       if (!((u8)sp_i2c_read_byte(TX_P2, TX_PLL_FILTER5)
> +                               & 0xc0)) {
> +                               pr_info("%s %s : 3.3V output enabled\n",
> +                                               LOG_TAG, __func__);
> +                               break;
> +                       }
> +
> +                       pr_info("%s %s : VBUS power can not be supplied\n",
> +                               LOG_TAG, __func__);
> +               }
> +       }
> +}
> +
> +void sp_tx_clean_state_machine(void)
> +{
> +       sp_tx_system_state = STATE_WAITTING_CABLE_PLUG;
> +       sp_tx_system_state_bak = STATE_WAITTING_CABLE_PLUG;
> +       sp_tx_sc_state = SC_INIT;
> +       sp_tx_lt_state = LT_INIT;
> +       hcdp_state = HDCP_CAPABLE_CHECK;
> +       sp_tx_vo_state = VO_WAIT_VIDEO_STABLE;
> +       sp_tx_ao_state = AO_INIT;
> +}
> +
> +u8 sp_tx_cur_states(void)
> +{
> +       return sp_tx_system_state;
> +}
> +
> +u8 sp_tx_cur_bw(void)
> +{
> +       return g_changed_bandwidth;
> +}
> +
> +void sp_tx_set_bw(u8 bw)
> +{
> +       g_changed_bandwidth = bw;
> +}
> +
> +void sp_tx_variable_init(void)
> +{
> +       uint i;
> +
> +       sp_tx_system_state = STATE_WAITTING_CABLE_PLUG;
> +       sp_tx_system_state_bak = STATE_WAITTING_CABLE_PLUG;
> +
> +       g_edid_break = 0;
> +       g_read_edid_flag = 0;
> +       g_edid_checksum = 0;
> +       for (i = 0; i < 256; i++)
> +               edid_blocks[i] = 0;
> +
> +       sp_tx_lt_state = LT_INIT;
> +       hcdp_state = HDCP_CAPABLE_CHECK;
> +       g_need_clean_status = 0;
> +       sp_tx_sc_state = SC_INIT;
> +       sp_tx_vo_state = VO_WAIT_VIDEO_STABLE;
> +       sp_tx_ao_state = AO_INIT;
> +       g_changed_bandwidth = LINK_5P4G;
> +       g_hdmi_dvi_status = HDMI_MODE;
> +
> +       sp_tx_test_lt = 0;
> +       sp_tx_test_bw = 0;
> +       sp_tx_test_edid = 0;
> +
> +       ds_vid_stb_cntr = 0;
> +       hdcp_fail_count = 0;
> +
> +}
> +
> +static void hdmi_rx_tmds_phy_initialization(void)
> +{
> +       sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG2, 0xa9);
> +       sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG7, 0x80);
> +
> +       sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG1, 0x90);
> +       sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG6, 0x92);
> +       sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG20, 0xf2);
> +}
> +
> +void hdmi_rx_initialization(void)
> +{
> +       sp_write_reg(RX_P0, RX_MUTE_CTRL, AUD_MUTE | VID_MUTE);
> +       sp_write_reg_or(RX_P0, RX_CHIP_CTRL,
> +               MAN_HDMI5V_DET | PLLLOCK_CKDT_EN | DIGITAL_CKDT_EN);
> +
> +       sp_write_reg_or(RX_P0, RX_SRST, HDCP_MAN_RST | SW_MAN_RST |
> +               TMDS_RST | VIDEO_RST);
> +       sp_write_reg_and(RX_P0, RX_SRST, (~HDCP_MAN_RST) & (~SW_MAN_RST) &
> +               (~TMDS_RST) & (~VIDEO_RST));
> +
> +       sp_write_reg_or(RX_P0, RX_AEC_EN0, AEC_EN06 | AEC_EN05);
> +       sp_write_reg_or(RX_P0, RX_AEC_EN2, AEC_EN21);
> +       sp_write_reg_or(RX_P0, RX_AEC_CTRL, AVC_EN | AAC_OE | AAC_EN);
> +
> +       sp_write_reg_and(RX_P0, RX_SYS_PWDN1, ~PWDN_CTRL);
> +
> +       sp_write_reg_or(RX_P0, RX_VID_DATA_RNG, R2Y_INPUT_LIMIT);
> +       sp_write_reg(RX_P0, 0x65, 0xc4);
> +       sp_write_reg(RX_P0, 0x66, 0x18);
> +
> +       sp_write_reg(TX_P0, TX_EXTRA_ADDR, 0x50); /* enable DDC stretch */
> +
> +       hdmi_rx_tmds_phy_initialization();
> +       hdmi_rx_set_hpd(0);
> +       hdmi_rx_set_termination(0);
> +       pr_info("%s %s : HDMI Rx is initialized...\n", LOG_TAG, __func__);
> +}
> +
> +struct clock_data const pxtal_data[XTAL_CLK_NUM] = {

static const struct clock_data pxtal_data[] = {

Also, if this is an anx78xx specific type, it should have a name like
"struct anx78xx_clock_data".

> +       {19, 192},
> +       {24, 240},
> +       {25, 250},
> +       {26, 260},
> +       {27, 270},
> +       {38, 384},
> +       {52, 520},
> +       {27, 270},
> +};
> +
> +void xtal_clk_sel(void)
> +{
> +       pr_info("%s %s : define XTAL_CLK:  %x\n ",
> +                       LOG_TAG, __func__, (uint)XTAL_27M);
> +       sp_write_reg_and_or(TX_P2,
> +                       TX_ANALOG_DEBUG2, (~0x3c), 0x3c & (XTAL_27M << 2));
> +       sp_write_reg(TX_P0, 0xEC, (u8)(((uint)XTAL_CLK_M10)));
> +       sp_write_reg(TX_P0, 0xED,
> +               (u8)(((uint)XTAL_CLK_M10 & 0xFF00) >> 2) | XTAL_CLK);
> +
> +       sp_write_reg(TX_P0,
> +                       I2C_GEN_10US_TIMER0, (u8)(((uint)XTAL_CLK_M10)));
> +       sp_write_reg(TX_P0, I2C_GEN_10US_TIMER1,
> +                       (u8)(((uint)XTAL_CLK_M10 & 0xFF00) >> 8));
> +       sp_write_reg(TX_P0, 0xBF, (u8)(((uint)XTAL_CLK - 1)));
> +
> +       sp_write_reg_and_or(RX_P0, 0x49, 0x07,
> +                       (u8)(((((uint)XTAL_CLK) >> 1) - 2) << 3));
> +
> +}
> +
> +void sp_tx_initialization(void)
> +{
> +       sp_write_reg(TX_P0, AUX_CTRL2, 0x30);
> +       sp_write_reg_or(TX_P0, AUX_CTRL2, 0x08);
> +
> +       sp_write_reg_and(TX_P0, TX_HDCP_CTRL, (~AUTO_EN) & (~AUTO_START));
> +       sp_write_reg(TX_P0, OTP_KEY_PROTECT1, OTP_PSW1);
> +       sp_write_reg(TX_P0, OTP_KEY_PROTECT2, OTP_PSW2);
> +       sp_write_reg(TX_P0, OTP_KEY_PROTECT3, OTP_PSW3);
> +       sp_write_reg_or(TX_P0, HDCP_KEY_CMD, DISABLE_SYNC_HDCP);
> +       sp_write_reg(TX_P2, SP_TX_VID_CTRL8_REG, VID_VRES_TH);
> +
> +       sp_write_reg(TX_P0, HDCP_AUTO_TIMER, HDCP_AUTO_TIMER_VAL);
> +       sp_write_reg_or(TX_P0, TX_HDCP_CTRL, LINK_POLLING);
> +
> +       sp_write_reg_or(TX_P0, TX_LINK_DEBUG, M_VID_DEBUG);
> +       sp_write_reg_or(TX_P2, TX_ANALOG_DEBUG2, POWERON_TIME_1P5MS);
> +
> +       xtal_clk_sel();
> +       sp_write_reg(TX_P0, AUX_DEFER_CTRL, 0x8C);
> +
> +       sp_write_reg_or(TX_P0, TX_DP_POLLING, AUTO_POLLING_DISABLE);
> +       /*
> +        * Short the link intergrity check timer to speed up bstatus
> +        * polling for HDCP CTS item 1A-07
> +        */
> +       sp_write_reg(TX_P0, SP_TX_LINK_CHK_TIMER, 0x1d);
> +       sp_write_reg_or(TX_P0, TX_MISC, EQ_TRAINING_LOOP);
> +
> +       sp_write_reg_or(TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD);
> +
> +       sp_write_reg(TX_P2, SP_TX_INT_CTRL_REG, 0X01);
> +       /* disable HDCP mismatch function for VGA dongle */
> +       sp_tx_link_phy_initialization();
> +       gen_m_clk_with_downspeading();
> +
> +       down_sample_en = 0;
> +}
> +
> +bool slimport_chip_detect(struct anx7814_data *data)
> +{
> +       uint16_t id;
> +       uint8_t idh = 0, idl = 0;
> +       int i;
> +
> +       hardware_power_ctl(data, 1);
> +
> +       /* check chip id */
> +       sp_read_reg(TX_P2, SP_TX_DEV_IDL_REG, &idl);
> +       sp_read_reg(TX_P2, SP_TX_DEV_IDH_REG, &idh);
> +       id = idl | (idh << 8);
> +
> +       pr_info("%s %s : CHIPID: ANX%x\n", LOG_TAG, __func__, id & 0xffff);
> +       for (i = 0; i < sizeof(chipid_list) / sizeof(uint16_t); i++) {
> +               if (id == chipid_list[i])
> +                       return 1;
> +       }
> +       return 0;

bool functions should return "true" and "false".

> +}
> +
> +void slimport_waitting_cable_plug_process(struct anx7814_data *data)

spelling: "_waiting_"

> +{
> +       sp_tx_variable_init();
> +       hardware_power_ctl(data, 1);
> +       goto_next_system_state();
> +}
> +
> +/*
> + * Check if it is ANALOGIX dongle.
> + */
> +unsigned char ANX_OUI[3] = {0x00, 0x22, 0xB9};

static const u8

> +
> +unsigned char is_anx_dongle(void)
> +{
> +       unsigned char buf[3];
> +
> +       /* 0x0500~0x0502: BRANCH_IEEE_OUI */
> +       sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x00, 3, buf);
> +       if (buf[0] == ANX_OUI[0] && buf[1] == ANX_OUI[1]
> +           && buf[2] == ANX_OUI[2])

memcmp()


> +               return 1;
> +
> +       return 0;
> +}
> +
> +void sp_tx_get_rx_bw(unsigned char *bw)
> +{
> +       u8 data_buf[4];
> +       /*
> +        * When ANX dongle connected, if CHIP_ID = 0x7750, bandwidth is 6.75G,
> +        * ecause ANX7750 DPCD 0x052x was not available.

"because"

> +        */
> +       if (is_anx_dongle()) {
> +               sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x03, 0x04, data_buf);
> +               if ((data_buf[0] == 0x37) && (data_buf[1] == 0x37)
> +                       && (data_buf[2] == 0x35) && (data_buf[3] == 0x30))

What are these magic numbers?

> +                       *bw = LINK_6P75G;
> +               else
> +                       sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x21, 1, bw);
> +               /* just for Debug */
> +               *bw = LINK_6P75G;

You just set this twice?

> +       } else

Use '{}' on both sides of the else:

  } else {

> +               sp_tx_aux_dpcdread_bytes(0x00, 0x00, DPCD_MAX_LINK_RATE, 1, bw);
> +}
> +
> +static u8 sp_tx_get_cable_type(enum cable_type_status det_cable_type_state)
> +{
> +       u8 ds_port_preset;
> +       u8 aux_status;
> +       u8 data_buf[16];
> +       u8 cur_cable_type;
> +
> +       ds_port_preset = 0;
> +       cur_cable_type = DWN_STRM_IS_NULL;
> +
> +       aux_status =
> +               sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0x05, 1, &ds_port_preset);
> +       pr_info("%s %s : DPCD 0x005: %x\n",
> +                       LOG_TAG, __func__, (int)ds_port_preset);
> +
> +       switch (det_cable_type_state) {
> +       case CHECK_AUXCH:
> +               if (AUX_OK == aux_status) {
> +                       sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0, 0x0c, data_buf);
> +                       det_cable_type_state = GETTED_CABLE_TYPE;
> +               } else {
> +                       msleep(50);
> +                       pr_err("%s %s :  AUX access error\n",
> +                                       LOG_TAG, __func__);

Why the delay just to print an error message?

  dev_err()

> +                       break;
> +               }
> +       case GETTED_CABLE_TYPE:
> +               switch ((ds_port_preset  & (_BIT1 | _BIT2)) >> 1) {
> +               case 0x00:
> +                       cur_cable_type = DWN_STRM_IS_DIGITAL;
> +                       pr_info("%s %s : Downstream is DP dongle.\n",
> +                                       LOG_TAG, __func__);
> +                       break;
> +               case 0x01:
> +               case 0x03:
> +                       cur_cable_type = DWN_STRM_IS_ANALOG;
> +                       pr_info("%s %s : Downstream is VGA dongle.\n",
> +                                       LOG_TAG, __func__);
> +                       break;
> +               case 0x02:
> +                       cur_cable_type = DWN_STRM_IS_HDMI;
> +                       pr_info("%s %s : Downstream is HDMI dongle.\n",
> +                                       LOG_TAG, __func__);
> +                       break;
> +               default:
> +                       cur_cable_type = DWN_STRM_IS_NULL;
> +                       pr_err("%s %s : Downstream can not recognized.\n",
> +                                       LOG_TAG, __func__);
> +                       break;
> +               }
> +       default:
> +               break;
> +       }
> +       return cur_cable_type;
> +}
> +
> +u8 sp_tx_get_hdmi_connection(void)
> +{
> +       u8 c;
> +
> +       if (AUX_OK != sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x18, 1, &c))

In the kernel, the constant is usually on the other side of the !=, like this:

if (sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x18, 1, &c) != AUX_OK)



> +               return 0;
> +
> +       if ((c & 0x41) == 0x41)

magic number?

> +               return 1;
> +       else
> +               return 0;
> +
> +}
> +
> +u8 sp_tx_get_vga_connection(void)
> +{
> +       u8 c;
> +
> +       if (AUX_OK !=
> +               sp_tx_aux_dpcdread_bytes(0x00, 0x02, DPCD_SINK_COUNT, 1, &c)) {
> +               pr_err("%s %s : aux error.\n", LOG_TAG, __func__);
> +               return 0;
> +       }
> +
> +       if (c & 0x01)
> +               return 1;
> +       else
> +               return 0;
> +}
> +
> +u8 sp_tx_get_dp_connection(void)
> +{
> +       u8 c;
> +
> +       if (AUX_OK !=
> +               sp_tx_aux_dpcdread_bytes(0x00, 0x02, DPCD_SINK_COUNT, 1, &c))
> +               return 0;
> +
> +       if (c & 0x1f) {
> +               sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0x04, 1, &c);
> +               if (c & 0x20) {
> +                       sp_tx_aux_dpcdread_bytes(0x00, 0x06, 0x00, 1, &c);
> +                       /*
> +                        * Bit 5 = SET_DN_DEVICE_DP_PWR_5V
> +                        * Bit 6 = SET_DN_DEVICE_DP_PWR_12V
> +                        *  Bit 7 = SET_DN_DEVICE_DP_PWR_18V
> +                        */
> +                       c = c & 0x1F;
> +                       sp_tx_aux_dpcdwrite_byte(0x00, 0x06, 0x00, c | 0x20);
> +               }
> +               return 1;
> +       } else
> +               return 0;
> +}
> +
> +u8 sp_tx_get_downstream_connection(void)
> +{
> +       return sp_tx_get_dp_connection();
> +}
> +
> +void slimport_sink_connection(void)
> +{

The whole "state machine" in this function seems entirely unnecessary.
Just do all required hotplug actions sequentially in a worker,
triggered from a hotplug event.

> +       switch (sp_tx_sc_state) {
> +       case SC_INIT:
> +               sp_tx_sc_state++;
> +       case SC_CHECK_CABLE_TYPE:
> +       case SC_WAITTING_CABLE_TYPE:
> +       default:
> +               if (sp_tx_get_cable_type(CHECK_AUXCH) == DWN_STRM_IS_NULL) {
> +                       sp_tx_sc_state++;
> +                       if (sp_tx_sc_state >= SC_WAITTING_CABLE_TYPE) {
> +                               sp_tx_sc_state = SC_NOT_CABLE;
> +                               pr_info("%s %s : Can not get cable type!\n",
> +                                               LOG_TAG, __func__);
> +                       }
> +                       break;
> +               }
> +
> +               sp_tx_sc_state = SC_SINK_CONNECTED;
> +       case SC_SINK_CONNECTED:
> +               if (sp_tx_get_downstream_connection())
> +                       goto_next_system_state();
> +               break;
> +       case SC_NOT_CABLE:
> +               vbus_power_ctrl(0);
> +               reg_hardware_reset();
> +               break;
> +       }
> +}
> +
> +/******************start EDID process********************/
> +void sp_tx_enable_video_input(u8 enable)
> +{
> +       u8 c;
> +
> +       sp_read_reg(TX_P2, VID_CTRL1, &c);
> +       if (enable) {
> +               if ((c & VIDEO_EN) != VIDEO_EN) {

The check here doesn't buy you much.
Just always set/clear the enable bit.

> +                       c = (c & 0xf7) | VIDEO_EN;
> +                       sp_write_reg(TX_P2, VID_CTRL1, c);
> +                       pr_info("%s %s : Slimport Video is enabled!\n",
> +                                       LOG_TAG, __func__);
> +               }
> +       } else {
> +               if ((c & VIDEO_EN) == VIDEO_EN) {
> +                       c &= ~VIDEO_EN;
> +                       sp_write_reg(TX_P2, VID_CTRL1, c);
> +                       pr_info("%s %s : Slimport Video is disabled!\n",
> +                                       LOG_TAG, __func__);
> +               }
> +       }
> +}
> +
> +static u8 read_dvi_hdmi_mode(void)
> +{
> +       return 1;
> +}
> +
> +static u8 get_edid_detail(u8 *data_buf)
> +{
> +       uint pixclock_edid;

u16 perhaps?

> +
> +       pixclock_edid = ((((uint)data_buf[1] << 8))
> +                       | ((uint)data_buf[0] & 0xFF));
> +       if (pixclock_edid <= 5300)
> +               return LINK_1P62G;
> +       else if ((5300 < pixclock_edid) && (pixclock_edid <= 8900))
> +               return LINK_2P7G;
> +       else if ((8900 < pixclock_edid) && (pixclock_edid <= 18000))
> +               return LINK_5P4G;
> +       else
> +               return LINK_6P75G;
> +}
> +

[snip...]

> +
> diff --git a/drivers/staging/slimport/slimport_tx_drv.h b/drivers/staging/slimport/slimport_tx_drv.h
> new file mode 100644
> index 0000000..9aaf47d
> --- /dev/null
> +++ b/drivers/staging/slimport/slimport_tx_drv.h
> @@ -0,0 +1,254 @@
> +/*
> + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef _SP_TX_DRV_H
> +#define _SP_TX_DRV_H
> +
> +#include "slimport.h"
> +#include "slimport_tx_reg.h"
> +
> +#define FW_VERSION     0x22
> +
> +#define _BIT0          0x01
> +#define _BIT1          0x02
> +#define _BIT2          0x04
> +#define _BIT3          0x08
> +#define _BIT4          0x10
> +#define _BIT5          0x20
> +#define _BIT6          0x40
> +#define _BIT7          0x80

BIT() already exists.

[snip...]

Ok, enough for now :-).

I'd be happy to review more in detail after you:
 (1) clean up the typos, and little nits above
 (2) move to the drm/bridge directory
 (3) rename the files, variables, types, etc. to anx78xx
 (4) plumb through the context struct to all functions that act on the device
 (5) use proper messaging (dev_ rather than pr_, _dbg/_err rather than _info)

I think replacing the state machine with an event-driven approach can
wait for a future round of review.

-Dan

On Mon, Sep 7, 2015 at 2:46 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
> On Mon, Sep 07, 2015 at 07:41:08AM +0200, Enric Balletbo Serra wrote:
>> 2015-09-07 1:27 GMT+02:00 Greg KH <gregkh@linuxfoundation.org>:
>> > On Sun, Sep 06, 2015 at 11:14:02PM +0200, Enric Balletbo i Serra wrote:
>> >> The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter
>> >> designed for portable devices.
>> >>
>> >> This driver adds initial support and supports HDMI to DP pass-through mode.
>> >>
>> >> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>> >> ---
>> >>  drivers/staging/Kconfig                    |    2 +
>> >>  drivers/staging/Makefile                   |    1 +
>> >>  drivers/staging/slimport/Kconfig           |    7 +
>> >>  drivers/staging/slimport/Makefile          |    4 +
>> >>  drivers/staging/slimport/slimport.c        |  301 +++
>> >>  drivers/staging/slimport/slimport.h        |   49 +
>> >>  drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
>> >>  drivers/staging/slimport/slimport_tx_drv.h |  254 +++
>> >>  drivers/staging/slimport/slimport_tx_reg.h |  786 +++++++
>> >
>> > Why is this a staging driver?
>> > What prevents it from being merged into the "real" part of the kernel
>> > tree?
>> >
>>
>> I'll be glad to move the driver to their subsystem if you think it's a
>> the better place. Basically there are two reasons why I send the
>> driver to the staging directory. The first one is because my test
>> environment is a bit limited, with my environment I can only test the
>> HDMI to DisplayPort pass-through mode so the driver builds but it's
>> partially tested. The second one is that I expect I'll need to
>> refactor some code, specially in slimport_tx_drv.c file to be
>> accepted, I decided not change too much this file from the original to
>> not break the functionality, so I thought that will be better send
>> first to the staging driver to have first reviews.
>>
>> > All staging drivers need a TODO file, listing what needs to be done and
>> > who is in charge of it.  I can't take this without that added.
>> >
>>
>> ok, I'll add in the next series once received some feedback (or move
>> to the video subsystem)
>
> I suggest trying to get it merged "properly" first before having to
> fall-back to the staging subsystem.
>
> thanks,
>
> greg k-h
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix.
  2015-09-09  3:38         ` Daniel Kurtz
@ 2015-09-09  7:10           ` Enric Balletbo Serra
  0 siblings, 0 replies; 9+ messages in thread
From: Enric Balletbo Serra @ 2015-09-09  7:10 UTC (permalink / raw)
  To: Daniel Kurtz
  Cc: devel, Greg KH, linux-kernel@vger.kernel.org, Sjoerd Simons,
	Javier Martinez Canillas, span, Nathan Chung, dri-devel

Hi Dan,

Many thanks for this first review.

2015-09-09 5:38 GMT+02:00 Daniel Kurtz <djkurtz@chromium.org>:
> Hi Eric,
>
> Thanks for starting to upstream this Analogix Slimport driver!
> As Greg says, please move this driver to its intended directory, I presume:
> /drivers/gpu/drm/bridge
>

I sent yesterday another version moving the driver. I'm not sure if
you were aware. In the second version I moved the driver to
drivers/gpu/drm/i2c instead of drivers/gpu/drm/bridge. Do you think
bridge is the better place ? If so I'll move to bridge directory. I
had doubts about it.

> And when you submit, use get_maintainer.pl to add the proper reviewers
> and lists.
> At present, you have no DRM folks, nor dri-devel, so you probably
> won't receive any additional feedback on this version, since the
> relevant folks have not seen your emails.
>
> Some more very detailed feedback inline...
>
> On Sep 7, 2015 05:15, "Enric Balletbo i Serra" <eballetbo@gmail.com> wrote:
>>
>> The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter
>> designed for portable devices.
>>
>> This driver adds initial support and supports HDMI to DP pass-through mode.
>>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>> ---
>>  drivers/staging/Kconfig                    |    2 +
>>  drivers/staging/Makefile                   |    1 +
>>  drivers/staging/slimport/Kconfig           |    7 +
>>  drivers/staging/slimport/Makefile          |    4 +
>>  drivers/staging/slimport/slimport.c        |  301 +++
>>  drivers/staging/slimport/slimport.h        |   49 +
>>  drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
>>  drivers/staging/slimport/slimport_tx_drv.h |  254 +++
>>  drivers/staging/slimport/slimport_tx_reg.h |  786 +++++++
>>  9 files changed, 4697 insertions(+)
>>  create mode 100644 drivers/staging/slimport/Kconfig
>>  create mode 100644 drivers/staging/slimport/Makefile
>>  create mode 100644 drivers/staging/slimport/slimport.c
>>  create mode 100644 drivers/staging/slimport/slimport.h
>>  create mode 100644 drivers/staging/slimport/slimport_tx_drv.c
>>  create mode 100644 drivers/staging/slimport/slimport_tx_drv.h
>>  create mode 100644 drivers/staging/slimport/slimport_tx_reg.h
>>
>> diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
>> index e29293c..24ccd7c 100644
>> --- a/drivers/staging/Kconfig
>> +++ b/drivers/staging/Kconfig
>> @@ -110,4 +110,6 @@ source "drivers/staging/wilc1000/Kconfig"
>>
>>  source "drivers/staging/most/Kconfig"
>>
>> +source "drivers/staging/slimport/Kconfig"
>> +
>>  endif # STAGING
>> diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
>> index 50824dd..942e886 100644
>> --- a/drivers/staging/Makefile
>> +++ b/drivers/staging/Makefile
>> @@ -47,3 +47,4 @@ obj-$(CONFIG_FB_TFT)          += fbtft/
>>  obj-$(CONFIG_FSL_MC_BUS)       += fsl-mc/
>>  obj-$(CONFIG_WILC1000)         += wilc1000/
>>  obj-$(CONFIG_MOST)             += most/
>> +obj-$(CONFIG_SLIMPORT_ANX78XX) += slimport/
>> diff --git a/drivers/staging/slimport/Kconfig b/drivers/staging/slimport/Kconfig
>> new file mode 100644
>> index 0000000..f5233ef
>> --- /dev/null
>> +++ b/drivers/staging/slimport/Kconfig
>> @@ -0,0 +1,7 @@
>> +config SLIMPORT_ANX78XX
>
> I think the "SLIMPORT_" here is a bit overkill, and just adds to
> confusion over what name to use where.  I'd recommend just
> CONFIG_ANX78XX.
>
> Likewise, for consistency, the rename the files as "anx78xx*" instead
> of "slimport*".
>
>> +       tristate "Analogix Slimport transmitter ANX78XX support"
>> +       help
>> +               Slimport Transmitter is a HD video transmitter chip
>> +               over micro-USB connector for smartphone device.
>> +
>> +
>> diff --git a/drivers/staging/slimport/Makefile b/drivers/staging/slimport/Makefile
>> new file mode 100644
>> index 0000000..9bb6ce2
>> --- /dev/null
>> +++ b/drivers/staging/slimport/Makefile
>> @@ -0,0 +1,4 @@
>> +obj-${CONFIG_SLIMPORT_ANX78XX} :=  anx78xx.o
>> +
>> +anx78xx-y := slimport.o
>> +anx78xx-y += slimport_tx_drv.o
>> diff --git a/drivers/staging/slimport/slimport.c b/drivers/staging/slimport/slimport.c
>> new file mode 100644
>> index 0000000..95c5114
>> --- /dev/null
>> +++ b/drivers/staging/slimport/slimport.c
>> @@ -0,0 +1,301 @@
>> +/*
>> + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 and
>> + * only version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/types.h>
>> +#include <linux/err.h>
>> +#include <linux/async.h>
>> +#include <linux/of_gpio.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/delay.h>
>> +
>> +#include "slimport.h"
>> +#include "slimport_tx_drv.h"
>> +
>> +/* HDCP switch for external block */
>> +/* external_block_en = 1: enable, 0: disable */
>
> This comment is a bit superfluous.
>
>> +int external_block_en = 1;
>> +
>> +struct i2c_client *anx7814_client;
>
> A single global client isn't going to work.  It is easy to imagine a
> machine with more than one anx78xx, requiring multiple instances of
> the driver and hence multiple i2c clients.
>
> Also, you'll want to be a bit more consistent with naming; is the
> driver for anx78xx?  Or anx7814 only?
>
>> +
>> +int sp_read_reg_byte(uint8_t slave_addr, uint8_t offset)
>> +{
>> +       int ret = 0;
>> +       struct device *dev = &anx7814_client->dev;
>
> The use of global anx7814_client has ramifications throughout this
> whole driver. direct
> Please re-write all of these transaction functions (and their callers)
> should to take a context struct pointer as their first parameter.
>
>> +
>> +       anx7814_client->addr = (slave_addr >> 1);
>> +       ret = i2c_smbus_read_byte_data(anx7814_client, offset);
>> +       if (ret < 0) {
>> +               dev_err(dev, "%s: failed to read i2c addr=%x\n", LOG_TAG,
>> +                     slave_addr);
>> +               return ret;
>> +       }
>> +       return 0;
>
> Don't you need to return the actual byte that was read (ret)?
>
>> +}
>> +
>> +int sp_read_reg(uint8_t slave_addr, uint8_t offset, uint8_t *buf)
>> +{
>> +       int ret = 0;
>> +       struct device *dev = &anx7814_client->dev;
>> +
>> +       anx7814_client->addr = (slave_addr >> 1);
>> +       ret = i2c_smbus_read_byte_data(anx7814_client, offset);
>> +       if (ret < 0) {
>> +               dev_err(dev, "%s: failed to read i2c addr=%x\n", LOG_TAG,
>> +                      slave_addr);
>> +               return ret;
>> +       }
>> +       *buf = (uint8_t) ret;
>> +
>> +       return 0;
>> +}
>> +
>> +int sp_write_reg(uint8_t slave_addr, uint8_t offset, uint8_t value)
>> +{
>> +       int ret = 0;
>> +       struct device *dev = &anx7814_client->dev;
>> +
>> +       anx7814_client->addr = (slave_addr >> 1);
>> +       ret = i2c_smbus_write_byte_data(anx7814_client, offset, value);
>> +       if (ret < 0) {
>> +               dev_err(dev, "%s: failed to write i2c addr=%x\n", LOG_TAG,
>> +                      slave_addr);
>> +       }
>> +       return ret;
>> +}
>> +
>> +void sp_tx_hardware_poweron(struct anx7814_data *data)
>
> nit: another personal preference, I prefer to use the specific device
> as the local parameter name, rather than the generic "data".
> So it would look something like:
>
>   void anx7814_tx_hardware_poweron(struct anx7814 *anx7814)
>
>> +{
>> +       struct device *dev = &data->client->dev;
>> +       struct anx7814_platform_data *pdata = data->pdata;
>> +
>> +       gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
>> +       usleep_range(1000, 2000);
>> +
>> +       gpiod_set_value_cansleep(pdata->gpiod_pd, 0);
>> +       usleep_range(1000, 2000);
>> +
>> +       gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
>> +
>> +       dev_info(dev, "%s: anx7814 power on\n", LOG_TAG);
>
> This kind of verbose logging should be dev_dbg(
>
>> +}
>> +
>> +void sp_tx_hardware_powerdown(struct anx7814_data *data)
>> +{
>> +       struct device *dev = &data->client->dev;
>> +       struct anx7814_platform_data *pdata = data->pdata;
>> +
>> +       gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
>> +       usleep_range(1000, 2000);
>> +
>> +       gpiod_set_value_cansleep(pdata->gpiod_pd, 1);
>> +       usleep_range(1000, 2000);
>> +
>> +       dev_info(dev, "%s: anx7814 power down\n", LOG_TAG);
>> +}
>> +
>> +static int anx7814_init_gpio(struct anx7814_data *data)
>> +{
>> +       struct device *dev = &data->client->dev;
>> +       struct anx7814_platform_data *pdata = data->pdata;
>> +       int ret;
>> +
>> +       /* gpio for chip power down */
>> +       pdata->gpiod_pd = devm_gpiod_get(dev, "pd", GPIOD_OUT_HIGH);
>> +       if (IS_ERR(pdata->gpiod_pd)) {
>> +               dev_err(dev, "unable to claim pd gpio\n");
>> +               ret = PTR_ERR(pdata->gpiod_pd);
>> +               return ret;
>> +       }
>> +
>> +       /* gpio for chip reset */
>> +       pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
>> +       if (IS_ERR(pdata->gpiod_reset)) {
>> +               dev_err(dev, "unable to claim reset gpio\n");
>> +               ret = PTR_ERR(pdata->gpiod_reset);
>> +               return ret;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int anx7814_system_init(struct anx7814_data *data)
>> +{
>> +       struct device *dev = &data->client->dev;
>> +
>> +       int ret = 0;
>> +
>> +       ret = slimport_chip_detect(data);
>> +       if (ret == 0) {
>> +               sp_tx_hardware_powerdown(data);
>> +               dev_err(dev, "failed to detect anx7814\n");
>> +               return -ENODEV;
>> +       }
>> +
>> +       sp_tx_variable_init();
>> +       return 0;
>> +}
>> +
>> +static void anx7814_work_func(struct work_struct *work)
>> +{
>> +       struct anx7814_data *data = container_of(work, struct anx7814_data,
>> +                                              work.work);
>> +       int workqueu_timer = 0;
>
> spelling: workqueue_timer
>
>> +
>> +       if (sp_tx_cur_states() >= STATE_PLAY_BACK)
>> +               workqueu_timer = 500;
>> +       else
>> +               workqueu_timer = 100;
>> +       mutex_lock(&data->lock);
>> +       slimport_main_process(data);
>> +       mutex_unlock(&data->lock);
>> +       queue_delayed_work(data->workqueue, &data->work,
>> +                          msecs_to_jiffies(workqueu_timer));
>
> The use of a periodic workqueue and a state machine like this seems
> like the wrong approach.
> The driver should be event driven, and any worker should do whatever
> work is required until it completes, rather than arbitrarily chopping
> up the tasks into ~100 ms chunks.
>
>> +}
>> +
>> +static int anx7814_i2c_probe(struct i2c_client *client,
>> +                            const struct i2c_device_id *id)
>> +{
>> +       struct anx7814_data *data;
>> +       struct anx7814_platform_data *pdata;
>> +       int ret = 0;
>
> In general, I prefer not to see 'ret' variables initialized up here to
> a default value.  Rather, only set the ret value as needed.
> This let's the compiler catch if there were any 'return' paths that
> did not explicitly initialize ret.
>
>> +
>> +       if (!i2c_check_functionality(client->adapter,
>> +               I2C_FUNC_SMBUS_I2C_BLOCK)) {
>> +               dev_err(&client->dev, "i2c bus does not support the device\n");
>> +               return -ENODEV;
>> +       }
>> +
>> +       data = devm_kzalloc(&client->dev,
>> +                       sizeof(struct anx7814_data),
>> +                       GFP_KERNEL);
>> +       if (!data)
>> +               return -ENOMEM;
>> +
>> +       pdata = devm_kzalloc(&client->dev,
>> +                       sizeof(struct anx7814_platform_data),
>> +                       GFP_KERNEL);
>> +       if (!pdata)
>> +               return -ENOMEM;
>
> If you are always explicitly allocating both anyway, might as well
> just embed a "struct anx7814_platform_data" directly in "struct
> anx7814_data".
>
>> +
>> +       data->pdata = pdata;
>> +
>> +       data->client = client;
>> +       anx7814_client = client;
>> +
>> +       mutex_init(&data->lock);
>> +
>> +       ret = anx7814_init_gpio(data);
>> +       if (ret) {
>> +               dev_err(&client->dev, "failed to initialize gpios\n");
>> +               return ret;
>> +       }
>> +
>> +       INIT_DELAYED_WORK(&data->work, anx7814_work_func);
>> +
>> +       data->workqueue = create_singlethread_workqueue("anx7814_work");
>> +       if (data->workqueue == NULL) {
>> +               dev_err(&client->dev, "failed to create work queue\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       ret = anx7814_system_init(data);
>> +       if (ret) {
>> +               dev_err(&client->dev, "failed to initialize anx7814\n");
>> +               goto cleanup;
>> +       }
>> +
>> +       i2c_set_clientdata(client, data);
>> +
>> +       /* enable driver */
>> +       queue_delayed_work(data->workqueue, &data->work, 0);
>> +
>> +       return 0;
>> +
>> +cleanup:
>> +       destroy_workqueue(data->workqueue);
>> +       return ret;
>> +}
>> +
>> +static int anx7814_i2c_remove(struct i2c_client *client)
>> +{
>> +       struct anx7814_data *data = i2c_get_clientdata(client);
>> +
>> +       destroy_workqueue(data->workqueue);
>> +
>> +       return 0;
>> +}
>> +
>> +static int anx7814_i2c_suspend(struct device *dev)
>> +{
>> +       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
>> +       struct anx7814_data *data = i2c_get_clientdata(client);
>> +
>> +       dev_info(&client->dev, "suspend\n");
>
> dev_dbg (or just remove this, since it is a bit redundant with verbose
> suspend logging).
>
>> +       cancel_delayed_work_sync(&data->work);
>> +       flush_workqueue(data->workqueue);
>> +       sp_tx_hardware_powerdown(data);
>> +       sp_tx_clean_state_machine();
>> +
>> +       return 0;
>> +}
>> +
>> +static int anx7814_i2c_resume(struct device *dev)
>> +{
>> +       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
>> +       struct anx7814_data *anx7814 = i2c_get_clientdata(client);
>> +
>> +       dev_info(&client->dev, "resume\n");
>> +       queue_delayed_work(anx7814->workqueue, &anx7814->work, 0);
>> +
>> +       return 0;
>> +}
>> +
>> +static SIMPLE_DEV_PM_OPS(anx7814_i2c_pm_ops,
>> +                       anx7814_i2c_suspend, anx7814_i2c_resume);
>> +
>> +static const struct i2c_device_id anx7814_id[] = {
>> +       {"anx7814", 0},
>> +       { /* sentinel */ }
>> +};
>> +
>> +MODULE_DEVICE_TABLE(i2c, anx7814_id);
>> +
>> +static const struct of_device_id anx_match_table[] = {
>> +       {.compatible = "analogix,anx7814",},
>> +       { /* sentinel */ },
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, anx_match_table);
>> +
>> +static struct i2c_driver anx7814_driver = {
>> +       .driver = {
>> +                  .name = "anx7814",
>> +                  .pm = &anx7814_i2c_pm_ops,
>> +                  .of_match_table = of_match_ptr(anx_match_table),
>> +                  },
>> +       .probe = anx7814_i2c_probe,
>> +       .remove = anx7814_i2c_remove,
>> +       .id_table = anx7814_id,
>> +};
>> +
>> +module_i2c_driver(anx7814_driver);
>> +
>> +MODULE_DESCRIPTION("Slimport  transmitter ANX7814 driver");
>> +MODULE_AUTHOR("Junhua Xia <jxia@analogixsemi.com>");
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_VERSION("1.1");
>> diff --git a/drivers/staging/slimport/slimport.h b/drivers/staging/slimport/slimport.h
>> new file mode 100644
>> index 0000000..614d746
>> --- /dev/null
>> +++ b/drivers/staging/slimport/slimport.h
>> @@ -0,0 +1,49 @@
>> +/*
>> + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 and
>> + * only version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + */
>> +
>> +#ifndef _SLIMPORT_H
>> +#define _SLIMPORT_H
>> +
>> +#include <linux/i2c.h>
>> +#include <linux/mutex.h>
>> +#include <linux/slab.h>
>> +#include <linux/workqueue.h>
>> +#include <linux/gpio/consumer.h>
>> +
>> +#define AUX_ERR  1
>> +#define AUX_OK   0
>> +
>> +#define LOG_TAG "SlimPort ANX78XX"
>> +
>> +struct anx7814_platform_data {
>> +       struct gpio_desc *gpiod_pd;
>> +       struct gpio_desc *gpiod_reset;
>> +       spinlock_t lock;
>> +};
>> +
>> +struct anx7814_data {
>
> Nit: my personal preference would be to drop the "_data":
>
>  struct anx7814  (or struct anx78xx, to match the driver name).
>
>
>> +       struct i2c_client *client;
>> +       struct anx7814_platform_data *pdata;
>> +       struct delayed_work work;
>> +       struct workqueue_struct *workqueue;
>> +       struct mutex lock;
>> +};
>> +
>> +int sp_read_reg(uint8_t slave_addr, uint8_t offset, uint8_t *buf);
>> +int sp_write_reg(uint8_t slave_addr, uint8_t offset, uint8_t value);
>> +
>> +void sp_tx_hardware_poweron(struct anx7814_data *data);
>> +void sp_tx_hardware_powerdown(struct anx7814_data *data);
>> +
>> +#endif
>> diff --git a/drivers/staging/slimport/slimport_tx_drv.c b/drivers/staging/slimport/slimport_tx_drv.c
>> new file mode 100644
>> index 0000000..6fad502
>> --- /dev/null
>> +++ b/drivers/staging/slimport/slimport_tx_drv.c
>> @@ -0,0 +1,3293 @@
>> +/*
>> + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 and
>> + * only version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/types.h>
>> +
>> +#include "slimport.h"
>> +#include "slimport_tx_drv.h"
>> +
>> +#define XTAL_CLK_M10   pxtal_data[XTAL_27M].xtal_clk_m10
>> +#define XTAL_CLK       pxtal_data[XTAL_27M].xtal_clk
>> +
>> +static u8 sp_tx_test_bw;
>> +static bool sp_tx_test_lt;
>> +static bool sp_tx_test_edid;
>> +
>> +static u8 g_changed_bandwidth;
>> +static u8 g_hdmi_dvi_status;
>> +
>> +static u8 g_need_clean_status;
>> +
>> +static u8 ds_vid_stb_cntr;
>> +static u8 hdcp_fail_count;
>> +
>> +u8 g_edid_break;
>> +u8 g_edid_checksum;
>> +u8 edid_blocks[256];
>> +static u8 g_read_edid_flag;
>> +
>> +static struct packet_avi sp_tx_packet_avi;
>> +static struct packet_spd sp_tx_packet_spd;
>> +static struct packet_mpeg sp_tx_packet_mpeg;
>> +static struct audio_info_frame sp_tx_audioinfoframe;
>> +
>> +enum sp_tx_state sp_tx_system_state;
>> +
>> +enum audio_output_status sp_tx_ao_state;
>> +enum video_output_status sp_tx_vo_state;
>> +enum sink_connection_status sp_tx_sc_state;
>> +enum sp_tx_lt_status sp_tx_lt_state;
>> +enum sp_tx_state sp_tx_system_state_bak;
>> +enum hdcp_status hcdp_state;
>> +
>> +const uint chipid_list[] = {
>> +       0x7818,
>> +       0x7816,
>> +       0x7814,
>> +       0x7812,
>> +       0x7810,
>> +       0x7806,
>> +       0x7802
>> +};
>> +
>> +struct common_int common_int_status;
>> +struct hdmi_rx_int hdmi_rx_int_status;
>> +
>> +static u8 down_sample_en;
>> +
>> +static unsigned char sp_i2c_read_byte(unsigned char dev, unsigned char offset);
>> +static void hdmi_rx_new_vsi_int(void);
>
> ... yeah, this driver needs a lot of work.  All of the above global
> state variables need to go away.
>
>> +
>> +#define reg_bit_ctl(addr, offset, data, enable) \
>> +       do { \
>> +               u8 c; \
>> +               sp_read_reg(addr, offset, &c); \
>> +               if (enable) { \
>> +                       if ((c & data) != data) { \
>> +                               c |= data; \
>> +                               sp_write_reg(addr, offset, c); \
>> +                       } \
>> +               } else { \
>> +                       if ((c & data) == data) { \
>> +                               c &= ~data; \
>> +                               sp_write_reg(addr, offset, c); \
>> +                       } \
>> +               } \
>> +       } while (0)
>> +
>> +#define sp_tx_video_mute(enable) \
>> +       reg_bit_ctl(TX_P2, VID_CTRL1, VIDEO_MUTE, enable)
>> +
>> +#define hdmi_rx_mute_audio(enable) \
>> +       reg_bit_ctl(RX_P0, RX_MUTE_CTRL, AUD_MUTE, enable)
>> +
>> +#define hdmi_rx_mute_video(enable) \
>> +       reg_bit_ctl(RX_P0, RX_MUTE_CTRL, VID_MUTE, enable)
>> +
>> +#define sp_tx_addronly_set(enable) \
>> +       reg_bit_ctl(TX_P0, AUX_CTRL2, ADDR_ONLY_BIT, enable)
>> +
>> +#define sp_tx_set_link_bw(bw) \
>> +       sp_write_reg(TX_P0, SP_TX_LINK_BW_SET_REG, bw)
>> +
>> +#define sp_tx_get_link_bw() \
>> +       sp_i2c_read_byte(TX_P0, SP_TX_LINK_BW_SET_REG)
>> +
>> +#define sp_tx_get_pll_lock_status() \
>> +       ((sp_i2c_read_byte(TX_P0, TX_DEBUG1) & DEBUG_PLL_LOCK) != 0 ? 1 : 0)
>> +
>> +#define gen_m_clk_with_downspeading() \
>> +       sp_write_reg_or(TX_P0, SP_TX_M_CALCU_CTRL, M_GEN_CLK_SEL)
>> +
>> +#define gen_m_clk_without_downspeading \
>> +       sp_write_reg_and(TX_P0, SP_TX_M_CALCU_CTRL, (~M_GEN_CLK_SEL))
>> +
>> +#define hdmi_rx_set_hpd(enable) do { \
>> +       if ((bool)enable) \
>> +               sp_write_reg_or(TX_P2, SP_TX_VID_CTRL3_REG, HPD_OUT); \
>> +       else \
>> +               sp_write_reg_and(TX_P2, SP_TX_VID_CTRL3_REG, ~HPD_OUT); \
>> +       } while (0)
>> +
>> +#define hdmi_rx_set_termination(enable) do { \
>> +       if ((bool)enable) \
>> +               sp_write_reg_and(RX_P0, HDMI_RX_TMDS_CTRL_REG7, ~TERM_PD); \
>> +       else \
>> +               sp_write_reg_or(RX_P0, HDMI_RX_TMDS_CTRL_REG7, TERM_PD); \
>> +       } while (0)
>> +
>> +#define sp_tx_clean_hdcp_status() do { \
>> +       sp_write_reg(TX_P0, TX_HDCP_CTRL0, 0x03); \
>> +       sp_write_reg_or(TX_P0, TX_HDCP_CTRL0, RE_AUTH); \
>> +       usleep_range(2000, 4000); \
>> +       pr_info("%s %s : sp_tx_clean_hdcp_status\n", LOG_TAG, __func__); \
>> +       } while (0)
>> +
>> +#define reg_hardware_reset() do { \
>> +       sp_write_reg_or(TX_P2, SP_TX_RST_CTRL_REG, HW_RST); \
>> +       sp_tx_clean_state_machine(); \
>> +       sp_tx_set_sys_state(STATE_SP_INITIALIZED); \
>> +       msleep(500); \
>> +       } while (0)
>> +
>> +#define write_dpcd_addr(addrh, addrm, addrl) \
>> +       do { \
>> +               u8 temp; \
>> +               if (sp_i2c_read_byte(TX_P0, AUX_ADDR_7_0) != (u8)addrl) \
>> +                       sp_write_reg(TX_P0, AUX_ADDR_7_0, (u8)addrl); \
>> +                       if (sp_i2c_read_byte(TX_P0, AUX_ADDR_15_8) \
>> +                                               != (u8)addrm) \
>> +                               sp_write_reg(TX_P0, \
>> +                                       AUX_ADDR_15_8, (u8)addrm); \
>> +               sp_read_reg(TX_P0, AUX_ADDR_19_16, &temp); \
>> +               if ((u8)(temp & 0x0F)  != ((u8)addrh & 0x0F)) \
>> +                       sp_write_reg(TX_P0, AUX_ADDR_19_16, \
>> +                               (temp  & 0xF0) | ((u8)addrh)); \
>> +       } while (0)
>> +
>> +#define sp_tx_set_sys_state(ss) \
>> +       do { \
>> +               pr_info("%s %s : set: clean_status: %x,\n ", \
>> +                               LOG_TAG, __func__, (uint)g_need_clean_status); \
>> +               if ((sp_tx_system_state >= STATE_LINK_TRAINING) \
>> +                                       && (ss < STATE_LINK_TRAINING)) \
>> +                       sp_write_reg_or(TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD); \
>> +               sp_tx_system_state_bak = sp_tx_system_state; \
>> +               sp_tx_system_state = (u8)ss; \
>> +               g_need_clean_status = 1; \
>> +               print_sys_state(sp_tx_system_state); \
>> +       } while (0)
>> +
>> +#define goto_next_system_state() \
>> +       do { \
>> +               pr_info("%s %s : next: clean_status: %x,\n ", \
>> +                               LOG_TAG, __func__, (uint)g_need_clean_status); \
>> +               sp_tx_system_state_bak = sp_tx_system_state; \
>> +               sp_tx_system_state++;\
>> +               print_sys_state(sp_tx_system_state); \
>> +       } while (0)
>> +
>> +#define redo_cur_system_state() \
>> +       do { \
>> +               pr_info("%s %s : redo: clean_status: %x,\n ", \
>> +                               LOG_TAG, __func__, (uint)g_need_clean_status); \
>> +               g_need_clean_status = 1; \
>> +               sp_tx_system_state_bak = sp_tx_system_state; \
>> +               print_sys_state(sp_tx_system_state); \
>> +       } while (0)
>> +
>> +#define system_state_change_with_case(status) \
>> +       do { \
>> +               if (sp_tx_system_state >= status) { \
>> +                       pr_info("%s %s : change_case: clean_status: %xm,\n ", \
>> +                               LOG_TAG, __func__, (uint)g_need_clean_status); \
>> +                       if ((sp_tx_system_state >= STATE_LINK_TRAINING) \
>> +                                       && (status < STATE_LINK_TRAINING)) \
>> +                               sp_write_reg_or(TX_P0, \
>> +                                               SP_TX_ANALOG_PD_REG, CH0_PD); \
>> +                       g_need_clean_status = 1; \
>> +                       sp_tx_system_state_bak = sp_tx_system_state; \
>> +                       sp_tx_system_state = (u8)status; \
>> +                       print_sys_state(sp_tx_system_state); \
>> +               } \
>> +       } while (0)
>> +
>> +#define sp_write_reg_or(address, offset, mask) \
>> +       sp_write_reg(address, offset, \
>> +               ((unsigned char)sp_i2c_read_byte(address, offset) | (mask)))
>> +
>> +#define sp_write_reg_and(address, offset, mask) \
>> +       sp_write_reg(address, offset, \
>> +               ((unsigned char)sp_i2c_read_byte(address, offset) & (mask)))
>> +
>> +#define sp_write_reg_and_or(address, offset, and_mask, or_mask) \
>> +       sp_write_reg(address, offset, \
>> +               (((unsigned char)sp_i2c_read_byte(address, offset)) \
>> +               & and_mask) | (or_mask))
>> +
>> +#define sp_write_reg_or_and(address, offset, or_mask, and_mask) \
>> +       sp_write_reg(address, offset, \
>> +               (((unsigned char)sp_i2c_read_byte(address, offset)) \
>> +               | or_mask) & (and_mask))
>
> ... and all of the above "function-like macros" should be converted to
> type-safe static functions, where applicable.
>
>
>> +
>> +static inline void sp_tx_link_phy_initialization(void)
>> +{
>> +       sp_write_reg(TX_P2, SP_TX_ANALOG_CTRL0, 0x02);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG0, 0x01);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG10, 0x00);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG1, 0x03);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG11, 0x00);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG2, 0x07);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG12, 0x00);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG3, 0x7f);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG13, 0x00);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG4, 0x71);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG14, 0x0c);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG5, 0x6b);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG15, 0x42);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG6, 0x7f);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG16, 0x1e);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG7, 0x73);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG17, 0x3e);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG8, 0x7f);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG18, 0x72);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG9, 0x7F);
>> +       sp_write_reg(TX_P1, SP_TX_LT_CTRL_REG19, 0x7e);
>> +}
>> +
>> +static unsigned char sp_i2c_read_byte(unsigned char dev, unsigned char offset)
>> +{
>> +       unsigned char temp;
>> +
>> +       sp_read_reg(dev, offset, &temp);
>> +       return temp;
>> +}
>> +
>> +static void hardware_power_ctl(struct anx7814_data *data, u8 enable)
>> +{
>> +       if (enable == 0)
>> +               sp_tx_hardware_powerdown(data);
>> +       else
>> +               sp_tx_hardware_poweron(data);
>> +}
>> +
>> +void wait_aux_op_finish(u8 *err_flag)
>> +{
>> +       u8 cnt;
>> +       u8 c;
>> +
>> +       *err_flag = 0;
>> +       cnt = 150;
>> +       while (sp_i2c_read_byte(TX_P0, AUX_CTRL2) & AUX_OP_EN) {
>> +               usleep_range(2000, 4000);
>> +               if ((cnt--) == 0) {
>> +                       pr_info("%s %s :aux operate failed!\n",
>> +                                       LOG_TAG, __func__);
>
> dev_err() for all of these error prints.
>
>> +                       *err_flag = 1;
>> +                       break;
>> +               }
>> +       }
>> +
>> +       sp_read_reg(TX_P0, SP_TX_AUX_STATUS, &c);
>> +       if (c & 0x0F) {
>> +               pr_info("%s %s : wait aux operation status %.2x\n",
>> +                               LOG_TAG, __func__, (uint)c);
>> +               *err_flag = 1;
>> +       }
>> +}
>> +
>> +void print_sys_state(u8 ss)
>> +{
>> +       switch (ss) {
>> +       case STATE_WAITTING_CABLE_PLUG:
>> +               pr_info("%s %s : -STATE_WAITTING_CABLE_PLUG-\n",
>> +                               LOG_TAG, __func__);
>
> dev_dbg() for all of these state transitions.
>
>> +               break;
>> +       case STATE_SP_INITIALIZED:
>> +               pr_info("%s %s : -STATE_SP_INITIALIZED-\n", LOG_TAG, __func__);
>> +               break;
>> +       case STATE_SINK_CONNECTION:
>> +               pr_info("%s %s : -STATE_SINK_CONNECTION-\n", LOG_TAG, __func__);
>> +               break;
>> +       case STATE_PARSE_EDID:
>> +               pr_info("%s %s : -STATE_PARSE_EDID-\n", LOG_TAG, __func__);
>> +               break;
>> +       case STATE_LINK_TRAINING:
>> +               pr_info("%s %s : -STATE_LINK_TRAINING-\n", LOG_TAG, __func__);
>> +               break;
>> +       case STATE_VIDEO_OUTPUT:
>> +               pr_info("%s %s : -STATE_VIDEO_OUTPUT-\n", LOG_TAG, __func__);
>> +               break;
>> +       case STATE_HDCP_AUTH:
>> +               pr_info("%s %s : -STATE_HDCP_AUTH-\n", LOG_TAG, __func__);
>> +               break;
>> +       case STATE_AUDIO_OUTPUT:
>> +               pr_info("%s %s : -STATE_AUDIO_OUTPUT-\n", LOG_TAG, __func__);
>> +               break;
>> +       case STATE_PLAY_BACK:
>> +               pr_info("%s %s : -STATE_PLAY_BACK-\n", LOG_TAG, __func__);
>> +               break;
>> +       default:
>> +               pr_err("%s %s : system state is error1\n", LOG_TAG, __func__);
>> +               break;
>> +       }
>> +}
>> +
>> +void sp_tx_rst_aux(void)
>> +{
>> +       sp_write_reg_or(TX_P2, RST_CTRL2, AUX_RST);
>> +       sp_write_reg_and(TX_P2, RST_CTRL2, ~AUX_RST);
>> +}
>> +
>> +u8 sp_tx_aux_dpcdread_bytes(u8 addrh, u8 addrm,
>> +               u8 addrl, u8 ccount, u8 *pbuf)
>> +{
>> +       u8 c, c1, i;
>> +       u8 bok;
>> +
>> +       sp_write_reg(TX_P0, BUF_DATA_COUNT, 0x80);
>> +       c = ((ccount - 1) << 4) | 0x09;
>> +       sp_write_reg(TX_P0, AUX_CTRL, c);
>> +       write_dpcd_addr(addrh, addrm, addrl);
>> +       sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN);
>> +       usleep_range(2000, 4000);
>> +
>> +       wait_aux_op_finish(&bok);
>> +       if (bok == AUX_ERR) {
>> +               pr_err("%s %s : aux read failed\n", LOG_TAG, __func__);
>> +               sp_read_reg(TX_P2, SP_TX_INT_STATUS1, &c);
>> +               sp_read_reg(TX_P0, TX_DEBUG1, &c1);
>> +               if (c1 & POLLING_EN) {
>> +                       if (c & POLLING_ERR)
>> +                               sp_tx_rst_aux();
>> +               } else
>> +                       sp_tx_rst_aux();
>> +               return AUX_ERR;
>> +       }
>> +
>> +       for (i = 0; i < ccount; i++) {
>> +               sp_read_reg(TX_P0, BUF_DATA_0 + i, &c);
>> +               *(pbuf + i) = c;
>> +               if (i >= MAX_BUF_CNT)
>> +                       break;
>> +       }
>> +       return AUX_OK;
>> +}
>> +
>> +u8 sp_tx_aux_dpcdwrite_bytes(u8 addrh, u8 addrm,
>> +               u8 addrl, u8 ccount, u8 *pbuf)
>> +{
>> +       u8 c, i, ret;
>> +
>> +       c =  ((ccount - 1) << 4) | 0x08;
>> +       sp_write_reg(TX_P0, AUX_CTRL, c);
>> +       write_dpcd_addr(addrh, addrm, addrl);
>> +       for (i = 0; i < ccount; i++) {
>> +               c = *pbuf;
>> +               pbuf++;
>> +               sp_write_reg(TX_P0, BUF_DATA_0 + i, c);
>> +
>> +               if (i >= 15)
>> +                       break;
>> +       }
>> +       sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN);
>> +       wait_aux_op_finish(&ret);
>> +       return ret;
>> +}
>> +
>> +u8 sp_tx_aux_dpcdwrite_byte(u8 addrh, u8 addrm,
>> +               u8 addrl, u8 data1)
>> +{
>> +       u8 ret;
>> +
>> +       sp_write_reg(TX_P0, AUX_CTRL, 0x08);
>> +       write_dpcd_addr(addrh, addrm, addrl);
>> +       sp_write_reg(TX_P0, BUF_DATA_0, data1);
>> +       sp_write_reg_or(TX_P0, AUX_CTRL2, AUX_OP_EN);
>> +       wait_aux_op_finish(&ret);
>> +       return ret;
>> +}
>> +
>> +void slimport_block_power_ctrl(enum sp_tx_power_block sp_tx_pd_block,
>> +               u8 power)
>> +{
>> +       if (power == SP_POWER_ON)
>> +               sp_write_reg_and(TX_P2, SP_POWERD_CTRL_REG, (~sp_tx_pd_block));
>> +       else
>> +               sp_write_reg_or(TX_P2, SP_POWERD_CTRL_REG, (sp_tx_pd_block));
>> +        pr_info("%s %s : sp_tx_power_on: %.2x\n",
>> +                       LOG_TAG, __func__, (uint)sp_tx_pd_block);
>> +}
>> +
>> +void vbus_power_ctrl(unsigned char on)
>
> I'd just split this into two functions:
>
> anx78xx_vbus_power_on() & anx78xx_vbus_power_off()
>
>> +{
>> +       u8 i;
>> +
>> +       if (on == 0) {
>> +               sp_write_reg_and(TX_P2, TX_PLL_FILTER, ~V33_SWITCH_ON);
>> +               sp_write_reg_or(TX_P2, TX_PLL_FILTER5,
>> +                                       P5V_PROTECT_PD | SHORT_PROTECT_PD);
>> +               pr_info("%s %s : 3.3V output disabled\n", LOG_TAG, __func__);
>> +       } else {
>> +               for (i = 0; i < 5; i++) {
>> +                       sp_write_reg_and(TX_P2, TX_PLL_FILTER5,
>> +                                       (~P5V_PROTECT_PD & ~SHORT_PROTECT_PD));
>> +                       sp_write_reg_or(TX_P2, TX_PLL_FILTER, V33_SWITCH_ON);
>> +                       if (!((u8)sp_i2c_read_byte(TX_P2, TX_PLL_FILTER5)
>> +                               & 0xc0)) {
>> +                               pr_info("%s %s : 3.3V output enabled\n",
>> +                                               LOG_TAG, __func__);
>> +                               break;
>> +                       }
>> +
>> +                       pr_info("%s %s : VBUS power can not be supplied\n",
>> +                               LOG_TAG, __func__);
>> +               }
>> +       }
>> +}
>> +
>> +void sp_tx_clean_state_machine(void)
>> +{
>> +       sp_tx_system_state = STATE_WAITTING_CABLE_PLUG;
>> +       sp_tx_system_state_bak = STATE_WAITTING_CABLE_PLUG;
>> +       sp_tx_sc_state = SC_INIT;
>> +       sp_tx_lt_state = LT_INIT;
>> +       hcdp_state = HDCP_CAPABLE_CHECK;
>> +       sp_tx_vo_state = VO_WAIT_VIDEO_STABLE;
>> +       sp_tx_ao_state = AO_INIT;
>> +}
>> +
>> +u8 sp_tx_cur_states(void)
>> +{
>> +       return sp_tx_system_state;
>> +}
>> +
>> +u8 sp_tx_cur_bw(void)
>> +{
>> +       return g_changed_bandwidth;
>> +}
>> +
>> +void sp_tx_set_bw(u8 bw)
>> +{
>> +       g_changed_bandwidth = bw;
>> +}
>> +
>> +void sp_tx_variable_init(void)
>> +{
>> +       uint i;
>> +
>> +       sp_tx_system_state = STATE_WAITTING_CABLE_PLUG;
>> +       sp_tx_system_state_bak = STATE_WAITTING_CABLE_PLUG;
>> +
>> +       g_edid_break = 0;
>> +       g_read_edid_flag = 0;
>> +       g_edid_checksum = 0;
>> +       for (i = 0; i < 256; i++)
>> +               edid_blocks[i] = 0;
>> +
>> +       sp_tx_lt_state = LT_INIT;
>> +       hcdp_state = HDCP_CAPABLE_CHECK;
>> +       g_need_clean_status = 0;
>> +       sp_tx_sc_state = SC_INIT;
>> +       sp_tx_vo_state = VO_WAIT_VIDEO_STABLE;
>> +       sp_tx_ao_state = AO_INIT;
>> +       g_changed_bandwidth = LINK_5P4G;
>> +       g_hdmi_dvi_status = HDMI_MODE;
>> +
>> +       sp_tx_test_lt = 0;
>> +       sp_tx_test_bw = 0;
>> +       sp_tx_test_edid = 0;
>> +
>> +       ds_vid_stb_cntr = 0;
>> +       hdcp_fail_count = 0;
>> +
>> +}
>> +
>> +static void hdmi_rx_tmds_phy_initialization(void)
>> +{
>> +       sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG2, 0xa9);
>> +       sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG7, 0x80);
>> +
>> +       sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG1, 0x90);
>> +       sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG6, 0x92);
>> +       sp_write_reg(RX_P0, HDMI_RX_TMDS_CTRL_REG20, 0xf2);
>> +}
>> +
>> +void hdmi_rx_initialization(void)
>> +{
>> +       sp_write_reg(RX_P0, RX_MUTE_CTRL, AUD_MUTE | VID_MUTE);
>> +       sp_write_reg_or(RX_P0, RX_CHIP_CTRL,
>> +               MAN_HDMI5V_DET | PLLLOCK_CKDT_EN | DIGITAL_CKDT_EN);
>> +
>> +       sp_write_reg_or(RX_P0, RX_SRST, HDCP_MAN_RST | SW_MAN_RST |
>> +               TMDS_RST | VIDEO_RST);
>> +       sp_write_reg_and(RX_P0, RX_SRST, (~HDCP_MAN_RST) & (~SW_MAN_RST) &
>> +               (~TMDS_RST) & (~VIDEO_RST));
>> +
>> +       sp_write_reg_or(RX_P0, RX_AEC_EN0, AEC_EN06 | AEC_EN05);
>> +       sp_write_reg_or(RX_P0, RX_AEC_EN2, AEC_EN21);
>> +       sp_write_reg_or(RX_P0, RX_AEC_CTRL, AVC_EN | AAC_OE | AAC_EN);
>> +
>> +       sp_write_reg_and(RX_P0, RX_SYS_PWDN1, ~PWDN_CTRL);
>> +
>> +       sp_write_reg_or(RX_P0, RX_VID_DATA_RNG, R2Y_INPUT_LIMIT);
>> +       sp_write_reg(RX_P0, 0x65, 0xc4);
>> +       sp_write_reg(RX_P0, 0x66, 0x18);
>> +
>> +       sp_write_reg(TX_P0, TX_EXTRA_ADDR, 0x50); /* enable DDC stretch */
>> +
>> +       hdmi_rx_tmds_phy_initialization();
>> +       hdmi_rx_set_hpd(0);
>> +       hdmi_rx_set_termination(0);
>> +       pr_info("%s %s : HDMI Rx is initialized...\n", LOG_TAG, __func__);
>> +}
>> +
>> +struct clock_data const pxtal_data[XTAL_CLK_NUM] = {
>
> static const struct clock_data pxtal_data[] = {
>
> Also, if this is an anx78xx specific type, it should have a name like
> "struct anx78xx_clock_data".
>
>> +       {19, 192},
>> +       {24, 240},
>> +       {25, 250},
>> +       {26, 260},
>> +       {27, 270},
>> +       {38, 384},
>> +       {52, 520},
>> +       {27, 270},
>> +};
>> +
>> +void xtal_clk_sel(void)
>> +{
>> +       pr_info("%s %s : define XTAL_CLK:  %x\n ",
>> +                       LOG_TAG, __func__, (uint)XTAL_27M);
>> +       sp_write_reg_and_or(TX_P2,
>> +                       TX_ANALOG_DEBUG2, (~0x3c), 0x3c & (XTAL_27M << 2));
>> +       sp_write_reg(TX_P0, 0xEC, (u8)(((uint)XTAL_CLK_M10)));
>> +       sp_write_reg(TX_P0, 0xED,
>> +               (u8)(((uint)XTAL_CLK_M10 & 0xFF00) >> 2) | XTAL_CLK);
>> +
>> +       sp_write_reg(TX_P0,
>> +                       I2C_GEN_10US_TIMER0, (u8)(((uint)XTAL_CLK_M10)));
>> +       sp_write_reg(TX_P0, I2C_GEN_10US_TIMER1,
>> +                       (u8)(((uint)XTAL_CLK_M10 & 0xFF00) >> 8));
>> +       sp_write_reg(TX_P0, 0xBF, (u8)(((uint)XTAL_CLK - 1)));
>> +
>> +       sp_write_reg_and_or(RX_P0, 0x49, 0x07,
>> +                       (u8)(((((uint)XTAL_CLK) >> 1) - 2) << 3));
>> +
>> +}
>> +
>> +void sp_tx_initialization(void)
>> +{
>> +       sp_write_reg(TX_P0, AUX_CTRL2, 0x30);
>> +       sp_write_reg_or(TX_P0, AUX_CTRL2, 0x08);
>> +
>> +       sp_write_reg_and(TX_P0, TX_HDCP_CTRL, (~AUTO_EN) & (~AUTO_START));
>> +       sp_write_reg(TX_P0, OTP_KEY_PROTECT1, OTP_PSW1);
>> +       sp_write_reg(TX_P0, OTP_KEY_PROTECT2, OTP_PSW2);
>> +       sp_write_reg(TX_P0, OTP_KEY_PROTECT3, OTP_PSW3);
>> +       sp_write_reg_or(TX_P0, HDCP_KEY_CMD, DISABLE_SYNC_HDCP);
>> +       sp_write_reg(TX_P2, SP_TX_VID_CTRL8_REG, VID_VRES_TH);
>> +
>> +       sp_write_reg(TX_P0, HDCP_AUTO_TIMER, HDCP_AUTO_TIMER_VAL);
>> +       sp_write_reg_or(TX_P0, TX_HDCP_CTRL, LINK_POLLING);
>> +
>> +       sp_write_reg_or(TX_P0, TX_LINK_DEBUG, M_VID_DEBUG);
>> +       sp_write_reg_or(TX_P2, TX_ANALOG_DEBUG2, POWERON_TIME_1P5MS);
>> +
>> +       xtal_clk_sel();
>> +       sp_write_reg(TX_P0, AUX_DEFER_CTRL, 0x8C);
>> +
>> +       sp_write_reg_or(TX_P0, TX_DP_POLLING, AUTO_POLLING_DISABLE);
>> +       /*
>> +        * Short the link intergrity check timer to speed up bstatus
>> +        * polling for HDCP CTS item 1A-07
>> +        */
>> +       sp_write_reg(TX_P0, SP_TX_LINK_CHK_TIMER, 0x1d);
>> +       sp_write_reg_or(TX_P0, TX_MISC, EQ_TRAINING_LOOP);
>> +
>> +       sp_write_reg_or(TX_P0, SP_TX_ANALOG_PD_REG, CH0_PD);
>> +
>> +       sp_write_reg(TX_P2, SP_TX_INT_CTRL_REG, 0X01);
>> +       /* disable HDCP mismatch function for VGA dongle */
>> +       sp_tx_link_phy_initialization();
>> +       gen_m_clk_with_downspeading();
>> +
>> +       down_sample_en = 0;
>> +}
>> +
>> +bool slimport_chip_detect(struct anx7814_data *data)
>> +{
>> +       uint16_t id;
>> +       uint8_t idh = 0, idl = 0;
>> +       int i;
>> +
>> +       hardware_power_ctl(data, 1);
>> +
>> +       /* check chip id */
>> +       sp_read_reg(TX_P2, SP_TX_DEV_IDL_REG, &idl);
>> +       sp_read_reg(TX_P2, SP_TX_DEV_IDH_REG, &idh);
>> +       id = idl | (idh << 8);
>> +
>> +       pr_info("%s %s : CHIPID: ANX%x\n", LOG_TAG, __func__, id & 0xffff);
>> +       for (i = 0; i < sizeof(chipid_list) / sizeof(uint16_t); i++) {
>> +               if (id == chipid_list[i])
>> +                       return 1;
>> +       }
>> +       return 0;
>
> bool functions should return "true" and "false".
>
>> +}
>> +
>> +void slimport_waitting_cable_plug_process(struct anx7814_data *data)
>
> spelling: "_waiting_"
>
>> +{
>> +       sp_tx_variable_init();
>> +       hardware_power_ctl(data, 1);
>> +       goto_next_system_state();
>> +}
>> +
>> +/*
>> + * Check if it is ANALOGIX dongle.
>> + */
>> +unsigned char ANX_OUI[3] = {0x00, 0x22, 0xB9};
>
> static const u8
>
>> +
>> +unsigned char is_anx_dongle(void)
>> +{
>> +       unsigned char buf[3];
>> +
>> +       /* 0x0500~0x0502: BRANCH_IEEE_OUI */
>> +       sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x00, 3, buf);
>> +       if (buf[0] == ANX_OUI[0] && buf[1] == ANX_OUI[1]
>> +           && buf[2] == ANX_OUI[2])
>
> memcmp()
>
>
>> +               return 1;
>> +
>> +       return 0;
>> +}
>> +
>> +void sp_tx_get_rx_bw(unsigned char *bw)
>> +{
>> +       u8 data_buf[4];
>> +       /*
>> +        * When ANX dongle connected, if CHIP_ID = 0x7750, bandwidth is 6.75G,
>> +        * ecause ANX7750 DPCD 0x052x was not available.
>
> "because"
>
>> +        */
>> +       if (is_anx_dongle()) {
>> +               sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x03, 0x04, data_buf);
>> +               if ((data_buf[0] == 0x37) && (data_buf[1] == 0x37)
>> +                       && (data_buf[2] == 0x35) && (data_buf[3] == 0x30))
>
> What are these magic numbers?
>
>> +                       *bw = LINK_6P75G;
>> +               else
>> +                       sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x21, 1, bw);
>> +               /* just for Debug */
>> +               *bw = LINK_6P75G;
>
> You just set this twice?
>
>> +       } else
>
> Use '{}' on both sides of the else:
>
>   } else {
>
>> +               sp_tx_aux_dpcdread_bytes(0x00, 0x00, DPCD_MAX_LINK_RATE, 1, bw);
>> +}
>> +
>> +static u8 sp_tx_get_cable_type(enum cable_type_status det_cable_type_state)
>> +{
>> +       u8 ds_port_preset;
>> +       u8 aux_status;
>> +       u8 data_buf[16];
>> +       u8 cur_cable_type;
>> +
>> +       ds_port_preset = 0;
>> +       cur_cable_type = DWN_STRM_IS_NULL;
>> +
>> +       aux_status =
>> +               sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0x05, 1, &ds_port_preset);
>> +       pr_info("%s %s : DPCD 0x005: %x\n",
>> +                       LOG_TAG, __func__, (int)ds_port_preset);
>> +
>> +       switch (det_cable_type_state) {
>> +       case CHECK_AUXCH:
>> +               if (AUX_OK == aux_status) {
>> +                       sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0, 0x0c, data_buf);
>> +                       det_cable_type_state = GETTED_CABLE_TYPE;
>> +               } else {
>> +                       msleep(50);
>> +                       pr_err("%s %s :  AUX access error\n",
>> +                                       LOG_TAG, __func__);
>
> Why the delay just to print an error message?
>
>   dev_err()
>
>> +                       break;
>> +               }
>> +       case GETTED_CABLE_TYPE:
>> +               switch ((ds_port_preset  & (_BIT1 | _BIT2)) >> 1) {
>> +               case 0x00:
>> +                       cur_cable_type = DWN_STRM_IS_DIGITAL;
>> +                       pr_info("%s %s : Downstream is DP dongle.\n",
>> +                                       LOG_TAG, __func__);
>> +                       break;
>> +               case 0x01:
>> +               case 0x03:
>> +                       cur_cable_type = DWN_STRM_IS_ANALOG;
>> +                       pr_info("%s %s : Downstream is VGA dongle.\n",
>> +                                       LOG_TAG, __func__);
>> +                       break;
>> +               case 0x02:
>> +                       cur_cable_type = DWN_STRM_IS_HDMI;
>> +                       pr_info("%s %s : Downstream is HDMI dongle.\n",
>> +                                       LOG_TAG, __func__);
>> +                       break;
>> +               default:
>> +                       cur_cable_type = DWN_STRM_IS_NULL;
>> +                       pr_err("%s %s : Downstream can not recognized.\n",
>> +                                       LOG_TAG, __func__);
>> +                       break;
>> +               }
>> +       default:
>> +               break;
>> +       }
>> +       return cur_cable_type;
>> +}
>> +
>> +u8 sp_tx_get_hdmi_connection(void)
>> +{
>> +       u8 c;
>> +
>> +       if (AUX_OK != sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x18, 1, &c))
>
> In the kernel, the constant is usually on the other side of the !=, like this:
>
> if (sp_tx_aux_dpcdread_bytes(0x00, 0x05, 0x18, 1, &c) != AUX_OK)
>
>
>
>> +               return 0;
>> +
>> +       if ((c & 0x41) == 0x41)
>
> magic number?
>
>> +               return 1;
>> +       else
>> +               return 0;
>> +
>> +}
>> +
>> +u8 sp_tx_get_vga_connection(void)
>> +{
>> +       u8 c;
>> +
>> +       if (AUX_OK !=
>> +               sp_tx_aux_dpcdread_bytes(0x00, 0x02, DPCD_SINK_COUNT, 1, &c)) {
>> +               pr_err("%s %s : aux error.\n", LOG_TAG, __func__);
>> +               return 0;
>> +       }
>> +
>> +       if (c & 0x01)
>> +               return 1;
>> +       else
>> +               return 0;
>> +}
>> +
>> +u8 sp_tx_get_dp_connection(void)
>> +{
>> +       u8 c;
>> +
>> +       if (AUX_OK !=
>> +               sp_tx_aux_dpcdread_bytes(0x00, 0x02, DPCD_SINK_COUNT, 1, &c))
>> +               return 0;
>> +
>> +       if (c & 0x1f) {
>> +               sp_tx_aux_dpcdread_bytes(0x00, 0x00, 0x04, 1, &c);
>> +               if (c & 0x20) {
>> +                       sp_tx_aux_dpcdread_bytes(0x00, 0x06, 0x00, 1, &c);
>> +                       /*
>> +                        * Bit 5 = SET_DN_DEVICE_DP_PWR_5V
>> +                        * Bit 6 = SET_DN_DEVICE_DP_PWR_12V
>> +                        *  Bit 7 = SET_DN_DEVICE_DP_PWR_18V
>> +                        */
>> +                       c = c & 0x1F;
>> +                       sp_tx_aux_dpcdwrite_byte(0x00, 0x06, 0x00, c | 0x20);
>> +               }
>> +               return 1;
>> +       } else
>> +               return 0;
>> +}
>> +
>> +u8 sp_tx_get_downstream_connection(void)
>> +{
>> +       return sp_tx_get_dp_connection();
>> +}
>> +
>> +void slimport_sink_connection(void)
>> +{
>
> The whole "state machine" in this function seems entirely unnecessary.
> Just do all required hotplug actions sequentially in a worker,
> triggered from a hotplug event.
>
>> +       switch (sp_tx_sc_state) {
>> +       case SC_INIT:
>> +               sp_tx_sc_state++;
>> +       case SC_CHECK_CABLE_TYPE:
>> +       case SC_WAITTING_CABLE_TYPE:
>> +       default:
>> +               if (sp_tx_get_cable_type(CHECK_AUXCH) == DWN_STRM_IS_NULL) {
>> +                       sp_tx_sc_state++;
>> +                       if (sp_tx_sc_state >= SC_WAITTING_CABLE_TYPE) {
>> +                               sp_tx_sc_state = SC_NOT_CABLE;
>> +                               pr_info("%s %s : Can not get cable type!\n",
>> +                                               LOG_TAG, __func__);
>> +                       }
>> +                       break;
>> +               }
>> +
>> +               sp_tx_sc_state = SC_SINK_CONNECTED;
>> +       case SC_SINK_CONNECTED:
>> +               if (sp_tx_get_downstream_connection())
>> +                       goto_next_system_state();
>> +               break;
>> +       case SC_NOT_CABLE:
>> +               vbus_power_ctrl(0);
>> +               reg_hardware_reset();
>> +               break;
>> +       }
>> +}
>> +
>> +/******************start EDID process********************/
>> +void sp_tx_enable_video_input(u8 enable)
>> +{
>> +       u8 c;
>> +
>> +       sp_read_reg(TX_P2, VID_CTRL1, &c);
>> +       if (enable) {
>> +               if ((c & VIDEO_EN) != VIDEO_EN) {
>
> The check here doesn't buy you much.
> Just always set/clear the enable bit.
>
>> +                       c = (c & 0xf7) | VIDEO_EN;
>> +                       sp_write_reg(TX_P2, VID_CTRL1, c);
>> +                       pr_info("%s %s : Slimport Video is enabled!\n",
>> +                                       LOG_TAG, __func__);
>> +               }
>> +       } else {
>> +               if ((c & VIDEO_EN) == VIDEO_EN) {
>> +                       c &= ~VIDEO_EN;
>> +                       sp_write_reg(TX_P2, VID_CTRL1, c);
>> +                       pr_info("%s %s : Slimport Video is disabled!\n",
>> +                                       LOG_TAG, __func__);
>> +               }
>> +       }
>> +}
>> +
>> +static u8 read_dvi_hdmi_mode(void)
>> +{
>> +       return 1;
>> +}
>> +
>> +static u8 get_edid_detail(u8 *data_buf)
>> +{
>> +       uint pixclock_edid;
>
> u16 perhaps?
>
>> +
>> +       pixclock_edid = ((((uint)data_buf[1] << 8))
>> +                       | ((uint)data_buf[0] & 0xFF));
>> +       if (pixclock_edid <= 5300)
>> +               return LINK_1P62G;
>> +       else if ((5300 < pixclock_edid) && (pixclock_edid <= 8900))
>> +               return LINK_2P7G;
>> +       else if ((8900 < pixclock_edid) && (pixclock_edid <= 18000))
>> +               return LINK_5P4G;
>> +       else
>> +               return LINK_6P75G;
>> +}
>> +
>
> [snip...]
>
>> +
>> diff --git a/drivers/staging/slimport/slimport_tx_drv.h b/drivers/staging/slimport/slimport_tx_drv.h
>> new file mode 100644
>> index 0000000..9aaf47d
>> --- /dev/null
>> +++ b/drivers/staging/slimport/slimport_tx_drv.h
>> @@ -0,0 +1,254 @@
>> +/*
>> + * Copyright(c) 2015, Analogix Semiconductor. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 and
>> + * only version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + */
>> +
>> +#ifndef _SP_TX_DRV_H
>> +#define _SP_TX_DRV_H
>> +
>> +#include "slimport.h"
>> +#include "slimport_tx_reg.h"
>> +
>> +#define FW_VERSION     0x22
>> +
>> +#define _BIT0          0x01
>> +#define _BIT1          0x02
>> +#define _BIT2          0x04
>> +#define _BIT3          0x08
>> +#define _BIT4          0x10
>> +#define _BIT5          0x20
>> +#define _BIT6          0x40
>> +#define _BIT7          0x80
>
> BIT() already exists.
>
> [snip...]
>
> Ok, enough for now :-).
>
> I'd be happy to review more in detail after you:
>  (1) clean up the typos, and little nits above
>  (2) move to the drm/bridge directory
>  (3) rename the files, variables, types, etc. to anx78xx
>  (4) plumb through the context struct to all functions that act on the device
>  (5) use proper messaging (dev_ rather than pr_, _dbg/_err rather than _info)
>

I'll include all your comments and send for review again.

> I think replacing the state machine with an event-driven approach can
> wait for a future round of review.
>

Looks a good plan for me, first review more trivial problems.

Best regards,
Enric

> -Dan
>
> On Mon, Sep 7, 2015 at 2:46 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
>> On Mon, Sep 07, 2015 at 07:41:08AM +0200, Enric Balletbo Serra wrote:
>>> 2015-09-07 1:27 GMT+02:00 Greg KH <gregkh@linuxfoundation.org>:
>>> > On Sun, Sep 06, 2015 at 11:14:02PM +0200, Enric Balletbo i Serra wrote:
>>> >> The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter
>>> >> designed for portable devices.
>>> >>
>>> >> This driver adds initial support and supports HDMI to DP pass-through mode.
>>> >>
>>> >> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
>>> >> ---
>>> >>  drivers/staging/Kconfig                    |    2 +
>>> >>  drivers/staging/Makefile                   |    1 +
>>> >>  drivers/staging/slimport/Kconfig           |    7 +
>>> >>  drivers/staging/slimport/Makefile          |    4 +
>>> >>  drivers/staging/slimport/slimport.c        |  301 +++
>>> >>  drivers/staging/slimport/slimport.h        |   49 +
>>> >>  drivers/staging/slimport/slimport_tx_drv.c | 3293 ++++++++++++++++++++++++++++
>>> >>  drivers/staging/slimport/slimport_tx_drv.h |  254 +++
>>> >>  drivers/staging/slimport/slimport_tx_reg.h |  786 +++++++
>>> >
>>> > Why is this a staging driver?
>>> > What prevents it from being merged into the "real" part of the kernel
>>> > tree?
>>> >
>>>
>>> I'll be glad to move the driver to their subsystem if you think it's a
>>> the better place. Basically there are two reasons why I send the
>>> driver to the staging directory. The first one is because my test
>>> environment is a bit limited, with my environment I can only test the
>>> HDMI to DisplayPort pass-through mode so the driver builds but it's
>>> partially tested. The second one is that I expect I'll need to
>>> refactor some code, specially in slimport_tx_drv.c file to be
>>> accepted, I decided not change too much this file from the original to
>>> not break the functionality, so I thought that will be better send
>>> first to the staging driver to have first reviews.
>>>
>>> > All staging drivers need a TODO file, listing what needs to be done and
>>> > who is in charge of it.  I can't take this without that added.
>>> >
>>>
>>> ok, I'll add in the next series once received some feedback (or move
>>> to the video subsystem)
>>
>> I suggest trying to get it merged "properly" first before having to
>> fall-back to the staging subsystem.
>>
>> thanks,
>>
>> greg k-h
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2015-09-09  7:10 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-06 21:13 [PATCH 0/3] Add initial support for slimport anx78xx Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 1/3] of: Add vendor prefix for Analogix Semiconductor, Inc Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 2/3] devicetree: Add new ANX7814 SlimPort transmitter binding Enric Balletbo i Serra
2015-09-06 21:14 ` [PATCH 3/3] staging: slimport: Add anx7814 driver support by analogix Enric Balletbo i Serra
2015-09-06 23:27   ` Greg KH
2015-09-07  5:41     ` Enric Balletbo Serra
2015-09-07  6:46       ` Greg KH
2015-09-09  3:38         ` Daniel Kurtz
2015-09-09  7:10           ` Enric Balletbo Serra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox