1f7ce69c9SNicolas Souchu /*- 2c17d4340SNicolas Souchu * Copyright (c) 1998, 2001 Nicolas Souchu, Marc Bouget 3f7ce69c9SNicolas Souchu * All rights reserved. 4f7ce69c9SNicolas Souchu * 5f7ce69c9SNicolas Souchu * Redistribution and use in source and binary forms, with or without 6f7ce69c9SNicolas Souchu * modification, are permitted provided that the following conditions 7f7ce69c9SNicolas Souchu * are met: 8f7ce69c9SNicolas Souchu * 1. Redistributions of source code must retain the above copyright 9f7ce69c9SNicolas Souchu * notice, this list of conditions and the following disclaimer. 10f7ce69c9SNicolas Souchu * 2. Redistributions in binary form must reproduce the above copyright 11f7ce69c9SNicolas Souchu * notice, this list of conditions and the following disclaimer in the 12f7ce69c9SNicolas Souchu * documentation and/or other materials provided with the distribution. 13f7ce69c9SNicolas Souchu * 14f7ce69c9SNicolas Souchu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15f7ce69c9SNicolas Souchu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16f7ce69c9SNicolas Souchu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17f7ce69c9SNicolas Souchu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18f7ce69c9SNicolas Souchu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19f7ce69c9SNicolas Souchu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20f7ce69c9SNicolas Souchu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21f7ce69c9SNicolas Souchu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22f7ce69c9SNicolas Souchu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23f7ce69c9SNicolas Souchu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24f7ce69c9SNicolas Souchu * SUCH DAMAGE. 25f7ce69c9SNicolas Souchu * 26f7ce69c9SNicolas Souchu * 27f7ce69c9SNicolas Souchu */ 28f7ce69c9SNicolas Souchu 29aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 30aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 31aad970f1SDavid E. O'Brien 32f7ce69c9SNicolas Souchu /* 33f7ce69c9SNicolas Souchu * I2C Bit-Banging over parallel port 34f7ce69c9SNicolas Souchu * 35f7ce69c9SNicolas Souchu * See the Official Philips interface description in lpbb(4) 36f7ce69c9SNicolas Souchu */ 37f7ce69c9SNicolas Souchu 38f7ce69c9SNicolas Souchu #include <sys/param.h> 39f7ce69c9SNicolas Souchu #include <sys/kernel.h> 40f7ce69c9SNicolas Souchu #include <sys/systm.h> 41f7ce69c9SNicolas Souchu #include <sys/module.h> 42f7ce69c9SNicolas Souchu #include <sys/bus.h> 43f7ce69c9SNicolas Souchu #include <sys/uio.h> 44f7ce69c9SNicolas Souchu 45f7ce69c9SNicolas Souchu 46f7ce69c9SNicolas Souchu #include <dev/ppbus/ppbconf.h> 470f210c92SNicolas Souchu #include "ppbus_if.h" 480f210c92SNicolas Souchu #include <dev/ppbus/ppbio.h> 49f7ce69c9SNicolas Souchu 50f7ce69c9SNicolas Souchu #include <dev/iicbus/iiconf.h> 51f7ce69c9SNicolas Souchu #include <dev/iicbus/iicbus.h> 52f7ce69c9SNicolas Souchu 53f7ce69c9SNicolas Souchu #include "iicbb_if.h" 54f7ce69c9SNicolas Souchu 550f210c92SNicolas Souchu static int lpbb_detect(device_t dev); 56f7ce69c9SNicolas Souchu 570f063508SPeter Wemm static void 580f063508SPeter Wemm lpbb_identify(driver_t *driver, device_t parent) 590f063508SPeter Wemm { 60f7ce69c9SNicolas Souchu 61338cad62SBernd Walter BUS_ADD_CHILD(parent, 0, "lpbb", -1); 620f063508SPeter Wemm } 63f7ce69c9SNicolas Souchu 64f7ce69c9SNicolas Souchu static int 65f7ce69c9SNicolas Souchu lpbb_probe(device_t dev) 66f7ce69c9SNicolas Souchu { 67f7ce69c9SNicolas Souchu 680f063508SPeter Wemm /* Perhaps call this during identify instead? */ 690f210c92SNicolas Souchu if (!lpbb_detect(dev)) 700f210c92SNicolas Souchu return (ENXIO); 71f7ce69c9SNicolas Souchu 720f063508SPeter Wemm device_set_desc(dev, "Parallel I2C bit-banging interface"); 730f063508SPeter Wemm 74f7ce69c9SNicolas Souchu return (0); 75f7ce69c9SNicolas Souchu } 76f7ce69c9SNicolas Souchu 77f7ce69c9SNicolas Souchu static int 78f7ce69c9SNicolas Souchu lpbb_attach(device_t dev) 79f7ce69c9SNicolas Souchu { 80c17d4340SNicolas Souchu device_t bitbang; 81f7ce69c9SNicolas Souchu 82f7ce69c9SNicolas Souchu /* add generic bit-banging code */ 83fe0d4089SMatthew N. Dodd bitbang = device_add_child(dev, "iicbb", -1); 84f7ce69c9SNicolas Souchu device_probe_and_attach(bitbang); 85f7ce69c9SNicolas Souchu 86f7ce69c9SNicolas Souchu return (0); 87f7ce69c9SNicolas Souchu } 88f7ce69c9SNicolas Souchu 89f7ce69c9SNicolas Souchu static int 90f7ce69c9SNicolas Souchu lpbb_callback(device_t dev, int index, caddr_t *data) 91f7ce69c9SNicolas Souchu { 920f210c92SNicolas Souchu device_t ppbus = device_get_parent(dev); 93f7ce69c9SNicolas Souchu int error = 0; 94f7ce69c9SNicolas Souchu int how; 95f7ce69c9SNicolas Souchu 96f7ce69c9SNicolas Souchu switch (index) { 97f7ce69c9SNicolas Souchu case IIC_REQUEST_BUS: 98f7ce69c9SNicolas Souchu /* request the ppbus */ 99f7ce69c9SNicolas Souchu how = *(int *)data; 1000f210c92SNicolas Souchu error = ppb_request_bus(ppbus, dev, how); 101f7ce69c9SNicolas Souchu break; 102f7ce69c9SNicolas Souchu 103f7ce69c9SNicolas Souchu case IIC_RELEASE_BUS: 104f7ce69c9SNicolas Souchu /* release the ppbus */ 1050f210c92SNicolas Souchu error = ppb_release_bus(ppbus, dev); 106f7ce69c9SNicolas Souchu break; 107f7ce69c9SNicolas Souchu 108f7ce69c9SNicolas Souchu default: 109f7ce69c9SNicolas Souchu error = EINVAL; 110f7ce69c9SNicolas Souchu } 111f7ce69c9SNicolas Souchu 112f7ce69c9SNicolas Souchu return (error); 113f7ce69c9SNicolas Souchu } 114f7ce69c9SNicolas Souchu 115f7ce69c9SNicolas Souchu #define SDA_out 0x80 116f7ce69c9SNicolas Souchu #define SCL_out 0x08 117f7ce69c9SNicolas Souchu #define SDA_in 0x80 118f7ce69c9SNicolas Souchu #define SCL_in 0x08 119f7ce69c9SNicolas Souchu #define ALIM 0x20 120f7ce69c9SNicolas Souchu #define I2CKEY 0x50 121f7ce69c9SNicolas Souchu 122c17d4340SNicolas Souchu static int lpbb_getscl(device_t dev) 123f7ce69c9SNicolas Souchu { 124c17d4340SNicolas Souchu return ((ppb_rstr(device_get_parent(dev)) & SCL_in) == SCL_in); 125f7ce69c9SNicolas Souchu } 126f7ce69c9SNicolas Souchu 127c17d4340SNicolas Souchu static int lpbb_getsda(device_t dev) 128f7ce69c9SNicolas Souchu { 129c17d4340SNicolas Souchu return ((ppb_rstr(device_get_parent(dev)) & SDA_in) == SDA_in); 130c17d4340SNicolas Souchu } 131c17d4340SNicolas Souchu 132c17d4340SNicolas Souchu static void lpbb_setsda(device_t dev, char val) 133c17d4340SNicolas Souchu { 134c17d4340SNicolas Souchu device_t ppbus = device_get_parent(dev); 135c17d4340SNicolas Souchu 136f7ce69c9SNicolas Souchu if(val==0) 1370f210c92SNicolas Souchu ppb_wdtr(ppbus, (u_char)SDA_out); 138f7ce69c9SNicolas Souchu else 1390f210c92SNicolas Souchu ppb_wdtr(ppbus, (u_char)~SDA_out); 140f7ce69c9SNicolas Souchu } 141f7ce69c9SNicolas Souchu 142c17d4340SNicolas Souchu static void lpbb_setscl(device_t dev, unsigned char val) 143f7ce69c9SNicolas Souchu { 144c17d4340SNicolas Souchu device_t ppbus = device_get_parent(dev); 145c17d4340SNicolas Souchu 146f7ce69c9SNicolas Souchu if(val==0) 1470f210c92SNicolas Souchu ppb_wctr(ppbus, (u_char)(ppb_rctr(ppbus)&~SCL_out)); 148f7ce69c9SNicolas Souchu else 1490f210c92SNicolas Souchu ppb_wctr(ppbus, (u_char)(ppb_rctr(ppbus)|SCL_out)); 150f7ce69c9SNicolas Souchu } 151f7ce69c9SNicolas Souchu 1520f210c92SNicolas Souchu static int lpbb_detect(device_t dev) 153f7ce69c9SNicolas Souchu { 1540f210c92SNicolas Souchu device_t ppbus = device_get_parent(dev); 1550f210c92SNicolas Souchu 1560f210c92SNicolas Souchu if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) { 1570f210c92SNicolas Souchu device_printf(dev, "can't allocate ppbus\n"); 158f7ce69c9SNicolas Souchu return (0); 159f7ce69c9SNicolas Souchu } 160f7ce69c9SNicolas Souchu 161f7ce69c9SNicolas Souchu /* reset bus */ 162c17d4340SNicolas Souchu lpbb_setsda(dev, 1); 163c17d4340SNicolas Souchu lpbb_setscl(dev, 1); 164f7ce69c9SNicolas Souchu 1650f210c92SNicolas Souchu if ((ppb_rstr(ppbus) & I2CKEY) || 1660f210c92SNicolas Souchu ((ppb_rstr(ppbus) & ALIM) != ALIM)) { 167a6530aceSNicolas Souchu 1680f210c92SNicolas Souchu ppb_release_bus(ppbus, dev); 169f7ce69c9SNicolas Souchu return (0); 170a6530aceSNicolas Souchu } 171f7ce69c9SNicolas Souchu 1720f210c92SNicolas Souchu ppb_release_bus(ppbus, dev); 173f7ce69c9SNicolas Souchu 174f7ce69c9SNicolas Souchu return (1); 175f7ce69c9SNicolas Souchu } 176f7ce69c9SNicolas Souchu 177f7ce69c9SNicolas Souchu static int 178f7ce69c9SNicolas Souchu lpbb_reset(device_t dev, u_char speed, u_char addr, u_char * oldaddr) 179f7ce69c9SNicolas Souchu { 1800f210c92SNicolas Souchu device_t ppbus = device_get_parent(dev); 181f7ce69c9SNicolas Souchu 182c17d4340SNicolas Souchu if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) { 183c17d4340SNicolas Souchu device_printf(dev, "can't allocate ppbus\n"); 184c17d4340SNicolas Souchu return (0); 185c17d4340SNicolas Souchu } 186c17d4340SNicolas Souchu 187f7ce69c9SNicolas Souchu /* reset bus */ 188c17d4340SNicolas Souchu lpbb_setsda(dev, 1); 189c17d4340SNicolas Souchu lpbb_setscl(dev, 1); 190c17d4340SNicolas Souchu 191c17d4340SNicolas Souchu ppb_release_bus(ppbus, dev); 192f7ce69c9SNicolas Souchu 193f7ce69c9SNicolas Souchu return (IIC_ENOADDR); 194f7ce69c9SNicolas Souchu } 195f7ce69c9SNicolas Souchu 1960f063508SPeter Wemm static devclass_t lpbb_devclass; 1970f063508SPeter Wemm 1980f063508SPeter Wemm static device_method_t lpbb_methods[] = { 1990f063508SPeter Wemm /* device interface */ 2000f063508SPeter Wemm DEVMETHOD(device_identify, lpbb_identify), 2010f063508SPeter Wemm DEVMETHOD(device_probe, lpbb_probe), 2020f063508SPeter Wemm DEVMETHOD(device_attach, lpbb_attach), 2030f063508SPeter Wemm 2040f063508SPeter Wemm /* bus interface */ 2050f063508SPeter Wemm DEVMETHOD(bus_print_child, bus_generic_print_child), 2060f063508SPeter Wemm 2070f063508SPeter Wemm /* iicbb interface */ 2080f063508SPeter Wemm DEVMETHOD(iicbb_callback, lpbb_callback), 209c17d4340SNicolas Souchu DEVMETHOD(iicbb_setsda, lpbb_setsda), 210c17d4340SNicolas Souchu DEVMETHOD(iicbb_setscl, lpbb_setscl), 211c17d4340SNicolas Souchu DEVMETHOD(iicbb_getsda, lpbb_getsda), 212c17d4340SNicolas Souchu DEVMETHOD(iicbb_getscl, lpbb_getscl), 2130f063508SPeter Wemm DEVMETHOD(iicbb_reset, lpbb_reset), 2140f063508SPeter Wemm 2150f063508SPeter Wemm { 0, 0 } 2160f063508SPeter Wemm }; 2170f063508SPeter Wemm 2180f063508SPeter Wemm static driver_t lpbb_driver = { 2190f063508SPeter Wemm "lpbb", 2200f063508SPeter Wemm lpbb_methods, 2210f063508SPeter Wemm 1, 2220f063508SPeter Wemm }; 2230f063508SPeter Wemm 2240f210c92SNicolas Souchu DRIVER_MODULE(lpbb, ppbus, lpbb_driver, lpbb_devclass, 0, 0); 225c17d4340SNicolas Souchu MODULE_DEPEND(lpbb, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); 226c17d4340SNicolas Souchu MODULE_VERSION(lpbb, 1); 227