diff options
Diffstat (limited to 'drivers/ata/sata_exynos_phy.c')
-rw-r--r-- | drivers/ata/sata_exynos_phy.c | 180 |
1 files changed, 86 insertions, 94 deletions
diff --git a/drivers/ata/sata_exynos_phy.c b/drivers/ata/sata_exynos_phy.c index 38f7e8db13fc..e9417097ffb2 100644 --- a/drivers/ata/sata_exynos_phy.c +++ b/drivers/ata/sata_exynos_phy.c @@ -21,15 +21,16 @@ #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> #include <mach/map.h> #include <mach/regs-pmu.h> -#include <mach/regs-sata.h> #include "sata_phy.h" +#include "sata_exynos_phy.h" #define SATA_TIME_LIMIT 1000 @@ -39,8 +40,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) @@ -54,17 +57,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; @@ -77,15 +104,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); @@ -115,11 +146,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); @@ -137,129 +168,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; } @@ -278,8 +270,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, @@ -291,9 +283,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, }; |