summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authornsouch <nsouch@FreeBSD.org>1998-10-31 11:35:21 +0000
committernsouch <nsouch@FreeBSD.org>1998-10-31 11:35:21 +0000
commit3b006890f16badfe89b25127eb04b14cfc373659 (patch)
tree251b56969ac767288f9b4ee1ff3ab1b9cd3579c1 /sys/dev
parenta8f721865de13fdf796dd7a371aed217c14710fa (diff)
downloadFreeBSD-src-3b006890f16badfe89b25127eb04b14cfc373659.zip
FreeBSD-src-3b006890f16badfe89b25127eb04b14cfc373659.tar.gz
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
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ppbus/immio.c22
-rw-r--r--sys/dev/ppbus/lpbb.c325
2 files changed, 340 insertions, 7 deletions
diff --git a/sys/dev/ppbus/immio.c b/sys/dev/ppbus/immio.c
index 630707c..dc37ab3 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 0000000..30b48fc
--- /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 <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 <dev/ppbus/ppbconf.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+
+#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);
OpenPOWER on IntegriCloud