HID: intel-ish-hid: Remove unneeded linux/miscdevice.h include
[platform/kernel/linux-exynos.git] / drivers / hid / intel-ish-hid / ipc / pci-ish.c
1 /*
2  * PCI glue for ISHTP provider device (ISH) driver
3  *
4  * Copyright (c) 2014-2016, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  */
15
16 #include <linux/module.h>
17 #include <linux/moduleparam.h>
18 #include <linux/kernel.h>
19 #include <linux/device.h>
20 #include <linux/fs.h>
21 #include <linux/errno.h>
22 #include <linux/types.h>
23 #include <linux/pci.h>
24 #include <linux/sched.h>
25 #include <linux/interrupt.h>
26 #include <linux/workqueue.h>
27 #define CREATE_TRACE_POINTS
28 #include <trace/events/intel_ish.h>
29 #include "ishtp-dev.h"
30 #include "hw-ish.h"
31
32 static const struct pci_device_id ish_pci_tbl[] = {
33         {PCI_DEVICE(PCI_VENDOR_ID_INTEL, CHV_DEVICE_ID)},
34         {PCI_DEVICE(PCI_VENDOR_ID_INTEL, BXT_Ax_DEVICE_ID)},
35         {PCI_DEVICE(PCI_VENDOR_ID_INTEL, BXT_Bx_DEVICE_ID)},
36         {PCI_DEVICE(PCI_VENDOR_ID_INTEL, APL_Ax_DEVICE_ID)},
37         {PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_Ax_DEVICE_ID)},
38         {0, }
39 };
40 MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
41
42 /**
43  * ish_event_tracer() - Callback function to dump trace messages
44  * @dev:        ishtp device
45  * @format:     printf style format
46  *
47  * Callback to direct log messages to Linux trace buffers
48  */
49 static void ish_event_tracer(struct ishtp_device *dev, char *format, ...)
50 {
51         if (trace_ishtp_dump_enabled()) {
52                 va_list args;
53                 char tmp_buf[100];
54
55                 va_start(args, format);
56                 vsnprintf(tmp_buf, sizeof(tmp_buf), format, args);
57                 va_end(args);
58
59                 trace_ishtp_dump(tmp_buf);
60         }
61 }
62
63 /**
64  * ish_init() - Init function
65  * @dev:        ishtp device
66  *
67  * This function initialize wait queues for suspend/resume and call
68  * calls hadware initialization function. This will initiate
69  * startup sequence
70  *
71  * Return: 0 for success or error code for failure
72  */
73 static int ish_init(struct ishtp_device *dev)
74 {
75         int ret;
76
77         /* Set the state of ISH HW to start */
78         ret = ish_hw_start(dev);
79         if (ret) {
80                 dev_err(dev->devc, "ISH: hw start failed.\n");
81                 return ret;
82         }
83
84         /* Start the inter process communication to ISH processor */
85         ret = ishtp_start(dev);
86         if (ret) {
87                 dev_err(dev->devc, "ISHTP: Protocol init failed.\n");
88                 return ret;
89         }
90
91         return 0;
92 }
93
94 /**
95  * ish_probe() - PCI driver probe callback
96  * @pdev:       pci device
97  * @ent:        pci device id
98  *
99  * Initialize PCI function, setup interrupt and call for ISH initialization
100  *
101  * Return: 0 for success or error code for failure
102  */
103 static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
104 {
105         struct ishtp_device *dev;
106         struct ish_hw *hw;
107         int     ret;
108
109         /* enable pci dev */
110         ret = pci_enable_device(pdev);
111         if (ret) {
112                 dev_err(&pdev->dev, "ISH: Failed to enable PCI device\n");
113                 return ret;
114         }
115
116         /* set PCI host mastering */
117         pci_set_master(pdev);
118
119         /* pci request regions for ISH driver */
120         ret = pci_request_regions(pdev, KBUILD_MODNAME);
121         if (ret) {
122                 dev_err(&pdev->dev, "ISH: Failed to get PCI regions\n");
123                 goto disable_device;
124         }
125
126         /* allocates and initializes the ISH dev structure */
127         dev = ish_dev_init(pdev);
128         if (!dev) {
129                 ret = -ENOMEM;
130                 goto release_regions;
131         }
132         hw = to_ish_hw(dev);
133         dev->print_log = ish_event_tracer;
134
135         /* mapping IO device memory */
136         hw->mem_addr = pci_iomap(pdev, 0, 0);
137         if (!hw->mem_addr) {
138                 dev_err(&pdev->dev, "ISH: mapping I/O range failure\n");
139                 ret = -ENOMEM;
140                 goto free_device;
141         }
142
143         dev->pdev = pdev;
144
145         pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
146
147         /* request and enable interrupt */
148         ret = request_irq(pdev->irq, ish_irq_handler, IRQF_SHARED,
149                           KBUILD_MODNAME, dev);
150         if (ret) {
151                 dev_err(&pdev->dev, "ISH: request IRQ failure (%d)\n",
152                         pdev->irq);
153                 goto free_device;
154         }
155
156         dev_set_drvdata(dev->devc, dev);
157
158         init_waitqueue_head(&dev->suspend_wait);
159         init_waitqueue_head(&dev->resume_wait);
160
161         ret = ish_init(dev);
162         if (ret)
163                 goto free_irq;
164
165         return 0;
166
167 free_irq:
168         free_irq(pdev->irq, dev);
169 free_device:
170         pci_iounmap(pdev, hw->mem_addr);
171         kfree(dev);
172 release_regions:
173         pci_release_regions(pdev);
174 disable_device:
175         pci_clear_master(pdev);
176         pci_disable_device(pdev);
177         dev_err(&pdev->dev, "ISH: PCI driver initialization failed.\n");
178
179         return ret;
180 }
181
182 /**
183  * ish_remove() - PCI driver remove callback
184  * @pdev:       pci device
185  *
186  * This function does cleanup of ISH on pci remove callback
187  */
188 static void ish_remove(struct pci_dev *pdev)
189 {
190         struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
191         struct ish_hw *hw = to_ish_hw(ishtp_dev);
192
193         ishtp_bus_remove_all_clients(ishtp_dev, false);
194         ish_device_disable(ishtp_dev);
195
196         free_irq(pdev->irq, ishtp_dev);
197         pci_iounmap(pdev, hw->mem_addr);
198         pci_release_regions(pdev);
199         pci_clear_master(pdev);
200         pci_disable_device(pdev);
201         kfree(ishtp_dev);
202 }
203
204 #ifdef CONFIG_PM
205 static struct device *ish_resume_device;
206
207 /**
208  * ish_resume_handler() - Work function to complete resume
209  * @work:       work struct
210  *
211  * The resume work function to complete resume function asynchronously.
212  * There are two types of platforms, one where ISH is not powered off,
213  * in that case a simple resume message is enough, others we need
214  * a reset sequence.
215  */
216 static void ish_resume_handler(struct work_struct *work)
217 {
218         struct pci_dev *pdev = to_pci_dev(ish_resume_device);
219         struct ishtp_device *dev = pci_get_drvdata(pdev);
220         int ret;
221
222         ishtp_send_resume(dev);
223
224         /* 50 ms to get resume response */
225         if (dev->resume_flag)
226                 ret = wait_event_interruptible_timeout(dev->resume_wait,
227                                                        !dev->resume_flag,
228                                                        msecs_to_jiffies(50));
229
230         /*
231          * If no resume response. This platform  is not S0ix compatible
232          * So on resume full reboot of ISH processor will happen, so
233          * need to go through init sequence again
234          */
235         if (dev->resume_flag)
236                 ish_init(dev);
237 }
238
239 /**
240  * ish_suspend() - ISH suspend callback
241  * @device:     device pointer
242  *
243  * ISH suspend callback
244  *
245  * Return: 0 to the pm core
246  */
247 static int ish_suspend(struct device *device)
248 {
249         struct pci_dev *pdev = to_pci_dev(device);
250         struct ishtp_device *dev = pci_get_drvdata(pdev);
251
252         enable_irq_wake(pdev->irq);
253         /*
254          * If previous suspend hasn't been asnwered then ISH is likely dead,
255          * don't attempt nested notification
256          */
257         if (dev->suspend_flag)
258                 return  0;
259
260         dev->resume_flag = 0;
261         dev->suspend_flag = 1;
262         ishtp_send_suspend(dev);
263
264         /* 25 ms should be enough for live ISH to flush all IPC buf */
265         if (dev->suspend_flag)
266                 wait_event_interruptible_timeout(dev->suspend_wait,
267                                                  !dev->suspend_flag,
268                                                   msecs_to_jiffies(25));
269
270         return 0;
271 }
272
273 static DECLARE_WORK(resume_work, ish_resume_handler);
274 /**
275  * ish_resume() - ISH resume callback
276  * @device:     device pointer
277  *
278  * ISH resume callback
279  *
280  * Return: 0 to the pm core
281  */
282 static int ish_resume(struct device *device)
283 {
284         struct pci_dev *pdev = to_pci_dev(device);
285         struct ishtp_device *dev = pci_get_drvdata(pdev);
286
287         ish_resume_device = device;
288         dev->resume_flag = 1;
289
290         disable_irq_wake(pdev->irq);
291         schedule_work(&resume_work);
292
293         return 0;
294 }
295
296 static const struct dev_pm_ops ish_pm_ops = {
297         .suspend = ish_suspend,
298         .resume = ish_resume,
299 };
300 #define ISHTP_ISH_PM_OPS        (&ish_pm_ops)
301 #else
302 #define ISHTP_ISH_PM_OPS        NULL
303 #endif /* CONFIG_PM */
304
305 static struct pci_driver ish_driver = {
306         .name = KBUILD_MODNAME,
307         .id_table = ish_pci_tbl,
308         .probe = ish_probe,
309         .remove = ish_remove,
310         .driver.pm = ISHTP_ISH_PM_OPS,
311 };
312
313 module_pci_driver(ish_driver);
314
315 /* Original author */
316 MODULE_AUTHOR("Daniel Drubin <daniel.drubin@intel.com>");
317 /* Adoption to upstream Linux kernel */
318 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
319
320 MODULE_DESCRIPTION("Intel(R) Integrated Sensor Hub PCI Device Driver");
321 MODULE_LICENSE("GPL");