xref: /linux/drivers/i2c/busses/i2c-amd-mp2-pci.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
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