summaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-designware-pcidrv.c
diff options
context:
space:
mode:
authorSanket Goswami <Sanket.Goswami@amd.com>2021-03-31 16:07:30 +0200
committerWolfram Sang <wsa@kernel.org>2021-04-05 23:00:46 +0200
commit17631e8ca2d3421090e54b39d9a1402091019ba1 (patch)
tree6b20f80e431d410c08c8159523496ec12953bfff /drivers/i2c/busses/i2c-designware-pcidrv.c
parenti2c: cp2615: add i2c driver for Silicon Labs' CP2615 Digital Audio Bridge (diff)
downloadlinux-17631e8ca2d3421090e54b39d9a1402091019ba1.tar.xz
linux-17631e8ca2d3421090e54b39d9a1402091019ba1.zip
i2c: designware: Add driver support for AMD NAVI GPU
The Latest AMD NAVI GPU card has an integrated Type-C controller and Designware I2C with PCI Interface. The PD controller for USB Type-C can be accessed over I2C. The client driver is part of the USB Type-C UCSI driver. Also, there exists a couple of notable IP limitations that are dealt as workarounds: - I2C transaction work on a polling mode as IP does not generate interrupt. - I2C read command sent twice to address the IP issues. - AMD NAVI GPU based products are already in the commercial market, hence some of the I2C parameters are statically programmed as they can not be part of the ACPI table. Reviewed-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> Co-developed-by: Nehal Bakulchandra Shah <Nehal-Bakulchandra.shah@amd.com> Signed-off-by: Nehal Bakulchandra Shah <Nehal-Bakulchandra.shah@amd.com> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Wolfram Sang <wsa@kernel.org>
Diffstat (limited to 'drivers/i2c/busses/i2c-designware-pcidrv.c')
-rw-r--r--drivers/i2c/busses/i2c-designware-pcidrv.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
index 55c83a7a24f3..7ca0017883a6 100644
--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -26,6 +26,7 @@
#include "i2c-designware-core.h"
#define DRIVER_NAME "i2c-designware-pci"
+#define AMD_CLK_RATE_HZ 100000
enum dw_pci_ctl_id_t {
medfield,
@@ -34,6 +35,7 @@ enum dw_pci_ctl_id_t {
cherrytrail,
haswell,
elkhartlake,
+ navi_amd,
};
struct dw_scl_sda_cfg {
@@ -78,11 +80,23 @@ static struct dw_scl_sda_cfg hsw_config = {
.sda_hold = 0x9,
};
+/* NAVI-AMD HCNT/LCNT/SDA hold time */
+static struct dw_scl_sda_cfg navi_amd_config = {
+ .ss_hcnt = 0x1ae,
+ .ss_lcnt = 0x23a,
+ .sda_hold = 0x9,
+};
+
static u32 mfld_get_clk_rate_khz(struct dw_i2c_dev *dev)
{
return 25000;
}
+static u32 navi_amd_get_clk_rate_khz(struct dw_i2c_dev *dev)
+{
+ return AMD_CLK_RATE_HZ;
+}
+
static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
{
struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
@@ -104,6 +118,35 @@ static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
return -ENODEV;
}
+ /*
+ * TODO find a better way how to deduplicate instantiation
+ * of USB PD slave device from nVidia GPU driver.
+ */
+static int navi_amd_register_client(struct dw_i2c_dev *dev)
+{
+ struct i2c_board_info info;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strscpy(info.type, "ccgx-ucsi", I2C_NAME_SIZE);
+ info.addr = 0x08;
+ info.irq = dev->irq;
+
+ dev->slave = i2c_new_client_device(&dev->adapter, &info);
+ if (!dev->slave)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
+{
+ struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
+
+ dev->flags |= MODEL_AMD_NAVI_GPU;
+ dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
+ return 0;
+}
+
static int mrfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
{
/*
@@ -155,6 +198,12 @@ static struct dw_pci_controller dw_pci_controllers[] = {
.bus_num = -1,
.get_clk_rate_khz = ehl_get_clk_rate_khz,
},
+ [navi_amd] = {
+ .bus_num = -1,
+ .scl_sda_cfg = &navi_amd_config,
+ .setup = navi_amd_setup,
+ .get_clk_rate_khz = navi_amd_get_clk_rate_khz,
+ },
};
#ifdef CONFIG_PM
@@ -274,6 +323,14 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
return r;
}
+ if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) {
+ r = navi_amd_register_client(dev);
+ if (r) {
+ dev_err(dev->dev, "register client failed with %d\n", r);
+ return r;
+ }
+ }
+
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
@@ -337,6 +394,10 @@ static const struct pci_device_id i2_designware_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x4bbe), elkhartlake },
{ PCI_VDEVICE(INTEL, 0x4bbf), elkhartlake },
{ PCI_VDEVICE(INTEL, 0x4bc0), elkhartlake },
+ { PCI_VDEVICE(ATI, 0x7314), navi_amd },
+ { PCI_VDEVICE(ATI, 0x73a4), navi_amd },
+ { PCI_VDEVICE(ATI, 0x73e4), navi_amd },
+ { PCI_VDEVICE(ATI, 0x73c4), navi_amd },
{ 0,}
};
MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);