Module Name: src
Committed By: khorben
Date: Sun May 12 01:49:44 UTC 2013
Modified Files:
src/sys/arch/evbarm/conf [khorben-n900]: N900
src/sys/conf [khorben-n900]: files
src/sys/dev/i2c [khorben-n900]: files.i2c tps65950.c tps65950reg.h
Log Message:
Added keyboard support for the TPS65950 companion chip.
Tested on the Nokia N900 (multi-user)
To generate a diff of this commit:
cvs rdiff -u -r1.13.2.4 -r1.13.2.5 src/sys/arch/evbarm/conf/N900
cvs rdiff -u -r1.1070 -r1.1070.2.1 src/sys/conf/files
cvs rdiff -u -r1.49.2.2 -r1.49.2.3 src/sys/dev/i2c/files.i2c
cvs rdiff -u -r1.3.10.3 -r1.3.10.4 src/sys/dev/i2c/tps65950.c
cvs rdiff -u -r1.1.2.3 -r1.1.2.4 src/sys/dev/i2c/tps65950reg.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/evbarm/conf/N900
diff -u src/sys/arch/evbarm/conf/N900:1.13.2.4 src/sys/arch/evbarm/conf/N900:1.13.2.5
--- src/sys/arch/evbarm/conf/N900:1.13.2.4 Sun May 12 00:42:50 2013
+++ src/sys/arch/evbarm/conf/N900 Sun May 12 01:49:44 2013
@@ -1,5 +1,5 @@
#
-# $NetBSD: N900,v 1.13.2.4 2013/05/12 00:42:50 khorben Exp $
+# $NetBSD: N900,v 1.13.2.5 2013/05/12 01:49:44 khorben Exp $
#
# N900 -- Nokia N900 Kernel
#
@@ -255,6 +255,9 @@ tps65950pm3 at iic0 addr 0x4b
gpio* at tps65950pm1
+# Integrated keyboard
+wskbd* at tps65950pm2 mux 1
+
# SPI devices
omapspi0 at obio0 addr 0x48098000 size 0x1000 intr 65
omapspi1 at obio0 addr 0x4809a000 size 0x1000 intr 66
Index: src/sys/conf/files
diff -u src/sys/conf/files:1.1070 src/sys/conf/files:1.1070.2.1
--- src/sys/conf/files:1.1070 Sun Apr 28 03:11:32 2013
+++ src/sys/conf/files Sun May 12 01:49:44 2013
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.1070 2013/04/28 03:11:32 christos Exp $
+# $NetBSD: files,v 1.1070.2.1 2013/05/12 01:49:44 khorben Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20100430
@@ -323,6 +323,17 @@ attach midi at midibus
#
define audiobell
+# display attributes, display with emulator, keyboard, and mouse
+#
+define wsdisplaydev {[kbdmux = 1]}
+define wsemuldisplaydev {[console = -1], [kbdmux = 1]}
+define wskbddev {[console = -1], [mux = 1]}
+define wsmousedev {[mux = 0]}
+define vcons
+# attribute to pull in raster support
+#
+define wsrasteremulops
+
# video devices, attaches to video hardware driver
#
device video
@@ -1100,16 +1111,6 @@ include "dev/drm/files.drm"
# Definitions for wscons
-# device attributes: display, display with emulator, keyboard, and mouse
-#
-define wsdisplaydev {[kbdmux = 1]}
-define wsemuldisplaydev {[console = -1], [kbdmux = 1]}
-define wskbddev {[console = -1], [mux = 1]}
-define wsmousedev {[mux = 0]}
-define vcons
-# attribute to pull in raster support
-#
-define wsrasteremulops
# common PC display functions
#
defflag opt_pcdisplay.h PCDISPLAY_SOFTCURSOR
Index: src/sys/dev/i2c/files.i2c
diff -u src/sys/dev/i2c/files.i2c:1.49.2.2 src/sys/dev/i2c/files.i2c:1.49.2.3
--- src/sys/dev/i2c/files.i2c:1.49.2.2 Sun May 12 00:56:28 2013
+++ src/sys/dev/i2c/files.i2c Sun May 12 01:49:44 2013
@@ -1,4 +1,4 @@
-# $NetBSD: files.i2c,v 1.49.2.2 2013/05/12 00:56:28 khorben Exp $
+# $NetBSD: files.i2c,v 1.49.2.3 2013/05/12 01:49:44 khorben Exp $
obsolete defflag opt_i2cbus.h I2C_SCAN
define i2cbus { }
@@ -173,7 +173,7 @@ attach ibmhawk at iic
file dev/i2c/ibmhawk.c ibmhawk
# TI TPS65950 OMAP Power Management and System Companion Device
-device tps65950pm: gpiobus, sysmon_wdog
+device tps65950pm: gpiobus, sysmon_wdog, wskbddev
attach tps65950pm at iic
file dev/i2c/tps65950.c tps65950pm
Index: src/sys/dev/i2c/tps65950.c
diff -u src/sys/dev/i2c/tps65950.c:1.3.10.3 src/sys/dev/i2c/tps65950.c:1.3.10.4
--- src/sys/dev/i2c/tps65950.c:1.3.10.3 Sun May 12 00:42:50 2013
+++ src/sys/dev/i2c/tps65950.c Sun May 12 01:49:44 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: tps65950.c,v 1.3.10.3 2013/05/12 00:42:50 khorben Exp $ */
+/* $NetBSD: tps65950.c,v 1.3.10.4 2013/05/12 01:49:44 khorben Exp $ */
/*-
* Copyright (c) 2012 Jared D. McNeill <[email protected]>
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tps65950.c,v 1.3.10.3 2013/05/12 00:42:50 khorben Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tps65950.c,v 1.3.10.4 2013/05/12 01:49:44 khorben Exp $");
#define _INTR_PRIVATE
@@ -55,6 +55,13 @@ __KERNEL_RCSID(0, "$NetBSD: tps65950.c,v
#include <dev/gpio/gpiovar.h>
#endif /* NGPIO > 0 */
+#if defined(OMAP_3430)
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wskbdvar.h>
+#include <dev/wscons/wsksymdef.h>
+#include <dev/wscons/wsksymvar.h>
+#endif
+
#include <dev/clock_subr.h>
#include <dev/sysmon/sysmonvar.h>
@@ -89,17 +96,29 @@ struct tps65950_softc {
offsetof(struct tps65950_softc, sc_gpio_pic)))
#endif /* NGPIO > 0 */
+#if defined(OMAP_3430)
+ /* KEYPAD */
+ device_t sc_wskbddev;
+ uint8_t sc_keycodes[8];
+#endif
+
/* WATCHDOG */
struct sysmon_wdog sc_smw;
struct todr_chip_handle sc_todr;
};
-
/* XXX global workqueue to re-enable interrupts once handled */
static struct workqueue *tps65950_pih_workqueue;
static struct work tps65950_pih_workqueue_work;
static bool tps65950_pih_workqueue_available;
+#if defined(OMAP_3430)
+/* XXX global workqueue to handle keyboard events on the right address */
+static struct workqueue *tps65950_kbd_workqueue;
+static struct work tps65950_kbd_workqueue_work;
+static bool tps65950_kbd_workqueue_available;
+#endif
+
static int tps65950_match(device_t, cfdata_t, void *);
static void tps65950_attach(device_t, device_t, void *);
@@ -139,6 +158,92 @@ const struct pic_ops tps65950_gpio_pic_o
};
#endif /* NGPIO > 0 */
+#if defined(OMAP_3430)
+static void tps65950_kbd_attach(struct tps65950_softc *);
+
+static void tps65950_kbd_intr(struct tps65950_softc *);
+static void tps65950_kbd_intr_work(struct work *, void *);
+
+static int tps65950_kbd_enable(void *, int);
+static void tps65950_kbd_set_leds(void *, int);
+static int tps65950_kbd_ioctl(void *, u_long, void *, int, struct lwp *);
+
+#define KC(n) KS_KEYCODE(n)
+static const keysym_t n900_keydesc_us[] = {
+ KC(0), KS_q,
+ KC(1), KS_o,
+ KC(2), KS_p,
+ KC(3), KS_comma,
+ KC(4), KS_BackSpace,
+ KC(6), KS_a,
+ KC(7), KS_s,
+ KC(8), KS_w,
+ KC(9), KS_d,
+ KC(10), KS_f,
+ KC(11), KS_g,
+ KC(12), KS_h,
+ KC(13), KS_j,
+ KC(14), KS_k,
+ KC(15), KS_l,
+ KC(16), KS_e,
+ KC(17), KS_period,
+ KC(18), KS_Up,
+ KC(19), KS_Return,
+ KC(21), KS_z,
+ KC(22), KS_x,
+ KC(23), KS_c,
+ KC(24), KS_r,
+ KC(25), KS_v,
+ KC(26), KS_b,
+ KC(27), KS_n,
+ KC(28), KS_m,
+ KC(29), KS_space,
+ KC(30), KS_space,
+ KC(31), KS_Left,
+ KC(32), KS_t,
+ KC(33), KS_Down,
+ KC(35), KS_Right,
+ KC(36), KS_Control_L,
+ KC(37), KS_Alt_R,
+ KC(38), KS_Shift_L,
+ KC(40), KS_y,
+ KC(48), KS_u,
+ KC(56), KS_i,
+ /* XXX report these differently according to the current profile? */
+ KC(57), KS_f7,
+ KC(58), KS_f8
+};
+
+#define KBD_MAP(name, base, map) \
+ { name, base, sizeof(map)/sizeof(keysym_t), map }
+const struct wscons_keydesc tps65950_kbd_keydesctab[] =
+{
+ KBD_MAP(KB_US, 0, n900_keydesc_us),
+ {0, 0, 0, 0}
+};
+#undef KBD_MAP
+
+const struct wskbd_mapdata tps65950_kbd_keymapdata = {
+ tps65950_kbd_keydesctab,
+ KB_US
+};
+
+static struct wskbd_accessops tps65950_kbd_accessops = {
+ tps65950_kbd_enable,
+ tps65950_kbd_set_leds,
+ tps65950_kbd_ioctl
+};
+
+static void tps65950_kbd_cngetc(void *, u_int *, int *);
+static void tps65950_kbd_cnpollc(void *, int);
+
+static const struct wskbd_consops tps65950_kbd_consops = {
+ tps65950_kbd_cngetc,
+ tps65950_kbd_cnpollc,
+ NULL
+};
+#endif
+
static void tps65950_rtc_attach(struct tps65950_softc *);
static int tps65950_rtc_enable(struct tps65950_softc *, bool);
static int tps65950_rtc_gettime(todr_chip_handle_t, struct clock_ymdhms *);
@@ -210,6 +315,13 @@ tps65950_attach(device_t parent, device_
case TPS65950_ADDR_ID3:
aprint_normal(": LED\n");
tps65950_sysctl_attach(sc);
+
+#if defined(OMAP_3430)
+ aprint_normal(", KEYPAD\n");
+ tps65950_kbd_attach(sc);
+#else
+ aprint_normal("\n");
+#endif
break;
case TPS65950_ADDR_ID4:
aprint_normal(": RTC, WATCHDOG\n");
@@ -370,6 +482,10 @@ tps65950_intr_work(struct work *work, vo
if (u8 & TPS65950_PIH_REG_ISR_P1_ISR0)
tps65950_gpio_intr(sc);
#endif /* NGPIO > 0 */
+#ifdef OMAP_3430
+ if (u8 & TPS65950_PIH_REG_ISR_P1_ISR1)
+ tps65950_kbd_intr(sc);
+#endif
iic_release_bus(sc->sc_i2c, 0);
@@ -652,7 +768,6 @@ tps65950_gpio_pic_find_pending_irqs(stru
tps65950_read_1(sc, TPS65950_GPIO_GPIO_ISR3A, &u8);
pending |= ((u8 & 0x3) << 16);
iic_release_bus(sc->sc_i2c, 0);
- aprint_normal_dev(sc->sc_dev, "%s() 0x%08x\n", __func__, pending);
return pending;
}
@@ -699,6 +814,226 @@ tps65950_gpio_pic_establish_irq(struct p
}
#endif /* NGPIO > 0 */
+#if defined(OMAP_3430)
+static void
+tps65950_kbd_attach(struct tps65950_softc *sc)
+{
+ uint8_t u8;
+ struct wskbddev_attach_args a;
+ int error;
+
+ iic_acquire_bus(sc->sc_i2c, 0);
+
+ /* reset the keyboard */
+ tps65950_write_1(sc, TPS65950_KEYPAD_REG_CTRL_REG, 0);
+
+ /* configure the keyboard */
+ u8 = TPS65950_KEYPAD_REG_CTRL_REG_KBD_ON
+ | TPS65950_KEYPAD_REG_CTRL_REG_SOFTMODEN
+ | TPS65950_KEYPAD_REG_CTRL_REG_SOFT_NRST;
+ tps65950_write_1(sc, TPS65950_KEYPAD_REG_CTRL_REG, u8);
+ u8 = 0 /* TPS65950_KEYPAD_REG_SIH_CTRL_COR */
+ | TPS65950_KEYPAD_REG_SIH_CTRL_EXCLEN;
+ tps65950_write_1(sc, TPS65950_KEYPAD_REG_SIH_CTRL, u8);
+
+ iic_release_bus(sc->sc_i2c, 0);
+
+ wskbd_cnattach(&tps65950_kbd_consops, sc, &tps65950_kbd_keymapdata);
+
+ a.console = 1;
+ a.keymap = &tps65950_kbd_keymapdata;
+ a.accessops = &tps65950_kbd_accessops;
+ a.accesscookie = sc;
+
+ sc->sc_wskbddev = config_found_sm_loc(sc->sc_dev, NULL, NULL, &a,
+ wskbddevprint, NULL);
+
+ /* create the workqueue */
+ error = workqueue_create(&tps65950_kbd_workqueue,
+ device_xname(sc->sc_dev), tps65950_kbd_intr_work, sc,
+ PRIO_MAX, IPL_VM, 0);
+ if (error) {
+ aprint_error_dev(sc->sc_dev, "couldn't create workqueue\n");
+ return;
+ }
+ tps65950_kbd_workqueue_available = true;
+}
+
+static void
+tps65950_kbd_intr(struct tps65950_softc *sc)
+{
+ if (tps65950_kbd_workqueue_available) {
+ workqueue_enqueue(tps65950_kbd_workqueue,
+ &tps65950_kbd_workqueue_work, NULL);
+ tps65950_kbd_workqueue_available = false;
+ }
+}
+
+static void
+tps65950_kbd_intr_work(struct work *work, void *v)
+{
+ struct tps65950_softc *sc = v;
+ uint8_t u8;
+ uint8_t code[8];
+ int i;
+ int j;
+ u_int type;
+ int data;
+ int s;
+
+ iic_acquire_bus(sc->sc_i2c, 0);
+ tps65950_read_1(sc, TPS65950_KEYPAD_REG_ISR1, &u8);
+
+ /* check if there is anything to do */
+ if (u8 == 0) {
+ iic_release_bus(sc->sc_i2c, 0);
+
+ /* allow queueing again */
+ tps65950_kbd_workqueue_available = true;
+ return;
+ }
+
+ /* read the keycodes pressed */
+ for (i = 0; i < sizeof(code); i++) {
+ /* XXX assumes registers are successive */
+ tps65950_read_1(sc, TPS65950_KEYPAD_REG_FULL_CODE_7_0 + i,
+ &code[i]);
+ }
+
+ /* compare with the last read */
+ for (i = 0; i < sizeof(sc->sc_keycodes); i++) {
+ if (sc->sc_keycodes[i] == code[i])
+ continue;
+ for (j = 0; j < 8; j++) {
+ if ((sc->sc_keycodes[i] & (1 << j))
+ == (code[i] & (1 << j)))
+ continue;
+ /* report the keyboard event */
+ type = (code[i] & (1 << j)) ? WSCONS_EVENT_KEY_DOWN
+ : WSCONS_EVENT_KEY_UP;
+ data = (i * 8) + j;
+ s = spltty();
+ wskbd_input(sc->sc_wskbddev, type, data);
+ splx(s);
+#if 1 /* XXX ugly hack */
+ if (type == WSCONS_EVENT_KEY_DOWN)
+ {
+ type = WSCONS_EVENT_KEY_UP;
+ s = spltty();
+ wskbd_input(sc->sc_wskbddev, type, data);
+ splx(s);
+ }
+#endif
+ }
+ sc->sc_keycodes[i] = code[i];
+ }
+
+ /* acknowledge the interrupt */
+ tps65950_write_1(sc, TPS65950_KEYPAD_REG_ISR1, 0xff);
+ iic_release_bus(sc->sc_i2c, 0);
+
+ /* allow queueing again */
+ tps65950_kbd_workqueue_available = true;
+}
+
+static int
+tps65950_kbd_enable(void *v, int on)
+{
+ struct tps65950_softc *sc = v;
+ uint8_t u8 = 0;
+
+ if (sc->sc_intr == NULL)
+ return ENXIO;
+
+ iic_acquire_bus(sc->sc_i2c, 0);
+ if (on)
+ u8 |= TPS65950_KEYPAD_REG_IMR1_ITKPIMR1;
+ else
+ u8 &= ~(TPS65950_KEYPAD_REG_IMR1_ITKPIMR1);
+ tps65950_write_1(sc, TPS65950_KEYPAD_REG_IMR1, u8);
+ iic_release_bus(sc->sc_i2c, 0);
+
+ return 0;
+}
+
+static void
+tps65950_kbd_set_leds(void *v, int leds)
+{
+}
+
+static int
+tps65950_kbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
+{
+ switch (cmd) {
+ case WSKBDIO_GTYPE:
+ *(int *)data = WSKBD_TYPE_N900;
+ return 0;
+ case WSKBDIO_SETLEDS:
+ return 0;
+ case WSKBDIO_GETLEDS:
+ *(int *)data = 0;
+ return 0;
+ }
+ return EPASSTHROUGH;
+}
+
+static void
+tps65950_kbd_cngetc(void *v, u_int *type, int *data)
+{
+ struct tps65950_softc *sc = v;
+ uint8_t u8;
+ uint8_t code[8];
+ int i;
+ int j;
+
+ for (;;) {
+ /* poll for keycodes */
+ tps65950_read_1(sc, TPS65950_KEYPAD_REG_ISR1, &u8);
+ if (u8 != 0)
+ break;
+ delay(100);
+ }
+
+ /* read the keycodes pressed */
+ for (i = 0; i < sizeof(code); i++) {
+ /* XXX assumes registers are successive */
+ tps65950_read_1(sc, TPS65950_KEYPAD_REG_FULL_CODE_7_0 + i,
+ &code[i]);
+ }
+
+ /* acknowledge the interrupt */
+ tps65950_write_1(sc, TPS65950_KEYPAD_REG_ISR1, 0xff);
+
+ /* compare with the last read */
+ for (i = 0; i < sizeof(sc->sc_keycodes); i++) {
+ if (sc->sc_keycodes[i] == code[i])
+ continue;
+ for (j = 0; j < 8; j++) {
+ if ((sc->sc_keycodes[i] & (1 << j))
+ == (code[i] & (1 << j)))
+ continue;
+ *type = (code[i] & (1 << j)) ? WSCONS_EVENT_KEY_DOWN
+ : WSCONS_EVENT_KEY_UP;
+ *data = (i * 8) + j;
+ sc->sc_keycodes[i] = code[i];
+ break;
+ }
+ break;
+ }
+}
+
+static void
+tps65950_kbd_cnpollc(void *v, int on)
+{
+ struct tps65950_softc *sc = v;
+
+ if (on)
+ iic_acquire_bus(sc->sc_i2c, 0);
+ else
+ iic_release_bus(sc->sc_i2c, 0);
+}
+#endif
+
static void
tps65950_rtc_attach(struct tps65950_softc *sc)
{
Index: src/sys/dev/i2c/tps65950reg.h
diff -u src/sys/dev/i2c/tps65950reg.h:1.1.2.3 src/sys/dev/i2c/tps65950reg.h:1.1.2.4
--- src/sys/dev/i2c/tps65950reg.h:1.1.2.3 Sun May 12 00:42:50 2013
+++ src/sys/dev/i2c/tps65950reg.h Sun May 12 01:49:44 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: tps65950reg.h,v 1.1.2.3 2013/05/12 00:42:50 khorben Exp $ */
+/* $NetBSD: tps65950reg.h,v 1.1.2.4 2013/05/12 01:49:44 khorben Exp $ */
/*-
* Copyright (c) 2012 Jared D. McNeill <[email protected]>
@@ -117,7 +117,37 @@
#define TPS65950_PIH_REG_ISR_P2_ISR0 __BIT(0)
#define TPS65950_PIH_REG_SIR (TPS65950_PIH_BASE + 0x03)
-/* ID3 */
+/* ID3: KEYPAD */
+#define TPS65950_KEYPAD_BASE 0xd2
+#define TPS65950_KEYPAD_REG_CTRL_REG (TPS65950_KEYPAD_BASE + 0x00)
+#define TPS65950_KEYPAD_REG_CTRL_REG_KBD_ON __BIT(6)
+#define TPS65950_KEYPAD_REG_CTRL_REG_RP_EN __BIT(5)
+#define TPS65950_KEYPAD_REG_CTRL_REG_TOLE_EN __BIT(4)
+#define TPS65950_KEYPAD_REG_CTRL_REG_TOE_EN __BIT(3)
+#define TPS65950_KEYPAD_REG_CTRL_REG_LK_EN __BIT(2)
+#define TPS65950_KEYPAD_REG_CTRL_REG_SOFTMODEN __BIT(1)
+#define TPS65950_KEYPAD_REG_CTRL_REG_SOFT_NRST __BIT(0)
+#define TPS65950_KEYPAD_REG_FULL_CODE_7_0 (TPS65950_KEYPAD_BASE + 0x09)
+#define TPS65950_KEYPAD_REG_FULL_CODE_15_8 (TPS65950_KEYPAD_BASE + 0x0a)
+#define TPS65950_KEYPAD_REG_FULL_CODE_23_16 (TPS65950_KEYPAD_BASE + 0x0b)
+#define TPS65950_KEYPAD_REG_FULL_CODE_31_24 (TPS65950_KEYPAD_BASE + 0x0c)
+#define TPS65950_KEYPAD_REG_FULL_CODE_39_32 (TPS65950_KEYPAD_BASE + 0x0d)
+#define TPS65950_KEYPAD_REG_FULL_CODE_47_40 (TPS65950_KEYPAD_BASE + 0x0e)
+#define TPS65950_KEYPAD_REG_FULL_CODE_55_48 (TPS65950_KEYPAD_BASE + 0x0f)
+#define TPS65950_KEYPAD_REG_FULL_CODE_63_56 (TPS65950_KEYPAD_BASE + 0x10)
+#define TPS65950_KEYPAD_REG_ISR1 (TPS65950_KEYPAD_BASE + 0x11)
+#define TPS65950_KEYPAD_REG_ISR1_ITKPISR1 __BIT(0)
+#define TPS65950_KEYPAD_REG_IMR1 (TPS65950_KEYPAD_BASE + 0x12)
+#define TPS65950_KEYPAD_REG_IMR1_ITMISIMR1 __BIT(3)
+#define TPS65950_KEYPAD_REG_IMR1_ITTOIMR1 __BIT(2)
+#define TPS65950_KEYPAD_REG_IMR1_ITLKIMR1 __BIT(1)
+#define TPS65950_KEYPAD_REG_IMR1_ITKPIMR1 __BIT(0)
+#define TPS65950_KEYPAD_REG_SIH_CTRL (TPS65950_KEYPAD_BASE + 0x17)
+#define TPS65950_KEYPAD_REG_SIH_CTRL_COR __BIT(2)
+#define TPS65950_KEYPAD_REG_SIH_CTRL_PENDDIS __BIT(1)
+#define TPS65950_KEYPAD_REG_SIH_CTRL_EXCLEN __BIT(0)
+
+/* ID3: LED */
#define TPS65950_LED_BASE 0xee
#define TPS65950_ID3_REG_LED (TPS65950_LED_BASE + 0)
#define TPS65950_ID3_REG_LED_LEDAON __BIT(0)