xref: /linux/drivers/misc/mei/pci-txe.c (revision d2d56faebaed1dd9bc011fcceed7df6b1bea8fac)
1795536acSTomas Winkler /*
2795536acSTomas Winkler  *
3795536acSTomas Winkler  * Intel Management Engine Interface (Intel MEI) Linux driver
4795536acSTomas Winkler  * Copyright (c) 2013-2014, Intel Corporation.
5795536acSTomas Winkler  *
6795536acSTomas Winkler  * This program is free software; you can redistribute it and/or modify it
7795536acSTomas Winkler  * under the terms and conditions of the GNU General Public License,
8795536acSTomas Winkler  * version 2, as published by the Free Software Foundation.
9795536acSTomas Winkler  *
10795536acSTomas Winkler  * This program is distributed in the hope it will be useful, but WITHOUT
11795536acSTomas Winkler  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12795536acSTomas Winkler  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13795536acSTomas Winkler  * more details.
14795536acSTomas Winkler  *
15795536acSTomas Winkler  */
16795536acSTomas Winkler 
17795536acSTomas Winkler #include <linux/module.h>
18795536acSTomas Winkler #include <linux/kernel.h>
19795536acSTomas Winkler #include <linux/device.h>
20795536acSTomas Winkler #include <linux/fs.h>
21795536acSTomas Winkler #include <linux/errno.h>
22795536acSTomas Winkler #include <linux/types.h>
23795536acSTomas Winkler #include <linux/pci.h>
24795536acSTomas Winkler #include <linux/init.h>
25795536acSTomas Winkler #include <linux/sched.h>
26795536acSTomas Winkler #include <linux/uuid.h>
27795536acSTomas Winkler #include <linux/jiffies.h>
28795536acSTomas Winkler #include <linux/interrupt.h>
29795536acSTomas Winkler #include <linux/workqueue.h>
30cfe5ab85SAlexander Usyskin #include <linux/pm_runtime.h>
31795536acSTomas Winkler 
32795536acSTomas Winkler #include <linux/mei.h>
33795536acSTomas Winkler 
34795536acSTomas Winkler 
35795536acSTomas Winkler #include "mei_dev.h"
36795536acSTomas Winkler #include "hw-txe.h"
37795536acSTomas Winkler 
38a05f8f86STomas Winkler static const struct pci_device_id mei_txe_pci_tbl[] = {
39795536acSTomas Winkler 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0F18)}, /* Baytrail */
40795536acSTomas Winkler 	{0, }
41795536acSTomas Winkler };
42795536acSTomas Winkler MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl);
43795536acSTomas Winkler 
44*d2d56faeSAlexander Usyskin #ifdef CONFIG_PM_RUNTIME
45*d2d56faeSAlexander Usyskin static inline void mei_txe_set_pm_domain(struct mei_device *dev);
46*d2d56faeSAlexander Usyskin static inline void mei_txe_unset_pm_domain(struct mei_device *dev);
47*d2d56faeSAlexander Usyskin #else
48*d2d56faeSAlexander Usyskin static inline void mei_txe_set_pm_domain(struct mei_device *dev) {}
49*d2d56faeSAlexander Usyskin static inline void mei_txe_unset_pm_domain(struct mei_device *dev) {}
50*d2d56faeSAlexander Usyskin #endif /* CONFIG_PM_RUNTIME */
51795536acSTomas Winkler 
52795536acSTomas Winkler static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw)
53795536acSTomas Winkler {
54795536acSTomas Winkler 	int i;
55795536acSTomas Winkler 	for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
56795536acSTomas Winkler 		if (hw->mem_addr[i]) {
57795536acSTomas Winkler 			pci_iounmap(pdev, hw->mem_addr[i]);
58795536acSTomas Winkler 			hw->mem_addr[i] = NULL;
59795536acSTomas Winkler 		}
60795536acSTomas Winkler 	}
61795536acSTomas Winkler }
62795536acSTomas Winkler /**
63795536acSTomas Winkler  * mei_probe - Device Initialization Routine
64795536acSTomas Winkler  *
65795536acSTomas Winkler  * @pdev: PCI device structure
66795536acSTomas Winkler  * @ent: entry in mei_txe_pci_tbl
67795536acSTomas Winkler  *
68795536acSTomas Winkler  * returns 0 on success, <0 on failure.
69795536acSTomas Winkler  */
70795536acSTomas Winkler static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
71795536acSTomas Winkler {
72795536acSTomas Winkler 	struct mei_device *dev;
73795536acSTomas Winkler 	struct mei_txe_hw *hw;
74795536acSTomas Winkler 	int err;
75795536acSTomas Winkler 	int i;
76795536acSTomas Winkler 
77795536acSTomas Winkler 	/* enable pci dev */
78795536acSTomas Winkler 	err = pci_enable_device(pdev);
79795536acSTomas Winkler 	if (err) {
80795536acSTomas Winkler 		dev_err(&pdev->dev, "failed to enable pci device.\n");
81795536acSTomas Winkler 		goto end;
82795536acSTomas Winkler 	}
83795536acSTomas Winkler 	/* set PCI host mastering  */
84795536acSTomas Winkler 	pci_set_master(pdev);
85795536acSTomas Winkler 	/* pci request regions for mei driver */
86795536acSTomas Winkler 	err = pci_request_regions(pdev, KBUILD_MODNAME);
87795536acSTomas Winkler 	if (err) {
88795536acSTomas Winkler 		dev_err(&pdev->dev, "failed to get pci regions.\n");
89795536acSTomas Winkler 		goto disable_device;
90795536acSTomas Winkler 	}
91795536acSTomas Winkler 
92795536acSTomas Winkler 	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
93795536acSTomas Winkler 	if (err) {
94795536acSTomas Winkler 		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
95795536acSTomas Winkler 		if (err) {
96795536acSTomas Winkler 			dev_err(&pdev->dev, "No suitable DMA available.\n");
97795536acSTomas Winkler 			goto release_regions;
98795536acSTomas Winkler 		}
99795536acSTomas Winkler 	}
100795536acSTomas Winkler 
101795536acSTomas Winkler 	/* allocates and initializes the mei dev structure */
102795536acSTomas Winkler 	dev = mei_txe_dev_init(pdev);
103795536acSTomas Winkler 	if (!dev) {
104795536acSTomas Winkler 		err = -ENOMEM;
105795536acSTomas Winkler 		goto release_regions;
106795536acSTomas Winkler 	}
107795536acSTomas Winkler 	hw = to_txe_hw(dev);
108795536acSTomas Winkler 
109795536acSTomas Winkler 	/* mapping  IO device memory */
110795536acSTomas Winkler 	for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
111795536acSTomas Winkler 		hw->mem_addr[i] = pci_iomap(pdev, i, 0);
112795536acSTomas Winkler 		if (!hw->mem_addr[i]) {
113795536acSTomas Winkler 			dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
114795536acSTomas Winkler 			err = -ENOMEM;
115795536acSTomas Winkler 			goto free_device;
116795536acSTomas Winkler 		}
117795536acSTomas Winkler 	}
118795536acSTomas Winkler 
119795536acSTomas Winkler 
120795536acSTomas Winkler 	pci_enable_msi(pdev);
121795536acSTomas Winkler 
122795536acSTomas Winkler 	/* clear spurious interrupts */
123795536acSTomas Winkler 	mei_clear_interrupts(dev);
124795536acSTomas Winkler 
125795536acSTomas Winkler 	/* request and enable interrupt  */
126795536acSTomas Winkler 	if (pci_dev_msi_enabled(pdev))
127795536acSTomas Winkler 		err = request_threaded_irq(pdev->irq,
128795536acSTomas Winkler 			NULL,
129795536acSTomas Winkler 			mei_txe_irq_thread_handler,
130795536acSTomas Winkler 			IRQF_ONESHOT, KBUILD_MODNAME, dev);
131795536acSTomas Winkler 	else
132795536acSTomas Winkler 		err = request_threaded_irq(pdev->irq,
133795536acSTomas Winkler 			mei_txe_irq_quick_handler,
134795536acSTomas Winkler 			mei_txe_irq_thread_handler,
135795536acSTomas Winkler 			IRQF_SHARED, KBUILD_MODNAME, dev);
136795536acSTomas Winkler 	if (err) {
137795536acSTomas Winkler 		dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n",
138795536acSTomas Winkler 			pdev->irq);
139795536acSTomas Winkler 		goto free_device;
140795536acSTomas Winkler 	}
141795536acSTomas Winkler 
142795536acSTomas Winkler 	if (mei_start(dev)) {
143795536acSTomas Winkler 		dev_err(&pdev->dev, "init hw failure.\n");
144795536acSTomas Winkler 		err = -ENODEV;
145795536acSTomas Winkler 		goto release_irq;
146795536acSTomas Winkler 	}
147795536acSTomas Winkler 
148cfe5ab85SAlexander Usyskin 	pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT);
149cfe5ab85SAlexander Usyskin 	pm_runtime_use_autosuspend(&pdev->dev);
150cfe5ab85SAlexander Usyskin 
151795536acSTomas Winkler 	err = mei_register(dev);
152795536acSTomas Winkler 	if (err)
153795536acSTomas Winkler 		goto release_irq;
154795536acSTomas Winkler 
155795536acSTomas Winkler 	pci_set_drvdata(pdev, dev);
156795536acSTomas Winkler 
157*d2d56faeSAlexander Usyskin 	/*
158*d2d56faeSAlexander Usyskin 	* For not wake-able HW runtime pm framework
159*d2d56faeSAlexander Usyskin 	* can't be used on pci device level.
160*d2d56faeSAlexander Usyskin 	* Use domain runtime pm callbacks instead.
161*d2d56faeSAlexander Usyskin 	*/
162*d2d56faeSAlexander Usyskin 	if (!pci_dev_run_wake(pdev))
163*d2d56faeSAlexander Usyskin 		mei_txe_set_pm_domain(dev);
164*d2d56faeSAlexander Usyskin 
165cfe5ab85SAlexander Usyskin 	pm_runtime_put_noidle(&pdev->dev);
166cfe5ab85SAlexander Usyskin 
167795536acSTomas Winkler 	return 0;
168795536acSTomas Winkler 
169795536acSTomas Winkler release_irq:
170795536acSTomas Winkler 
171795536acSTomas Winkler 	mei_cancel_work(dev);
172795536acSTomas Winkler 
173795536acSTomas Winkler 	/* disable interrupts */
174795536acSTomas Winkler 	mei_disable_interrupts(dev);
175795536acSTomas Winkler 
176795536acSTomas Winkler 	free_irq(pdev->irq, dev);
177795536acSTomas Winkler 	pci_disable_msi(pdev);
178795536acSTomas Winkler 
179795536acSTomas Winkler free_device:
180795536acSTomas Winkler 	mei_txe_pci_iounmap(pdev, hw);
181795536acSTomas Winkler 
182795536acSTomas Winkler 	kfree(dev);
183795536acSTomas Winkler release_regions:
184795536acSTomas Winkler 	pci_release_regions(pdev);
185795536acSTomas Winkler disable_device:
186795536acSTomas Winkler 	pci_disable_device(pdev);
187795536acSTomas Winkler end:
188795536acSTomas Winkler 	dev_err(&pdev->dev, "initialization failed.\n");
189795536acSTomas Winkler 	return err;
190795536acSTomas Winkler }
191795536acSTomas Winkler 
192795536acSTomas Winkler /**
193795536acSTomas Winkler  * mei_remove - Device Removal Routine
194795536acSTomas Winkler  *
195795536acSTomas Winkler  * @pdev: PCI device structure
196795536acSTomas Winkler  *
197795536acSTomas Winkler  * mei_remove is called by the PCI subsystem to alert the driver
198795536acSTomas Winkler  * that it should release a PCI device.
199795536acSTomas Winkler  */
200795536acSTomas Winkler static void mei_txe_remove(struct pci_dev *pdev)
201795536acSTomas Winkler {
202795536acSTomas Winkler 	struct mei_device *dev;
203795536acSTomas Winkler 	struct mei_txe_hw *hw;
204795536acSTomas Winkler 
205795536acSTomas Winkler 	dev = pci_get_drvdata(pdev);
206795536acSTomas Winkler 	if (!dev) {
207795536acSTomas Winkler 		dev_err(&pdev->dev, "mei: dev =NULL\n");
208795536acSTomas Winkler 		return;
209795536acSTomas Winkler 	}
210795536acSTomas Winkler 
211cfe5ab85SAlexander Usyskin 	pm_runtime_get_noresume(&pdev->dev);
212cfe5ab85SAlexander Usyskin 
213795536acSTomas Winkler 	hw = to_txe_hw(dev);
214795536acSTomas Winkler 
215795536acSTomas Winkler 	mei_stop(dev);
216795536acSTomas Winkler 
217*d2d56faeSAlexander Usyskin 	if (!pci_dev_run_wake(pdev))
218*d2d56faeSAlexander Usyskin 		mei_txe_unset_pm_domain(dev);
219*d2d56faeSAlexander Usyskin 
220795536acSTomas Winkler 	/* disable interrupts */
221795536acSTomas Winkler 	mei_disable_interrupts(dev);
222795536acSTomas Winkler 	free_irq(pdev->irq, dev);
223795536acSTomas Winkler 	pci_disable_msi(pdev);
224795536acSTomas Winkler 
225795536acSTomas Winkler 	pci_set_drvdata(pdev, NULL);
226795536acSTomas Winkler 
227795536acSTomas Winkler 	mei_txe_pci_iounmap(pdev, hw);
228795536acSTomas Winkler 
229795536acSTomas Winkler 	mei_deregister(dev);
230795536acSTomas Winkler 
231795536acSTomas Winkler 	kfree(dev);
232795536acSTomas Winkler 
233795536acSTomas Winkler 	pci_release_regions(pdev);
234795536acSTomas Winkler 	pci_disable_device(pdev);
235795536acSTomas Winkler }
236795536acSTomas Winkler 
237795536acSTomas Winkler 
238e0270addSTomas Winkler #ifdef CONFIG_PM_SLEEP
239795536acSTomas Winkler static int mei_txe_pci_suspend(struct device *device)
240795536acSTomas Winkler {
241795536acSTomas Winkler 	struct pci_dev *pdev = to_pci_dev(device);
242795536acSTomas Winkler 	struct mei_device *dev = pci_get_drvdata(pdev);
243795536acSTomas Winkler 
244795536acSTomas Winkler 	if (!dev)
245795536acSTomas Winkler 		return -ENODEV;
246795536acSTomas Winkler 
247795536acSTomas Winkler 	dev_dbg(&pdev->dev, "suspend\n");
248795536acSTomas Winkler 
249795536acSTomas Winkler 	mei_stop(dev);
250795536acSTomas Winkler 
251795536acSTomas Winkler 	mei_disable_interrupts(dev);
252795536acSTomas Winkler 
253795536acSTomas Winkler 	free_irq(pdev->irq, dev);
254795536acSTomas Winkler 	pci_disable_msi(pdev);
255795536acSTomas Winkler 
256795536acSTomas Winkler 	return 0;
257795536acSTomas Winkler }
258795536acSTomas Winkler 
259795536acSTomas Winkler static int mei_txe_pci_resume(struct device *device)
260795536acSTomas Winkler {
261795536acSTomas Winkler 	struct pci_dev *pdev = to_pci_dev(device);
262795536acSTomas Winkler 	struct mei_device *dev;
263795536acSTomas Winkler 	int err;
264795536acSTomas Winkler 
265795536acSTomas Winkler 	dev = pci_get_drvdata(pdev);
266795536acSTomas Winkler 	if (!dev)
267795536acSTomas Winkler 		return -ENODEV;
268795536acSTomas Winkler 
269795536acSTomas Winkler 	pci_enable_msi(pdev);
270795536acSTomas Winkler 
271795536acSTomas Winkler 	mei_clear_interrupts(dev);
272795536acSTomas Winkler 
273795536acSTomas Winkler 	/* request and enable interrupt */
274795536acSTomas Winkler 	if (pci_dev_msi_enabled(pdev))
275795536acSTomas Winkler 		err = request_threaded_irq(pdev->irq,
276795536acSTomas Winkler 			NULL,
277795536acSTomas Winkler 			mei_txe_irq_thread_handler,
278795536acSTomas Winkler 			IRQF_ONESHOT, KBUILD_MODNAME, dev);
279795536acSTomas Winkler 	else
280795536acSTomas Winkler 		err = request_threaded_irq(pdev->irq,
281795536acSTomas Winkler 			mei_txe_irq_quick_handler,
282795536acSTomas Winkler 			mei_txe_irq_thread_handler,
283795536acSTomas Winkler 			IRQF_SHARED, KBUILD_MODNAME, dev);
284795536acSTomas Winkler 	if (err) {
285795536acSTomas Winkler 		dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
286795536acSTomas Winkler 				pdev->irq);
287795536acSTomas Winkler 		return err;
288795536acSTomas Winkler 	}
289795536acSTomas Winkler 
290795536acSTomas Winkler 	err = mei_restart(dev);
291795536acSTomas Winkler 
292795536acSTomas Winkler 	return err;
293795536acSTomas Winkler }
294cfe5ab85SAlexander Usyskin #endif /* CONFIG_PM_SLEEP */
295795536acSTomas Winkler 
296cfe5ab85SAlexander Usyskin #ifdef CONFIG_PM_RUNTIME
297cfe5ab85SAlexander Usyskin static int mei_txe_pm_runtime_idle(struct device *device)
298cfe5ab85SAlexander Usyskin {
299cfe5ab85SAlexander Usyskin 	struct pci_dev *pdev = to_pci_dev(device);
300cfe5ab85SAlexander Usyskin 	struct mei_device *dev;
301cfe5ab85SAlexander Usyskin 
302cfe5ab85SAlexander Usyskin 	dev_dbg(&pdev->dev, "rpm: txe: runtime_idle\n");
303cfe5ab85SAlexander Usyskin 
304cfe5ab85SAlexander Usyskin 	dev = pci_get_drvdata(pdev);
305cfe5ab85SAlexander Usyskin 	if (!dev)
306cfe5ab85SAlexander Usyskin 		return -ENODEV;
307cfe5ab85SAlexander Usyskin 	if (mei_write_is_idle(dev))
308cfe5ab85SAlexander Usyskin 		pm_schedule_suspend(device, MEI_TXI_RPM_TIMEOUT * 2);
309cfe5ab85SAlexander Usyskin 
310cfe5ab85SAlexander Usyskin 	return -EBUSY;
311cfe5ab85SAlexander Usyskin }
312cfe5ab85SAlexander Usyskin static int mei_txe_pm_runtime_suspend(struct device *device)
313cfe5ab85SAlexander Usyskin {
314cfe5ab85SAlexander Usyskin 	struct pci_dev *pdev = to_pci_dev(device);
315cfe5ab85SAlexander Usyskin 	struct mei_device *dev;
316cfe5ab85SAlexander Usyskin 	int ret;
317cfe5ab85SAlexander Usyskin 
318cfe5ab85SAlexander Usyskin 	dev_dbg(&pdev->dev, "rpm: txe: runtime suspend\n");
319cfe5ab85SAlexander Usyskin 
320cfe5ab85SAlexander Usyskin 	dev = pci_get_drvdata(pdev);
321cfe5ab85SAlexander Usyskin 	if (!dev)
322cfe5ab85SAlexander Usyskin 		return -ENODEV;
323cfe5ab85SAlexander Usyskin 
324cfe5ab85SAlexander Usyskin 	mutex_lock(&dev->device_lock);
325cfe5ab85SAlexander Usyskin 
326cfe5ab85SAlexander Usyskin 	if (mei_write_is_idle(dev))
327cfe5ab85SAlexander Usyskin 		ret = mei_txe_aliveness_set_sync(dev, 0);
328cfe5ab85SAlexander Usyskin 	else
329cfe5ab85SAlexander Usyskin 		ret = -EAGAIN;
330cfe5ab85SAlexander Usyskin 
331cfe5ab85SAlexander Usyskin 	/*
332cfe5ab85SAlexander Usyskin 	 * If everything is okay we're about to enter PCI low
333cfe5ab85SAlexander Usyskin 	 * power state (D3) therefor we need to disable the
334cfe5ab85SAlexander Usyskin 	 * interrupts towards host.
335cfe5ab85SAlexander Usyskin 	 * However if device is not wakeable we do not enter
336cfe5ab85SAlexander Usyskin 	 * D-low state and we need to keep the interrupt kicking
337cfe5ab85SAlexander Usyskin 	 */
338cfe5ab85SAlexander Usyskin 	 if (!ret && pci_dev_run_wake(pdev))
339cfe5ab85SAlexander Usyskin 		mei_disable_interrupts(dev);
340cfe5ab85SAlexander Usyskin 
341cfe5ab85SAlexander Usyskin 	dev_dbg(&pdev->dev, "rpm: txe: runtime suspend ret=%d\n", ret);
342cfe5ab85SAlexander Usyskin 
343cfe5ab85SAlexander Usyskin 	mutex_unlock(&dev->device_lock);
344cfe5ab85SAlexander Usyskin 	return ret;
345cfe5ab85SAlexander Usyskin }
346cfe5ab85SAlexander Usyskin 
347cfe5ab85SAlexander Usyskin static int mei_txe_pm_runtime_resume(struct device *device)
348cfe5ab85SAlexander Usyskin {
349cfe5ab85SAlexander Usyskin 	struct pci_dev *pdev = to_pci_dev(device);
350cfe5ab85SAlexander Usyskin 	struct mei_device *dev;
351cfe5ab85SAlexander Usyskin 	int ret;
352cfe5ab85SAlexander Usyskin 
353cfe5ab85SAlexander Usyskin 	dev_dbg(&pdev->dev, "rpm: txe: runtime resume\n");
354cfe5ab85SAlexander Usyskin 
355cfe5ab85SAlexander Usyskin 	dev = pci_get_drvdata(pdev);
356cfe5ab85SAlexander Usyskin 	if (!dev)
357cfe5ab85SAlexander Usyskin 		return -ENODEV;
358cfe5ab85SAlexander Usyskin 
359cfe5ab85SAlexander Usyskin 	mutex_lock(&dev->device_lock);
360cfe5ab85SAlexander Usyskin 
361cfe5ab85SAlexander Usyskin 	mei_enable_interrupts(dev);
362cfe5ab85SAlexander Usyskin 
363cfe5ab85SAlexander Usyskin 	ret = mei_txe_aliveness_set_sync(dev, 1);
364cfe5ab85SAlexander Usyskin 
365cfe5ab85SAlexander Usyskin 	mutex_unlock(&dev->device_lock);
366cfe5ab85SAlexander Usyskin 
367cfe5ab85SAlexander Usyskin 	dev_dbg(&pdev->dev, "rpm: txe: runtime resume ret = %d\n", ret);
368cfe5ab85SAlexander Usyskin 
369cfe5ab85SAlexander Usyskin 	return ret;
370cfe5ab85SAlexander Usyskin }
371*d2d56faeSAlexander Usyskin 
372*d2d56faeSAlexander Usyskin /**
373*d2d56faeSAlexander Usyskin  * mei_txe_set_pm_domain - fill and set pm domian stucture for device
374*d2d56faeSAlexander Usyskin  *
375*d2d56faeSAlexander Usyskin  * @dev: mei_device
376*d2d56faeSAlexander Usyskin  */
377*d2d56faeSAlexander Usyskin static inline void mei_txe_set_pm_domain(struct mei_device *dev)
378*d2d56faeSAlexander Usyskin {
379*d2d56faeSAlexander Usyskin 	struct pci_dev *pdev  = dev->pdev;
380*d2d56faeSAlexander Usyskin 
381*d2d56faeSAlexander Usyskin 	if (pdev->dev.bus && pdev->dev.bus->pm) {
382*d2d56faeSAlexander Usyskin 		dev->pg_domain.ops = *pdev->dev.bus->pm;
383*d2d56faeSAlexander Usyskin 
384*d2d56faeSAlexander Usyskin 		dev->pg_domain.ops.runtime_suspend = mei_txe_pm_runtime_suspend;
385*d2d56faeSAlexander Usyskin 		dev->pg_domain.ops.runtime_resume = mei_txe_pm_runtime_resume;
386*d2d56faeSAlexander Usyskin 		dev->pg_domain.ops.runtime_idle = mei_txe_pm_runtime_idle;
387*d2d56faeSAlexander Usyskin 
388*d2d56faeSAlexander Usyskin 		pdev->dev.pm_domain = &dev->pg_domain;
389*d2d56faeSAlexander Usyskin 	}
390*d2d56faeSAlexander Usyskin }
391*d2d56faeSAlexander Usyskin 
392*d2d56faeSAlexander Usyskin /**
393*d2d56faeSAlexander Usyskin  * mei_txe_unset_pm_domain - clean pm domian stucture for device
394*d2d56faeSAlexander Usyskin  *
395*d2d56faeSAlexander Usyskin  * @dev: mei_device
396*d2d56faeSAlexander Usyskin  */
397*d2d56faeSAlexander Usyskin static inline void mei_txe_unset_pm_domain(struct mei_device *dev)
398*d2d56faeSAlexander Usyskin {
399*d2d56faeSAlexander Usyskin 	/* stop using pm callbacks if any */
400*d2d56faeSAlexander Usyskin 	dev->pdev->dev.pm_domain = NULL;
401*d2d56faeSAlexander Usyskin }
402cfe5ab85SAlexander Usyskin #endif /* CONFIG_PM_RUNTIME */
403cfe5ab85SAlexander Usyskin 
404cfe5ab85SAlexander Usyskin #ifdef CONFIG_PM
405cfe5ab85SAlexander Usyskin static const struct dev_pm_ops mei_txe_pm_ops = {
406cfe5ab85SAlexander Usyskin 	SET_SYSTEM_SLEEP_PM_OPS(mei_txe_pci_suspend,
407cfe5ab85SAlexander Usyskin 				mei_txe_pci_resume)
408cfe5ab85SAlexander Usyskin 	SET_RUNTIME_PM_OPS(
409cfe5ab85SAlexander Usyskin 		mei_txe_pm_runtime_suspend,
410cfe5ab85SAlexander Usyskin 		mei_txe_pm_runtime_resume,
411cfe5ab85SAlexander Usyskin 		mei_txe_pm_runtime_idle)
412cfe5ab85SAlexander Usyskin };
413795536acSTomas Winkler 
414795536acSTomas Winkler #define MEI_TXE_PM_OPS	(&mei_txe_pm_ops)
415795536acSTomas Winkler #else
416795536acSTomas Winkler #define MEI_TXE_PM_OPS	NULL
417cfe5ab85SAlexander Usyskin #endif /* CONFIG_PM */
418cfe5ab85SAlexander Usyskin 
419795536acSTomas Winkler /*
420795536acSTomas Winkler  *  PCI driver structure
421795536acSTomas Winkler  */
422795536acSTomas Winkler static struct pci_driver mei_txe_driver = {
423795536acSTomas Winkler 	.name = KBUILD_MODNAME,
424795536acSTomas Winkler 	.id_table = mei_txe_pci_tbl,
425795536acSTomas Winkler 	.probe = mei_txe_probe,
426795536acSTomas Winkler 	.remove = mei_txe_remove,
427795536acSTomas Winkler 	.shutdown = mei_txe_remove,
428795536acSTomas Winkler 	.driver.pm = MEI_TXE_PM_OPS,
429795536acSTomas Winkler };
430795536acSTomas Winkler 
431795536acSTomas Winkler module_pci_driver(mei_txe_driver);
432795536acSTomas Winkler 
433795536acSTomas Winkler MODULE_AUTHOR("Intel Corporation");
434795536acSTomas Winkler MODULE_DESCRIPTION("Intel(R) Trusted Execution Environment Interface");
435795536acSTomas Winkler MODULE_LICENSE("GPL v2");
436