iicbus.c revision 228257
138774Snsouch/*- 293023Snsouch * Copyright (c) 1998, 2001 Nicolas Souchu 338774Snsouch * All rights reserved. 438774Snsouch * 538774Snsouch * Redistribution and use in source and binary forms, with or without 638774Snsouch * modification, are permitted provided that the following conditions 738774Snsouch * are met: 838774Snsouch * 1. Redistributions of source code must retain the above copyright 938774Snsouch * notice, this list of conditions and the following disclaimer. 1038774Snsouch * 2. Redistributions in binary form must reproduce the above copyright 1138774Snsouch * notice, this list of conditions and the following disclaimer in the 1238774Snsouch * documentation and/or other materials provided with the distribution. 1338774Snsouch * 1438774Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538774Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638774Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738774Snsouch * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838774Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938774Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038774Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138774Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238774Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338774Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438774Snsouch * SUCH DAMAGE. 2538774Snsouch */ 2638774Snsouch 27119418Sobrien#include <sys/cdefs.h> 28119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/iicbus/iicbus.c 228257 2011-12-04 11:55:33Z adrian $"); 29119418Sobrien 3038774Snsouch/* 3138774Snsouch * Autoconfiguration and support routines for the Philips serial I2C bus 3238774Snsouch */ 3338774Snsouch 3438774Snsouch#include <sys/param.h> 3538774Snsouch#include <sys/systm.h> 3638774Snsouch#include <sys/kernel.h> 37181304Sjhb#include <sys/lock.h> 38167856Simp#include <sys/malloc.h> 3938774Snsouch#include <sys/module.h> 40181304Sjhb#include <sys/mutex.h> 4138774Snsouch#include <sys/bus.h> 4238774Snsouch 4338774Snsouch#include <dev/iicbus/iiconf.h> 4438774Snsouch#include <dev/iicbus/iicbus.h> 4538774Snsouch 4638774Snsouch#include "iicbus_if.h" 4738774Snsouch 48129152Sjoerg/* See comments below for why auto-scanning is a bad idea. */ 49129152Sjoerg#define SCAN_IICBUS 0 50129152Sjoerg 5140782Snsouchstatic int 5240782Snsouchiicbus_probe(device_t dev) 5340782Snsouch{ 54160372Simp 5542442Snsouch device_set_desc(dev, "Philips I2C bus"); 56186833Snwhitehorn 57186833Snwhitehorn /* Allow other subclasses to override this driver. */ 58187457Snwhitehorn return (BUS_PROBE_GENERIC); 5940782Snsouch} 6040782Snsouch 61129152Sjoerg#if SCAN_IICBUS 6240782Snsouchstatic int 6340782Snsouchiic_probe_device(device_t dev, u_char addr) 6440782Snsouch{ 6540782Snsouch int count; 6640782Snsouch char byte; 6740782Snsouch 6840782Snsouch if ((addr & 1) == 0) { 6940782Snsouch /* is device writable? */ 7040782Snsouch if (!iicbus_start(dev, (u_char)addr, 0)) { 7140782Snsouch iicbus_stop(dev); 7240782Snsouch return (1); 7340782Snsouch } 7440782Snsouch } else { 7540782Snsouch /* is device readable? */ 7640782Snsouch if (!iicbus_block_read(dev, (u_char)addr, &byte, 1, &count)) 7740782Snsouch return (1); 7840782Snsouch } 7940782Snsouch 8040782Snsouch return (0); 8140782Snsouch} 8242442Snsouch#endif 8340782Snsouch 8438774Snsouch/* 8540782Snsouch * We add all the devices which we know about. 8640782Snsouch * The generic attach routine will attach them if they are alive. 8738774Snsouch */ 8838774Snsouchstatic int 8940782Snsouchiicbus_attach(device_t dev) 9038774Snsouch{ 91129152Sjoerg#if SCAN_IICBUS 92129152Sjoerg unsigned char addr; 93129152Sjoerg#endif 94167856Simp struct iicbus_softc *sc = IICBUS_SOFTC(dev); 95228257Sadrian int strict; 96129152Sjoerg 97167856Simp sc->dev = dev; 98181304Sjhb mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF); 9940782Snsouch iicbus_reset(dev, IIC_FASTEST, 0, NULL); 100228257Sadrian if (resource_int_value(device_get_name(dev), 101228257Sadrian device_get_unit(dev), "strict", &strict) == 0) 102228257Sadrian sc->strict = strict; 103228257Sadrian else 104228257Sadrian sc->strict = 1; 10538774Snsouch 10642442Snsouch /* device probing is meaningless since the bus is supposed to be 10742442Snsouch * hot-plug. Moreover, some I2C chips do not appreciate random 10842442Snsouch * accesses like stop after start to fast, reads for less than 10942442Snsouch * x bytes... 11042442Snsouch */ 111129152Sjoerg#if SCAN_IICBUS 11240782Snsouch printf("Probing for devices on iicbus%d:", device_get_unit(dev)); 11338774Snsouch 11440782Snsouch /* probe any devices */ 115129152Sjoerg for (addr = 16; addr < 240; addr++) { 11640782Snsouch if (iic_probe_device(dev, (u_char)addr)) { 11740782Snsouch printf(" <%x>", addr); 11840782Snsouch } 11940782Snsouch } 12040782Snsouch printf("\n"); 12142442Snsouch#endif 122181304Sjhb bus_generic_probe(dev); 123167856Simp bus_enumerate_hinted_children(dev); 12438774Snsouch bus_generic_attach(dev); 12538774Snsouch return (0); 12638774Snsouch} 12793023Snsouch 12893023Snsouchstatic int 12993023Snsouchiicbus_detach(device_t dev) 13093023Snsouch{ 131181304Sjhb struct iicbus_softc *sc = IICBUS_SOFTC(dev); 132160372Simp 13393023Snsouch iicbus_reset(dev, IIC_FASTEST, 0, NULL); 13493023Snsouch bus_generic_detach(dev); 135181304Sjhb mtx_destroy(&sc->lock); 13693023Snsouch return (0); 13793023Snsouch} 13893023Snsouch 13993023Snsouchstatic int 140167856Simpiicbus_print_child(device_t dev, device_t child) 14193023Snsouch{ 142167856Simp struct iicbus_ivar *devi = IICBUS_IVAR(child); 143167856Simp int retval = 0; 144160372Simp 145167856Simp retval += bus_print_child_header(dev, child); 146167856Simp if (devi->addr != 0) 147167856Simp retval += printf(" at addr %#x", devi->addr); 148167856Simp retval += bus_print_child_footer(dev, child); 149167856Simp 150167856Simp return (retval); 151167856Simp} 152167856Simp 153167856Simpstatic void 154167856Simpiicbus_probe_nomatch(device_t bus, device_t child) 155167856Simp{ 156167856Simp struct iicbus_ivar *devi = IICBUS_IVAR(child); 157167856Simp 158167856Simp device_printf(bus, "<unknown card>"); 159167856Simp printf(" at addr %#x\n", devi->addr); 160167856Simp return; 161167856Simp} 162167856Simp 163167856Simpstatic int 164167856Simpiicbus_child_location_str(device_t bus, device_t child, char *buf, 165167856Simp size_t buflen) 166167856Simp{ 167167856Simp struct iicbus_ivar *devi = IICBUS_IVAR(child); 168167856Simp 169167856Simp snprintf(buf, buflen, "addr=%#x", devi->addr); 17093023Snsouch return (0); 17193023Snsouch} 17293023Snsouch 173167856Simpstatic int 174167856Simpiicbus_child_pnpinfo_str(device_t bus, device_t child, char *buf, 175167856Simp size_t buflen) 176167856Simp{ 177167856Simp *buf = '\0'; 178167856Simp return (0); 179167856Simp} 180167856Simp 181167856Simpstatic int 182188461Simpiicbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) 183167856Simp{ 184167856Simp struct iicbus_ivar *devi = IICBUS_IVAR(child); 185167856Simp 186167856Simp switch (which) { 187167856Simp default: 188167856Simp return (EINVAL); 189167856Simp case IICBUS_IVAR_ADDR: 190209800Snwhitehorn *result = devi->addr; 191167856Simp break; 192167856Simp } 193167856Simp return (0); 194167856Simp} 195167856Simp 196167856Simpstatic device_t 197212413Savgiicbus_add_child(device_t dev, u_int order, const char *name, int unit) 198167856Simp{ 199167856Simp device_t child; 200167856Simp struct iicbus_ivar *devi; 201167856Simp 202167856Simp child = device_add_child_ordered(dev, order, name, unit); 203167856Simp if (child == NULL) 204167856Simp return (child); 205167856Simp devi = malloc(sizeof(struct iicbus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 206167856Simp if (devi == NULL) { 207167856Simp device_delete_child(dev, child); 208167856Simp return (0); 209167856Simp } 210167856Simp device_set_ivars(child, devi); 211167856Simp return (child); 212167856Simp} 213167856Simp 214167856Simpstatic void 215167856Simpiicbus_hinted_child(device_t bus, const char *dname, int dunit) 216167856Simp{ 217167856Simp device_t child; 218167856Simp struct iicbus_ivar *devi; 219167856Simp 220167856Simp child = BUS_ADD_CHILD(bus, 0, dname, dunit); 221167856Simp devi = IICBUS_IVAR(child); 222167856Simp resource_int_value(dname, dunit, "addr", &devi->addr); 223167856Simp} 224167856Simp 22538774Snsouchint 22638774Snsouchiicbus_generic_intr(device_t dev, int event, char *buf) 22738774Snsouch{ 228160372Simp 22938774Snsouch return (0); 23038774Snsouch} 23138774Snsouch 23240782Snsouchint 23340782Snsouchiicbus_null_callback(device_t dev, int index, caddr_t data) 23440782Snsouch{ 235160372Simp 23640782Snsouch return (0); 23740782Snsouch} 23840782Snsouch 23940782Snsouchint 24040782Snsouchiicbus_null_repeated_start(device_t dev, u_char addr) 24140782Snsouch{ 242160372Simp 24340782Snsouch return (IIC_ENOTSUPP); 24440782Snsouch} 24540782Snsouch 246167856Simpstatic device_method_t iicbus_methods[] = { 247167856Simp /* device interface */ 248167856Simp DEVMETHOD(device_probe, iicbus_probe), 249167856Simp DEVMETHOD(device_attach, iicbus_attach), 250167856Simp DEVMETHOD(device_detach, iicbus_detach), 251167856Simp 252167856Simp /* bus interface */ 253167856Simp DEVMETHOD(bus_add_child, iicbus_add_child), 254167856Simp DEVMETHOD(bus_print_child, iicbus_print_child), 255167856Simp DEVMETHOD(bus_probe_nomatch, iicbus_probe_nomatch), 256167856Simp DEVMETHOD(bus_read_ivar, iicbus_read_ivar), 257167856Simp DEVMETHOD(bus_child_pnpinfo_str, iicbus_child_pnpinfo_str), 258167856Simp DEVMETHOD(bus_child_location_str, iicbus_child_location_str), 259167856Simp DEVMETHOD(bus_hinted_child, iicbus_hinted_child), 260167856Simp 261167856Simp /* iicbus interface */ 262167856Simp DEVMETHOD(iicbus_transfer, iicbus_transfer), 263167856Simp 264227843Smarius DEVMETHOD_END 265167856Simp}; 266167856Simp 267167856Simpdriver_t iicbus_driver = { 268167856Simp "iicbus", 269167856Simp iicbus_methods, 270167856Simp sizeof(struct iicbus_softc), 271167856Simp}; 272167856Simp 273167856Simpdevclass_t iicbus_devclass; 274167856Simp 27593023SnsouchMODULE_VERSION(iicbus, IICBUS_MODVER); 276187261SnwhitehornDRIVER_MODULE(iicbus, iichb, iicbus_driver, iicbus_devclass, 0, 0); 277187261Snwhitehorn 278