1 /* $NetBSD: ucbtp.c,v 1.18 2008/04/28 20:23:21 martin Exp $ */
4 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * Device driver for PHILIPS UCB1200 Advanced modem/audio analog front-end
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: ucbtp.c,v 1.18 2008/04/28 20:23:21 martin Exp $");
40 #include "opt_use_poll.h"
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/device.h>
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48 #include <machine/bootinfo.h> /* bootinfo */
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wsmousevar.h>
53 #include <dev/hpc/hpctpanelvar.h>
55 #include <hpcmips/tx/tx39var.h>
56 #include <hpcmips/tx/tx39sibvar.h>
57 #include <hpcmips/tx/tx39sibreg.h>
58 #include <hpcmips/tx/tx39icureg.h>
60 #include <hpcmips/dev/ucb1200var.h>
61 #include <hpcmips/dev/ucb1200reg.h>
63 #include <hpcmips/tx/txsnd.h>
64 #include <dev/hpc/video_subr.h> /* debug */
68 #define DPRINTF(arg) if (ucbtp_debug) printf arg;
69 #define DPRINTFN(n, arg) if (ucbtp_debug > (n)) printf arg;
72 #define DPRINTFN(n, arg)
86 #define UCBTS_PRESS_THRESHOLD 80
87 #define UCBTS_TAP_THRESHOLD 5
91 /* 1 */ UCBADC_ADC_INIT
,
92 /* 2 */ UCBADC_ADC_FINI
,
93 /* 3 */ UCBADC_MEASUMENT_INIT
,
94 /* 4 */ UCBADC_MEASUMENT_FINI
,
95 /* 5 */ UCBADC_ADC_ENABLE
,
96 /* 6 */ UCBADC_ADC_START0
,
97 /* 7 */ UCBADC_ADC_START1
,
98 /* 8 */ UCBADC_ADC_DATAREAD
,
99 /* 9 */ UCBADC_ADC_DATAREAD_WAIT
,
100 /*10 */ UCBADC_ADC_DISABLE
,
101 /*11 */ UCBADC_ADC_INTRMODE
,
102 /*12 */ UCBADC_ADC_INPUT
,
103 /*13 */ UCBADC_INTR_ACK0
,
104 /*14 */ UCBADC_INTR_ACK1
,
105 /*15 */ UCBADC_INTR_ACK2
,
106 /*16 */ UCBADC_REGREAD
,
107 /*17 */ UCBADC_REGWRITE
111 struct device sc_dev
;
112 struct device
*sc_sib
; /* parent (TX39 SIB module) */
113 struct device
*sc_ucb
; /* parent (UCB1200 module) */
114 tx_chipset_tag_t sc_tc
;
116 enum ucbts_stat sc_stat
;
118 int sc_polling_finish
;
121 struct tpcalib_softc sc_tpcalib
;
124 /* measurement value */
125 int sc_x
, sc_y
, sc_p
;
127 int sc_xy_reverse
; /* some platform pin connect interchanged */
130 * touch panel state machine
132 void *sm_ih
; /* TX39 SIB subframe 0 interrupt handler */
134 int sm_addr
; /* UCB1200 register address */
135 u_int32_t sm_reg
; /* UCB1200 register data & TX39 SIB header */
137 #define UCBADC_RETRY_DEFAULT 200
138 int sm_retry
; /* retry counter */
140 enum ucbadc_state sm_state
;
141 int sm_measurement
; /* X, Y, Pressure */
142 #define UCBADC_MEASUREMENT_X 0
143 #define UCBADC_MEASUREMENT_Y 1
144 #define UCBADC_MEASUREMENT_PRESSURE 2
147 int sm_read_state
, sm_write_state
;
148 int sm_writing
; /* writing state flag */
149 u_int32_t sm_write_val
; /* temporary buffer */
151 int sm_rw_retry
; /* retry counter for r/w */
154 struct device
*sc_wsmousedev
;
157 int ucbtp_match(struct device
*, struct cfdata
*, void *);
158 void ucbtp_attach(struct device
*, struct device
*, void *);
160 int ucbtp_sibintr(void *);
161 int ucbtp_poll(void *);
162 int ucbtp_adc_async(void *);
163 int ucbtp_input(struct ucbtp_softc
*);
164 int ucbtp_busy(void *);
166 int ucbtp_enable(void *);
167 int ucbtp_ioctl(void *, u_long
, void *, int, struct lwp
*);
168 void ucbtp_disable(void *);
170 CFATTACH_DECL(ucbtp
, sizeof(struct ucbtp_softc
),
171 ucbtp_match
, ucbtp_attach
, NULL
, NULL
);
173 const struct wsmouse_accessops ucbtp_accessops
= {
180 * XXX currently no calibration method. this is temporary hack.
182 #include <machine/platid.h>
184 struct wsmouse_calibcoords
*calibration_sample_lookup(void);
185 int ucbtp_calibration(struct ucbtp_softc
*);
187 struct calibration_sample_table
{
188 platid_t cst_platform
;
189 struct wsmouse_calibcoords cst_sample
;
190 } calibration_sample_table
[] = {
191 {{{PLATID_WILD
, PLATID_MACH_COMPAQ_C_8XX
}}, /* uch machine */
193 {{ 507, 510, 320, 120 },
194 { 898, 757, 40, 40 },
195 { 900, 255, 40, 200 },
196 { 109, 249, 600, 200 },
197 { 110, 753, 600, 40 }}}},
199 {{{PLATID_WILD
, PLATID_MACH_COMPAQ_C_2010
}}, /* uch machine */
201 {{ 506, 487, 320, 120 },
202 { 880, 250, 40, 40 },
203 { 880, 718, 40, 200 },
204 { 140, 726, 600, 200 },
205 { 137, 250, 600, 40 }}}},
207 {{{PLATID_WILD
, PLATID_MACH_SHARP_MOBILON_HC4100
}}, /* uch machine */
209 {{ 497, 501, 320, 120 },
210 { 752, 893, 40, 40 },
211 { 242, 891, 40, 200 },
212 { 241, 115, 600, 200 },
213 { 747, 101, 600, 40 }}}},
215 {{{PLATID_WILD
, PLATID_MACH_SHARP_TELIOS_HCVJ
}}, /* uch machine */
218 { 850, 880, 1, 479 },
219 { 850, 880, 1, 479 },
220 { 85, 880, 799, 479 },
221 { 85, 150, 799, 1 }}}},
223 {{{PLATID_UNKNOWN
, PLATID_UNKNOWN
}},
232 struct wsmouse_calibcoords
*
233 calibration_sample_lookup(void)
235 struct calibration_sample_table
*tab
;
238 for (tab
= calibration_sample_table
;
239 tab
->cst_platform
.dw
.dw1
!= PLATID_UNKNOWN
; tab
++) {
241 mask
= PLATID_DEREF(&tab
->cst_platform
);
243 if (platid_match(&platid
, &mask
)) {
244 return (&tab
->cst_sample
);
252 ucbtp_calibration(struct ucbtp_softc
*sc
)
254 struct wsmouse_calibcoords
*cs
;
256 if (sc
->sc_tc
->tc_videot
)
257 video_calibration_pattern(sc
->sc_tc
->tc_videot
); /* debug */
259 tpcalib_init(&sc
->sc_tpcalib
);
261 if (!(cs
= calibration_sample_lookup())) {
262 DPRINTF(("no calibration data"));
267 tpcalib_ioctl(&sc
->sc_tpcalib
, WSMOUSEIO_SCALIBCOORDS
,
268 (void *)cs
, 0, 0) == 0 ? 1 : 0;
270 if (!sc
->sc_calibrated
)
272 printf("calibrated");
278 ucbtp_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
285 ucbtp_attach(struct device
*parent
, struct device
*self
, void *aux
)
287 struct ucb1200_attach_args
*ucba
= aux
;
288 struct ucbtp_softc
*sc
= (void*)self
;
289 struct wsmousedev_attach_args wsmaa
;
292 tc
= sc
->sc_tc
= ucba
->ucba_tc
;
293 sc
->sc_sib
= ucba
->ucba_sib
;
294 sc
->sc_ucb
= ucba
->ucba_ucb
;
297 /* touch panel interrupt */
298 tx_intr_establish(tc
, MAKEINTR(1, TX39_INTRSTATUS1_SIBIRQPOSINT
),
299 IST_EDGE
, IPL_TTY
, ucbtp_sibintr
, sc
);
301 /* attempt to calibrate touch panel */
302 ucbtp_calibration(sc
);
303 #ifdef TX392X /* hack for Telios HC-VJ1C */
304 sc
->sc_xy_reverse
= 1;
309 wsmaa
.accessops
= &ucbtp_accessops
;
310 wsmaa
.accesscookie
= sc
;
312 ucb1200_state_install(parent
, ucbtp_busy
, self
, UCB1200_TP_MODULE
);
317 sc
->sc_wsmousedev
= config_found(self
, &wsmaa
, wsmousedevprint
);
321 ucbtp_busy(void *arg
)
323 struct ucbtp_softc
*sc
= arg
;
325 return (sc
->sm_state
!= UCBADC_IDLE
);
329 ucbtp_poll(void *arg
)
331 struct ucbtp_softc
*sc
= arg
;
333 if (!ucb1200_state_idle(sc
->sc_ucb
)) /* subframe0 busy */
336 if (sc
->sc_polling_finish
) {
337 sc
->sc_polling_finish
= 0;
341 /* execute A-D converter */
342 sc
->sm_state
= UCBADC_ADC_INIT
;
349 ucbtp_sibintr(void *arg
)
351 struct ucbtp_softc
*sc
= arg
;
353 sc
->sc_stat
= UCBTS_STAT_TOUCH
;
356 tx_sound_click(sc
->sc_tc
);
358 /* invoke touch panel polling */
359 if (!sc
->sc_polling
) {
360 sc
->sc_pollh
= tx39_poll_establish(sc
->sc_tc
, 1, IST_EDGE
,
363 printf("%s: can't poll\n", sc
->sc_dev
.dv_xname
);
367 /* don't acknoledge interrupt until polling finish */
372 #define REGWRITE(addr, reg, ret) ( \
373 sc->sm_addr = (addr), \
374 sc->sm_reg = (reg), \
375 sc->sm_returnstate = (ret), \
376 sc->sm_state = UCBADC_REGWRITE)
377 #define REGREAD(addr, ret) ( \
378 sc->sm_addr = (addr), \
379 sc->sm_returnstate = (ret), \
380 sc->sm_state = UCBADC_REGREAD)
383 ucbtp_adc_async(void *arg
)
385 struct ucbtp_softc
*sc
= arg
;
386 tx_chipset_tag_t tc
= sc
->sc_tc
;
390 DPRINTFN(9, ("state: %d\n", sc
->sm_state
));
392 switch (sc
->sm_state
) {
394 panic("ucbtp_adc: invalid state %d", sc
->sm_state
);
402 case UCBADC_ADC_INIT
:
404 sc
->sc_stat
= UCBTS_STAT_DRAG
;
405 /* enable heart beat of this state machine */
406 sc
->sm_ih
= tx_intr_establish(
408 MAKEINTR(1, TX39_INTRSTATUS1_SIBSF0INT
),
409 IST_EDGE
, IPL_TTY
, ucbtp_adc_async
, sc
);
411 sc
->sm_state
= UCBADC_MEASUMENT_INIT
;
414 case UCBADC_ADC_FINI
:
415 /* disable heart beat of this state machine */
416 tx_intr_disestablish(tc
, sc
->sm_ih
);
417 sc
->sm_state
= UCBADC_IDLE
;
420 case UCBADC_MEASUMENT_INIT
:
421 switch (sc
->sm_measurement
) {
423 panic("unknown measurement spec.");
426 case UCBADC_MEASUREMENT_X
:
427 REGWRITE(UCB1200_TSCTRL_REG
,
428 UCB1200_TSCTRL_XPOSITION
,
431 case UCBADC_MEASUREMENT_Y
:
432 REGWRITE(UCB1200_TSCTRL_REG
,
433 UCB1200_TSCTRL_YPOSITION
,
436 case UCBADC_MEASUREMENT_PRESSURE
:
437 REGWRITE(UCB1200_TSCTRL_REG
,
438 UCB1200_TSCTRL_PRESSURE
,
444 case UCBADC_MEASUMENT_FINI
:
445 switch (sc
->sm_measurement
) {
446 case UCBADC_MEASUREMENT_X
:
447 sc
->sm_measurement
= UCBADC_MEASUREMENT_Y
;
448 sc
->sm_state
= UCBADC_MEASUMENT_INIT
;
450 case UCBADC_MEASUREMENT_Y
:
451 sc
->sm_measurement
= UCBADC_MEASUREMENT_PRESSURE
;
452 sc
->sm_state
= UCBADC_MEASUMENT_INIT
;
454 case UCBADC_MEASUREMENT_PRESSURE
:
455 sc
->sm_measurement
= UCBADC_MEASUREMENT_X
;
456 /* measument complete. pass down to wsmouse_input */
457 sc
->sm_state
= UCBADC_ADC_INPUT
;
462 case UCBADC_ADC_ENABLE
:
463 switch (sc
->sm_measurement
) {
464 case UCBADC_MEASUREMENT_PRESSURE
:
466 case UCBADC_MEASUREMENT_X
:
467 sc
->sm_tmpreg
= UCB1200_ADCCTRL_INPUT_SET(
468 UCB1200_ADCCTRL_ENABLE
,
469 UCB1200_ADCCTRL_INPUT_TSPX
);
470 REGWRITE(UCB1200_ADCCTRL_REG
, sc
->sm_tmpreg
,
473 case UCBADC_MEASUREMENT_Y
:
474 sc
->sm_tmpreg
= UCB1200_ADCCTRL_INPUT_SET(
475 UCB1200_ADCCTRL_ENABLE
,
476 UCB1200_ADCCTRL_INPUT_TSPY
);
477 REGWRITE(UCB1200_ADCCTRL_REG
, sc
->sm_tmpreg
,
483 case UCBADC_ADC_START0
:
484 REGWRITE(UCB1200_ADCCTRL_REG
,
485 sc
->sm_tmpreg
| UCB1200_ADCCTRL_START
,
489 case UCBADC_ADC_START1
:
490 REGWRITE(UCB1200_ADCCTRL_REG
,
492 UCBADC_ADC_DATAREAD
);
493 sc
->sm_retry
= UCBADC_RETRY_DEFAULT
;
496 case UCBADC_ADC_DATAREAD
:
497 REGREAD(UCB1200_ADCDATA_REG
, UCBADC_ADC_DATAREAD_WAIT
);
500 case UCBADC_ADC_DATAREAD_WAIT
:
501 reg16
= TX39_SIBSF0_REGDATA(sc
->sm_reg
);
502 if (!(reg16
& UCB1200_ADCDATA_INPROGRESS
) &&
503 --sc
->sm_retry
> 0) {
504 sc
->sm_state
= UCBADC_ADC_DATAREAD
;
506 if (sc
->sm_retry
<= 0) {
507 printf("dataread failed\n");
508 sc
->sm_state
= UCBADC_ADC_FINI
;
512 switch (sc
->sm_measurement
) {
513 case UCBADC_MEASUREMENT_X
:
514 sc
->sc_x
= UCB1200_ADCDATA(reg16
);
515 DPRINTFN(9, ("x=%d\n", sc
->sc_x
));
517 case UCBADC_MEASUREMENT_Y
:
518 sc
->sc_y
= UCB1200_ADCDATA(reg16
);
519 DPRINTFN(9, ("y=%d\n", sc
->sc_y
));
521 case UCBADC_MEASUREMENT_PRESSURE
:
522 sc
->sc_p
= UCB1200_ADCDATA(reg16
);
523 DPRINTFN(9, ("p=%d\n", sc
->sc_p
));
527 sc
->sm_state
= UCBADC_ADC_DISABLE
;
532 case UCBADC_ADC_DISABLE
:
533 REGWRITE(UCB1200_ADCCTRL_REG
, 0, UCBADC_ADC_INTRMODE
);
536 case UCBADC_ADC_INTRMODE
:
537 REGWRITE(UCB1200_TSCTRL_REG
, UCB1200_TSCTRL_INTERRUPT
,
538 UCBADC_MEASUMENT_FINI
);
541 case UCBADC_ADC_INPUT
:
542 if (ucbtp_input(sc
) == 0)
543 sc
->sm_state
= UCBADC_ADC_FINI
;
545 sc
->sm_state
= UCBADC_INTR_ACK0
;
548 case UCBADC_INTR_ACK0
:
549 REGREAD(UCB1200_INTSTAT_REG
, UCBADC_INTR_ACK1
);
552 case UCBADC_INTR_ACK1
:
553 REGWRITE(UCB1200_INTSTAT_REG
, sc
->sm_reg
, UCBADC_INTR_ACK2
);
556 case UCBADC_INTR_ACK2
:
557 sc
->sc_polling_finish
= 1;
558 REGWRITE(UCB1200_INTSTAT_REG
, 0, UCBADC_ADC_FINI
);
562 * UCB1200 register access state
567 * Out : sc->sm_reg (with SIBtag)
569 #define TXSIB_REGREAD_INIT 0
570 #define TXSIB_REGREAD_READ 1
571 switch (sc
->sm_read_state
) {
572 case TXSIB_REGREAD_INIT
:
573 reg
= TX39_SIBSF0_REGADDR_SET(0, sc
->sm_addr
);
574 tx_conf_write(tc
, TX39_SIBSF0CTRL_REG
, reg
);
575 sc
->sm_rw_retry
= UCBADC_RETRY_DEFAULT
;
576 sc
->sm_read_state
= TXSIB_REGREAD_READ
;
578 case TXSIB_REGREAD_READ
:
579 reg
= tx_conf_read(tc
, TX39_SIBSF0STAT_REG
);
580 if ((TX39_SIBSF0_REGADDR(reg
) != sc
->sm_addr
) &&
581 --sc
->sm_rw_retry
> 0) {
585 if (sc
->sm_rw_retry
<= 0) {
586 printf("sf0read: command failed\n");
587 sc
->sm_state
= UCBADC_ADC_FINI
;
590 sc
->sm_read_state
= TXSIB_REGREAD_INIT
;
591 DPRINTFN(9, ("%08x\n", reg
));
593 sc
->sm_state
= UCBADC_REGWRITE
;
595 sc
->sm_state
= sc
->sm_returnstate
;
601 case UCBADC_REGWRITE
:
603 * In : sc->sm_addr, sc->sm_reg (lower 16bit only)
605 #define TXSIB_REGWRITE_INIT 0
606 #define TXSIB_REGWRITE_WRITE 1
607 switch (sc
->sm_write_state
) {
608 case TXSIB_REGWRITE_INIT
:
610 sc
->sm_write_state
= TXSIB_REGWRITE_WRITE
;
611 sc
->sm_state
= UCBADC_REGREAD
;
613 sc
->sm_write_val
= sc
->sm_reg
;
615 case TXSIB_REGWRITE_WRITE
:
617 sc
->sm_write_state
= TXSIB_REGWRITE_INIT
;
618 sc
->sm_state
= sc
->sm_returnstate
;
621 reg
|= TX39_SIBSF0_WRITE
;
622 TX39_SIBSF0_REGDATA_CLR(reg
);
623 reg
= TX39_SIBSF0_REGDATA_SET(reg
, sc
->sm_write_val
);
624 tx_conf_write(tc
, TX39_SIBSF0CTRL_REG
, reg
);
634 ucbtp_input(struct ucbtp_softc
*sc
)
642 if (!sc
->sc_calibrated
) {
643 DPRINTFN(2, ("x=%4d y=%4d p=%4d\n", rx
, ry
, p
));
644 DPRINTF(("ucbtp_input: no calibration data\n"));
647 if (p
< UCBTS_PRESS_THRESHOLD
|| rx
== 0x3ff || ry
== 0x3ff ||
648 rx
== 0 || ry
== 0) {
649 sc
->sc_stat
= UCBTS_STAT_RELEASE
;
650 if (sc
->sc_polling
< UCBTS_TAP_THRESHOLD
) {
651 DPRINTFN(2, ("TAP!\n"));
653 wsmouse_input(sc
->sc_wsmousedev
, 1, 0, 0, 0, 0, 0);
655 wsmouse_input(sc
->sc_wsmousedev
, 0, 0, 0, 0, 0, 0);
657 wsmouse_input(sc
->sc_wsmousedev
, 0,
658 sc
->sc_ox
, sc
->sc_oy
, 0, 0,
659 WSMOUSE_INPUT_ABSOLUTE_X
|
660 WSMOUSE_INPUT_ABSOLUTE_Y
);
662 DPRINTFN(2, ("RELEASE\n"));
669 if (sc
->sc_xy_reverse
)
670 tpcalib_trans(&sc
->sc_tpcalib
, ry
, rx
, &x
, &y
);
672 tpcalib_trans(&sc
->sc_tpcalib
, rx
, ry
, &x
, &y
);
674 DPRINTFN(2, ("x: %4d->%4d y: %4d->%4d pressure=%4d\n",
678 if (sc
->sc_tc
->tc_videot
) {
679 if (sc
->sc_polling
== 1)
680 video_dot(sc
->sc_tc
->tc_videot
, x
, y
);
682 video_line(sc
->sc_tc
->tc_videot
, sc
->sc_ox
,
686 sc
->sc_ox
= x
, sc
->sc_oy
= y
;
688 wsmouse_input(sc
->sc_wsmousedev
, 1, x
, y
, 0, 0,
689 WSMOUSE_INPUT_ABSOLUTE_X
| WSMOUSE_INPUT_ABSOLUTE_Y
);
699 ucbtp_enable(void *v
)
706 ucbtp_disable(void *v
)
712 ucbtp_ioctl(void *v
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
714 struct ucbtp_softc
*sc
= v
;
716 DPRINTF(("%s(%d): ucbtp_ioctl(%08lx)\n", __FILE__
, __LINE__
, cmd
));
720 printf("%s(%d): WSMOUSRIO_SRES is not supported",
725 return hpc_tpanel_ioctl(&sc
->sc_tpcalib
, cmd
, data
, flag
, l
);