Lines Matching +full:sun6i +full:- +full:a31 +full:- +full:mipi +full:- +full:dphy

1 // SPDX-License-Identifier: GPL-2.0+
4 * Copyright (C) 2017-2018 Bootlin
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
18 #include <linux/phy/phy-mipi-dphy.h>
21 #define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4)
183 void (*tx_power_on)(struct sun6i_dphy *dphy);
202 struct sun6i_dphy *dphy = phy_get_drvdata(phy); in sun6i_dphy_init() local
204 reset_control_deassert(dphy->reset); in sun6i_dphy_init()
205 clk_prepare_enable(dphy->mod_clk); in sun6i_dphy_init()
206 clk_set_rate_exclusive(dphy->mod_clk, 150000000); in sun6i_dphy_init()
213 struct sun6i_dphy *dphy = phy_get_drvdata(phy); in sun6i_dphy_configure() local
216 ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy); in sun6i_dphy_configure()
220 memcpy(&dphy->config, opts, sizeof(dphy->config)); in sun6i_dphy_configure()
225 static void sun6i_a31_mipi_dphy_tx_power_on(struct sun6i_dphy *dphy) in sun6i_a31_mipi_dphy_tx_power_on() argument
227 u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); in sun6i_a31_mipi_dphy_tx_power_on()
229 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, in sun6i_a31_mipi_dphy_tx_power_on()
236 regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, in sun6i_a31_mipi_dphy_tx_power_on()
240 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, in sun6i_a31_mipi_dphy_tx_power_on()
251 regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, in sun6i_a31_mipi_dphy_tx_power_on()
255 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, in sun6i_a31_mipi_dphy_tx_power_on()
262 static void sun50i_a100_mipi_dphy_tx_power_on(struct sun6i_dphy *dphy) in sun50i_a100_mipi_dphy_tx_power_on() argument
264 unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate; in sun50i_a100_mipi_dphy_tx_power_on()
267 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, in sun50i_a100_mipi_dphy_tx_power_on()
279 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, in sun50i_a100_mipi_dphy_tx_power_on()
283 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, in sun50i_a100_mipi_dphy_tx_power_on()
287 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, in sun50i_a100_mipi_dphy_tx_power_on()
292 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, in sun50i_a100_mipi_dphy_tx_power_on()
296 regmap_write(dphy->regs, SUN50I_COMBO_PHY_REG0, in sun50i_a100_mipi_dphy_tx_power_on()
303 regmap_write(dphy->regs, SUN50I_DPHY_PLL_REG0, in sun50i_a100_mipi_dphy_tx_power_on()
309 SUN50I_DPHY_PLL_REG0_P((div - 1) % 8) | in sun50i_a100_mipi_dphy_tx_power_on()
311 SUN50I_DPHY_PLL_REG0_M0((div - 1) / 8) | in sun50i_a100_mipi_dphy_tx_power_on()
314 /* Disable sigma-delta modulation. */ in sun50i_a100_mipi_dphy_tx_power_on()
315 regmap_write(dphy->regs, SUN50I_DPHY_PLL_REG2, 0); in sun50i_a100_mipi_dphy_tx_power_on()
317 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA4_REG, in sun50i_a100_mipi_dphy_tx_power_on()
321 regmap_update_bits(dphy->regs, SUN50I_COMBO_PHY_REG0, in sun50i_a100_mipi_dphy_tx_power_on()
327 regmap_write(dphy->regs, SUN50I_COMBO_PHY_REG2, in sun50i_a100_mipi_dphy_tx_power_on()
332 static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy) in sun6i_dphy_tx_power_on() argument
334 u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); in sun6i_dphy_tx_power_on()
336 regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG, in sun6i_dphy_tx_power_on()
339 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG, in sun6i_dphy_tx_power_on()
344 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG, in sun6i_dphy_tx_power_on()
350 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG, in sun6i_dphy_tx_power_on()
353 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0); in sun6i_dphy_tx_power_on()
355 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG, in sun6i_dphy_tx_power_on()
359 dphy->variant->tx_power_on(dphy); in sun6i_dphy_tx_power_on()
361 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, in sun6i_dphy_tx_power_on()
368 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, in sun6i_dphy_tx_power_on()
373 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, in sun6i_dphy_tx_power_on()
378 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, in sun6i_dphy_tx_power_on()
382 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, in sun6i_dphy_tx_power_on()
386 regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, in sun6i_dphy_tx_power_on()
387 SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | in sun6i_dphy_tx_power_on()
393 static int sun6i_dphy_rx_power_on(struct sun6i_dphy *dphy) in sun6i_dphy_rx_power_on() argument
396 unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate; in sun6i_dphy_rx_power_on()
402 dphy_clk_rate = clk_get_rate(dphy->mod_clk); in sun6i_dphy_rx_power_on()
404 return -EINVAL; in sun6i_dphy_rx_power_on()
407 regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME0_REG, in sun6i_dphy_rx_power_on()
423 regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME1_REG, in sun6i_dphy_rx_power_on()
428 regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME2_REG, in sun6i_dphy_rx_power_on()
437 regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME3_REG, in sun6i_dphy_rx_power_on()
441 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, in sun6i_dphy_rx_power_on()
446 regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, in sun6i_dphy_rx_power_on()
449 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, in sun6i_dphy_rx_power_on()
453 regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, in sun6i_dphy_rx_power_on()
456 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, in sun6i_dphy_rx_power_on()
463 * ramp-up. in sun6i_dphy_rx_power_on()
470 * Rx data lane force-enable bits are used as regular RX enable by the in sun6i_dphy_rx_power_on()
473 if (dphy->config.lanes >= 1) in sun6i_dphy_rx_power_on()
475 if (dphy->config.lanes >= 2) in sun6i_dphy_rx_power_on()
477 if (dphy->config.lanes >= 3) in sun6i_dphy_rx_power_on()
479 if (dphy->config.lanes == 4) in sun6i_dphy_rx_power_on()
482 regmap_write(dphy->regs, SUN6I_DPHY_RX_CTL_REG, value); in sun6i_dphy_rx_power_on()
484 regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, in sun6i_dphy_rx_power_on()
485 SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | in sun6i_dphy_rx_power_on()
493 struct sun6i_dphy *dphy = phy_get_drvdata(phy); in sun6i_dphy_power_on() local
495 switch (dphy->direction) { in sun6i_dphy_power_on()
497 return sun6i_dphy_tx_power_on(dphy); in sun6i_dphy_power_on()
499 return sun6i_dphy_rx_power_on(dphy); in sun6i_dphy_power_on()
501 return -EINVAL; in sun6i_dphy_power_on()
507 struct sun6i_dphy *dphy = phy_get_drvdata(phy); in sun6i_dphy_power_off() local
509 regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, 0); in sun6i_dphy_power_off()
511 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, 0); in sun6i_dphy_power_off()
512 regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, 0); in sun6i_dphy_power_off()
513 regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, 0); in sun6i_dphy_power_off()
514 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, 0); in sun6i_dphy_power_off()
515 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, 0); in sun6i_dphy_power_off()
522 struct sun6i_dphy *dphy = phy_get_drvdata(phy); in sun6i_dphy_exit() local
524 clk_rate_exclusive_put(dphy->mod_clk); in sun6i_dphy_exit()
525 clk_disable_unprepare(dphy->mod_clk); in sun6i_dphy_exit()
526 reset_control_assert(dphy->reset); in sun6i_dphy_exit()
545 .name = "mipi-dphy",
551 struct sun6i_dphy *dphy; in sun6i_dphy_probe() local
556 dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); in sun6i_dphy_probe()
557 if (!dphy) in sun6i_dphy_probe()
558 return -ENOMEM; in sun6i_dphy_probe()
560 dphy->variant = device_get_match_data(&pdev->dev); in sun6i_dphy_probe()
561 if (!dphy->variant) in sun6i_dphy_probe()
562 return -EINVAL; in sun6i_dphy_probe()
566 dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n"); in sun6i_dphy_probe()
570 dphy->regs = devm_regmap_init_mmio_clk(&pdev->dev, "bus", in sun6i_dphy_probe()
572 if (IS_ERR(dphy->regs)) { in sun6i_dphy_probe()
573 dev_err(&pdev->dev, "Couldn't create the DPHY encoder regmap\n"); in sun6i_dphy_probe()
574 return PTR_ERR(dphy->regs); in sun6i_dphy_probe()
577 dphy->reset = devm_reset_control_get_shared(&pdev->dev, NULL); in sun6i_dphy_probe()
578 if (IS_ERR(dphy->reset)) { in sun6i_dphy_probe()
579 dev_err(&pdev->dev, "Couldn't get our reset line\n"); in sun6i_dphy_probe()
580 return PTR_ERR(dphy->reset); in sun6i_dphy_probe()
583 dphy->mod_clk = devm_clk_get(&pdev->dev, "mod"); in sun6i_dphy_probe()
584 if (IS_ERR(dphy->mod_clk)) { in sun6i_dphy_probe()
585 dev_err(&pdev->dev, "Couldn't get the DPHY mod clock\n"); in sun6i_dphy_probe()
586 return PTR_ERR(dphy->mod_clk); in sun6i_dphy_probe()
589 dphy->phy = devm_phy_create(&pdev->dev, NULL, &sun6i_dphy_ops); in sun6i_dphy_probe()
590 if (IS_ERR(dphy->phy)) { in sun6i_dphy_probe()
591 dev_err(&pdev->dev, "failed to create PHY\n"); in sun6i_dphy_probe()
592 return PTR_ERR(dphy->phy); in sun6i_dphy_probe()
595 dphy->direction = SUN6I_DPHY_DIRECTION_TX; in sun6i_dphy_probe()
597 ret = of_property_read_string(pdev->dev.of_node, "allwinner,direction", in sun6i_dphy_probe()
601 if (!dphy->variant->rx_supported) { in sun6i_dphy_probe()
602 dev_err(&pdev->dev, "RX not supported on this variant\n"); in sun6i_dphy_probe()
603 return -EOPNOTSUPP; in sun6i_dphy_probe()
606 dphy->direction = SUN6I_DPHY_DIRECTION_RX; in sun6i_dphy_probe()
609 phy_set_drvdata(dphy->phy, dphy); in sun6i_dphy_probe()
610 phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); in sun6i_dphy_probe()
626 .compatible = "allwinner,sun6i-a31-mipi-dphy",
630 .compatible = "allwinner,sun50i-a100-mipi-dphy",
640 .name = "sun6i-mipi-dphy",
647 MODULE_DESCRIPTION("Allwinner A31 MIPI D-PHY Driver");