138776Snsouch/*- 293023Snsouch * Copyright (c) 1998, 2001 Nicolas Souchu 338776Snsouch * All rights reserved. 438776Snsouch * 538776Snsouch * Redistribution and use in source and binary forms, with or without 638776Snsouch * modification, are permitted provided that the following conditions 738776Snsouch * are met: 838776Snsouch * 1. Redistributions of source code must retain the above copyright 938776Snsouch * notice, this list of conditions and the following disclaimer. 1038776Snsouch * 2. Redistributions in binary form must reproduce the above copyright 1138776Snsouch * notice, this list of conditions and the following disclaimer in the 1238776Snsouch * documentation and/or other materials provided with the distribution. 1338776Snsouch * 1438776Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538776Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638776Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738776Snsouch * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838776Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938776Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038776Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138776Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238776Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338776Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438776Snsouch * SUCH DAMAGE. 2538776Snsouch * 2638776Snsouch * 2738776Snsouch */ 28119419Sobrien 29119419Sobrien#include <sys/cdefs.h> 30119419Sobrien__FBSDID("$FreeBSD: stable/10/sys/dev/smbus/smbus.c 308042 2016-10-28 15:02:24Z avg $"); 3138776Snsouch#include <sys/param.h> 3238776Snsouch#include <sys/systm.h> 33162234Sjhb#include <sys/lock.h> 34308042Savg#include <sys/malloc.h> 3538776Snsouch#include <sys/module.h> 36162234Sjhb#include <sys/mutex.h> 37308042Savg#include <sys/bus.h> 3838776Snsouch 3938776Snsouch#include <dev/smbus/smbconf.h> 4038776Snsouch#include <dev/smbus/smbus.h> 4138776Snsouch 4238776Snsouch 43308042Savgstruct smbus_ivar 44308042Savg{ 45308042Savg uint8_t addr; 4638776Snsouch}; 4738776Snsouch 4838776Snsouch/* 49308042Savg * Autoconfiguration and support routines for System Management bus 5038776Snsouch */ 51308042Savg 5238776Snsouchstatic int 5338776Snsouchsmbus_probe(device_t dev) 5438776Snsouch{ 55162234Sjhb 5640785Snsouch device_set_desc(dev, "System Management Bus"); 5742129Snsouch 5840785Snsouch return (0); 5940785Snsouch} 6040785Snsouch 61153569Srustatic int 62153569Srusmbus_attach(device_t dev) 63153569Sru{ 64162234Sjhb struct smbus_softc *sc = device_get_softc(dev); 65162234Sjhb 66162234Sjhb mtx_init(&sc->lock, device_get_nameunit(dev), "smbus", MTX_DEF); 67162234Sjhb bus_generic_probe(dev); 68308042Savg bus_enumerate_hinted_children(dev); 69153569Sru bus_generic_attach(dev); 70153569Sru 71153569Sru return (0); 72153569Sru} 73153569Sru 74162234Sjhbstatic int 75162234Sjhbsmbus_detach(device_t dev) 76162234Sjhb{ 77162234Sjhb struct smbus_softc *sc = device_get_softc(dev); 78162234Sjhb int error; 79162234Sjhb 80162234Sjhb error = bus_generic_detach(dev); 81162234Sjhb if (error) 82162234Sjhb return (error); 83308042Savg device_delete_children(dev); 84162234Sjhb mtx_destroy(&sc->lock); 85162234Sjhb 86162234Sjhb return (0); 87162234Sjhb} 88162234Sjhb 8938776Snsouchvoid 90189580Simpsmbus_generic_intr(device_t dev, u_char devaddr, char low, char high, int err) 9138776Snsouch{ 9238776Snsouch} 9338776Snsouch 94308042Savgstatic device_t 95308042Savgsmbus_add_child(device_t dev, u_int order, const char *name, int unit) 96308042Savg{ 97308042Savg struct smbus_ivar *devi; 98308042Savg device_t child; 99308042Savg 100308042Savg child = device_add_child_ordered(dev, order, name, unit); 101308042Savg if (child == NULL) 102308042Savg return (child); 103308042Savg devi = malloc(sizeof(struct smbus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 104308042Savg if (devi == NULL) { 105308042Savg device_delete_child(dev, child); 106308042Savg return (NULL); 107308042Savg } 108308042Savg device_set_ivars(child, devi); 109308042Savg return (child); 110308042Savg} 111308042Savg 112308042Savgstatic void 113308042Savgsmbus_hinted_child(device_t bus, const char *dname, int dunit) 114308042Savg{ 115308042Savg struct smbus_ivar *devi; 116308042Savg device_t child; 117308042Savg int addr; 118308042Savg 119308042Savg addr = 0; 120308042Savg resource_int_value(dname, dunit, "addr", &addr); 121308042Savg if (addr > UINT8_MAX) { 122308042Savg device_printf(bus, "ignored incorrect slave address hint 0x%x" 123308042Savg " for %s%d\n", addr, dname, dunit); 124308042Savg return; 125308042Savg } 126308042Savg child = BUS_ADD_CHILD(bus, SMBUS_ORDER_HINTED, dname, dunit); 127308042Savg if (child == NULL) 128308042Savg return; 129308042Savg devi = device_get_ivars(child); 130308042Savg devi->addr = addr; 131308042Savg} 132308042Savg 133308042Savg 134308042Savgstatic int 135308042Savgsmbus_child_location_str(device_t parent, device_t child, char *buf, 136308042Savg size_t buflen) 137308042Savg{ 138308042Savg struct smbus_ivar *devi; 139308042Savg 140308042Savg devi = device_get_ivars(child); 141308042Savg if (devi->addr != 0) 142308042Savg snprintf(buf, buflen, "addr=0x%x", devi->addr); 143308042Savg else if (buflen) 144308042Savg buf[0] = 0; 145308042Savg return (0); 146308042Savg} 147308042Savg 148308042Savgstatic int 149308042Savgsmbus_print_child(device_t parent, device_t child) 150308042Savg{ 151308042Savg struct smbus_ivar *devi; 152308042Savg int retval; 153308042Savg 154308042Savg devi = device_get_ivars(child); 155308042Savg retval = bus_print_child_header(parent, child); 156308042Savg if (devi->addr != 0) 157308042Savg retval += printf(" at addr 0x%x", devi->addr); 158308042Savg retval += bus_print_child_footer(parent, child); 159308042Savg 160308042Savg return (retval); 161308042Savg} 162308042Savg 163308042Savgstatic int 164308042Savgsmbus_read_ivar(device_t parent, device_t child, int which, uintptr_t *result) 165308042Savg{ 166308042Savg struct smbus_ivar *devi; 167308042Savg 168308042Savg devi = device_get_ivars(child); 169308042Savg switch (which) { 170308042Savg case SMBUS_IVAR_ADDR: 171308042Savg if (devi->addr != 0) 172308042Savg *result = devi->addr; 173308042Savg else 174308042Savg *result = -1; 175308042Savg break; 176308042Savg default: 177308042Savg return (ENOENT); 178308042Savg } 179308042Savg return (0); 180308042Savg} 181308042Savg 182308042Savgstatic int 183308042Savgsmbus_write_ivar(device_t parent, device_t child, int which, uintptr_t value) 184308042Savg{ 185308042Savg struct smbus_ivar *devi; 186308042Savg 187308042Savg devi = device_get_ivars(child); 188308042Savg switch (which) { 189308042Savg case SMBUS_IVAR_ADDR: 190308042Savg /* Allow to set but no change the slave address. */ 191308042Savg if (devi->addr != 0) 192308042Savg return (EINVAL); 193308042Savg devi->addr = value; 194308042Savg break; 195308042Savg default: 196308042Savg return (ENOENT); 197308042Savg } 198308042Savg return (0); 199308042Savg} 200308042Savg 201308042Savgstatic void 202308042Savgsmbus_probe_nomatch(device_t bus, device_t child) 203308042Savg{ 204308042Savg struct smbus_ivar *devi = device_get_ivars(child); 205308042Savg 206308042Savg /* 207308042Savg * Ignore (self-identified) devices without a slave address set. 208308042Savg * For example, smb(4). 209308042Savg */ 210308042Savg if (devi->addr != 0) 211308042Savg device_printf(bus, "<unknown device> at addr %#x\n", 212308042Savg devi->addr); 213308042Savg} 214308042Savg 215308042Savg/* 216308042Savg * Device methods 217308042Savg */ 218308042Savgstatic device_method_t smbus_methods[] = { 219308042Savg /* device interface */ 220308042Savg DEVMETHOD(device_probe, smbus_probe), 221308042Savg DEVMETHOD(device_attach, smbus_attach), 222308042Savg DEVMETHOD(device_detach, smbus_detach), 223308042Savg 224308042Savg /* bus interface */ 225308042Savg DEVMETHOD(bus_add_child, smbus_add_child), 226308042Savg DEVMETHOD(bus_hinted_child, smbus_hinted_child), 227308042Savg DEVMETHOD(bus_probe_nomatch, smbus_probe_nomatch), 228308042Savg DEVMETHOD(bus_child_location_str, smbus_child_location_str), 229308042Savg DEVMETHOD(bus_print_child, smbus_print_child), 230308042Savg DEVMETHOD(bus_read_ivar, smbus_read_ivar), 231308042Savg DEVMETHOD(bus_write_ivar, smbus_write_ivar), 232308042Savg 233308042Savg DEVMETHOD_END 234308042Savg}; 235308042Savg 236308042Savgdriver_t smbus_driver = { 237308042Savg "smbus", 238308042Savg smbus_methods, 239308042Savg sizeof(struct smbus_softc), 240308042Savg}; 241308042Savg 242308042Savgdevclass_t smbus_devclass; 243308042Savg 24493023SnsouchMODULE_VERSION(smbus, SMBUS_MODVER); 245