1e9afadfdSSascha Wildner /*
2e9afadfdSSascha Wildner * Copyright (c) 2003, 2004, 2005
3e9afadfdSSascha Wildner * John Wehle <john@feith.com>. All rights reserved.
4e9afadfdSSascha Wildner *
5e9afadfdSSascha Wildner * Redistribution and use in source and binary forms, with or without
6e9afadfdSSascha Wildner * modification, are permitted provided that the following conditions
7e9afadfdSSascha Wildner * are met:
8e9afadfdSSascha Wildner * 1. Redistributions of source code must retain the above copyright
9e9afadfdSSascha Wildner * notice, this list of conditions and the following disclaimer.
10e9afadfdSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
11e9afadfdSSascha Wildner * notice, this list of conditions and the following disclaimer in the
12e9afadfdSSascha Wildner * documentation and/or other materials provided with the distribution.
13e9afadfdSSascha Wildner * 3. All advertising materials mentioning features or use of this software
14e9afadfdSSascha Wildner * must display the following acknowledgement:
15e9afadfdSSascha Wildner * This product includes software developed by John Wehle.
16e9afadfdSSascha Wildner * 4. The name of the author may not be used to endorse or promote products
17e9afadfdSSascha Wildner * derived from this software without specific prior written permission.
18e9afadfdSSascha Wildner *
19e9afadfdSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20e9afadfdSSascha Wildner * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21e9afadfdSSascha Wildner * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22e9afadfdSSascha Wildner * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23e9afadfdSSascha Wildner * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24e9afadfdSSascha Wildner * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25e9afadfdSSascha Wildner * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26e9afadfdSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27e9afadfdSSascha Wildner * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28e9afadfdSSascha Wildner * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29e9afadfdSSascha Wildner * POSSIBILITY OF SUCH DAMAGE.
30e9afadfdSSascha Wildner */
31e9afadfdSSascha Wildner
32e9afadfdSSascha Wildner /*
33e9afadfdSSascha Wildner * I2c routines for the Conexant MPEG-2 Codec driver.
34e9afadfdSSascha Wildner */
35e9afadfdSSascha Wildner
36e9afadfdSSascha Wildner #include <sys/param.h>
37e9afadfdSSascha Wildner #include <sys/systm.h>
38e9afadfdSSascha Wildner #include <sys/malloc.h>
39e9afadfdSSascha Wildner #include <sys/conf.h>
40e9afadfdSSascha Wildner #include <sys/uio.h>
41e9afadfdSSascha Wildner #include <sys/kernel.h>
42e9afadfdSSascha Wildner #include <sys/module.h>
43e9afadfdSSascha Wildner #include <sys/poll.h>
44e9afadfdSSascha Wildner #include <sys/select.h>
45e9afadfdSSascha Wildner #include <sys/resource.h>
46e9afadfdSSascha Wildner #include <sys/bus.h>
47e9afadfdSSascha Wildner #include <sys/rman.h>
48e9afadfdSSascha Wildner
49e9afadfdSSascha Wildner #include <machine/clock.h>
50e9afadfdSSascha Wildner
51e9afadfdSSascha Wildner #include <bus/pci/pcireg.h>
52e9afadfdSSascha Wildner #include <bus/pci/pcivar.h>
53e9afadfdSSascha Wildner
54e9afadfdSSascha Wildner #include <dev/video/cxm/cxm.h>
55e9afadfdSSascha Wildner
56e9afadfdSSascha Wildner #include <bus/iicbus/iiconf.h>
57e9afadfdSSascha Wildner
58e9afadfdSSascha Wildner #include "iicbb_if.h"
59e9afadfdSSascha Wildner
60e9afadfdSSascha Wildner
61e9afadfdSSascha Wildner static int cxm_iic_probe(device_t dev);
62e9afadfdSSascha Wildner static int cxm_iic_attach(device_t dev);
63e9afadfdSSascha Wildner static int cxm_iic_detach(device_t dev);
64e9afadfdSSascha Wildner static void cxm_iic_child_detached(device_t dev, device_t child);
65e9afadfdSSascha Wildner
66e9afadfdSSascha Wildner static int cxm_iic_callback(device_t, int, caddr_t *);
67e9afadfdSSascha Wildner static int cxm_iic_reset(device_t, u_char, u_char, u_char *);
68e9afadfdSSascha Wildner static int cxm_iic_getscl(device_t);
69e9afadfdSSascha Wildner static int cxm_iic_getsda(device_t);
70e9afadfdSSascha Wildner static void cxm_iic_setscl(device_t, int);
71e9afadfdSSascha Wildner static void cxm_iic_setsda(device_t, int);
72e9afadfdSSascha Wildner
73e9afadfdSSascha Wildner static device_method_t cxm_iic_methods[] = {
74e9afadfdSSascha Wildner /* Device interface */
75e9afadfdSSascha Wildner DEVMETHOD(device_probe, cxm_iic_probe),
76e9afadfdSSascha Wildner DEVMETHOD(device_attach, cxm_iic_attach),
77e9afadfdSSascha Wildner DEVMETHOD(device_detach, cxm_iic_detach),
78e9afadfdSSascha Wildner
79e9afadfdSSascha Wildner /* bus interface */
80e9afadfdSSascha Wildner DEVMETHOD(bus_child_detached, cxm_iic_child_detached),
81e9afadfdSSascha Wildner DEVMETHOD(bus_print_child, bus_generic_print_child),
82e9afadfdSSascha Wildner DEVMETHOD(bus_driver_added, bus_generic_driver_added),
83e9afadfdSSascha Wildner
84e9afadfdSSascha Wildner /* iicbb interface */
85e9afadfdSSascha Wildner DEVMETHOD(iicbb_callback, cxm_iic_callback),
86e9afadfdSSascha Wildner DEVMETHOD(iicbb_reset, cxm_iic_reset),
87a9656fbcSSascha Wildner DEVMETHOD(iicbb_getscl, cxm_iic_getscl),
88a9656fbcSSascha Wildner DEVMETHOD(iicbb_getsda, cxm_iic_getsda),
89a9656fbcSSascha Wildner DEVMETHOD(iicbb_setscl, cxm_iic_setscl),
90a9656fbcSSascha Wildner DEVMETHOD(iicbb_setsda, cxm_iic_setsda),
91e9afadfdSSascha Wildner
92*d3c9c58eSSascha Wildner DEVMETHOD_END
93e9afadfdSSascha Wildner };
94e9afadfdSSascha Wildner
95e9afadfdSSascha Wildner static driver_t cxm_iic_driver = {
96e9afadfdSSascha Wildner "cxm_iic",
97e9afadfdSSascha Wildner cxm_iic_methods,
98e9afadfdSSascha Wildner sizeof(struct cxm_iic_softc),
99e9afadfdSSascha Wildner };
100e9afadfdSSascha Wildner
101e9afadfdSSascha Wildner static devclass_t cxm_iic_devclass;
102e9afadfdSSascha Wildner
103aa2b9d05SSascha Wildner DRIVER_MODULE(cxm_iic, cxm, cxm_iic_driver, cxm_iic_devclass, NULL, NULL);
104a9656fbcSSascha Wildner MODULE_VERSION(cxm_iic, 1);
105a9656fbcSSascha Wildner MODULE_DEPEND(cxm_iic, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
106e9afadfdSSascha Wildner
107e9afadfdSSascha Wildner
108e9afadfdSSascha Wildner /*
109e9afadfdSSascha Wildner * the boot time probe routine.
110e9afadfdSSascha Wildner *
111e9afadfdSSascha Wildner * The cxm_iic device is only probed after it has
112e9afadfdSSascha Wildner * been established that the cxm device is present
113e9afadfdSSascha Wildner * which means that the cxm_iic device * must *
114e9afadfdSSascha Wildner * be present since it's built into the cxm hardware.
115e9afadfdSSascha Wildner */
116e9afadfdSSascha Wildner static int
cxm_iic_probe(device_t dev)117e9afadfdSSascha Wildner cxm_iic_probe(device_t dev)
118e9afadfdSSascha Wildner {
119e9afadfdSSascha Wildner device_set_desc(dev, "Conexant iTVC15 / iTVC16 I2C controller");
120e9afadfdSSascha Wildner
121e9afadfdSSascha Wildner return 0;
122e9afadfdSSascha Wildner }
123e9afadfdSSascha Wildner
124e9afadfdSSascha Wildner
125e9afadfdSSascha Wildner /*
126e9afadfdSSascha Wildner * the attach routine.
127e9afadfdSSascha Wildner */
128e9afadfdSSascha Wildner static int
cxm_iic_attach(device_t dev)129e9afadfdSSascha Wildner cxm_iic_attach(device_t dev)
130e9afadfdSSascha Wildner {
131e9afadfdSSascha Wildner device_t *kids;
132e9afadfdSSascha Wildner device_t iicbus;
133e9afadfdSSascha Wildner int error;
134e9afadfdSSascha Wildner int numkids;
135e9afadfdSSascha Wildner int i;
136e9afadfdSSascha Wildner bus_space_handle_t *bhandlep;
137e9afadfdSSascha Wildner bus_space_tag_t *btagp;
138e9afadfdSSascha Wildner struct cxm_iic_softc *sc;
139e9afadfdSSascha Wildner device_t child;
140e9afadfdSSascha Wildner
141e9afadfdSSascha Wildner /* Get the device data */
142e9afadfdSSascha Wildner sc = device_get_softc(dev);
143e9afadfdSSascha Wildner
144e9afadfdSSascha Wildner /* retrieve the cxm btag and bhandle */
145e9afadfdSSascha Wildner if (BUS_READ_IVAR(device_get_parent(dev), dev,
146e9afadfdSSascha Wildner CXM_IVAR_BTAG, (uintptr_t *)&btagp)
147e9afadfdSSascha Wildner || BUS_READ_IVAR(device_get_parent(dev), dev,
148e9afadfdSSascha Wildner CXM_IVAR_BHANDLE, (uintptr_t *)&bhandlep)) {
149e9afadfdSSascha Wildner device_printf(dev,
150e9afadfdSSascha Wildner "could not retrieve bus space information\n");
151e9afadfdSSascha Wildner return ENXIO;
152e9afadfdSSascha Wildner }
153e9afadfdSSascha Wildner
154e9afadfdSSascha Wildner sc->btag = *btagp;
155e9afadfdSSascha Wildner sc->bhandle = *bhandlep;
156e9afadfdSSascha Wildner
157e9afadfdSSascha Wildner /* add bit-banging generic code onto cxm_iic interface */
158e9afadfdSSascha Wildner sc->iicbb = device_add_child(dev, "iicbb", -1);
159e9afadfdSSascha Wildner
160e9afadfdSSascha Wildner if (!sc->iicbb) {
161e9afadfdSSascha Wildner device_printf(dev, "could not add iicbb\n");
162e9afadfdSSascha Wildner return ENXIO;
163e9afadfdSSascha Wildner }
164e9afadfdSSascha Wildner
165e9afadfdSSascha Wildner /* probed and attached the bit-banging code */
166e9afadfdSSascha Wildner error = device_probe_and_attach(sc->iicbb);
167e9afadfdSSascha Wildner
168e9afadfdSSascha Wildner if (error) {
169e9afadfdSSascha Wildner device_printf(dev, "could not attach iicbb\n");
170e9afadfdSSascha Wildner goto fail;
171e9afadfdSSascha Wildner }
172e9afadfdSSascha Wildner
173e9afadfdSSascha Wildner /* locate iicbus which was attached by the bit-banging code */
174e9afadfdSSascha Wildner iicbus = NULL;
175e9afadfdSSascha Wildner device_get_children(sc->iicbb, &kids, &numkids);
176e9afadfdSSascha Wildner for (i = 0; i < numkids; i++)
177e9afadfdSSascha Wildner if (strcmp(device_get_name(kids[i]), "iicbus") == 0) {
178e9afadfdSSascha Wildner iicbus = kids[i];
179e9afadfdSSascha Wildner break;
180e9afadfdSSascha Wildner }
181e9afadfdSSascha Wildner kfree(kids, M_TEMP);
182e9afadfdSSascha Wildner
183e9afadfdSSascha Wildner if (!iicbus) {
184e9afadfdSSascha Wildner device_printf(dev, "could not find iicbus\n");
185e9afadfdSSascha Wildner error = ENXIO;
186e9afadfdSSascha Wildner goto fail;
187e9afadfdSSascha Wildner }
188e9afadfdSSascha Wildner
189e9afadfdSSascha Wildner if (BUS_WRITE_IVAR(device_get_parent(dev), dev,
190e9afadfdSSascha Wildner CXM_IVAR_IICBUS, (uintptr_t)&iicbus)) {
191e9afadfdSSascha Wildner device_printf(dev, "could not store iicbus information\n");
192e9afadfdSSascha Wildner error = ENXIO;
193e9afadfdSSascha Wildner goto fail;
194e9afadfdSSascha Wildner }
195e9afadfdSSascha Wildner
196e9afadfdSSascha Wildner return 0;
197e9afadfdSSascha Wildner
198e9afadfdSSascha Wildner fail:
199e9afadfdSSascha Wildner /*
200e9afadfdSSascha Wildner * Detach the children before recursively deleting
201e9afadfdSSascha Wildner * in case a child has a pointer to a grandchild
202e9afadfdSSascha Wildner * which is used by the child's detach routine.
203e9afadfdSSascha Wildner *
204e9afadfdSSascha Wildner * Remember the child before detaching so we can
205e9afadfdSSascha Wildner * delete it (bus_generic_detach indirectly zeroes
206e9afadfdSSascha Wildner * sc->child_dev).
207e9afadfdSSascha Wildner */
208e9afadfdSSascha Wildner child = sc->iicbb;
209e9afadfdSSascha Wildner bus_generic_detach(dev);
210e9afadfdSSascha Wildner if (child)
211e9afadfdSSascha Wildner device_delete_child(dev, child);
212e9afadfdSSascha Wildner
213e9afadfdSSascha Wildner return error;
214e9afadfdSSascha Wildner }
215e9afadfdSSascha Wildner
216e9afadfdSSascha Wildner
217e9afadfdSSascha Wildner /*
218e9afadfdSSascha Wildner * the detach routine.
219e9afadfdSSascha Wildner */
220e9afadfdSSascha Wildner static int
cxm_iic_detach(device_t dev)221e9afadfdSSascha Wildner cxm_iic_detach(device_t dev)
222e9afadfdSSascha Wildner {
223e9afadfdSSascha Wildner struct cxm_iic_softc *sc;
224e9afadfdSSascha Wildner device_t child;
225e9afadfdSSascha Wildner
226e9afadfdSSascha Wildner /* Get the device data */
227e9afadfdSSascha Wildner sc = device_get_softc(dev);
228e9afadfdSSascha Wildner
229e9afadfdSSascha Wildner BUS_WRITE_IVAR(device_get_parent(dev), dev, CXM_IVAR_IICBUS, 0);
230e9afadfdSSascha Wildner
231e9afadfdSSascha Wildner /*
232e9afadfdSSascha Wildner * Detach the children before recursively deleting
233e9afadfdSSascha Wildner * in case a child has a pointer to a grandchild
234e9afadfdSSascha Wildner * which is used by the child's detach routine.
235e9afadfdSSascha Wildner *
236e9afadfdSSascha Wildner * Remember the child before detaching so we can
237e9afadfdSSascha Wildner * delete it (bus_generic_detach indirectly zeroes
238e9afadfdSSascha Wildner * sc->child_dev).
239e9afadfdSSascha Wildner */
240e9afadfdSSascha Wildner child = sc->iicbb;
241e9afadfdSSascha Wildner bus_generic_detach(dev);
242e9afadfdSSascha Wildner if (child)
243e9afadfdSSascha Wildner device_delete_child(dev, child);
244e9afadfdSSascha Wildner
245e9afadfdSSascha Wildner return 0;
246e9afadfdSSascha Wildner }
247e9afadfdSSascha Wildner
248e9afadfdSSascha Wildner
249e9afadfdSSascha Wildner /*
250e9afadfdSSascha Wildner * the child detached routine.
251e9afadfdSSascha Wildner */
252e9afadfdSSascha Wildner static void
cxm_iic_child_detached(device_t dev,device_t child)253e9afadfdSSascha Wildner cxm_iic_child_detached(device_t dev, device_t child)
254e9afadfdSSascha Wildner {
255e9afadfdSSascha Wildner struct cxm_iic_softc *sc;
256e9afadfdSSascha Wildner
257e9afadfdSSascha Wildner /* Get the device data */
258e9afadfdSSascha Wildner sc = device_get_softc(dev);
259e9afadfdSSascha Wildner
260e9afadfdSSascha Wildner if (child == sc->iicbb)
261e9afadfdSSascha Wildner sc->iicbb = NULL;
262e9afadfdSSascha Wildner }
263e9afadfdSSascha Wildner
264e9afadfdSSascha Wildner
265e9afadfdSSascha Wildner static int
cxm_iic_callback(device_t dev,int index,caddr_t * data)266e9afadfdSSascha Wildner cxm_iic_callback(device_t dev, int index, caddr_t *data)
267e9afadfdSSascha Wildner {
268e9afadfdSSascha Wildner return 0;
269e9afadfdSSascha Wildner }
270e9afadfdSSascha Wildner
271e9afadfdSSascha Wildner
272e9afadfdSSascha Wildner static int
cxm_iic_reset(device_t dev,u_char speed,u_char addr,u_char * oldaddr)273e9afadfdSSascha Wildner cxm_iic_reset(device_t dev, u_char speed, u_char addr, u_char * oldaddr)
274e9afadfdSSascha Wildner {
275e9afadfdSSascha Wildner struct cxm_iic_softc *sc;
276e9afadfdSSascha Wildner
277e9afadfdSSascha Wildner /* Get the device data */
278e9afadfdSSascha Wildner sc = (struct cxm_iic_softc *)device_get_softc(dev);
279e9afadfdSSascha Wildner
280e9afadfdSSascha Wildner /* Set scl to 1 */
281e9afadfdSSascha Wildner CSR_WRITE_4(sc, CXM_REG_I2C_SETSCL, ~(int)1);
282e9afadfdSSascha Wildner
283e9afadfdSSascha Wildner /* Set sda to 1 */
284e9afadfdSSascha Wildner CSR_WRITE_4(sc, CXM_REG_I2C_SETSDA, ~(int)1);
285e9afadfdSSascha Wildner
286e9afadfdSSascha Wildner /*
287e9afadfdSSascha Wildner * PCI writes may be buffered so force the
288e9afadfdSSascha Wildner * write to complete by reading the last
289e9afadfdSSascha Wildner * location written.
290e9afadfdSSascha Wildner */
291e9afadfdSSascha Wildner
292e9afadfdSSascha Wildner CSR_READ_4(sc, CXM_REG_I2C_SETSDA);
293e9afadfdSSascha Wildner
294e9afadfdSSascha Wildner /* Wait for 10 usec */
295e9afadfdSSascha Wildner DELAY(10);
296e9afadfdSSascha Wildner
297e9afadfdSSascha Wildner return IIC_ENOADDR;
298e9afadfdSSascha Wildner }
299e9afadfdSSascha Wildner
300e9afadfdSSascha Wildner
301e9afadfdSSascha Wildner static int
cxm_iic_getscl(device_t dev)302e9afadfdSSascha Wildner cxm_iic_getscl(device_t dev)
303e9afadfdSSascha Wildner {
304e9afadfdSSascha Wildner struct cxm_iic_softc *sc;
305e9afadfdSSascha Wildner
306e9afadfdSSascha Wildner /* Get the device data */
307e9afadfdSSascha Wildner sc = (struct cxm_iic_softc *)device_get_softc(dev);
308e9afadfdSSascha Wildner
309e9afadfdSSascha Wildner /* Get sda */
310e9afadfdSSascha Wildner return CSR_READ_1(sc, CXM_REG_I2C_GETSCL);
311e9afadfdSSascha Wildner }
312e9afadfdSSascha Wildner
313e9afadfdSSascha Wildner
314e9afadfdSSascha Wildner static int
cxm_iic_getsda(device_t dev)315e9afadfdSSascha Wildner cxm_iic_getsda(device_t dev)
316e9afadfdSSascha Wildner {
317e9afadfdSSascha Wildner struct cxm_iic_softc *sc;
318e9afadfdSSascha Wildner
319e9afadfdSSascha Wildner /* Get the device data */
320e9afadfdSSascha Wildner sc = (struct cxm_iic_softc *)device_get_softc(dev);
321e9afadfdSSascha Wildner
322e9afadfdSSascha Wildner /* Get sda */
323e9afadfdSSascha Wildner return CSR_READ_1(sc, CXM_REG_I2C_GETSDA);
324e9afadfdSSascha Wildner }
325e9afadfdSSascha Wildner
326e9afadfdSSascha Wildner
327e9afadfdSSascha Wildner static void
cxm_iic_setscl(device_t dev,int val)328e9afadfdSSascha Wildner cxm_iic_setscl(device_t dev, int val)
329e9afadfdSSascha Wildner {
330e9afadfdSSascha Wildner struct cxm_iic_softc *sc;
331e9afadfdSSascha Wildner
332e9afadfdSSascha Wildner /* Get the device data */
333e9afadfdSSascha Wildner sc = (struct cxm_iic_softc *)device_get_softc(dev);
334e9afadfdSSascha Wildner
335e9afadfdSSascha Wildner /* Set scl to the requested value */
336e9afadfdSSascha Wildner CSR_WRITE_4(sc, CXM_REG_I2C_SETSCL, ~(int)(val ? 1 : 0));
337e9afadfdSSascha Wildner
338e9afadfdSSascha Wildner /*
339e9afadfdSSascha Wildner * PCI writes may be buffered so force the
340e9afadfdSSascha Wildner * write to complete by reading the last
341e9afadfdSSascha Wildner * location written.
342e9afadfdSSascha Wildner */
343e9afadfdSSascha Wildner
344e9afadfdSSascha Wildner CSR_READ_4(sc, CXM_REG_I2C_SETSCL);
345e9afadfdSSascha Wildner }
346e9afadfdSSascha Wildner
347e9afadfdSSascha Wildner
348e9afadfdSSascha Wildner static void
cxm_iic_setsda(device_t dev,int val)349e9afadfdSSascha Wildner cxm_iic_setsda(device_t dev, int val)
350e9afadfdSSascha Wildner {
351e9afadfdSSascha Wildner struct cxm_iic_softc *sc;
352e9afadfdSSascha Wildner
353e9afadfdSSascha Wildner /* Get the device data */
354e9afadfdSSascha Wildner sc = (struct cxm_iic_softc *)device_get_softc(dev);
355e9afadfdSSascha Wildner
356e9afadfdSSascha Wildner /* Set sda to the requested value */
357e9afadfdSSascha Wildner CSR_WRITE_4(sc, CXM_REG_I2C_SETSDA, ~(int)(val ? 1 : 0));
358e9afadfdSSascha Wildner
359e9afadfdSSascha Wildner /*
360e9afadfdSSascha Wildner * PCI writes may be buffered so force the
361e9afadfdSSascha Wildner * write to complete by reading the last
362e9afadfdSSascha Wildner * location written.
363e9afadfdSSascha Wildner */
364e9afadfdSSascha Wildner
365e9afadfdSSascha Wildner CSR_READ_4(sc, CXM_REG_I2C_SETSDA);
366e9afadfdSSascha Wildner }
367