diff options
author | nsouch <nsouch@FreeBSD.org> | 1998-10-31 11:26:38 +0000 |
---|---|---|
committer | nsouch <nsouch@FreeBSD.org> | 1998-10-31 11:26:38 +0000 |
commit | 714f720fe4d52d1e7de1220cced124f0cab0314b (patch) | |
tree | 1ae147d9a2dfaf9db9933c13755ea7322963a504 /sys/dev/bktr | |
parent | a1aeebedd27d88e320c064bec59ae23ed6fa96e1 (diff) | |
download | FreeBSD-src-714f720fe4d52d1e7de1220cced124f0cab0314b.zip FreeBSD-src-714f720fe4d52d1e7de1220cced124f0cab0314b.tar.gz |
Brooktree driver ported to the new I2C framework. See iicbus(4) for more info.
Diffstat (limited to 'sys/dev/bktr')
-rw-r--r-- | sys/dev/bktr/bktr_core.c | 100 | ||||
-rw-r--r-- | sys/dev/bktr/bktr_i2c.c | 412 | ||||
-rw-r--r-- | sys/dev/bktr/bktr_i2c.h | 34 | ||||
-rw-r--r-- | sys/dev/bktr/bktr_reg.h | 11 |
4 files changed, 538 insertions, 19 deletions
diff --git a/sys/dev/bktr/bktr_core.c b/sys/dev/bktr/bktr_core.c index 2801499..2a468dd 100644 --- a/sys/dev/bktr/bktr_core.c +++ b/sys/dev/bktr/bktr_core.c @@ -1,4 +1,4 @@ -/* $Id$ */ +/* $Id: brooktree848.c,v 1.56 1998/10/01 09:35:48 sos Exp $ */ /* BT848 Driver for Brooktree's Bt848 based cards. The Brooktree BT848 Driver driver is based upon Mark Tinguely and Jim Lowe's driver for the Matrox Meteor PCI card . The @@ -353,7 +353,13 @@ #include <machine/ioctl_meteor.h> #include <machine/ioctl_bt848.h> /* extensions to ioctl_meteor.h */ +#include <sys/bus.h> #include <pci/brktree_reg.h> +#include <pci/bt848_i2c.h> +#include <dev/smbus/smbconf.h> +#include <dev/iicbus/iiconf.h> +#include "smbus_if.h" +#include "iicbus_if.h" #include <sys/sysctl.h> static int bt848_card = -1; static int bt848_tuner = -1; @@ -1117,6 +1123,7 @@ static int readEEProm( bktr_ptr_t bktr, int offset, int count, #ifdef __FreeBSD__ + /* * the boot time probe routine. */ @@ -1139,8 +1146,6 @@ bktr_probe( pcici_t tag, pcidi_t type ) #endif /* __FreeBSD__ */ - - /* * the attach routine. */ @@ -1173,6 +1178,9 @@ bktr_attach( ATTACH_ARGS ) fun = pci_conf_read(tag, 0x40); pci_conf_write(tag, 0x40, fun | 1); + /* XXX call bt848_i2c dependent attach() routine */ + if (bt848_i2c_attach(unit, bktr->base, &bktr->i2c_sc)) + printf("bktr%d: i2c_attach: can't attach\n", unit); #ifdef BROOKTREE_IRQ /* from the configuration file */ old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG); @@ -4161,6 +4169,55 @@ static int oformat_meteor_to_bt( u_long format ) BT848_DATA_CTL_I2CSCL | \ BT848_DATA_CTL_I2CSDA) +#if defined(__FreeBSD__) + +/* + * The hardware interface is actually SMB commands + */ +static int +i2cWrite( bktr_ptr_t bktr, int addr, int byte1, int byte2 ) +{ + char cmd; + + if (bktr->id == BROOKTREE_848_ID || + bktr->id == BROOKTREE_849_ID) + cmd = I2C_COMMAND; + else + cmd = I2C_COMMAND_878; + + if (byte2 != -1) { + if (smbus_writew(bktr->i2c_sc.smbus, addr, cmd, + (short)(((byte2 & 0xff) << 8) | (byte1 & 0xff)))) + return (-1); + } else { + if (smbus_writeb(bktr->i2c_sc.smbus, addr, cmd, + (char)(byte1 & 0xff))) + return (-1); + } + + /* return OK */ + return( 0 ); +} + +static int +i2cRead( bktr_ptr_t bktr, int addr ) +{ + char result; + char cmd; + + if (bktr->id == BROOKTREE_848_ID || + bktr->id == BROOKTREE_849_ID) + cmd = I2C_COMMAND; + else + cmd = I2C_COMMAND_878; + + if (smbus_readb(bktr->i2c_sc.smbus, addr, cmd, &result)) + return (-1); + + return ((int)result); +} + +#else /* defined(__FreeBSD__) */ /* * @@ -4245,6 +4302,8 @@ i2cRead( bktr_ptr_t bktr, int addr ) return( (bt848->i2c_data_ctl >> 8) & 0xff ); } +#endif /* !define(__FreeBSD__) */ + #if defined( I2C_SOFTWARE_PROBE ) /* @@ -4361,6 +4420,18 @@ readEEProm( bktr_ptr_t bktr, int offset, int count, u_char *data ) return( 0 ); } +#define ABSENT (-1) +static int +probeDevice(bktr_ptr_t bktr, u_char addr) +{ + int read; + read = i2cRead( bktr, addr); + if (read == ABSENT || read == 0) + return (0); + + return (1); +} + /* * get a signature of the card * read all 128 possible i2c read addresses from 0x01 thru 0xff @@ -4368,7 +4439,6 @@ readEEProm( bktr_ptr_t bktr, int offset, int count, u_char *data ) * * XXX FIXME: use offset & count args */ -#define ABSENT (-1) static int signCard( bktr_ptr_t bktr, int offset, int count, u_char* sig ) { @@ -4378,9 +4448,8 @@ signCard( bktr_ptr_t bktr, int offset, int count, u_char* sig ) sig[ x ] = 0; for ( x = 0; x < count; ++x ) { - if ( i2cRead( bktr, (2 * x) + 1 ) != ABSENT ) { + if (probeDevice(bktr, (u_char)(2 * x + 1))) sig[ x / 8 ] |= (1 << (x % 8) ); - } } return( 0 ); @@ -4399,17 +4468,12 @@ signCard( bktr_ptr_t bktr, int offset, int count, u_char* sig ) * (eg VideoLogic Captivator PCI rev. 2F with BT848A) */ static int check_for_i2c_devices( bktr_ptr_t bktr ){ - int x, temp_read; - int i2c_all_0 = 1; - int i2c_all_absent = 1; + int x; for ( x = 0; x < 128; ++x ) { - temp_read = i2cRead( bktr, (2 * x) + 1 ); - if (temp_read != 0) i2c_all_0 = 0; - if (temp_read != ABSENT) i2c_all_absent = 0; + if (probeDevice(bktr, (u_char)(2 * x + 1))) + return (1); } - - if ((i2c_all_0) || (i2c_all_absent)) return 0; - else return 1; + return (0); } /* @@ -4424,8 +4488,6 @@ static int locate_tuner_address( bktr_ptr_t bktr) { if (i2cRead( bktr, 0xc7) != ABSENT) return 0xc6; return -1; /* no tuner found */ } - -#undef ABSENT /* * determine the card brand/model @@ -4433,7 +4495,6 @@ static int locate_tuner_address( bktr_ptr_t bktr) { * can be used to select a specific device, regardless of the * autodetection and i2c device checks. */ -#define ABSENT (-1) static void probeCard( bktr_ptr_t bktr, int verbose ) { @@ -4447,6 +4508,9 @@ probeCard( bktr_ptr_t bktr, int verbose ) int tuner_i2c_address = -1; any_i2c_devices = check_for_i2c_devices( bktr ); + if (bootverbose) + if (!any_i2c_devices) + printf("bktr: no I2C device found!\n"); bt848 = bktr->base; bt848->gpio_out_en = 0; diff --git a/sys/dev/bktr/bktr_i2c.c b/sys/dev/bktr/bktr_i2c.c new file mode 100644 index 0000000..b2b7912 --- /dev/null +++ b/sys/dev/bktr/bktr_i2c.c @@ -0,0 +1,412 @@ +/*- + * Copyright (c) 1998 Nicolas Souchu + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + * + */ + +/* + * I2C support for the bti2c chipset. + * + * From brooktree848.c <fsmp@freefall.org> + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/buf.h> +#include <sys/uio.h> +#include <sys/malloc.h> + +#include <machine/clock.h> + +#include <pci/pcivar.h> +#include <pci/pcireg.h> +#include <machine/ioctl_meteor.h> +#include <machine/ioctl_bt848.h> /* extensions to ioctl_meteor.h */ +#include <pci/brktree_reg.h> + +#include <pci/bt848_i2c.h> + +#include <dev/iicbus/iiconf.h> +#include <dev/iicbus/iicbus.h> + +#include <dev/smbus/smbconf.h> + +#include "iicbb_if.h" +#include "smbus_if.h" + +#include "pci.h" +#include "bktr.h" + +#if (NBKTR > 0 && NPCI > 0) + +#define I2C_DELAY 40 + +#define BTI2C_DEBUG(x) if (bti2c_debug) (x) +static int bti2c_debug = 0; + +struct bti2c_softc { + + bt848_ptr_t base; + + int iic_owned; /* 1 if we own the iicbus */ + int smb_owned; /* 1 if we own the smbbus */ + + device_t smbus; + device_t iicbus; +}; + +struct bt_data { + bt848_ptr_t base; +}; +struct bt_data btdata[NBKTR]; + +static int bti2c_probe(device_t); +static int bti2c_attach(device_t); +static void bti2c_print_child(device_t, device_t); + +static int bti2c_iic_callback(device_t, int, caddr_t *); +static void bti2c_iic_setlines(device_t, int, int); +static int bti2c_iic_getdataline(device_t); +static int bti2c_iic_reset(device_t, u_char, u_char, u_char *); + +static int bti2c_smb_callback(device_t, int, caddr_t *); +static int bti2c_smb_writeb(device_t dev, u_char slave, char cmd, char byte); +static int bti2c_smb_writew(device_t dev, u_char slave, char cmd, short word); +static int bti2c_smb_readb(device_t dev, u_char slave, char cmd, char *byte); + +static devclass_t bti2c_devclass; + +static device_method_t bti2c_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, bti2c_probe), + DEVMETHOD(device_attach, bti2c_attach), + + /* bus interface */ + DEVMETHOD(bus_print_child, bti2c_print_child), + + /* iicbb interface */ + DEVMETHOD(iicbb_callback, bti2c_iic_callback), + DEVMETHOD(iicbb_setlines, bti2c_iic_setlines), + DEVMETHOD(iicbb_getdataline, bti2c_iic_getdataline), + DEVMETHOD(iicbb_reset, bti2c_iic_reset), + + /* smbus interface */ + DEVMETHOD(smbus_callback, bti2c_smb_callback), + DEVMETHOD(smbus_writeb, bti2c_smb_writeb), + DEVMETHOD(smbus_writew, bti2c_smb_writew), + DEVMETHOD(smbus_readb, bti2c_smb_readb), + + { 0, 0 } +}; + +static driver_t bti2c_driver = { + "bti2c", + bti2c_methods, + DRIVER_TYPE_MISC, + sizeof(struct bti2c_softc), +}; + +/* + * Call this to pass the base address of the bktr device to the + * bti2c_i2c layer and initialize all the I2C bus architecture + */ +int +bt848_i2c_attach(int unit, bt848_ptr_t base, struct bktr_i2c_softc *i2c_sc) +{ + device_t interface; + device_t bitbang; + + btdata[unit].base = base; + + /* XXX add the I2C interface to the root_bus until pcibus is ready */ + interface = device_add_child(root_bus, "bti2c", unit, NULL); + + /* add bit-banging generic code onto bti2c interface */ + bitbang = device_add_child(interface, "iicbb", -1, NULL); + + /* probe and attach the interface, we need it NOW + * bit-banging code is also probed and attached */ + device_probe_and_attach(interface); + device_probe_and_attach(bitbang); + + /* smb and i2c interfaces are available for the bt848 chip + * connect bit-banging generic code to an iicbus */ + if ((i2c_sc->iicbus = iicbus_alloc_bus(bitbang))) + device_probe_and_attach(i2c_sc->iicbus); + + /* hardware i2c is actually smb over the bti2c interface */ + if ((i2c_sc->smbus = smbus_alloc_bus(interface))) + device_probe_and_attach(i2c_sc->smbus); + + return (0); +}; + +/* + * Not a real probe, we know the device exists since the device has + * been added after the successfull pci probe. + */ +static int +bti2c_probe(device_t dev) +{ + device_set_desc(dev, "bt848 Hard/Soft I2C controller"); + + return (0); +} + +static int +bti2c_attach(device_t dev) +{ + struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); + + /* XXX should use ivars with pcibus or pcibus methods to access + * onboard memory */ + sc->base = btdata[device_get_unit(dev)].base; + + return (0); +} + +static void +bti2c_print_child(device_t bus, device_t dev) +{ + printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); + + return; +} + +static int +bti2c_smb_callback(device_t dev, int index, caddr_t *data) +{ + struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); + int error = 0; + int how; + + /* test each time if we already have/haven't the iicbus + * to avoid deadlocks + */ + switch (index) { + case SMB_REQUEST_BUS: + if (!sc->iic_owned) { + /* request the iicbus */ + how = *(int *)data; + error = iicbus_request_bus(sc->iicbus, dev, how); + if (!error) + sc->iic_owned = 1; + } + break; + + case SMB_RELEASE_BUS: + if (sc->iic_owned) { + /* release the iicbus */ + error = iicbus_release_bus(sc->iicbus, dev); + if (!error) + sc->iic_owned = 0; + } + break; + + default: + error = EINVAL; + } + + return (error); +} + +static int +bti2c_iic_callback(device_t dev, int index, caddr_t *data) +{ + struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); + int error = 0; + int how; + + /* test each time if we already have/haven't the smbus + * to avoid deadlocks + */ + switch (index) { + case IIC_REQUEST_BUS: + if (!sc->smb_owned) { + /* request the smbus */ + how = *(int *)data; + error = smbus_request_bus(sc->smbus, dev, how); + if (!error) + sc->smb_owned = 1; + } + break; + + case IIC_RELEASE_BUS: + if (sc->smb_owned) { + /* release the smbus */ + error = smbus_release_bus(sc->smbus, dev); + if (!error) + sc->smb_owned = 0; + } + break; + + default: + error = EINVAL; + } + + return (error); +} + +static int +bti2c_iic_reset(device_t dev, u_char speed, u_char addr, u_char * oldaddr) +{ + if (oldaddr) + *oldaddr = 0; /* XXX */ + + return (IIC_ENOADDR); +} + +static void +bti2c_iic_setlines(device_t dev, int ctrl, int data) +{ + struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); + bt848_ptr_t bti2c; + + bti2c = sc->base; + + bti2c->i2c_data_ctl = (ctrl << 1) | data; + DELAY(I2C_DELAY); + + return; +} + +static int +bti2c_iic_getdataline(device_t dev) +{ + struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); + bt848_ptr_t bti2c; + + bti2c = sc->base; + + return (bti2c->i2c_data_ctl & 0x1); +} + +static int +bti2c_write(bt848_ptr_t bti2c, u_long data) +{ + u_long x; + + /* clear status bits */ + bti2c->int_stat = (BT848_INT_RACK | BT848_INT_I2CDONE); + + BTI2C_DEBUG(printf("w%lx", data)); + + /* write the address and data */ + bti2c->i2c_data_ctl = data; + + /* wait for completion */ + for ( x = 0x7fffffff; x; --x ) { /* safety valve */ + if ( bti2c->int_stat & BT848_INT_I2CDONE ) + break; + } + + /* check for ACK */ + if ( !x || !(bti2c->int_stat & BT848_INT_RACK) ) { + BTI2C_DEBUG(printf("%c%c", (!x)?'+':'-', + (!(bti2c->int_stat & BT848_INT_RACK))?'+':'-')); + return (SMB_ENOACK); + } + BTI2C_DEBUG(printf("+")); + + /* return OK */ + return( 0 ); +} + +static int +bti2c_smb_writeb(device_t dev, u_char slave, char cmd, char byte) +{ + struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); + u_long data; + + data = ((slave & 0xff) << 24) | ((byte & 0xff) << 16) | cmd; + + return (bti2c_write(sc->base, data)); +} + +/* + * byte1 becomes low byte of word + * byte2 becomes high byte of word + */ +static int +bti2c_smb_writew(device_t dev, u_char slave, char cmd, short word) +{ + struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); + u_long data; + char low, high; + + low = (char)(word & 0xff); + high = (char)((word & 0xff00) >> 8); + + data = ((slave & 0xff) << 24) | ((low & 0xff) << 16) | + ((high & 0xff) << 8) | BT848_DATA_CTL_I2CW3B | cmd; + + return (bti2c_write(sc->base, data)); +} + +/* + * The Bt878 and Bt879 differed on the treatment of i2c commands + */ +static int +bti2c_smb_readb(device_t dev, u_char slave, char cmd, char *byte) +{ + struct bti2c_softc *sc = (struct bti2c_softc *)device_get_softc(dev); + bt848_ptr_t bti2c; + u_long x; + + bti2c = sc->base; + + /* clear status bits */ + bti2c->int_stat = (BT848_INT_RACK | BT848_INT_I2CDONE); + + bti2c->i2c_data_ctl = ((slave & 0xff) << 24) | cmd; + + BTI2C_DEBUG(printf("r%lx/", (u_long)(((slave & 0xff) << 24) | cmd))); + + /* wait for completion */ + for ( x = 0x7fffffff; x; --x ) { /* safety valve */ + if ( bti2c->int_stat & BT848_INT_I2CDONE ) + break; + } + + /* check for ACK */ + if ( !x || !(bti2c->int_stat & BT848_INT_RACK) ) { + BTI2C_DEBUG(printf("r%c%c", (!x)?'+':'-', + (!(bti2c->int_stat & BT848_INT_RACK))?'+':'-')); + return (SMB_ENOACK); + } + + *byte = (char)((bti2c->i2c_data_ctl >> 8) & 0xff); + BTI2C_DEBUG(printf("r%x+", *byte)); + + return (0); +} + +DRIVER_MODULE(bti2c, root, bti2c_driver, bti2c_devclass, 0, 0); +#endif diff --git a/sys/dev/bktr/bktr_i2c.h b/sys/dev/bktr/bktr_i2c.h new file mode 100644 index 0000000..c7d22c5 --- /dev/null +++ b/sys/dev/bktr/bktr_i2c.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 1998 Nicolas Souchu + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + * + */ +#ifndef _BT848_I2C_H +#define _BT848_I2C_H + +extern int bt848_i2c_attach(int, bt848_ptr_t, struct bktr_i2c_softc *); + +#endif diff --git a/sys/dev/bktr/bktr_reg.h b/sys/dev/bktr/bktr_reg.h index 9ef9aae..b3f9efd4 100644 --- a/sys/dev/bktr/bktr_reg.h +++ b/sys/dev/bktr/bktr_reg.h @@ -28,7 +28,7 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Id: brktree_reg.h,v 1.22 1998/09/30 21:06:54 sos Exp $ */ #ifndef PCI_LATENCY_TIMER #define PCI_LATENCY_TIMER 0x0c /* pci timer register */ @@ -369,6 +369,12 @@ struct format_params { int iform_xtsel; }; +#ifdef __FreeBSD__ +struct bktr_i2c_softc { + device_t iicbus; + device_t smbus; +}; +#endif typedef struct bktr_clip bktr_clip_t; /* @@ -381,6 +387,9 @@ struct bktr_softc { struct intrhand bktr_ih; /* interrupt vectoring */ #define pcici_t pci_devaddr_t #endif +#ifdef __FreeBSD__ + struct bktr_i2c_softc i2c_sc; /* bt848_i2c device */ +#endif bt848_ptr_t base; /* Bt848 register physical address */ vm_offset_t phys_base; /* Bt848 register physical address */ pcici_t tag; /* PCI tag, for doing PCI commands */ |