aboutsummaryrefslogtreecommitdiff
path: root/drivers/ata/sata_phy.c
diff options
context:
space:
mode:
authorYuvaraj Kumar C D <yuvaraj.cd@gmail.com>2013-05-17 15:56:24 +0530
committerAndrey Konovalov <andrey.konovalov@linaro.org>2014-04-16 23:51:34 +0400
commit6f7f0bd9ad62bda74b48a950418aa676b6884f2b (patch)
treef4942f403eb0f6f9effad5cae821257f098bd862 /drivers/ata/sata_phy.c
parent4c6484650554ca333492b7b4ed190a5c748cfd2b (diff)
ata: samsung: Rebase as per 3.10-rc1
This patchset integrate the SATA patches submitted by Vasanth Ananthan. In addition to that SATA and SATA PHY driver will use common clock framework API. Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com> Signed-off-by: Tushar Behera <tushar.behera@linaro.org>
Diffstat (limited to 'drivers/ata/sata_phy.c')
-rw-r--r--drivers/ata/sata_phy.c107
1 files changed, 75 insertions, 32 deletions
diff --git a/drivers/ata/sata_phy.c b/drivers/ata/sata_phy.c
index e5631a97951..53d441775d7 100644
--- a/drivers/ata/sata_phy.c
+++ b/drivers/ata/sata_phy.c
@@ -2,7 +2,14 @@
* Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * EXYNOS - SATA utility framework.
+ * SATA PHY framework.
+ *
+ * This file provides a set of functions/interfaces for establishing
+ * communication between SATA controller and the PHY controller. A
+ * PHY controller driver registers call backs for its initialization and
+ * shutdown. The SATA controller driver finds the appropriate PHYs for
+ * its implemented ports and initialize/shutdown PHYs through the
+ * call backs provided.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,47 +27,59 @@
static LIST_HEAD(phy_list);
static DEFINE_SPINLOCK(phy_lock);
-struct sata_phy *sata_get_phy(enum sata_phy_type type)
+struct sata_phy *sata_get_phy(struct device_node *phy_np)
{
- struct sata_phy *x = NULL;
+ struct sata_phy *phy;
unsigned long flag;
- if (list_empty(&phy_list))
- return x;
-
spin_lock_irqsave(&phy_lock, flag);
- list_for_each_entry(x, &phy_list, head) {
- if (x->type == type) {
- get_device(x->dev);
- break;
+ if (list_empty(&phy_list)) {
+ spin_unlock_irqrestore(&phy_lock, flag);
+ return ERR_PTR(-ENODEV);
+ }
+
+ list_for_each_entry(phy, &phy_list, head) {
+ if (phy->dev->of_node == phy_np) {
+ if (phy->status == IN_USE) {
+ pr_info(KERN_INFO
+ "PHY already in use\n");
+ spin_unlock_irqrestore(&phy_lock, flag);
+ return ERR_PTR(-EBUSY);
+ }
+
+ get_device(phy->dev);
+ phy->status = IN_USE;
+ spin_unlock_irqrestore(&phy_lock, flag);
+ return phy;
}
}
spin_unlock_irqrestore(&phy_lock, flag);
- return x;
+ return ERR_PTR(-ENODEV);
}
EXPORT_SYMBOL(sata_get_phy);
-int sata_add_phy(struct sata_phy *phy, enum sata_phy_type type)
+int sata_add_phy(struct sata_phy *sataphy)
{
unsigned long flag;
unsigned int ret = -EINVAL;
- struct sata_phy *x;
+ struct sata_phy *phy;
- spin_lock_irqsave(&phy_lock, flag);
-
- if (!phy)
+ if (!sataphy)
return ret;
- list_for_each_entry(x, &phy_list, head) {
- if (x->type == type) {
- dev_err(phy->dev, "transceiver type already exists\n");
+ spin_lock_irqsave(&phy_lock, flag);
+
+ list_for_each_entry(phy, &phy_list, head) {
+ if (phy->dev->of_node == sataphy->dev->of_node) {
+ dev_err(sataphy->dev, "PHY already exists in the list\n");
goto out;
}
}
- phy->type = type;
- list_add_tail(&phy->head, &phy_list);
+
+ sataphy->status = NOT_IN_USE;
+ list_add_tail(&sataphy->head, &phy_list);
ret = 0;
out:
@@ -69,18 +88,24 @@ int sata_add_phy(struct sata_phy *phy, enum sata_phy_type type)
}
EXPORT_SYMBOL(sata_add_phy);
-void sata_remove_phy(struct sata_phy *phy)
+void sata_remove_phy(struct sata_phy *sataphy)
{
unsigned long flag;
- struct sata_phy *x;
+ struct sata_phy *phy;
- spin_lock_irqsave(&phy_lock, flag);
+ if (!sataphy)
+ return;
- if (!phy)
+ if (sataphy->status == IN_USE) {
+ pr_info(KERN_INFO
+ "PHY in use, cannot be removed\n");
return;
+ }
+
+ spin_lock_irqsave(&phy_lock, flag);
- list_for_each_entry(x, &phy_list, head) {
- if (x->type == phy->type)
+ list_for_each_entry(phy, &phy_list, head) {
+ if (phy->dev->of_node == sataphy->dev->of_node)
list_del(&phy->head);
}
@@ -88,17 +113,35 @@ void sata_remove_phy(struct sata_phy *phy)
}
EXPORT_SYMBOL(sata_remove_phy);
-void sata_put_phy(struct sata_phy *phy)
+void sata_put_phy(struct sata_phy *sataphy)
{
unsigned long flag;
+ if (!sataphy)
+ return;
+
spin_lock_irqsave(&phy_lock, flag);
- if (!phy)
- return;
+ put_device(sataphy->dev);
+ sataphy->status = NOT_IN_USE;
- put_device(phy->dev);
spin_unlock_irqrestore(&phy_lock, flag);
-
}
EXPORT_SYMBOL(sata_put_phy);
+
+int sata_init_phy(struct sata_phy *sataphy)
+{
+ if (sataphy && sataphy->init)
+ return sataphy->init(sataphy);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(sata_init_phy);
+
+void sata_shutdown_phy(struct sata_phy *sataphy)
+{
+ if (sataphy && sataphy->shutdown)
+ sataphy->shutdown(sataphy);
+}
+EXPORT_SYMBOL(sata_shutdown_phy);
+