162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * phy-uniphier-ahci.c - PHY driver for UniPhier AHCI controller 462306a36Sopenharmony_ci * Copyright 2016-2020, Socionext Inc. 562306a36Sopenharmony_ci * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitfield.h> 962306a36Sopenharmony_ci#include <linux/bitops.h> 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/iopoll.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/of_platform.h> 1562306a36Sopenharmony_ci#include <linux/phy/phy.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/reset.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct uniphier_ahciphy_priv { 2062306a36Sopenharmony_ci struct device *dev; 2162306a36Sopenharmony_ci void __iomem *base; 2262306a36Sopenharmony_ci struct clk *clk, *clk_parent, *clk_parent_gio; 2362306a36Sopenharmony_ci struct reset_control *rst, *rst_parent, *rst_parent_gio; 2462306a36Sopenharmony_ci struct reset_control *rst_pm, *rst_tx, *rst_rx; 2562306a36Sopenharmony_ci const struct uniphier_ahciphy_soc_data *data; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct uniphier_ahciphy_soc_data { 2962306a36Sopenharmony_ci int (*init)(struct uniphier_ahciphy_priv *priv); 3062306a36Sopenharmony_ci int (*power_on)(struct uniphier_ahciphy_priv *priv); 3162306a36Sopenharmony_ci int (*power_off)(struct uniphier_ahciphy_priv *priv); 3262306a36Sopenharmony_ci bool is_legacy; 3362306a36Sopenharmony_ci bool is_ready_high; 3462306a36Sopenharmony_ci bool is_phy_clk; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* for Pro4 */ 3862306a36Sopenharmony_ci#define CKCTRL0 0x0 3962306a36Sopenharmony_ci#define CKCTRL0_CK_OFF BIT(9) 4062306a36Sopenharmony_ci#define CKCTRL0_NCY_MASK GENMASK(8, 4) 4162306a36Sopenharmony_ci#define CKCTRL0_NCY5_MASK GENMASK(3, 2) 4262306a36Sopenharmony_ci#define CKCTRL0_PRESCALE_MASK GENMASK(1, 0) 4362306a36Sopenharmony_ci#define CKCTRL1 0x4 4462306a36Sopenharmony_ci#define CKCTRL1_LOS_LVL_MASK GENMASK(20, 16) 4562306a36Sopenharmony_ci#define CKCTRL1_TX_LVL_MASK GENMASK(12, 8) 4662306a36Sopenharmony_ci#define RXTXCTRL 0x8 4762306a36Sopenharmony_ci#define RXTXCTRL_RX_EQ_VALL_MASK GENMASK(31, 29) 4862306a36Sopenharmony_ci#define RXTXCTRL_RX_DPLL_MODE_MASK GENMASK(28, 26) 4962306a36Sopenharmony_ci#define RXTXCTRL_TX_ATTEN_MASK GENMASK(14, 12) 5062306a36Sopenharmony_ci#define RXTXCTRL_TX_BOOST_MASK GENMASK(11, 8) 5162306a36Sopenharmony_ci#define RXTXCTRL_TX_EDGERATE_MASK GENMASK(3, 2) 5262306a36Sopenharmony_ci#define RXTXCTRL_TX_CKO_EN BIT(0) 5362306a36Sopenharmony_ci#define RSTPWR 0x30 5462306a36Sopenharmony_ci#define RSTPWR_RX_EN_VAL BIT(18) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* for PXs2/PXs3 */ 5762306a36Sopenharmony_ci#define CKCTRL 0x0 5862306a36Sopenharmony_ci#define CKCTRL_P0_READY BIT(15) 5962306a36Sopenharmony_ci#define CKCTRL_P0_RESET BIT(10) 6062306a36Sopenharmony_ci#define CKCTRL_REF_SSP_EN BIT(9) 6162306a36Sopenharmony_ci#define TXCTRL0 0x4 6262306a36Sopenharmony_ci#define TXCTRL0_AMP_G3_MASK GENMASK(22, 16) 6362306a36Sopenharmony_ci#define TXCTRL0_AMP_G2_MASK GENMASK(14, 8) 6462306a36Sopenharmony_ci#define TXCTRL0_AMP_G1_MASK GENMASK(6, 0) 6562306a36Sopenharmony_ci#define TXCTRL1 0x8 6662306a36Sopenharmony_ci#define TXCTRL1_DEEMPH_G3_MASK GENMASK(21, 16) 6762306a36Sopenharmony_ci#define TXCTRL1_DEEMPH_G2_MASK GENMASK(13, 8) 6862306a36Sopenharmony_ci#define TXCTRL1_DEEMPH_G1_MASK GENMASK(5, 0) 6962306a36Sopenharmony_ci#define RXCTRL 0xc 7062306a36Sopenharmony_ci#define RXCTRL_LOS_LVL_MASK GENMASK(20, 16) 7162306a36Sopenharmony_ci#define RXCTRL_LOS_BIAS_MASK GENMASK(10, 8) 7262306a36Sopenharmony_ci#define RXCTRL_RX_EQ_MASK GENMASK(2, 0) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int uniphier_ahciphy_pro4_init(struct uniphier_ahciphy_priv *priv) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci u32 val; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* set phy MPLL parameters */ 7962306a36Sopenharmony_ci val = readl(priv->base + CKCTRL0); 8062306a36Sopenharmony_ci val &= ~CKCTRL0_NCY_MASK; 8162306a36Sopenharmony_ci val |= FIELD_PREP(CKCTRL0_NCY_MASK, 0x6); 8262306a36Sopenharmony_ci val &= ~CKCTRL0_NCY5_MASK; 8362306a36Sopenharmony_ci val |= FIELD_PREP(CKCTRL0_NCY5_MASK, 0x2); 8462306a36Sopenharmony_ci val &= ~CKCTRL0_PRESCALE_MASK; 8562306a36Sopenharmony_ci val |= FIELD_PREP(CKCTRL0_PRESCALE_MASK, 0x1); 8662306a36Sopenharmony_ci writel(val, priv->base + CKCTRL0); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* setup phy control parameters */ 8962306a36Sopenharmony_ci val = readl(priv->base + CKCTRL1); 9062306a36Sopenharmony_ci val &= ~CKCTRL1_LOS_LVL_MASK; 9162306a36Sopenharmony_ci val |= FIELD_PREP(CKCTRL1_LOS_LVL_MASK, 0x10); 9262306a36Sopenharmony_ci val &= ~CKCTRL1_TX_LVL_MASK; 9362306a36Sopenharmony_ci val |= FIELD_PREP(CKCTRL1_TX_LVL_MASK, 0x06); 9462306a36Sopenharmony_ci writel(val, priv->base + CKCTRL1); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci val = readl(priv->base + RXTXCTRL); 9762306a36Sopenharmony_ci val &= ~RXTXCTRL_RX_EQ_VALL_MASK; 9862306a36Sopenharmony_ci val |= FIELD_PREP(RXTXCTRL_RX_EQ_VALL_MASK, 0x6); 9962306a36Sopenharmony_ci val &= ~RXTXCTRL_RX_DPLL_MODE_MASK; 10062306a36Sopenharmony_ci val |= FIELD_PREP(RXTXCTRL_RX_DPLL_MODE_MASK, 0x3); 10162306a36Sopenharmony_ci val &= ~RXTXCTRL_TX_ATTEN_MASK; 10262306a36Sopenharmony_ci val |= FIELD_PREP(RXTXCTRL_TX_ATTEN_MASK, 0x3); 10362306a36Sopenharmony_ci val &= ~RXTXCTRL_TX_BOOST_MASK; 10462306a36Sopenharmony_ci val |= FIELD_PREP(RXTXCTRL_TX_BOOST_MASK, 0x5); 10562306a36Sopenharmony_ci val &= ~RXTXCTRL_TX_EDGERATE_MASK; 10662306a36Sopenharmony_ci val |= FIELD_PREP(RXTXCTRL_TX_EDGERATE_MASK, 0x0); 10762306a36Sopenharmony_ci writel(val, priv->base + RXTXCTRL); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int uniphier_ahciphy_pro4_power_on(struct uniphier_ahciphy_priv *priv) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci u32 val; 11562306a36Sopenharmony_ci int ret; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* enable reference clock for phy */ 11862306a36Sopenharmony_ci val = readl(priv->base + CKCTRL0); 11962306a36Sopenharmony_ci val &= ~CKCTRL0_CK_OFF; 12062306a36Sopenharmony_ci writel(val, priv->base + CKCTRL0); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* enable TX clock */ 12362306a36Sopenharmony_ci val = readl(priv->base + RXTXCTRL); 12462306a36Sopenharmony_ci val |= RXTXCTRL_TX_CKO_EN; 12562306a36Sopenharmony_ci writel(val, priv->base + RXTXCTRL); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* wait until RX is ready */ 12862306a36Sopenharmony_ci ret = readl_poll_timeout(priv->base + RSTPWR, val, 12962306a36Sopenharmony_ci !(val & RSTPWR_RX_EN_VAL), 200, 2000); 13062306a36Sopenharmony_ci if (ret) { 13162306a36Sopenharmony_ci dev_err(priv->dev, "Failed to check whether Rx is ready\n"); 13262306a36Sopenharmony_ci goto out_disable_clock; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* release all reset */ 13662306a36Sopenharmony_ci ret = reset_control_deassert(priv->rst_pm); 13762306a36Sopenharmony_ci if (ret) { 13862306a36Sopenharmony_ci dev_err(priv->dev, "Failed to release PM reset\n"); 13962306a36Sopenharmony_ci goto out_disable_clock; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci ret = reset_control_deassert(priv->rst_tx); 14362306a36Sopenharmony_ci if (ret) { 14462306a36Sopenharmony_ci dev_err(priv->dev, "Failed to release Tx reset\n"); 14562306a36Sopenharmony_ci goto out_reset_pm_assert; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci ret = reset_control_deassert(priv->rst_rx); 14962306a36Sopenharmony_ci if (ret) { 15062306a36Sopenharmony_ci dev_err(priv->dev, "Failed to release Rx reset\n"); 15162306a36Sopenharmony_ci goto out_reset_tx_assert; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ciout_reset_tx_assert: 15762306a36Sopenharmony_ci reset_control_assert(priv->rst_tx); 15862306a36Sopenharmony_ciout_reset_pm_assert: 15962306a36Sopenharmony_ci reset_control_assert(priv->rst_pm); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ciout_disable_clock: 16262306a36Sopenharmony_ci /* disable TX clock */ 16362306a36Sopenharmony_ci val = readl(priv->base + RXTXCTRL); 16462306a36Sopenharmony_ci val &= ~RXTXCTRL_TX_CKO_EN; 16562306a36Sopenharmony_ci writel(val, priv->base + RXTXCTRL); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* disable reference clock for phy */ 16862306a36Sopenharmony_ci val = readl(priv->base + CKCTRL0); 16962306a36Sopenharmony_ci val |= CKCTRL0_CK_OFF; 17062306a36Sopenharmony_ci writel(val, priv->base + CKCTRL0); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return ret; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int uniphier_ahciphy_pro4_power_off(struct uniphier_ahciphy_priv *priv) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci u32 val; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci reset_control_assert(priv->rst_rx); 18062306a36Sopenharmony_ci reset_control_assert(priv->rst_tx); 18162306a36Sopenharmony_ci reset_control_assert(priv->rst_pm); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* disable TX clock */ 18462306a36Sopenharmony_ci val = readl(priv->base + RXTXCTRL); 18562306a36Sopenharmony_ci val &= ~RXTXCTRL_TX_CKO_EN; 18662306a36Sopenharmony_ci writel(val, priv->base + RXTXCTRL); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* disable reference clock for phy */ 18962306a36Sopenharmony_ci val = readl(priv->base + CKCTRL0); 19062306a36Sopenharmony_ci val |= CKCTRL0_CK_OFF; 19162306a36Sopenharmony_ci writel(val, priv->base + CKCTRL0); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void uniphier_ahciphy_pxs2_enable(struct uniphier_ahciphy_priv *priv, 19762306a36Sopenharmony_ci bool enable) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci u32 val; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci val = readl(priv->base + CKCTRL); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (enable) { 20462306a36Sopenharmony_ci val |= CKCTRL_REF_SSP_EN; 20562306a36Sopenharmony_ci writel(val, priv->base + CKCTRL); 20662306a36Sopenharmony_ci val &= ~CKCTRL_P0_RESET; 20762306a36Sopenharmony_ci writel(val, priv->base + CKCTRL); 20862306a36Sopenharmony_ci } else { 20962306a36Sopenharmony_ci val |= CKCTRL_P0_RESET; 21062306a36Sopenharmony_ci writel(val, priv->base + CKCTRL); 21162306a36Sopenharmony_ci val &= ~CKCTRL_REF_SSP_EN; 21262306a36Sopenharmony_ci writel(val, priv->base + CKCTRL); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int uniphier_ahciphy_pxs2_power_on(struct uniphier_ahciphy_priv *priv) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci int ret; 21962306a36Sopenharmony_ci u32 val; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci uniphier_ahciphy_pxs2_enable(priv, true); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* wait until PLL is ready */ 22462306a36Sopenharmony_ci if (priv->data->is_ready_high) 22562306a36Sopenharmony_ci ret = readl_poll_timeout(priv->base + CKCTRL, val, 22662306a36Sopenharmony_ci (val & CKCTRL_P0_READY), 200, 400); 22762306a36Sopenharmony_ci else 22862306a36Sopenharmony_ci ret = readl_poll_timeout(priv->base + CKCTRL, val, 22962306a36Sopenharmony_ci !(val & CKCTRL_P0_READY), 200, 400); 23062306a36Sopenharmony_ci if (ret) { 23162306a36Sopenharmony_ci dev_err(priv->dev, "Failed to check whether PHY PLL is ready\n"); 23262306a36Sopenharmony_ci uniphier_ahciphy_pxs2_enable(priv, false); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci return ret; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic int uniphier_ahciphy_pxs2_power_off(struct uniphier_ahciphy_priv *priv) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci uniphier_ahciphy_pxs2_enable(priv, false); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci return 0; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic int uniphier_ahciphy_pxs3_init(struct uniphier_ahciphy_priv *priv) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci int i; 24862306a36Sopenharmony_ci u32 val; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* setup port parameter */ 25162306a36Sopenharmony_ci val = readl(priv->base + TXCTRL0); 25262306a36Sopenharmony_ci val &= ~TXCTRL0_AMP_G3_MASK; 25362306a36Sopenharmony_ci val |= FIELD_PREP(TXCTRL0_AMP_G3_MASK, 0x73); 25462306a36Sopenharmony_ci val &= ~TXCTRL0_AMP_G2_MASK; 25562306a36Sopenharmony_ci val |= FIELD_PREP(TXCTRL0_AMP_G2_MASK, 0x46); 25662306a36Sopenharmony_ci val &= ~TXCTRL0_AMP_G1_MASK; 25762306a36Sopenharmony_ci val |= FIELD_PREP(TXCTRL0_AMP_G1_MASK, 0x42); 25862306a36Sopenharmony_ci writel(val, priv->base + TXCTRL0); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci val = readl(priv->base + TXCTRL1); 26162306a36Sopenharmony_ci val &= ~TXCTRL1_DEEMPH_G3_MASK; 26262306a36Sopenharmony_ci val |= FIELD_PREP(TXCTRL1_DEEMPH_G3_MASK, 0x23); 26362306a36Sopenharmony_ci val &= ~TXCTRL1_DEEMPH_G2_MASK; 26462306a36Sopenharmony_ci val |= FIELD_PREP(TXCTRL1_DEEMPH_G2_MASK, 0x05); 26562306a36Sopenharmony_ci val &= ~TXCTRL1_DEEMPH_G1_MASK; 26662306a36Sopenharmony_ci val |= FIELD_PREP(TXCTRL1_DEEMPH_G1_MASK, 0x05); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci val = readl(priv->base + RXCTRL); 26962306a36Sopenharmony_ci val &= ~RXCTRL_LOS_LVL_MASK; 27062306a36Sopenharmony_ci val |= FIELD_PREP(RXCTRL_LOS_LVL_MASK, 0x9); 27162306a36Sopenharmony_ci val &= ~RXCTRL_LOS_BIAS_MASK; 27262306a36Sopenharmony_ci val |= FIELD_PREP(RXCTRL_LOS_BIAS_MASK, 0x2); 27362306a36Sopenharmony_ci val &= ~RXCTRL_RX_EQ_MASK; 27462306a36Sopenharmony_ci val |= FIELD_PREP(RXCTRL_RX_EQ_MASK, 0x1); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* dummy read 25 times to make a wait time for the phy to stabilize */ 27762306a36Sopenharmony_ci for (i = 0; i < 25; i++) 27862306a36Sopenharmony_ci readl(priv->base + CKCTRL); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int uniphier_ahciphy_init(struct phy *phy) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy); 28662306a36Sopenharmony_ci int ret; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci ret = clk_prepare_enable(priv->clk_parent_gio); 28962306a36Sopenharmony_ci if (ret) 29062306a36Sopenharmony_ci return ret; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci ret = clk_prepare_enable(priv->clk_parent); 29362306a36Sopenharmony_ci if (ret) 29462306a36Sopenharmony_ci goto out_clk_gio_disable; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci ret = reset_control_deassert(priv->rst_parent_gio); 29762306a36Sopenharmony_ci if (ret) 29862306a36Sopenharmony_ci goto out_clk_disable; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci ret = reset_control_deassert(priv->rst_parent); 30162306a36Sopenharmony_ci if (ret) 30262306a36Sopenharmony_ci goto out_rst_gio_assert; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (priv->data->init) { 30562306a36Sopenharmony_ci ret = priv->data->init(priv); 30662306a36Sopenharmony_ci if (ret) 30762306a36Sopenharmony_ci goto out_rst_assert; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci return 0; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ciout_rst_assert: 31362306a36Sopenharmony_ci reset_control_assert(priv->rst_parent); 31462306a36Sopenharmony_ciout_rst_gio_assert: 31562306a36Sopenharmony_ci reset_control_assert(priv->rst_parent_gio); 31662306a36Sopenharmony_ciout_clk_disable: 31762306a36Sopenharmony_ci clk_disable_unprepare(priv->clk_parent); 31862306a36Sopenharmony_ciout_clk_gio_disable: 31962306a36Sopenharmony_ci clk_disable_unprepare(priv->clk_parent_gio); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return ret; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int uniphier_ahciphy_exit(struct phy *phy) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci reset_control_assert(priv->rst_parent); 32962306a36Sopenharmony_ci reset_control_assert(priv->rst_parent_gio); 33062306a36Sopenharmony_ci clk_disable_unprepare(priv->clk_parent); 33162306a36Sopenharmony_ci clk_disable_unprepare(priv->clk_parent_gio); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci return 0; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic int uniphier_ahciphy_power_on(struct phy *phy) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy); 33962306a36Sopenharmony_ci int ret = 0; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 34262306a36Sopenharmony_ci if (ret) 34362306a36Sopenharmony_ci return ret; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci ret = reset_control_deassert(priv->rst); 34662306a36Sopenharmony_ci if (ret) 34762306a36Sopenharmony_ci goto out_clk_disable; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (priv->data->power_on) { 35062306a36Sopenharmony_ci ret = priv->data->power_on(priv); 35162306a36Sopenharmony_ci if (ret) 35262306a36Sopenharmony_ci goto out_reset_assert; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ciout_reset_assert: 35862306a36Sopenharmony_ci reset_control_assert(priv->rst); 35962306a36Sopenharmony_ciout_clk_disable: 36062306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int uniphier_ahciphy_power_off(struct phy *phy) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci struct uniphier_ahciphy_priv *priv = phy_get_drvdata(phy); 36862306a36Sopenharmony_ci int ret = 0; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (priv->data->power_off) 37162306a36Sopenharmony_ci ret = priv->data->power_off(priv); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci reset_control_assert(priv->rst); 37462306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci return ret; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic const struct phy_ops uniphier_ahciphy_ops = { 38062306a36Sopenharmony_ci .init = uniphier_ahciphy_init, 38162306a36Sopenharmony_ci .exit = uniphier_ahciphy_exit, 38262306a36Sopenharmony_ci .power_on = uniphier_ahciphy_power_on, 38362306a36Sopenharmony_ci .power_off = uniphier_ahciphy_power_off, 38462306a36Sopenharmony_ci .owner = THIS_MODULE, 38562306a36Sopenharmony_ci}; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int uniphier_ahciphy_probe(struct platform_device *pdev) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 39062306a36Sopenharmony_ci struct uniphier_ahciphy_priv *priv; 39162306a36Sopenharmony_ci struct phy *phy; 39262306a36Sopenharmony_ci struct phy_provider *phy_provider; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 39562306a36Sopenharmony_ci if (!priv) 39662306a36Sopenharmony_ci return -ENOMEM; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci priv->dev = dev; 39962306a36Sopenharmony_ci priv->data = of_device_get_match_data(dev); 40062306a36Sopenharmony_ci if (WARN_ON(!priv->data)) 40162306a36Sopenharmony_ci return -EINVAL; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci priv->base = devm_platform_ioremap_resource(pdev, 0); 40462306a36Sopenharmony_ci if (IS_ERR(priv->base)) 40562306a36Sopenharmony_ci return PTR_ERR(priv->base); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci priv->clk_parent = devm_clk_get(dev, "link"); 40862306a36Sopenharmony_ci if (IS_ERR(priv->clk_parent)) 40962306a36Sopenharmony_ci return PTR_ERR(priv->clk_parent); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (priv->data->is_phy_clk) { 41262306a36Sopenharmony_ci priv->clk = devm_clk_get(dev, "phy"); 41362306a36Sopenharmony_ci if (IS_ERR(priv->clk)) 41462306a36Sopenharmony_ci return PTR_ERR(priv->clk); 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci priv->rst_parent = devm_reset_control_get_shared(dev, "link"); 41862306a36Sopenharmony_ci if (IS_ERR(priv->rst_parent)) 41962306a36Sopenharmony_ci return PTR_ERR(priv->rst_parent); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci priv->rst = devm_reset_control_get_shared(dev, "phy"); 42262306a36Sopenharmony_ci if (IS_ERR(priv->rst)) 42362306a36Sopenharmony_ci return PTR_ERR(priv->rst); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (priv->data->is_legacy) { 42662306a36Sopenharmony_ci priv->clk_parent_gio = devm_clk_get(dev, "gio"); 42762306a36Sopenharmony_ci if (IS_ERR(priv->clk_parent_gio)) 42862306a36Sopenharmony_ci return PTR_ERR(priv->clk_parent_gio); 42962306a36Sopenharmony_ci priv->rst_parent_gio = 43062306a36Sopenharmony_ci devm_reset_control_get_shared(dev, "gio"); 43162306a36Sopenharmony_ci if (IS_ERR(priv->rst_parent_gio)) 43262306a36Sopenharmony_ci return PTR_ERR(priv->rst_parent_gio); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci priv->rst_pm = devm_reset_control_get_shared(dev, "pm"); 43562306a36Sopenharmony_ci if (IS_ERR(priv->rst_pm)) 43662306a36Sopenharmony_ci return PTR_ERR(priv->rst_pm); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci priv->rst_tx = devm_reset_control_get_shared(dev, "tx"); 43962306a36Sopenharmony_ci if (IS_ERR(priv->rst_tx)) 44062306a36Sopenharmony_ci return PTR_ERR(priv->rst_tx); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci priv->rst_rx = devm_reset_control_get_shared(dev, "rx"); 44362306a36Sopenharmony_ci if (IS_ERR(priv->rst_rx)) 44462306a36Sopenharmony_ci return PTR_ERR(priv->rst_rx); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci phy = devm_phy_create(dev, dev->of_node, &uniphier_ahciphy_ops); 44862306a36Sopenharmony_ci if (IS_ERR(phy)) { 44962306a36Sopenharmony_ci dev_err(dev, "failed to create phy\n"); 45062306a36Sopenharmony_ci return PTR_ERR(phy); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci phy_set_drvdata(phy, priv); 45462306a36Sopenharmony_ci phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 45562306a36Sopenharmony_ci if (IS_ERR(phy_provider)) 45662306a36Sopenharmony_ci return PTR_ERR(phy_provider); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic const struct uniphier_ahciphy_soc_data uniphier_pro4_data = { 46262306a36Sopenharmony_ci .init = uniphier_ahciphy_pro4_init, 46362306a36Sopenharmony_ci .power_on = uniphier_ahciphy_pro4_power_on, 46462306a36Sopenharmony_ci .power_off = uniphier_ahciphy_pro4_power_off, 46562306a36Sopenharmony_ci .is_legacy = true, 46662306a36Sopenharmony_ci .is_phy_clk = false, 46762306a36Sopenharmony_ci}; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic const struct uniphier_ahciphy_soc_data uniphier_pxs2_data = { 47062306a36Sopenharmony_ci .power_on = uniphier_ahciphy_pxs2_power_on, 47162306a36Sopenharmony_ci .power_off = uniphier_ahciphy_pxs2_power_off, 47262306a36Sopenharmony_ci .is_legacy = false, 47362306a36Sopenharmony_ci .is_ready_high = false, 47462306a36Sopenharmony_ci .is_phy_clk = false, 47562306a36Sopenharmony_ci}; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic const struct uniphier_ahciphy_soc_data uniphier_pxs3_data = { 47862306a36Sopenharmony_ci .init = uniphier_ahciphy_pxs3_init, 47962306a36Sopenharmony_ci .power_on = uniphier_ahciphy_pxs2_power_on, 48062306a36Sopenharmony_ci .power_off = uniphier_ahciphy_pxs2_power_off, 48162306a36Sopenharmony_ci .is_legacy = false, 48262306a36Sopenharmony_ci .is_ready_high = true, 48362306a36Sopenharmony_ci .is_phy_clk = true, 48462306a36Sopenharmony_ci}; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic const struct of_device_id uniphier_ahciphy_match[] = { 48762306a36Sopenharmony_ci { 48862306a36Sopenharmony_ci .compatible = "socionext,uniphier-pro4-ahci-phy", 48962306a36Sopenharmony_ci .data = &uniphier_pro4_data, 49062306a36Sopenharmony_ci }, 49162306a36Sopenharmony_ci { 49262306a36Sopenharmony_ci .compatible = "socionext,uniphier-pxs2-ahci-phy", 49362306a36Sopenharmony_ci .data = &uniphier_pxs2_data, 49462306a36Sopenharmony_ci }, 49562306a36Sopenharmony_ci { 49662306a36Sopenharmony_ci .compatible = "socionext,uniphier-pxs3-ahci-phy", 49762306a36Sopenharmony_ci .data = &uniphier_pxs3_data, 49862306a36Sopenharmony_ci }, 49962306a36Sopenharmony_ci { /* Sentinel */ }, 50062306a36Sopenharmony_ci}; 50162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, uniphier_ahciphy_match); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic struct platform_driver uniphier_ahciphy_driver = { 50462306a36Sopenharmony_ci .probe = uniphier_ahciphy_probe, 50562306a36Sopenharmony_ci .driver = { 50662306a36Sopenharmony_ci .name = "uniphier-ahci-phy", 50762306a36Sopenharmony_ci .of_match_table = uniphier_ahciphy_match, 50862306a36Sopenharmony_ci }, 50962306a36Sopenharmony_ci}; 51062306a36Sopenharmony_cimodule_platform_driver(uniphier_ahciphy_driver); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ciMODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); 51362306a36Sopenharmony_ciMODULE_DESCRIPTION("UniPhier PHY driver for AHCI controller"); 51462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 515