Line data Source code
1 : /* $OpenBSD: dwiic_pci.c,v 1.3 2018/01/12 08:11:48 mlarkin Exp $ */
2 : /*
3 : * Synopsys DesignWare I2C controller
4 : * PCI attachment
5 : *
6 : * Copyright (c) 2015-2017 joshua stein <jcs@openbsd.org>
7 : *
8 : * Permission to use, copy, modify, and/or distribute this software for any
9 : * purpose with or without fee is hereby granted, provided that the above
10 : * copyright notice and this permission notice appear in all copies.
11 : *
12 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 : */
20 :
21 : #include <sys/param.h>
22 : #include <sys/systm.h>
23 : #include <sys/kernel.h>
24 : #include <sys/kthread.h>
25 :
26 : #include <dev/pci/pcidevs.h>
27 : #include <dev/pci/pcireg.h>
28 : #include <dev/pci/pcivar.h>
29 :
30 : #include <dev/ic/dwiicvar.h>
31 :
32 : /* 13.3: I2C Additional Registers Summary */
33 : #define LPSS_RESETS 0x204
34 : #define LPSS_RESETS_I2C (1 << 0) | (1 << 1)
35 : #define LPSS_RESETS_IDMA (1 << 2)
36 : #define LPSS_ACTIVELTR 0x210
37 : #define LPSS_IDLELTR 0x214
38 : #define LPSS_CAPS 0x2fc
39 : #define LPSS_CAPS_NO_IDMA (1 << 8)
40 : #define LPSS_CAPS_TYPE_SHIFT 4
41 : #define LPSS_CAPS_TYPE_MASK (0xf << LPSS_CAPS_TYPE_SHIFT)
42 :
43 : int dwiic_pci_match(struct device *, void *, void *);
44 : void dwiic_pci_attach(struct device *, struct device *, void *);
45 : int dwiic_pci_activate(struct device *, int);
46 : void dwiic_pci_bus_scan(struct device *,
47 : struct i2cbus_attach_args *, void *);
48 :
49 : #include "acpi.h"
50 : #if NACPI > 0
51 : struct aml_node *acpi_pci_match(struct device *dev, struct pci_attach_args *pa);
52 : #endif
53 :
54 : struct cfattach dwiic_pci_ca = {
55 : sizeof(struct dwiic_softc),
56 : dwiic_pci_match,
57 : dwiic_pci_attach,
58 : NULL,
59 : dwiic_pci_activate,
60 : };
61 :
62 : const struct pci_matchid dwiic_pci_ids[] = {
63 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_I2C_1 },
64 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_I2C_2 },
65 : };
66 :
67 : int
68 0 : dwiic_pci_match(struct device *parent, void *match, void *aux)
69 : {
70 0 : return (pci_matchbyid(aux, dwiic_pci_ids, nitems(dwiic_pci_ids)));
71 : }
72 :
73 : void
74 0 : dwiic_pci_attach(struct device *parent, struct device *self, void *aux)
75 : {
76 0 : struct dwiic_softc *sc = (struct dwiic_softc *)self;
77 0 : struct pci_attach_args *pa = aux;
78 0 : bus_size_t iosize;
79 0 : pci_intr_handle_t ih;
80 : const char *intrstr = NULL;
81 : uint8_t type;
82 :
83 0 : memcpy(&sc->sc_paa, pa, sizeof(sc->sc_paa));
84 :
85 0 : pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D0);
86 :
87 0 : if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_MEM_TYPE_64BIT, 0,
88 0 : &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
89 0 : printf(": can't map mem space\n");
90 0 : return;
91 : }
92 :
93 0 : sc->sc_caps = bus_space_read_4(sc->sc_iot, sc->sc_ioh, LPSS_CAPS);
94 0 : type = sc->sc_caps & LPSS_CAPS_TYPE_MASK;
95 0 : type >>= LPSS_CAPS_TYPE_SHIFT;
96 0 : if (type != 0) {
97 0 : printf(": type %d not supported\n", type);
98 0 : return;
99 : }
100 :
101 : /* un-reset - page 958 */
102 0 : bus_space_write_4(sc->sc_iot, sc->sc_ioh, LPSS_RESETS,
103 : (LPSS_RESETS_I2C | LPSS_RESETS_IDMA));
104 :
105 : /* fetch timing parameters */
106 0 : sc->ss_hcnt = dwiic_read(sc, DW_IC_SS_SCL_HCNT);
107 0 : sc->ss_lcnt = dwiic_read(sc, DW_IC_SS_SCL_LCNT);
108 0 : sc->fs_hcnt = dwiic_read(sc, DW_IC_FS_SCL_HCNT);
109 0 : sc->fs_lcnt = dwiic_read(sc, DW_IC_FS_SCL_LCNT);
110 0 : sc->sda_hold_time = dwiic_read(sc, DW_IC_SDA_HOLD);
111 :
112 0 : if (dwiic_init(sc)) {
113 0 : printf(": failed initializing\n");
114 0 : return;
115 : }
116 :
117 : /* leave the controller disabled */
118 0 : dwiic_write(sc, DW_IC_INTR_MASK, 0);
119 0 : dwiic_enable(sc, 0);
120 0 : dwiic_read(sc, DW_IC_CLR_INTR);
121 :
122 : /* install interrupt handler */
123 0 : sc->sc_poll = 1;
124 0 : if (pci_intr_map(&sc->sc_paa, &ih) == 0) {
125 0 : intrstr = pci_intr_string(sc->sc_paa.pa_pc, ih);
126 0 : sc->sc_ih = pci_intr_establish(sc->sc_paa.pa_pc, ih, IPL_BIO,
127 0 : dwiic_intr, sc, sc->sc_dev.dv_xname);
128 0 : if (sc->sc_ih != NULL) {
129 0 : printf(": %s", intrstr);
130 0 : sc->sc_poll = 0;
131 0 : }
132 : }
133 0 : if (sc->sc_poll)
134 0 : printf(": polling");
135 :
136 0 : printf("\n");
137 :
138 0 : rw_init(&sc->sc_i2c_lock, "iiclk");
139 :
140 : /* setup and attach iic bus */
141 0 : sc->sc_i2c_tag.ic_cookie = sc;
142 0 : sc->sc_i2c_tag.ic_acquire_bus = dwiic_i2c_acquire_bus;
143 0 : sc->sc_i2c_tag.ic_release_bus = dwiic_i2c_release_bus;
144 0 : sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec;
145 0 : sc->sc_i2c_tag.ic_intr_establish = dwiic_i2c_intr_establish;
146 0 : sc->sc_i2c_tag.ic_intr_string = dwiic_i2c_intr_string;
147 :
148 0 : bzero(&sc->sc_iba, sizeof(sc->sc_iba));
149 0 : sc->sc_iba.iba_name = "iic";
150 0 : sc->sc_iba.iba_tag = &sc->sc_i2c_tag;
151 0 : sc->sc_iba.iba_bus_scan = dwiic_pci_bus_scan;
152 0 : sc->sc_iba.iba_bus_scan_arg = sc;
153 :
154 0 : config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
155 :
156 0 : return;
157 0 : }
158 :
159 : int
160 0 : dwiic_pci_activate(struct device *self, int act)
161 : {
162 0 : struct dwiic_softc *sc = (struct dwiic_softc *)self;
163 :
164 0 : switch (act) {
165 : case DVACT_WAKEUP:
166 0 : bus_space_write_4(sc->sc_iot, sc->sc_ioh, LPSS_RESETS,
167 : (LPSS_RESETS_I2C | LPSS_RESETS_IDMA));
168 :
169 0 : dwiic_init(sc);
170 :
171 0 : break;
172 : }
173 :
174 0 : dwiic_activate(self, act);
175 :
176 0 : return 0;
177 : }
178 :
179 : void
180 0 : dwiic_pci_bus_scan(struct device *iic, struct i2cbus_attach_args *iba,
181 : void *aux)
182 : {
183 0 : struct dwiic_softc *sc = (struct dwiic_softc *)aux;
184 :
185 0 : sc->sc_iic = iic;
186 :
187 : #if NACPI > 0
188 : {
189 0 : struct aml_node *node = acpi_pci_match(aux, &sc->sc_paa);
190 0 : if (node == NULL)
191 0 : return;
192 :
193 : /*
194 : * XXX: until we can figure out why interrupts don't arrive for
195 : * i2c slave devices on intel 100 series and newer, force
196 : * polling for ihidev.
197 : */
198 0 : sc->sc_poll_ihidev = 1;
199 :
200 0 : aml_find_node(node, "_HID", dwiic_acpi_found_hid, sc);
201 0 : }
202 : #endif
203 0 : }
|