1529766e0SElie Morisse // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2529766e0SElie Morisse /*
3529766e0SElie Morisse * AMD MP2 PCIe communication driver
4529766e0SElie Morisse *
5529766e0SElie Morisse * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
6529766e0SElie Morisse * Elie Morisse <syniurge@gmail.com>
7529766e0SElie Morisse */
8529766e0SElie Morisse
9529766e0SElie Morisse #include <linux/dma-mapping.h>
10529766e0SElie Morisse #include <linux/interrupt.h>
11529766e0SElie Morisse #include <linux/module.h>
12529766e0SElie Morisse #include <linux/pci.h>
13529766e0SElie Morisse #include <linux/slab.h>
14529766e0SElie Morisse
15529766e0SElie Morisse #include "i2c-amd-mp2.h"
16529766e0SElie Morisse
17529766e0SElie Morisse #include <linux/io-64-nonatomic-lo-hi.h>
18529766e0SElie Morisse
amd_mp2_c2p_mutex_lock(struct amd_i2c_common * i2c_common)19529766e0SElie Morisse static void amd_mp2_c2p_mutex_lock(struct amd_i2c_common *i2c_common)
20529766e0SElie Morisse {
21529766e0SElie Morisse struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
22529766e0SElie Morisse
23529766e0SElie Morisse /* there is only one data mailbox for two i2c adapters */
24529766e0SElie Morisse mutex_lock(&privdata->c2p_lock);
25529766e0SElie Morisse privdata->c2p_lock_busid = i2c_common->bus_id;
26529766e0SElie Morisse }
27529766e0SElie Morisse
amd_mp2_c2p_mutex_unlock(struct amd_i2c_common * i2c_common)28529766e0SElie Morisse static void amd_mp2_c2p_mutex_unlock(struct amd_i2c_common *i2c_common)
29529766e0SElie Morisse {
30529766e0SElie Morisse struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
31529766e0SElie Morisse
32529766e0SElie Morisse if (unlikely(privdata->c2p_lock_busid != i2c_common->bus_id)) {
33267e82b9SRichard Neumann pci_warn(privdata->pci_dev,
34529766e0SElie Morisse "bus %d attempting to unlock C2P locked by bus %d\n",
35529766e0SElie Morisse i2c_common->bus_id, privdata->c2p_lock_busid);
36529766e0SElie Morisse return;
37529766e0SElie Morisse }
38529766e0SElie Morisse
39529766e0SElie Morisse mutex_unlock(&privdata->c2p_lock);
40529766e0SElie Morisse }
41529766e0SElie Morisse
amd_mp2_cmd(struct amd_i2c_common * i2c_common,union i2c_cmd_base i2c_cmd_base)42529766e0SElie Morisse static int amd_mp2_cmd(struct amd_i2c_common *i2c_common,
43529766e0SElie Morisse union i2c_cmd_base i2c_cmd_base)
44529766e0SElie Morisse {
45529766e0SElie Morisse struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
46529766e0SElie Morisse void __iomem *reg;
47529766e0SElie Morisse
48529766e0SElie Morisse i2c_common->reqcmd = i2c_cmd_base.s.i2c_cmd;
49529766e0SElie Morisse
50529766e0SElie Morisse reg = privdata->mmio + ((i2c_cmd_base.s.bus_id == 1) ?
51529766e0SElie Morisse AMD_C2P_MSG1 : AMD_C2P_MSG0);
52529766e0SElie Morisse writel(i2c_cmd_base.ul, reg);
53529766e0SElie Morisse
54529766e0SElie Morisse return 0;
55529766e0SElie Morisse }
56529766e0SElie Morisse
amd_mp2_bus_enable_set(struct amd_i2c_common * i2c_common,bool enable)57529766e0SElie Morisse int amd_mp2_bus_enable_set(struct amd_i2c_common *i2c_common, bool enable)
58529766e0SElie Morisse {
59529766e0SElie Morisse struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
60529766e0SElie Morisse union i2c_cmd_base i2c_cmd_base;
61529766e0SElie Morisse
62267e82b9SRichard Neumann pci_dbg(privdata->pci_dev, "id: %d\n", i2c_common->bus_id);
63529766e0SElie Morisse
64529766e0SElie Morisse i2c_cmd_base.ul = 0;
65529766e0SElie Morisse i2c_cmd_base.s.i2c_cmd = enable ? i2c_enable : i2c_disable;
66529766e0SElie Morisse i2c_cmd_base.s.bus_id = i2c_common->bus_id;
67529766e0SElie Morisse i2c_cmd_base.s.i2c_speed = i2c_common->i2c_speed;
68529766e0SElie Morisse
69529766e0SElie Morisse amd_mp2_c2p_mutex_lock(i2c_common);
70529766e0SElie Morisse
71529766e0SElie Morisse return amd_mp2_cmd(i2c_common, i2c_cmd_base);
72529766e0SElie Morisse }
73529766e0SElie Morisse EXPORT_SYMBOL_GPL(amd_mp2_bus_enable_set);
74529766e0SElie Morisse
amd_mp2_cmd_rw_fill(struct amd_i2c_common * i2c_common,union i2c_cmd_base * i2c_cmd_base,enum i2c_cmd reqcmd)75529766e0SElie Morisse static void amd_mp2_cmd_rw_fill(struct amd_i2c_common *i2c_common,
76529766e0SElie Morisse union i2c_cmd_base *i2c_cmd_base,
77529766e0SElie Morisse enum i2c_cmd reqcmd)
78529766e0SElie Morisse {
79529766e0SElie Morisse i2c_cmd_base->s.i2c_cmd = reqcmd;
80529766e0SElie Morisse i2c_cmd_base->s.bus_id = i2c_common->bus_id;
81529766e0SElie Morisse i2c_cmd_base->s.i2c_speed = i2c_common->i2c_speed;
82529766e0SElie Morisse i2c_cmd_base->s.slave_addr = i2c_common->msg->addr;
83529766e0SElie Morisse i2c_cmd_base->s.length = i2c_common->msg->len;
84529766e0SElie Morisse }
85529766e0SElie Morisse
amd_mp2_rw(struct amd_i2c_common * i2c_common,enum i2c_cmd reqcmd)86529766e0SElie Morisse int amd_mp2_rw(struct amd_i2c_common *i2c_common, enum i2c_cmd reqcmd)
87529766e0SElie Morisse {
88529766e0SElie Morisse struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
89529766e0SElie Morisse union i2c_cmd_base i2c_cmd_base;
90529766e0SElie Morisse
91529766e0SElie Morisse amd_mp2_cmd_rw_fill(i2c_common, &i2c_cmd_base, reqcmd);
92529766e0SElie Morisse amd_mp2_c2p_mutex_lock(i2c_common);
93529766e0SElie Morisse
94529766e0SElie Morisse if (i2c_common->msg->len <= 32) {
95529766e0SElie Morisse i2c_cmd_base.s.mem_type = use_c2pmsg;
96529766e0SElie Morisse if (reqcmd == i2c_write)
97529766e0SElie Morisse memcpy_toio(privdata->mmio + AMD_C2P_MSG2,
98529766e0SElie Morisse i2c_common->msg->buf,
99529766e0SElie Morisse i2c_common->msg->len);
100529766e0SElie Morisse } else {
101529766e0SElie Morisse i2c_cmd_base.s.mem_type = use_dram;
102529766e0SElie Morisse writeq((u64)i2c_common->dma_addr,
103529766e0SElie Morisse privdata->mmio + AMD_C2P_MSG2);
104529766e0SElie Morisse }
105529766e0SElie Morisse
106529766e0SElie Morisse return amd_mp2_cmd(i2c_common, i2c_cmd_base);
107529766e0SElie Morisse }
108529766e0SElie Morisse EXPORT_SYMBOL_GPL(amd_mp2_rw);
109529766e0SElie Morisse
amd_mp2_pci_check_rw_event(struct amd_i2c_common * i2c_common)110529766e0SElie Morisse static void amd_mp2_pci_check_rw_event(struct amd_i2c_common *i2c_common)
111529766e0SElie Morisse {
112529766e0SElie Morisse struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
113267e82b9SRichard Neumann struct pci_dev *pdev = privdata->pci_dev;
114529766e0SElie Morisse int len = i2c_common->eventval.r.length;
115529766e0SElie Morisse u32 slave_addr = i2c_common->eventval.r.slave_addr;
116529766e0SElie Morisse bool err = false;
117529766e0SElie Morisse
118529766e0SElie Morisse if (unlikely(len != i2c_common->msg->len)) {
119267e82b9SRichard Neumann pci_err(pdev, "length %d in event doesn't match buffer length %d!\n",
120529766e0SElie Morisse len, i2c_common->msg->len);
121529766e0SElie Morisse err = true;
122529766e0SElie Morisse }
123529766e0SElie Morisse
124529766e0SElie Morisse if (unlikely(slave_addr != i2c_common->msg->addr)) {
125267e82b9SRichard Neumann pci_err(pdev, "unexpected slave address %x (expected: %x)!\n",
126529766e0SElie Morisse slave_addr, i2c_common->msg->addr);
127529766e0SElie Morisse err = true;
128529766e0SElie Morisse }
129529766e0SElie Morisse
130529766e0SElie Morisse if (!err)
131529766e0SElie Morisse i2c_common->cmd_success = true;
132529766e0SElie Morisse }
133529766e0SElie Morisse
__amd_mp2_process_event(struct amd_i2c_common * i2c_common)134529766e0SElie Morisse static void __amd_mp2_process_event(struct amd_i2c_common *i2c_common)
135529766e0SElie Morisse {
136529766e0SElie Morisse struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
137267e82b9SRichard Neumann struct pci_dev *pdev = privdata->pci_dev;
138529766e0SElie Morisse enum status_type sts = i2c_common->eventval.r.status;
139529766e0SElie Morisse enum response_type res = i2c_common->eventval.r.response;
140529766e0SElie Morisse int len = i2c_common->eventval.r.length;
141529766e0SElie Morisse
142529766e0SElie Morisse if (res != command_success) {
143529766e0SElie Morisse if (res != command_failed)
144267e82b9SRichard Neumann pci_err(pdev, "invalid response to i2c command!\n");
145529766e0SElie Morisse return;
146529766e0SElie Morisse }
147529766e0SElie Morisse
148529766e0SElie Morisse switch (i2c_common->reqcmd) {
149529766e0SElie Morisse case i2c_read:
150529766e0SElie Morisse if (sts == i2c_readcomplete_event) {
151529766e0SElie Morisse amd_mp2_pci_check_rw_event(i2c_common);
152529766e0SElie Morisse if (len <= 32)
153529766e0SElie Morisse memcpy_fromio(i2c_common->msg->buf,
154529766e0SElie Morisse privdata->mmio + AMD_C2P_MSG2,
155529766e0SElie Morisse len);
156529766e0SElie Morisse } else if (sts != i2c_readfail_event) {
157267e82b9SRichard Neumann pci_err(pdev, "invalid i2c status after read (%d)!\n", sts);
158529766e0SElie Morisse }
159529766e0SElie Morisse break;
160529766e0SElie Morisse case i2c_write:
161529766e0SElie Morisse if (sts == i2c_writecomplete_event)
162529766e0SElie Morisse amd_mp2_pci_check_rw_event(i2c_common);
163529766e0SElie Morisse else if (sts != i2c_writefail_event)
164267e82b9SRichard Neumann pci_err(pdev, "invalid i2c status after write (%d)!\n", sts);
165529766e0SElie Morisse break;
166529766e0SElie Morisse case i2c_enable:
167529766e0SElie Morisse if (sts == i2c_busenable_complete)
168529766e0SElie Morisse i2c_common->cmd_success = true;
169529766e0SElie Morisse else if (sts != i2c_busenable_failed)
170267e82b9SRichard Neumann pci_err(pdev, "invalid i2c status after bus enable (%d)!\n", sts);
171529766e0SElie Morisse break;
172529766e0SElie Morisse case i2c_disable:
173529766e0SElie Morisse if (sts == i2c_busdisable_complete)
174529766e0SElie Morisse i2c_common->cmd_success = true;
175529766e0SElie Morisse else if (sts != i2c_busdisable_failed)
176267e82b9SRichard Neumann pci_err(pdev, "invalid i2c status after bus disable (%d)!\n", sts);
177529766e0SElie Morisse break;
178529766e0SElie Morisse default:
179529766e0SElie Morisse break;
180529766e0SElie Morisse }
181529766e0SElie Morisse }
182529766e0SElie Morisse
amd_mp2_process_event(struct amd_i2c_common * i2c_common)183529766e0SElie Morisse void amd_mp2_process_event(struct amd_i2c_common *i2c_common)
184529766e0SElie Morisse {
185529766e0SElie Morisse struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
186267e82b9SRichard Neumann struct pci_dev *pdev = privdata->pci_dev;
187529766e0SElie Morisse
188529766e0SElie Morisse if (unlikely(i2c_common->reqcmd == i2c_none)) {
189267e82b9SRichard Neumann pci_warn(pdev, "received msg but no cmd was sent (bus = %d)!\n",
190529766e0SElie Morisse i2c_common->bus_id);
191529766e0SElie Morisse return;
192529766e0SElie Morisse }
193529766e0SElie Morisse
194529766e0SElie Morisse __amd_mp2_process_event(i2c_common);
195529766e0SElie Morisse
196529766e0SElie Morisse i2c_common->reqcmd = i2c_none;
197529766e0SElie Morisse amd_mp2_c2p_mutex_unlock(i2c_common);
198529766e0SElie Morisse }
199529766e0SElie Morisse EXPORT_SYMBOL_GPL(amd_mp2_process_event);
200529766e0SElie Morisse
amd_mp2_irq_isr(int irq,void * dev)201529766e0SElie Morisse static irqreturn_t amd_mp2_irq_isr(int irq, void *dev)
202529766e0SElie Morisse {
203529766e0SElie Morisse struct amd_mp2_dev *privdata = dev;
204267e82b9SRichard Neumann struct pci_dev *pdev = privdata->pci_dev;
205529766e0SElie Morisse struct amd_i2c_common *i2c_common;
206529766e0SElie Morisse u32 val;
207529766e0SElie Morisse unsigned int bus_id;
208529766e0SElie Morisse void __iomem *reg;
209529766e0SElie Morisse enum irqreturn ret = IRQ_NONE;
210529766e0SElie Morisse
211529766e0SElie Morisse for (bus_id = 0; bus_id < 2; bus_id++) {
212529766e0SElie Morisse i2c_common = privdata->busses[bus_id];
213529766e0SElie Morisse if (!i2c_common)
214529766e0SElie Morisse continue;
215529766e0SElie Morisse
216529766e0SElie Morisse reg = privdata->mmio + ((bus_id == 0) ?
217529766e0SElie Morisse AMD_P2C_MSG1 : AMD_P2C_MSG2);
218529766e0SElie Morisse val = readl(reg);
219529766e0SElie Morisse if (val != 0) {
220529766e0SElie Morisse writel(0, reg);
221529766e0SElie Morisse writel(0, privdata->mmio + AMD_P2C_MSG_INTEN);
222529766e0SElie Morisse i2c_common->eventval.ul = val;
223529766e0SElie Morisse i2c_common->cmd_completion(i2c_common);
224529766e0SElie Morisse
225529766e0SElie Morisse ret = IRQ_HANDLED;
226529766e0SElie Morisse }
227529766e0SElie Morisse }
228529766e0SElie Morisse
229529766e0SElie Morisse if (ret != IRQ_HANDLED) {
230529766e0SElie Morisse val = readl(privdata->mmio + AMD_P2C_MSG_INTEN);
231529766e0SElie Morisse if (val != 0) {
232529766e0SElie Morisse writel(0, privdata->mmio + AMD_P2C_MSG_INTEN);
233267e82b9SRichard Neumann pci_warn(pdev, "received irq without message\n");
234529766e0SElie Morisse ret = IRQ_HANDLED;
235529766e0SElie Morisse }
236529766e0SElie Morisse }
237529766e0SElie Morisse
238529766e0SElie Morisse return ret;
239529766e0SElie Morisse }
240529766e0SElie Morisse
amd_mp2_rw_timeout(struct amd_i2c_common * i2c_common)241529766e0SElie Morisse void amd_mp2_rw_timeout(struct amd_i2c_common *i2c_common)
242529766e0SElie Morisse {
243529766e0SElie Morisse i2c_common->reqcmd = i2c_none;
244529766e0SElie Morisse amd_mp2_c2p_mutex_unlock(i2c_common);
245529766e0SElie Morisse }
246529766e0SElie Morisse EXPORT_SYMBOL_GPL(amd_mp2_rw_timeout);
247529766e0SElie Morisse
amd_mp2_register_cb(struct amd_i2c_common * i2c_common)248529766e0SElie Morisse int amd_mp2_register_cb(struct amd_i2c_common *i2c_common)
249529766e0SElie Morisse {
250529766e0SElie Morisse struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
251267e82b9SRichard Neumann struct pci_dev *pdev = privdata->pci_dev;
252529766e0SElie Morisse
253529766e0SElie Morisse if (i2c_common->bus_id > 1)
254529766e0SElie Morisse return -EINVAL;
255529766e0SElie Morisse
256529766e0SElie Morisse if (privdata->busses[i2c_common->bus_id]) {
257267e82b9SRichard Neumann pci_err(pdev, "Bus %d already taken!\n", i2c_common->bus_id);
258529766e0SElie Morisse return -EINVAL;
259529766e0SElie Morisse }
260529766e0SElie Morisse
261529766e0SElie Morisse privdata->busses[i2c_common->bus_id] = i2c_common;
262529766e0SElie Morisse
263529766e0SElie Morisse return 0;
264529766e0SElie Morisse }
265529766e0SElie Morisse EXPORT_SYMBOL_GPL(amd_mp2_register_cb);
266529766e0SElie Morisse
amd_mp2_unregister_cb(struct amd_i2c_common * i2c_common)267529766e0SElie Morisse int amd_mp2_unregister_cb(struct amd_i2c_common *i2c_common)
268529766e0SElie Morisse {
269529766e0SElie Morisse struct amd_mp2_dev *privdata = i2c_common->mp2_dev;
270529766e0SElie Morisse
271529766e0SElie Morisse privdata->busses[i2c_common->bus_id] = NULL;
272529766e0SElie Morisse
273529766e0SElie Morisse return 0;
274529766e0SElie Morisse }
275529766e0SElie Morisse EXPORT_SYMBOL_GPL(amd_mp2_unregister_cb);
276529766e0SElie Morisse
amd_mp2_clear_reg(struct amd_mp2_dev * privdata)277529766e0SElie Morisse static void amd_mp2_clear_reg(struct amd_mp2_dev *privdata)
278529766e0SElie Morisse {
279529766e0SElie Morisse int reg;
280529766e0SElie Morisse
281529766e0SElie Morisse for (reg = AMD_C2P_MSG0; reg <= AMD_C2P_MSG9; reg += 4)
282529766e0SElie Morisse writel(0, privdata->mmio + reg);
283529766e0SElie Morisse
284529766e0SElie Morisse for (reg = AMD_P2C_MSG1; reg <= AMD_P2C_MSG2; reg += 4)
285529766e0SElie Morisse writel(0, privdata->mmio + reg);
286529766e0SElie Morisse }
287529766e0SElie Morisse
amd_mp2_pci_init(struct amd_mp2_dev * privdata,struct pci_dev * pci_dev)288529766e0SElie Morisse static int amd_mp2_pci_init(struct amd_mp2_dev *privdata,
289529766e0SElie Morisse struct pci_dev *pci_dev)
290529766e0SElie Morisse {
291*969864efSRaju Rangoju int irq_flag = 0, rc;
292529766e0SElie Morisse
293529766e0SElie Morisse pci_set_drvdata(pci_dev, privdata);
294529766e0SElie Morisse
295529766e0SElie Morisse rc = pcim_enable_device(pci_dev);
296529766e0SElie Morisse if (rc) {
297267e82b9SRichard Neumann pci_err(pci_dev, "Failed to enable MP2 PCI device\n");
298529766e0SElie Morisse goto err_pci_enable;
299529766e0SElie Morisse }
300529766e0SElie Morisse
301529766e0SElie Morisse rc = pcim_iomap_regions(pci_dev, 1 << 2, pci_name(pci_dev));
302529766e0SElie Morisse if (rc) {
303267e82b9SRichard Neumann pci_err(pci_dev, "I/O memory remapping failed\n");
304529766e0SElie Morisse goto err_pci_enable;
305529766e0SElie Morisse }
306529766e0SElie Morisse privdata->mmio = pcim_iomap_table(pci_dev)[2];
307529766e0SElie Morisse
308529766e0SElie Morisse pci_set_master(pci_dev);
309529766e0SElie Morisse
310d56baf6eSChristophe JAILLET rc = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(64));
311529766e0SElie Morisse if (rc)
312529766e0SElie Morisse goto err_dma_mask;
313529766e0SElie Morisse
314*969864efSRaju Rangoju /* request and enable interrupt */
315529766e0SElie Morisse writel(0, privdata->mmio + AMD_P2C_MSG_INTEN);
316*969864efSRaju Rangoju rc = pci_alloc_irq_vectors(pci_dev, 1, 1, PCI_IRQ_ALL_TYPES);
317*969864efSRaju Rangoju if (rc < 0) {
318*969864efSRaju Rangoju dev_err(&pci_dev->dev, "Failed to allocate single IRQ err=%d\n", rc);
319*969864efSRaju Rangoju goto err_dma_mask;
320*969864efSRaju Rangoju }
321*969864efSRaju Rangoju
322*969864efSRaju Rangoju privdata->dev_irq = pci_irq_vector(pci_dev, 0);
323*969864efSRaju Rangoju if (!pci_dev->msix_enabled && !pci_dev->msi_enabled)
324*969864efSRaju Rangoju irq_flag = IRQF_SHARED;
325*969864efSRaju Rangoju
326*969864efSRaju Rangoju rc = devm_request_irq(&pci_dev->dev, privdata->dev_irq,
327*969864efSRaju Rangoju amd_mp2_irq_isr, irq_flag, dev_name(&pci_dev->dev), privdata);
328*969864efSRaju Rangoju if (rc) {
329*969864efSRaju Rangoju pci_err(pci_dev, "Failure requesting irq %i: %d\n", privdata->dev_irq, rc);
330*969864efSRaju Rangoju goto free_irq_vectors;
331*969864efSRaju Rangoju }
332529766e0SElie Morisse
333529766e0SElie Morisse return rc;
334529766e0SElie Morisse
335*969864efSRaju Rangoju free_irq_vectors:
336*969864efSRaju Rangoju free_irq(privdata->dev_irq, privdata);
337529766e0SElie Morisse err_dma_mask:
338529766e0SElie Morisse pci_clear_master(pci_dev);
339529766e0SElie Morisse err_pci_enable:
340529766e0SElie Morisse pci_set_drvdata(pci_dev, NULL);
341529766e0SElie Morisse return rc;
342529766e0SElie Morisse }
343529766e0SElie Morisse
amd_mp2_pci_probe(struct pci_dev * pci_dev,const struct pci_device_id * id)344529766e0SElie Morisse static int amd_mp2_pci_probe(struct pci_dev *pci_dev,
345529766e0SElie Morisse const struct pci_device_id *id)
346529766e0SElie Morisse {
347529766e0SElie Morisse struct amd_mp2_dev *privdata;
348529766e0SElie Morisse int rc;
349529766e0SElie Morisse
350529766e0SElie Morisse privdata = devm_kzalloc(&pci_dev->dev, sizeof(*privdata), GFP_KERNEL);
351529766e0SElie Morisse if (!privdata)
352529766e0SElie Morisse return -ENOMEM;
353529766e0SElie Morisse
354ac2b0813SDan Carpenter privdata->pci_dev = pci_dev;
355529766e0SElie Morisse rc = amd_mp2_pci_init(privdata, pci_dev);
356529766e0SElie Morisse if (rc)
357529766e0SElie Morisse return rc;
358529766e0SElie Morisse
359529766e0SElie Morisse mutex_init(&privdata->c2p_lock);
360529766e0SElie Morisse
361529766e0SElie Morisse pm_runtime_set_autosuspend_delay(&pci_dev->dev, 1000);
362529766e0SElie Morisse pm_runtime_use_autosuspend(&pci_dev->dev);
363529766e0SElie Morisse pm_runtime_put_autosuspend(&pci_dev->dev);
364529766e0SElie Morisse pm_runtime_allow(&pci_dev->dev);
365529766e0SElie Morisse
366529766e0SElie Morisse privdata->probed = true;
367529766e0SElie Morisse
368267e82b9SRichard Neumann pci_info(pci_dev, "MP2 device registered.\n");
369529766e0SElie Morisse return 0;
370529766e0SElie Morisse }
371529766e0SElie Morisse
amd_mp2_pci_remove(struct pci_dev * pci_dev)372529766e0SElie Morisse static void amd_mp2_pci_remove(struct pci_dev *pci_dev)
373529766e0SElie Morisse {
374529766e0SElie Morisse struct amd_mp2_dev *privdata = pci_get_drvdata(pci_dev);
375529766e0SElie Morisse
376529766e0SElie Morisse pm_runtime_forbid(&pci_dev->dev);
377529766e0SElie Morisse pm_runtime_get_noresume(&pci_dev->dev);
378529766e0SElie Morisse
379*969864efSRaju Rangoju free_irq(privdata->dev_irq, privdata);
380529766e0SElie Morisse pci_clear_master(pci_dev);
381529766e0SElie Morisse
382529766e0SElie Morisse amd_mp2_clear_reg(privdata);
383529766e0SElie Morisse }
384529766e0SElie Morisse
385529766e0SElie Morisse #ifdef CONFIG_PM
amd_mp2_pci_suspend(struct device * dev)386529766e0SElie Morisse static int amd_mp2_pci_suspend(struct device *dev)
387529766e0SElie Morisse {
388529766e0SElie Morisse struct pci_dev *pci_dev = to_pci_dev(dev);
389529766e0SElie Morisse struct amd_mp2_dev *privdata = pci_get_drvdata(pci_dev);
390529766e0SElie Morisse struct amd_i2c_common *i2c_common;
391529766e0SElie Morisse unsigned int bus_id;
392529766e0SElie Morisse int ret = 0;
393529766e0SElie Morisse
394529766e0SElie Morisse for (bus_id = 0; bus_id < 2; bus_id++) {
395529766e0SElie Morisse i2c_common = privdata->busses[bus_id];
396529766e0SElie Morisse if (i2c_common)
397529766e0SElie Morisse i2c_common->suspend(i2c_common);
398529766e0SElie Morisse }
399529766e0SElie Morisse
400529766e0SElie Morisse ret = pci_save_state(pci_dev);
401529766e0SElie Morisse if (ret) {
402267e82b9SRichard Neumann pci_err(pci_dev, "pci_save_state failed = %d\n", ret);
403529766e0SElie Morisse return ret;
404529766e0SElie Morisse }
405529766e0SElie Morisse
406529766e0SElie Morisse pci_disable_device(pci_dev);
407529766e0SElie Morisse return ret;
408529766e0SElie Morisse }
409529766e0SElie Morisse
amd_mp2_pci_resume(struct device * dev)410529766e0SElie Morisse static int amd_mp2_pci_resume(struct device *dev)
411529766e0SElie Morisse {
412529766e0SElie Morisse struct pci_dev *pci_dev = to_pci_dev(dev);
413529766e0SElie Morisse struct amd_mp2_dev *privdata = pci_get_drvdata(pci_dev);
414529766e0SElie Morisse struct amd_i2c_common *i2c_common;
415529766e0SElie Morisse unsigned int bus_id;
416529766e0SElie Morisse int ret = 0;
417529766e0SElie Morisse
418529766e0SElie Morisse pci_restore_state(pci_dev);
419529766e0SElie Morisse ret = pci_enable_device(pci_dev);
420529766e0SElie Morisse if (ret < 0) {
421267e82b9SRichard Neumann pci_err(pci_dev, "pci_enable_device failed = %d\n", ret);
422529766e0SElie Morisse return ret;
423529766e0SElie Morisse }
424529766e0SElie Morisse
425529766e0SElie Morisse for (bus_id = 0; bus_id < 2; bus_id++) {
426529766e0SElie Morisse i2c_common = privdata->busses[bus_id];
427529766e0SElie Morisse if (i2c_common) {
428529766e0SElie Morisse ret = i2c_common->resume(i2c_common);
429529766e0SElie Morisse if (ret < 0)
430529766e0SElie Morisse return ret;
431529766e0SElie Morisse }
432529766e0SElie Morisse }
433529766e0SElie Morisse
434529766e0SElie Morisse return ret;
435529766e0SElie Morisse }
436529766e0SElie Morisse
437529766e0SElie Morisse static UNIVERSAL_DEV_PM_OPS(amd_mp2_pci_pm_ops, amd_mp2_pci_suspend,
438529766e0SElie Morisse amd_mp2_pci_resume, NULL);
439529766e0SElie Morisse #endif /* CONFIG_PM */
440529766e0SElie Morisse
441529766e0SElie Morisse static const struct pci_device_id amd_mp2_pci_tbl[] = {
442529766e0SElie Morisse {PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2)},
443529766e0SElie Morisse {0}
444529766e0SElie Morisse };
445529766e0SElie Morisse MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
446529766e0SElie Morisse
447529766e0SElie Morisse static struct pci_driver amd_mp2_pci_driver = {
448529766e0SElie Morisse .name = "i2c_amd_mp2",
449529766e0SElie Morisse .id_table = amd_mp2_pci_tbl,
450529766e0SElie Morisse .probe = amd_mp2_pci_probe,
451529766e0SElie Morisse .remove = amd_mp2_pci_remove,
452529766e0SElie Morisse #ifdef CONFIG_PM
453529766e0SElie Morisse .driver = {
454529766e0SElie Morisse .pm = &amd_mp2_pci_pm_ops,
455529766e0SElie Morisse },
456529766e0SElie Morisse #endif
457529766e0SElie Morisse };
458529766e0SElie Morisse module_pci_driver(amd_mp2_pci_driver);
459529766e0SElie Morisse
amd_mp2_find_device(void)460529766e0SElie Morisse struct amd_mp2_dev *amd_mp2_find_device(void)
461529766e0SElie Morisse {
462529766e0SElie Morisse struct device *dev;
463529766e0SElie Morisse struct pci_dev *pci_dev;
464529766e0SElie Morisse
4656bf85ba9SSuzuki K Poulose dev = driver_find_next_device(&amd_mp2_pci_driver.driver, NULL);
466529766e0SElie Morisse if (!dev)
467529766e0SElie Morisse return NULL;
468529766e0SElie Morisse
469529766e0SElie Morisse pci_dev = to_pci_dev(dev);
470529766e0SElie Morisse return (struct amd_mp2_dev *)pci_get_drvdata(pci_dev);
471529766e0SElie Morisse }
472529766e0SElie Morisse EXPORT_SYMBOL_GPL(amd_mp2_find_device);
473529766e0SElie Morisse
474529766e0SElie Morisse MODULE_DESCRIPTION("AMD(R) PCI-E MP2 I2C Controller Driver");
475529766e0SElie Morisse MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
476529766e0SElie Morisse MODULE_AUTHOR("Elie Morisse <syniurge@gmail.com>");
477529766e0SElie Morisse MODULE_LICENSE("Dual BSD/GPL");
478