Lines Matching +full:m +full:- +full:phy

1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2017-2020,2022 NXP
12 #include <linux/phy/phy.h>
23 #define M(n) FIELD_PREP(M_MASK, (n)) macro
36 #define CTRL_RESET_VAL (M(0x0) | CCM(0x4) | CA(0x4) | TST(0x25))
38 /* PHY initialization value and mask */
40 #define CTRL_INIT_VAL (M(0x0) | CCM(0x5) | CA(0x4) | TST(0x25) | RFB)
54 struct phy *phy; member
66 static int mixel_lvds_phy_init(struct phy *phy) in mixel_lvds_phy_init() argument
68 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent); in mixel_lvds_phy_init()
70 mutex_lock(&priv->lock); in mixel_lvds_phy_init()
71 regmap_update_bits(priv->regmap, in mixel_lvds_phy_init()
73 mutex_unlock(&priv->lock); in mixel_lvds_phy_init()
78 static int mixel_lvds_phy_power_on(struct phy *phy) in mixel_lvds_phy_power_on() argument
80 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent); in mixel_lvds_phy_power_on()
81 struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy); in mixel_lvds_phy_power_on()
82 struct mixel_lvds_phy *companion = priv->phys[lvds_phy->id ^ 1]; in mixel_lvds_phy_power_on()
83 struct phy_configure_opts_lvds *cfg = &lvds_phy->cfg; in mixel_lvds_phy_power_on()
88 /* The master PHY would power on the slave PHY. */ in mixel_lvds_phy_power_on()
89 if (cfg->is_slave) in mixel_lvds_phy_power_on()
92 ret = clk_prepare_enable(priv->phy_ref_clk); in mixel_lvds_phy_power_on()
94 dev_err(&phy->dev, in mixel_lvds_phy_power_on()
95 "failed to enable PHY reference clock: %d\n", ret); in mixel_lvds_phy_power_on()
99 mutex_lock(&priv->lock); in mixel_lvds_phy_power_on()
100 if (cfg->bits_per_lane_and_dclk_cycle == 7) { in mixel_lvds_phy_power_on()
101 if (cfg->differential_clk_rate < 44000000) in mixel_lvds_phy_power_on()
102 val |= M(0x2); in mixel_lvds_phy_power_on()
103 else if (cfg->differential_clk_rate < 90000000) in mixel_lvds_phy_power_on()
104 val |= M(0x1); in mixel_lvds_phy_power_on()
106 val |= M(0x0); in mixel_lvds_phy_power_on()
110 if (cfg->differential_clk_rate < 32000000) in mixel_lvds_phy_power_on()
111 val |= M(0x2); in mixel_lvds_phy_power_on()
112 else if (cfg->differential_clk_rate < 63000000) in mixel_lvds_phy_power_on()
113 val |= M(0x1); in mixel_lvds_phy_power_on()
115 val |= M(0x0); in mixel_lvds_phy_power_on()
117 regmap_update_bits(priv->regmap, PHY_CTRL, M_MASK | NB, val); in mixel_lvds_phy_power_on()
121 * if the companion PHY is a slave PHY. in mixel_lvds_phy_power_on()
123 if (companion->cfg.is_slave) in mixel_lvds_phy_power_on()
126 val = CH_EN(lvds_phy->id); in mixel_lvds_phy_power_on()
127 regmap_write(priv->regmap, PHY_CTRL + REG_SET, val); in mixel_lvds_phy_power_on()
129 ret = regmap_read_poll_timeout(priv->regmap, PHY_STATUS, locked, in mixel_lvds_phy_power_on()
133 dev_err(&phy->dev, "failed to get PHY lock: %d\n", ret); in mixel_lvds_phy_power_on()
134 clk_disable_unprepare(priv->phy_ref_clk); in mixel_lvds_phy_power_on()
136 mutex_unlock(&priv->lock); in mixel_lvds_phy_power_on()
141 static int mixel_lvds_phy_power_off(struct phy *phy) in mixel_lvds_phy_power_off() argument
143 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent); in mixel_lvds_phy_power_off()
144 struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy); in mixel_lvds_phy_power_off()
145 struct mixel_lvds_phy *companion = priv->phys[lvds_phy->id ^ 1]; in mixel_lvds_phy_power_off()
146 struct phy_configure_opts_lvds *cfg = &lvds_phy->cfg; in mixel_lvds_phy_power_off()
148 /* The master PHY would power off the slave PHY. */ in mixel_lvds_phy_power_off()
149 if (cfg->is_slave) in mixel_lvds_phy_power_off()
152 mutex_lock(&priv->lock); in mixel_lvds_phy_power_off()
153 if (companion->cfg.is_slave) in mixel_lvds_phy_power_off()
154 regmap_write(priv->regmap, PHY_CTRL + REG_CLR, in mixel_lvds_phy_power_off()
157 regmap_write(priv->regmap, PHY_CTRL + REG_CLR, in mixel_lvds_phy_power_off()
158 CH_EN(lvds_phy->id)); in mixel_lvds_phy_power_off()
159 mutex_unlock(&priv->lock); in mixel_lvds_phy_power_off()
161 clk_disable_unprepare(priv->phy_ref_clk); in mixel_lvds_phy_power_off()
166 static int mixel_lvds_phy_configure(struct phy *phy, in mixel_lvds_phy_configure() argument
169 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent); in mixel_lvds_phy_configure()
170 struct phy_configure_opts_lvds *cfg = &opts->lvds; in mixel_lvds_phy_configure()
173 ret = clk_set_rate(priv->phy_ref_clk, cfg->differential_clk_rate); in mixel_lvds_phy_configure()
175 dev_err(&phy->dev, "failed to set PHY reference clock rate(%lu): %d\n", in mixel_lvds_phy_configure()
176 cfg->differential_clk_rate, ret); in mixel_lvds_phy_configure()
181 /* Assume the master PHY's configuration set is cached first. */
182 static int mixel_lvds_phy_check_slave(struct phy *slave_phy) in mixel_lvds_phy_check_slave()
184 struct device *dev = &slave_phy->dev; in mixel_lvds_phy_check_slave()
185 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(dev->parent); in mixel_lvds_phy_check_slave()
187 struct mixel_lvds_phy *mst = priv->phys[slv->id ^ 1]; in mixel_lvds_phy_check_slave()
188 struct phy_configure_opts_lvds *mst_cfg = &mst->cfg; in mixel_lvds_phy_check_slave()
189 struct phy_configure_opts_lvds *slv_cfg = &slv->cfg; in mixel_lvds_phy_check_slave()
191 if (mst_cfg->bits_per_lane_and_dclk_cycle != in mixel_lvds_phy_check_slave()
192 slv_cfg->bits_per_lane_and_dclk_cycle) { in mixel_lvds_phy_check_slave()
194 mst_cfg->bits_per_lane_and_dclk_cycle, in mixel_lvds_phy_check_slave()
195 slv_cfg->bits_per_lane_and_dclk_cycle); in mixel_lvds_phy_check_slave()
196 return -EINVAL; in mixel_lvds_phy_check_slave()
199 if (mst_cfg->differential_clk_rate != in mixel_lvds_phy_check_slave()
200 slv_cfg->differential_clk_rate) { in mixel_lvds_phy_check_slave()
202 mst_cfg->differential_clk_rate, in mixel_lvds_phy_check_slave()
203 slv_cfg->differential_clk_rate); in mixel_lvds_phy_check_slave()
204 return -EINVAL; in mixel_lvds_phy_check_slave()
207 if (mst_cfg->lanes != slv_cfg->lanes) { in mixel_lvds_phy_check_slave()
209 mst_cfg->lanes, slv_cfg->lanes); in mixel_lvds_phy_check_slave()
210 return -EINVAL; in mixel_lvds_phy_check_slave()
213 if (mst_cfg->is_slave == slv_cfg->is_slave) { in mixel_lvds_phy_check_slave()
214 dev_err(dev, "master PHY is not found\n"); in mixel_lvds_phy_check_slave()
215 return -EINVAL; in mixel_lvds_phy_check_slave()
221 static int mixel_lvds_phy_validate(struct phy *phy, enum phy_mode mode, in mixel_lvds_phy_validate() argument
224 struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent); in mixel_lvds_phy_validate()
225 struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy); in mixel_lvds_phy_validate()
226 struct phy_configure_opts_lvds *cfg = &opts->lvds; in mixel_lvds_phy_validate()
230 dev_err(&phy->dev, "invalid PHY mode(%d)\n", mode); in mixel_lvds_phy_validate()
231 return -EINVAL; in mixel_lvds_phy_validate()
234 if (cfg->bits_per_lane_and_dclk_cycle != 7 && in mixel_lvds_phy_validate()
235 cfg->bits_per_lane_and_dclk_cycle != 10) { in mixel_lvds_phy_validate()
236 dev_err(&phy->dev, "invalid bits per data lane(%u)\n", in mixel_lvds_phy_validate()
237 cfg->bits_per_lane_and_dclk_cycle); in mixel_lvds_phy_validate()
238 return -EINVAL; in mixel_lvds_phy_validate()
241 if (cfg->lanes != 4 && cfg->lanes != 3) { in mixel_lvds_phy_validate()
242 dev_err(&phy->dev, "invalid data lanes(%u)\n", cfg->lanes); in mixel_lvds_phy_validate()
243 return -EINVAL; in mixel_lvds_phy_validate()
246 if (cfg->differential_clk_rate < MIN_CLKIN_FREQ || in mixel_lvds_phy_validate()
247 cfg->differential_clk_rate > MAX_CLKIN_FREQ) { in mixel_lvds_phy_validate()
248 dev_err(&phy->dev, "invalid differential clock rate(%lu)\n", in mixel_lvds_phy_validate()
249 cfg->differential_clk_rate); in mixel_lvds_phy_validate()
250 return -EINVAL; in mixel_lvds_phy_validate()
253 mutex_lock(&priv->lock); in mixel_lvds_phy_validate()
255 memcpy(&lvds_phy->cfg, cfg, sizeof(*cfg)); in mixel_lvds_phy_validate()
257 if (cfg->is_slave) { in mixel_lvds_phy_validate()
258 ret = mixel_lvds_phy_check_slave(phy); in mixel_lvds_phy_validate()
260 dev_err(&phy->dev, "failed to check slave PHY: %d\n", ret); in mixel_lvds_phy_validate()
262 mutex_unlock(&priv->lock); in mixel_lvds_phy_validate()
287 regmap_write(priv->regmap, PHY_CTRL, CTRL_RESET_VAL); in mixel_lvds_phy_reset()
296 static struct phy *mixel_lvds_phy_xlate(struct device *dev, in mixel_lvds_phy_xlate()
302 if (args->args_count != 1) { in mixel_lvds_phy_xlate()
305 args->args_count); in mixel_lvds_phy_xlate()
306 return ERR_PTR(-EINVAL); in mixel_lvds_phy_xlate()
309 phy_id = args->args[0]; in mixel_lvds_phy_xlate()
312 dev_err(dev, "invalid PHY index(%d)\n", phy_id); in mixel_lvds_phy_xlate()
313 return ERR_PTR(-ENODEV); in mixel_lvds_phy_xlate()
316 return priv->phys[phy_id]->phy; in mixel_lvds_phy_xlate()
321 struct device *dev = &pdev->dev; in mixel_lvds_phy_probe()
325 struct phy *phy; in mixel_lvds_phy_probe() local
329 if (!dev->of_node) in mixel_lvds_phy_probe()
330 return -ENODEV; in mixel_lvds_phy_probe()
334 return -ENOMEM; in mixel_lvds_phy_probe()
336 priv->regmap = syscon_node_to_regmap(dev->of_node->parent); in mixel_lvds_phy_probe()
337 if (IS_ERR(priv->regmap)) in mixel_lvds_phy_probe()
338 return dev_err_probe(dev, PTR_ERR(priv->regmap), in mixel_lvds_phy_probe()
341 priv->phy_ref_clk = devm_clk_get(dev, NULL); in mixel_lvds_phy_probe()
342 if (IS_ERR(priv->phy_ref_clk)) in mixel_lvds_phy_probe()
343 return dev_err_probe(dev, PTR_ERR(priv->phy_ref_clk), in mixel_lvds_phy_probe()
344 "failed to get PHY reference clock\n"); in mixel_lvds_phy_probe()
346 mutex_init(&priv->lock); in mixel_lvds_phy_probe()
361 ret = -ENOMEM; in mixel_lvds_phy_probe()
365 phy = devm_phy_create(dev, NULL, &mixel_lvds_phy_ops); in mixel_lvds_phy_probe()
366 if (IS_ERR(phy)) { in mixel_lvds_phy_probe()
367 ret = PTR_ERR(phy); in mixel_lvds_phy_probe()
368 dev_err(dev, "failed to create PHY for channel%d: %d\n", in mixel_lvds_phy_probe()
373 lvds_phy->phy = phy; in mixel_lvds_phy_probe()
374 lvds_phy->id = i; in mixel_lvds_phy_probe()
375 priv->phys[i] = lvds_phy; in mixel_lvds_phy_probe()
377 phy_set_drvdata(phy, lvds_phy); in mixel_lvds_phy_probe()
383 dev_err(dev, "failed to register PHY provider: %d\n", ret); in mixel_lvds_phy_probe()
396 pm_runtime_disable(&pdev->dev); in mixel_lvds_phy_remove()
404 mutex_lock(&priv->lock); in mixel_lvds_phy_runtime_suspend()
405 regmap_write(priv->regmap, PHY_CTRL + REG_SET, PD); in mixel_lvds_phy_runtime_suspend()
406 mutex_unlock(&priv->lock); in mixel_lvds_phy_runtime_suspend()
416 mutex_lock(&priv->lock); in mixel_lvds_phy_runtime_resume()
417 regmap_update_bits(priv->regmap, PHY_CTRL, in mixel_lvds_phy_runtime_resume()
419 mutex_unlock(&priv->lock); in mixel_lvds_phy_runtime_resume()
430 { .compatible = "fsl,imx8qm-lvds-phy" },
440 .name = "mixel-lvds-phy",
446 MODULE_DESCRIPTION("Mixel LVDS PHY driver");