Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/nctgpio/nctgpio.c
Show All 36 Lines | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/eventhandler.h> | #include <sys/eventhandler.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/rman.h> | |||||
#include <sys/gpio.h> | #include <sys/gpio.h> | ||||
#include <isa/isavar.h> | |||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/resource.h> | |||||
#include <dev/gpio/gpiobusvar.h> | #include <dev/gpio/gpiobusvar.h> | ||||
#include <dev/superio/superio.h> | |||||
#include "gpio_if.h" | #include "gpio_if.h" | ||||
/* | |||||
* Global configuration registers (CR). | |||||
*/ | |||||
#define NCT_CR_LDN 0x07 /* Logical Device Number */ | |||||
#define NCT_CR_CHIP_ID 0x20 /* Chip ID */ | |||||
#define NCT_CR_CHIP_ID_H 0x20 /* Chip ID (high byte) */ | |||||
#define NCT_CR_CHIP_ID_L 0x21 /* Chip ID (low byte) */ | |||||
#define NCT_CR_OPT_1 0x26 /* Global Options (1) */ | |||||
/* Logical Device Numbers. */ | /* Logical Device Numbers. */ | ||||
#define NCT_LDN_GPIO 0x07 | #define NCT_LDN_GPIO 0x07 | ||||
#define NCT_LDN_GPIO_CFG 0x08 | |||||
#define NCT_LDN_GPIO_MODE 0x0f | #define NCT_LDN_GPIO_MODE 0x0f | ||||
/* Logical Device 7 */ | /* Logical Device 7 */ | ||||
#define NCT_LD7_GPIO_ENABLE 0x30 | |||||
#define NCT_LD7_GPIO0_IOR 0xe0 | #define NCT_LD7_GPIO0_IOR 0xe0 | ||||
#define NCT_LD7_GPIO0_DAT 0xe1 | #define NCT_LD7_GPIO0_DAT 0xe1 | ||||
#define NCT_LD7_GPIO0_INV 0xe2 | #define NCT_LD7_GPIO0_INV 0xe2 | ||||
#define NCT_LD7_GPIO0_DST 0xe3 | #define NCT_LD7_GPIO0_DST 0xe3 | ||||
#define NCT_LD7_GPIO1_IOR 0xe4 | #define NCT_LD7_GPIO1_IOR 0xe4 | ||||
#define NCT_LD7_GPIO1_DAT 0xe5 | #define NCT_LD7_GPIO1_DAT 0xe5 | ||||
#define NCT_LD7_GPIO1_INV 0xe6 | #define NCT_LD7_GPIO1_INV 0xe6 | ||||
#define NCT_LD7_GPIO1_DST 0xe7 | #define NCT_LD7_GPIO1_DST 0xe7 | ||||
/* Logical Device F */ | /* Logical Device F */ | ||||
#define NCT_LDF_GPIO0_OUTCFG 0xe0 | #define NCT_LDF_GPIO0_OUTCFG 0xe0 | ||||
#define NCT_LDF_GPIO1_OUTCFG 0xe1 | #define NCT_LDF_GPIO1_OUTCFG 0xe1 | ||||
#define NCT_EXTFUNC_ENTER 0x87 | |||||
#define NCT_EXTFUNC_EXIT 0xaa | |||||
#define NCT_MAX_PIN 15 | #define NCT_MAX_PIN 15 | ||||
#define NCT_IS_VALID_PIN(_p) ((_p) >= 0 && (_p) <= NCT_MAX_PIN) | #define NCT_IS_VALID_PIN(_p) ((_p) >= 0 && (_p) <= NCT_MAX_PIN) | ||||
#define NCT_PIN_BIT(_p) (1 << ((_p) % 8)) | #define NCT_PIN_BIT(_p) (1 << ((_p) % 8)) | ||||
#define NCT_GPIO_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ | #define NCT_GPIO_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ | ||||
GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \ | GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \ | ||||
GPIO_PIN_INVIN | GPIO_PIN_INVOUT) | GPIO_PIN_INVIN | GPIO_PIN_INVOUT) | ||||
struct nct_softc { | struct nct_softc { | ||||
device_t dev; | device_t dev; | ||||
device_t dev_f; | |||||
device_t busdev; | device_t busdev; | ||||
struct mtx mtx; | struct mtx mtx; | ||||
struct resource *portres; | |||||
int rid; | |||||
struct gpio_pin pins[NCT_MAX_PIN + 1]; | struct gpio_pin pins[NCT_MAX_PIN + 1]; | ||||
}; | }; | ||||
#define GPIO_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \ | #define GPIO_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \ | ||||
device_get_nameunit(dev), NULL, MTX_DEF) | device_get_nameunit(dev), NULL, MTX_DEF) | ||||
#define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx) | #define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx) | ||||
#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx) | #define GPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx) | ||||
#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) | #define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) | ||||
#define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED) | #define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED) | ||||
#define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED) | #define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED) | ||||
#define NCT_BARRIER_WRITE(_sc) \ | |||||
bus_barrier((_sc)->portres, 0, 2, BUS_SPACE_BARRIER_WRITE) | |||||
#define NCT_BARRIER_READ_WRITE(_sc) \ | |||||
bus_barrier((_sc)->portres, 0, 2, \ | |||||
BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE) | |||||
static void ext_cfg_enter(struct nct_softc *); | |||||
static void ext_cfg_exit(struct nct_softc *); | |||||
/* | |||||
* Potential Extended Function Enable Register addresses. | |||||
* Same address as EFIR. | |||||
*/ | |||||
uint8_t probe_addrs[] = {0x2e, 0x4e}; | |||||
struct nuvoton_vendor_device_id { | struct nuvoton_vendor_device_id { | ||||
uint16_t chip_id; | uint16_t chip_id; | ||||
const char * descr; | const char * descr; | ||||
} nct_devs[] = { | } nct_devs[] = { | ||||
{ | { | ||||
.chip_id = 0x1061, | .chip_id = 0x1061, | ||||
.descr = "Nuvoton NCT5104D", | .descr = "Nuvoton NCT5104D", | ||||
}, | }, | ||||
{ | { | ||||
.chip_id = 0xc452, | .chip_id = 0xc452, | ||||
.descr = "Nuvoton NCT5104D (PC-Engines APU)", | .descr = "Nuvoton NCT5104D (PC-Engines APU)", | ||||
}, | }, | ||||
{ | { | ||||
.chip_id = 0xc453, | .chip_id = 0xc453, | ||||
.descr = "Nuvoton NCT5104D (PC-Engines APU3)", | .descr = "Nuvoton NCT5104D (PC-Engines APU3)", | ||||
}, | }, | ||||
}; | }; | ||||
static void | |||||
write_cfg_reg_1(struct nct_softc *sc, uint8_t reg, uint8_t value) | |||||
{ | |||||
GPIO_ASSERT_LOCKED(sc); | |||||
bus_write_1(sc->portres, 0, reg); | |||||
NCT_BARRIER_WRITE(sc); | |||||
bus_write_1(sc->portres, 1, value); | |||||
NCT_BARRIER_WRITE(sc); | |||||
} | |||||
static uint8_t | |||||
read_cfg_reg_1(struct nct_softc *sc, uint8_t reg) | |||||
{ | |||||
uint8_t value; | |||||
GPIO_ASSERT_LOCKED(sc); | |||||
bus_write_1(sc->portres, 0, reg); | |||||
NCT_BARRIER_READ_WRITE(sc); | |||||
value = bus_read_1(sc->portres, 1); | |||||
NCT_BARRIER_READ_WRITE(sc); | |||||
return (value); | |||||
} | |||||
static uint16_t | |||||
read_cfg_reg_2(struct nct_softc *sc, uint8_t reg) | |||||
{ | |||||
uint16_t value; | |||||
value = read_cfg_reg_1(sc, reg) << 8; | |||||
value |= read_cfg_reg_1(sc, reg + 1); | |||||
return (value); | |||||
} | |||||
/* | /* | ||||
* Enable extended function mode. | |||||
* | |||||
*/ | |||||
static void | |||||
ext_cfg_enter(struct nct_softc *sc) | |||||
{ | |||||
GPIO_ASSERT_LOCKED(sc); | |||||
bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER); | |||||
NCT_BARRIER_WRITE(sc); | |||||
bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER); | |||||
NCT_BARRIER_WRITE(sc); | |||||
} | |||||
/* | |||||
* Disable extended function mode. | |||||
* | |||||
*/ | |||||
static void | |||||
ext_cfg_exit(struct nct_softc *sc) | |||||
{ | |||||
GPIO_ASSERT_LOCKED(sc); | |||||
bus_write_1(sc->portres, 0, NCT_EXTFUNC_EXIT); | |||||
NCT_BARRIER_WRITE(sc); | |||||
} | |||||
/* | |||||
* Select a Logical Device. | |||||
*/ | |||||
static void | |||||
select_ldn(struct nct_softc *sc, uint8_t ldn) | |||||
{ | |||||
write_cfg_reg_1(sc, NCT_CR_LDN, ldn); | |||||
} | |||||
/* | |||||
* Get the GPIO Input/Output register address | * Get the GPIO Input/Output register address | ||||
* for a pin. | * for a pin. | ||||
*/ | */ | ||||
static uint8_t | static uint8_t | ||||
nct_ior_addr(uint32_t pin_num) | nct_ior_addr(uint32_t pin_num) | ||||
{ | { | ||||
uint8_t addr; | uint8_t addr; | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static void | static void | ||||
nct_set_pin_is_output(struct nct_softc *sc, uint32_t pin_num) | nct_set_pin_is_output(struct nct_softc *sc, uint32_t pin_num) | ||||
{ | { | ||||
uint8_t reg; | uint8_t reg; | ||||
uint8_t ior; | uint8_t ior; | ||||
reg = nct_ior_addr(pin_num); | reg = nct_ior_addr(pin_num); | ||||
select_ldn(sc, NCT_LDN_GPIO); | ior = superio_read(sc->dev, reg); | ||||
ior = read_cfg_reg_1(sc, reg); | |||||
ior &= ~(NCT_PIN_BIT(pin_num)); | ior &= ~(NCT_PIN_BIT(pin_num)); | ||||
write_cfg_reg_1(sc, reg, ior); | superio_write(sc->dev, reg, ior); | ||||
} | } | ||||
/* | /* | ||||
* Set a pin to input mode. | * Set a pin to input mode. | ||||
*/ | */ | ||||
static void | static void | ||||
nct_set_pin_is_input(struct nct_softc *sc, uint32_t pin_num) | nct_set_pin_is_input(struct nct_softc *sc, uint32_t pin_num) | ||||
{ | { | ||||
uint8_t reg; | uint8_t reg; | ||||
uint8_t ior; | uint8_t ior; | ||||
reg = nct_ior_addr(pin_num); | reg = nct_ior_addr(pin_num); | ||||
select_ldn(sc, NCT_LDN_GPIO); | ior = superio_read(sc->dev, reg); | ||||
ior = read_cfg_reg_1(sc, reg); | |||||
ior |= NCT_PIN_BIT(pin_num); | ior |= NCT_PIN_BIT(pin_num); | ||||
write_cfg_reg_1(sc, reg, ior); | superio_write(sc->dev, reg, ior); | ||||
} | } | ||||
/* | /* | ||||
* Check whether a pin is configured as an input. | * Check whether a pin is configured as an input. | ||||
*/ | */ | ||||
static bool | static bool | ||||
nct_pin_is_input(struct nct_softc *sc, uint32_t pin_num) | nct_pin_is_input(struct nct_softc *sc, uint32_t pin_num) | ||||
{ | { | ||||
uint8_t reg; | uint8_t reg; | ||||
uint8_t ior; | uint8_t ior; | ||||
reg = nct_ior_addr(pin_num); | reg = nct_ior_addr(pin_num); | ||||
select_ldn(sc, NCT_LDN_GPIO); | ior = superio_read(sc->dev, reg); | ||||
ior = read_cfg_reg_1(sc, reg); | |||||
return (ior & NCT_PIN_BIT(pin_num)); | return (ior & NCT_PIN_BIT(pin_num)); | ||||
} | } | ||||
/* | /* | ||||
* Write a value to an output pin. | * Write a value to an output pin. | ||||
*/ | */ | ||||
static void | static void | ||||
nct_write_pin(struct nct_softc *sc, uint32_t pin_num, uint8_t data) | nct_write_pin(struct nct_softc *sc, uint32_t pin_num, uint8_t data) | ||||
{ | { | ||||
uint8_t reg; | uint8_t reg; | ||||
uint8_t value; | uint8_t value; | ||||
reg = nct_dat_addr(pin_num); | reg = nct_dat_addr(pin_num); | ||||
select_ldn(sc, NCT_LDN_GPIO); | value = superio_read(sc->dev, reg); | ||||
value = read_cfg_reg_1(sc, reg); | |||||
if (data) | if (data) | ||||
value |= NCT_PIN_BIT(pin_num); | value |= NCT_PIN_BIT(pin_num); | ||||
else | else | ||||
value &= ~(NCT_PIN_BIT(pin_num)); | value &= ~(NCT_PIN_BIT(pin_num)); | ||||
write_cfg_reg_1(sc, reg, value); | superio_write(sc->dev, reg, value); | ||||
} | } | ||||
static bool | static bool | ||||
nct_read_pin(struct nct_softc *sc, uint32_t pin_num) | nct_read_pin(struct nct_softc *sc, uint32_t pin_num) | ||||
{ | { | ||||
uint8_t reg; | uint8_t reg; | ||||
reg = nct_dat_addr(pin_num); | reg = nct_dat_addr(pin_num); | ||||
select_ldn(sc, NCT_LDN_GPIO); | |||||
return (read_cfg_reg_1(sc, reg) & NCT_PIN_BIT(pin_num)); | return (superio_read(sc->dev, reg) & NCT_PIN_BIT(pin_num)); | ||||
} | } | ||||
static void | static void | ||||
nct_set_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num) | nct_set_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num) | ||||
{ | { | ||||
uint8_t reg; | uint8_t reg; | ||||
uint8_t inv; | uint8_t inv; | ||||
reg = nct_inv_addr(pin_num); | reg = nct_inv_addr(pin_num); | ||||
select_ldn(sc, NCT_LDN_GPIO); | inv = superio_read(sc->dev, reg); | ||||
inv = read_cfg_reg_1(sc, reg); | |||||
inv |= (NCT_PIN_BIT(pin_num)); | inv |= (NCT_PIN_BIT(pin_num)); | ||||
write_cfg_reg_1(sc, reg, inv); | superio_write(sc->dev, reg, inv); | ||||
} | } | ||||
static void | static void | ||||
nct_set_pin_not_inverted(struct nct_softc *sc, uint32_t pin_num) | nct_set_pin_not_inverted(struct nct_softc *sc, uint32_t pin_num) | ||||
{ | { | ||||
uint8_t reg; | uint8_t reg; | ||||
uint8_t inv; | uint8_t inv; | ||||
reg = nct_inv_addr(pin_num); | reg = nct_inv_addr(pin_num); | ||||
select_ldn(sc, NCT_LDN_GPIO); | inv = superio_read(sc->dev, reg); | ||||
inv = read_cfg_reg_1(sc, reg); | |||||
inv &= ~(NCT_PIN_BIT(pin_num)); | inv &= ~(NCT_PIN_BIT(pin_num)); | ||||
write_cfg_reg_1(sc, reg, inv); | superio_write(sc->dev, reg, inv); | ||||
} | } | ||||
static bool | static bool | ||||
nct_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num) | nct_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num) | ||||
{ | { | ||||
uint8_t reg; | uint8_t reg; | ||||
uint8_t inv; | uint8_t inv; | ||||
reg = nct_inv_addr(pin_num); | reg = nct_inv_addr(pin_num); | ||||
select_ldn(sc, NCT_LDN_GPIO); | inv = superio_read(sc->dev, reg); | ||||
inv = read_cfg_reg_1(sc, reg); | |||||
return (inv & NCT_PIN_BIT(pin_num)); | return (inv & NCT_PIN_BIT(pin_num)); | ||||
} | } | ||||
static void | static void | ||||
nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num) | nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num) | ||||
{ | { | ||||
uint8_t reg; | uint8_t reg; | ||||
uint8_t outcfg; | uint8_t outcfg; | ||||
reg = nct_outcfg_addr(pin_num); | reg = nct_outcfg_addr(pin_num); | ||||
select_ldn(sc, NCT_LDN_GPIO_MODE); | outcfg = superio_read(sc->dev_f, reg); | ||||
outcfg = read_cfg_reg_1(sc, reg); | outcfg |= NCT_PIN_BIT(pin_num); | ||||
outcfg |= (NCT_PIN_BIT(pin_num)); | superio_write(sc->dev_f, reg, outcfg); | ||||
write_cfg_reg_1(sc, reg, outcfg); | |||||
} | } | ||||
static void | static void | ||||
nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num) | nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num) | ||||
{ | { | ||||
uint8_t reg; | uint8_t reg; | ||||
uint8_t outcfg; | uint8_t outcfg; | ||||
reg = nct_outcfg_addr(pin_num); | reg = nct_outcfg_addr(pin_num); | ||||
select_ldn(sc, NCT_LDN_GPIO_MODE); | outcfg = superio_read(sc->dev_f, reg); | ||||
outcfg = read_cfg_reg_1(sc, reg); | outcfg &= ~NCT_PIN_BIT(pin_num); | ||||
outcfg &= ~(NCT_PIN_BIT(pin_num)); | superio_write(sc->dev_f, reg, outcfg); | ||||
write_cfg_reg_1(sc, reg, outcfg); | |||||
} | } | ||||
static bool | static bool | ||||
nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num) | nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num) | ||||
{ | { | ||||
uint8_t reg; | uint8_t reg; | ||||
uint8_t outcfg; | uint8_t outcfg; | ||||
reg = nct_outcfg_addr(pin_num); | reg = nct_outcfg_addr(pin_num); | ||||
select_ldn(sc, NCT_LDN_GPIO_MODE); | outcfg = superio_read(sc->dev_f, reg); | ||||
outcfg = read_cfg_reg_1(sc, reg); | |||||
return (outcfg & NCT_PIN_BIT(pin_num)); | return (outcfg & NCT_PIN_BIT(pin_num)); | ||||
} | } | ||||
static void | |||||
nct_identify(driver_t *driver, device_t parent) | |||||
{ | |||||
if (device_find_child(parent, driver->name, 0) != NULL) | |||||
return; | |||||
BUS_ADD_CHILD(parent, 0, driver->name, 0); | |||||
} | |||||
static int | static int | ||||
nct_probe(device_t dev) | nct_probe(device_t dev) | ||||
{ | { | ||||
int i, j; | int j; | ||||
int rc; | |||||
struct nct_softc *sc; | |||||
uint16_t chipid; | uint16_t chipid; | ||||
/* Make sure we do not claim some ISA PNP device. */ | if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON) | ||||
if (isa_get_logicalid(dev) != 0) | |||||
return (ENXIO); | return (ENXIO); | ||||
if (superio_get_type(dev) != SUPERIO_DEV_GPIO) | |||||
return (ENXIO); | |||||
sc = device_get_softc(dev); | /* | ||||
* There are several GPIO devices, we attach only to one of them | |||||
* and use the rest without attaching. | |||||
*/ | |||||
if (superio_get_ldn(dev) != NCT_LDN_GPIO) | |||||
return (ENXIO); | |||||
for (i = 0; i < nitems(probe_addrs); i++) { | chipid = superio_devid(dev); | ||||
sc->rid = 0; | |||||
sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid, | |||||
probe_addrs[i], probe_addrs[i] + 1, 2, RF_ACTIVE); | |||||
if (sc->portres == NULL) | |||||
continue; | |||||
GPIO_LOCK_INIT(sc); | |||||
GPIO_ASSERT_UNLOCKED(sc); | |||||
GPIO_LOCK(sc); | |||||
ext_cfg_enter(sc); | |||||
chipid = read_cfg_reg_2(sc, NCT_CR_CHIP_ID); | |||||
ext_cfg_exit(sc); | |||||
GPIO_UNLOCK(sc); | |||||
GPIO_LOCK_DESTROY(sc); | |||||
bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres); | |||||
bus_delete_resource(dev, SYS_RES_IOPORT, sc->rid); | |||||
for (j = 0; j < nitems(nct_devs); j++) { | for (j = 0; j < nitems(nct_devs); j++) { | ||||
if (chipid == nct_devs[j].chip_id) { | if (chipid == nct_devs[j].chip_id) { | ||||
rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, probe_addrs[i], 2); | device_set_desc(dev, "Nuvoton GPIO controller"); | ||||
if (rc != 0) { | |||||
device_printf(dev, "bus_set_resource failed for address 0x%02X\n", probe_addrs[i]); | |||||
continue; | |||||
} | |||||
device_set_desc(dev, nct_devs[j].descr); | |||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
} | } | ||||
} | |||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
static int | static int | ||||
nct_attach(device_t dev) | nct_attach(device_t dev) | ||||
{ | { | ||||
struct nct_softc *sc; | struct nct_softc *sc; | ||||
int i; | int i; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sc->dev = dev; | |||||
sc->rid = 0; | sc->dev_f = superio_find_dev(device_get_parent(dev), SUPERIO_DEV_GPIO, | ||||
sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid, | NCT_LDN_GPIO_MODE); | ||||
0ul, ~0ul, 2, RF_ACTIVE); | if (sc->dev_f == NULL) { | ||||
if (sc->portres == NULL) { | device_printf(dev, "failed to find LDN F\n"); | ||||
device_printf(dev, "cannot allocate ioport\n"); | |||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
GPIO_LOCK_INIT(sc); | /* Enable gpio0 and gpio1. */ | ||||
superio_dev_enable(dev, 0x03); | |||||
GPIO_ASSERT_UNLOCKED(sc); | GPIO_LOCK_INIT(sc); | ||||
GPIO_LOCK(sc); | GPIO_LOCK(sc); | ||||
ext_cfg_enter(sc); | |||||
select_ldn(sc, NCT_LDN_GPIO); | |||||
/* Enable gpio0 and gpio1. */ | |||||
write_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE, | |||||
read_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE) | 0x03); | |||||
for (i = 0; i <= NCT_MAX_PIN; i++) { | for (i = 0; i <= NCT_MAX_PIN; i++) { | ||||
struct gpio_pin *pin; | struct gpio_pin *pin; | ||||
pin = &sc->pins[i]; | pin = &sc->pins[i]; | ||||
pin->gp_pin = i; | pin->gp_pin = i; | ||||
pin->gp_caps = NCT_GPIO_CAPS; | pin->gp_caps = NCT_GPIO_CAPS; | ||||
pin->gp_flags = 0; | pin->gp_flags = 0; | ||||
Show All 14 Lines | for (i = 0; i <= NCT_MAX_PIN; i++) { | ||||
if (nct_pin_is_inverted(sc, i)) | if (nct_pin_is_inverted(sc, i)) | ||||
pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT); | pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT); | ||||
} | } | ||||
GPIO_UNLOCK(sc); | GPIO_UNLOCK(sc); | ||||
sc->busdev = gpiobus_attach_bus(dev); | sc->busdev = gpiobus_attach_bus(dev); | ||||
if (sc->busdev == NULL) { | if (sc->busdev == NULL) { | ||||
GPIO_ASSERT_UNLOCKED(sc); | GPIO_ASSERT_UNLOCKED(sc); | ||||
GPIO_LOCK(sc); | |||||
ext_cfg_exit(sc); | |||||
GPIO_UNLOCK(sc); | |||||
bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres); | |||||
GPIO_LOCK_DESTROY(sc); | GPIO_LOCK_DESTROY(sc); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
nct_detach(device_t dev) | nct_detach(device_t dev) | ||||
{ | { | ||||
struct nct_softc *sc; | struct nct_softc *sc; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
gpiobus_detach_bus(dev); | gpiobus_detach_bus(dev); | ||||
GPIO_ASSERT_UNLOCKED(sc); | GPIO_ASSERT_UNLOCKED(sc); | ||||
GPIO_LOCK(sc); | |||||
ext_cfg_exit(sc); | |||||
GPIO_UNLOCK(sc); | |||||
/* Cleanup resources. */ | |||||
bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres); | |||||
GPIO_LOCK_DESTROY(sc); | GPIO_LOCK_DESTROY(sc); | ||||
return (0); | return (0); | ||||
} | } | ||||
static device_t | static device_t | ||||
nct_gpio_get_bus(device_t dev) | nct_gpio_get_bus(device_t dev) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | nct_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags) | ||||
pin->gp_flags = flags; | pin->gp_flags = flags; | ||||
GPIO_UNLOCK(sc); | GPIO_UNLOCK(sc); | ||||
return (0); | return (0); | ||||
} | } | ||||
static device_method_t nct_methods[] = { | static device_method_t nct_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_identify, nct_identify), | |||||
DEVMETHOD(device_probe, nct_probe), | DEVMETHOD(device_probe, nct_probe), | ||||
DEVMETHOD(device_attach, nct_attach), | DEVMETHOD(device_attach, nct_attach), | ||||
DEVMETHOD(device_detach, nct_detach), | DEVMETHOD(device_detach, nct_detach), | ||||
/* GPIO */ | /* GPIO */ | ||||
DEVMETHOD(gpio_get_bus, nct_gpio_get_bus), | DEVMETHOD(gpio_get_bus, nct_gpio_get_bus), | ||||
DEVMETHOD(gpio_pin_max, nct_gpio_pin_max), | DEVMETHOD(gpio_pin_max, nct_gpio_pin_max), | ||||
DEVMETHOD(gpio_pin_get, nct_gpio_pin_get), | DEVMETHOD(gpio_pin_get, nct_gpio_pin_get), | ||||
DEVMETHOD(gpio_pin_set, nct_gpio_pin_set), | DEVMETHOD(gpio_pin_set, nct_gpio_pin_set), | ||||
DEVMETHOD(gpio_pin_toggle, nct_gpio_pin_toggle), | DEVMETHOD(gpio_pin_toggle, nct_gpio_pin_toggle), | ||||
DEVMETHOD(gpio_pin_getname, nct_gpio_pin_getname), | DEVMETHOD(gpio_pin_getname, nct_gpio_pin_getname), | ||||
DEVMETHOD(gpio_pin_getcaps, nct_gpio_pin_getcaps), | DEVMETHOD(gpio_pin_getcaps, nct_gpio_pin_getcaps), | ||||
DEVMETHOD(gpio_pin_getflags, nct_gpio_pin_getflags), | DEVMETHOD(gpio_pin_getflags, nct_gpio_pin_getflags), | ||||
DEVMETHOD(gpio_pin_setflags, nct_gpio_pin_setflags), | DEVMETHOD(gpio_pin_setflags, nct_gpio_pin_setflags), | ||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
static driver_t nct_isa_driver = { | static driver_t nct_driver = { | ||||
"gpio", | "gpio", | ||||
nct_methods, | nct_methods, | ||||
sizeof(struct nct_softc) | sizeof(struct nct_softc) | ||||
}; | }; | ||||
static devclass_t nct_devclass; | static devclass_t nct_devclass; | ||||
DRIVER_MODULE(nctgpio, isa, nct_isa_driver, nct_devclass, NULL, NULL); | DRIVER_MODULE(nctgpio, superio, nct_driver, nct_devclass, NULL, NULL); | ||||
MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1); | MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1); | ||||
MODULE_DEPEND(nctgpio, superio, 1, 1, 1); | |||||
MODULE_VERSION(nctgpio, 1); | |||||