Message ID | 1349783332-18467-7-git-send-email-vasanthananthan@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi, On Tuesday 09 of October 2012 17:18:52 Vasanth Ananthan wrote: > This patch adds a platform driver and I2C client driver for SATA PHY > controller > > Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> > --- > drivers/ata/Makefile | 2 +- > drivers/ata/sata_exynos_phy.c | 303 > +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 304 > insertions(+), 1 deletions(-) > create mode 100644 drivers/ata/sata_exynos_phy.c > > diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile > index 33fb2f6..769d945 100644 > --- a/drivers/ata/Makefile > +++ b/drivers/ata/Makefile > @@ -9,7 +9,7 @@ obj-$(CONFIG_SATA_FSL) += sata_fsl.o > obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o > obj-$(CONFIG_SATA_SIL24) += sata_sil24.o > obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o > -obj-$(CONFIG_SATA_EXYNOS) += sata_phy.o sata_exynos.o > libahci.o +obj-$(CONFIG_SATA_EXYNOS) += sata_phy.o > sata_exynos_phy.o sata_exynos.o libahci.o > > # SFF w/ custom DMA > obj-$(CONFIG_PDC_ADMA) += pdc_adma.o > diff --git a/drivers/ata/sata_exynos_phy.c > b/drivers/ata/sata_exynos_phy.c new file mode 100644 > index 0000000..44861de > --- /dev/null > +++ b/drivers/ata/sata_exynos_phy.c > @@ -0,0 +1,303 @@ > +/* > + * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd. > + * http://www.samsung.com > + * > + * EXYNOS - SATA PHY controller driver > + * > + * 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. > +*/ > + > +#include <linux/module.h> > +#include <linux/device.h> > +#include <linux/platform_device.h> > +#include <linux/i2c.h> > +#include <linux/clk.h> > +#include <linux/delay.h> > +#include <linux/dma-mapping.h> > +#include <linux/ahci_platform.h> > +#include <linux/kernel.h> > +#include <linux/slab.h> > +#include <linux/list.h> > + > +#include <plat/cpu.h> > + > +#include <mach/irqs.h> > +#include <mach/map.h> > +#include <mach/regs-pmu.h> > +#include <mach/regs-sata.h> > + > +#include "sata_phy.h" > + > +#define SATA_TIME_LIMIT 1000 > + > +static struct i2c_client *i2c_client; > + > +static struct i2c_driver sataphy_i2c_driver; > + > +struct exynos_sata_phy { > + void __iomem *mmio; > + struct resource *mem; > + struct clk *clk; > +}; > + > +static bool sata_is_reg(void __iomem *base, u32 reg, u32 checkbit, u32 > Status) +{ Please use lowercase for variable names. > + if ((readl(base + reg) & checkbit) == Status) > + return true; > + else > + return false; > +} > + > +static bool wait_for_reg_status(void __iomem *base, u32 reg, u32 > checkbit, + u32 Status) Same here. > +{ > + 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++; > + } > + return true; > +} > + > +int sataphy_init(struct sata_phy *phy) static int sataphy_init(struct sata_phy *phy) ? > +{ > + int ret; > + u32 val; > + > + /* Values to be written to enable 40 bits interface */ > + u8 buf[] = { 0x3A, 0x0B }; > + > + struct exynos_sata_phy *sata_phy; > + > + sata_phy = (struct exynos_sata_phy *)phy->priv_data; > + > + clk_enable(sata_phy->clk); > + > + writel(S5P_PMU_SATA_PHY_CONTROL_EN, EXYNOS5_SATA_PHY_CONTROL); > + > + val = 0; > + writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); > + > + val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET); > + val |= 0xFF; > + writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); > + > + val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET); > + val |= LINK_RESET; > + writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); > + > + val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET); > + val |= RESET_CMN_RST_N; > + writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); > + > + val = readl(sata_phy->mmio + EXYNOS5_SATA_PHSATA_CTRLM); > + val &= ~PHCTRLM_REF_RATE; > + writel(val, sata_phy->mmio + EXYNOS5_SATA_PHSATA_CTRLM); > + > + /* High speed enable for Gen3 */ > + val = readl(sata_phy->mmio + EXYNOS5_SATA_PHSATA_CTRLM); > + val |= PHCTRLM_HIGH_SPEED; > + writel(val, sata_phy->mmio + EXYNOS5_SATA_PHSATA_CTRLM); > + > + val = readl(sata_phy->mmio + EXYNOS5_SATA_CTRL0); > + 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); > + > + ret = i2c_master_send(i2c_client, buf, sizeof(buf)); > + if (ret < 0) > + return -EINVAL; > + > + /* release cmu reset */ > + val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET); > + val &= ~RESET_CMN_RST_N; > + writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); > + > + val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET); > + val |= RESET_CMN_RST_N; > + writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); > + > + if (wait_for_reg_status(sata_phy->mmio, EXYNOS5_SATA_PHSATA_STATM, > + PHSTATM_PLL_LOCKED, 1)) { > + return 0; > + } > + return -EINVAL; > +} > + > +int sataphy_shutdown(struct sata_phy *phy) static int 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); > + > + return 0; > +} > + > +static int sata_i2c_probe(struct i2c_client *client, > + const struct i2c_device_id *i2c_id) > +{ > + i2c_client = client; > + return 0; > +} > + > +static int __init sata_phy_probe(struct platform_device *pdev) > +{ > + struct exynos_sata_phy *sataphy; > + struct sata_phy *phy; > + struct resource *res; > + int ret = 0; > + > + phy = kzalloc(sizeof(struct sata_phy), GFP_KERNEL); devm_ > + if (!phy) { > + dev_err(&pdev->dev, "failed to allocate memory\n"); > + ret = -ENOMEM; > + goto out; > + } > + > + sataphy = kzalloc(sizeof(struct exynos_sata_phy), GFP_KERNEL); devm_ > + if (!sataphy) { > + dev_err(&pdev->dev, "failed to allocate memory\n"); > + ret = -ENOMEM; > + goto err0; > + } > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) { > + dev_err(&pdev->dev, "Could not find IO resource\n"); > + ret = -EINVAL; > + goto err1; > + } > + > + sataphy->mem = request_mem_region(res->start, resource_size(res), > + pdev->name); devm_ > + if (!sataphy->mem) { > + dev_err(&pdev->dev, "Could not request IO resource\n"); > + ret = -EINVAL; > + goto err1; > + } > + > + sataphy->mmio = > + ioremap(res->start, resource_size(res)); devm_ > + nitpick: Unnecessary blank line. > + if (!sataphy->mmio) { > + dev_err(&pdev->dev, "failed to remap IO\n"); > + ret = -ENOMEM; > + goto err2; > + } > + > + sataphy->clk = clk_get(&pdev->dev, "sata_phy"); devm_ > + if (IS_ERR(sataphy->clk)) { > + dev_err(&pdev->dev, "failed to get clk for PHY\n"); > + ret = PTR_ERR(sataphy->clk); > + sataphy->clk = NULL; > + goto err3; > + } > + > + phy->init = sataphy_init; > + phy->shutdown = sataphy_shutdown; > + phy->priv_data = (void *)sataphy; > + phy->dev = &pdev->dev; > + > + ret = sata_add_phy(phy, SATA_PHY_GENERATION3); > + if (ret < 0) > + goto err4; Do you have any warranties that phy callbacks won't get called before i2c device probes and sets i2c_client? > + > + ret = i2c_add_driver(&sataphy_i2c_driver); > + if (ret < 0) > + goto err5; > + > + platform_set_drvdata(pdev, phy); > + > + return ret; > + > + err5: > + sata_remove_phy(phy); > + > + err4: > + clk_put(sataphy->clk); > + > + err3: > + iounmap(sataphy->mmio); > + > + err2: > + release_resource(sataphy->mem); > + > + err1: > + kfree(sataphy); > + > + err0: > + kfree(phy); > + > + out: > + return ret; > +} > + > +static int 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); > + > + iounmap(sataphy->mmio); > + > + release_resource(sataphy->mem); > + > + clk_disable(sataphy->clk); > + clk_put(sataphy->clk); > + > + kfree(sataphy); > + kfree(phy); > + > + return 0; > +} > + > +static const struct of_device_id sata_phy_of_match[] = { > + {.compatible = "samsung,exynos-sata-phy",}, nitpick: Space after opening and before closing brackets. > + {}, > +}; > + > +MODULE_DEVICE_TABLE(of, sata_phy_of_match); > + > +static const struct i2c_device_id phy_i2c_device_match[] = { > + {"sataphy", 0}, Same here. > +}; > + > +MODULE_DEVICE_TABLE(of, phy_i2c_device_match); > + > +static struct platform_driver sata_phy_driver = { > + .probe = sata_phy_probe, > + .remove = sata_phy_remove, > + .driver = { > + .name = "sata-phy", > + .owner = THIS_MODULE, > + .of_match_table = sata_phy_of_match, > + }, nitpick: Wrong indentation of closing bracket. > +}; > + > +static struct i2c_driver sataphy_i2c_driver = { > + .driver = { > + .name = "i2c-phy", > + .owner = THIS_MODULE, > + .of_match_table = phy_i2c_device_match, > + }, nitpick: Wrong indentation of closing bracket. Best regards, Tomasz Figa
Hi Tomasz, On Sat, Oct 13, 2012 at 4:20 AM, Tomasz Figa <tomasz.figa@gmail.com> wrote: > Hi, > > On Tuesday 09 of October 2012 17:18:52 Vasanth Ananthan wrote: >> This patch adds a platform driver and I2C client driver for SATA PHY >> controller >> >> Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> >> --- >> drivers/ata/Makefile | 2 +- >> drivers/ata/sata_exynos_phy.c | 303 >> +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 304 >> insertions(+), 1 deletions(-) >> create mode 100644 drivers/ata/sata_exynos_phy.c >> [ ... ] >> + >> + phy->init = sataphy_init; >> + phy->shutdown = sataphy_shutdown; >> + phy->priv_data = (void *)sataphy; >> + phy->dev = &pdev->dev; >> + >> + ret = sata_add_phy(phy, SATA_PHY_GENERATION3); >> + if (ret < 0) >> + goto err4; > > Do you have any warranties that phy callbacks won't get called before i2c > device probes and sets i2c_client? > >> + >> + ret = i2c_add_driver(&sataphy_i2c_driver); >> + if (ret < 0) >> + goto err5; >> + >> + platform_set_drvdata(pdev, phy); I shall register my i2c client driver before assigning the SATA PHY call backs. Would that guarantee the calling of phy callbacks after the i2c device probes? -- Vasanth Ananthan
Hi Vasanth, On Tuesday 16 of October 2012 12:03:47 Vasanth Ananthan wrote: > Hi Tomasz, > > On Sat, Oct 13, 2012 at 4:20 AM, Tomasz Figa <tomasz.figa@gmail.com> wrote: > > Hi, > > > > On Tuesday 09 of October 2012 17:18:52 Vasanth Ananthan wrote: > >> This patch adds a platform driver and I2C client driver for SATA PHY > >> controller > >> > >> Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> > >> --- > >> > >> drivers/ata/Makefile | 2 +- > >> drivers/ata/sata_exynos_phy.c | 303 > >> > >> +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 304 > >> insertions(+), 1 deletions(-) > >> > >> create mode 100644 drivers/ata/sata_exynos_phy.c > > [ ... ] > > >> + > >> + phy->init = sataphy_init; > >> + phy->shutdown = sataphy_shutdown; > >> + phy->priv_data = (void *)sataphy; > >> + phy->dev = &pdev->dev; > >> + > >> + ret = sata_add_phy(phy, SATA_PHY_GENERATION3); > >> + if (ret < 0) > >> + goto err4; > > > > Do you have any warranties that phy callbacks won't get called before > > i2c device probes and sets i2c_client? > > > >> + > >> + ret = i2c_add_driver(&sataphy_i2c_driver); > >> + if (ret < 0) > >> + goto err5; > >> + > >> + platform_set_drvdata(pdev, phy); > > I shall register my i2c client driver before assigning the SATA PHY > call backs. Would that guarantee the calling of phy callbacks after > the i2c device probes? No. You might still not have the sata phy i2c controller registered at that time and so the i2c driver will not be probed. The only definitive solution for this would be to register both platform and i2c drivers in module init (instead of using module_platform_driver) and defer the probe of platform driver until i2c device gets registered. You can defer the probe by returning -EPROBE_DEFER after checking that i2c_client is still NULL. Best regards,
Hi Vasanth, On Tuesday 16 of October 2012 12:03:47 Vasanth Ananthan wrote: > Hi Tomasz, > > On Sat, Oct 13, 2012 at 4:20 AM, Tomasz Figa <tomasz.figa@gmail.com> wrote: > > Hi, > > > > On Tuesday 09 of October 2012 17:18:52 Vasanth Ananthan wrote: > >> This patch adds a platform driver and I2C client driver for SATA PHY > >> controller > >> > >> Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> > >> --- > >> > >> drivers/ata/Makefile | 2 +- > >> drivers/ata/sata_exynos_phy.c | 303 > >> > >> +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 304 > >> insertions(+), 1 deletions(-) > >> > >> create mode 100644 drivers/ata/sata_exynos_phy.c > > [ ... ] > > >> + > >> + phy->init = sataphy_init; > >> + phy->shutdown = sataphy_shutdown; > >> + phy->priv_data = (void *)sataphy; > >> + phy->dev = &pdev->dev; > >> + > >> + ret = sata_add_phy(phy, SATA_PHY_GENERATION3); > >> + if (ret < 0) > >> + goto err4; > > > > Do you have any warranties that phy callbacks won't get called before > > i2c device probes and sets i2c_client? > > > >> + > >> + ret = i2c_add_driver(&sataphy_i2c_driver); > >> + if (ret < 0) > >> + goto err5; > >> + > >> + platform_set_drvdata(pdev, phy); > > I shall register my i2c client driver before assigning the SATA PHY > call backs. Would that guarantee the calling of phy callbacks after > the i2c device probes? No. You might still not have the sata phy i2c controller registered at that time and so the i2c driver will not be probed. The only definitive solution for this would be to register both platform and i2c drivers in module init (instead of using module_platform_driver) and defer the probe of platform driver until i2c device gets registered. You can defer the probe by returning -EPROBE_DEFER after checking that i2c_client is still NULL. Best regards,
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 33fb2f6..769d945 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_SATA_FSL) += sata_fsl.o obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o obj-$(CONFIG_SATA_SIL24) += sata_sil24.o obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o -obj-$(CONFIG_SATA_EXYNOS) += sata_phy.o sata_exynos.o libahci.o +obj-$(CONFIG_SATA_EXYNOS) += sata_phy.o sata_exynos_phy.o sata_exynos.o libahci.o # SFF w/ custom DMA obj-$(CONFIG_PDC_ADMA) += pdc_adma.o diff --git a/drivers/ata/sata_exynos_phy.c b/drivers/ata/sata_exynos_phy.c new file mode 100644 index 0000000..44861de --- /dev/null +++ b/drivers/ata/sata_exynos_phy.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * EXYNOS - SATA PHY controller driver + * + * 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. +*/ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/ahci_platform.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/list.h> + +#include <plat/cpu.h> + +#include <mach/irqs.h> +#include <mach/map.h> +#include <mach/regs-pmu.h> +#include <mach/regs-sata.h> + +#include "sata_phy.h" + +#define SATA_TIME_LIMIT 1000 + +static struct i2c_client *i2c_client; + +static struct i2c_driver sataphy_i2c_driver; + +struct exynos_sata_phy { + void __iomem *mmio; + struct resource *mem; + struct clk *clk; +}; + +static bool sata_is_reg(void __iomem *base, u32 reg, u32 checkbit, u32 Status) +{ + if ((readl(base + reg) & checkbit) == Status) + return true; + else + return false; +} + +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++; + } + return true; +} + +int sataphy_init(struct sata_phy *phy) +{ + int ret; + u32 val; + + /* Values to be written to enable 40 bits interface */ + u8 buf[] = { 0x3A, 0x0B }; + + struct exynos_sata_phy *sata_phy; + + sata_phy = (struct exynos_sata_phy *)phy->priv_data; + + clk_enable(sata_phy->clk); + + writel(S5P_PMU_SATA_PHY_CONTROL_EN, EXYNOS5_SATA_PHY_CONTROL); + + val = 0; + writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); + + val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET); + val |= 0xFF; + writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); + + val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET); + val |= LINK_RESET; + writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); + + val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET); + val |= RESET_CMN_RST_N; + writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); + + val = readl(sata_phy->mmio + EXYNOS5_SATA_PHSATA_CTRLM); + val &= ~PHCTRLM_REF_RATE; + writel(val, sata_phy->mmio + EXYNOS5_SATA_PHSATA_CTRLM); + + /* High speed enable for Gen3 */ + val = readl(sata_phy->mmio + EXYNOS5_SATA_PHSATA_CTRLM); + val |= PHCTRLM_HIGH_SPEED; + writel(val, sata_phy->mmio + EXYNOS5_SATA_PHSATA_CTRLM); + + val = readl(sata_phy->mmio + EXYNOS5_SATA_CTRL0); + 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); + + ret = i2c_master_send(i2c_client, buf, sizeof(buf)); + if (ret < 0) + return -EINVAL; + + /* release cmu reset */ + val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET); + val &= ~RESET_CMN_RST_N; + writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); + + val = readl(sata_phy->mmio + EXYNOS5_SATA_RESET); + val |= RESET_CMN_RST_N; + writel(val, sata_phy->mmio + EXYNOS5_SATA_RESET); + + if (wait_for_reg_status(sata_phy->mmio, EXYNOS5_SATA_PHSATA_STATM, + PHSTATM_PLL_LOCKED, 1)) { + return 0; + } + return -EINVAL; +} + +int 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); + + return 0; +} + +static int sata_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + i2c_client = client; + return 0; +} + +static int __init sata_phy_probe(struct platform_device *pdev) +{ + struct exynos_sata_phy *sataphy; + struct sata_phy *phy; + struct resource *res; + 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); + if (!sataphy) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + ret = -ENOMEM; + goto err0; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Could not find IO resource\n"); + ret = -EINVAL; + goto err1; + } + + sataphy->mem = request_mem_region(res->start, resource_size(res), + pdev->name); + if (!sataphy->mem) { + dev_err(&pdev->dev, "Could not request IO resource\n"); + ret = -EINVAL; + goto err1; + } + + sataphy->mmio = + ioremap(res->start, resource_size(res)); + + if (!sataphy->mmio) { + dev_err(&pdev->dev, "failed to remap IO\n"); + ret = -ENOMEM; + goto err2; + } + + sataphy->clk = clk_get(&pdev->dev, "sata_phy"); + if (IS_ERR(sataphy->clk)) { + dev_err(&pdev->dev, "failed to get clk for PHY\n"); + ret = PTR_ERR(sataphy->clk); + sataphy->clk = NULL; + goto err3; + } + + phy->init = sataphy_init; + phy->shutdown = sataphy_shutdown; + phy->priv_data = (void *)sataphy; + phy->dev = &pdev->dev; + + ret = sata_add_phy(phy, SATA_PHY_GENERATION3); + if (ret < 0) + goto err4; + + ret = i2c_add_driver(&sataphy_i2c_driver); + if (ret < 0) + goto err5; + + platform_set_drvdata(pdev, phy); + + return ret; + + err5: + sata_remove_phy(phy); + + err4: + clk_put(sataphy->clk); + + err3: + iounmap(sataphy->mmio); + + err2: + release_resource(sataphy->mem); + + err1: + kfree(sataphy); + + err0: + kfree(phy); + + out: + return ret; +} + +static int 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); + + iounmap(sataphy->mmio); + + release_resource(sataphy->mem); + + clk_disable(sataphy->clk); + clk_put(sataphy->clk); + + kfree(sataphy); + kfree(phy); + + return 0; +} + +static const struct of_device_id sata_phy_of_match[] = { + {.compatible = "samsung,exynos-sata-phy",}, + {}, +}; + +MODULE_DEVICE_TABLE(of, sata_phy_of_match); + +static const struct i2c_device_id phy_i2c_device_match[] = { + {"sataphy", 0}, +}; + +MODULE_DEVICE_TABLE(of, phy_i2c_device_match); + +static struct platform_driver sata_phy_driver = { + .probe = sata_phy_probe, + .remove = sata_phy_remove, + .driver = { + .name = "sata-phy", + .owner = THIS_MODULE, + .of_match_table = sata_phy_of_match, + }, +}; + +static struct i2c_driver sataphy_i2c_driver = { + .driver = { + .name = "i2c-phy", + .owner = THIS_MODULE, + .of_match_table = phy_i2c_device_match, + }, + .probe = sata_i2c_probe, + .id_table = phy_i2c_device_match, +}; + +module_platform_driver(sata_phy_driver); + +MODULE_DESCRIPTION("EXYNOS SATA PHY DRIVER"); +MODULE_AUTHOR("Vasanth Ananthan, <vasanth.a@samsung.com>"); +MODULE_LICENSE("GPL");
This patch adds a platform driver and I2C client driver for SATA PHY controller Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com> --- drivers/ata/Makefile | 2 +- drivers/ata/sata_exynos_phy.c | 303 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 304 insertions(+), 1 deletions(-) create mode 100644 drivers/ata/sata_exynos_phy.c