diff options
author | Joshua Stein <jcs@cvs.openbsd.org> | 2016-09-01 09:38:26 +0000 |
---|---|---|
committer | Joshua Stein <jcs@cvs.openbsd.org> | 2016-09-01 09:38:26 +0000 |
commit | d69bf0fecaed5c1c7f4e6b86ff27336103373d97 (patch) | |
tree | 854d141205fe048810ddbb5ce12e2488c5b8af7a | |
parent | b742dd7dcc34250b2dab5620a72dcb8654979ff2 (diff) |
- separate hid and ihidev attachment for upcoming drivers
- move power control into a dedicated function
- sprinkle aml_freevalue
-rw-r--r-- | sys/dev/acpi/dwiic.c | 170 |
1 files changed, 101 insertions, 69 deletions
diff --git a/sys/dev/acpi/dwiic.c b/sys/dev/acpi/dwiic.c index 7e9a92a6e68..24a455fbe4e 100644 --- a/sys/dev/acpi/dwiic.c +++ b/sys/dev/acpi/dwiic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dwiic.c,v 1.16 2016/04/23 10:23:44 kettenis Exp $ */ +/* $OpenBSD: dwiic.c,v 1.17 2016/09/01 09:38:25 jcs Exp $ */ /* * Synopsys DesignWare I2C controller * @@ -101,8 +101,6 @@ #define DW_IC_STATUS_ACTIVITY 0x1 -#define DW_IC_ERR_TX_ABRT 0x1 - /* hardware abort codes from the DW_IC_TX_ABRT_SOURCE register */ #define ABRT_7B_ADDR_NOACK 0 #define ABRT_10ADDR1_NOACK 1 @@ -156,11 +154,11 @@ struct dwiic_softc { struct i2c_controller sc_i2c_tag; struct rwlock sc_i2c_lock; struct { - i2c_op_t op; - void * buf; - size_t len; - int flags; - volatile int error; + i2c_op_t op; + void *buf; + size_t len; + int flags; + volatile int error; } sc_i2c_xfer; }; @@ -178,9 +176,12 @@ void * dwiic_i2c_intr_establish(void *, void *, int, const char * dwiic_i2c_intr_string(void *, void *); int dwiic_acpi_parse_crs(union acpi_resource *, void *); -int dwiic_acpi_foundhid(struct aml_node *, void *); +int dwiic_acpi_found_hid(struct aml_node *, void *); +int dwiic_acpi_found_ihidev(struct dwiic_softc *, + struct aml_node *, char *, struct dwiic_crs); void dwiic_acpi_get_params(struct dwiic_softc *, char *, uint16_t *, uint16_t *, uint32_t *); +void dwiic_acpi_power(struct dwiic_softc *, int); void dwiic_bus_scan(struct device *, struct i2cbus_attach_args *, void *); @@ -214,6 +215,12 @@ const char *dwiic_hids[] = { NULL }; +const char *ihidev_hids[] = { + "PNP0C50", + "ACPI0C50", + NULL +}; + int dwiic_match(struct device *parent, void *match, void *aux) { @@ -265,6 +272,9 @@ dwiic_attach(struct device *parent, struct device *self, void *aux) return; } + /* power up the controller */ + dwiic_acpi_power(sc, 1); + /* fetch timing parameters */ sc->ss_hcnt = dwiic_read(sc, DW_IC_SS_SCL_HCNT); sc->ss_lcnt = dwiic_read(sc, DW_IC_SS_SCL_LCNT); @@ -275,13 +285,6 @@ dwiic_attach(struct device *parent, struct device *self, void *aux) dwiic_acpi_get_params(sc, "FMCN", &sc->fs_hcnt, &sc->fs_lcnt, &sc->sda_hold_time); - /* power up the controller */ - if (!aml_searchname(sc->sc_devnode, "_PS0") || - aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PS0", 0, NULL, NULL)) { - printf(", failed powering on with _PS0\n"); - return; - } - if (dwiic_init(sc)) { printf(", failed initializing\n"); bus_space_unmap(sc->sc_iot, sc->sc_ioh, crs.addr_len); @@ -351,26 +354,15 @@ dwiic_activate(struct device *self, int act) /* disable interrupts */ dwiic_write(sc, DW_IC_INTR_MASK, 0); + dwiic_read(sc, DW_IC_CLR_INTR); /* power down the controller */ - if (!aml_searchname(sc->sc_devnode, "_PS3") || - aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PS3", 0, NULL, - NULL)) { - printf("%s: failed powering down with _PS3\n", - sc->sc_dev.dv_xname); - return (1); - } + dwiic_acpi_power(sc, 0); break; case DVACT_WAKEUP: /* power up the controller */ - if (!aml_searchname(sc->sc_devnode, "_PS0") || - aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PS0", 0, NULL, - NULL)) { - printf("%s: failed powering up with _PS0\n", - sc->sc_dev.dv_xname); - return (1); - } + dwiic_acpi_power(sc, 1); dwiic_init(sc); @@ -451,11 +443,13 @@ dwiic_acpi_get_params(struct dwiic_softc *sc, char *method, uint16_t *hcnt, if (res.type != AML_OBJTYPE_PACKAGE) { printf(": %s is not a package (%d)", method, res.type); + aml_freevalue(&res); return; } if (res.length <= 2) { printf(": %s returned package of len %d", method, res.length); + aml_freevalue(&res); return; } @@ -463,6 +457,7 @@ dwiic_acpi_get_params(struct dwiic_softc *sc, char *method, uint16_t *hcnt, *lcnt = aml_val2int(res.v_package[1]); if (sda_hold_time) *sda_hold_time = aml_val2int(res.v_package[2]); + aml_freevalue(&res); } void @@ -470,11 +465,8 @@ dwiic_bus_scan(struct device *iic, struct i2cbus_attach_args *iba, void *aux) { struct dwiic_softc *sc = (struct dwiic_softc *)aux; - /* just to pass through to dwiic_acpi_foundhid */ sc->sc_iic = iic; - - /* find i2c hid devices */ - aml_find_node(sc->sc_devnode, "_HID", dwiic_acpi_foundhid, sc); + aml_find_node(sc->sc_devnode, "_HID", dwiic_acpi_found_hid, sc); } int @@ -522,36 +514,72 @@ dwiic_i2c_intr_string(void *cookie, void *ih) } int -dwiic_acpi_foundhid(struct aml_node *node, void *arg) +dwiic_matchhids(const char *hid, const char *hids[]) +{ + int i; + + for (i = 0; hids[i]; i++) + if (!strcmp(hid, hids[i])) + return (1); + + return (0); +} + +int +dwiic_acpi_found_hid(struct aml_node *node, void *arg) { struct dwiic_softc *sc = (struct dwiic_softc *)arg; - struct i2c_attach_args ia; - struct aml_value cmd[4], res; struct dwiic_crs crs; - char cdev[16], dev[16]; + struct aml_value res; int64_t sta; - - /* 3cdff6f7-4267-4555-ad05-b30a3d8938de */ - static uint8_t i2c_hid_guid[] = { - 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, - 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, - }; + char cdev[16], dev[16]; if (acpi_parsehid(node, arg, cdev, dev, 16) != 0) return 0; - if (strcmp(cdev, ACPI_DEV_HIDI2C) != 0 && - strcmp(cdev, ACPI_DEV_HIDI2C2) != 0) + if (aml_evalinteger(acpi_softc, node->parent, "_STA", 0, NULL, &sta)) + sta = STA_PRESENT | STA_ENABLED | STA_DEV_OK | 0x1000; + + if ((sta & STA_PRESENT) == 0) return 0; DPRINTF(("%s: found HID %s at %s\n", sc->sc_dev.dv_xname, dev, aml_nodename(node))); - if (aml_evalinteger(acpi_softc, node->parent, "_STA", 0, NULL, &sta)) - sta = STA_PRESENT | STA_ENABLED | STA_DEV_OK | 0x1000; + if (aml_evalname(acpi_softc, node->parent, "_CRS", 0, NULL, &res)) { + printf("%s: no _CRS method at %s\n", sc->sc_dev.dv_xname, + aml_nodename(node->parent)); + return (0); + } + if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) { + printf("%s: invalid _CRS object (type %d len %d)\n", + sc->sc_dev.dv_xname, res.type, res.length); + aml_freevalue(&res); + return (0); + } + memset(&crs, 0, sizeof(crs)); + crs.devnode = sc->sc_devnode; + aml_parse_resource(&res, dwiic_acpi_parse_crs, &crs); + aml_freevalue(&res); - if ((sta & STA_PRESENT) == 0) - return 0; + if (dwiic_matchhids(cdev, ihidev_hids)) + return dwiic_acpi_found_ihidev(sc, node, dev, crs); + + return 0; +} + +int +dwiic_acpi_found_ihidev(struct dwiic_softc *sc, struct aml_node *node, + char *dev, struct dwiic_crs crs) +{ + struct i2c_attach_args ia; + struct aml_value cmd[4], res; + + /* 3cdff6f7-4267-4555-ad05-b30a3d8938de */ + static uint8_t i2c_hid_guid[] = { + 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, + 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE, + }; if (!aml_searchname(node->parent, "_DSM")) { printf("%s: couldn't find _DSM at %s\n", sc->sc_dev.dv_xname, @@ -593,28 +621,11 @@ dwiic_acpi_foundhid(struct aml_node *node, void *arg) ia.ia_size = 1; ia.ia_name = "ihidev"; ia.ia_size = aml_val2int(&res); /* hid descriptor address */ + ia.ia_addr = crs.i2c_addr; ia.ia_cookie = dev; aml_freevalue(&res); - if (aml_evalname(acpi_softc, node->parent, "_CRS", 0, NULL, &res)) { - printf("%s: no _CRS method at %s\n", sc->sc_dev.dv_xname, - aml_nodename(node->parent)); - return (0); - } - if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) { - printf("%s: invalid _CRS object (type %d len %d)\n", - sc->sc_dev.dv_xname, res.type, res.length); - aml_freevalue(&res); - return (0); - } - memset(&crs, 0, sizeof(crs)); - crs.devnode = sc->sc_devnode; - aml_parse_resource(&res, dwiic_acpi_parse_crs, &crs); - aml_freevalue(&res); - - ia.ia_addr = crs.i2c_addr; - if (crs.irq_int <= 0 && crs.gpio_int_node == NULL) { printf("%s: couldn't find irq for %s\n", sc->sc_dev.dv_xname, aml_nodename(node->parent)); @@ -729,6 +740,28 @@ dwiic_enable(struct dwiic_softc *sc, int enable) (enable ? "en" : "dis")); } +void +dwiic_acpi_power(struct dwiic_softc *sc, int power) +{ + char ps[] = "_PS0"; + + if (!power) + ps[3] = '3'; + + if (aml_searchname(sc->sc_devnode, ps)) { + if (aml_evalname(sc->sc_acpi, sc->sc_devnode, ps, 0, NULL, + NULL)) { + printf("%s: failed powering %s with %s\n", + sc->sc_dev.dv_xname, power ? "on" : "off", + ps); + return; + } + + DELAY(10000); /* 10 milliseconds */ + } else + DPRINTF(("%s: no %s method\n", sc->sc_dev.dv_xname, ps)); +} + int dwiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) @@ -957,7 +990,6 @@ dwiic_read_clear_intrbits(struct dwiic_softc *sc) return stat; } - int dwiic_intr(void *arg) { |