diff options
| author | jmcneill <jmcneill@NetBSD.org> | 2005-04-04 18:52:30 +0000 |
|---|---|---|
| committer | jmcneill <jmcneill@NetBSD.org> | 2005-04-04 18:52:30 +0000 |
| commit | f1db07fc36a98fce976ba7cdc2c4c869db7558a9 (patch) | |
| tree | 7affdf596aec4b5368ff85f0abbad7d2ecb5b25f /sys/dev/ic | |
| parent | 914d68e290bddfcfa18b1517cf4590f1050de464 (diff) | |
* Add more AC97 modem registers (from AC'97 revision 2.2)
* Add sysctls to control the modem's off-hook status (work in progress)
Diffstat (limited to 'sys/dev/ic')
| -rw-r--r-- | sys/dev/ic/ac97.c | 154 | ||||
| -rw-r--r-- | sys/dev/ic/ac97reg.h | 53 |
2 files changed, 182 insertions, 25 deletions
diff --git a/sys/dev/ic/ac97.c b/sys/dev/ic/ac97.c index 4f7debffb35..21a5cdd34c9 100644 --- a/sys/dev/ic/ac97.c +++ b/sys/dev/ic/ac97.c @@ -1,4 +1,4 @@ -/* $NetBSD: ac97.c,v 1.67 2005/04/04 02:08:58 jmcneill Exp $ */ +/* $NetBSD: ac97.c,v 1.68 2005/04/04 18:52:30 jmcneill Exp $ */ /* $OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $ */ /* @@ -63,13 +63,14 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.67 2005/04/04 02:08:58 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.68 2005/04/04 18:52:30 jmcneill Exp $"); #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/device.h> +#include <sys/sysctl.h> #include <sys/audioio.h> #include <dev/audio_if.h> @@ -102,6 +103,9 @@ static void ac97_ad198x_init(struct ac97_softc *); static void ac97_alc650_init(struct ac97_softc *); static void ac97_vt1616_init(struct ac97_softc *); +static int ac97_modem_offhook_set(struct ac97_softc *, int, int); +static int ac97_sysctl_verify(SYSCTLFN_ARGS); + #define Ac97Nphone "phone" static const struct audio_mixer_enum @@ -337,6 +341,13 @@ struct ac97_softc { uint16_t ext_id; /* -> AC97_REG_EXT_AUDIO_ID */ uint16_t ext_mid; /* -> AC97_REG_EXT_MODEM_ID */ uint16_t shadow_reg[128]; + + /* sysctl */ + struct sysctllog *log; + int offhook_line1_mib; + int offhook_line2_mib; + int offhook_line1; + int offhook_line2; }; static struct ac97_codec_if_vtbl ac97civ = { @@ -1109,8 +1120,12 @@ ac97_attach(struct ac97_host_if *host_if, struct device *sc_dev) as->ext_mid = 0; } if (as->ext_mid != 0) { + struct sysctlnode *node; + struct sysctlnode *node_line1; + struct sysctlnode *node_line2; uint16_t rate = 12000; uint16_t val, reg; + int err; /* Print capabilities */ bitmask_snprintf(as->ext_mid, @@ -1122,40 +1137,93 @@ ac97_attach(struct ac97_host_if *host_if, struct device *sc_dev) (as->ext_mid & 0xc000) == 0 ? "primary" : "secondary"); - /* Setup modem */ - val = AC97_MEA_GPIO; + /* Setup modem and sysctls */ + val = AC97_EXT_MODEM_CTRL_GPIO; + err = sysctl_createv(&as->log, 0, NULL, NULL, 0, CTLTYPE_NODE, + "hw", NULL, NULL, 0, NULL, 0, CTL_HW, + CTL_EOL); + if (err != 0) + goto sysctl_err; + err = sysctl_createv(&as->log, 0, NULL, &node, 0, + CTLTYPE_NODE, sc_dev->dv_xname, NULL, + NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, + CTL_EOL); + if (err != 0) + goto sysctl_err; if (as->ext_mid & AC97_EXT_MODEM_LINE1) { ac97_write(as, AC97_REG_LINE1_RATE, rate); - val |= AC97_MEA_ADC1 | AC97_MEA_DAC1; + val |= AC97_EXT_MODEM_CTRL_ADC1 | + AC97_EXT_MODEM_CTRL_DAC1; } if (as->ext_mid & AC97_EXT_MODEM_LINE2) { ac97_write(as, AC97_REG_LINE2_RATE, rate); - val |= AC97_MEA_ADC2 | AC97_MEA_DAC2; + val |= AC97_EXT_MODEM_CTRL_ADC2 | + AC97_EXT_MODEM_CTRL_DAC2; } if (as->ext_mid & AC97_EXT_MODEM_HANDSET) { ac97_write(as, AC97_REG_HANDSET_RATE, rate); - val |= AC97_MEA_HADC | AC97_MEA_HDAC; + val |= AC97_EXT_MODEM_CTRL_HADC | + AC97_EXT_MODEM_CTRL_HDAC; } - ac97_write(as, AC97_REG_EXT_MODEM_STATUS, 0xff00 & ~(val << 8)); + /* power-up everything that we have */ + ac97_write(as, AC97_REG_EXT_MODEM_CTRL, 0xff00 & ~(val << 8)); delay(100); - ac97_write(as, AC97_REG_EXT_MODEM_STATUS, 0xff00 & ~(val << 8)); + ac97_write(as, AC97_REG_EXT_MODEM_CTRL, 0xff00 & ~(val << 8)); + i = 500000; do { - ac97_read(as, AC97_REG_EXT_MODEM_STATUS, ®); + ac97_read(as, AC97_REG_EXT_MODEM_CTRL, ®); delay(1); } while ((reg & val) != val && i--); if (i == 0) - printf("%s: error setting extended modem controls\n", + printf("%s: error setting extended modem status\n", sc_dev->dv_xname); - ac97_write(as, AC97_REG_GPIO_CFG, - 0xffff & ~(AC97_GPIO_LINE1_OH)); - ac97_write(as, AC97_REG_GPIO_POLARITY, - 0xffff & ~(AC97_GPIO_LINE1_OH)); + /* setup sysctls */ + if (as->ext_mid & AC97_EXT_MODEM_LINE1) { + ac97_read(as, AC97_REG_GPIO_CFG, ®); + reg &= ~AC97_GPIO_LINE1_OH; + ac97_write(as, AC97_REG_GPIO_CFG, reg); + ac97_read(as, AC97_REG_GPIO_POLARITY, ®); + reg &= ~AC97_GPIO_LINE1_OH; + ac97_write(as, AC97_REG_GPIO_POLARITY, reg); + + err = sysctl_createv(&as->log, 0, NULL, &node_line1, + CTLFLAG_READWRITE, CTLTYPE_INT, + "line1", + SYSCTL_DESCR("off-hook line1"), + ac97_sysctl_verify, 0, as, 0, + CTL_HW, node->sysctl_num, + CTL_CREATE, CTL_EOL); + if (err != 0) + goto sysctl_err; + as->offhook_line1_mib = node_line1->sysctl_num; + } + if (as->ext_mid & AC97_EXT_MODEM_LINE2) { + ac97_read(as, AC97_REG_GPIO_CFG, ®); + reg &= ~AC97_GPIO_LINE2_OH; + ac97_write(as, AC97_REG_GPIO_CFG, reg); + ac97_read(as, AC97_REG_GPIO_POLARITY, ®); + reg &= ~AC97_GPIO_LINE2_OH; + ac97_write(as, AC97_REG_GPIO_POLARITY, reg); + + err = sysctl_createv(&as->log, 0, NULL, &node_line2, + CTLFLAG_READWRITE, CTLTYPE_INT, + "line2", + SYSCTL_DESCR("off-hook line2"), + ac97_sysctl_verify, 0, as, 0, + CTL_HW, node->sysctl_num, + CTL_CREATE, CTL_EOL); + if (err != 0) + goto sysctl_err; + as->offhook_line2_mib = node_line2->sysctl_num; + } + ac97_write(as, AC97_REG_GPIO_STICKY, 0xffff); ac97_write(as, AC97_REG_GPIO_WAKEUP, 0x0); ac97_write(as, AC97_REG_MISC_AFE, 0x0); } +sysctl_err: ac97_setup_source_info(as); memset(&ctl, 0, sizeof(ctl)); @@ -1755,3 +1823,59 @@ ac97_vt1616_init(struct ac97_softc *as) ac97_add_port(as, &sources[1]); ac97_add_port(as, &sources[2]); } + +static int +ac97_modem_offhook_set(struct ac97_softc *as, int line, int newval) +{ + uint16_t val = 0; + + switch (newval) { + case 0: + val &= ~line; + break; + case 1: + val |= line; + break; + } + ac97_write(as, AC97_REG_GPIO_STATUS, val); + + return 0; +} + +static int +ac97_sysctl_verify(SYSCTLFN_ARGS) +{ + int error, tmp; + struct sysctlnode node; + struct ac97_softc *as; + + node = *rnode; + as = rnode->sysctl_data; + if (node.sysctl_num == as->offhook_line1_mib) { + tmp = as->offhook_line1; + node.sysctl_data = &tmp; + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error || newp == NULL) + return error; + + if (tmp < 0 || tmp > 1) + return EINVAL; + + as->offhook_line1 = tmp; + ac97_modem_offhook_set(as, AC97_GPIO_LINE1_OH, tmp); + } else if (node.sysctl_num == as->offhook_line2_mib) { + tmp = as->offhook_line2; + node.sysctl_data = &tmp; + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error || newp == NULL) + return error; + + if (tmp < 0 || tmp > 1) + return EINVAL; + + as->offhook_line2 = tmp; + ac97_modem_offhook_set(as, AC97_GPIO_LINE2_OH, tmp); + } + + return 0; +} diff --git a/sys/dev/ic/ac97reg.h b/sys/dev/ic/ac97reg.h index 44821189020..0eaab9e1834 100644 --- a/sys/dev/ic/ac97reg.h +++ b/sys/dev/ic/ac97reg.h @@ -1,4 +1,4 @@ -/* $NetBSD: ac97reg.h,v 1.10 2005/04/04 02:08:58 jmcneill Exp $ */ +/* $NetBSD: ac97reg.h,v 1.11 2005/04/04 18:52:30 jmcneill Exp $ */ /* * Copyright (c) 1999 Constantine Sapuntzakis @@ -142,15 +142,26 @@ #define AC97_EXT_MODEM_HANDSET 0x0004 #define AC97_EXT_MODEM_CID1 0x0008 #define AC97_EXT_MODEM_CID2 0x0010 -#define AC97_REG_EXT_MODEM_STATUS 0x3e /* extended modem status */ -#define AC97_MEA_GPIO 0x0001 /* gpio is ready */ -#define AC97_MEA_ADC1 0x0004 -#define AC97_MEA_DAC1 0x0008 -#define AC97_MEA_ADC2 0x0010 -#define AC97_MEA_DAC2 0x0020 -#define AC97_MEA_HADC 0x0040 -#define AC97_MEA_HDAC 0x0080 - +#define AC97_EXT_MODEM_ID0 0x4000 +#define AC97_EXT_MODEM_ID1 0x8000 +#define AC97_EXT_MODEM_ID_MASK 0xc000 +#define AC97_REG_EXT_MODEM_CTRL 0x3e /* extended modem ctrl */ +#define AC97_EXT_MODEM_CTRL_GPIO 0x0001 /* gpio is ready */ +#define AC97_EXT_MODEM_CTRL_MREF 0x0002 /* vref up */ +#define AC97_EXT_MODEM_CTRL_ADC1 0x0004 /* line1 adc ready */ +#define AC97_EXT_MODEM_CTRL_DAC1 0x0008 /* line1 dac ready */ +#define AC97_EXT_MODEM_CTRL_ADC2 0x0010 /* line2 adc ready */ +#define AC97_EXT_MODEM_CTRL_DAC2 0x0020 /* line2 dac ready */ +#define AC97_EXT_MODEM_CTRL_HADC 0x0040 /* handset adc ready */ +#define AC97_EXT_MODEM_CTRL_HDAC 0x0080 /* handset dac ready */ +#define AC97_EXT_MODEM_CTRL_PRA 0x0100 /* gpio off */ +#define AC97_EXT_MODEM_CTRL_PRB 0x0200 /* vref off */ +#define AC97_EXT_MODEM_CTRL_PRC 0x0400 /* line1 adc off */ +#define AC97_EXT_MODEM_CTRL_PRD 0x0800 /* line1 dac off */ +#define AC97_EXT_MODEM_CTRL_PRE 0x1000 /* line2 adc off */ +#define AC97_EXT_MODEM_CTRL_PRF 0x2000 /* line2 dac off */ +#define AC97_EXT_MODEM_CTRL_PRG 0x4000 /* handset adc off */ +#define AC97_EXT_MODEM_CTRL_PRH 0x8000 /* handset dac off */ #define AC97_REG_LINE1_RATE 0x40 #define AC97_REG_LINE2_RATE 0x42 #define AC97_REG_HANDSET_RATE 0x44 @@ -165,7 +176,29 @@ #define AC97_GPIO_LINE1_OH 0x0001 /* off-hook */ #define AC97_GPIO_LINE1_RI 0x0002 /* ring detect */ #define AC97_GPIO_LINE1_CID 0x0004 /* caller-id */ +#define AC97_GPIO_LINE2_OH 0x0400 /* off-hook */ +#define AC97_GPIO_LINE2_RI 0x0800 /* ring detect */ +#define AC97_GPIO_LINE2_CID 0x1000 /* caller-id */ #define AC97_REG_MISC_AFE 0x56 /* misc modem afe status & control */ +#define AC97_MISC_AFE_L1B_MASK 0x0007 /* line1 loopback */ +#define AC97_MISC_AFE_L2B_MASK 0x0070 /* line2 loopback */ +#define AC97_MISC_AFE_HSB_MASK 0x0700 /* handset loopback */ +#define AC97_MISC_AFE_MLNK 0x1000 /* ac-link status */ +#define AC97_MISC_AFE_CID1 0x2000 /* line1 cid decode */ +#define AC97_MISC_AFE_CID2 0x4000 /* line2 cid decide */ +#define AC97_MISC_AFE_CIDR 0x8000 /* raw cid data */ + +/* Modem loopback modes */ +#define AC97_LOOPBACK_DISABLE 0 +#define AC97_LOOPBACK_ADC 1 +#define AC97_LOOPBACK_LOCAL_ANALOG 2 +#define AC97_LOOPBACK_DAC 3 +#define AC97_LOOPBACK_REMOTE_ANALOG 4 +#define AC97_LOOPBACK_VENDOR1 5 +#define AC97_LOOPBACK_VENDOR2 6 +#define AC97_LOOPBACK_VENDOR3 7 + + /* Vendor specific -- 0x5a-0x7b */ |
