diff options
Diffstat (limited to 'board/gen860t/beeper.c')
-rw-r--r-- | board/gen860t/beeper.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/board/gen860t/beeper.c b/board/gen860t/beeper.c new file mode 100644 index 0000000..46fe66b --- /dev/null +++ b/board/gen860t/beeper.c @@ -0,0 +1,213 @@ +/* + * (C) Copyright 2002 + * Keith Outwater, keith_outwater@mvis.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <mpc8xx.h> +#include <asm/8xx_immap.h> +#include <linux/ctype.h> + +/* + * Basic beeper support for the GEN860T board. The GEN860T includes + * an audio sounder driven by a Phillips TDA8551 amplifier. The + * TDA8551 features a digital volume control which uses a "trinary" + * input (high/high-Z/low) to set volume. The 860's SPKROUT pin + * drives the amplifier input. + */ + + +/* + * Initialize beeper-related hardware. Initialize timer 1 for use with + * the beeper. Use 66 Mhz internal clock with prescale of 33 to get + * 1 uS period per count. + * FIXME: we should really compute the prescale based on the reported + * core clock frequency. + */ +void +init_beeper(void) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + immap->im_cpmtimer.cpmt_tgcr &= ~TGCR_RST1 | TGCR_STP1; + immap->im_cpmtimer.cpmt_tmr1 = ((33 << TMR_PS_SHIFT) & TMR_PS_MSK) + | TMR_OM | TMR_FRR | TMR_ICLK_IN_GEN; + immap->im_cpmtimer.cpmt_tcn1 = 0; + immap->im_cpmtimer.cpmt_ter1 = 0xffff; + immap->im_cpmtimer.cpmt_tgcr |= TGCR_RST1; +} + + +/* + * Set beeper frequency. Max allowed frequency is 2.5 KHz. This limit + * is mostly arbitrary, but the beeper isn't really much good beyond this + * frequency. + */ +void +set_beeper_frequency(uint frequency) +{ +#define FREQ_LIMIT 2500 + + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + /* + * Compute timer ticks given desired frequency. The timer is set up + * to count 0.5 uS per tick and it takes two ticks per cycle (Hz). + */ + if (frequency > FREQ_LIMIT) frequency = FREQ_LIMIT; + frequency = 1000000/frequency; + immap->im_cpmtimer.cpmt_trr1 = (ushort)frequency; +} + + +/* + * Turn the beeper on + */ +void +beeper_on(void) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + immap->im_cpmtimer.cpmt_tgcr &= ~TGCR_STP1; +} + + +/* + * Turn the beeper off + */ +void +beeper_off(void) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + + immap->im_cpmtimer.cpmt_tgcr |= TGCR_STP1; +} + + +/* + * Increase or decrease the beeper volume. Volume can be set + * from off to full in 64 steps. To increase volume, the output + * pin is actively driven high, then returned to tristate. + * To decrease volume, output a low on the port pin (no need to + * change pin mode to tristate) then output a high to go back to + * tristate. + */ +void +set_beeper_volume(int steps) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + int i; + + if (steps >= 0) { + for (i = 0; i < (steps >= 64 ? 64 : steps); i++) { + immap->im_cpm.cp_pbodr &= ~(0x80000000 >> 19); + udelay(1); + immap->im_cpm.cp_pbodr |= (0x80000000 >> 19); + udelay(1); + } + } + else { + for (i = 0; i > (steps <= -64 ? -64 : steps); i--) { + immap->im_cpm.cp_pbdat &= ~(0x80000000 >> 19); + udelay(1); + immap->im_cpm.cp_pbdat |= (0x80000000 >> 19); + udelay(1); + } + } +} + + +/* + * Check the environment to see if the beeper needs beeping. + * Controlled by a sequence of the form: + * freq/delta volume/on time/off time;... where: + * freq = frequency in Hz (0 - 2500) + * delta volume = volume steps up or down (-64 <= vol <= 64) + * on time = time in mS + * off time = time in mS + * + * Return 1 on success, 0 on failure + */ +int +do_beeper(char *sequence) +{ +#define DELIMITER ';' + +int args[4]; +int i; +int val; +char *p = sequence; +char *tp; + + /* + * Parse the control sequence. This is a really simple parser + * without any real error checking. You can probably blow it + * up really easily. + */ + if (*p == '\0' || !isdigit(*p)) { + printf("%s:%d: null or invalid string (%s)\n", + __FILE__, __LINE__, p); + return 0; + } + + i = 0; + while (*p != '\0') { + while (*p != DELIMITER) { + if (i > 3) i = 0; + val = (int) simple_strtol(p, &tp, 0); + if (tp == p) { + printf("%s:%d: no digits or bad format\n", + __FILE__,__LINE__); + return 0; + } + else { + args[i] = val; + } + + i++; + if (*tp == DELIMITER) + p = tp; + else + p = ++tp; + } + p++; + + /* + * Well, we got something that has a chance of being correct + */ +#if 0 + for (i = 0; i < 4; i++) { + printf("%s:%d:arg %d = %d\n", __FILE__, __LINE__, i, args[i]); + } + printf("\n"); +#endif + + set_beeper_frequency(args[0]); + set_beeper_volume(args[1]); + beeper_on(); + udelay(1000 * args[2]); + beeper_off(); + udelay(1000 * args[3]); + } + return 1; +} + +/* vim: set ts=4 sw=4 tw=78: */ |