i2c: designware: Support use in SPL
[oweals/u-boot.git] / drivers / i2c / designware_i2c_pci.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2009
4  * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
5  * Copyright 2019 Google Inc
6  */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <spl.h>
11 #include "designware_i2c.h"
12
13 /* BayTrail HCNT/LCNT/SDA hold time */
14 static struct dw_scl_sda_cfg byt_config = {
15         .ss_hcnt = 0x200,
16         .fs_hcnt = 0x55,
17         .ss_lcnt = 0x200,
18         .fs_lcnt = 0x99,
19         .sda_hold = 0x6,
20 };
21
22 static int designware_i2c_pci_ofdata_to_platdata(struct udevice *dev)
23 {
24         struct dw_i2c *priv = dev_get_priv(dev);
25
26         if (spl_phase() < PHASE_SPL) {
27                 u32 base;
28                 int ret;
29
30                 ret = dev_read_u32(dev, "early-regs", &base);
31                 if (ret)
32                         return log_msg_ret("early-regs", ret);
33
34                 /* Set i2c base address */
35                 dm_pci_write_config32(dev, PCI_BASE_ADDRESS_0, base);
36
37                 /* Enable memory access and bus master */
38                 dm_pci_write_config32(dev, PCI_COMMAND, PCI_COMMAND_MEMORY |
39                                       PCI_COMMAND_MASTER);
40         }
41
42         if (spl_phase() < PHASE_BOARD_F) {
43                 /* Handle early, fixed mapping into a different address space */
44                 priv->regs = (struct i2c_regs *)dm_pci_read_bar32(dev, 0);
45         } else {
46                 priv->regs = (struct i2c_regs *)
47                         dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
48         }
49         if (!priv->regs)
50                 return -EINVAL;
51
52         /* Save base address from PCI BAR */
53         if (IS_ENABLED(CONFIG_INTEL_BAYTRAIL))
54                 /* Use BayTrail specific timing values */
55                 priv->scl_sda_cfg = &byt_config;
56
57         return 0;
58 }
59
60 static int designware_i2c_pci_probe(struct udevice *dev)
61 {
62         return designware_i2c_probe(dev);
63 }
64
65 static int designware_i2c_pci_bind(struct udevice *dev)
66 {
67         char name[20];
68
69         /*
70          * Create a unique device name for PCI type devices
71          * ToDo:
72          * Setting req_seq in the driver is probably not recommended.
73          * But without a DT alias the number is not configured. And
74          * using this driver is impossible for PCIe I2C devices.
75          * This can be removed, once a better (correct) way for this
76          * is found and implemented.
77          *
78          * TODO(sjg@chromium.org): Perhaps if uclasses had platdata this would
79          * be possible. We cannot use static data in drivers since they may be
80          * used in SPL or before relocation.
81          */
82         dev->req_seq = gd->arch.dw_i2c_num_cards++;
83         sprintf(name, "i2c_designware#%u", dev->req_seq);
84         device_set_name(dev, name);
85
86         return 0;
87 }
88
89 static const struct udevice_id designware_i2c_pci_ids[] = {
90         { .compatible = "snps,designware-i2c-pci" },
91         { }
92 };
93
94 U_BOOT_DRIVER(i2c_designware_pci) = {
95         .name   = "i2c_designware_pci",
96         .id     = UCLASS_I2C,
97         .of_match = designware_i2c_pci_ids,
98         .bind   = designware_i2c_pci_bind,
99         .ofdata_to_platdata     = designware_i2c_pci_ofdata_to_platdata,
100         .probe  = designware_i2c_pci_probe,
101         .priv_auto_alloc_size = sizeof(struct dw_i2c),
102         .remove = designware_i2c_remove,
103         .flags = DM_FLAG_OS_PREPARE,
104         .ops    = &designware_i2c_ops,
105 };
106
107 static struct pci_device_id designware_pci_supported[] = {
108         /* Intel BayTrail has 7 I2C controller located on the PCI bus */
109         { PCI_VDEVICE(INTEL, 0x0f41) },
110         { PCI_VDEVICE(INTEL, 0x0f42) },
111         { PCI_VDEVICE(INTEL, 0x0f43) },
112         { PCI_VDEVICE(INTEL, 0x0f44) },
113         { PCI_VDEVICE(INTEL, 0x0f45) },
114         { PCI_VDEVICE(INTEL, 0x0f46) },
115         { PCI_VDEVICE(INTEL, 0x0f47) },
116         {},
117 };
118
119 U_BOOT_PCI_DEVICE(i2c_designware_pci, designware_pci_supported);