iicbus.c revision 167856
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 167856 2007-03-23 23:08:28Z imp $"); 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> 37167856Simp#include <sys/malloc.h> 3838774Snsouch#include <sys/module.h> 3938774Snsouch#include <sys/bus.h> 4038774Snsouch 4138774Snsouch#include <dev/iicbus/iiconf.h> 4238774Snsouch#include <dev/iicbus/iicbus.h> 4338774Snsouch 4438774Snsouch#include "iicbus_if.h" 4538774Snsouch 46129152Sjoerg/* See comments below for why auto-scanning is a bad idea. */ 47129152Sjoerg#define SCAN_IICBUS 0 48129152Sjoerg 4940782Snsouchstatic int 5040782Snsouchiicbus_probe(device_t dev) 5140782Snsouch{ 52160372Simp 5342442Snsouch device_set_desc(dev, "Philips I2C bus"); 5440782Snsouch return (0); 5540782Snsouch} 5640782Snsouch 57129152Sjoerg#if SCAN_IICBUS 5840782Snsouchstatic int 5940782Snsouchiic_probe_device(device_t dev, u_char addr) 6040782Snsouch{ 6140782Snsouch int count; 6240782Snsouch char byte; 6340782Snsouch 6440782Snsouch if ((addr & 1) == 0) { 6540782Snsouch /* is device writable? */ 6640782Snsouch if (!iicbus_start(dev, (u_char)addr, 0)) { 6740782Snsouch iicbus_stop(dev); 6840782Snsouch return (1); 6940782Snsouch } 7040782Snsouch } else { 7140782Snsouch /* is device readable? */ 7240782Snsouch if (!iicbus_block_read(dev, (u_char)addr, &byte, 1, &count)) 7340782Snsouch return (1); 7440782Snsouch } 7540782Snsouch 7640782Snsouch return (0); 7740782Snsouch} 7842442Snsouch#endif 7940782Snsouch 8038774Snsouch/* 8140782Snsouch * We add all the devices which we know about. 8240782Snsouch * The generic attach routine will attach them if they are alive. 8338774Snsouch */ 8438774Snsouchstatic int 8540782Snsouchiicbus_attach(device_t dev) 8638774Snsouch{ 87129152Sjoerg#if SCAN_IICBUS 88129152Sjoerg unsigned char addr; 89129152Sjoerg#endif 90167856Simp struct iicbus_softc *sc = IICBUS_SOFTC(dev); 91129152Sjoerg 92167856Simp sc->dev = dev; 9340782Snsouch iicbus_reset(dev, IIC_FASTEST, 0, NULL); 9438774Snsouch 9542442Snsouch /* device probing is meaningless since the bus is supposed to be 9642442Snsouch * hot-plug. Moreover, some I2C chips do not appreciate random 9742442Snsouch * accesses like stop after start to fast, reads for less than 9842442Snsouch * x bytes... 9942442Snsouch */ 100129152Sjoerg#if SCAN_IICBUS 10140782Snsouch printf("Probing for devices on iicbus%d:", device_get_unit(dev)); 10238774Snsouch 10340782Snsouch /* probe any devices */ 104129152Sjoerg for (addr = 16; addr < 240; addr++) { 10540782Snsouch if (iic_probe_device(dev, (u_char)addr)) { 10640782Snsouch printf(" <%x>", addr); 10740782Snsouch } 10840782Snsouch } 10940782Snsouch printf("\n"); 11042442Snsouch#endif 111167856Simp /* Always attach the iicsmb children */ 112167856Simp BUS_ADD_CHILD(dev, 0, "iicsmb", -1); 11393023Snsouch /* attach any known device */ 114167856Simp BUS_ADD_CHILD(dev, 0, "iic", -1); 115167856Simp /* Attach the wired devices via hints */ 116167856Simp bus_enumerate_hinted_children(dev); 117167856Simp /* Now probe and attach them */ 11838774Snsouch bus_generic_attach(dev); 11938774Snsouch return (0); 12038774Snsouch} 12193023Snsouch 12293023Snsouchstatic int 12393023Snsouchiicbus_detach(device_t dev) 12493023Snsouch{ 125160372Simp 12693023Snsouch iicbus_reset(dev, IIC_FASTEST, 0, NULL); 12793023Snsouch bus_generic_detach(dev); 12893023Snsouch return (0); 12993023Snsouch} 13093023Snsouch 13193023Snsouchstatic int 132167856Simpiicbus_print_child(device_t dev, device_t child) 13393023Snsouch{ 134167856Simp struct iicbus_ivar *devi = IICBUS_IVAR(child); 135167856Simp int retval = 0; 136160372Simp 137167856Simp retval += bus_print_child_header(dev, child); 138167856Simp if (devi->addr != 0) 139167856Simp retval += printf(" at addr %#x", devi->addr); 140167856Simp retval += bus_print_child_footer(dev, child); 141167856Simp 142167856Simp return (retval); 143167856Simp} 144167856Simp 145167856Simpstatic void 146167856Simpiicbus_probe_nomatch(device_t bus, device_t child) 147167856Simp{ 148167856Simp struct iicbus_ivar *devi = IICBUS_IVAR(child); 149167856Simp 150167856Simp device_printf(bus, "<unknown card>"); 151167856Simp printf(" at addr %#x\n", devi->addr); 152167856Simp return; 153167856Simp} 154167856Simp 155167856Simpstatic int 156167856Simpiicbus_child_location_str(device_t bus, device_t child, char *buf, 157167856Simp size_t buflen) 158167856Simp{ 159167856Simp struct iicbus_ivar *devi = IICBUS_IVAR(child); 160167856Simp 161167856Simp snprintf(buf, buflen, "addr=%#x", devi->addr); 16293023Snsouch return (0); 16393023Snsouch} 16493023Snsouch 165167856Simpstatic int 166167856Simpiicbus_child_pnpinfo_str(device_t bus, device_t child, char *buf, 167167856Simp size_t buflen) 168167856Simp{ 169167856Simp *buf = '\0'; 170167856Simp return (0); 171167856Simp} 172167856Simp 173167856Simpstatic int 174167856Simpiicbus_read_ivar(device_t bus, device_t child, int which, u_char *result) 175167856Simp{ 176167856Simp struct iicbus_ivar *devi = IICBUS_IVAR(child); 177167856Simp 178167856Simp switch (which) { 179167856Simp default: 180167856Simp return (EINVAL); 181167856Simp case IICBUS_IVAR_ADDR: 182167856Simp *(uint32_t *)result = devi->addr; 183167856Simp break; 184167856Simp } 185167856Simp return (0); 186167856Simp} 187167856Simp 188167856Simpstatic device_t 189167856Simpiicbus_add_child(device_t dev, int order, const char *name, int unit) 190167856Simp{ 191167856Simp device_t child; 192167856Simp struct iicbus_ivar *devi; 193167856Simp 194167856Simp child = device_add_child_ordered(dev, order, name, unit); 195167856Simp if (child == NULL) 196167856Simp return (child); 197167856Simp devi = malloc(sizeof(struct iicbus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 198167856Simp if (devi == NULL) { 199167856Simp device_delete_child(dev, child); 200167856Simp return (0); 201167856Simp } 202167856Simp device_set_ivars(child, devi); 203167856Simp return (child); 204167856Simp} 205167856Simp 206167856Simpstatic void 207167856Simpiicbus_hinted_child(device_t bus, const char *dname, int dunit) 208167856Simp{ 209167856Simp device_t child; 210167856Simp struct iicbus_ivar *devi; 211167856Simp 212167856Simp child = BUS_ADD_CHILD(bus, 0, dname, dunit); 213167856Simp devi = IICBUS_IVAR(child); 214167856Simp resource_int_value(dname, dunit, "addr", &devi->addr); 215167856Simp} 216167856Simp 21738774Snsouchint 21838774Snsouchiicbus_generic_intr(device_t dev, int event, char *buf) 21938774Snsouch{ 220160372Simp 22138774Snsouch return (0); 22238774Snsouch} 22338774Snsouch 22440782Snsouchint 22540782Snsouchiicbus_null_callback(device_t dev, int index, caddr_t data) 22640782Snsouch{ 227160372Simp 22840782Snsouch return (0); 22940782Snsouch} 23040782Snsouch 23140782Snsouchint 23240782Snsouchiicbus_null_repeated_start(device_t dev, u_char addr) 23340782Snsouch{ 234160372Simp 23540782Snsouch return (IIC_ENOTSUPP); 23640782Snsouch} 23740782Snsouch 238167856Simpstatic device_method_t iicbus_methods[] = { 239167856Simp /* device interface */ 240167856Simp DEVMETHOD(device_probe, iicbus_probe), 241167856Simp DEVMETHOD(device_attach, iicbus_attach), 242167856Simp DEVMETHOD(device_detach, iicbus_detach), 243167856Simp 244167856Simp /* bus interface */ 245167856Simp DEVMETHOD(bus_add_child, iicbus_add_child), 246167856Simp DEVMETHOD(bus_driver_added, bus_generic_driver_added), 247167856Simp DEVMETHOD(bus_print_child, iicbus_print_child), 248167856Simp DEVMETHOD(bus_probe_nomatch, iicbus_probe_nomatch), 249167856Simp DEVMETHOD(bus_read_ivar, iicbus_read_ivar), 250167856Simp DEVMETHOD(bus_child_pnpinfo_str, iicbus_child_pnpinfo_str), 251167856Simp DEVMETHOD(bus_child_location_str, iicbus_child_location_str), 252167856Simp DEVMETHOD(bus_hinted_child, iicbus_hinted_child), 253167856Simp 254167856Simp /* iicbus interface */ 255167856Simp DEVMETHOD(iicbus_transfer, iicbus_transfer), 256167856Simp 257167856Simp { 0, 0 } 258167856Simp}; 259167856Simp 260167856Simpdriver_t iicbus_driver = { 261167856Simp "iicbus", 262167856Simp iicbus_methods, 263167856Simp sizeof(struct iicbus_softc), 264167856Simp}; 265167856Simp 266167856Simpdevclass_t iicbus_devclass; 267167856Simp 268129778SjoergDRIVER_MODULE(iicbus, envctrl, iicbus_driver, iicbus_devclass, 0, 0); 26940782SnsouchDRIVER_MODULE(iicbus, iicbb, iicbus_driver, iicbus_devclass, 0, 0); 27093023SnsouchMODULE_VERSION(iicbus, IICBUS_MODVER); 271