xref: /openbsd/sys/dev/pci/dwiic_pci.c (revision 4cfece93)
1 /* $OpenBSD: dwiic_pci.c,v 1.10 2020/02/18 12:13:40 mpi 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 
25 #include <dev/pci/pcidevs.h>
26 #include <dev/pci/pcireg.h>
27 #include <dev/pci/pcivar.h>
28 
29 #include <dev/ic/dwiicvar.h>
30 
31 /* 13.3: I2C Additional Registers Summary */
32 #define LPSS_RESETS		0x204
33 #define  LPSS_RESETS_I2C	(1 << 0) | (1 << 1)
34 #define  LPSS_RESETS_IDMA	(1 << 2)
35 #define LPSS_ACTIVELTR		0x210
36 #define LPSS_IDLELTR		0x214
37 #define LPSS_CAPS		0x2fc
38 #define  LPSS_CAPS_NO_IDMA	(1 << 8)
39 #define  LPSS_CAPS_TYPE_SHIFT	4
40 #define  LPSS_CAPS_TYPE_MASK	(0xf << LPSS_CAPS_TYPE_SHIFT)
41 
42 int		dwiic_pci_match(struct device *, void *, void *);
43 void		dwiic_pci_attach(struct device *, struct device *, void *);
44 int		dwiic_pci_activate(struct device *, int);
45 void		dwiic_pci_bus_scan(struct device *,
46 		    struct i2cbus_attach_args *, void *);
47 
48 #include "acpi.h"
49 #if NACPI > 0
50 struct aml_node *acpi_pci_match(struct device *dev, struct pci_attach_args *pa);
51 #endif
52 
53 struct cfattach dwiic_pci_ca = {
54 	sizeof(struct dwiic_softc),
55 	dwiic_pci_match,
56 	dwiic_pci_attach,
57 	NULL,
58 	dwiic_pci_activate,
59 };
60 
61 const struct pci_matchid dwiic_pci_ids[] = {
62 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_I2C_1 },
63 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_I2C_2 },
64 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_I2C0 },
65 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_I2C1 },
66 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_I2C_1 },
67 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_I2C_2 },
68 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_I2C_3 },
69 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_I2C_4 },
70 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_I2C_5 },
71 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_300SERIES_U_I2C_6 },
72 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_1 },
73 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_2 },
74 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_3 },
75 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_4 },
76 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_5 },
77 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_6 },
78 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_7 },
79 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_I2C_8 },
80 };
81 
82 int
83 dwiic_pci_match(struct device *parent, void *match, void *aux)
84 {
85 	return (pci_matchbyid(aux, dwiic_pci_ids, nitems(dwiic_pci_ids)));
86 }
87 
88 void
89 dwiic_pci_attach(struct device *parent, struct device *self, void *aux)
90 {
91 	struct dwiic_softc *sc = (struct dwiic_softc *)self;
92 	struct pci_attach_args *pa = aux;
93 #if NACPI > 0
94 	struct aml_node *node;
95 #endif
96 	bus_size_t iosize;
97 	pci_intr_handle_t ih;
98 	const char *intrstr = NULL;
99 	uint8_t type;
100 
101 	memcpy(&sc->sc_paa, pa, sizeof(sc->sc_paa));
102 
103 	pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D0);
104 
105 	if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_MEM_TYPE_64BIT, 0,
106 	    &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
107 		printf(": can't map mem space\n");
108 		return;
109 	}
110 
111 	sc->sc_caps = bus_space_read_4(sc->sc_iot, sc->sc_ioh, LPSS_CAPS);
112 	type = sc->sc_caps & LPSS_CAPS_TYPE_MASK;
113 	type >>= LPSS_CAPS_TYPE_SHIFT;
114 	if (type != 0) {
115 		printf(": type %d not supported\n", type);
116 		return;
117 	}
118 
119 	/* un-reset - page 958 */
120 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, LPSS_RESETS,
121 	    (LPSS_RESETS_I2C | LPSS_RESETS_IDMA));
122 
123 #if NACPI > 0
124 	/* fetch timing parameters from ACPI, if possible */
125 	node = acpi_pci_match(self, &sc->sc_paa);
126 	if (node != NULL) {
127 		sc->sc_devnode = node;
128 
129 		dwiic_acpi_get_params(sc, "SSCN", &sc->ss_hcnt, &sc->ss_lcnt,
130 		    NULL);
131 		dwiic_acpi_get_params(sc, "FMCN", &sc->fs_hcnt, &sc->fs_lcnt,
132 		    &sc->sda_hold_time);
133 	}
134 #endif
135 
136 	if (dwiic_init(sc)) {
137 		printf(": failed initializing\n");
138 		return;
139 	}
140 
141 	/* leave the controller disabled */
142 	dwiic_write(sc, DW_IC_INTR_MASK, 0);
143 	dwiic_enable(sc, 0);
144 	dwiic_read(sc, DW_IC_CLR_INTR);
145 
146 	/* install interrupt handler */
147 	sc->sc_poll = 1;
148 	if (pci_intr_map(&sc->sc_paa, &ih) == 0) {
149 		intrstr = pci_intr_string(sc->sc_paa.pa_pc, ih);
150 		sc->sc_ih = pci_intr_establish(sc->sc_paa.pa_pc, ih, IPL_BIO,
151 		    dwiic_intr, sc, sc->sc_dev.dv_xname);
152 		if (sc->sc_ih != NULL) {
153 			printf(": %s", intrstr);
154 			sc->sc_poll = 0;
155 		}
156 	}
157 	if (sc->sc_poll)
158 		printf(": polling");
159 
160 	printf("\n");
161 
162 	rw_init(&sc->sc_i2c_lock, "iiclk");
163 
164 	/* setup and attach iic bus */
165 	sc->sc_i2c_tag.ic_cookie = sc;
166 	sc->sc_i2c_tag.ic_acquire_bus = dwiic_i2c_acquire_bus;
167 	sc->sc_i2c_tag.ic_release_bus = dwiic_i2c_release_bus;
168 	sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec;
169 	sc->sc_i2c_tag.ic_intr_establish = dwiic_i2c_intr_establish;
170 	sc->sc_i2c_tag.ic_intr_string = dwiic_i2c_intr_string;
171 
172 	bzero(&sc->sc_iba, sizeof(sc->sc_iba));
173 	sc->sc_iba.iba_name = "iic";
174 	sc->sc_iba.iba_tag = &sc->sc_i2c_tag;
175 	sc->sc_iba.iba_bus_scan = dwiic_pci_bus_scan;
176 	sc->sc_iba.iba_bus_scan_arg = sc;
177 
178 	config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
179 
180 	return;
181 }
182 
183 int
184 dwiic_pci_activate(struct device *self, int act)
185 {
186 	struct dwiic_softc *sc = (struct dwiic_softc *)self;
187 
188 	switch (act) {
189 	case DVACT_WAKEUP:
190 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, LPSS_RESETS,
191 		    (LPSS_RESETS_I2C | LPSS_RESETS_IDMA));
192 		break;
193 	}
194 
195 	dwiic_activate(self, act);
196 
197 	return 0;
198 }
199 
200 void
201 dwiic_pci_bus_scan(struct device *iic, struct i2cbus_attach_args *iba,
202     void *aux)
203 {
204 	struct dwiic_softc *sc = (struct dwiic_softc *)aux;
205 
206 	sc->sc_iic = iic;
207 
208 #if NACPI > 0
209 	if (sc->sc_devnode != NULL)
210 		aml_find_node(sc->sc_devnode, "_HID", dwiic_acpi_found_hid, sc);
211 #endif
212 }
213