Contributors: 1
Author Tokens Token Proportion Commits Commit Proportion
Clément Le Goffic 2162 100.00% 1 100.00%
Total 2162 1


// 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");