diff --git a/arch/arm64/configs/qcom_defconfig b/arch/arm64/configs/qcom_defconfig index bad36f3818f3e..a1539178e5a14 100644 --- a/arch/arm64/configs/qcom_defconfig +++ b/arch/arm64/configs/qcom_defconfig @@ -760,6 +760,7 @@ CONFIG_IIO=y CONFIG_QCOM_SPMI_VADC=m CONFIG_QCOM_SPMI_ADC5=y CONFIG_PWM=y +CONFIG_PWM_CLK=y CONFIG_PWM_GPIO=m CONFIG_PWM_PCA9632=m CONFIG_PWM_PCA9685=m diff --git a/drivers/clk/qcom/gcc-sa8775p.c b/drivers/clk/qcom/gcc-sa8775p.c index 11c72a10ba698..199bfdfacb2b3 100644 --- a/drivers/clk/qcom/gcc-sa8775p.c +++ b/drivers/clk/qcom/gcc-sa8775p.c @@ -721,6 +721,11 @@ static struct clk_rcg2 gcc_emac1_rgmii_clk_src = { }; static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(1000, P_BI_TCXO, 16, 1, 1200), + F(5000, P_BI_TCXO, 16, 1, 240), + F(10000, P_BI_TCXO, 16, 1, 120), + F(20000, P_BI_TCXO, 16, 1, 60), + F(100000, P_BI_TCXO, 16, 1, 12), F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), { } @@ -736,7 +741,7 @@ static struct clk_rcg2 gcc_gp1_clk_src = { .name = "gcc_gp1_clk_src", .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_ops, }, }; @@ -750,7 +755,7 @@ static struct clk_rcg2 gcc_gp2_clk_src = { .name = "gcc_gp2_clk_src", .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_ops, }, }; @@ -764,7 +769,7 @@ static struct clk_rcg2 gcc_gp3_clk_src = { .name = "gcc_gp3_clk_src", .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_ops, }, }; @@ -778,7 +783,7 @@ static struct clk_rcg2 gcc_gp4_clk_src = { .name = "gcc_gp4_clk_src", .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_ops, }, }; @@ -792,7 +797,7 @@ static struct clk_rcg2 gcc_gp5_clk_src = { .name = "gcc_gp5_clk_src", .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_ops, }, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index d95f39e5b3219..ea1999d0290b3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -147,6 +147,7 @@ struct qcom_ethqos { struct phy *serdes_phy; unsigned int speed; int serdes_speed; + bool link_speed_valid; phy_interface_t phy_mode; struct reset_control *serdes_reset; @@ -948,15 +949,27 @@ static void ethqos_xpcs_validate_link_post_reset(struct qcom_ethqos *ethqos) } } +static bool ethqos_needs_speed_change_reset(unsigned int old_speed, + unsigned int new_speed) +{ + return old_speed != new_speed && + (old_speed == SPEED_2500 || new_speed == SPEED_2500); +} + static void ethqos_fix_mac_speed(void *priv_n, unsigned int speed, unsigned int mode) { struct qcom_ethqos *ethqos = priv_n; struct net_device *dev = platform_get_drvdata(ethqos->pdev); struct stmmac_priv *priv = netdev_priv(dev); + unsigned int old_speed = ethqos->speed; + bool reset_needed; + + reset_needed = ethqos->link_speed_valid && + ethqos_needs_speed_change_reset(old_speed, speed); qcom_ethqos_set_sgmii_loopback(ethqos, false); - ethqos->speed = speed; ethqos_update_link_clk(ethqos, speed); + ethqos->speed = speed; ethqos_configure(ethqos); if (priv->hw->phylink_pcs) { @@ -965,6 +978,14 @@ static void ethqos_fix_mac_speed(void *priv_n, unsigned int speed, unsigned int DUPLEX_FULL); ethqos_xpcs_validate_link_post_reset(ethqos); } + + ethqos->link_speed_valid = true; + + if (reset_needed) { + netdev_info(dev, "reset adapter after %uMbps to %uMbps link speed change\n", + old_speed, speed); + stmmac_request_reset(priv); + } } static int qcom_ethqos_serdes_powerup(struct net_device *ndev, void *priv) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 7020d369801b7..2b8eec75e1688 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -387,6 +387,7 @@ int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt); int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size); int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled); void stmmac_fpe_handshake(struct stmmac_priv *priv, bool enable); +void stmmac_request_reset(struct stmmac_priv *priv); static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 40fdb1a11ff08..bd7f3ad3c3825 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -287,6 +287,12 @@ static void stmmac_global_err(struct stmmac_priv *priv) stmmac_service_event_schedule(priv); } +void stmmac_request_reset(struct stmmac_priv *priv) +{ + stmmac_global_err(priv); +} +EXPORT_SYMBOL_GPL(stmmac_request_reset); + /** * stmmac_clk_csr_set - dynamically set the MDC clock * @priv: driver private structure diff --git a/drivers/pwm/pwm-clk.c b/drivers/pwm/pwm-clk.c index 9dd88b386907c..8fac5c50d7ae2 100644 --- a/drivers/pwm/pwm-clk.c +++ b/drivers/pwm/pwm-clk.c @@ -11,11 +11,20 @@ * - Due to the fact that exact behavior depends on the underlying * clock driver, various limitations are possible. * - Underlying clock may not be able to give 0% or 100% duty cycle - * (constant off or on), exact behavior will depend on the clock. + * (constant off or on), exact behavior will depend on the clock, + * unless a gpio pinctrl state is supplied. * - When the PWM is disabled, the clock will be disabled as well, - * line state will depend on the clock. + * line state will depend on the clock, unless a gpio pinctrl + * state is supplied. * - The clk API doesn't expose the necessary calls to implement * .get_state(). + * + * Optionally, a GPIO descriptor and pinctrl states ("default" and + * "gpio") can be provided. When a constant output level is needed + * (0% duty, 100% duty, or disabled), the driver switches the pin to + * GPIO mode and drives the appropriate level. For normal PWM output + * the pin is switched back to its clock function mux. If no GPIO is + * provided, the driver falls back to the original clock-only behavior. */ #include @@ -25,12 +34,18 @@ #include #include #include +#include +#include #include struct pwm_clk_chip { struct pwm_chip chip; struct clk *clk; bool clk_enabled; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_gpio; + struct gpio_desc *gpiod; }; #define to_pwm_clk_chip(_chip) container_of(_chip, struct pwm_clk_chip, chip) @@ -43,14 +58,38 @@ static int pwm_clk_apply(struct pwm_chip *chip, struct pwm_device *pwm, u32 rate; u64 period = state->period; u64 duty_cycle = state->duty_cycle; + bool constant_level = false; + int gpio_value = 0; if (!state->enabled) { - if (pwm->state.enabled) { + constant_level = true; + gpio_value = 0; + } else if (state->duty_cycle == 0) { + constant_level = true; + gpio_value = (state->polarity == PWM_POLARITY_INVERSED) ? 1 : 0; + } else if (state->duty_cycle >= state->period) { + constant_level = true; + gpio_value = (state->polarity == PWM_POLARITY_INVERSED) ? 0 : 1; + } + + if (constant_level) { + if (pcchip->gpiod) + gpiod_direction_output(pcchip->gpiod, gpio_value); + if (pcchip->clk_enabled) { clk_disable(pcchip->clk); pcchip->clk_enabled = false; } + if (pcchip->gpiod) { + pinctrl_select_state(pcchip->pinctrl, pcchip->pins_gpio); + gpiod_direction_output(pcchip->gpiod, gpio_value); + } return 0; - } else if (!pwm->state.enabled) { + } + + if (pcchip->gpiod) + pinctrl_select_state(pcchip->pinctrl, pcchip->pins_default); + + if (!pcchip->clk_enabled) { ret = clk_enable(pcchip->clk); if (ret) return ret; @@ -93,6 +132,44 @@ static int pwm_clk_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, PTR_ERR(pcchip->clk), "Failed to get clock\n"); + pcchip->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(pcchip->pinctrl)) { + ret = PTR_ERR(pcchip->pinctrl); + pcchip->pinctrl = NULL; + if (ret == -EPROBE_DEFER) + return ret; + } else { + pcchip->pins_default = pinctrl_lookup_state(pcchip->pinctrl, + PINCTRL_STATE_DEFAULT); + pcchip->pins_gpio = pinctrl_lookup_state(pcchip->pinctrl, "gpio"); + if (IS_ERR(pcchip->pins_default) || IS_ERR(pcchip->pins_gpio)) + pcchip->pinctrl = NULL; + } + + /* + * Switch to GPIO pinctrl state before requesting the GPIO. The driver + * core has already applied the default state, which muxes the pin to the + * clock function and claims it. Release that claim first so gpiolib can + * request the pin. + */ + if (pcchip->pinctrl) + pinctrl_select_state(pcchip->pinctrl, pcchip->pins_gpio); + + pcchip->gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, GPIOD_ASIS); + if (IS_ERR(pcchip->gpiod)) + return dev_err_probe(&pdev->dev, PTR_ERR(pcchip->gpiod), + "Failed to get gpio\n"); + + /* + * If pinctrl states were found but no GPIO was provided, the pin is stuck + * in GPIO mode from the switch above. Restore the default mux and fall + * back to clock-only operation. + */ + if (pcchip->pinctrl && !pcchip->gpiod) { + pinctrl_select_state(pcchip->pinctrl, pcchip->pins_default); + pcchip->pinctrl = NULL; + } + pcchip->chip.dev = &pdev->dev; pcchip->chip.ops = &pwm_clk_ops; pcchip->chip.npwm = 1; diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 765a3701d95a0..a533457e02196 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -1243,6 +1243,11 @@ static int qcom_geni_serial_startup(struct uart_port *uport) if (ret) return ret; } + + if (uport->rs485.flags & SER_RS485_ENABLED) + qcom_geni_set_rts_pin(uport, + !!(uport->rs485.flags & SER_RS485_RTS_AFTER_SEND)); + enable_irq(uport->irq); return 0; @@ -1601,12 +1606,12 @@ static void qcom_geni_serial_pm(struct uart_port *uport, static int qcom_geni_rs485_config(struct uart_port *uport, struct ktermios *termios, struct serial_rs485 *rs485) { - /* When RS485 is enabled, keep the RTS pin in ACTIVE state - * and revert back to auto flow control mode, i.e. flow control - * managed by the QUP HW once RS485 is disabled. + /* Initialize RTS to its idle state when RS485 is enabled and revert + * to QUP-managed automatic flow control once RS485 is disabled. */ if (rs485->flags & SER_RS485_ENABLED) - qcom_geni_set_rts_pin(uport, true); + qcom_geni_set_rts_pin(uport, + !!(rs485->flags & SER_RS485_RTS_AFTER_SEND)); else writel(0, uport->membase + SE_UART_MANUAL_RFR);