xref: /dflybsd-src/sys/dev/video/cxm/cxm_i2c.c (revision 2267fd784e8a7d1ca13e6d3541caa91f36c9e9fb)
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