2 * Copyright (c) 2014 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * Intel 4th generation mobile cpus integrated I2C device, smbus driver.
37 * See ig4_reg.h for datasheet reference and notes.
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/module.h>
44 #include <sys/errno.h>
45 #include <sys/serialize.h>
46 #include <sys/syslog.h>
51 #include <bus/pci/pcivar.h>
52 #include <bus/pci/pcireg.h>
53 #include <bus/smbus/smbconf.h>
60 static int ig4iic_pci_detach(device_t dev
);
62 #define PCI_CHIP_LYNXPT_LP_I2C_1 0x9c618086
63 #define PCI_CHIP_LYNXPT_LP_I2C_2 0x9c628086
64 #define PCI_CHIP_BRASWELL_I2C_1 0x22c18086
65 #define PCI_CHIP_BRASWELL_I2C_2 0x22c28086
66 #define PCI_CHIP_BRASWELL_I2C_3 0x22c38086
67 #define PCI_CHIP_BRASWELL_I2C_5 0x22c58086
68 #define PCI_CHIP_BRASWELL_I2C_6 0x22c68086
69 #define PCI_CHIP_BRASWELL_I2C_7 0x22c78086
70 #define PCI_CHIP_SKYLAKE_I2C_0 0x9d608086
71 #define PCI_CHIP_SKYLAKE_I2C_1 0x9d618086
72 #define PCI_CHIP_SKYLAKE_I2C_2 0x9d628086
73 #define PCI_CHIP_SKYLAKE_I2C_3 0x9d638086
74 #define PCI_CHIP_SKYLAKE_I2C_4 0x9d648086
75 #define PCI_CHIP_SKYLAKE_I2C_5 0x9d658086
76 #define PCI_CHIP_KABYLAKE_I2C_0 0xa1608086
77 #define PCI_CHIP_KABYLAKE_I2C_1 0xa1618086
78 #define PCI_CHIP_APL_I2C_0 0x5aac8086
79 #define PCI_CHIP_APL_I2C_1 0x5aae8086
80 #define PCI_CHIP_APL_I2C_2 0x5ab08086
81 #define PCI_CHIP_APL_I2C_3 0x5ab28086
82 #define PCI_CHIP_APL_I2C_4 0x5ab48086
83 #define PCI_CHIP_APL_I2C_5 0x5ab68086
84 #define PCI_CHIP_APL_I2C_6 0x5ab88086
85 #define PCI_CHIP_APL_I2C_7 0x5aba8086
86 #define PCI_CHIP_CANNONLAKE_LP_I2C_0 0x9dc58086
87 #define PCI_CHIP_CANNONLAKE_LP_I2C_1 0x9dc68086
88 #define PCI_CHIP_CANNONLAKE_LP_I2C_2 0x9de88086
89 #define PCI_CHIP_CANNONLAKE_LP_I2C_3 0x9de98086
90 #define PCI_CHIP_CANNONLAKE_LP_I2C_4 0x9dea8086
91 #define PCI_CHIP_CANNONLAKE_LP_I2C_5 0x9deb8086
92 #define PCI_CHIP_CANNONLAKE_H_I2C_0 0xa3688086
93 #define PCI_CHIP_CANNONLAKE_H_I2C_1 0xa3698086
94 #define PCI_CHIP_CANNONLAKE_H_I2C_2 0xa36a8086
95 #define PCI_CHIP_CANNONLAKE_H_I2C_3 0xa36b8086
97 struct ig4iic_pci_device
{
100 enum ig4_vers version
;
103 static struct ig4iic_pci_device ig4iic_pci_devices
[] = {
104 { PCI_CHIP_LYNXPT_LP_I2C_1
, "Intel Lynx Point-LP I2C Controller-1", IG4_HASWELL
},
105 { PCI_CHIP_LYNXPT_LP_I2C_2
, "Intel Lynx Point-LP I2C Controller-2", IG4_HASWELL
},
106 { PCI_CHIP_BRASWELL_I2C_1
, "Intel Braswell Serial I/O I2C Port 1", IG4_ATOM
},
107 { PCI_CHIP_BRASWELL_I2C_2
, "Intel Braswell Serial I/O I2C Port 2", IG4_ATOM
},
108 { PCI_CHIP_BRASWELL_I2C_3
, "Intel Braswell Serial I/O I2C Port 3", IG4_ATOM
},
109 { PCI_CHIP_BRASWELL_I2C_5
, "Intel Braswell Serial I/O I2C Port 5", IG4_ATOM
},
110 { PCI_CHIP_BRASWELL_I2C_6
, "Intel Braswell Serial I/O I2C Port 6", IG4_ATOM
},
111 { PCI_CHIP_BRASWELL_I2C_7
, "Intel Braswell Serial I/O I2C Port 7", IG4_ATOM
},
112 { PCI_CHIP_SKYLAKE_I2C_0
, "Intel Sunrise Point-LP I2C Controller-0", IG4_SKYLAKE
},
113 { PCI_CHIP_SKYLAKE_I2C_1
, "Intel Sunrise Point-LP I2C Controller-1", IG4_SKYLAKE
},
114 { PCI_CHIP_SKYLAKE_I2C_2
, "Intel Sunrise Point-LP I2C Controller-2", IG4_SKYLAKE
},
115 { PCI_CHIP_SKYLAKE_I2C_3
, "Intel Sunrise Point-LP I2C Controller-3", IG4_SKYLAKE
},
116 { PCI_CHIP_SKYLAKE_I2C_4
, "Intel Sunrise Point-LP I2C Controller-4", IG4_SKYLAKE
},
117 { PCI_CHIP_SKYLAKE_I2C_5
, "Intel Sunrise Point-LP I2C Controller-5", IG4_SKYLAKE
},
118 { PCI_CHIP_KABYLAKE_I2C_0
, "Intel Sunrise Point-H I2C Controller-0", IG4_SKYLAKE
},
119 { PCI_CHIP_KABYLAKE_I2C_1
, "Intel Sunrise Point-H I2C Controller-1", IG4_SKYLAKE
},
120 { PCI_CHIP_APL_I2C_0
, "Intel Apollo Lake I2C Controller-0", IG4_APL
},
121 { PCI_CHIP_APL_I2C_1
, "Intel Apollo Lake I2C Controller-1", IG4_APL
},
122 { PCI_CHIP_APL_I2C_2
, "Intel Apollo Lake I2C Controller-2", IG4_APL
},
123 { PCI_CHIP_APL_I2C_3
, "Intel Apollo Lake I2C Controller-3", IG4_APL
},
124 { PCI_CHIP_APL_I2C_4
, "Intel Apollo Lake I2C Controller-4", IG4_APL
},
125 { PCI_CHIP_APL_I2C_5
, "Intel Apollo Lake I2C Controller-5", IG4_APL
},
126 { PCI_CHIP_APL_I2C_6
, "Intel Apollo Lake I2C Controller-6", IG4_APL
},
127 { PCI_CHIP_APL_I2C_7
, "Intel Apollo Lake I2C Controller-7", IG4_APL
},
128 { PCI_CHIP_CANNONLAKE_LP_I2C_0
, "Intel Cannon Lake-LP I2C Controller-0", IG4_CANNONLAKE
},
129 { PCI_CHIP_CANNONLAKE_LP_I2C_1
, "Intel Cannon Lake-LP I2C Controller-1", IG4_CANNONLAKE
},
130 { PCI_CHIP_CANNONLAKE_LP_I2C_2
, "Intel Cannon Lake-LP I2C Controller-2", IG4_CANNONLAKE
},
131 { PCI_CHIP_CANNONLAKE_LP_I2C_3
, "Intel Cannon Lake-LP I2C Controller-3", IG4_CANNONLAKE
},
132 { PCI_CHIP_CANNONLAKE_LP_I2C_4
, "Intel Cannon Lake-LP I2C Controller-4", IG4_CANNONLAKE
},
133 { PCI_CHIP_CANNONLAKE_LP_I2C_5
, "Intel Cannon Lake-LP I2C Controller-5", IG4_CANNONLAKE
},
134 { PCI_CHIP_CANNONLAKE_H_I2C_0
, "Intel Cannon Lake-H I2C Controller-0", IG4_CANNONLAKE
},
135 { PCI_CHIP_CANNONLAKE_H_I2C_1
, "Intel Cannon Lake-H I2C Controller-1", IG4_CANNONLAKE
},
136 { PCI_CHIP_CANNONLAKE_H_I2C_2
, "Intel Cannon Lake-H I2C Controller-2", IG4_CANNONLAKE
},
137 { PCI_CHIP_CANNONLAKE_H_I2C_3
, "Intel Cannon Lake-H I2C Controller-3", IG4_CANNONLAKE
},
141 ig4iic_pci_probe(device_t dev
)
143 ig4iic_softc_t
*sc
= device_get_softc(dev
);
147 devid
= pci_get_devid(dev
);
148 for (i
= 0; i
< nitems(ig4iic_pci_devices
); i
++) {
149 if (ig4iic_pci_devices
[i
].devid
== devid
) {
150 device_set_desc(dev
, ig4iic_pci_devices
[i
].desc
);
151 sc
->version
= ig4iic_pci_devices
[i
].version
;
152 return (BUS_PROBE_DEFAULT
);
160 ig4iic_pci_attach(device_t dev
)
162 ig4iic_softc_t
*sc
= device_get_softc(dev
);
167 bzero(sc
, sizeof(*sc
));
169 lwkt_serialize_init(&sc
->slz
);
172 sc
->regs_rid
= PCIR_BAR(0);
173 sc
->regs_res
= bus_alloc_resource_any(dev
, SYS_RES_MEMORY
,
174 &sc
->regs_rid
, RF_ACTIVE
);
175 if (sc
->regs_res
== NULL
) {
176 device_printf(dev
, "unable to map registers");
177 ig4iic_pci_detach(dev
);
180 sc
->intr_type
= pci_alloc_1intr(dev
, msi_enable
,
181 &sc
->intr_rid
, &irq_flags
);
182 sc
->intr_res
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
,
183 &sc
->intr_rid
, irq_flags
);
184 if (sc
->intr_res
== NULL
) {
185 device_printf(dev
, "unable to map interrupt");
186 ig4iic_pci_detach(dev
);
189 sc
->regs_t
= rman_get_bustag(sc
->regs_res
);
190 sc
->regs_h
= rman_get_bushandle(sc
->regs_res
);
191 sc
->pci_attached
= 1;
193 error
= ig4iic_attach(sc
);
195 ig4iic_pci_detach(dev
);
202 ig4iic_pci_detach(device_t dev
)
204 ig4iic_softc_t
*sc
= device_get_softc(dev
);
207 if (sc
->pci_attached
) {
208 error
= ig4iic_detach(sc
);
211 sc
->pci_attached
= 0;
215 bus_release_resource(dev
, SYS_RES_IRQ
,
216 sc
->intr_rid
, sc
->intr_res
);
219 if (sc
->intr_type
== PCI_INTR_TYPE_MSI
)
220 pci_release_msi(dev
);
222 bus_release_resource(dev
, SYS_RES_MEMORY
,
223 sc
->regs_rid
, sc
->regs_res
);
232 static device_method_t ig4iic_pci_methods
[] = {
233 /* Device interface */
234 DEVMETHOD(device_probe
, ig4iic_pci_probe
),
235 DEVMETHOD(device_attach
, ig4iic_pci_attach
),
236 DEVMETHOD(device_detach
, ig4iic_pci_detach
),
239 DEVMETHOD(bus_print_child
, bus_generic_print_child
),
241 /* SMBus methods from ig4_smb.c */
242 DEVMETHOD(smbus_callback
, ig4iic_smb_callback
),
243 DEVMETHOD(smbus_quick
, ig4iic_smb_quick
),
244 DEVMETHOD(smbus_sendb
, ig4iic_smb_sendb
),
245 DEVMETHOD(smbus_recvb
, ig4iic_smb_recvb
),
246 DEVMETHOD(smbus_writeb
, ig4iic_smb_writeb
),
247 DEVMETHOD(smbus_writew
, ig4iic_smb_writew
),
248 DEVMETHOD(smbus_readb
, ig4iic_smb_readb
),
249 DEVMETHOD(smbus_readw
, ig4iic_smb_readw
),
250 DEVMETHOD(smbus_pcall
, ig4iic_smb_pcall
),
251 DEVMETHOD(smbus_bwrite
, ig4iic_smb_bwrite
),
252 DEVMETHOD(smbus_bread
, ig4iic_smb_bread
),
253 DEVMETHOD(smbus_trans
, ig4iic_smb_trans
),
257 static driver_t ig4iic_pci_driver
= {
260 sizeof(struct ig4iic_softc
)
263 static devclass_t ig4iic_pci_devclass
;
265 DRIVER_MODULE(ig4iic
, pci
, ig4iic_pci_driver
, ig4iic_pci_devclass
, NULL
, NULL
);
266 MODULE_DEPEND(ig4iic
, pci
, 1, 1, 1);
267 MODULE_DEPEND(ig4iic
, smbus
, SMBUS_MINVER
, SMBUS_PREFVER
, SMBUS_MAXVER
);
268 MODULE_VERSION(ig4iic
, 1);