浏览代码

i2c: designware: Add support for AMD I2C controller

Add support for AMD version of the DW I2C host controller. The device is
enumerated from ACPI namespace with ACPI ID AMD0010. Because the core
driver needs an input source clock, and this is not an Intel LPSS device
where clocks are provided through drivers/acpi/acpi_lpss.c, we register the
clock ourselves if the clock rate is given in ->driver_data

Signed-off-by: Carl Peng <carlpeng008@gmail.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Carl Peng 11 年之前
父节点
当前提交
a445900c90
共有 2 个文件被更改,包括 28 次插入0 次删除
  1. 1 0
      drivers/i2c/busses/Kconfig
  2. 27 0
      drivers/i2c/busses/i2c-designware-platdrv.c

+ 1 - 0
drivers/i2c/busses/Kconfig

@@ -434,6 +434,7 @@ config I2C_DESIGNWARE_CORE
 config I2C_DESIGNWARE_PLATFORM
 config I2C_DESIGNWARE_PLATFORM
 	tristate "Synopsys DesignWare Platform"
 	tristate "Synopsys DesignWare Platform"
 	select I2C_DESIGNWARE_CORE
 	select I2C_DESIGNWARE_CORE
+	depends on (ACPI && COMMON_CLK) || !ACPI
 	help
 	help
 	  If you say yes to this option, support will be included for the
 	  If you say yes to this option, support will be included for the
 	  Synopsys DesignWare I2C adapter. Only master mode is supported.
 	  Synopsys DesignWare I2C adapter. Only master mode is supported.

+ 27 - 0
drivers/i2c/busses/i2c-designware-platdrv.c

@@ -30,6 +30,7 @@
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/err.h>
 #include <linux/err.h>
@@ -80,6 +81,7 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
 static int dw_i2c_acpi_configure(struct platform_device *pdev)
 static int dw_i2c_acpi_configure(struct platform_device *pdev)
 {
 {
 	struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
 	struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+	const struct acpi_device_id *id;
 
 
 	dev->adapter.nr = -1;
 	dev->adapter.nr = -1;
 	dev->tx_fifo_depth = 32;
 	dev->tx_fifo_depth = 32;
@@ -93,9 +95,29 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
 	dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
 	dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
 			   &dev->sda_hold_time);
 			   &dev->sda_hold_time);
 
 
+	/*
+	 * Provide a way for Designware I2C host controllers that are not
+	 * based on Intel LPSS to specify their input clock frequency via
+	 * id->driver_data.
+	 */
+	id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
+	if (id && id->driver_data)
+		clk_register_fixed_rate(&pdev->dev, dev_name(&pdev->dev), NULL,
+					CLK_IS_ROOT, id->driver_data);
+
 	return 0;
 	return 0;
 }
 }
 
 
+static void dw_i2c_acpi_unconfigure(struct platform_device *pdev)
+{
+	struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+	const struct acpi_device_id *id;
+
+	id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
+	if (id && id->driver_data)
+		clk_unregister(dev->clk);
+}
+
 static const struct acpi_device_id dw_i2c_acpi_match[] = {
 static const struct acpi_device_id dw_i2c_acpi_match[] = {
 	{ "INT33C2", 0 },
 	{ "INT33C2", 0 },
 	{ "INT33C3", 0 },
 	{ "INT33C3", 0 },
@@ -103,6 +125,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
 	{ "INT3433", 0 },
 	{ "INT3433", 0 },
 	{ "80860F41", 0 },
 	{ "80860F41", 0 },
 	{ "808622C1", 0 },
 	{ "808622C1", 0 },
+	{ "AMD0010", 133 * 1000 * 1000 },
 	{ }
 	{ }
 };
 };
 MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
 MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
@@ -111,6 +134,7 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
 {
 {
 	return -ENODEV;
 	return -ENODEV;
 }
 }
+static inline void dw_i2c_acpi_unconfigure(struct platform_device *pdev) { }
 #endif
 #endif
 
 
 static int dw_i2c_probe(struct platform_device *pdev)
 static int dw_i2c_probe(struct platform_device *pdev)
@@ -258,6 +282,9 @@ static int dw_i2c_remove(struct platform_device *pdev)
 	pm_runtime_put(&pdev->dev);
 	pm_runtime_put(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
 
+	if (ACPI_COMPANION(&pdev->dev))
+		dw_i2c_acpi_unconfigure(pdev);
+
 	return 0;
 	return 0;
 }
 }