diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-08-02 12:07:09 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-08-02 12:07:09 -0700 |
commit | 186f3edfdd41f2ae87fc40a9ccba52a3bf930994 (patch) | |
tree | a429b2877cbd9651e3e4926f62bc53bbed36ac63 /drivers/pinctrl/stm32/pinctrl-stm32-hdp.c | |
parent | eacf91b0c78a7113844830ed65ebf543eb9052c5 (diff) | |
parent | a3fe1324c3c5c292ec79bd756497c1c44ff247d2 (diff) |
Merge tag 'pinctrl-v6.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrlHEADmaster
Pull pin control updates from Linus Walleij:
"Nothing stands out, apart from maybe the interesting Eswin EIC7700, a
RISC-V SoC I've never seen before.
Core changes:
- Open code PINCTRL_FUNCTION_DESC() instead of defining a complex
macro only used in one place
- Add pinmux_generic_add_pinfunction() helper and use this in a few
drivers
New drivers:
- Amlogic S7, S7D and S6 pin control support
- Eswin EIC7700 pin control support
- Qualcomm PMIV0104, PM7550 and Milos pin control support
Because of unhelpful numbering schemes, the Qualcomm driver now
needs to start to rely on SoC codenames
- STM32 HDP pin control support
- Mediatek MT8189 pin control support
Improvements:
- Switch remaining pin control drivers over to the new GPIO set
callback that provides a return value
- Support RSVD (reserved) pins in the STM32 driver
- Move many fixed assignments over to pinctrl_desc definitions
- Handle multiple TLMM regions in the Qualcomm driver"
* tag 'pinctrl-v6.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (105 commits)
pinctrl: mediatek: Add pinctrl driver for mt8189
dt-bindings: pinctrl: mediatek: Add support for mt8189
pinctrl: aspeed-g6: Add PCIe RC PERST pin group
pinctrl: ingenic: use pinmux_generic_add_pinfunction()
pinctrl: keembay: use pinmux_generic_add_pinfunction()
pinctrl: mediatek: moore: use pinmux_generic_add_pinfunction()
pinctrl: airoha: use pinmux_generic_add_pinfunction()
pinctrl: equilibrium: use pinmux_generic_add_pinfunction()
pinctrl: provide pinmux_generic_add_pinfunction()
pinctrl: pinmux: open-code PINCTRL_FUNCTION_DESC()
pinctrl: ma35: use new GPIO line value setter callbacks
MAINTAINERS: add Clément Le Goffic as STM32 HDP maintainer
pinctrl: stm32: Introduce HDP driver
dt-bindings: pinctrl: stm32: Introduce HDP
pinctrl: qcom: Add Milos pinctrl driver
dt-bindings: pinctrl: document the Milos Top Level Mode Multiplexer
pinctrl: qcom: spmi: Add PM7550
dt-bindings: pinctrl: qcom,pmic-gpio: Add PM7550 support
pinctrl: qcom: spmi: Add PMIV0104
dt-bindings: pinctrl: qcom,pmic-gpio: Add PMIV0104 support
...
Diffstat (limited to 'drivers/pinctrl/stm32/pinctrl-stm32-hdp.c')
-rw-r--r-- | drivers/pinctrl/stm32/pinctrl-stm32-hdp.c | 720 |
1 files changed, 720 insertions, 0 deletions
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c b/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c new file mode 100644 index 000000000000..e91442eb566b --- /dev/null +++ b/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c @@ -0,0 +1,720 @@ +// 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"); |