ofw_iicbus.c revision 266105
155714Skris/*- 255714Skris * Copyright (c) 2009, Nathan Whitehorn <nwhitehorn@FreeBSD.org> 355714Skris * All rights reserved. 455714Skris * 555714Skris * Redistribution and use in source and binary forms, with or without 655714Skris * modification, are permitted provided that the following conditions 755714Skris * are met: 8280297Sjkim * 1. Redistributions of source code must retain the above copyright 955714Skris * notice unmodified, this list of conditions, and the following 1055714Skris * disclaimer. 1155714Skris * 2. Redistributions in binary form must reproduce the above copyright 1255714Skris * notice, this list of conditions and the following disclaimer in the 1355714Skris * documentation and/or other materials provided with the distribution. 1455714Skris * 15280297Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1655714Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1755714Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1855714Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1955714Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2055714Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2155714Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22280297Sjkim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2355714Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2455714Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2555714Skris */ 2655714Skris 2755714Skris#include <sys/cdefs.h> 2855714Skris__FBSDID("$FreeBSD: stable/10/sys/dev/ofw/ofw_iicbus.c 266105 2014-05-15 01:27:53Z loos $"); 2955714Skris 3055714Skris#include <sys/param.h> 3155714Skris#include <sys/bus.h> 3255714Skris#include <sys/kernel.h> 3355714Skris#include <sys/libkern.h> 3455714Skris#include <sys/lock.h> 3555714Skris#include <sys/module.h> 3655714Skris#include <sys/mutex.h> 37280297Sjkim 3855714Skris#include <dev/iicbus/iicbus.h> 3955714Skris#include <dev/iicbus/iiconf.h> 40280297Sjkim#include <dev/ofw/ofw_bus.h> 4155714Skris#include <dev/ofw/ofw_bus_subr.h> 4255714Skris#include <dev/ofw/openfirm.h> 4355714Skris 4455714Skris#include "iicbus_if.h" 4555714Skris 4655714Skris/* Methods */ 4755714Skrisstatic device_probe_t ofw_iicbus_probe; 4855714Skrisstatic device_attach_t ofw_iicbus_attach; 4955714Skrisstatic device_t ofw_iicbus_add_child(device_t dev, u_int order, 5055714Skris const char *name, int unit); 5155714Skrisstatic const struct ofw_bus_devinfo *ofw_iicbus_get_devinfo(device_t bus, 52280297Sjkim device_t dev); 5355714Skris 5455714Skrisstatic device_method_t ofw_iicbus_methods[] = { 5555714Skris /* Device interface */ 5655714Skris DEVMETHOD(device_probe, ofw_iicbus_probe), 5755714Skris DEVMETHOD(device_attach, ofw_iicbus_attach), 5855714Skris 5955714Skris /* Bus interface */ 6055714Skris DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), 6155714Skris DEVMETHOD(bus_add_child, ofw_iicbus_add_child), 6255714Skris 6355714Skris /* ofw_bus interface */ 6455714Skris DEVMETHOD(ofw_bus_get_devinfo, ofw_iicbus_get_devinfo), 6555714Skris DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 6655714Skris DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 6755714Skris DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 6855714Skris DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 6955714Skris DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 7055714Skris 7155714Skris DEVMETHOD_END 7255714Skris}; 7355714Skris 7455714Skrisstruct ofw_iicbus_devinfo { 7555714Skris struct iicbus_ivar opd_dinfo; 7655714Skris struct ofw_bus_devinfo opd_obdinfo; 7755714Skris}; 7855714Skris 7955714Skrisstatic devclass_t ofwiicbus_devclass; 8055714Skris 8155714SkrisDEFINE_CLASS_1(iicbus, ofw_iicbus_driver, ofw_iicbus_methods, 8255714Skris sizeof(struct iicbus_softc), iicbus_driver); 8355714SkrisDRIVER_MODULE(ofw_iicbus, iicbb, ofw_iicbus_driver, ofwiicbus_devclass, 0, 0); 8455714SkrisDRIVER_MODULE(ofw_iicbus, iichb, ofw_iicbus_driver, ofwiicbus_devclass, 0, 0); 8555714SkrisMODULE_VERSION(ofw_iicbus, 1); 8655714SkrisMODULE_DEPEND(ofw_iicbus, iicbus, 1, 1, 1); 8755714Skris 8855714Skrisstatic int 8955714Skrisofw_iicbus_probe(device_t dev) 9055714Skris{ 9155714Skris 9255714Skris if (ofw_bus_get_node(dev) == -1) 9355714Skris return (ENXIO); 9455714Skris device_set_desc(dev, "OFW I2C bus"); 9555714Skris 9655714Skris return (0); 9755714Skris} 9855714Skris 9955714Skrisstatic int 10055714Skrisofw_iicbus_attach(device_t dev) 10155714Skris{ 10255714Skris struct iicbus_softc *sc = IICBUS_SOFTC(dev); 10355714Skris struct ofw_iicbus_devinfo *dinfo; 10455714Skris phandle_t child; 10555714Skris pcell_t paddr; 10655714Skris device_t childdev; 10755714Skris 10855714Skris sc->dev = dev; 10955714Skris mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF); 11055714Skris iicbus_reset(dev, IIC_FASTEST, 0, NULL); 11155714Skris 11255714Skris bus_generic_probe(dev); 11355714Skris bus_enumerate_hinted_children(dev); 11455714Skris 11555714Skris /* 11655714Skris * Attach those children represented in the device tree. 11755714Skris */ 11855714Skris for (child = OF_child(ofw_bus_get_node(dev)); child != 0; 11955714Skris child = OF_peer(child)) { 12055714Skris /* 12155714Skris * Try to get the I2C address first from the i2c-address 12255714Skris * property, then try the reg property. It moves around 12355714Skris * on different systems. 12455714Skris */ 12555714Skris if (OF_getencprop(child, "i2c-address", &paddr, 12655714Skris sizeof(paddr)) == -1) 12755714Skris if (OF_getencprop(child, "reg", &paddr, 12855714Skris sizeof(paddr)) == -1) 12955714Skris continue; 13055714Skris 13155714Skris /* 13255714Skris * Now set up the I2C and OFW bus layer devinfo and add it 13355714Skris * to the bus. 13455714Skris */ 13555714Skris dinfo = malloc(sizeof(struct ofw_iicbus_devinfo), M_DEVBUF, 13655714Skris M_NOWAIT | M_ZERO); 13755714Skris if (dinfo == NULL) 13855714Skris continue; 13955714Skris dinfo->opd_dinfo.addr = paddr; 14055714Skris if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) != 14155714Skris 0) { 14255714Skris free(dinfo, M_DEVBUF); 14355714Skris continue; 14455714Skris } 14555714Skris childdev = device_add_child(dev, NULL, -1); 14655714Skris device_set_ivars(childdev, dinfo); 14755714Skris } 14855714Skris 14955714Skris return (bus_generic_attach(dev)); 15055714Skris} 15155714Skris 15255714Skrisstatic device_t 15355714Skrisofw_iicbus_add_child(device_t dev, u_int order, const char *name, int unit) 15455714Skris{ 15555714Skris device_t child; 15655714Skris struct ofw_iicbus_devinfo *devi; 15755714Skris 15855714Skris child = device_add_child_ordered(dev, order, name, unit); 15955714Skris if (child == NULL) 16055714Skris return (child); 16155714Skris devi = malloc(sizeof(struct ofw_iicbus_devinfo), M_DEVBUF, 16255714Skris M_NOWAIT | M_ZERO); 16355714Skris if (devi == NULL) { 16455714Skris device_delete_child(dev, child); 16555714Skris return (0); 16655714Skris } 16755714Skris 16855714Skris /* 16955714Skris * NULL all the OFW-related parts of the ivars for non-OFW 17055714Skris * children. 17155714Skris */ 17255714Skris devi->opd_obdinfo.obd_node = -1; 17355714Skris devi->opd_obdinfo.obd_name = NULL; 17455714Skris devi->opd_obdinfo.obd_compat = NULL; 17555714Skris devi->opd_obdinfo.obd_type = NULL; 17655714Skris devi->opd_obdinfo.obd_model = NULL; 17755714Skris 17855714Skris device_set_ivars(child, devi); 17955714Skris 18055714Skris return (child); 18155714Skris} 18255714Skris 18355714Skrisstatic const struct ofw_bus_devinfo * 18455714Skrisofw_iicbus_get_devinfo(device_t bus, device_t dev) 18555714Skris{ 18655714Skris struct ofw_iicbus_devinfo *dinfo; 18755714Skris 18855714Skris dinfo = device_get_ivars(dev); 18955714Skris return (&dinfo->opd_obdinfo); 19055714Skris} 19155714Skris