1*c7fb772bSthorpej /* $NetBSD: ucb1200.c,v 1.21 2021/08/07 16:18:54 thorpej Exp $ */
2ce3b031dSuch
358f851eeSuch /*-
458f851eeSuch * Copyright (c) 2000 The NetBSD Foundation, Inc.
5ce3b031dSuch * All rights reserved.
6ce3b031dSuch *
758f851eeSuch * This code is derived from software contributed to The NetBSD Foundation
858f851eeSuch * by UCHIYAMA Yasushi.
958f851eeSuch *
10ce3b031dSuch * Redistribution and use in source and binary forms, with or without
11ce3b031dSuch * modification, are permitted provided that the following conditions
12ce3b031dSuch * are met:
13ce3b031dSuch * 1. Redistributions of source code must retain the above copyright
14ce3b031dSuch * notice, this list of conditions and the following disclaimer.
1558f851eeSuch * 2. Redistributions in binary form must reproduce the above copyright
1658f851eeSuch * notice, this list of conditions and the following disclaimer in the
1758f851eeSuch * documentation and/or other materials provided with the distribution.
18ce3b031dSuch *
1958f851eeSuch * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2058f851eeSuch * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2158f851eeSuch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2258f851eeSuch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2358f851eeSuch * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2458f851eeSuch * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2558f851eeSuch * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2658f851eeSuch * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2758f851eeSuch * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2858f851eeSuch * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2958f851eeSuch * POSSIBILITY OF SUCH DAMAGE.
30ce3b031dSuch */
31ce3b031dSuch
32ce3b031dSuch /*
33ce3b031dSuch * Device driver for PHILIPS UCB1200 Advanced modem/audio analog front-end
34ce3b031dSuch */
35ce3b031dSuch
360c82163cSlukem #include <sys/cdefs.h>
37*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: ucb1200.c,v 1.21 2021/08/07 16:18:54 thorpej Exp $");
380c82163cSlukem
39ce3b031dSuch #include <sys/param.h>
40ce3b031dSuch #include <sys/systm.h>
41ce3b031dSuch #include <sys/device.h>
42ce3b031dSuch
43ce3b031dSuch #include <machine/bus.h>
44ce3b031dSuch #include <machine/intr.h>
45ce3b031dSuch
46ce3b031dSuch #include <hpcmips/tx/tx39var.h>
47ce3b031dSuch #include <hpcmips/tx/tx39sibvar.h>
48ce3b031dSuch #include <hpcmips/tx/tx39sibreg.h>
49ce3b031dSuch
50ce3b031dSuch #include <hpcmips/dev/ucb1200var.h>
51ce3b031dSuch #include <hpcmips/dev/ucb1200reg.h>
52ce3b031dSuch
537d170993Such #ifdef UCB1200_DEBUG
547d170993Such #define DPRINTF_ENABLE
557d170993Such #define DPRINTF_DEBUG ucb1200_debug
56ce3b031dSuch #endif
577d170993Such #include <machine/debug.h>
58ce3b031dSuch
59dce2bc94Such struct ucbchild_state {
60fc9212e5Such int (*cs_busy)(void *);
61dce2bc94Such void *cs_arg;
62dce2bc94Such };
63dce2bc94Such
64dce2bc94Such struct ucb1200_softc {
65cbab9cadSchs device_t sc_parent; /* parent (TX39 SIB module) */
66dce2bc94Such tx_chipset_tag_t sc_tc;
67dce2bc94Such
68dce2bc94Such int sc_snd_rate; /* passed down from SIB module */
69dce2bc94Such int sc_tel_rate;
70dce2bc94Such
71dce2bc94Such /* inquire child module state */
72dce2bc94Such struct ucbchild_state sc_child[UCB1200_MODULE_MAX];
73dce2bc94Such };
74dce2bc94Such
75cbab9cadSchs int ucb1200_match(device_t, cfdata_t, void *);
76cbab9cadSchs void ucb1200_attach(device_t, device_t, void *);
77fc9212e5Such int ucb1200_print(void *, const char *);
78cbab9cadSchs int ucb1200_search(device_t, cfdata_t, const int *, void *);
79fc9212e5Such int ucb1200_check_id(u_int16_t, int);
80ce3b031dSuch
817d170993Such #ifdef UCB1200_DEBUG
82fc9212e5Such void ucb1200_dump(struct ucb1200_softc *);
83dc8f1b2cSuch #endif
84ce3b031dSuch
85cbab9cadSchs CFATTACH_DECL_NEW(ucb, sizeof(struct ucb1200_softc),
86c5e91d44Sthorpej ucb1200_match, ucb1200_attach, NULL, NULL);
87ce3b031dSuch
8844b86d33Such const struct ucb_id {
8944b86d33Such u_int16_t id;
9044b86d33Such const char *product;
9144b86d33Such } ucb_id[] = {
9244b86d33Such { UCB1100_ID, "PHILIPS UCB1100" },
9344b86d33Such { UCB1200_ID, "PHILIPS UCB1200" },
9444b86d33Such { UCB1300_ID, "PHILIPS UCB1300" },
9544b86d33Such { TC35413F_ID, "TOSHIBA TC35413F" },
9644b86d33Such { 0, 0 }
9744b86d33Such };
9844b86d33Such
99ce3b031dSuch int
ucb1200_match(device_t parent,cfdata_t cf,void * aux)100cbab9cadSchs ucb1200_match(device_t parent, cfdata_t cf, void *aux)
101ce3b031dSuch {
102ce3b031dSuch struct txsib_attach_args *sa = aux;
103dce2bc94Such u_int16_t reg;
104ce3b031dSuch
105ce3b031dSuch if (sa->sa_slot != 0) /* UCB1200 must be subframe 0 */
10658f851eeSuch return (0);
107dce2bc94Such reg = txsibsf0_reg_read(sa->sa_tc, UCB1200_ID_REG);
108ce3b031dSuch
10944b86d33Such return (ucb1200_check_id(reg, 0));
110ce3b031dSuch }
111ce3b031dSuch
112ce3b031dSuch void
ucb1200_attach(device_t parent,device_t self,void * aux)113cbab9cadSchs ucb1200_attach(device_t parent, device_t self, void *aux)
114ce3b031dSuch {
115ce3b031dSuch struct txsib_attach_args *sa = aux;
116cbab9cadSchs struct ucb1200_softc *sc = device_private(self);
11744b86d33Such u_int16_t reg;
118ce3b031dSuch
11944b86d33Such printf(": ");
120ce3b031dSuch sc->sc_tc = sa->sa_tc;
121ce3b031dSuch sc->sc_parent = parent;
122dce2bc94Such sc->sc_snd_rate = sa->sa_snd_rate;
123dce2bc94Such sc->sc_tel_rate = sa->sa_tel_rate;
124ce3b031dSuch
125dce2bc94Such tx39sib_enable1(sc->sc_parent);
126dce2bc94Such tx39sib_enable2(sc->sc_parent);
127ce3b031dSuch
1287d170993Such #ifdef UCB1200_DEBUG
1297d170993Such if (ucb1200_debug)
130ce3b031dSuch ucb1200_dump(sc);
131ce3b031dSuch #endif
13244b86d33Such reg = txsibsf0_reg_read(sa->sa_tc, UCB1200_ID_REG);
13344b86d33Such (void)ucb1200_check_id(reg, 1);
134ce3b031dSuch printf("\n");
135ce3b031dSuch
1362685996bSthorpej config_search(self, NULL,
137*c7fb772bSthorpej CFARGS(.search = ucb1200_search));
138ce3b031dSuch }
139ce3b031dSuch
140ce3b031dSuch int
ucb1200_search(device_t parent,cfdata_t cf,const int * ldesc,void * aux)141cbab9cadSchs ucb1200_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
142ce3b031dSuch {
143cbab9cadSchs struct ucb1200_softc *sc = device_private(parent);
144dce2bc94Such struct ucb1200_attach_args ucba;
145ce3b031dSuch
146dce2bc94Such ucba.ucba_tc = sc->sc_tc;
147dce2bc94Such ucba.ucba_snd_rate = sc->sc_snd_rate;
148dce2bc94Such ucba.ucba_tel_rate = sc->sc_tel_rate;
149dce2bc94Such ucba.ucba_sib = sc->sc_parent;
150dce2bc94Such ucba.ucba_ucb = parent;
151ce3b031dSuch
1522685996bSthorpej if (config_probe(parent, cf, &ucba))
153*c7fb772bSthorpej config_attach(parent, cf, &ucba, ucb1200_print, CFARGS_NONE);
154ce3b031dSuch
15558f851eeSuch return (0);
156ce3b031dSuch }
157ce3b031dSuch
158ce3b031dSuch int
ucb1200_print(void * aux,const char * pnp)159fc9212e5Such ucb1200_print(void *aux, const char *pnp)
160ce3b031dSuch {
16158f851eeSuch
16258f851eeSuch return (pnp ? QUIET : UNCONF);
163ce3b031dSuch }
164ce3b031dSuch
16544b86d33Such int
ucb1200_check_id(u_int16_t idreg,int print)166fc9212e5Such ucb1200_check_id(u_int16_t idreg, int print)
16744b86d33Such {
16844b86d33Such int i;
16944b86d33Such
17044b86d33Such for (i = 0; ucb_id[i].product; i++) {
17144b86d33Such if (ucb_id[i].id == idreg) {
17244b86d33Such if (print) {
17344b86d33Such printf("%s", ucb_id[i].product);
17444b86d33Such }
17544b86d33Such
17644b86d33Such return (1);
17744b86d33Such }
17844b86d33Such }
17944b86d33Such
18058f851eeSuch return (0);
18144b86d33Such }
18244b86d33Such
183ce3b031dSuch void
ucb1200_state_install(device_t dev,int (* sfun)(void *),void * sarg,int sid)184cbab9cadSchs ucb1200_state_install(device_t dev, int (*sfun)(void *), void *sarg,
185fc9212e5Such int sid)
186ce3b031dSuch {
187cbab9cadSchs struct ucb1200_softc *sc = device_private(dev);
188dce2bc94Such
189dce2bc94Such sc->sc_child[sid].cs_busy = sfun;
190dce2bc94Such sc->sc_child[sid].cs_arg = sarg;
191ce3b031dSuch }
192ce3b031dSuch
193ce3b031dSuch int
ucb1200_state_idle(device_t dev)194cbab9cadSchs ucb1200_state_idle(device_t dev)
195ce3b031dSuch {
196cbab9cadSchs struct ucb1200_softc *sc = device_private(dev);
197dce2bc94Such struct ucbchild_state *cs;
198dce2bc94Such int i;
199dce2bc94Such
200dce2bc94Such cs = sc->sc_child;
201dce2bc94Such for (i = 0; i < UCB1200_MODULE_MAX; i++, cs++)
202dce2bc94Such if (cs->cs_busy)
203dce2bc94Such if ((*cs->cs_busy)(cs->cs_arg))
20458f851eeSuch return (0);
205dce2bc94Such
20658f851eeSuch return (1); /* idle state */
207ce3b031dSuch }
208ce3b031dSuch
2097d170993Such #ifdef UCB1200_DEBUG
210ce3b031dSuch void
ucb1200_dump(struct ucb1200_softc * sc)211fc9212e5Such ucb1200_dump(struct ucb1200_softc *sc)
212ce3b031dSuch {
213560a78f6Syamt static const char *const regname[] = {
214ce3b031dSuch "IO_DATA ",
215ce3b031dSuch "IO_DIR ",
216ce3b031dSuch "POSINTEN ",
217ce3b031dSuch "NEGINTEN ",
218ce3b031dSuch "INTSTAT ",
219ce3b031dSuch "TELECOMCTRLA ",
220ce3b031dSuch "TELECOMCTRLB ",
221ce3b031dSuch "AUDIOCTRLA ",
222ce3b031dSuch "AUDIOCTRLB ",
223ce3b031dSuch "TOUCHSCREENCTRL",
224ce3b031dSuch "ADCCTRL ",
225ce3b031dSuch "ADCDATA ",
226ce3b031dSuch "ID ",
227ce3b031dSuch "MODE ",
228ce3b031dSuch "RESERVED ",
229ce3b031dSuch "NULL "
230ce3b031dSuch };
231fc9212e5Such tx_chipset_tag_t tc;
232ce3b031dSuch u_int16_t reg;
233ce3b031dSuch int i;
234ce3b031dSuch
235fc9212e5Such tc = sc->sc_tc;
236fc9212e5Such
237dce2bc94Such printf("\n\t[UCB1200 register]\n");
238ce3b031dSuch for (i = 0; i < 16; i++) {
239ce3b031dSuch reg = txsibsf0_reg_read(tc, i);
240ce3b031dSuch printf("%s(%02d) 0x%04x ", regname[i], i, reg);
2417d170993Such dbg_bit_print(reg);
242ce3b031dSuch }
243ce3b031dSuch }
2447d170993Such #endif /* UCB1200_DEBUG */
245