#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/mfd/syscon.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 
 #include "ufshcd.h"
 #include "ufshcd-pltfrm.h"
                                 UIC_TRANSPORT_NO_CONNECTION_RX |\
                                 UIC_TRANSPORT_BAD_TC)
 
+/* FSYS UFS Shareability */
+#define UFS_WR_SHARABLE                BIT(2)
+#define UFS_RD_SHARABLE                BIT(1)
+#define UFS_SHARABLE           (UFS_WR_SHARABLE | UFS_RD_SHARABLE)
+#define UFS_SHAREABILITY_OFFSET        0x710
+
 enum {
        UNIPRO_L1_5 = 0,/* PHY Adapter */
        UNIPRO_L2,      /* Data Link */
        return 0;
 }
 
+static int exynosauto_ufs_drv_init(struct device *dev, struct exynos_ufs *ufs)
+{
+       struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr;
+
+       /* IO Coherency setting */
+       if (ufs->sysreg) {
+               return regmap_update_bits(ufs->sysreg,
+                                         ufs->shareability_reg_offset,
+                                         UFS_SHARABLE, UFS_SHARABLE);
+       }
+
+       attr->tx_dif_p_nsec = 3200000;
+
+       return 0;
+}
+
+static int exynosauto_ufs_pre_link(struct exynos_ufs *ufs)
+{
+       struct ufs_hba *hba = ufs->hba;
+       int i;
+       u32 tx_line_reset_period, rx_line_reset_period;
+
+       rx_line_reset_period = (RX_LINE_RESET_TIME * ufs->mclk_rate) / NSEC_PER_MSEC;
+       tx_line_reset_period = (TX_LINE_RESET_TIME * ufs->mclk_rate) / NSEC_PER_MSEC;
+
+       ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x40);
+       for_each_ufs_rx_lane(ufs, i) {
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD, i),
+                              DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate));
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD_EN, i), 0x0);
+
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE2, i),
+                              (rx_line_reset_period >> 16) & 0xFF);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE1, i),
+                              (rx_line_reset_period >> 8) & 0xFF);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE0, i),
+                              (rx_line_reset_period) & 0xFF);
+
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x2f, i), 0x79);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x84, i), 0x1);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x25, i), 0xf6);
+       }
+
+       for_each_ufs_tx_lane(ufs, i) {
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD, i),
+                              DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate));
+               /* Not to affect VND_TX_LINERESET_PVALUE to VND_TX_CLK_PRD */
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD_EN, i),
+                              0x02);
+
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE2, i),
+                              (tx_line_reset_period >> 16) & 0xFF);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE1, i),
+                              (tx_line_reset_period >> 8) & 0xFF);
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE0, i),
+                              (tx_line_reset_period) & 0xFF);
+
+               /* TX PWM Gear Capability / PWM_G1_ONLY */
+               ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x04, i), 0x1);
+       }
+
+       ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x0);
+
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0x0);
+
+       ufshcd_dme_set(hba, UIC_ARG_MIB(0xa011), 0x8000);
+
+       return 0;
+}
+
+static int exynosauto_ufs_pre_pwr_change(struct exynos_ufs *ufs,
+                                        struct ufs_pa_layer_attr *pwr)
+{
+       struct ufs_hba *hba = ufs->hba;
+
+       /* PACP_PWR_req and delivered to the remote DME */
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA0), 12000);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA1), 32000);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA2), 16000);
+
+       return 0;
+}
+
 static int exynos7_ufs_pre_link(struct exynos_ufs *ufs)
 {
        struct ufs_hba *hba = ufs->hba;
                goto out;
        }
 
+       ufs->sysreg = syscon_regmap_lookup_by_phandle(np, "samsung,sysreg");
+       if (IS_ERR(ufs->sysreg))
+               ufs->sysreg = NULL;
+       else {
+               if (of_property_read_u32_index(np, "samsung,sysreg", 1,
+                                              &ufs->shareability_reg_offset)) {
+                       dev_warn(dev, "can't get an offset from sysreg. Set to default value\n");
+                       ufs->shareability_reg_offset = UFS_SHAREABILITY_OFFSET;
+               }
+       }
+
        ufs->pclk_avail_min = PCLK_AVAIL_MIN;
        ufs->pclk_avail_max = PCLK_AVAIL_MAX;
 
        .pa_dbg_option_suite            = 0x30103,
 };
 
+static struct exynos_ufs_drv_data exynosauto_ufs_drvs = {
+       .uic_attr               = &exynos7_uic_attr,
+       .quirks                 = UFSHCD_QUIRK_PRDT_BYTE_GRAN |
+                                 UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR |
+                                 UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR |
+                                 UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING,
+       .opts                   = EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL |
+                                 EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR |
+                                 EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX,
+       .drv_init               = exynosauto_ufs_drv_init,
+       .pre_link               = exynosauto_ufs_pre_link,
+       .pre_pwr_change         = exynosauto_ufs_pre_pwr_change,
+};
+
 static struct exynos_ufs_drv_data exynos_ufs_drvs = {
        .uic_attr               = &exynos7_uic_attr,
        .quirks                 = UFSHCD_QUIRK_PRDT_BYTE_GRAN |
 static const struct of_device_id exynos_ufs_of_match[] = {
        { .compatible = "samsung,exynos7-ufs",
          .data       = &exynos_ufs_drvs },
+       { .compatible = "samsung,exynosautov9-ufs",
+         .data       = &exynosauto_ufs_drvs },
        {},
 };