@@ -6,6 +6,7 @@
#define pr_fmt(fmt) "aspeed-kcs-bmc: " fmt
#include <linux/atomic.h>
+#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -126,6 +127,8 @@ struct aspeed_kcs_bmc {
bool remove;
struct timer_list timer;
} obe;
+
+ struct clk *clk;
};
struct aspeed_kcs_of_ops {
@@ -620,24 +623,37 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
return -ENODEV;
}
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ rc = PTR_ERR(priv->clk);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Couldn't get clock\n");
+ return rc;
+ }
+ rc = clk_prepare_enable(priv->clk);
+ if (rc) {
+ dev_err(&pdev->dev, "Couldn't enable clock\n");
+ return rc;
+ }
+
spin_lock_init(&priv->obe.lock);
priv->obe.remove = false;
timer_setup(&priv->obe.timer, aspeed_kcs_check_obe, 0);
rc = aspeed_kcs_set_address(kcs_bmc, addrs, nr_addrs);
if (rc)
- return rc;
+ goto err;
/* Host to BMC IRQ */
rc = aspeed_kcs_config_downstream_irq(kcs_bmc, pdev);
if (rc)
- return rc;
+ goto err;
/* BMC to Host IRQ */
if (have_upstream_irq) {
rc = aspeed_kcs_config_upstream_irq(priv, upstream_irq[0], upstream_irq[1]);
if (rc < 0)
- return rc;
+ goto err;
} else {
priv->upstream_irq.mode = aspeed_kcs_irq_none;
}
@@ -650,13 +666,19 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
rc = kcs_bmc_add_device(&priv->kcs_bmc);
if (rc) {
dev_warn(&pdev->dev, "Failed to register channel %d: %d\n", kcs_bmc->channel, rc);
- return rc;
+ goto err;
}
dev_info(&pdev->dev, "Initialised channel %d at 0x%x\n",
kcs_bmc->channel, addrs[0]);
return 0;
+
+err:
+ aspeed_kcs_enable_channel(kcs_bmc, false);
+ clk_disable_unprepare(priv->clk);
+
+ return rc;
}
static int aspeed_kcs_remove(struct platform_device *pdev)
@@ -664,6 +686,7 @@ static int aspeed_kcs_remove(struct platform_device *pdev)
struct aspeed_kcs_bmc *priv = platform_get_drvdata(pdev);
struct kcs_bmc_device *kcs_bmc = &priv->kcs_bmc;
+ clk_disable_unprepare(priv->clk);
kcs_bmc_remove_device(kcs_bmc);
aspeed_kcs_enable_channel(kcs_bmc, false);