1 // SPDX-License-Identifier: GPL-2.0
4 * This file is provided under a dual BSD/GPLv2 license. When using or
5 * redistributing this file, you may do so under either license.
9 * Copyright (C) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
17 * Copyright (C) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
23 * * Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * * Redistributions in binary form must reproduce the above copy
26 * notice, this list of conditions and the following disclaimer in
27 * the documentation and/or other materials provided with the
29 * * Neither the name of AMD Corporation nor the names of its
30 * contributors may be used to endorse or promote products derived
31 * from this software without specific prior written permission.
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
34 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
35 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
36 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
37 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
40 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
41 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
43 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 * AMD I2C Platform Driver
47 * Author: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
50 #include <linux/kernel.h>
51 #include <linux/module.h>
52 #include <linux/types.h>
53 #include <linux/slab.h>
54 #include <linux/i2c.h>
55 #include <linux/platform_device.h>
56 #include <linux/acpi.h>
57 #include <linux/delay.h>
58 #include "i2c-amd-pci-mp2.h"
59 #include <linux/dma-mapping.h>
60 #define DRIVER_NAME "AMD-I2C-PLATDRV"
63 struct platform_device
*pdev
;
64 struct i2c_adapter adapter
;
65 struct amd_i2c_common i2c_common
;
66 struct completion msg_complete
;
67 struct i2c_msg
*msg_buf
;
74 static int i2c_amd_read_completion(union i2c_event_base event
, void *dev_ctx
)
76 struct amd_i2c_dev
*i2c_dev
= (struct amd_i2c_dev
*)dev_ctx
;
77 struct amd_i2c_common
*commond
= &i2c_dev
->i2c_common
;
80 if (event
.r
.status
== i2c_readcomplete_event
) {
81 if (event
.r
.length
<= 32) {
82 pr_devel(" in %s i2c_dev->msg_buf :%p\n",
83 __func__
, i2c_dev
->msg_buf
);
85 memcpy(i2c_dev
->msg_buf
->buf
,
86 (unsigned char *)event
.buf
, event
.r
.length
);
88 for (i
= 0; i
< ((event
.r
.length
+ 3) / 4); i
++)
89 pr_devel("%s:%s readdata:%x\n",
90 DRIVER_NAME
, __func__
, event
.buf
[i
]);
93 memcpy(i2c_dev
->msg_buf
->buf
,
94 (unsigned char *)commond
->read_cfg
.buf
,
96 pr_devel("%s:%s virt:%llx phy_addr:%llx\n",
97 DRIVER_NAME
, __func__
,
98 (u64
)commond
->read_cfg
.buf
,
99 (u64
)commond
->read_cfg
.phy_addr
);
101 for (i
= 0; i
< ((event
.r
.length
+ 3) / 4); i
++)
102 pr_devel("%s:%s readdata:%x\n",
103 DRIVER_NAME
, __func__
, ((unsigned int *)
104 commond
->read_cfg
.buf
)[i
]);
107 complete(&i2c_dev
->msg_complete
);
113 static int i2c_amd_write_completion(union i2c_event_base event
, void *dev_ctx
)
115 struct amd_i2c_dev
*i2c_dev
= (struct amd_i2c_dev
*)dev_ctx
;
117 if (event
.r
.status
== i2c_writecomplete_event
)
118 complete(&i2c_dev
->msg_complete
);
123 static int i2c_amd_connect_completion(union i2c_event_base event
, void *dev_ctx
)
125 struct amd_i2c_dev
*i2c_dev
= (struct amd_i2c_dev
*)dev_ctx
;
127 if (event
.r
.status
== i2c_busenable_complete
)
128 complete(&i2c_dev
->msg_complete
);
133 static const struct amd_i2c_pci_ops data_handler
= {
134 .read_complete
= i2c_amd_read_completion
,
135 .write_complete
= i2c_amd_write_completion
,
136 .connect_complete
= i2c_amd_connect_completion
,
139 static int i2c_amd_pci_configure(struct amd_i2c_dev
*i2c_dev
, int slaveaddr
)
141 struct amd_i2c_common
*i2c_common
= &i2c_dev
->i2c_common
;
144 amd_i2c_register_cb(i2c_common
->pdev
, &data_handler
, (void *)i2c_dev
);
145 i2c_common
->connect_cfg
.bus_id
= i2c_dev
->bus_id
;
146 i2c_common
->connect_cfg
.dev_addr
= slaveaddr
;
147 i2c_common
->connect_cfg
.i2c_speed
= speed400k
;
149 ret
= amd_mp2_connect(i2c_common
->pdev
, i2c_common
->connect_cfg
);
155 i2c_common
->write_cfg
.bus_id
= i2c_dev
->bus_id
;
156 i2c_common
->write_cfg
.dev_addr
= slaveaddr
;
157 i2c_common
->write_cfg
.i2c_speed
= speed400k
;
159 i2c_common
->read_cfg
.bus_id
= i2c_dev
->bus_id
;
160 i2c_common
->read_cfg
.dev_addr
= slaveaddr
;
161 i2c_common
->read_cfg
.i2c_speed
= speed400k
;
166 static int i2c_amd_xfer(struct i2c_adapter
*adap
, struct i2c_msg
*msgs
, int num
)
168 struct amd_i2c_dev
*dev
= i2c_get_adapdata(adap
);
169 struct amd_i2c_common
*i2c_common
= &dev
->i2c_common
;
172 unsigned long timeout
;
173 struct i2c_msg
*pmsg
;
174 unsigned char *dma_buf
= NULL
;
178 reinit_completion(&dev
->msg_complete
);
179 if (dev
->is_configured
== 0) {
180 i2c_amd_pci_configure(dev
, msgs
->addr
);
181 timeout
= wait_for_completion_timeout(&dev
->msg_complete
, 50);
182 dev
->is_configured
= 1;
185 for (i
= 0; i
< num
; i
++) {
187 if (pmsg
->flags
& I2C_M_RD
) {
188 if (pmsg
->len
<= 32) {
189 i2c_common
->read_cfg
.buf
= dev
->buf
;
190 i2c_common
->read_cfg
.length
= pmsg
->len
;
191 i2c_common
->read_cfg
.phy_addr
=
192 virt_to_phys(dev
->buf
);
194 dma_buf
= (u8
*)dma_alloc_coherent(&i2c_common
->pdev
->dev
,
195 pmsg
->len
, &phys
, GFP_KERNEL
);
200 i2c_common
->read_cfg
.buf
= dma_buf
;
201 i2c_common
->read_cfg
.length
= pmsg
->len
;
202 i2c_common
->read_cfg
.phy_addr
= phys
;
205 amd_mp2_read(i2c_common
->pdev
,
206 i2c_common
->read_cfg
);
207 timeout
= wait_for_completion_timeout
208 (&dev
->msg_complete
, 50);
209 if (pmsg
->len
> 32 && dma_buf
)
210 dma_free_coherent(&i2c_common
->pdev
->dev
,
211 pmsg
->len
, dma_buf
, phys
);
214 i2c_common
->write_cfg
.buf
= (unsigned int *)pmsg
->buf
;
215 i2c_common
->write_cfg
.length
= pmsg
->len
;
216 amd_mp2_write(i2c_common
->pdev
,
217 i2c_common
->write_cfg
);
219 timeout
= wait_for_completion_timeout
220 (&dev
->msg_complete
, 50);
226 static u32
i2c_amd_func(struct i2c_adapter
*a
)
231 static const struct i2c_algorithm i2c_amd_algorithm
= {
232 .master_xfer
= i2c_amd_xfer
,
233 .functionality
= i2c_amd_func
,
236 static int i2c_amd_probe(struct platform_device
*pdev
)
239 struct amd_i2c_dev
*i2c_dev
;
240 struct device
*dev
= &pdev
->dev
;
241 acpi_handle handle
= ACPI_HANDLE(&pdev
->dev
);
242 struct acpi_device
*adev
;
243 const char *uid
= NULL
;
245 i2c_dev
= devm_kzalloc(dev
, sizeof(*i2c_dev
), GFP_KERNEL
);
249 i2c_dev
->pdev
= pdev
;
251 if (!acpi_bus_get_device(handle
, &adev
)) {
252 pr_err(" i2c0 pdev->id=%s\n", adev
->pnp
.unique_id
);
253 uid
= adev
->pnp
.unique_id
;
256 if (strcmp(uid
, "0") == 0) {
257 pr_err(" bus id is 0\n");
261 pr_devel(" i2c1 pdev->id=%s\n", uid
);
262 if (strcmp(uid
, "1") == 0) {
263 pr_err(" bus id is 1\n");
266 /* setup i2c adapter description */
267 i2c_dev
->adapter
.owner
= THIS_MODULE
;
268 i2c_dev
->adapter
.algo
= &i2c_amd_algorithm
;
269 i2c_dev
->adapter
.dev
.parent
= dev
;
270 i2c_dev
->adapter
.algo_data
= i2c_dev
;
271 ACPI_COMPANION_SET(&i2c_dev
->adapter
.dev
, ACPI_COMPANION(&pdev
->dev
));
272 i2c_dev
->adapter
.dev
.of_node
= dev
->of_node
;
273 snprintf(i2c_dev
->adapter
.name
, sizeof(i2c_dev
->adapter
.name
), "%s-%s",
274 "i2c_dev-i2c", dev_name(pdev
->dev
.parent
));
276 i2c_dev
->i2c_common
.pdev
= pci_get_device(PCI_VENDOR_ID_AMD
,
277 PCI_DEVICE_ID_AMD_MP2
, NULL
);
279 if (!i2c_dev
->i2c_common
.pdev
) {
280 pr_err("%s Could not find pdev in i2c\n", __func__
);
283 i2c_dev
->buf
= kzalloc(32, GFP_KERNEL
);
288 platform_set_drvdata(pdev
, i2c_dev
);
290 i2c_set_adapdata(&i2c_dev
->adapter
, i2c_dev
);
292 init_completion(&i2c_dev
->msg_complete
);
293 /* and finally attach to i2c layer */
294 ret
= i2c_add_adapter(&i2c_dev
->adapter
);
297 pr_err(" i2c add adpater failed =%d", ret
);
302 static int i2c_amd_remove(struct platform_device
*pdev
)
304 struct amd_i2c_dev
*i2c_dev
= platform_get_drvdata(pdev
);
307 i2c_del_adapter(&i2c_dev
->adapter
);
312 static const struct acpi_device_id i2c_amd_acpi_match
[] = {
317 static struct platform_driver amd_i2c_plat_driver
= {
318 .probe
= i2c_amd_probe
,
319 .remove
= i2c_amd_remove
,
321 .name
= "i2c_amd_platdrv",
322 .acpi_match_table
= ACPI_PTR
323 (i2c_amd_acpi_match
),
327 module_platform_driver(amd_i2c_plat_driver
);
329 MODULE_AUTHOR("Nehal Shah <nehal-bakulchandra.shah@amd.com>");
330 MODULE_DESCRIPTION("AMD I2C Platform Driver");
331 MODULE_LICENSE("Dual BSD/GPL");