xref: /openbmc/linux/drivers/hwtracing/intel_th/pti.c (revision d9962f6f)
150352fa7SAlexander Shishkin // SPDX-License-Identifier: GPL-2.0
214cdbf04SAlexander Shishkin /*
314cdbf04SAlexander Shishkin  * Intel(R) Trace Hub PTI output driver
414cdbf04SAlexander Shishkin  *
5f77d22bcSAlexander Shishkin  * Copyright (C) 2014-2016 Intel Corporation.
614cdbf04SAlexander Shishkin  */
714cdbf04SAlexander Shishkin 
814cdbf04SAlexander Shishkin #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
914cdbf04SAlexander Shishkin 
1014cdbf04SAlexander Shishkin #include <linux/types.h>
1114cdbf04SAlexander Shishkin #include <linux/module.h>
1214cdbf04SAlexander Shishkin #include <linux/device.h>
1314cdbf04SAlexander Shishkin #include <linux/sizes.h>
1414cdbf04SAlexander Shishkin #include <linux/printk.h>
1514cdbf04SAlexander Shishkin #include <linux/slab.h>
1614cdbf04SAlexander Shishkin #include <linux/mm.h>
1714cdbf04SAlexander Shishkin #include <linux/io.h>
1814cdbf04SAlexander Shishkin 
1914cdbf04SAlexander Shishkin #include "intel_th.h"
2014cdbf04SAlexander Shishkin #include "pti.h"
2114cdbf04SAlexander Shishkin 
2214cdbf04SAlexander Shishkin struct pti_device {
2314cdbf04SAlexander Shishkin 	void __iomem		*base;
2414cdbf04SAlexander Shishkin 	struct intel_th_device	*thdev;
2514cdbf04SAlexander Shishkin 	unsigned int		mode;
2614cdbf04SAlexander Shishkin 	unsigned int		freeclk;
2714cdbf04SAlexander Shishkin 	unsigned int		clkdiv;
2814cdbf04SAlexander Shishkin 	unsigned int		patgen;
29f77d22bcSAlexander Shishkin 	unsigned int		lpp_dest_mask;
30f77d22bcSAlexander Shishkin 	unsigned int		lpp_dest;
3114cdbf04SAlexander Shishkin };
3214cdbf04SAlexander Shishkin 
3314cdbf04SAlexander Shishkin /* map PTI widths to MODE settings of PTI_CTL register */
3414cdbf04SAlexander Shishkin static const unsigned int pti_mode[] = {
3514cdbf04SAlexander Shishkin 	0, 4, 8, 0, 12, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,
3614cdbf04SAlexander Shishkin };
3714cdbf04SAlexander Shishkin 
pti_width_mode(unsigned int width)3814cdbf04SAlexander Shishkin static int pti_width_mode(unsigned int width)
3914cdbf04SAlexander Shishkin {
4014cdbf04SAlexander Shishkin 	int i;
4114cdbf04SAlexander Shishkin 
4214cdbf04SAlexander Shishkin 	for (i = 0; i < ARRAY_SIZE(pti_mode); i++)
4314cdbf04SAlexander Shishkin 		if (pti_mode[i] == width)
4414cdbf04SAlexander Shishkin 			return i;
4514cdbf04SAlexander Shishkin 
4614cdbf04SAlexander Shishkin 	return -EINVAL;
4714cdbf04SAlexander Shishkin }
4814cdbf04SAlexander Shishkin 
mode_show(struct device * dev,struct device_attribute * attr,char * buf)4914cdbf04SAlexander Shishkin static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
5014cdbf04SAlexander Shishkin 			 char *buf)
5114cdbf04SAlexander Shishkin {
5214cdbf04SAlexander Shishkin 	struct pti_device *pti = dev_get_drvdata(dev);
5314cdbf04SAlexander Shishkin 
5414cdbf04SAlexander Shishkin 	return scnprintf(buf, PAGE_SIZE, "%d\n", pti_mode[pti->mode]);
5514cdbf04SAlexander Shishkin }
5614cdbf04SAlexander Shishkin 
mode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)5714cdbf04SAlexander Shishkin static ssize_t mode_store(struct device *dev, struct device_attribute *attr,
5814cdbf04SAlexander Shishkin 			  const char *buf, size_t size)
5914cdbf04SAlexander Shishkin {
6014cdbf04SAlexander Shishkin 	struct pti_device *pti = dev_get_drvdata(dev);
6114cdbf04SAlexander Shishkin 	unsigned long val;
6214cdbf04SAlexander Shishkin 	int ret;
6314cdbf04SAlexander Shishkin 
6414cdbf04SAlexander Shishkin 	ret = kstrtoul(buf, 10, &val);
6514cdbf04SAlexander Shishkin 	if (ret)
6614cdbf04SAlexander Shishkin 		return ret;
6714cdbf04SAlexander Shishkin 
6814cdbf04SAlexander Shishkin 	ret = pti_width_mode(val);
6914cdbf04SAlexander Shishkin 	if (ret < 0)
7014cdbf04SAlexander Shishkin 		return ret;
7114cdbf04SAlexander Shishkin 
7214cdbf04SAlexander Shishkin 	pti->mode = ret;
7314cdbf04SAlexander Shishkin 
7414cdbf04SAlexander Shishkin 	return size;
7514cdbf04SAlexander Shishkin }
7614cdbf04SAlexander Shishkin 
7714cdbf04SAlexander Shishkin static DEVICE_ATTR_RW(mode);
7814cdbf04SAlexander Shishkin 
7914cdbf04SAlexander Shishkin static ssize_t
freerunning_clock_show(struct device * dev,struct device_attribute * attr,char * buf)8014cdbf04SAlexander Shishkin freerunning_clock_show(struct device *dev, struct device_attribute *attr,
8114cdbf04SAlexander Shishkin 		       char *buf)
8214cdbf04SAlexander Shishkin {
8314cdbf04SAlexander Shishkin 	struct pti_device *pti = dev_get_drvdata(dev);
8414cdbf04SAlexander Shishkin 
8514cdbf04SAlexander Shishkin 	return scnprintf(buf, PAGE_SIZE, "%d\n", pti->freeclk);
8614cdbf04SAlexander Shishkin }
8714cdbf04SAlexander Shishkin 
8814cdbf04SAlexander Shishkin static ssize_t
freerunning_clock_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)8914cdbf04SAlexander Shishkin freerunning_clock_store(struct device *dev, struct device_attribute *attr,
9014cdbf04SAlexander Shishkin 			const char *buf, size_t size)
9114cdbf04SAlexander Shishkin {
9214cdbf04SAlexander Shishkin 	struct pti_device *pti = dev_get_drvdata(dev);
9314cdbf04SAlexander Shishkin 	unsigned long val;
9414cdbf04SAlexander Shishkin 	int ret;
9514cdbf04SAlexander Shishkin 
9614cdbf04SAlexander Shishkin 	ret = kstrtoul(buf, 10, &val);
9714cdbf04SAlexander Shishkin 	if (ret)
9814cdbf04SAlexander Shishkin 		return ret;
9914cdbf04SAlexander Shishkin 
10014cdbf04SAlexander Shishkin 	pti->freeclk = !!val;
10114cdbf04SAlexander Shishkin 
10214cdbf04SAlexander Shishkin 	return size;
10314cdbf04SAlexander Shishkin }
10414cdbf04SAlexander Shishkin 
10514cdbf04SAlexander Shishkin static DEVICE_ATTR_RW(freerunning_clock);
10614cdbf04SAlexander Shishkin 
10714cdbf04SAlexander Shishkin static ssize_t
clock_divider_show(struct device * dev,struct device_attribute * attr,char * buf)10814cdbf04SAlexander Shishkin clock_divider_show(struct device *dev, struct device_attribute *attr,
10914cdbf04SAlexander Shishkin 		   char *buf)
11014cdbf04SAlexander Shishkin {
11114cdbf04SAlexander Shishkin 	struct pti_device *pti = dev_get_drvdata(dev);
11214cdbf04SAlexander Shishkin 
11314cdbf04SAlexander Shishkin 	return scnprintf(buf, PAGE_SIZE, "%d\n", 1u << pti->clkdiv);
11414cdbf04SAlexander Shishkin }
11514cdbf04SAlexander Shishkin 
11614cdbf04SAlexander Shishkin static ssize_t
clock_divider_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)11714cdbf04SAlexander Shishkin clock_divider_store(struct device *dev, struct device_attribute *attr,
11814cdbf04SAlexander Shishkin 		    const char *buf, size_t size)
11914cdbf04SAlexander Shishkin {
12014cdbf04SAlexander Shishkin 	struct pti_device *pti = dev_get_drvdata(dev);
12114cdbf04SAlexander Shishkin 	unsigned long val;
12214cdbf04SAlexander Shishkin 	int ret;
12314cdbf04SAlexander Shishkin 
12414cdbf04SAlexander Shishkin 	ret = kstrtoul(buf, 10, &val);
12514cdbf04SAlexander Shishkin 	if (ret)
12614cdbf04SAlexander Shishkin 		return ret;
12714cdbf04SAlexander Shishkin 
12814cdbf04SAlexander Shishkin 	if (!is_power_of_2(val) || val > 8 || !val)
12914cdbf04SAlexander Shishkin 		return -EINVAL;
13014cdbf04SAlexander Shishkin 
13114cdbf04SAlexander Shishkin 	pti->clkdiv = val;
13214cdbf04SAlexander Shishkin 
13314cdbf04SAlexander Shishkin 	return size;
13414cdbf04SAlexander Shishkin }
13514cdbf04SAlexander Shishkin 
13614cdbf04SAlexander Shishkin static DEVICE_ATTR_RW(clock_divider);
13714cdbf04SAlexander Shishkin 
13814cdbf04SAlexander Shishkin static struct attribute *pti_output_attrs[] = {
13914cdbf04SAlexander Shishkin 	&dev_attr_mode.attr,
14014cdbf04SAlexander Shishkin 	&dev_attr_freerunning_clock.attr,
14114cdbf04SAlexander Shishkin 	&dev_attr_clock_divider.attr,
14214cdbf04SAlexander Shishkin 	NULL,
14314cdbf04SAlexander Shishkin };
14414cdbf04SAlexander Shishkin 
145*d9962f6fSRikard Falkeborn static const struct attribute_group pti_output_group = {
14614cdbf04SAlexander Shishkin 	.attrs	= pti_output_attrs,
14714cdbf04SAlexander Shishkin };
14814cdbf04SAlexander Shishkin 
intel_th_pti_activate(struct intel_th_device * thdev)14914cdbf04SAlexander Shishkin static int intel_th_pti_activate(struct intel_th_device *thdev)
15014cdbf04SAlexander Shishkin {
15114cdbf04SAlexander Shishkin 	struct pti_device *pti = dev_get_drvdata(&thdev->dev);
15214cdbf04SAlexander Shishkin 	u32 ctl = PTI_EN;
15314cdbf04SAlexander Shishkin 
15414cdbf04SAlexander Shishkin 	if (pti->patgen)
15514cdbf04SAlexander Shishkin 		ctl |= pti->patgen << __ffs(PTI_PATGENMODE);
15614cdbf04SAlexander Shishkin 	if (pti->freeclk)
15714cdbf04SAlexander Shishkin 		ctl |= PTI_FCEN;
15814cdbf04SAlexander Shishkin 	ctl |= pti->mode << __ffs(PTI_MODE);
15914cdbf04SAlexander Shishkin 	ctl |= pti->clkdiv << __ffs(PTI_CLKDIV);
160f77d22bcSAlexander Shishkin 	ctl |= pti->lpp_dest << __ffs(LPP_DEST);
16114cdbf04SAlexander Shishkin 
16214cdbf04SAlexander Shishkin 	iowrite32(ctl, pti->base + REG_PTI_CTL);
16314cdbf04SAlexander Shishkin 
16414cdbf04SAlexander Shishkin 	intel_th_trace_enable(thdev);
16514cdbf04SAlexander Shishkin 
16614cdbf04SAlexander Shishkin 	return 0;
16714cdbf04SAlexander Shishkin }
16814cdbf04SAlexander Shishkin 
intel_th_pti_deactivate(struct intel_th_device * thdev)16914cdbf04SAlexander Shishkin static void intel_th_pti_deactivate(struct intel_th_device *thdev)
17014cdbf04SAlexander Shishkin {
17114cdbf04SAlexander Shishkin 	struct pti_device *pti = dev_get_drvdata(&thdev->dev);
17214cdbf04SAlexander Shishkin 
17314cdbf04SAlexander Shishkin 	intel_th_trace_disable(thdev);
17414cdbf04SAlexander Shishkin 
17514cdbf04SAlexander Shishkin 	iowrite32(0, pti->base + REG_PTI_CTL);
17614cdbf04SAlexander Shishkin }
17714cdbf04SAlexander Shishkin 
read_hw_config(struct pti_device * pti)17814cdbf04SAlexander Shishkin static void read_hw_config(struct pti_device *pti)
17914cdbf04SAlexander Shishkin {
18014cdbf04SAlexander Shishkin 	u32 ctl = ioread32(pti->base + REG_PTI_CTL);
18114cdbf04SAlexander Shishkin 
18214cdbf04SAlexander Shishkin 	pti->mode	= (ctl & PTI_MODE) >> __ffs(PTI_MODE);
18314cdbf04SAlexander Shishkin 	pti->clkdiv	= (ctl & PTI_CLKDIV) >> __ffs(PTI_CLKDIV);
18414cdbf04SAlexander Shishkin 	pti->freeclk	= !!(ctl & PTI_FCEN);
18514cdbf04SAlexander Shishkin 
18614cdbf04SAlexander Shishkin 	if (!pti_mode[pti->mode])
18714cdbf04SAlexander Shishkin 		pti->mode = pti_width_mode(4);
18814cdbf04SAlexander Shishkin 	if (!pti->clkdiv)
18914cdbf04SAlexander Shishkin 		pti->clkdiv = 1;
190f77d22bcSAlexander Shishkin 
191f77d22bcSAlexander Shishkin 	if (pti->thdev->output.type == GTH_LPP) {
192f77d22bcSAlexander Shishkin 		if (ctl & LPP_PTIPRESENT)
193f77d22bcSAlexander Shishkin 			pti->lpp_dest_mask |= LPP_DEST_PTI;
194f77d22bcSAlexander Shishkin 		if (ctl & LPP_BSSBPRESENT)
195f77d22bcSAlexander Shishkin 			pti->lpp_dest_mask |= LPP_DEST_EXI;
196f77d22bcSAlexander Shishkin 		if (ctl & LPP_DEST)
197f77d22bcSAlexander Shishkin 			pti->lpp_dest = 1;
198f77d22bcSAlexander Shishkin 	}
19914cdbf04SAlexander Shishkin }
20014cdbf04SAlexander Shishkin 
intel_th_pti_probe(struct intel_th_device * thdev)20114cdbf04SAlexander Shishkin static int intel_th_pti_probe(struct intel_th_device *thdev)
20214cdbf04SAlexander Shishkin {
20314cdbf04SAlexander Shishkin 	struct device *dev = &thdev->dev;
20414cdbf04SAlexander Shishkin 	struct resource *res;
20514cdbf04SAlexander Shishkin 	struct pti_device *pti;
20614cdbf04SAlexander Shishkin 	void __iomem *base;
20714cdbf04SAlexander Shishkin 
20814cdbf04SAlexander Shishkin 	res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0);
20914cdbf04SAlexander Shishkin 	if (!res)
21014cdbf04SAlexander Shishkin 		return -ENODEV;
21114cdbf04SAlexander Shishkin 
21214cdbf04SAlexander Shishkin 	base = devm_ioremap(dev, res->start, resource_size(res));
21373061da0SDan Carpenter 	if (!base)
21473061da0SDan Carpenter 		return -ENOMEM;
21514cdbf04SAlexander Shishkin 
21614cdbf04SAlexander Shishkin 	pti = devm_kzalloc(dev, sizeof(*pti), GFP_KERNEL);
21714cdbf04SAlexander Shishkin 	if (!pti)
21814cdbf04SAlexander Shishkin 		return -ENOMEM;
21914cdbf04SAlexander Shishkin 
22014cdbf04SAlexander Shishkin 	pti->thdev = thdev;
22114cdbf04SAlexander Shishkin 	pti->base = base;
22214cdbf04SAlexander Shishkin 
22314cdbf04SAlexander Shishkin 	read_hw_config(pti);
22414cdbf04SAlexander Shishkin 
22514cdbf04SAlexander Shishkin 	dev_set_drvdata(dev, pti);
22614cdbf04SAlexander Shishkin 
22714cdbf04SAlexander Shishkin 	return 0;
22814cdbf04SAlexander Shishkin }
22914cdbf04SAlexander Shishkin 
intel_th_pti_remove(struct intel_th_device * thdev)23014cdbf04SAlexander Shishkin static void intel_th_pti_remove(struct intel_th_device *thdev)
23114cdbf04SAlexander Shishkin {
23214cdbf04SAlexander Shishkin }
23314cdbf04SAlexander Shishkin 
23414cdbf04SAlexander Shishkin static struct intel_th_driver intel_th_pti_driver = {
23514cdbf04SAlexander Shishkin 	.probe	= intel_th_pti_probe,
23614cdbf04SAlexander Shishkin 	.remove	= intel_th_pti_remove,
23714cdbf04SAlexander Shishkin 	.activate	= intel_th_pti_activate,
23814cdbf04SAlexander Shishkin 	.deactivate	= intel_th_pti_deactivate,
239e8644e4cSAlexander Shishkin 	.attr_group	= &pti_output_group,
24014cdbf04SAlexander Shishkin 	.driver	= {
24114cdbf04SAlexander Shishkin 		.name	= "pti",
24214cdbf04SAlexander Shishkin 		.owner	= THIS_MODULE,
24314cdbf04SAlexander Shishkin 	},
24414cdbf04SAlexander Shishkin };
24514cdbf04SAlexander Shishkin 
246f77d22bcSAlexander Shishkin static const char * const lpp_dest_str[] = { "pti", "exi" };
247f77d22bcSAlexander Shishkin 
lpp_dest_show(struct device * dev,struct device_attribute * attr,char * buf)248f77d22bcSAlexander Shishkin static ssize_t lpp_dest_show(struct device *dev, struct device_attribute *attr,
249f77d22bcSAlexander Shishkin 			     char *buf)
250f77d22bcSAlexander Shishkin {
251f77d22bcSAlexander Shishkin 	struct pti_device *pti = dev_get_drvdata(dev);
252f77d22bcSAlexander Shishkin 	ssize_t ret = 0;
253f77d22bcSAlexander Shishkin 	int i;
254f77d22bcSAlexander Shishkin 
255f77d22bcSAlexander Shishkin 	for (i = ARRAY_SIZE(lpp_dest_str) - 1; i >= 0; i--) {
256f77d22bcSAlexander Shishkin 		const char *fmt = pti->lpp_dest == i ? "[%s] " : "%s ";
257f77d22bcSAlexander Shishkin 
258f77d22bcSAlexander Shishkin 		if (!(pti->lpp_dest_mask & BIT(i)))
259f77d22bcSAlexander Shishkin 			continue;
260f77d22bcSAlexander Shishkin 
261f77d22bcSAlexander Shishkin 		ret += scnprintf(buf + ret, PAGE_SIZE - ret,
262f77d22bcSAlexander Shishkin 				 fmt, lpp_dest_str[i]);
263f77d22bcSAlexander Shishkin 	}
264f77d22bcSAlexander Shishkin 
265f77d22bcSAlexander Shishkin 	if (ret)
266f77d22bcSAlexander Shishkin 		buf[ret - 1] = '\n';
267f77d22bcSAlexander Shishkin 
268f77d22bcSAlexander Shishkin 	return ret;
269f77d22bcSAlexander Shishkin }
270f77d22bcSAlexander Shishkin 
lpp_dest_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)271f77d22bcSAlexander Shishkin static ssize_t lpp_dest_store(struct device *dev, struct device_attribute *attr,
272f77d22bcSAlexander Shishkin 			      const char *buf, size_t size)
273f77d22bcSAlexander Shishkin {
274f77d22bcSAlexander Shishkin 	struct pti_device *pti = dev_get_drvdata(dev);
275f77d22bcSAlexander Shishkin 	int i;
276f77d22bcSAlexander Shishkin 
2771d2ef028SAndy Shevchenko 	i = sysfs_match_string(lpp_dest_str, buf);
2781d2ef028SAndy Shevchenko 	if (i < 0)
2791d2ef028SAndy Shevchenko 		return i;
280f77d22bcSAlexander Shishkin 
2811d2ef028SAndy Shevchenko 	if (!(pti->lpp_dest_mask & BIT(i)))
2821d2ef028SAndy Shevchenko 		return -EINVAL;
2831d2ef028SAndy Shevchenko 
284f77d22bcSAlexander Shishkin 	pti->lpp_dest = i;
2851d2ef028SAndy Shevchenko 	return size;
286f77d22bcSAlexander Shishkin }
287f77d22bcSAlexander Shishkin 
288f77d22bcSAlexander Shishkin static DEVICE_ATTR_RW(lpp_dest);
289f77d22bcSAlexander Shishkin 
290f77d22bcSAlexander Shishkin static struct attribute *lpp_output_attrs[] = {
291f77d22bcSAlexander Shishkin 	&dev_attr_mode.attr,
292f77d22bcSAlexander Shishkin 	&dev_attr_freerunning_clock.attr,
293f77d22bcSAlexander Shishkin 	&dev_attr_clock_divider.attr,
294f77d22bcSAlexander Shishkin 	&dev_attr_lpp_dest.attr,
295f77d22bcSAlexander Shishkin 	NULL,
296f77d22bcSAlexander Shishkin };
297f77d22bcSAlexander Shishkin 
298*d9962f6fSRikard Falkeborn static const struct attribute_group lpp_output_group = {
299f77d22bcSAlexander Shishkin 	.attrs	= lpp_output_attrs,
300f77d22bcSAlexander Shishkin };
301f77d22bcSAlexander Shishkin 
302f77d22bcSAlexander Shishkin static struct intel_th_driver intel_th_lpp_driver = {
303f77d22bcSAlexander Shishkin 	.probe		= intel_th_pti_probe,
304f77d22bcSAlexander Shishkin 	.remove		= intel_th_pti_remove,
305f77d22bcSAlexander Shishkin 	.activate	= intel_th_pti_activate,
306f77d22bcSAlexander Shishkin 	.deactivate	= intel_th_pti_deactivate,
307f77d22bcSAlexander Shishkin 	.attr_group	= &lpp_output_group,
308f77d22bcSAlexander Shishkin 	.driver	= {
309f77d22bcSAlexander Shishkin 		.name	= "lpp",
310f77d22bcSAlexander Shishkin 		.owner	= THIS_MODULE,
311f77d22bcSAlexander Shishkin 	},
312f77d22bcSAlexander Shishkin };
313f77d22bcSAlexander Shishkin 
intel_th_pti_lpp_init(void)314f77d22bcSAlexander Shishkin static int __init intel_th_pti_lpp_init(void)
315f77d22bcSAlexander Shishkin {
316f77d22bcSAlexander Shishkin 	int err;
317f77d22bcSAlexander Shishkin 
318f77d22bcSAlexander Shishkin 	err = intel_th_driver_register(&intel_th_pti_driver);
319f77d22bcSAlexander Shishkin 	if (err)
320f77d22bcSAlexander Shishkin 		return err;
321f77d22bcSAlexander Shishkin 
322f77d22bcSAlexander Shishkin 	err = intel_th_driver_register(&intel_th_lpp_driver);
323f77d22bcSAlexander Shishkin 	if (err) {
324f77d22bcSAlexander Shishkin 		intel_th_driver_unregister(&intel_th_pti_driver);
325f77d22bcSAlexander Shishkin 		return err;
326f77d22bcSAlexander Shishkin 	}
327f77d22bcSAlexander Shishkin 
328f77d22bcSAlexander Shishkin 	return 0;
329f77d22bcSAlexander Shishkin }
330f77d22bcSAlexander Shishkin 
331f77d22bcSAlexander Shishkin module_init(intel_th_pti_lpp_init);
332f77d22bcSAlexander Shishkin 
intel_th_pti_lpp_exit(void)333f77d22bcSAlexander Shishkin static void __exit intel_th_pti_lpp_exit(void)
334f77d22bcSAlexander Shishkin {
335f77d22bcSAlexander Shishkin 	intel_th_driver_unregister(&intel_th_pti_driver);
336f77d22bcSAlexander Shishkin 	intel_th_driver_unregister(&intel_th_lpp_driver);
337f77d22bcSAlexander Shishkin }
338f77d22bcSAlexander Shishkin 
339f77d22bcSAlexander Shishkin module_exit(intel_th_pti_lpp_exit);
34014cdbf04SAlexander Shishkin 
34114cdbf04SAlexander Shishkin MODULE_LICENSE("GPL v2");
342f77d22bcSAlexander Shishkin MODULE_DESCRIPTION("Intel(R) Trace Hub PTI/LPP output driver");
34314cdbf04SAlexander Shishkin MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
344