diff options
author | Yuvaraj Kumar C D <yuvaraj.cd@gmail.com> | 2013-05-17 15:56:24 +0530 |
---|---|---|
committer | Andrey Konovalov <andrey.konovalov@linaro.org> | 2014-04-16 23:51:34 +0400 |
commit | 6f7f0bd9ad62bda74b48a950418aa676b6884f2b (patch) | |
tree | f4942f403eb0f6f9effad5cae821257f098bd862 /drivers/ata | |
parent | 4c6484650554ca333492b7b4ed190a5c748cfd2b (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')
-rw-r--r-- | drivers/ata/sata_exynos.c | 183 | ||||
-rw-r--r-- | drivers/ata/sata_exynos_phy.c | 179 | ||||
-rw-r--r-- | drivers/ata/sata_exynos_phy.h | 32 | ||||
-rw-r--r-- | drivers/ata/sata_phy.c | 107 | ||||
-rw-r--r-- | drivers/ata/sata_phy.h | 32 |
5 files changed, 313 insertions, 220 deletions
diff --git a/drivers/ata/sata_exynos.c b/drivers/ata/sata_exynos.c index 01ec82e1b3c..1dcfb2c8d0d 100644 --- a/drivers/ata/sata_exynos.c +++ b/drivers/ata/sata_exynos.c @@ -2,7 +2,7 @@ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * EXYNOS - SATA controller driver + * EXYNOS - SATA controller platform driver wrapper * * 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 @@ -21,11 +21,15 @@ #include <linux/clk.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> #include "ahci.h" #include "sata_phy.h" -#define MHZ (1000 * 1000) +#define MHZ (1000 * 1000) +#define DEFERED 1 +#define NO_PORT 0 static const struct ata_port_info ahci_port_info = { .flags = AHCI_FLAG_COMMON, @@ -41,18 +45,19 @@ static struct scsi_host_template ahci_platform_sht = { struct exynos_sata { struct clk *sclk; struct clk *clk; - struct sata_phy *phy; int irq; unsigned int freq; + struct sata_phy *phy[]; }; -static void exynos_sata_parse_dt(struct device_node *np, +static int exynos_sata_parse_dt(struct device_node *np, struct exynos_sata *sata) { if (!np) - return; + return -EINVAL; - of_property_read_u32(np, "samsung,sata-freq", &sata->freq); + return of_property_read_u32(np, "samsung,sata-freq", + &sata->freq); } static int exynos_sata_probe(struct platform_device *pdev) @@ -63,80 +68,72 @@ static int exynos_sata_probe(struct platform_device *pdev) struct ahci_host_priv *hpriv; struct exynos_sata *sata; struct ata_host *host; - struct resource *mem; + struct device_node *of_node_phy = NULL; + static int flag = 0, port_init = NO_PORT; int n_ports, i, ret; sata = devm_kzalloc(dev, sizeof(*sata), GFP_KERNEL); if (!sata) { dev_err(dev, "can't alloc sata\n"); - return -EINVAL; + return -ENOMEM; } hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) { dev_err(dev, "can't alloc ahci_host_priv\n"); - ret = -ENOMEM; - goto err1; + return -ENOMEM; } hpriv->flags |= (unsigned long)pi.private_data; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(dev, "no mmio space\n"); - ret = -EINVAL; - goto err2; - } - - sata->irq = platform_get_irq(pdev, 0); + sata->irq = irq_of_parse_and_map(dev->of_node, 0); if (sata->irq <= 0) { - dev_err(dev, "no irq\n"); - ret = -EINVAL; - goto err2; + dev_err(dev, "irq not specified\n"); + return -EINVAL; } - hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem)); + hpriv->mmio = of_iomap(dev->of_node, 0); if (!hpriv->mmio) { - dev_err(dev, "can't map %pR\n", mem); - ret = -ENOMEM; - goto err2; + dev_err(dev, "failed to map IO\n"); + return -ENOMEM; } - exynos_sata_parse_dt(dev->of_node, sata); + ret = exynos_sata_parse_dt(dev->of_node, sata); + if (ret < 0) { + dev_err(dev, "failed to get frequency for sata ctrl\n"); + goto err_iomap; + } sata->sclk = devm_clk_get(dev, "sclk_sata"); if (IS_ERR(sata->sclk)) { dev_err(dev, "failed to get sclk_sata\n"); ret = PTR_ERR(sata->sclk); - goto err3; + goto err_iomap; } - clk_enable(sata->sclk); - clk_set_rate(sata->sclk, sata->freq * MHZ); + ret = clk_prepare_enable(sata->sclk); + if (ret < 0) { + dev_err(dev, "failed to enable source clk\n"); + goto err_iomap; + } + + ret = clk_set_rate(sata->sclk, sata->freq * MHZ); + if (ret < 0) { + dev_err(dev, "failed to set clk frequency\n"); + goto err_clkstrt; + } sata->clk = devm_clk_get(dev, "sata"); if (IS_ERR(sata->clk)) { dev_err(dev, "failed to get sata clock\n"); ret = PTR_ERR(sata->clk); - goto err4; - } - clk_enable(sata->clk); - - /* Get a gen 3 PHY controller */ - - sata->phy = sata_get_phy(SATA_PHY_GENERATION3); - if (!sata->phy) { - dev_err(dev, "failed to get sata phy\n"); - ret = -EPROBE_DEFER; - goto err5; + goto err_clkstrt; } - /* Initialize the controller */ - - ret = sata_init_phy(sata->phy); + ret = clk_prepare_enable(sata->clk); if (ret < 0) { - dev_err(dev, "failed to initialize sata phy\n"); - goto err6; + dev_err(dev, "failed to enable source clk\n"); + goto err_clkstrt; } ahci_save_initial_config(dev, hpriv, 0, 0); @@ -160,7 +157,7 @@ static int exynos_sata_probe(struct platform_device *pdev) host = ata_host_alloc_pinfo(dev, ppi, n_ports); if (!host) { ret = -ENOMEM; - goto err7; + goto err_clken; } host->private_data = hpriv; @@ -176,9 +173,46 @@ static int exynos_sata_probe(struct platform_device *pdev) for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; - - ata_port_desc(ap, "mmio %pR", mem); - ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); + of_node_phy = of_parse_phandle(dev->of_node, + "samsung,exynos-sata-phy", i); + if (!of_node_phy) { + dev_err(dev, + "phandle of phy not found for port %d\n", i); + break; + } + + sata->phy[i] = sata_get_phy(of_node_phy); + if (IS_ERR(sata->phy[i])) { + if (PTR_ERR(sata->phy[i]) == -EBUSY) + continue; + dev_err(dev, + "failed to get sata phy for port %d\n", i); + if (flag != DEFERED) { + flag = DEFERED ; + return -EPROBE_DEFER; + } else + continue; + + } + /* Initialize the PHY */ + ret = sata_init_phy(sata->phy[i]); + if (ret < 0) { + if (ret == -EPROBE_DEFER) { + if (flag != DEFERED) { + flag = DEFERED ; + sata_put_phy(sata->phy[i]); + return -EPROBE_DEFER; + } else { + continue; + } + } else { + dev_err(dev, + "failed to initialize sata phy for port %d\n", + i); + sata_put_phy(sata->phy[i]); + } + + } /* set enclosure management message type */ if (ap->flags & ATA_FLAG_EM) @@ -187,11 +221,16 @@ static int exynos_sata_probe(struct platform_device *pdev) /* disabled/not-implemented port */ if (!(hpriv->port_map & (1 << i))) ap->ops = &ata_dummy_port_ops; + + port_init++; } + if (port_init == NO_PORT) + goto err_initphy; + ret = ahci_reset_controller(host); if (ret) - goto err7; + goto err_rst; ahci_init_controller(host); ahci_print_info(host, "platform"); @@ -199,48 +238,48 @@ static int exynos_sata_probe(struct platform_device *pdev) ret = ata_host_activate(host, sata->irq, ahci_interrupt, IRQF_SHARED, &ahci_platform_sht); if (ret) - goto err7; + goto err_rst; platform_set_drvdata(pdev, sata); return 0; - err7: - sata_shutdown_phy(sata->phy); - - err6: - sata_put_phy(sata->phy); + err_rst: + for (i = 0; i < host->n_ports; i++) + sata_shutdown_phy(sata->phy[i]); - err5: - clk_disable(sata->clk); - devm_clk_put(dev, sata->clk); + err_initphy: + for (i = 0; i < host->n_ports; i++) + sata_put_phy(sata->phy[i]); - err4: - clk_disable(sata->sclk); - devm_clk_put(dev, sata->sclk); + err_clken: + clk_disable_unprepare(sata->clk); - err3: - devm_iounmap(dev, hpriv->mmio); + err_clkstrt: + clk_disable_unprepare(sata->sclk); - err2: - devm_kfree(dev, hpriv); - - err1: - devm_kfree(dev, sata); + err_iomap: + iounmap(hpriv->mmio); return ret; } static int exynos_sata_remove(struct platform_device *pdev) { + unsigned int i; struct device *dev = &pdev->dev; struct ata_host *host = dev_get_drvdata(dev); struct exynos_sata *sata = platform_get_drvdata(pdev); + struct ahci_host_priv *hpriv = + (struct ahci_host_priv *)host->private_data; ata_host_detach(host); - sata_shutdown_phy(sata->phy); - sata_put_phy(sata->phy); + for (i = 0; i < host->n_ports; i++) { + sata_shutdown_phy(sata->phy[i]); + sata_put_phy(sata->phy[i]); + } + iounmap(hpriv->mmio); return 0; } @@ -255,7 +294,7 @@ static struct platform_driver exynos_sata_driver = { .probe = exynos_sata_probe, .remove = exynos_sata_remove, .driver = { - .name = "ahci-sata", + .name = "exynos-sata", .owner = THIS_MODULE, .of_match_table = ahci_of_match, }, diff --git a/drivers/ata/sata_exynos_phy.c b/drivers/ata/sata_exynos_phy.c index 8f2c686916b..052b053bd26 100644 --- a/drivers/ata/sata_exynos_phy.c +++ b/drivers/ata/sata_exynos_phy.c @@ -21,6 +21,7 @@ #include <linux/slab.h> #include <linux/list.h> #include <linux/io.h> +#include <linux/of_address.h> #include <plat/cpu.h> #include <plat/irqs.h> @@ -28,6 +29,7 @@ #include <mach/map.h> #include "sata_phy.h" +#include "sata_exynos_phy.h" #define SATA_TIME_LIMIT 1000 @@ -37,8 +39,10 @@ static struct i2c_driver sataphy_i2c_driver; struct exynos_sata_phy { void __iomem *mmio; - struct resource *mem; + void __iomem *pmureg; struct clk *clk; + struct device *dev; + struct sata_phy phy; }; static bool sata_is_reg(void __iomem *base, u32 reg, u32 checkbit, u32 status) @@ -52,17 +56,41 @@ static bool sata_is_reg(void __iomem *base, u32 reg, u32 checkbit, u32 status) static bool wait_for_reg_status(void __iomem *base, u32 reg, u32 checkbit, u32 status) { - u16 time_limit_cnt = 0; - while (!sata_is_reg(base, reg, checkbit, status)) { - if (time_limit_cnt == SATA_TIME_LIMIT) - return false; - udelay(1000); - time_limit_cnt++; + unsigned long timeout = jiffies + usecs_to_jiffies(1000); + + while (time_before(jiffies, timeout)) { + if (sata_is_reg(base, reg, checkbit, status)) + return true; } - return true; + + return false; } -static int sataphy_init(struct sata_phy *phy) +static int exynos_sataphy_parse_dt(struct device *dev, + struct exynos_sata_phy *phy) +{ + struct device_node *sataphy_pmu; + + sataphy_pmu = of_get_child_by_name(dev->of_node, "sataphy-pmu"); + if (!sataphy_pmu) { + dev_err(dev, + "PMU control register for sata-phy not specified\n"); + return -ENODEV; + } + + phy->pmureg = of_iomap(sataphy_pmu, 0); + + of_node_put(sataphy_pmu); + + if (!phy->pmureg) { + dev_err(dev, "Can't get sata-phy pmu control register\n"); + return -EADDRNOTAVAIL; + } + + return 0; +} + +static int exynos_sataphy_init(struct sata_phy *phy) { int ret; u32 val; @@ -75,15 +103,19 @@ static int sataphy_init(struct sata_phy *phy) if (!i2c_client) return -EPROBE_DEFER; - sata_phy = (struct exynos_sata_phy *)phy->priv_data; + sata_phy = container_of(phy, struct exynos_sata_phy, phy); - clk_enable(sata_phy->clk); + ret = clk_prepare_enable(sata_phy->clk); + if (ret < 0) { + dev_err(phy->dev, "failed to enable source clk\n"); + return ret; + } if (sata_is_reg(sata_phy->mmio , EXYNOS5_SATA_CTRL0, CTRL0_P0_PHY_CALIBRATED, CTRL0_P0_PHY_CALIBRATED)) return 0; - writel(S5P_PMU_SATA_PHY_CONTROL_EN, EXYNOS5_SATA_PHY_CONTROL); + writel(SATA_PHY_PMU_EN, sata_phy->pmureg); val = 0; writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); @@ -113,11 +145,11 @@ static int sataphy_init(struct sata_phy *phy) val |= CTRL0_P0_PHY_CALIBRATED_SEL | CTRL0_P0_PHY_CALIBRATED; writel(val, sata_phy->mmio + EXYNOS5_SATA_CTRL0); - writel(SATA_PHY_GENERATION3, sata_phy->mmio + EXYNOS5_SATA_MODE0); + writel(0x2, sata_phy->mmio + EXYNOS5_SATA_MODE0); ret = i2c_master_send(i2c_client, buf, sizeof(buf)); if (ret < 0) - return -EINVAL; + return -ENXIO; /* release cmu reset */ val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET); @@ -135,129 +167,90 @@ static int sataphy_init(struct sata_phy *phy) return -EINVAL; } -static int sataphy_shutdown(struct sata_phy *phy) +static int exynos_sataphy_shutdown(struct sata_phy *phy) { struct exynos_sata_phy *sata_phy; - sata_phy = (struct exynos_sata_phy *)phy->priv_data; - - clk_disable(sata_phy->clk); + sata_phy = container_of(phy, struct exynos_sata_phy, phy); + clk_disable_unprepare(sata_phy->clk); return 0; } -static int sata_i2c_probe(struct i2c_client *client, +static int exynos_sata_i2c_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { i2c_client = client; return 0; } -static int sata_phy_probe(struct platform_device *pdev) +static int exynos_sata_phy_probe(struct platform_device *pdev) { struct exynos_sata_phy *sataphy; - struct sata_phy *phy; - struct resource *res; struct device *dev = &pdev->dev; int ret = 0; - - phy = kzalloc(sizeof(struct sata_phy), GFP_KERNEL); - if (!phy) { - dev_err(&pdev->dev, "failed to allocate memory\n"); - ret = -ENOMEM; - goto out; - } - - sataphy = kzalloc(sizeof(struct exynos_sata_phy), GFP_KERNEL); + sataphy = devm_kzalloc(dev, sizeof(struct exynos_sata_phy), GFP_KERNEL); if (!sataphy) { dev_err(dev, "failed to allocate memory\n"); - ret = -ENOMEM; - goto err0; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "Could not find IO resource\n"); - ret = -EINVAL; - goto err1; - } - - sataphy->mem = devm_request_mem_region(dev, res->start, - resource_size(res), pdev->name); - if (!sataphy->mem) { - dev_err(dev, "Could not request IO resource\n"); - ret = -EINVAL; - goto err1; + return -ENOMEM; } - sataphy->mmio = - devm_ioremap(dev, res->start, resource_size(res)); + sataphy->mmio = of_iomap(dev->of_node, 0); if (!sataphy->mmio) { dev_err(dev, "failed to remap IO\n"); - ret = -ENOMEM; - goto err2; + return -EADDRNOTAVAIL; } - sataphy->clk = devm_clk_get(dev, "sata-phy"); + ret = exynos_sataphy_parse_dt(dev, sataphy); + if (ret != 0) + goto err_iomap; + + sataphy->clk = devm_clk_get(dev, "sata_phyctrl"); if (IS_ERR(sataphy->clk)) { dev_err(dev, "failed to get clk for PHY\n"); ret = PTR_ERR(sataphy->clk); - goto err3; + goto err_pmu; } - phy->init = sataphy_init; - phy->shutdown = sataphy_shutdown; - phy->priv_data = (void *)sataphy; - phy->dev = dev; + sataphy->phy.init = exynos_sataphy_init; + sataphy->phy.shutdown = exynos_sataphy_shutdown; + sataphy->phy.dev = dev; - ret = sata_add_phy(phy, SATA_PHY_GENERATION3); - if (ret < 0) - goto err4; + ret = sata_add_phy(&sataphy->phy); + if (ret < 0) { + dev_err(dev, "PHY not registered with framework\n"); + goto err_iomap; + } ret = i2c_add_driver(&sataphy_i2c_driver); if (ret < 0) - goto err5; + goto err_phy; - platform_set_drvdata(pdev, phy); + platform_set_drvdata(pdev, sataphy); return ret; - err5: - sata_remove_phy(phy); - - err4: - clk_disable(sataphy->clk); - devm_clk_put(dev, sataphy->clk); - - err3: - devm_iounmap(dev, sataphy->mmio); + err_phy: + sata_remove_phy(&sataphy->phy); - err2: - devm_release_mem_region(dev, res->start, resource_size(res)); + err_pmu: + iounmap(sataphy->pmureg); - err1: - kfree(sataphy); + err_iomap: + iounmap(sataphy->mmio); - err0: - kfree(phy); - - out: return ret; } -static int sata_phy_remove(struct platform_device *pdev) +static int exynos_sata_phy_remove(struct platform_device *pdev) { - struct sata_phy *phy; struct exynos_sata_phy *sataphy; - phy = platform_get_drvdata(pdev); - - sataphy = (struct exynos_sata_phy *)phy->priv_data; - sata_remove_phy(phy); - - kfree(sataphy); - kfree(phy); + sataphy = platform_get_drvdata(pdev); + iounmap(sataphy->mmio); + i2c_del_driver(&sataphy_i2c_driver); + sata_remove_phy(&sataphy->phy); return 0; } @@ -276,8 +269,8 @@ static const struct i2c_device_id phy_i2c_device_match[] = { MODULE_DEVICE_TABLE(of, phy_i2c_device_match); static struct platform_driver sata_phy_driver = { - .probe = sata_phy_probe, - .remove = sata_phy_remove, + .probe = exynos_sata_phy_probe, + .remove = exynos_sata_phy_remove, .driver = { .name = "sata-phy", .owner = THIS_MODULE, @@ -289,9 +282,9 @@ static struct i2c_driver sataphy_i2c_driver = { .driver = { .name = "sata-phy-i2c", .owner = THIS_MODULE, - .of_match_table = phy_i2c_device_match, + .of_match_table = (void *)phy_i2c_device_match, }, - .probe = sata_i2c_probe, + .probe = exynos_sata_i2c_probe, .id_table = phy_i2c_device_match, }; diff --git a/drivers/ata/sata_exynos_phy.h b/drivers/ata/sata_exynos_phy.h new file mode 100644 index 00000000000..f9889ccd9ab --- /dev/null +++ b/drivers/ata/sata_exynos_phy.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * EXYNOS - SATA PHY controller definition + * + * 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 + * published by the Free Software Foundation. +*/ + +#define EXYNOS5_SATA_RESET 0x4 +#define RESET_CMN_RST_N (1 << 1) +#define LINK_RESET 0xF0000 + +#define EXYNOS5_SATA_MODE0 0x10 + +#define EXYNOS5_SATA_CTRL0 0x14 +#define CTRL0_P0_PHY_CALIBRATED_SEL (1 << 9) +#define CTRL0_P0_PHY_CALIBRATED (1 << 8) + +#define EXYNOS5_SATA_PHSATA_CTRLM 0xE0 +#define PHCTRLM_REF_RATE (1 << 1) +#define PHCTRLM_HIGH_SPEED (1 << 0) + +#define EXYNOS5_SATA_PHSATA_STATM 0xF0 +#define PHSTATM_PLL_LOCKED (1 << 0) + +#define SATA_PHY_CON_RESET 0xF003F + +#define SATA_PHY_PMU_EN 0x1 + 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); + diff --git a/drivers/ata/sata_phy.h b/drivers/ata/sata_phy.h index dc38683052e..9ed1dbed5a1 100644 --- a/drivers/ata/sata_phy.h +++ b/drivers/ata/sata_phy.h @@ -2,43 +2,29 @@ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * EXYNOS - SATA utility framework definitions. + * SATA utility framework definitions. * * 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 * published by the Free Software Foundation. */ -enum sata_phy_type { - SATA_PHY_GENERATION1, - SATA_PHY_GENERATION2, - SATA_PHY_GENERATION3, -}; +#define IN_USE 1 +#define NOT_IN_USE 0 struct sata_phy { int (*init) (struct sata_phy *); int (*shutdown) (struct sata_phy *); struct device *dev; void *priv_data; - enum sata_phy_type type; struct list_head head; + unsigned char status; }; -static inline int sata_init_phy(struct sata_phy *x) -{ - if (x && x->init) - return x->init(x); - - return -EINVAL; -} - -static inline void sata_shutdown_phy(struct sata_phy *x) -{ - if (x && x->shutdown) - x->shutdown(x); -} - -struct sata_phy *sata_get_phy(enum sata_phy_type); -int sata_add_phy(struct sata_phy *, enum sata_phy_type); +struct sata_phy *sata_get_phy(struct device_node *); +int sata_add_phy(struct sata_phy *); void sata_remove_phy(struct sata_phy *); void sata_put_phy(struct sata_phy *); +int sata_init_phy(struct sata_phy *); +void sata_shutdown_phy(struct sata_phy *); + |