• Home
  • Raw
  • Download

Lines Matching +full:d +full:- +full:phy

1 // SPDX-License-Identifier: GPL-2.0+
8 #include <linux/clk-provider.h>
15 #include <linux/phy/phy.h>
47 ((x) < 32) ? 0xe0 | ((x) - 16) : \
48 ((x) < 64) ? 0xc0 | ((x) - 32) : \
49 ((x) < 128) ? 0x80 | ((x) - 64) : \
50 ((x) - 128))
51 #define CN(x) (((x) == 1) ? 0x1f : (((CN_BUF) >> ((x) - 1)) & 0x1f))
52 #define CO(x) ((CO_BUF) >> (8 - (x)) & 0x03)
54 /* PHY power on is active low */
107 .name = "mipi-dphy",
110 static int phy_write(struct phy *phy, u32 value, unsigned int reg) in phy_write() argument
112 struct mixel_dphy_priv *priv = phy_get_drvdata(phy); in phy_write()
115 ret = regmap_write(priv->regmap, reg, value); in phy_write()
117 dev_err(&phy->dev, "Failed to write DPHY reg %d: %d\n", reg, in phy_write()
133 u32 d[] = {1, 0}; in get_best_ratio() local
141 d[i] += (d[i ^ 1] * whole); in get_best_ratio()
142 if ((n[i] > max_n) || (d[i] > max_d)) { in get_best_ratio()
146 c = a - (b * whole); in get_best_ratio()
151 *pdenom = d[i]; in get_best_ratio()
154 static int mixel_dphy_config_from_opts(struct phy *phy, in mixel_dphy_config_from_opts() argument
158 struct mixel_dphy_priv *priv = dev_get_drvdata(phy->dev.parent); in mixel_dphy_config_from_opts()
159 unsigned long ref_clk = clk_get_rate(priv->phy_ref_clk); in mixel_dphy_config_from_opts()
165 if (dphy_opts->hs_clk_rate > DATA_RATE_MAX_SPEED || in mixel_dphy_config_from_opts()
166 dphy_opts->hs_clk_rate < DATA_RATE_MIN_SPEED) in mixel_dphy_config_from_opts()
167 return -EINVAL; in mixel_dphy_config_from_opts()
169 numerator = dphy_opts->hs_clk_rate; in mixel_dphy_config_from_opts()
173 dev_err(&phy->dev, "Invalid %d/%d for %ld/%ld\n", in mixel_dphy_config_from_opts()
175 dphy_opts->hs_clk_rate, ref_clk); in mixel_dphy_config_from_opts()
176 return -EINVAL; in mixel_dphy_config_from_opts()
191 cfg->cn = denominator >> i; in mixel_dphy_config_from_opts()
192 cfg->co = 1 << i; in mixel_dphy_config_from_opts()
193 cfg->cm = numerator; in mixel_dphy_config_from_opts()
195 if (cfg->cm < 16 || cfg->cm > 255 || in mixel_dphy_config_from_opts()
196 cfg->cn < 1 || cfg->cn > 32 || in mixel_dphy_config_from_opts()
197 cfg->co < 1 || cfg->co > 8) { in mixel_dphy_config_from_opts()
198 dev_err(&phy->dev, "Invalid CM/CN/CO values: %u/%u/%u\n", in mixel_dphy_config_from_opts()
199 cfg->cm, cfg->cn, cfg->co); in mixel_dphy_config_from_opts()
200 dev_err(&phy->dev, "for hs_clk/ref_clk=%ld/%ld ~ %d/%d\n", in mixel_dphy_config_from_opts()
201 dphy_opts->hs_clk_rate, ref_clk, in mixel_dphy_config_from_opts()
203 return -EINVAL; in mixel_dphy_config_from_opts()
206 dev_dbg(&phy->dev, "hs_clk/ref_clk=%ld/%ld ~ %d/%d\n", in mixel_dphy_config_from_opts()
207 dphy_opts->hs_clk_rate, ref_clk, numerator, denominator); in mixel_dphy_config_from_opts()
211 do_div(tmp, dphy_opts->lp_clk_rate); /* ps */ in mixel_dphy_config_from_opts()
213 return -EINVAL; in mixel_dphy_config_from_opts()
216 dev_dbg(&phy->dev, "LP clock %lu, period: %u ps\n", in mixel_dphy_config_from_opts()
217 dphy_opts->lp_clk_rate, lp_t); in mixel_dphy_config_from_opts()
220 if (2 * dphy_opts->hs_prepare > 5 * lp_t) { in mixel_dphy_config_from_opts()
221 dev_err(&phy->dev, in mixel_dphy_config_from_opts()
223 dphy_opts->hs_prepare, lp_t); in mixel_dphy_config_from_opts()
224 return -EINVAL; in mixel_dphy_config_from_opts()
227 if (dphy_opts->hs_prepare < lp_t) { in mixel_dphy_config_from_opts()
230 tmp = 2 * (dphy_opts->hs_prepare - lp_t); in mixel_dphy_config_from_opts()
234 cfg->m_prg_hs_prepare = n; in mixel_dphy_config_from_opts()
237 if (2 * dphy_opts->clk_prepare > 3 * lp_t) { in mixel_dphy_config_from_opts()
238 dev_err(&phy->dev, in mixel_dphy_config_from_opts()
240 dphy_opts->clk_prepare, lp_t); in mixel_dphy_config_from_opts()
241 return -EINVAL; in mixel_dphy_config_from_opts()
244 cfg->mc_prg_hs_prepare = dphy_opts->clk_prepare > lp_t ? 1 : 0; in mixel_dphy_config_from_opts()
247 n = (144 * (dphy_opts->hs_clk_rate / 1000000) - 47500) / 10000; in mixel_dphy_config_from_opts()
248 cfg->m_prg_hs_zero = n < 1 ? 1 : n; in mixel_dphy_config_from_opts()
251 n = (34 * (dphy_opts->hs_clk_rate / 1000000) - 2500) / 1000; in mixel_dphy_config_from_opts()
252 cfg->mc_prg_hs_zero = n < 1 ? 1 : n; in mixel_dphy_config_from_opts()
255 n = (103 * (dphy_opts->hs_clk_rate / 1000000) + 10000) / 10000; in mixel_dphy_config_from_opts()
260 cfg->m_prg_hs_trail = n; in mixel_dphy_config_from_opts()
261 cfg->mc_prg_hs_trail = n; in mixel_dphy_config_from_opts()
264 if (dphy_opts->hs_clk_rate < MBPS(80)) in mixel_dphy_config_from_opts()
265 cfg->rxhs_settle = 0x0d; in mixel_dphy_config_from_opts()
266 else if (dphy_opts->hs_clk_rate < MBPS(90)) in mixel_dphy_config_from_opts()
267 cfg->rxhs_settle = 0x0c; in mixel_dphy_config_from_opts()
268 else if (dphy_opts->hs_clk_rate < MBPS(125)) in mixel_dphy_config_from_opts()
269 cfg->rxhs_settle = 0x0b; in mixel_dphy_config_from_opts()
270 else if (dphy_opts->hs_clk_rate < MBPS(150)) in mixel_dphy_config_from_opts()
271 cfg->rxhs_settle = 0x0a; in mixel_dphy_config_from_opts()
272 else if (dphy_opts->hs_clk_rate < MBPS(225)) in mixel_dphy_config_from_opts()
273 cfg->rxhs_settle = 0x09; in mixel_dphy_config_from_opts()
274 else if (dphy_opts->hs_clk_rate < MBPS(500)) in mixel_dphy_config_from_opts()
275 cfg->rxhs_settle = 0x08; in mixel_dphy_config_from_opts()
277 cfg->rxhs_settle = 0x07; in mixel_dphy_config_from_opts()
279 dev_dbg(&phy->dev, "phy_config: %u %u %u %u %u %u %u\n", in mixel_dphy_config_from_opts()
280 cfg->m_prg_hs_prepare, cfg->mc_prg_hs_prepare, in mixel_dphy_config_from_opts()
281 cfg->m_prg_hs_zero, cfg->mc_prg_hs_zero, in mixel_dphy_config_from_opts()
282 cfg->m_prg_hs_trail, cfg->mc_prg_hs_trail, in mixel_dphy_config_from_opts()
283 cfg->rxhs_settle); in mixel_dphy_config_from_opts()
288 static void mixel_phy_set_hs_timings(struct phy *phy) in mixel_phy_set_hs_timings() argument
290 struct mixel_dphy_priv *priv = phy_get_drvdata(phy); in mixel_phy_set_hs_timings()
292 phy_write(phy, priv->cfg.m_prg_hs_prepare, DPHY_M_PRG_HS_PREPARE); in mixel_phy_set_hs_timings()
293 phy_write(phy, priv->cfg.mc_prg_hs_prepare, DPHY_MC_PRG_HS_PREPARE); in mixel_phy_set_hs_timings()
294 phy_write(phy, priv->cfg.m_prg_hs_zero, DPHY_M_PRG_HS_ZERO); in mixel_phy_set_hs_timings()
295 phy_write(phy, priv->cfg.mc_prg_hs_zero, DPHY_MC_PRG_HS_ZERO); in mixel_phy_set_hs_timings()
296 phy_write(phy, priv->cfg.m_prg_hs_trail, DPHY_M_PRG_HS_TRAIL); in mixel_phy_set_hs_timings()
297 phy_write(phy, priv->cfg.mc_prg_hs_trail, DPHY_MC_PRG_HS_TRAIL); in mixel_phy_set_hs_timings()
298 phy_write(phy, priv->cfg.rxhs_settle, priv->devdata->reg_rxhs_settle); in mixel_phy_set_hs_timings()
301 static int mixel_dphy_set_pll_params(struct phy *phy) in mixel_dphy_set_pll_params() argument
303 struct mixel_dphy_priv *priv = dev_get_drvdata(phy->dev.parent); in mixel_dphy_set_pll_params()
305 if (priv->cfg.cm < 16 || priv->cfg.cm > 255 || in mixel_dphy_set_pll_params()
306 priv->cfg.cn < 1 || priv->cfg.cn > 32 || in mixel_dphy_set_pll_params()
307 priv->cfg.co < 1 || priv->cfg.co > 8) { in mixel_dphy_set_pll_params()
308 dev_err(&phy->dev, "Invalid CM/CN/CO values! (%u/%u/%u)\n", in mixel_dphy_set_pll_params()
309 priv->cfg.cm, priv->cfg.cn, priv->cfg.co); in mixel_dphy_set_pll_params()
310 return -EINVAL; in mixel_dphy_set_pll_params()
312 dev_dbg(&phy->dev, "Using CM:%u CN:%u CO:%u\n", in mixel_dphy_set_pll_params()
313 priv->cfg.cm, priv->cfg.cn, priv->cfg.co); in mixel_dphy_set_pll_params()
314 phy_write(phy, CM(priv->cfg.cm), DPHY_CM); in mixel_dphy_set_pll_params()
315 phy_write(phy, CN(priv->cfg.cn), DPHY_CN); in mixel_dphy_set_pll_params()
316 phy_write(phy, CO(priv->cfg.co), DPHY_CO); in mixel_dphy_set_pll_params()
320 static int mixel_dphy_configure(struct phy *phy, union phy_configure_opts *opts) in mixel_dphy_configure() argument
322 struct mixel_dphy_priv *priv = phy_get_drvdata(phy); in mixel_dphy_configure()
326 ret = mixel_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg); in mixel_dphy_configure()
331 memcpy(&priv->cfg, &cfg, sizeof(struct mixel_dphy_cfg)); in mixel_dphy_configure()
333 phy_write(phy, 0x00, DPHY_LOCK_BYP); in mixel_dphy_configure()
334 phy_write(phy, 0x01, priv->devdata->reg_tx_rcal); in mixel_dphy_configure()
335 phy_write(phy, 0x00, priv->devdata->reg_auto_pd_en); in mixel_dphy_configure()
336 phy_write(phy, 0x02, priv->devdata->reg_rxlprp); in mixel_dphy_configure()
337 phy_write(phy, 0x02, priv->devdata->reg_rxcdrp); in mixel_dphy_configure()
338 phy_write(phy, 0x25, DPHY_TST); in mixel_dphy_configure()
340 mixel_phy_set_hs_timings(phy); in mixel_dphy_configure()
341 ret = mixel_dphy_set_pll_params(phy); in mixel_dphy_configure()
348 static int mixel_dphy_validate(struct phy *phy, enum phy_mode mode, int submode, in mixel_dphy_validate() argument
354 return -EINVAL; in mixel_dphy_validate()
356 return mixel_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg); in mixel_dphy_validate()
359 static int mixel_dphy_init(struct phy *phy) in mixel_dphy_init() argument
361 phy_write(phy, PWR_OFF, DPHY_PD_PLL); in mixel_dphy_init()
362 phy_write(phy, PWR_OFF, DPHY_PD_DPHY); in mixel_dphy_init()
367 static int mixel_dphy_exit(struct phy *phy) in mixel_dphy_exit() argument
369 phy_write(phy, 0, DPHY_CM); in mixel_dphy_exit()
370 phy_write(phy, 0, DPHY_CN); in mixel_dphy_exit()
371 phy_write(phy, 0, DPHY_CO); in mixel_dphy_exit()
376 static int mixel_dphy_power_on(struct phy *phy) in mixel_dphy_power_on() argument
378 struct mixel_dphy_priv *priv = phy_get_drvdata(phy); in mixel_dphy_power_on()
382 ret = clk_prepare_enable(priv->phy_ref_clk); in mixel_dphy_power_on()
386 phy_write(phy, PWR_ON, DPHY_PD_PLL); in mixel_dphy_power_on()
387 ret = regmap_read_poll_timeout(priv->regmap, DPHY_LOCK, locked, in mixel_dphy_power_on()
391 dev_err(&phy->dev, "Could not get DPHY lock (%d)!\n", ret); in mixel_dphy_power_on()
394 phy_write(phy, PWR_ON, DPHY_PD_DPHY); in mixel_dphy_power_on()
398 clk_disable_unprepare(priv->phy_ref_clk); in mixel_dphy_power_on()
402 static int mixel_dphy_power_off(struct phy *phy) in mixel_dphy_power_off() argument
404 struct mixel_dphy_priv *priv = phy_get_drvdata(phy); in mixel_dphy_power_off()
406 phy_write(phy, PWR_OFF, DPHY_PD_PLL); in mixel_dphy_power_off()
407 phy_write(phy, PWR_OFF, DPHY_PD_DPHY); in mixel_dphy_power_off()
409 clk_disable_unprepare(priv->phy_ref_clk); in mixel_dphy_power_off()
425 { .compatible = "fsl,imx8mq-mipi-dphy",
433 struct device *dev = &pdev->dev; in mixel_dphy_probe()
434 struct device_node *np = dev->of_node; in mixel_dphy_probe()
438 struct phy *phy; in mixel_dphy_probe() local
442 return -ENODEV; in mixel_dphy_probe()
446 return -ENOMEM; in mixel_dphy_probe()
448 priv->devdata = of_device_get_match_data(&pdev->dev); in mixel_dphy_probe()
449 if (!priv->devdata) in mixel_dphy_probe()
450 return -EINVAL; in mixel_dphy_probe()
457 priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, in mixel_dphy_probe()
459 if (IS_ERR(priv->regmap)) { in mixel_dphy_probe()
461 return PTR_ERR(priv->regmap); in mixel_dphy_probe()
464 priv->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref"); in mixel_dphy_probe()
465 if (IS_ERR(priv->phy_ref_clk)) { in mixel_dphy_probe()
467 return PTR_ERR(priv->phy_ref_clk); in mixel_dphy_probe()
470 clk_get_rate(priv->phy_ref_clk)); in mixel_dphy_probe()
474 phy = devm_phy_create(dev, np, &mixel_dphy_phy_ops); in mixel_dphy_probe()
475 if (IS_ERR(phy)) { in mixel_dphy_probe()
476 dev_err(dev, "Failed to create phy %ld\n", PTR_ERR(phy)); in mixel_dphy_probe()
477 return PTR_ERR(phy); in mixel_dphy_probe()
479 phy_set_drvdata(phy, priv); in mixel_dphy_probe()
489 .name = "mixel-mipi-dphy",
496 MODULE_DESCRIPTION("Mixel MIPI-DSI PHY driver");