bktr_i2c.c revision 331722
1/*-
2 * Copyright (c) 1998, 2001 Nicolas Souchu
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/11/sys/dev/bktr/bktr_i2c.c 331722 2018-03-29 02:50:57Z eadler $");
29
30/*
31 * I2C support for the bti2c chipset.
32 *
33 * From brooktree848.c <fsmp@freefall.org>
34 */
35
36#include "opt_bktr.h"
37
38#include <sys/param.h>
39#include <sys/kernel.h>
40#include <sys/malloc.h>
41#include <sys/systm.h>
42#include <sys/module.h>
43#include <sys/bus.h>
44#include <sys/uio.h>
45
46#if __FreeBSD_version < 500014
47#include <sys/select.h>
48#else
49#include <sys/selinfo.h>
50#endif
51
52#if (__FreeBSD_version < 500000)
53#include <pci/pcivar.h>
54#include <pci/pcireg.h>
55#else
56#include <dev/pci/pcivar.h>
57#include <dev/pci/pcireg.h>
58#endif
59
60#include <machine/bus.h>
61#include <sys/bus.h>
62
63#include <dev/bktr/ioctl_meteor.h>
64#include <dev/bktr/ioctl_bt848.h>	/* extensions to ioctl_meteor.h */
65#include <dev/bktr/bktr_reg.h>
66#include <dev/bktr/bktr_i2c.h>
67
68#include <dev/smbus/smbconf.h>
69#include <dev/iicbus/iiconf.h>
70
71/* Compilation is void if BKTR_USE_FREEBSD_SMBUS is not
72 * defined. This allows bktr owners to have smbus active for there
73 * motherboard and still use their bktr without smbus.
74 */
75#if defined(BKTR_USE_FREEBSD_SMBUS)
76
77#define BTI2C_DEBUG(x)	if (bti2c_debug) (x)
78static int bti2c_debug = 0;
79
80/*
81 * Call this to pass the address of the bktr device to the
82 * bti2c_i2c layer and initialize all the I2C bus architecture
83 */
84int bt848_i2c_attach(device_t dev)
85{
86	struct bktr_softc *bktr_sc = (struct bktr_softc *)device_get_softc(dev);
87	struct bktr_i2c_softc *sc = &bktr_sc->i2c_sc;
88
89	sc->smbus = device_add_child(dev, "smbus", -1);
90	sc->iicbb = device_add_child(dev, "iicbb", -1);
91
92	if (!sc->iicbb || !sc->smbus)
93		return ENXIO;
94
95	bus_generic_attach(dev);
96
97	return (0);
98};
99
100int bt848_i2c_detach(device_t dev)
101{
102	struct bktr_softc *bktr_sc = (struct bktr_softc *)device_get_softc(dev);
103	struct bktr_i2c_softc *sc = &bktr_sc->i2c_sc;
104	int error = 0;
105
106	if ((error = bus_generic_detach(dev)))
107		goto error;
108
109	if (sc->iicbb && (error = device_delete_child(dev, sc->iicbb)))
110		goto error;
111
112	if (sc->smbus && (error = device_delete_child(dev, sc->smbus)))
113		goto error;
114
115error:
116	return (error);
117}
118
119int bti2c_smb_callback(device_t dev, int index, void *data)
120{
121	struct bktr_softc *bktr_sc = (struct bktr_softc *)device_get_softc(dev);
122	struct bktr_i2c_softc *sc = &bktr_sc->i2c_sc;
123	int error = 0;
124
125	/* test each time if we already have/haven't the iicbus
126	 * to avoid deadlocks
127	 */
128	switch (index) {
129	case SMB_REQUEST_BUS:
130		/* XXX test & set */
131		mtx_lock(&Giant);
132		if (!sc->bus_owned) {
133			sc->bus_owned = 1;
134		} else
135			error = EWOULDBLOCK;
136		mtx_unlock(&Giant);
137		break;
138
139	case SMB_RELEASE_BUS:
140		/* XXX test & set */
141		mtx_lock(&Giant);
142		if (sc->bus_owned) {
143			sc->bus_owned = 0;
144		} else
145			error = EINVAL;
146		mtx_unlock(&Giant);
147		break;
148
149	default:
150		error = EINVAL;
151	}
152
153	return (error);
154}
155
156int bti2c_iic_callback(device_t dev, int index, caddr_t *data)
157{
158	struct bktr_softc *bktr_sc = (struct bktr_softc *)device_get_softc(dev);
159	struct bktr_i2c_softc *sc = &bktr_sc->i2c_sc;
160	int error = 0;
161
162	/* test each time if we already have/haven't the smbus
163	 * to avoid deadlocks
164	 */
165	switch (index) {
166	case IIC_REQUEST_BUS:
167		/* XXX test & set */
168		mtx_lock(&Giant);
169		if (!sc->bus_owned) {
170			sc->bus_owned = 1;
171		} else
172			error = EWOULDBLOCK;
173		mtx_unlock(&Giant);
174		break;
175
176	case IIC_RELEASE_BUS:
177		/* XXX test & set */
178		mtx_lock(&Giant);
179		if (sc->bus_owned) {
180			sc->bus_owned = 0;
181		} else
182			error = EINVAL;
183		mtx_unlock(&Giant);
184		break;
185
186	default:
187		error = EINVAL;
188	}
189
190	return (error);
191}
192
193int bti2c_iic_reset(device_t dev, u_char speed, u_char addr, u_char * oldaddr)
194{
195	mtx_lock(&Giant);
196	if (oldaddr)
197		*oldaddr = 0;			/* XXX */
198	mtx_unlock(&Giant);
199
200	return (IIC_ENOADDR);
201}
202
203void bti2c_iic_setsda(device_t dev, int val)
204{
205	struct bktr_softc *sc  = (struct bktr_softc *)device_get_softc(dev);
206	int clock;
207
208	mtx_lock(&Giant);
209	clock = INL(sc, BKTR_I2C_DATA_CTL) & 0x2;
210
211	if (val)
212		OUTL(sc, BKTR_I2C_DATA_CTL, clock | 1);
213	else
214		OUTL(sc, BKTR_I2C_DATA_CTL, clock);
215	mtx_unlock(&Giant);
216
217	return;
218}
219
220void bti2c_iic_setscl(device_t dev, int val)
221{
222	struct bktr_softc *sc  = (struct bktr_softc *)device_get_softc(dev);
223	int data;
224
225	mtx_lock(&Giant);
226	data = INL(sc, BKTR_I2C_DATA_CTL) & 0x1;
227
228	if (val)
229		OUTL(sc, BKTR_I2C_DATA_CTL, 0x2 | data);
230	else
231		OUTL(sc, BKTR_I2C_DATA_CTL, data);
232	mtx_unlock(&Giant);
233
234	return;
235}
236
237int
238bti2c_iic_getsda(device_t dev)
239{
240	struct bktr_softc *sc  = (struct bktr_softc *)device_get_softc(dev);
241	int retval;
242
243	mtx_lock(&Giant);
244	retval = INL(sc,BKTR_I2C_DATA_CTL) & 0x1;
245	mtx_unlock(&Giant);
246	return (retval);
247}
248
249int
250bti2c_iic_getscl(device_t dev)
251{
252	return (0);
253}
254
255static int
256bti2c_write(struct bktr_softc *sc, u_long data)
257{
258	u_long		x;
259
260	mtx_lock(&Giant);
261
262	/* clear status bits */
263	OUTL(sc, BKTR_INT_STAT, (BT848_INT_RACK | BT848_INT_I2CDONE));
264
265	BTI2C_DEBUG(printf("w%lx", data));
266
267	/* write the address and data */
268	OUTL(sc, BKTR_I2C_DATA_CTL, data);
269
270	/* wait for completion */
271	for ( x = 0x7fffffff; x; --x ) {	/* safety valve */
272		if ( INL(sc, BKTR_INT_STAT) & BT848_INT_I2CDONE )
273			break;
274	}
275
276	/* check for ACK */
277	if ( !x || !( INL(sc, BKTR_INT_STAT) & BT848_INT_RACK) ) {
278		BTI2C_DEBUG(printf("%c%c", (!x)?'+':'-',
279			(!( INL(sc, BKTR_INT_STAT) & BT848_INT_RACK))?'+':'-'));
280		mtx_unlock(&Giant);
281		return (SMB_ENOACK);
282	}
283	BTI2C_DEBUG(printf("+"));
284	mtx_unlock(&Giant);
285
286	/* return OK */
287	return( 0 );
288}
289
290int
291bti2c_smb_writeb(device_t dev, u_char slave, char cmd, char byte)
292{
293	struct bktr_softc *sc  = (struct bktr_softc *)device_get_softc(dev);
294	u_long data;
295
296	data = ((slave & 0xff) << 24) | ((byte & 0xff) << 16) | (u_char)cmd;
297
298	return (bti2c_write(sc, data));
299}
300
301/*
302 * byte1 becomes low byte of word
303 * byte2 becomes high byte of word
304 */
305int
306bti2c_smb_writew(device_t dev, u_char slave, char cmd, short word)
307{
308	struct bktr_softc *sc  = (struct bktr_softc *)device_get_softc(dev);
309	u_long data;
310	char low, high;
311
312	low = (char)(word & 0xff);
313	high = (char)((word & 0xff00) >> 8);
314
315	data = ((slave & 0xff) << 24) | ((low & 0xff) << 16) |
316		((high & 0xff) << 8) | BT848_DATA_CTL_I2CW3B | (u_char)cmd;
317
318	return (bti2c_write(sc, data));
319}
320
321/*
322 * The Bt878 and Bt879 differed on the treatment of i2c commands
323 */
324int
325bti2c_smb_readb(device_t dev, u_char slave, char cmd, char *byte)
326{
327	struct bktr_softc *sc  = (struct bktr_softc *)device_get_softc(dev);
328	u_long		x;
329
330	mtx_lock(&Giant);
331	/* clear status bits */
332	OUTL(sc,BKTR_INT_STAT, (BT848_INT_RACK | BT848_INT_I2CDONE));
333
334	OUTL(sc,BKTR_I2C_DATA_CTL, ((slave & 0xff) << 24) | (u_char)cmd);
335
336	BTI2C_DEBUG(printf("r%lx/", (u_long)(((slave & 0xff) << 24) | (u_char)cmd)));
337
338	/* wait for completion */
339	for ( x = 0x7fffffff; x; --x ) {	/* safety valve */
340		if ( INL(sc,BKTR_INT_STAT) & BT848_INT_I2CDONE )
341			break;
342	}
343
344	/* check for ACK */
345	if ( !x || !(INL(sc,BKTR_INT_STAT) & BT848_INT_RACK) ) {
346		BTI2C_DEBUG(printf("r%c%c", (!x)?'+':'-',
347			(!( INL(sc,BKTR_INT_STAT) & BT848_INT_RACK))?'+':'-'));
348		mtx_unlock(&Giant);
349		return (SMB_ENOACK);
350	}
351
352	*byte = (char)((INL(sc,BKTR_I2C_DATA_CTL) >> 8) & 0xff);
353	BTI2C_DEBUG(printf("r%x+", *byte));
354	mtx_unlock(&Giant);
355
356	return (0);
357}
358
359DRIVER_MODULE(iicbb, bktr, iicbb_driver, iicbb_devclass, 0, 0);
360DRIVER_MODULE(smbus, bktr, smbus_driver, smbus_devclass, 0, 0);
361
362#endif /* defined(BKTR_USE_FREEBSD_SMBUS) */
363