Lines Matching +full:force +full:- +full:internal +full:- +full:phy
1 // SPDX-License-Identifier: GPL-2.0+
4 * Copyright (C) 2017-2018 Bootlin
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
17 #include <linux/phy/phy.h>
18 #include <linux/phy/phy-mipi-dphy.h>
21 #define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4)
123 struct phy *phy; member
129 static int sun6i_dphy_init(struct phy *phy) in sun6i_dphy_init() argument
131 struct sun6i_dphy *dphy = phy_get_drvdata(phy); in sun6i_dphy_init()
133 reset_control_deassert(dphy->reset); in sun6i_dphy_init()
134 clk_prepare_enable(dphy->mod_clk); in sun6i_dphy_init()
135 clk_set_rate_exclusive(dphy->mod_clk, 150000000); in sun6i_dphy_init()
140 static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts) in sun6i_dphy_configure() argument
142 struct sun6i_dphy *dphy = phy_get_drvdata(phy); in sun6i_dphy_configure()
145 ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy); in sun6i_dphy_configure()
149 memcpy(&dphy->config, opts, sizeof(dphy->config)); in sun6i_dphy_configure()
156 u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); in sun6i_dphy_tx_power_on()
158 regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG, in sun6i_dphy_tx_power_on()
161 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG, in sun6i_dphy_tx_power_on()
166 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG, in sun6i_dphy_tx_power_on()
172 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG, in sun6i_dphy_tx_power_on()
175 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0); in sun6i_dphy_tx_power_on()
177 regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG, in sun6i_dphy_tx_power_on()
181 regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, in sun6i_dphy_tx_power_on()
182 SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | in sun6i_dphy_tx_power_on()
185 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, in sun6i_dphy_tx_power_on()
192 regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, in sun6i_dphy_tx_power_on()
196 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, in sun6i_dphy_tx_power_on()
207 regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, in sun6i_dphy_tx_power_on()
211 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, in sun6i_dphy_tx_power_on()
217 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, in sun6i_dphy_tx_power_on()
224 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG, in sun6i_dphy_tx_power_on()
229 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, in sun6i_dphy_tx_power_on()
234 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, in sun6i_dphy_tx_power_on()
238 regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG, in sun6i_dphy_tx_power_on()
248 unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate; in sun6i_dphy_rx_power_on()
254 dphy_clk_rate = clk_get_rate(dphy->mod_clk); in sun6i_dphy_rx_power_on()
256 return -EINVAL; in sun6i_dphy_rx_power_on()
259 regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME0_REG, in sun6i_dphy_rx_power_on()
266 * (probably internal divider/multiplier). in sun6i_dphy_rx_power_on()
275 regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME1_REG, in sun6i_dphy_rx_power_on()
280 regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME2_REG, in sun6i_dphy_rx_power_on()
285 * (probably internal divider/multiplier). in sun6i_dphy_rx_power_on()
289 regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME3_REG, in sun6i_dphy_rx_power_on()
293 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, in sun6i_dphy_rx_power_on()
298 regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, in sun6i_dphy_rx_power_on()
301 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, in sun6i_dphy_rx_power_on()
305 regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, in sun6i_dphy_rx_power_on()
308 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, in sun6i_dphy_rx_power_on()
314 * Delay comes from the Allwinner BSP, likely for internal regulator in sun6i_dphy_rx_power_on()
315 * ramp-up. in sun6i_dphy_rx_power_on()
322 * Rx data lane force-enable bits are used as regular RX enable by the in sun6i_dphy_rx_power_on()
325 if (dphy->config.lanes >= 1) in sun6i_dphy_rx_power_on()
327 if (dphy->config.lanes >= 2) in sun6i_dphy_rx_power_on()
329 if (dphy->config.lanes >= 3) in sun6i_dphy_rx_power_on()
331 if (dphy->config.lanes == 4) in sun6i_dphy_rx_power_on()
334 regmap_write(dphy->regs, SUN6I_DPHY_RX_CTL_REG, value); in sun6i_dphy_rx_power_on()
336 regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, in sun6i_dphy_rx_power_on()
337 SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | in sun6i_dphy_rx_power_on()
343 static int sun6i_dphy_power_on(struct phy *phy) in sun6i_dphy_power_on() argument
345 struct sun6i_dphy *dphy = phy_get_drvdata(phy); in sun6i_dphy_power_on()
347 switch (dphy->direction) { in sun6i_dphy_power_on()
353 return -EINVAL; in sun6i_dphy_power_on()
357 static int sun6i_dphy_power_off(struct phy *phy) in sun6i_dphy_power_off() argument
359 struct sun6i_dphy *dphy = phy_get_drvdata(phy); in sun6i_dphy_power_off()
361 regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, 0); in sun6i_dphy_power_off()
363 regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, 0); in sun6i_dphy_power_off()
364 regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, 0); in sun6i_dphy_power_off()
365 regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, 0); in sun6i_dphy_power_off()
366 regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, 0); in sun6i_dphy_power_off()
367 regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, 0); in sun6i_dphy_power_off()
372 static int sun6i_dphy_exit(struct phy *phy) in sun6i_dphy_exit() argument
374 struct sun6i_dphy *dphy = phy_get_drvdata(phy); in sun6i_dphy_exit()
376 clk_rate_exclusive_put(dphy->mod_clk); in sun6i_dphy_exit()
377 clk_disable_unprepare(dphy->mod_clk); in sun6i_dphy_exit()
378 reset_control_assert(dphy->reset); in sun6i_dphy_exit()
397 .name = "mipi-dphy",
408 dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); in sun6i_dphy_probe()
410 return -ENOMEM; in sun6i_dphy_probe()
414 dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n"); in sun6i_dphy_probe()
418 dphy->regs = devm_regmap_init_mmio_clk(&pdev->dev, "bus", in sun6i_dphy_probe()
420 if (IS_ERR(dphy->regs)) { in sun6i_dphy_probe()
421 dev_err(&pdev->dev, "Couldn't create the DPHY encoder regmap\n"); in sun6i_dphy_probe()
422 return PTR_ERR(dphy->regs); in sun6i_dphy_probe()
425 dphy->reset = devm_reset_control_get_shared(&pdev->dev, NULL); in sun6i_dphy_probe()
426 if (IS_ERR(dphy->reset)) { in sun6i_dphy_probe()
427 dev_err(&pdev->dev, "Couldn't get our reset line\n"); in sun6i_dphy_probe()
428 return PTR_ERR(dphy->reset); in sun6i_dphy_probe()
431 dphy->mod_clk = devm_clk_get(&pdev->dev, "mod"); in sun6i_dphy_probe()
432 if (IS_ERR(dphy->mod_clk)) { in sun6i_dphy_probe()
433 dev_err(&pdev->dev, "Couldn't get the DPHY mod clock\n"); in sun6i_dphy_probe()
434 return PTR_ERR(dphy->mod_clk); in sun6i_dphy_probe()
437 dphy->phy = devm_phy_create(&pdev->dev, NULL, &sun6i_dphy_ops); in sun6i_dphy_probe()
438 if (IS_ERR(dphy->phy)) { in sun6i_dphy_probe()
439 dev_err(&pdev->dev, "failed to create PHY\n"); in sun6i_dphy_probe()
440 return PTR_ERR(dphy->phy); in sun6i_dphy_probe()
443 dphy->direction = SUN6I_DPHY_DIRECTION_TX; in sun6i_dphy_probe()
445 ret = of_property_read_string(pdev->dev.of_node, "allwinner,direction", in sun6i_dphy_probe()
449 dphy->direction = SUN6I_DPHY_DIRECTION_RX; in sun6i_dphy_probe()
451 phy_set_drvdata(dphy->phy, dphy); in sun6i_dphy_probe()
452 phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); in sun6i_dphy_probe()
458 { .compatible = "allwinner,sun6i-a31-mipi-dphy" },
466 .name = "sun6i-mipi-dphy",
473 MODULE_DESCRIPTION("Allwinner A31 MIPI D-PHY Driver");