aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/Kconfig11
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-nvidia-gpu.c368
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c15
4 files changed, 387 insertions, 8 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 56ccb1ea7da5..f2c681971201 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
224 This driver can also be built as a module. If so, the module 224 This driver can also be built as a module. If so, the module
225 will be called i2c-nforce2-s4985. 225 will be called i2c-nforce2-s4985.
226 226
227config I2C_NVIDIA_GPU
228 tristate "NVIDIA GPU I2C controller"
229 depends on PCI
230 help
231 If you say yes to this option, support will be included for the
232 NVIDIA GPU I2C controller which is used to communicate with the GPU's
233 Type-C controller. This driver can also be built as a module called
234 i2c-nvidia-gpu.
235
227config I2C_SIS5595 236config I2C_SIS5595
228 tristate "SiS 5595" 237 tristate "SiS 5595"
229 depends on PCI 238 depends on PCI
@@ -752,7 +761,7 @@ config I2C_OCORES
752 761
753config I2C_OMAP 762config I2C_OMAP
754 tristate "OMAP I2C adapter" 763 tristate "OMAP I2C adapter"
755 depends on ARCH_OMAP 764 depends on ARCH_OMAP || ARCH_K3
756 default y if MACH_OMAP_H3 || MACH_OMAP_OSK 765 default y if MACH_OMAP_H3 || MACH_OMAP_OSK
757 help 766 help
758 If you say yes to this option, support will be included for the 767 If you say yes to this option, support will be included for the
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18b26af82b1c..5f0cb6915969 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_I2C_ISCH) += i2c-isch.o
19obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o 19obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o
20obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o 20obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
21obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o 21obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o
22obj-$(CONFIG_I2C_NVIDIA_GPU) += i2c-nvidia-gpu.o
22obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o 23obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
23obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o 24obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
24obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o 25obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c
new file mode 100644
index 000000000000..8822357bca0c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -0,0 +1,368 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Nvidia GPU I2C controller Driver
4 *
5 * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
6 * Author: Ajay Gupta <ajayg@nvidia.com>
7 */
8#include <linux/delay.h>
9#include <linux/i2c.h>
10#include <linux/interrupt.h>
11#include <linux/module.h>
12#include <linux/pci.h>
13#include <linux/platform_device.h>
14#include <linux/pm.h>
15#include <linux/pm_runtime.h>
16
17#include <asm/unaligned.h>
18
19/* I2C definitions */
20#define I2C_MST_CNTL 0x00
21#define I2C_MST_CNTL_GEN_START BIT(0)
22#define I2C_MST_CNTL_GEN_STOP BIT(1)
23#define I2C_MST_CNTL_CMD_READ (1 << 2)
24#define I2C_MST_CNTL_CMD_WRITE (2 << 2)
25#define I2C_MST_CNTL_BURST_SIZE_SHIFT 6
26#define I2C_MST_CNTL_GEN_NACK BIT(28)
27#define I2C_MST_CNTL_STATUS GENMASK(30, 29)
28#define I2C_MST_CNTL_STATUS_OKAY (0 << 29)
29#define I2C_MST_CNTL_STATUS_NO_ACK (1 << 29)
30#define I2C_MST_CNTL_STATUS_TIMEOUT (2 << 29)
31#define I2C_MST_CNTL_STATUS_BUS_BUSY (3 << 29)
32#define I2C_MST_CNTL_CYCLE_TRIGGER BIT(31)
33
34#define I2C_MST_ADDR 0x04
35
36#define I2C_MST_I2C0_TIMING 0x08
37#define I2C_MST_I2C0_TIMING_SCL_PERIOD_100KHZ 0x10e
38#define I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT 16
39#define I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT_MAX 255
40#define I2C_MST_I2C0_TIMING_TIMEOUT_CHECK BIT(24)
41
42#define I2C_MST_DATA 0x0c
43
44#define I2C_MST_HYBRID_PADCTL 0x20
45#define I2C_MST_HYBRID_PADCTL_MODE_I2C BIT(0)
46#define I2C_MST_HYBRID_PADCTL_I2C_SCL_INPUT_RCV BIT(14)
47#define I2C_MST_HYBRID_PADCTL_I2C_SDA_INPUT_RCV BIT(15)
48
49struct gpu_i2c_dev {
50 struct device *dev;
51 void __iomem *regs;
52 struct i2c_adapter adapter;
53 struct i2c_board_info *gpu_ccgx_ucsi;
54};
55
56static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd)
57{
58 u32 val;
59
60 /* enable I2C */
61 val = readl(i2cd->regs + I2C_MST_HYBRID_PADCTL);
62 val |= I2C_MST_HYBRID_PADCTL_MODE_I2C |
63 I2C_MST_HYBRID_PADCTL_I2C_SCL_INPUT_RCV |
64 I2C_MST_HYBRID_PADCTL_I2C_SDA_INPUT_RCV;
65 writel(val, i2cd->regs + I2C_MST_HYBRID_PADCTL);
66
67 /* enable 100KHZ mode */
68 val = I2C_MST_I2C0_TIMING_SCL_PERIOD_100KHZ;
69 val |= (I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT_MAX
70 << I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT);
71 val |= I2C_MST_I2C0_TIMING_TIMEOUT_CHECK;
72 writel(val, i2cd->regs + I2C_MST_I2C0_TIMING);
73}
74
75static int gpu_i2c_check_status(struct gpu_i2c_dev *i2cd)
76{
77 unsigned long target = jiffies + msecs_to_jiffies(1000);
78 u32 val;
79
80 do {
81 val = readl(i2cd->regs + I2C_MST_CNTL);
82 if (!(val & I2C_MST_CNTL_CYCLE_TRIGGER))
83 break;
84 if ((val & I2C_MST_CNTL_STATUS) !=
85 I2C_MST_CNTL_STATUS_BUS_BUSY)
86 break;
87 usleep_range(500, 600);
88 } while (time_is_after_jiffies(target));
89
90 if (time_is_before_jiffies(target)) {
91 dev_err(i2cd->dev, "i2c timeout error %x\n", val);
92 return -ETIME;
93 }
94
95 val = readl(i2cd->regs + I2C_MST_CNTL);
96 switch (val & I2C_MST_CNTL_STATUS) {
97 case I2C_MST_CNTL_STATUS_OKAY:
98 return 0;
99 case I2C_MST_CNTL_STATUS_NO_ACK:
100 return -EIO;
101 case I2C_MST_CNTL_STATUS_TIMEOUT:
102 return -ETIME;
103 default:
104 return 0;
105 }
106}
107
108static int gpu_i2c_read(struct gpu_i2c_dev *i2cd, u8 *data, u16 len)
109{
110 int status;
111 u32 val;
112
113 val = I2C_MST_CNTL_GEN_START | I2C_MST_CNTL_CMD_READ |
114 (len << I2C_MST_CNTL_BURST_SIZE_SHIFT) |
115 I2C_MST_CNTL_CYCLE_TRIGGER | I2C_MST_CNTL_GEN_NACK;
116 writel(val, i2cd->regs + I2C_MST_CNTL);
117
118 status = gpu_i2c_check_status(i2cd);
119 if (status < 0)
120 return status;
121
122 val = readl(i2cd->regs + I2C_MST_DATA);
123 switch (len) {
124 case 1:
125 data[0] = val;
126 break;
127 case 2:
128 put_unaligned_be16(val, data);
129 break;
130 case 3:
131 put_unaligned_be16(val >> 8, data);
132 data[2] = val;
133 break;
134 case 4:
135 put_unaligned_be32(val, data);
136 break;
137 default:
138 break;
139 }
140 return status;
141}
142
143static int gpu_i2c_start(struct gpu_i2c_dev *i2cd)
144{
145 writel(I2C_MST_CNTL_GEN_START, i2cd->regs + I2C_MST_CNTL);
146 return gpu_i2c_check_status(i2cd);
147}
148
149static int gpu_i2c_stop(struct gpu_i2c_dev *i2cd)
150{
151 writel(I2C_MST_CNTL_GEN_STOP, i2cd->regs + I2C_MST_CNTL);
152 return gpu_i2c_check_status(i2cd);
153}
154
155static int gpu_i2c_write(struct gpu_i2c_dev *i2cd, u8 data)
156{
157 u32 val;
158
159 writel(data, i2cd->regs + I2C_MST_DATA);
160
161 val = I2C_MST_CNTL_CMD_WRITE | (1 << I2C_MST_CNTL_BURST_SIZE_SHIFT);
162 writel(val, i2cd->regs + I2C_MST_CNTL);
163
164 return gpu_i2c_check_status(i2cd);
165}
166
167static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
168 struct i2c_msg *msgs, int num)
169{
170 struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap);
171 int status, status2;
172 int i, j;
173
174 /*
175 * The controller supports maximum 4 byte read due to known
176 * limitation of sending STOP after every read.
177 */
178 for (i = 0; i < num; i++) {
179 if (msgs[i].flags & I2C_M_RD) {
180 /* program client address before starting read */
181 writel(msgs[i].addr, i2cd->regs + I2C_MST_ADDR);
182 /* gpu_i2c_read has implicit start */
183 status = gpu_i2c_read(i2cd, msgs[i].buf, msgs[i].len);
184 if (status < 0)
185 goto stop;
186 } else {
187 u8 addr = i2c_8bit_addr_from_msg(msgs + i);
188
189 status = gpu_i2c_start(i2cd);
190 if (status < 0) {
191 if (i == 0)
192 return status;
193 goto stop;
194 }
195
196 status = gpu_i2c_write(i2cd, addr);
197 if (status < 0)
198 goto stop;
199
200 for (j = 0; j < msgs[i].len; j++) {
201 status = gpu_i2c_write(i2cd, msgs[i].buf[j]);
202 if (status < 0)
203 goto stop;
204 }
205 }
206 }
207 status = gpu_i2c_stop(i2cd);
208 if (status < 0)
209 return status;
210
211 return i;
212stop:
213 status2 = gpu_i2c_stop(i2cd);
214 if (status2 < 0)
215 dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
216 return status;
217}
218
219static const struct i2c_adapter_quirks gpu_i2c_quirks = {
220 .max_read_len = 4,
221 .flags = I2C_AQ_COMB_WRITE_THEN_READ,
222};
223
224static u32 gpu_i2c_functionality(struct i2c_adapter *adap)
225{
226 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
227}
228
229static const struct i2c_algorithm gpu_i2c_algorithm = {
230 .master_xfer = gpu_i2c_master_xfer,
231 .functionality = gpu_i2c_functionality,
232};
233
234/*
235 * This driver is for Nvidia GPU cards with USB Type-C interface.
236 * We want to identify the cards using vendor ID and class code only
237 * to avoid dependency of adding product id for any new card which
238 * requires this driver.
239 * Currently there is no class code defined for UCSI device over PCI
240 * so using UNKNOWN class for now and it will be updated when UCSI
241 * over PCI gets a class code.
242 * There is no other NVIDIA cards with UNKNOWN class code. Even if the
243 * driver gets loaded for an undesired card then eventually i2c_read()
244 * (initiated from UCSI i2c_client) will timeout or UCSI commands will
245 * timeout.
246 */
247#define PCI_CLASS_SERIAL_UNKNOWN 0x0c80
248static const struct pci_device_id gpu_i2c_ids[] = {
249 { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
250 PCI_CLASS_SERIAL_UNKNOWN << 8, 0xffffff00},
251 { }
252};
253MODULE_DEVICE_TABLE(pci, gpu_i2c_ids);
254
255static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
256{
257 struct i2c_client *ccgx_client;
258
259 i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev,
260 sizeof(*i2cd->gpu_ccgx_ucsi),
261 GFP_KERNEL);
262 if (!i2cd->gpu_ccgx_ucsi)
263 return -ENOMEM;
264
265 strlcpy(i2cd->gpu_ccgx_ucsi->type, "ccgx-ucsi",
266 sizeof(i2cd->gpu_ccgx_ucsi->type));
267 i2cd->gpu_ccgx_ucsi->addr = 0x8;
268 i2cd->gpu_ccgx_ucsi->irq = irq;
269 ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
270 if (!ccgx_client)
271 return -ENODEV;
272
273 return 0;
274}
275
276static int gpu_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
277{
278 struct gpu_i2c_dev *i2cd;
279 int status;
280
281 i2cd = devm_kzalloc(&pdev->dev, sizeof(*i2cd), GFP_KERNEL);
282 if (!i2cd)
283 return -ENOMEM;
284
285 i2cd->dev = &pdev->dev;
286 dev_set_drvdata(&pdev->dev, i2cd);
287
288 status = pcim_enable_device(pdev);
289 if (status < 0) {
290 dev_err(&pdev->dev, "pcim_enable_device failed %d\n", status);
291 return status;
292 }
293
294 pci_set_master(pdev);
295
296 i2cd->regs = pcim_iomap(pdev, 0, 0);
297 if (!i2cd->regs) {
298 dev_err(&pdev->dev, "pcim_iomap failed\n");
299 return -ENOMEM;
300 }
301
302 status = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
303 if (status < 0) {
304 dev_err(&pdev->dev, "pci_alloc_irq_vectors err %d\n", status);
305 return status;
306 }
307
308 gpu_enable_i2c_bus(i2cd);
309
310 i2c_set_adapdata(&i2cd->adapter, i2cd);
311 i2cd->adapter.owner = THIS_MODULE;
312 strlcpy(i2cd->adapter.name, "NVIDIA GPU I2C adapter",
313 sizeof(i2cd->adapter.name));
314 i2cd->adapter.algo = &gpu_i2c_algorithm;
315 i2cd->adapter.quirks = &gpu_i2c_quirks;
316 i2cd->adapter.dev.parent = &pdev->dev;
317 status = i2c_add_adapter(&i2cd->adapter);
318 if (status < 0)
319 goto free_irq_vectors;
320
321 status = gpu_populate_client(i2cd, pdev->irq);
322 if (status < 0) {
323 dev_err(&pdev->dev, "gpu_populate_client failed %d\n", status);
324 goto del_adapter;
325 }
326
327 return 0;
328
329del_adapter:
330 i2c_del_adapter(&i2cd->adapter);
331free_irq_vectors:
332 pci_free_irq_vectors(pdev);
333 return status;
334}
335
336static void gpu_i2c_remove(struct pci_dev *pdev)
337{
338 struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev);
339
340 i2c_del_adapter(&i2cd->adapter);
341 pci_free_irq_vectors(pdev);
342}
343
344static int gpu_i2c_resume(struct device *dev)
345{
346 struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
347
348 gpu_enable_i2c_bus(i2cd);
349 return 0;
350}
351
352static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume, NULL);
353
354static struct pci_driver gpu_i2c_driver = {
355 .name = "nvidia-gpu",
356 .id_table = gpu_i2c_ids,
357 .probe = gpu_i2c_probe,
358 .remove = gpu_i2c_remove,
359 .driver = {
360 .pm = &gpu_i2c_driver_pm,
361 },
362};
363
364module_pci_driver(gpu_i2c_driver);
365
366MODULE_AUTHOR("Ajay Gupta <ajayg@nvidia.com>");
367MODULE_DESCRIPTION("Nvidia GPU I2C controller Driver");
368MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 527f55c8c4c7..db075bc0d952 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -571,18 +571,19 @@ static int geni_i2c_probe(struct platform_device *pdev)
571 571
572 dev_dbg(&pdev->dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth); 572 dev_dbg(&pdev->dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
573 573
574 ret = i2c_add_adapter(&gi2c->adap);
575 if (ret) {
576 dev_err(&pdev->dev, "Error adding i2c adapter %d\n", ret);
577 return ret;
578 }
579
580 gi2c->suspended = 1; 574 gi2c->suspended = 1;
581 pm_runtime_set_suspended(gi2c->se.dev); 575 pm_runtime_set_suspended(gi2c->se.dev);
582 pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY); 576 pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY);
583 pm_runtime_use_autosuspend(gi2c->se.dev); 577 pm_runtime_use_autosuspend(gi2c->se.dev);
584 pm_runtime_enable(gi2c->se.dev); 578 pm_runtime_enable(gi2c->se.dev);
585 579
580 ret = i2c_add_adapter(&gi2c->adap);
581 if (ret) {
582 dev_err(&pdev->dev, "Error adding i2c adapter %d\n", ret);
583 pm_runtime_disable(gi2c->se.dev);
584 return ret;
585 }
586
586 return 0; 587 return 0;
587} 588}
588 589
@@ -590,8 +591,8 @@ static int geni_i2c_remove(struct platform_device *pdev)
590{ 591{
591 struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); 592 struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
592 593
593 pm_runtime_disable(gi2c->se.dev);
594 i2c_del_adapter(&gi2c->adap); 594 i2c_del_adapter(&gi2c->adap);
595 pm_runtime_disable(gi2c->se.dev);
595 return 0; 596 return 0;
596} 597}
597 598