From f7ce69c963f9866814d85f518f188db6da7cf853 Mon Sep 17 00:00:00 2001 From: Nicolas Souchu Date: Sat, 31 Oct 1998 11:35:21 +0000 Subject: [PATCH] lpbb is the official Philips parallel I2C interface. lpbb.c contains only basic i/o functions, bit-banging mechanism is implemented by dev/iicbus/iicbb.c immio.c: some bootverbose logs to watch zip+ connect/disconnect process --- sys/dev/ppbus/immio.c | 22 ++- sys/dev/ppbus/lpbb.c | 325 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+), 7 deletions(-) create mode 100644 sys/dev/ppbus/lpbb.c diff --git a/sys/dev/ppbus/immio.c b/sys/dev/ppbus/immio.c index 630707cb0ad0..dc37ab3891ce 100644 --- a/sys/dev/ppbus/immio.c +++ b/sys/dev/ppbus/immio.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: immio.c,v 1.2 1998/09/20 14:41:54 nsouch Exp $ + * $Id: immio.c,v 1.3 1998/10/02 20:44:58 nsouch Exp $ * */ @@ -286,9 +286,13 @@ imm_disconnect(struct vpoio_data *vpo, int *connected, int release_bus) ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret); - if ((s1 != (char)0xb8 || s2 != (char)0x18 || s3 != (char)0x38) && - connected) - *connected = VP0_ECONNECT; + if ((s1 != (char)0xb8 || s2 != (char)0x18 || s3 != (char)0x38)) { + if (bootverbose) + printf("imm%d: (disconnect) s1=0x%x s2=0x%x, s3=0x%x\n", + vpo->vpo_unit, s1 & 0xff, s2 & 0xff, s3 & 0xff); + if (connected) + *connected = VP0_ECONNECT; + } if (release_bus) return (ppb_release_bus(&vpo->vpo_dev)); @@ -334,9 +338,13 @@ imm_connect(struct vpoio_data *vpo, int how, int *disconnected, int request_bus) ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret); - if ((s1 != (char)0xb8 || s2 != (char)0x18 || s3 != (char)0x30) - && disconnected) - *disconnected = VP0_ECONNECT; + if ((s1 != (char)0xb8 || s2 != (char)0x18 || s3 != (char)0x30)) { + if (bootverbose) + printf("imm%d: (connect) s1=0x%x s2=0x%x, s3=0x%x\n", + vpo->vpo_unit, s1 & 0xff, s2 & 0xff, s3 & 0xff); + if (disconnected) + *disconnected = VP0_ECONNECT; + } return (0); } diff --git a/sys/dev/ppbus/lpbb.c b/sys/dev/ppbus/lpbb.c new file mode 100644 index 000000000000..30b48fc3fe97 --- /dev/null +++ b/sys/dev/ppbus/lpbb.c @@ -0,0 +1,325 @@ +/*- + * Copyright (c) 1998 Nicolas Souchu, Marc Bouget + * 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 Bit-Banging over parallel port + * + * See the Official Philips interface description in lpbb(4) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include "iicbb_if.h" + +/* iicbus softc */ +struct lpbb_softc { + + struct ppb_device lpbb_dev; +}; + +static int lpbb_detect(struct lpbb_softc *); + +static int lpbb_probe(device_t); +static int lpbb_attach(device_t); +static void lpbb_print_child(device_t, device_t); + +static int lpbb_callback(device_t, int, caddr_t *); +static void lpbb_setlines(device_t, int, int); +static int lpbb_getdataline(device_t); +static int lpbb_reset(device_t, u_char, u_char, u_char *); + +static devclass_t lpbb_devclass; + +static device_method_t lpbb_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, lpbb_probe), + DEVMETHOD(device_attach, lpbb_attach), + + /* bus interface */ + DEVMETHOD(bus_print_child, lpbb_print_child), + + /* iicbb interface */ + DEVMETHOD(iicbb_callback, lpbb_callback), + DEVMETHOD(iicbb_setlines, lpbb_setlines), + DEVMETHOD(iicbb_getdataline, lpbb_getdataline), + DEVMETHOD(iicbb_reset, lpbb_reset), + + { 0, 0 } +}; + +static driver_t lpbb_driver = { + "lpbb", + lpbb_methods, + DRIVER_TYPE_MISC, + sizeof(struct lpbb_softc), +}; + +/* + * Make ourselves visible as a ppbus driver + */ +static struct ppb_device *lpbb_ppb_probe(struct ppb_data *ppb); +static int lpbb_ppb_attach(struct ppb_device *dev); + +#define MAXLPBB 8 /* XXX not much better! */ +static struct lpbb_softc *lpbbdata[MAXLPBB]; +static int nlpbb = 0; + +#ifdef KERNEL + +static struct ppb_driver lpbbdriver = { + lpbb_ppb_probe, lpbb_ppb_attach, "lpbb" +}; +DATA_SET(ppbdriver_set, lpbbdriver); + +#endif /* KERNEL */ + +static int +lpbb_probe(device_t dev) +{ + struct lpbb_softc *sc = lpbbdata[device_get_unit(dev)]; + struct lpbb_softc *scdst = (struct lpbb_softc *)device_get_softc(dev); + + /* XXX copy softc. Yet, ppbus device is sc->lpbb_dev, but will be + * dev->parent when ppbus will be ported to the new bus architecture */ + bcopy(sc, scdst, sizeof(struct lpbb_softc)); + + device_set_desc(dev, "parallel I2C bit-banging interface"); + + /* probe done by ppbus initialization */ + return (0); +} + +static int +lpbb_attach(device_t dev) +{ + struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev); + device_t bitbang, iicbus; + + /* add generic bit-banging code */ + bitbang = device_add_child(dev, "iicbb", -1, NULL); + + /* add the iicbus to the tree */ + iicbus = iicbus_alloc_bus(bitbang); + + device_probe_and_attach(bitbang); + + /* XXX should be in iicbb_attach! */ + device_probe_and_attach(iicbus); + + return (0); +} + +/* + * lppbb_ppb_probe() + */ +static struct ppb_device * +lpbb_ppb_probe(struct ppb_data *ppb) +{ + struct lpbb_softc *sc; + + sc = (struct lpbb_softc *) malloc(sizeof(struct lpbb_softc), + M_TEMP, M_NOWAIT); + if (!sc) { + printf("lpbb: cannot malloc!\n"); + return (0); + } + bzero(sc, sizeof(struct lpbb_softc)); + + lpbbdata[nlpbb] = sc; + + /* + * ppbus dependent initialisation. + */ + sc->lpbb_dev.id_unit = nlpbb; + sc->lpbb_dev.name = lpbbdriver.name; + sc->lpbb_dev.ppb = ppb; + sc->lpbb_dev.intr = 0; + + if (!lpbb_detect(sc)) { + free(sc, M_TEMP); + return (NULL); + } + + /* Ok, go to next device on next probe */ + nlpbb ++; + + /* XXX wrong according to new bus architecture. ppbus needs to be + * ported + */ + return (&sc->lpbb_dev); +} + +static int +lpbb_ppb_attach(struct ppb_device *dev) +{ + /* add the parallel port I2C interface to the bus tree */ + if (!device_add_child(root_bus, "lpbb", dev->id_unit, NULL)) + return (0); + + return (1); +} + +static int +lpbb_callback(device_t dev, int index, caddr_t *data) +{ + struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev); + int error = 0; + int how; + + switch (index) { + case IIC_REQUEST_BUS: + /* request the ppbus */ + how = *(int *)data; + error = ppb_request_bus(&sc->lpbb_dev, how); + break; + + case IIC_RELEASE_BUS: + /* release the ppbus */ + error = ppb_release_bus(&sc->lpbb_dev); + break; + + default: + error = EINVAL; + } + + return (error); +} + +#define SDA_out 0x80 +#define SCL_out 0x08 +#define SDA_in 0x80 +#define SCL_in 0x08 +#define ALIM 0x20 +#define I2CKEY 0x50 + +static int getSDA(struct lpbb_softc *sc) +{ +if((ppb_rstr(&sc->lpbb_dev)&SDA_in)==SDA_in) + return 1; +else + return 0; +} + +static int getSCL(struct lpbb_softc *sc) +{ +if((ppb_rstr(&sc->lpbb_dev)&SCL_in)==SCL_in) + return 1; +else + return 0; +} + +static void setSDA(struct lpbb_softc *sc, char val) +{ +if(val==0) + ppb_wdtr(&sc->lpbb_dev, (u_char)SDA_out); +else + ppb_wdtr(&sc->lpbb_dev, (u_char)~SDA_out); +} + +static void setSCL(struct lpbb_softc *sc, unsigned char val) +{ +if(val==0) + ppb_wctr(&sc->lpbb_dev, (u_char)(ppb_rctr(&sc->lpbb_dev)&~SCL_out)); +else + ppb_wctr(&sc->lpbb_dev, (u_char)(ppb_rctr(&sc->lpbb_dev)|SCL_out)); +} + +static int lpbb_detect(struct lpbb_softc *sc) +{ + if (ppb_request_bus(&sc->lpbb_dev, PPB_DONTWAIT)) { + printf("lpbb: can't allocate ppbus\n"); + return (0); + } + + /* reset bus */ + setSDA(sc, 1); + setSCL(sc, 1); + + if ((ppb_rstr(&sc->lpbb_dev) & I2CKEY) || + ((ppb_rstr(&sc->lpbb_dev) & ALIM) != ALIM)) + return (0); + + ppb_release_bus(&sc->lpbb_dev); + + return (1); +} + +static int +lpbb_reset(device_t dev, u_char speed, u_char addr, u_char * oldaddr) +{ + struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev); + + /* reset bus */ + setSDA(sc, 1); + setSCL(sc, 1); + + return (IIC_ENOADDR); +} + +static void +lpbb_setlines(device_t dev, int ctrl, int data) +{ + struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev); + + setSCL(sc, ctrl); + setSDA(sc, data); +} + +static int +lpbb_getdataline(device_t dev) +{ + struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev); + + return (getSDA(sc)); +} + +static void +lpbb_print_child(device_t bus, device_t dev) +{ + printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); + + return; +} + +DRIVER_MODULE(lpbb, root, lpbb_driver, lpbb_devclass, 0, 0);