diff options
author | Andrew Lunn <andrew@lunn.ch> | 2013-12-26 12:25:41 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2014-01-20 07:46:15 -0500 |
commit | b7db4f2e15603c394da56a0536a33669f4c87c4f (patch) | |
tree | 086a200e4a87f30ce62b16d489a7be3aa17e6c11 /drivers/ata/sata_mv.c | |
parent | 3a3a8cf51df49e61dce7e623fb2bcc1a9e560efe (diff) |
SATA: MV: Add support for the optional PHYs
Some Marvell SoCs have a SATA PHY which can be powered off, in order
to save power. Make use of the generic phy framework to control these
phys.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/ata/sata_mv.c')
-rw-r--r-- | drivers/ata/sata_mv.c | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index dc9d4b1ea4ec..20a7517bd339 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include <linux/dma-mapping.h> | 60 | #include <linux/dma-mapping.h> |
61 | #include <linux/device.h> | 61 | #include <linux/device.h> |
62 | #include <linux/clk.h> | 62 | #include <linux/clk.h> |
63 | #include <linux/phy/phy.h> | ||
63 | #include <linux/platform_device.h> | 64 | #include <linux/platform_device.h> |
64 | #include <linux/ata_platform.h> | 65 | #include <linux/ata_platform.h> |
65 | #include <linux/mbus.h> | 66 | #include <linux/mbus.h> |
@@ -565,6 +566,12 @@ struct mv_host_priv { | |||
565 | struct clk *clk; | 566 | struct clk *clk; |
566 | struct clk **port_clks; | 567 | struct clk **port_clks; |
567 | /* | 568 | /* |
569 | * Some devices have a SATA PHY which can be enabled/disabled | ||
570 | * in order to save power. These are optional: if the platform | ||
571 | * devices does not have any phy, they won't be used. | ||
572 | */ | ||
573 | struct phy **port_phys; | ||
574 | /* | ||
568 | * These consistent DMA memory pools give us guaranteed | 575 | * These consistent DMA memory pools give us guaranteed |
569 | * alignment for hardware-accessed data structures, | 576 | * alignment for hardware-accessed data structures, |
570 | * and less memory waste in accomplishing the alignment. | 577 | * and less memory waste in accomplishing the alignment. |
@@ -4091,6 +4098,11 @@ static int mv_platform_probe(struct platform_device *pdev) | |||
4091 | GFP_KERNEL); | 4098 | GFP_KERNEL); |
4092 | if (!hpriv->port_clks) | 4099 | if (!hpriv->port_clks) |
4093 | return -ENOMEM; | 4100 | return -ENOMEM; |
4101 | hpriv->port_phys = devm_kzalloc(&pdev->dev, | ||
4102 | sizeof(struct phy *) * n_ports, | ||
4103 | GFP_KERNEL); | ||
4104 | if (!hpriv->port_phys) | ||
4105 | return -ENOMEM; | ||
4094 | host->private_data = hpriv; | 4106 | host->private_data = hpriv; |
4095 | hpriv->n_ports = n_ports; | 4107 | hpriv->n_ports = n_ports; |
4096 | hpriv->board_idx = chip_soc; | 4108 | hpriv->board_idx = chip_soc; |
@@ -4112,6 +4124,17 @@ static int mv_platform_probe(struct platform_device *pdev) | |||
4112 | hpriv->port_clks[port] = clk_get(&pdev->dev, port_number); | 4124 | hpriv->port_clks[port] = clk_get(&pdev->dev, port_number); |
4113 | if (!IS_ERR(hpriv->port_clks[port])) | 4125 | if (!IS_ERR(hpriv->port_clks[port])) |
4114 | clk_prepare_enable(hpriv->port_clks[port]); | 4126 | clk_prepare_enable(hpriv->port_clks[port]); |
4127 | |||
4128 | sprintf(port_number, "port%d", port); | ||
4129 | hpriv->port_phys[port] = devm_phy_get(&pdev->dev, port_number); | ||
4130 | if (IS_ERR(hpriv->port_phys[port])) { | ||
4131 | rc = PTR_ERR(hpriv->port_phys[port]); | ||
4132 | hpriv->port_phys[port] = NULL; | ||
4133 | if ((rc != -EPROBE_DEFER) && (rc != -ENODEV)) | ||
4134 | dev_warn(&pdev->dev, "error getting phy"); | ||
4135 | goto err; | ||
4136 | } else | ||
4137 | phy_power_on(hpriv->port_phys[port]); | ||
4115 | } | 4138 | } |
4116 | 4139 | ||
4117 | /* | 4140 | /* |
@@ -4156,6 +4179,8 @@ err: | |||
4156 | clk_disable_unprepare(hpriv->port_clks[port]); | 4179 | clk_disable_unprepare(hpriv->port_clks[port]); |
4157 | clk_put(hpriv->port_clks[port]); | 4180 | clk_put(hpriv->port_clks[port]); |
4158 | } | 4181 | } |
4182 | if (hpriv->port_phys[port]) | ||
4183 | phy_power_off(hpriv->port_phys[port]); | ||
4159 | } | 4184 | } |
4160 | 4185 | ||
4161 | return rc; | 4186 | return rc; |
@@ -4185,6 +4210,8 @@ static int mv_platform_remove(struct platform_device *pdev) | |||
4185 | clk_disable_unprepare(hpriv->port_clks[port]); | 4210 | clk_disable_unprepare(hpriv->port_clks[port]); |
4186 | clk_put(hpriv->port_clks[port]); | 4211 | clk_put(hpriv->port_clks[port]); |
4187 | } | 4212 | } |
4213 | if (hpriv->port_phys[port]) | ||
4214 | phy_power_off(hpriv->port_phys[port]); | ||
4188 | } | 4215 | } |
4189 | return 0; | 4216 | return 0; |
4190 | } | 4217 | } |