1/*	$NetBSD: tc5165buf.c,v 1.20 2021/08/07 16:18:54 thorpej Exp $ */
2
3/*-
4 * Copyright (c) 1999-2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * Device driver for TOSHIBA TC5165BFTS, PHILIPS 74ALVC16241/245
34 * buffer chip
35 */
36
37#include <sys/cdefs.h>
38__KERNEL_RCSID(0, "$NetBSD: tc5165buf.c,v 1.20 2021/08/07 16:18:54 thorpej Exp $");
39
40#include "opt_use_poll.h"
41
42#include <sys/param.h>
43#include <sys/bus.h>
44#include <sys/callout.h>
45#include <sys/device.h>
46#include <sys/intr.h>
47#include <sys/systm.h>
48
49#include <dev/hpc/hpckbdvar.h>
50
51#include <mips/cpuregs.h>
52
53#include <hpcmips/tx/tx39var.h>
54#include <hpcmips/tx/txcsbusvar.h>
55#include <hpcmips/dev/tc5165bufvar.h>
56
57#define TC5165_ROW_MAX		16
58#define TC5165_COLUMN_MAX	8
59
60#ifdef TC5165DEBUG
61#define	DPRINTF(arg) printf arg
62#else
63#define	DPRINTF(arg)
64#endif
65
66struct tc5165buf_chip {
67	bus_space_tag_t		scc_cst;
68	bus_space_handle_t	scc_csh;
69	u_int16_t		scc_buf[TC5165_COLUMN_MAX];
70	int			scc_enabled;
71	int			scc_queued;
72	struct callout		scc_soft_ch;
73	struct hpckbd_ic_if	scc_if;
74	struct hpckbd_if	*scc_hpckbd;
75};
76
77struct tc5165buf_softc {
78	struct tc5165buf_chip	*sc_chip;
79	tx_chipset_tag_t	sc_tc;
80	void			*sc_ih;
81};
82
83int	tc5165buf_match(device_t, cfdata_t, void *);
84void	tc5165buf_attach(device_t, device_t, void *);
85int	tc5165buf_intr(void *);
86int	tc5165buf_poll(void *);
87void	tc5165buf_soft(void *);
88void	tc5165buf_ifsetup(struct tc5165buf_chip *);
89
90int	tc5165buf_input_establish(void *, struct hpckbd_if *);
91
92struct tc5165buf_chip tc5165buf_chip;
93
94CFATTACH_DECL_NEW(tc5165buf, sizeof(struct tc5165buf_softc),
95    tc5165buf_match, tc5165buf_attach, NULL, NULL);
96
97int
98tc5165buf_match(device_t parent, cfdata_t cf, void *aux)
99{
100
101	return (1);
102}
103
104void
105tc5165buf_attach(device_t parent, device_t self, void *aux)
106{
107	struct cs_attach_args *ca = aux;
108	struct tc5165buf_softc *sc = device_private(self);
109	struct hpckbd_attach_args haa;
110
111	printf(": ");
112	sc->sc_tc = ca->ca_tc;
113	sc->sc_chip = &tc5165buf_chip;
114
115	callout_init(&sc->sc_chip->scc_soft_ch, 0);
116
117	sc->sc_chip->scc_cst = ca->ca_csio.cstag;
118
119	if (bus_space_map(sc->sc_chip->scc_cst, ca->ca_csio.csbase,
120	    ca->ca_csio.cssize, 0, &sc->sc_chip->scc_csh)) {
121		printf("can't map i/o space\n");
122		return;
123	}
124
125	sc->sc_chip->scc_enabled = 0;
126
127	if (ca->ca_irq1 != -1) {
128		sc->sc_ih = tx_intr_establish(sc->sc_tc, ca->ca_irq1,
129		    IST_EDGE, IPL_TTY,
130		    tc5165buf_intr, sc);
131		printf("interrupt mode");
132	} else {
133		sc->sc_ih = tx39_poll_establish(sc->sc_tc, 1, IPL_TTY,
134		    tc5165buf_intr, sc);
135		printf("polling mode");
136	}
137
138	if (!sc->sc_ih) {
139		printf(" can't establish interrupt\n");
140		return;
141	}
142
143	printf("\n");
144
145	/* setup upper interface */
146	tc5165buf_ifsetup(sc->sc_chip);
147
148	haa.haa_ic = &sc->sc_chip->scc_if;
149
150	config_found(self, &haa, hpckbd_print, CFARGS_NONE);
151}
152
153void
154tc5165buf_ifsetup(struct tc5165buf_chip *scc)
155{
156
157	scc->scc_if.hii_ctx		= scc;
158	scc->scc_if.hii_establish	= tc5165buf_input_establish;
159	scc->scc_if.hii_poll		= tc5165buf_poll;
160}
161
162int
163tc5165buf_cnattach(paddr_t addr)
164{
165	struct tc5165buf_chip *scc = &tc5165buf_chip;
166
167	scc->scc_csh = MIPS_PHYS_TO_KSEG1(addr);
168
169	tc5165buf_ifsetup(scc);
170
171	hpckbd_cnattach(&scc->scc_if);
172
173	return (0);
174}
175
176int
177tc5165buf_input_establish(void *ic, struct hpckbd_if *kbdif)
178{
179	struct tc5165buf_chip *scc = ic;
180
181	/* save hpckbd interface */
182	scc->scc_hpckbd = kbdif;
183
184	scc->scc_enabled = 1;
185
186	return (0);
187}
188
189int
190tc5165buf_intr(void *arg)
191{
192	struct tc5165buf_softc *sc = arg;
193	struct tc5165buf_chip *scc = sc->sc_chip;
194
195	if (!scc->scc_enabled || scc->scc_queued)
196		return (0);
197
198	scc->scc_queued = 1;
199	callout_reset(&scc->scc_soft_ch, 1, tc5165buf_soft, scc);
200
201	return (0);
202}
203
204int
205tc5165buf_poll(void *arg)
206{
207	struct tc5165buf_chip *scc = arg;
208
209	if (!scc->scc_enabled)
210		return (POLL_CONT);
211
212	tc5165buf_soft(arg);
213
214	return (POLL_CONT);
215}
216
217void
218tc5165buf_soft(void *arg)
219{
220	struct tc5165buf_chip *scc = arg;
221	bus_space_tag_t t = scc->scc_cst;
222	bus_space_handle_t h = scc->scc_csh;
223	u_int16_t mask, rpat, edge;
224	int i, j, type, val;
225	int s;
226
227	hpckbd_input_hook(scc->scc_hpckbd);
228
229	/* clear scanlines */
230	(void)bus_space_read_2(t, h, 0);
231	delay(3);
232
233	for (i = 0; i < TC5165_COLUMN_MAX; i++) {
234		rpat = bus_space_read_2(t, h, 2 << i);
235		delay(3);
236		(void)bus_space_read_2(t, h, 0);
237		delay(3);
238		if ((edge = (rpat ^ scc->scc_buf[i]))) {
239			scc->scc_buf[i] = rpat;
240			for (j = 0, mask = 1; j < TC5165_ROW_MAX;
241			    j++, mask <<= 1) {
242				if (mask & edge) {
243					type = mask & rpat ? 1 : 0;
244					val = j * TC5165_COLUMN_MAX + i;
245					DPRINTF(("%d %d\n", j, i));
246					hpckbd_input(scc->scc_hpckbd,
247					    type, val);
248				}
249			}
250		}
251	}
252
253	s = spltty();
254	scc->scc_queued = 0;
255	splx(s);
256}
257