| // SPDX-License-Identifier: GPL-2.0-only |
| /* |
| * Copyright (C) STMicroelectronics 2025 - All Rights Reserved |
| * Author: Clément Le Goffic <clement.legoffic@foss.st.com> for STMicroelectronics. |
| */ |
| #include <linux/bits.h> |
| #include <linux/clk.h> |
| #include <linux/gpio/driver.h> |
| #include <linux/io.h> |
| #include <linux/of.h> |
| #include <linux/of_device.h> |
| #include <linux/pinctrl/consumer.h> |
| #include <linux/pinctrl/pinconf-generic.h> |
| #include <linux/pinctrl/pinctrl.h> |
| #include <linux/pinctrl/pinmux.h> |
| #include <linux/platform_device.h> |
| #include <linux/pm.h> |
| |
| #include "../core.h" |
| |
| #define DRIVER_NAME "stm32_hdp" |
| #define HDP_CTRL_ENABLE 1 |
| #define HDP_CTRL_DISABLE 0 |
| |
| #define HDP_CTRL 0x000 |
| #define HDP_MUX 0x004 |
| #define HDP_VAL 0x010 |
| #define HDP_GPOSET 0x014 |
| #define HDP_GPOCLR 0x018 |
| #define HDP_GPOVAL 0x01c |
| #define HDP_VERR 0x3f4 |
| #define HDP_IPIDR 0x3f8 |
| #define HDP_SIDR 0x3fc |
| |
| #define HDP_MUX_SHIFT(n) ((n) * 4) |
| #define HDP_MUX_MASK(n) (GENMASK(3, 0) << HDP_MUX_SHIFT(n)) |
| #define HDP_MUX_GPOVAL(n) (0xf << HDP_MUX_SHIFT(n)) |
| |
| #define HDP_PIN 8 |
| #define HDP_FUNC 16 |
| #define HDP_FUNC_TOTAL (HDP_PIN * HDP_FUNC) |
| |
| struct stm32_hdp { |
| struct device *dev; |
| void __iomem *base; |
| struct clk *clk; |
| struct pinctrl_dev *pctl_dev; |
| struct gpio_chip gpio_chip; |
| u32 mux_conf; |
| u32 gposet_conf; |
| const char * const *func_name; |
| }; |
| |
| static const struct pinctrl_pin_desc stm32_hdp_pins[] = { |
| PINCTRL_PIN(0, "HDP0"), |
| PINCTRL_PIN(1, "HDP1"), |
| PINCTRL_PIN(2, "HDP2"), |
| PINCTRL_PIN(3, "HDP3"), |
| PINCTRL_PIN(4, "HDP4"), |
| PINCTRL_PIN(5, "HDP5"), |
| PINCTRL_PIN(6, "HDP6"), |
| PINCTRL_PIN(7, "HDP7"), |
| }; |
| |
| static const char * const func_name_mp13[] = { |
| //HDP0 functions: |
| "pwr_pwrwake_sys", |
| "pwr_stop_forbidden", |
| "pwr_stdby_wakeup", |
| "pwr_encomp_vddcore", |
| "bsec_out_sec_niden", |
| "aiec_sys_wakeup", |
| "none", |
| "none", |
| "ddrctrl_lp_req", |
| "pwr_ddr_ret_enable_n", |
| "dts_clk_ptat", |
| "none", |
| "sram3ctrl_tamp_erase_act", |
| "none", |
| "none", |
| "gpoval0", |
| //HDP1 functions: |
| "pwr_sel_vth_vddcpu", |
| "pwr_mpu_ram_lowspeed", |
| "ca7_naxierrirq", |
| "pwr_okin_mr", |
| "bsec_out_sec_dbgen", |
| "aiec_c1_wakeup", |
| "rcc_pwrds_mpu", |
| "none", |
| "ddrctrl_dfi_ctrlupd_req", |
| "ddrctrl_cactive_ddrc_asr", |
| "none", |
| "none", |
| "sram3ctrl_hw_erase_act", |
| "nic400_s0_bready", |
| "none", |
| "gpoval1", |
| //HDP2 functions: |
| "pwr_pwrwake_mpu", |
| "pwr_mpu_clock_disable_ack", |
| "ca7_ndbgreset_i", |
| "none", |
| "bsec_in_rstcore_n", |
| "bsec_out_sec_bsc_dis", |
| "none", |
| "none", |
| "ddrctrl_dfi_init_complete", |
| "ddrctrl_perf_op_is_refresh", |
| "ddrctrl_gskp_dfi_lp_req", |
| "none", |
| "sram3ctrl_sw_erase_act", |
| "nic400_s0_bvalid", |
| "none", |
| "gpoval2", |
| //HDP3 functions: |
| "pwr_sel_vth_vddcore", |
| "pwr_mpu_clock_disable_req", |
| "ca7_npmuirq0", |
| "ca7_nfiqout0", |
| "bsec_out_sec_dftlock", |
| "bsec_out_sec_jtag_dis", |
| "rcc_pwrds_sys", |
| "sram3ctrl_tamp_erase_req", |
| "ddrctrl_stat_ddrc_reg_selfref_type0", |
| "none", |
| "dts_valobus1_0", |
| "dts_valobus2_0", |
| "tamp_potential_tamp_erfcfg", |
| "nic400_s0_wready", |
| "nic400_s0_rready", |
| "gpoval3", |
| //HDP4 functions: |
| "none", |
| "pwr_stop2_active", |
| "ca7_nl2reset_i", |
| "ca7_npreset_varm_i", |
| "bsec_out_sec_dften", |
| "bsec_out_sec_dbgswenable", |
| "eth1_out_pmt_intr_o", |
| "eth2_out_pmt_intr_o", |
| "ddrctrl_stat_ddrc_reg_selfref_type1", |
| "ddrctrl_cactive_0", |
| "dts_valobus1_1", |
| "dts_valobus2_1", |
| "tamp_nreset_sram_ercfg", |
| "nic400_s0_wlast", |
| "nic400_s0_rlast", |
| "gpoval4", |
| //HDP5 functions: |
| "ca7_standbywfil2", |
| "pwr_vth_vddcore_ack", |
| "ca7_ncorereset_i", |
| "ca7_nirqout0", |
| "bsec_in_pwrok", |
| "bsec_out_sec_deviceen", |
| "eth1_out_lpi_intr_o", |
| "eth2_out_lpi_intr_o", |
| "ddrctrl_cactive_ddrc", |
| "ddrctrl_wr_credit_cnt", |
| "dts_valobus1_2", |
| "dts_valobus2_2", |
| "pka_pka_itamp_out", |
| "nic400_s0_wvalid", |
| "nic400_s0_rvalid", |
| "gpoval5", |
| //HDP6 functions: |
| "ca7_standbywfe0", |
| "pwr_vth_vddcpu_ack", |
| "ca7_evento", |
| "none", |
| "bsec_in_tamper_det", |
| "bsec_out_sec_spniden", |
| "eth1_out_mac_speed_o1", |
| "eth2_out_mac_speed_o1", |
| "ddrctrl_csysack_ddrc", |
| "ddrctrl_lpr_credit_cnt", |
| "dts_valobus1_3", |
| "dts_valobus2_3", |
| "saes_tamper_out", |
| "nic400_s0_awready", |
| "nic400_s0_arready", |
| "gpoval6", |
| //HDP7 functions: |
| "ca7_standbywfi0", |
| "pwr_rcc_vcpu_rdy", |
| "ca7_eventi", |
| "ca7_dbgack0", |
| "bsec_out_fuse_ok", |
| "bsec_out_sec_spiden", |
| "eth1_out_mac_speed_o0", |
| "eth2_out_mac_speed_o0", |
| "ddrctrl_csysreq_ddrc", |
| "ddrctrl_hpr_credit_cnt", |
| "dts_valobus1_4", |
| "dts_valobus2_4", |
| "rng_tamper_out", |
| "nic400_s0_awavalid", |
| "nic400_s0_aravalid", |
| "gpoval7", |
| }; |
| |
| static const char * const func_name_mp15[] = { |
| //HDP0 functions: |
| "pwr_pwrwake_sys", |
| "cm4_sleepdeep", |
| "pwr_stdby_wkup", |
| "pwr_encomp_vddcore", |
| "bsec_out_sec_niden", |
| "none", |
| "rcc_cm4_sleepdeep", |
| "gpu_dbg7", |
| "ddrctrl_lp_req", |
| "pwr_ddr_ret_enable_n", |
| "dts_clk_ptat", |
| "none", |
| "none", |
| "none", |
| "none", |
| "gpoval0", |
| //HDP1 functions: |
| "pwr_pwrwake_mcu", |
| "cm4_halted", |
| "ca7_naxierrirq", |
| "pwr_okin_mr", |
| "bsec_out_sec_dbgen", |
| "exti_sys_wakeup", |
| "rcc_pwrds_mpu", |
| "gpu_dbg6", |
| "ddrctrl_dfi_ctrlupd_req", |
| "ddrctrl_cactive_ddrc_asr", |
| "none", |
| "none", |
| "none", |
| "none", |
| "none", |
| "gpoval1", |
| //HDP2 functions: |
| "pwr_pwrwake_mpu", |
| "cm4_rxev", |
| "ca7_npmuirq1", |
| "ca7_nfiqout1", |
| "bsec_in_rstcore_n", |
| "exti_c2_wakeup", |
| "rcc_pwrds_mcu", |
| "gpu_dbg5", |
| "ddrctrl_dfi_init_complete", |
| "ddrctrl_perf_op_is_refresh", |
| "ddrctrl_gskp_dfi_lp_req", |
| "none", |
| "none", |
| "none", |
| "none", |
| "gpoval2", |
| //HDP3 functions: |
| "pwr_sel_vth_vddcore", |
| "cm4_txev", |
| "ca7_npmuirq0", |
| "ca7_nfiqout0", |
| "bsec_out_sec_dftlock", |
| "exti_c1_wakeup", |
| "rcc_pwrds_sys", |
| "gpu_dbg4", |
| "ddrctrl_stat_ddrc_reg_selfref_type0", |
| "ddrctrl_cactive_1", |
| "dts_valobus1_0", |
| "dts_valobus2_0", |
| "none", |
| "none", |
| "none", |
| "gpoval3", |
| //HDP4 functions: |
| "pwr_mpu_pdds_not_cstbydis", |
| "cm4_sleeping", |
| "ca7_nreset1", |
| "ca7_nirqout1", |
| "bsec_out_sec_dften", |
| "bsec_out_sec_dbgswenable", |
| "eth_out_pmt_intr_o", |
| "gpu_dbg3", |
| "ddrctrl_stat_ddrc_reg_selfref_type1", |
| "ddrctrl_cactive_0", |
| "dts_valobus1_1", |
| "dts_valobus2_1", |
| "none", |
| "none", |
| "none", |
| "gpoval4", |
| //HDP5 functions: |
| "ca7_standbywfil2", |
| "pwr_vth_vddcore_ack", |
| "ca7_nreset0", |
| "ca7_nirqout0", |
| "bsec_in_pwrok", |
| "bsec_out_sec_deviceen", |
| "eth_out_lpi_intr_o", |
| "gpu_dbg2", |
| "ddrctrl_cactive_ddrc", |
| "ddrctrl_wr_credit_cnt", |
| "dts_valobus1_2", |
| "dts_valobus2_2", |
| "none", |
| "none", |
| "none", |
| "gpoval5", |
| //HDP6 functions: |
| "ca7_standbywfi1", |
| "ca7_standbywfe1", |
| "ca7_evento", |
| "ca7_dbgack1", |
| "none", |
| "bsec_out_sec_spniden", |
| "eth_out_mac_speed_o1", |
| "gpu_dbg1", |
| "ddrctrl_csysack_ddrc", |
| "ddrctrl_lpr_credit_cnt", |
| "dts_valobus1_3", |
| "dts_valobus2_3", |
| "none", |
| "none", |
| "none", |
| "gpoval6", |
| //HDP7 functions: |
| "ca7_standbywfi0", |
| "ca7_standbywfe0", |
| "none", |
| "ca7_dbgack0", |
| "bsec_out_fuse_ok", |
| "bsec_out_sec_spiden", |
| "eth_out_mac_speed_o0", |
| "gpu_dbg0", |
| "ddrctrl_csysreq_ddrc", |
| "ddrctrl_hpr_credit_cnt", |
| "dts_valobus1_4", |
| "dts_valobus2_4", |
| "none", |
| "none", |
| "none", |
| "gpoval7" |
| }; |
| |
| static const char * const func_name_mp25[] = { |
| //HDP0 functions: |
| "pwr_pwrwake_sys", |
| "cpu2_sleep_deep", |
| "bsec_out_tst_sdr_unlock_or_disable_scan", |
| "bsec_out_nidenm", |
| "bsec_out_nidena", |
| "cpu2_state_0", |
| "rcc_pwrds_sys", |
| "gpu_dbg7", |
| "ddrss_csysreq_ddrc", |
| "ddrss_dfi_phyupd_req", |
| "cpu3_sleep_deep", |
| "d2_gbl_per_clk_bus_req", |
| "pcie_usb_cxpl_debug_info_ei_0", |
| "pcie_usb_cxpl_debug_info_ei_8", |
| "d3_state_0", |
| "gpoval0", |
| //HDP1 functions: |
| "pwr_pwrwake_cpu2", |
| "cpu2_halted", |
| "cpu2_state_1", |
| "bsec_out_dbgenm", |
| "bsec_out_dbgena", |
| "exti1_sys_wakeup", |
| "rcc_pwrds_cpu2", |
| "gpu_dbg6", |
| "ddrss_csysack_ddrc", |
| "ddrss_dfi_phymstr_req", |
| "cpu3_halted", |
| "d2_gbl_per_dma_req", |
| "pcie_usb_cxpl_debug_info_ei_1", |
| "pcie_usb_cxpl_debug_info_ei_9", |
| "d3_state_1", |
| "gpoval1", |
| //HDP2 functions: |
| "pwr_pwrwake_cpu1", |
| "cpu2_rxev", |
| "cpu1_npumirq1", |
| "cpu1_nfiqout1", |
| "bsec_out_shdbgen", |
| "exti1_cpu2_wakeup", |
| "rcc_pwrds_cpu1", |
| "gpu_dbg5", |
| "ddrss_cactive_ddrc", |
| "ddrss_dfi_lp_req", |
| "cpu3_rxev", |
| "hpdma1_clk_bus_req", |
| "pcie_usb_cxpl_debug_info_ei_2", |
| "pcie_usb_cxpl_debug_info_ei_10", |
| "d3_state_2", |
| "gpoval2", |
| //HDP3 functions: |
| "pwr_sel_vth_vddcpu", |
| "cpu2_txev", |
| "cpu1_npumirq0", |
| "cpu1_nfiqout0", |
| "bsec_out_ddbgen", |
| "exti1_cpu1_wakeup", |
| "cpu3_state_0", |
| "gpu_dbg4", |
| "ddrss_mcdcg_en", |
| "ddrss_dfi_freq_0", |
| "cpu3_txev", |
| "hpdma2_clk_bus_req", |
| "pcie_usb_cxpl_debug_info_ei_3", |
| "pcie_usb_cxpl_debug_info_ei_11", |
| "d1_state_0", |
| "gpoval3", |
| //HDP4 functions: |
| "pwr_sel_vth_vddcore", |
| "cpu2_sleeping", |
| "cpu1_evento", |
| "cpu1_nirqout1", |
| "bsec_out_spnidena", |
| "exti2_d3_wakeup", |
| "eth1_out_pmt_intr_o", |
| "gpu_dbg3", |
| "ddrss_dphycg_en", |
| "ddrss_obsp0", |
| "cpu3_sleeping", |
| "hpdma3_clk_bus_req", |
| "pcie_usb_cxpl_debug_info_ei_4", |
| "pcie_usb_cxpl_debug_info_ei_12", |
| "d1_state_1", |
| "gpoval4", |
| //HDP5 functions: |
| "cpu1_standby_wfil2", |
| "none", |
| "none", |
| "cpu1_nirqout0", |
| "bsec_out_spidena", |
| "exti2_cpu3_wakeup", |
| "eth1_out_lpi_intr_o", |
| "gpu_dbg2", |
| "ddrctrl_dfi_init_start", |
| "ddrss_obsp1", |
| "cpu3_state_1", |
| "d3_gbl_per_clk_bus_req", |
| "pcie_usb_cxpl_debug_info_ei_5", |
| "pcie_usb_cxpl_debug_info_ei_13", |
| "d1_state_2", |
| "gpoval5", |
| //HDP6 functions: |
| "cpu1_standby_wfi1", |
| "cpu1_standby_wfe1", |
| "cpu1_halted1", |
| "cpu1_naxierrirq", |
| "bsec_out_spnidenm", |
| "exti2_cpu2_wakeup", |
| "eth2_out_pmt_intr_o", |
| "gpu_dbg1", |
| "ddrss_dfi_init_complete", |
| "ddrss_obsp2", |
| "d2_state_0", |
| "d3_gbl_per_dma_req", |
| "pcie_usb_cxpl_debug_info_ei_6", |
| "pcie_usb_cxpl_debug_info_ei_14", |
| "cpu1_state_0", |
| "gpoval6", |
| //HDP7 functions: |
| "cpu1_standby_wfi0", |
| "cpu1_standby_wfe0", |
| "cpu1_halted0", |
| "none", |
| "bsec_out_spidenm", |
| "exti2_cpu1__wakeup", |
| "eth2_out_lpi_intr_o", |
| "gpu_dbg0", |
| "ddrss_dfi_ctrlupd_req", |
| "ddrss_obsp3", |
| "d2_state_1", |
| "lpdma1_clk_bus_req", |
| "pcie_usb_cxpl_debug_info_ei_7", |
| "pcie_usb_cxpl_debug_info_ei_15", |
| "cpu1_state_1", |
| "gpoval7", |
| }; |
| |
| static const char * const stm32_hdp_pins_group[] = { |
| "HDP0", |
| "HDP1", |
| "HDP2", |
| "HDP3", |
| "HDP4", |
| "HDP5", |
| "HDP6", |
| "HDP7" |
| }; |
| |
| static int stm32_hdp_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) |
| { |
| return GPIO_LINE_DIRECTION_OUT; |
| } |
| |
| static int stm32_hdp_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) |
| { |
| return ARRAY_SIZE(stm32_hdp_pins); |
| } |
| |
| static const char *stm32_hdp_pinctrl_get_group_name(struct pinctrl_dev *pctldev, |
| unsigned int selector) |
| { |
| return stm32_hdp_pins[selector].name; |
| } |
| |
| static int stm32_hdp_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, |
| const unsigned int **pins, unsigned int *num_pins) |
| { |
| *pins = &stm32_hdp_pins[selector].number; |
| *num_pins = 1; |
| |
| return 0; |
| } |
| |
| static const struct pinctrl_ops stm32_hdp_pinctrl_ops = { |
| .get_groups_count = stm32_hdp_pinctrl_get_groups_count, |
| .get_group_name = stm32_hdp_pinctrl_get_group_name, |
| .get_group_pins = stm32_hdp_pinctrl_get_group_pins, |
| .dt_node_to_map = pinconf_generic_dt_node_to_map_all, |
| .dt_free_map = pinconf_generic_dt_free_map, |
| }; |
| |
| static int stm32_hdp_pinmux_get_functions_count(struct pinctrl_dev *pctldev) |
| { |
| return HDP_FUNC_TOTAL; |
| } |
| |
| static const char *stm32_hdp_pinmux_get_function_name(struct pinctrl_dev *pctldev, |
| unsigned int selector) |
| { |
| struct stm32_hdp *hdp = pinctrl_dev_get_drvdata(pctldev); |
| |
| return hdp->func_name[selector]; |
| } |
| |
| static int stm32_hdp_pinmux_get_function_groups(struct pinctrl_dev *pctldev, unsigned int selector, |
| const char *const **groups, |
| unsigned int *num_groups) |
| { |
| u32 index = selector / HDP_FUNC; |
| |
| *groups = &stm32_hdp_pins[index].name; |
| *num_groups = 1; |
| |
| return 0; |
| } |
| |
| static int stm32_hdp_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, |
| unsigned int group_selector) |
| { |
| struct stm32_hdp *hdp = pinctrl_dev_get_drvdata(pctldev); |
| |
| unsigned int pin = stm32_hdp_pins[group_selector].number; |
| u32 mux; |
| |
| func_selector %= HDP_FUNC; |
| mux = readl_relaxed(hdp->base + HDP_MUX); |
| mux &= ~HDP_MUX_MASK(pin); |
| mux |= func_selector << HDP_MUX_SHIFT(pin); |
| |
| writel_relaxed(mux, hdp->base + HDP_MUX); |
| hdp->mux_conf = mux; |
| |
| return 0; |
| } |
| |
| static const struct pinmux_ops stm32_hdp_pinmux_ops = { |
| .get_functions_count = stm32_hdp_pinmux_get_functions_count, |
| .get_function_name = stm32_hdp_pinmux_get_function_name, |
| .get_function_groups = stm32_hdp_pinmux_get_function_groups, |
| .set_mux = stm32_hdp_pinmux_set_mux, |
| .gpio_set_direction = NULL, |
| }; |
| |
| static struct pinctrl_desc stm32_hdp_pdesc = { |
| .name = DRIVER_NAME, |
| .pins = stm32_hdp_pins, |
| .npins = ARRAY_SIZE(stm32_hdp_pins), |
| .pctlops = &stm32_hdp_pinctrl_ops, |
| .pmxops = &stm32_hdp_pinmux_ops, |
| .owner = THIS_MODULE, |
| }; |
| |
| static const struct of_device_id stm32_hdp_of_match[] = { |
| { |
| .compatible = "st,stm32mp131-hdp", |
| .data = &func_name_mp13, |
| }, |
| { |
| .compatible = "st,stm32mp151-hdp", |
| .data = &func_name_mp15, |
| }, |
| { |
| .compatible = "st,stm32mp251-hdp", |
| .data = &func_name_mp25, |
| }, |
| {} |
| }; |
| MODULE_DEVICE_TABLE(of, stm32_hdp_of_match); |
| |
| static int stm32_hdp_probe(struct platform_device *pdev) |
| { |
| struct device *dev = &pdev->dev; |
| struct stm32_hdp *hdp; |
| u8 version; |
| int err; |
| |
| hdp = devm_kzalloc(dev, sizeof(*hdp), GFP_KERNEL); |
| if (!hdp) |
| return -ENOMEM; |
| hdp->dev = dev; |
| |
| platform_set_drvdata(pdev, hdp); |
| |
| hdp->base = devm_platform_ioremap_resource(pdev, 0); |
| if (IS_ERR(hdp->base)) |
| return PTR_ERR(hdp->base); |
| |
| hdp->func_name = of_device_get_match_data(dev); |
| if (!hdp->func_name) |
| return dev_err_probe(dev, -ENODEV, "No function name provided\n"); |
| |
| hdp->clk = devm_clk_get_enabled(dev, NULL); |
| if (IS_ERR(hdp->clk)) |
| return dev_err_probe(dev, PTR_ERR(hdp->clk), "No HDP clock provided\n"); |
| |
| err = devm_pinctrl_register_and_init(dev, &stm32_hdp_pdesc, hdp, &hdp->pctl_dev); |
| if (err) |
| return dev_err_probe(dev, err, "Failed to register pinctrl\n"); |
| |
| err = pinctrl_enable(hdp->pctl_dev); |
| if (err) |
| return dev_err_probe(dev, err, "Failed to enable pinctrl\n"); |
| |
| hdp->gpio_chip.get_direction = stm32_hdp_gpio_get_direction; |
| hdp->gpio_chip.ngpio = ARRAY_SIZE(stm32_hdp_pins); |
| hdp->gpio_chip.can_sleep = true; |
| hdp->gpio_chip.names = stm32_hdp_pins_group; |
| |
| err = bgpio_init(&hdp->gpio_chip, dev, 4, |
| hdp->base + HDP_GPOVAL, |
| hdp->base + HDP_GPOSET, |
| hdp->base + HDP_GPOCLR, |
| NULL, NULL, BGPIOF_NO_INPUT); |
| if (err) |
| return dev_err_probe(dev, err, "Failed to init bgpio\n"); |
| |
| |
| err = devm_gpiochip_add_data(dev, &hdp->gpio_chip, hdp); |
| if (err) |
| return dev_err_probe(dev, err, "Failed to add gpiochip\n"); |
| |
| writel_relaxed(HDP_CTRL_ENABLE, hdp->base + HDP_CTRL); |
| |
| version = readl_relaxed(hdp->base + HDP_VERR); |
| dev_dbg(dev, "STM32 HDP version %u.%u initialized\n", version >> 4, version & 0x0f); |
| |
| return 0; |
| } |
| |
| static void stm32_hdp_remove(struct platform_device *pdev) |
| { |
| struct stm32_hdp *hdp = platform_get_drvdata(pdev); |
| |
| writel_relaxed(HDP_CTRL_DISABLE, hdp->base + HDP_CTRL); |
| } |
| |
| static int stm32_hdp_suspend(struct device *dev) |
| { |
| struct stm32_hdp *hdp = dev_get_drvdata(dev); |
| |
| hdp->gposet_conf = readl_relaxed(hdp->base + HDP_GPOSET); |
| |
| pinctrl_pm_select_sleep_state(dev); |
| |
| clk_disable_unprepare(hdp->clk); |
| |
| return 0; |
| } |
| |
| static int stm32_hdp_resume(struct device *dev) |
| { |
| struct stm32_hdp *hdp = dev_get_drvdata(dev); |
| int err; |
| |
| err = clk_prepare_enable(hdp->clk); |
| if (err) { |
| dev_err(dev, "Failed to prepare_enable clk (%d)\n", err); |
| return err; |
| } |
| |
| writel_relaxed(HDP_CTRL_ENABLE, hdp->base + HDP_CTRL); |
| writel_relaxed(hdp->gposet_conf, hdp->base + HDP_GPOSET); |
| writel_relaxed(hdp->mux_conf, hdp->base + HDP_MUX); |
| |
| pinctrl_pm_select_default_state(dev); |
| |
| return 0; |
| } |
| |
| static DEFINE_SIMPLE_DEV_PM_OPS(stm32_hdp_pm_ops, stm32_hdp_suspend, stm32_hdp_resume); |
| |
| static struct platform_driver stm32_hdp_driver = { |
| .probe = stm32_hdp_probe, |
| .remove = stm32_hdp_remove, |
| .driver = { |
| .name = DRIVER_NAME, |
| .pm = pm_sleep_ptr(&stm32_hdp_pm_ops), |
| .of_match_table = stm32_hdp_of_match, |
| } |
| }; |
| |
| module_platform_driver(stm32_hdp_driver); |
| |
| MODULE_AUTHOR("Clément Le Goffic"); |
| MODULE_DESCRIPTION("STMicroelectronics STM32 Hardware Debug Port driver"); |
| MODULE_LICENSE("GPL"); |