iicbus.c revision 38774
138774Snsouch/*- 238774Snsouch * Copyright (c) 1998 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 * $Id: iicbus.c,v 1.1.2.7 1998/08/29 16:54:16 son Exp $ 2738774Snsouch * 2838774Snsouch */ 2938774Snsouch 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> 3738774Snsouch#include <sys/module.h> 3838774Snsouch#include <sys/bus.h> 3938774Snsouch 4038774Snsouch#include <machine/clock.h> 4138774Snsouch 4238774Snsouch#include <dev/iicbus/iiconf.h> 4338774Snsouch#include <dev/iicbus/iicbus.h> 4438774Snsouch 4538774Snsouch#include "iicbus_if.h" 4638774Snsouch 4738774Snsouch#define DEVTOIICBUS(dev) ((struct iicbus_device*)device_get_ivars(dev)) 4838774Snsouch 4938774Snsouch/* 5038774Snsouch * structure used to attach devices to the I2C bus 5138774Snsouch */ 5238774Snsouchstruct iicbus_device { 5338774Snsouch const char *iicd_name; /* device name */ 5438774Snsouch int iicd_class; /* driver or slave device class */ 5538774Snsouch const char *iicd_desc; /* device descriptor */ 5638774Snsouch u_char iicd_addr; /* address of the device */ 5738774Snsouch int iicd_alive; /* 1 if device found */ 5838774Snsouch}; 5938774Snsouch 6038774Snsouch/* 6138774Snsouch * Common I2C addresses 6238774Snsouch */ 6338774Snsouch#define I2C_GENERAL_CALL 0x0 6438774Snsouch#define I2C_MASTER_ADDRESS 0xaa 6538774Snsouch#define I2C_INET_ADDRESS 0xaa 6638774Snsouch 6738774Snsouch#define MAXSLAVE 256 6838774Snsouch 6938774Snsouch#define IICBUS_UNKNOWN_CLASS 0 7038774Snsouch#define IICBUS_DEVICE_CLASS 1 7138774Snsouch#define IICBUS_DRIVER_CLASS 2 7238774Snsouch 7338774Snsouch/* 7438774Snsouch * list of known devices 7538774Snsouch */ 7638774Snsouchstruct iicbus_device iicbus_children[] = { 7738774Snsouch { "iic", IICBUS_DRIVER_CLASS, "General Call", I2C_GENERAL_CALL }, 7838774Snsouch { "iicsmb", IICBUS_DRIVER_CLASS, "I2C to SMB bridge" }, 7938774Snsouch { "iic", IICBUS_DEVICE_CLASS, "PCF8574 I2C to 8 bits parallel i/o", 64}, 8038774Snsouch { "iic", IICBUS_DEVICE_CLASS, "PCF8584 as slave", I2C_MASTER_ADDRESS }, 8138774Snsouch { "ic", IICBUS_DEVICE_CLASS, "network interface", I2C_INET_ADDRESS }, 8238774Snsouch { NULL, 0 } 8338774Snsouch}; 8438774Snsouch 8538774Snsouchstatic devclass_t iicbus_devclass; 8638774Snsouch 8738774Snsouch/* 8838774Snsouch * Device methods 8938774Snsouch */ 9038774Snsouchstatic int iicbus_probe(device_t); 9138774Snsouchstatic int iicbus_attach(device_t); 9238774Snsouchstatic void iicbus_print_child(device_t, device_t); 9338774Snsouchstatic int iicbus_read_ivar(device_t , device_t, int, u_long *); 9438774Snsouch 9538774Snsouchstatic device_method_t iicbus_methods[] = { 9638774Snsouch /* device interface */ 9738774Snsouch DEVMETHOD(device_probe, iicbus_probe), 9838774Snsouch DEVMETHOD(device_attach, iicbus_attach), 9938774Snsouch DEVMETHOD(device_detach, bus_generic_detach), 10038774Snsouch DEVMETHOD(device_shutdown, bus_generic_shutdown), 10138774Snsouch 10238774Snsouch /* bus interface */ 10338774Snsouch DEVMETHOD(bus_print_child, iicbus_print_child), 10438774Snsouch DEVMETHOD(bus_read_ivar, iicbus_read_ivar), 10538774Snsouch DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), 10638774Snsouch DEVMETHOD(bus_create_intr, bus_generic_create_intr), 10738774Snsouch DEVMETHOD(bus_connect_intr, bus_generic_connect_intr), 10838774Snsouch 10938774Snsouch { 0, 0 } 11038774Snsouch}; 11138774Snsouch 11238774Snsouchstatic driver_t iicbus_driver = { 11338774Snsouch "iicbus", 11438774Snsouch iicbus_methods, 11538774Snsouch DRIVER_TYPE_MISC, 11638774Snsouch sizeof(struct iicbus_softc), 11738774Snsouch}; 11838774Snsouch 11938774Snsouch/* 12038774Snsouch * At 'probe' time, we add all the devices which we know about to the 12138774Snsouch * bus. The generic attach routine will probe and attach them if they 12238774Snsouch * are alive. 12338774Snsouch */ 12438774Snsouchstatic int 12538774Snsouchiicbus_probe(device_t dev) 12638774Snsouch{ 12738774Snsouch struct iicbus_softc *sc = device_get_softc(dev); 12838774Snsouch struct iicbus_device *iicdev; 12938774Snsouch device_t child; 13038774Snsouch 13138774Snsouch /* XXX should query parent */ 13238774Snsouch sc->ownaddr = I2C_MASTER_ADDRESS; 13338774Snsouch 13438774Snsouch iicbus_reset(dev, IIC_FASTEST); 13538774Snsouch 13638774Snsouch for (iicdev = iicbus_children; iicdev->iicd_name; iicdev++) { 13738774Snsouch 13838774Snsouch /* probe devices, not drivers */ 13938774Snsouch switch (iicdev->iicd_class) { 14038774Snsouch case IICBUS_DEVICE_CLASS: 14138774Snsouch if (!iicbus_start(dev, iicdev->iicd_addr)) { 14238774Snsouch iicbus_stop(dev); 14338774Snsouch iicdev->iicd_alive = 1; 14438774Snsouch } 14538774Snsouch break; 14638774Snsouch case IICBUS_DRIVER_CLASS: 14738774Snsouch iicdev->iicd_addr = sc->ownaddr; 14838774Snsouch break; 14938774Snsouch default: 15038774Snsouch panic("%s: unknown class!", __FUNCTION__); 15138774Snsouch } 15238774Snsouch 15338774Snsouch child = device_add_child(dev, iicdev->iicd_name, -1, iicdev); 15438774Snsouch device_set_desc(child, iicdev->iicd_desc); 15538774Snsouch } 15638774Snsouch 15738774Snsouch return (0); 15838774Snsouch} 15938774Snsouch 16038774Snsouchstatic int 16138774Snsouchiicbus_attach(device_t dev) 16238774Snsouch{ 16338774Snsouch bus_generic_attach(dev); 16438774Snsouch 16538774Snsouch return (0); 16638774Snsouch} 16738774Snsouch 16838774Snsouchint 16938774Snsouchiicbus_generic_intr(device_t dev, int event, char *buf) 17038774Snsouch{ 17138774Snsouch return (0); 17238774Snsouch} 17338774Snsouch 17438774Snsouchstatic void 17538774Snsouchiicbus_print_child(device_t bus, device_t dev) 17638774Snsouch{ 17738774Snsouch struct iicbus_device* iicdev = DEVTOIICBUS(dev); 17838774Snsouch 17938774Snsouch switch (iicdev->iicd_class) { 18038774Snsouch case IICBUS_DEVICE_CLASS: 18138774Snsouch printf(" on %s%d addr %d %s", device_get_name(bus), 18238774Snsouch device_get_unit(bus), iicdev->iicd_addr, 18338774Snsouch (iicdev->iicd_alive) ? "found" : "not found"); 18438774Snsouch break; 18538774Snsouch 18638774Snsouch case IICBUS_DRIVER_CLASS: 18738774Snsouch printf(" on %s%d", device_get_name(bus), 18838774Snsouch device_get_unit(bus)); 18938774Snsouch break; 19038774Snsouch 19138774Snsouch default: 19238774Snsouch panic("%s: unknown class!", __FUNCTION__); 19338774Snsouch } 19438774Snsouch 19538774Snsouch return; 19638774Snsouch} 19738774Snsouch 19838774Snsouchstatic int 19938774Snsouchiicbus_read_ivar(device_t bus, device_t dev, int index, u_long* result) 20038774Snsouch{ 20138774Snsouch struct iicbus_device* iicdev = DEVTOIICBUS(dev); 20238774Snsouch 20338774Snsouch switch (index) { 20438774Snsouch case IICBUS_IVAR_ADDR: 20538774Snsouch *result = (u_long)iicdev->iicd_addr; 20638774Snsouch break; 20738774Snsouch 20838774Snsouch default: 20938774Snsouch return (ENOENT); 21038774Snsouch } 21138774Snsouch 21238774Snsouch return (0); 21338774Snsouch} 21438774Snsouch 21538774SnsouchDRIVER_MODULE(iicbus, pcf, iicbus_driver, iicbus_devclass, 0, 0); 216