145f62dc9SImre Vadász /*
245f62dc9SImre Vadász * Copyright (c) 2014 The DragonFly Project. All rights reserved.
345f62dc9SImre Vadász *
445f62dc9SImre Vadász * This code is derived from software contributed to The DragonFly Project
545f62dc9SImre Vadász * by Matthew Dillon <dillon@backplane.com>
645f62dc9SImre Vadász *
745f62dc9SImre Vadász * Redistribution and use in source and binary forms, with or without
845f62dc9SImre Vadász * modification, are permitted provided that the following conditions
945f62dc9SImre Vadász * are met:
1045f62dc9SImre Vadász *
1145f62dc9SImre Vadász * 1. Redistributions of source code must retain the above copyright
1245f62dc9SImre Vadász * notice, this list of conditions and the following disclaimer.
1345f62dc9SImre Vadász * 2. Redistributions in binary form must reproduce the above copyright
1445f62dc9SImre Vadász * notice, this list of conditions and the following disclaimer in
1545f62dc9SImre Vadász * the documentation and/or other materials provided with the
1645f62dc9SImre Vadász * distribution.
1745f62dc9SImre Vadász * 3. Neither the name of The DragonFly Project nor the names of its
1845f62dc9SImre Vadász * contributors may be used to endorse or promote products derived
1945f62dc9SImre Vadász * from this software without specific, prior written permission.
2045f62dc9SImre Vadász *
2145f62dc9SImre Vadász * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2245f62dc9SImre Vadász * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2345f62dc9SImre Vadász * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2445f62dc9SImre Vadász * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2545f62dc9SImre Vadász * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2645f62dc9SImre Vadász * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2745f62dc9SImre Vadász * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2845f62dc9SImre Vadász * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2945f62dc9SImre Vadász * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3045f62dc9SImre Vadász * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3145f62dc9SImre Vadász * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3245f62dc9SImre Vadász * SUCH DAMAGE.
3345f62dc9SImre Vadász */
3445f62dc9SImre Vadász /*
3545f62dc9SImre Vadász * Intel 4th generation mobile cpus integrated I2C device, smbus driver.
3645f62dc9SImre Vadász *
3745f62dc9SImre Vadász * See ig4_reg.h for datasheet reference and notes.
3845f62dc9SImre Vadász */
3945f62dc9SImre Vadász
4045f62dc9SImre Vadász #include <sys/param.h>
4145f62dc9SImre Vadász #include <sys/systm.h>
4245f62dc9SImre Vadász #include <sys/kernel.h>
4345f62dc9SImre Vadász #include <sys/module.h>
4445f62dc9SImre Vadász #include <sys/errno.h>
45ab1e5d7fSImre Vadász #include <sys/serialize.h>
4645f62dc9SImre Vadász #include <sys/syslog.h>
4745f62dc9SImre Vadász #include <sys/bus.h>
4845f62dc9SImre Vadász
4945f62dc9SImre Vadász #include <sys/rman.h>
5045f62dc9SImre Vadász
5145f62dc9SImre Vadász #include "opt_acpi.h"
5245f62dc9SImre Vadász #include "acpi.h"
5345f62dc9SImre Vadász #include <dev/acpica/acpivar.h>
5445f62dc9SImre Vadász
5545f62dc9SImre Vadász #include <bus/pci/pcivar.h>
5645f62dc9SImre Vadász
5745f62dc9SImre Vadász #include <bus/smbus/smbconf.h>
5845f62dc9SImre Vadász
5945f62dc9SImre Vadász #include "smbus_if.h"
6045f62dc9SImre Vadász
6145f62dc9SImre Vadász #include "ig4_reg.h"
6245f62dc9SImre Vadász #include "ig4_var.h"
6345f62dc9SImre Vadász
6445f62dc9SImre Vadász ACPI_MODULE_NAME("ig4iic");
6545f62dc9SImre Vadász
6645f62dc9SImre Vadász static int ig4iic_acpi_probe(device_t dev);
6745f62dc9SImre Vadász static int ig4iic_acpi_attach(device_t dev);
6845f62dc9SImre Vadász static int ig4iic_acpi_detach(device_t dev);
6945f62dc9SImre Vadász
7045f62dc9SImre Vadász static char *ig4iic_ids[] = {
7145f62dc9SImre Vadász "INT33C2",
7245f62dc9SImre Vadász "INT33C3",
7345f62dc9SImre Vadász "INT3432",
7445f62dc9SImre Vadász "INT3433",
7545f62dc9SImre Vadász "80860F41",
7645f62dc9SImre Vadász "808622C1",
77*39bca545SMatthew Dillon "AMDI0510",
78*39bca545SMatthew Dillon "AMDI0010",
79*39bca545SMatthew Dillon "APMC0D0F",
8045f62dc9SImre Vadász NULL
8145f62dc9SImre Vadász };
8245f62dc9SImre Vadász
8345f62dc9SImre Vadász static
8445f62dc9SImre Vadász int
ig4iic_acpi_probe(device_t dev)8545f62dc9SImre Vadász ig4iic_acpi_probe(device_t dev)
8645f62dc9SImre Vadász {
8745f62dc9SImre Vadász
8845f62dc9SImre Vadász if (acpi_disabled("ig4iic") ||
8945f62dc9SImre Vadász ACPI_ID_PROBE(device_get_parent(dev), dev, ig4iic_ids) == NULL)
9045f62dc9SImre Vadász return (ENXIO);
9145f62dc9SImre Vadász
92*39bca545SMatthew Dillon device_set_desc(dev, "Designware I2C Controller");
9345f62dc9SImre Vadász
9445f62dc9SImre Vadász return (BUS_PROBE_DEFAULT);
9545f62dc9SImre Vadász }
9645f62dc9SImre Vadász
9745f62dc9SImre Vadász static
9845f62dc9SImre Vadász int
ig4iic_acpi_attach(device_t dev)9945f62dc9SImre Vadász ig4iic_acpi_attach(device_t dev)
10045f62dc9SImre Vadász {
10145f62dc9SImre Vadász ig4iic_softc_t *sc = device_get_softc(dev);
10245f62dc9SImre Vadász int error;
10345f62dc9SImre Vadász
104ab1e5d7fSImre Vadász lwkt_serialize_init(&sc->slz);
10545f62dc9SImre Vadász
10645f62dc9SImre Vadász sc->dev = dev;
107a4549657SImre Vadász /* All the HIDs matched are Atom SOCs. */
108a4549657SImre Vadász sc->version = IG4_ATOM;
10945f62dc9SImre Vadász sc->regs_rid = 0;
11045f62dc9SImre Vadász sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
11145f62dc9SImre Vadász &sc->regs_rid, RF_ACTIVE);
11245f62dc9SImre Vadász if (sc->regs_res == NULL) {
113*39bca545SMatthew Dillon device_printf(dev, "unable to map registers\n");
11445f62dc9SImre Vadász ig4iic_acpi_detach(dev);
11545f62dc9SImre Vadász return (ENXIO);
11645f62dc9SImre Vadász }
11745f62dc9SImre Vadász sc->intr_rid = 0;
11845f62dc9SImre Vadász sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
11945f62dc9SImre Vadász &sc->intr_rid, RF_ACTIVE);
12045f62dc9SImre Vadász if (sc->intr_res == NULL) {
121*39bca545SMatthew Dillon device_printf(dev, "unable to map interrupt\n");
12245f62dc9SImre Vadász ig4iic_acpi_detach(dev);
12345f62dc9SImre Vadász return (ENXIO);
12445f62dc9SImre Vadász }
12545f62dc9SImre Vadász sc->regs_t = rman_get_bustag(sc->regs_res);
12645f62dc9SImre Vadász sc->regs_h = rman_get_bushandle(sc->regs_res);
12745f62dc9SImre Vadász sc->pci_attached = 1;
12845f62dc9SImre Vadász
12945f62dc9SImre Vadász /* power up the controller */
13045f62dc9SImre Vadász pci_set_powerstate(dev, PCI_POWERSTATE_D0);
13145f62dc9SImre Vadász
13245f62dc9SImre Vadász error = ig4iic_attach(sc);
13345f62dc9SImre Vadász if (error)
13445f62dc9SImre Vadász ig4iic_acpi_detach(dev);
13545f62dc9SImre Vadász
13645f62dc9SImre Vadász return error;
13745f62dc9SImre Vadász }
13845f62dc9SImre Vadász
13945f62dc9SImre Vadász static
14045f62dc9SImre Vadász int
ig4iic_acpi_detach(device_t dev)14145f62dc9SImre Vadász ig4iic_acpi_detach(device_t dev)
14245f62dc9SImre Vadász {
14345f62dc9SImre Vadász ig4iic_softc_t *sc = device_get_softc(dev);
14445f62dc9SImre Vadász int error;
14545f62dc9SImre Vadász
14645f62dc9SImre Vadász if (sc->pci_attached) {
14745f62dc9SImre Vadász error = ig4iic_detach(sc);
14845f62dc9SImre Vadász if (error)
14945f62dc9SImre Vadász return error;
15045f62dc9SImre Vadász sc->pci_attached = 0;
15145f62dc9SImre Vadász }
15245f62dc9SImre Vadász
15345f62dc9SImre Vadász if (sc->intr_res) {
15445f62dc9SImre Vadász bus_release_resource(dev, SYS_RES_IRQ,
15545f62dc9SImre Vadász sc->intr_rid, sc->intr_res);
15645f62dc9SImre Vadász sc->intr_res = NULL;
15745f62dc9SImre Vadász }
15845f62dc9SImre Vadász if (sc->regs_res) {
15945f62dc9SImre Vadász bus_release_resource(dev, SYS_RES_MEMORY,
16045f62dc9SImre Vadász sc->regs_rid, sc->regs_res);
16145f62dc9SImre Vadász sc->regs_res = NULL;
16245f62dc9SImre Vadász }
16345f62dc9SImre Vadász sc->regs_t = 0;
16445f62dc9SImre Vadász sc->regs_h = 0;
16545f62dc9SImre Vadász
16645f62dc9SImre Vadász pci_set_powerstate(dev, PCI_POWERSTATE_D3);
16745f62dc9SImre Vadász
16845f62dc9SImre Vadász return 0;
16945f62dc9SImre Vadász }
17045f62dc9SImre Vadász
17145f62dc9SImre Vadász static device_method_t ig4iic_acpi_methods[] = {
17245f62dc9SImre Vadász /* Device interface */
17345f62dc9SImre Vadász DEVMETHOD(device_probe, ig4iic_acpi_probe),
17445f62dc9SImre Vadász DEVMETHOD(device_attach, ig4iic_acpi_attach),
17545f62dc9SImre Vadász DEVMETHOD(device_detach, ig4iic_acpi_detach),
17645f62dc9SImre Vadász
17745f62dc9SImre Vadász /* Bus methods */
17845f62dc9SImre Vadász DEVMETHOD(bus_print_child, bus_generic_print_child),
17945f62dc9SImre Vadász
18045f62dc9SImre Vadász /* SMBus methods from ig4_smb.c */
18145f62dc9SImre Vadász DEVMETHOD(smbus_callback, ig4iic_smb_callback),
18245f62dc9SImre Vadász DEVMETHOD(smbus_quick, ig4iic_smb_quick),
18345f62dc9SImre Vadász DEVMETHOD(smbus_sendb, ig4iic_smb_sendb),
18445f62dc9SImre Vadász DEVMETHOD(smbus_recvb, ig4iic_smb_recvb),
18545f62dc9SImre Vadász DEVMETHOD(smbus_writeb, ig4iic_smb_writeb),
18645f62dc9SImre Vadász DEVMETHOD(smbus_writew, ig4iic_smb_writew),
18745f62dc9SImre Vadász DEVMETHOD(smbus_readb, ig4iic_smb_readb),
18845f62dc9SImre Vadász DEVMETHOD(smbus_readw, ig4iic_smb_readw),
18945f62dc9SImre Vadász DEVMETHOD(smbus_pcall, ig4iic_smb_pcall),
19045f62dc9SImre Vadász DEVMETHOD(smbus_bwrite, ig4iic_smb_bwrite),
19145f62dc9SImre Vadász DEVMETHOD(smbus_bread, ig4iic_smb_bread),
19245f62dc9SImre Vadász DEVMETHOD(smbus_trans, ig4iic_smb_trans),
19345f62dc9SImre Vadász DEVMETHOD_END
19445f62dc9SImre Vadász };
19545f62dc9SImre Vadász
19645f62dc9SImre Vadász static driver_t ig4iic_acpi_driver = {
19745f62dc9SImre Vadász "ig4iic",
19845f62dc9SImre Vadász ig4iic_acpi_methods,
199df21e16dSImre Vadász sizeof(struct ig4iic_softc),
200df21e16dSImre Vadász .gpri = KOBJ_GPRI_ACPI+1
20145f62dc9SImre Vadász };
20245f62dc9SImre Vadász
20345f62dc9SImre Vadász static devclass_t ig4iic_acpi_devclass;
20445f62dc9SImre Vadász
20545f62dc9SImre Vadász DRIVER_MODULE(ig4iic, acpi, ig4iic_acpi_driver, ig4iic_acpi_devclass, NULL, NULL);
20645f62dc9SImre Vadász MODULE_DEPEND(ig4iic, acpi, 1, 1, 1);
20745f62dc9SImre Vadász MODULE_DEPEND(ig4iic, smbacpi, 1, 1, 1);
208