configs/many/Make.defs: Fix typo -wstrict-prototypes; Add Calypso keypad driver (Denis Cariki)
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5395 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
bf4bee0b1e
commit
6b0398a65a
@ -36,22 +36,22 @@
|
||||
#
|
||||
############################################################################
|
||||
|
||||
HEAD_ASRC = calypso_head.S
|
||||
HEAD_ASRC = calypso_head.S
|
||||
|
||||
CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_vectors.S \
|
||||
up_nommuhead.S
|
||||
CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \
|
||||
up_createstack.c up_dataabort.c up_mdelay.c up_udelay.c up_doirq.c \
|
||||
up_exit.c up_idle.c up_initialstate.c up_initialize.c \
|
||||
up_interruptcontext.c up_prefetchabort.c up_releasepending.c \
|
||||
up_releasestack.c up_reprioritizertr.c up_schedulesigaction.c \
|
||||
up_sigdeliver.c up_syscall.c up_unblocktask.c \
|
||||
up_undefinedinsn.c up_usestack.c calypso_power.c
|
||||
CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_vectors.S \
|
||||
up_nommuhead.S
|
||||
CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \
|
||||
up_createstack.c up_dataabort.c up_mdelay.c up_udelay.c up_doirq.c \
|
||||
up_exit.c up_idle.c up_initialstate.c up_initialize.c \
|
||||
up_interruptcontext.c up_prefetchabort.c up_releasepending.c \
|
||||
up_releasestack.c up_reprioritizertr.c up_schedulesigaction.c \
|
||||
up_sigdeliver.c up_syscall.c up_unblocktask.c \
|
||||
up_undefinedinsn.c up_usestack.c calypso_power.c
|
||||
|
||||
ifeq ($(CONFIG_ELF),y)
|
||||
CMN_CSRCS += up_elf.c
|
||||
endif
|
||||
|
||||
CHIP_ASRCS = calypso_lowputc.S
|
||||
CHIP_CSRCS = calypso_irq.c calypso_timer.c calypso_heap.c \
|
||||
calypso_serial.c calypso_spi.c clock.c calypso_uwire.c
|
||||
CHIP_ASRCS = calypso_lowputc.S
|
||||
CHIP_CSRCS = calypso_irq.c calypso_timer.c calypso_heap.c calypso_serial.c \
|
||||
calypso_spi.c clock.c calypso_uwire.c calypso_armio.c calypso_keypad.c
|
||||
|
370
arch/arm/src/calypso/calypso_keypad.c
Normal file
370
arch/arm/src/calypso/calypso_keypad.c
Normal file
@ -0,0 +1,370 @@
|
||||
/****************************************************************************
|
||||
* Driver for Calypso keypad hardware
|
||||
*
|
||||
* Copyright (C) 2011 Stefan Richter. All rights reserved.
|
||||
* Author: Stefan Richter <ichgeh@l--putt.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include <arch/calypso/defines.h>
|
||||
#include <arch/calypso/memory.h>
|
||||
#include <arch/calypso/timer.h>
|
||||
|
||||
/****************************************************************************
|
||||
* HW access
|
||||
****************************************************************************/
|
||||
|
||||
#define BASE_ADDR_ARMIO 0xfffe4800
|
||||
#define ARMIO_REG(x) ((void *)BASE_ADDR_ARMIO + (x))
|
||||
|
||||
enum armio_reg
|
||||
{
|
||||
LATCH_IN = 0x00,
|
||||
LATCH_OUT = 0x02,
|
||||
IO_CNTL = 0x04,
|
||||
CNTL_REG = 0x06,
|
||||
LOAD_TIM = 0x08,
|
||||
KBR_LATCH_REG = 0x0a,
|
||||
KBC_REG = 0x0c,
|
||||
BUZZ_LIGHT_REG = 0x0e,
|
||||
LIGHT_LEVEL = 0x10,
|
||||
BUZZER_LEVEL = 0x12,
|
||||
GPIO_EVENT_MODE = 0x14,
|
||||
KBD_GPIO_INT = 0x16,
|
||||
KBD_GPIO_MASKIT = 0x18,
|
||||
GPIO_DEBOUNCING = 0x1a,
|
||||
GPIO_LATCH = 0x1c,
|
||||
};
|
||||
|
||||
#define KBD_INT (1 << 0)
|
||||
#define GPIO_INT (1 << 1)
|
||||
|
||||
/****************************************************************************
|
||||
* Decoder functions for matrix and power button
|
||||
****************************************************************************/
|
||||
|
||||
static int btn_dec(uint32_t * btn_state, uint8_t col, uint8_t reg,
|
||||
char *buf, size_t buflen, size_t * len)
|
||||
{
|
||||
uint8_t diff = (*btn_state ^ reg) & 0x1f;
|
||||
|
||||
while (diff)
|
||||
{
|
||||
uint8_t val = diff & ~(diff - 1);
|
||||
uint8_t sc = val >> 1;
|
||||
sc |= sc << 2;
|
||||
sc += col;
|
||||
sc += (sc & 0x20) ? 0x26 : 0x3f;
|
||||
|
||||
if (reg & val)
|
||||
{
|
||||
sc |= 0x20;
|
||||
}
|
||||
|
||||
/* Check for space in buffer and dispatch */
|
||||
|
||||
if (*len < buflen)
|
||||
{
|
||||
buf[(*len)++] = sc;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only change diff if dispatched/buffer not full */
|
||||
|
||||
diff ^= val;
|
||||
}
|
||||
|
||||
/* Store new state of the buttons (but only if they where dispatch) */
|
||||
|
||||
*btn_state >>= 5;
|
||||
#ifdef INCLUDE_ALL_COLS
|
||||
*btn_state |= (reg ^ diff) << 20;
|
||||
#else
|
||||
*btn_state |= (reg ^ diff) << 15;
|
||||
#endif
|
||||
return diff;
|
||||
}
|
||||
|
||||
static int pwr_btn_dec(uint32_t * state, uint8_t reg, char *buf, size_t * len)
|
||||
{
|
||||
if (reg)
|
||||
{
|
||||
/* Check for pressed power button. If pressed, ignore other
|
||||
* buttons since it collides with an entire row.
|
||||
*/
|
||||
|
||||
if (~*state & 0x80000000)
|
||||
{
|
||||
buf[0] = 'z';
|
||||
*len = 1;
|
||||
*state |= 0x80000000;
|
||||
}
|
||||
|
||||
return 1; // break loop in caller
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check for released power button. */
|
||||
|
||||
if (*state & 0x80000000)
|
||||
{
|
||||
buf[0] = 'Z';
|
||||
*len = 1;
|
||||
|
||||
*state &= 0x7fffffff;
|
||||
|
||||
/* Don't scan others when released; might trigger
|
||||
* false keystrokes otherwise
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // continue with other columns
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Keypad: Fileops Prototypes and Structures
|
||||
****************************************************************************/
|
||||
|
||||
typedef FAR struct file file_t;
|
||||
|
||||
static int keypad_open(file_t * filep);
|
||||
static int keypad_close(file_t * filep);
|
||||
static ssize_t keypad_read(file_t * filep, FAR char *buffer, size_t buflen);
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
static int keypad_poll(file_t * filep, FAR struct pollfd *fds, bool setup);
|
||||
#endif
|
||||
|
||||
static const struct file_operations keypad_ops =
|
||||
{
|
||||
keypad_open, /* open */
|
||||
keypad_close, /* close */
|
||||
keypad_read, /* read */
|
||||
0, /* write */
|
||||
0, /* seek */
|
||||
0, /* ioctl */
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
keypad_poll /* poll */
|
||||
#endif
|
||||
};
|
||||
|
||||
static sem_t kbdsem;
|
||||
|
||||
/****************************************************************************
|
||||
* Keypad: Fileops
|
||||
****************************************************************************/
|
||||
|
||||
static int keypad_open(file_t * filep)
|
||||
{
|
||||
register uint16_t reg;
|
||||
|
||||
/* Unmask keypad interrupt */
|
||||
reg = readw(ARMIO_REG(KBD_GPIO_MASKIT));
|
||||
writew(reg & ~KBD_INT, ARMIO_REG(KBD_GPIO_MASKIT));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int keypad_close(file_t * filep)
|
||||
{
|
||||
register uint16_t reg;
|
||||
|
||||
/* Mask keypad interrupt */
|
||||
|
||||
reg = readw(ARMIO_REG(KBD_GPIO_MASKIT));
|
||||
writew(reg | KBD_INT, ARMIO_REG(KBD_GPIO_MASKIT));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static ssize_t keypad_read(file_t * filep, FAR char *buf, size_t buflen)
|
||||
{
|
||||
static uint32_t btn_state = 0;
|
||||
register uint16_t reg;
|
||||
uint16_t col, col_mask;
|
||||
size_t len = 0;
|
||||
|
||||
if (buf == NULL || buflen < 1)
|
||||
{
|
||||
/* Well... nothing to do */
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
retry:
|
||||
col = 1;
|
||||
col_mask = 0x1e;
|
||||
|
||||
if (!btn_state)
|
||||
{
|
||||
/* Drive all cols low such that all buttons cause events */
|
||||
|
||||
writew(0, ARMIO_REG(KBC_REG));
|
||||
|
||||
/* No button currently pressed, use IRQ */
|
||||
|
||||
reg = readw(ARMIO_REG(KBD_GPIO_MASKIT));
|
||||
writew(reg & ~KBD_INT, ARMIO_REG(KBD_GPIO_MASKIT));
|
||||
sem_wait(&kbdsem);
|
||||
}
|
||||
else
|
||||
{
|
||||
writew(0x1f, ARMIO_REG(KBC_REG));
|
||||
usleep(80000);
|
||||
}
|
||||
|
||||
/* Scan columns */
|
||||
|
||||
#ifdef INCLUDE_ALL_COLS
|
||||
while (col <= 6)
|
||||
{
|
||||
#else
|
||||
while (col <= 5)
|
||||
{
|
||||
#endif
|
||||
/* Read keypad latch and immediately set new column since
|
||||
* synchronization takes about 5usec. For the 1st round, the
|
||||
* interrupt has prepared this and the context switch takes
|
||||
* long enough to serve as a delay.
|
||||
*/
|
||||
|
||||
reg = readw(ARMIO_REG(KBR_LATCH_REG));
|
||||
writew(col_mask, ARMIO_REG(KBC_REG));
|
||||
|
||||
/* Turn pressed buttons into 1s */
|
||||
|
||||
reg = 0x1f & ~reg;
|
||||
|
||||
if (col == 1)
|
||||
{
|
||||
/* Power/End switch */
|
||||
|
||||
if (pwr_btn_dec(&btn_state, reg, buf, &len))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Non-power switches */
|
||||
|
||||
if (btn_dec(&btn_state, col, reg, buf, buflen, &len))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Select next column and respective mask */
|
||||
|
||||
col_mask = 0x1f & ~(1 << col++);
|
||||
|
||||
/* We have to wait for synchronization of the inputs. The
|
||||
* processing is too fast if no/few buttons are processed.
|
||||
*/
|
||||
|
||||
usleep(5);
|
||||
|
||||
/* XXX: usleep seems to suffer hugh overhead. Better this!?
|
||||
* If nothing else can be done, it's overhead still wastes
|
||||
* time 'usefully'.
|
||||
*/
|
||||
/* sched_yield(); up_udelay(2); */
|
||||
}
|
||||
|
||||
/* If we don't have anything to return, retry to avoid EOF */
|
||||
|
||||
if (!len)
|
||||
{
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Keypad interrupt handler
|
||||
* mask interrupts
|
||||
* prepare column drivers for scan
|
||||
* posts keypad semaphore
|
||||
****************************************************************************/
|
||||
|
||||
inline int calypso_kbd_irq(int irq, uint32_t * regs)
|
||||
{
|
||||
register uint16_t reg;
|
||||
|
||||
/* Mask keypad interrupt */
|
||||
|
||||
reg = readw(ARMIO_REG(KBD_GPIO_MASKIT));
|
||||
writew(reg | KBD_INT, ARMIO_REG(KBD_GPIO_MASKIT));
|
||||
|
||||
/* Turn off column drivers */
|
||||
|
||||
writew(0x1f, ARMIO_REG(KBC_REG));
|
||||
|
||||
/* Let the userspace know */
|
||||
|
||||
sem_post(&kbdsem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Initialize device, add /dev/... nodes
|
||||
****************************************************************************/
|
||||
|
||||
void up_keypad(void)
|
||||
{
|
||||
/* Semaphore; helps leaving IRQ ctx as soon as possible */
|
||||
|
||||
sem_init(&kbdsem, 0, 0);
|
||||
|
||||
/* Drive cols low in idle state such that all buttons cause events */
|
||||
|
||||
writew(0, ARMIO_REG(KBC_REG));
|
||||
|
||||
(void)register_driver("/dev/keypad", &keypad_ops, 0444, NULL);
|
||||
}
|
Loading…
Reference in New Issue
Block a user