void iicbus_init_frequency(device_t dev, u_int bus_freq) { struct iicbus_softc *sc = IICBUS_SOFTC(dev); /* * If a bus frequency value was passed in, use it. Otherwise initialize * it first to the standard i2c 100KHz frequency, then override that * from a hint if one exists. */ if (bus_freq > 0) sc->bus_freq = bus_freq; else { sc->bus_freq = 100000; resource_int_value(device_get_name(dev), device_get_unit(dev), "frequency", (int *)&sc->bus_freq); } /* * Set up the sysctl that allows the bus frequency to be changed. * It is flagged as a tunable so that the user can set the value in * loader(8), and that will override any other setting from any source. * The sysctl tunable/value is the one most directly controlled by the * user and thus the one that always takes precedence. */ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "frequency", CTLFLAG_RW | CTLFLAG_TUN, &sc->bus_freq, sc->bus_freq, "Bus frequency in Hz"); }
static int iicbus_detach(device_t dev) { struct iicbus_softc *sc = IICBUS_SOFTC(dev); iicbus_reset(dev, IIC_FASTEST, 0, NULL); bus_generic_detach(dev); mtx_destroy(&sc->lock); return (0); }
static int ofw_iicbus_attach(device_t dev) { struct iicbus_softc *sc = IICBUS_SOFTC(dev); struct ofw_iicbus_devinfo *dinfo; phandle_t child; pcell_t paddr; device_t childdev; uint32_t addr; sc->dev = dev; mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF); iicbus_reset(dev, IIC_FASTEST, 0, NULL); bus_generic_probe(dev); bus_enumerate_hinted_children(dev); /* * Attach those children represented in the device tree. */ for (child = OF_child(ofw_bus_get_node(dev)); child != 0; child = OF_peer(child)) { /* * Try to get the I2C address first from the i2c-address * property, then try the reg property. It moves around * on different systems. */ if (OF_getprop(child, "i2c-address", &paddr, sizeof(paddr)) == -1) if (OF_getprop(child, "reg", &paddr, sizeof(paddr)) == -1) continue; addr = fdt32_to_cpu(paddr); /* * Now set up the I2C and OFW bus layer devinfo and add it * to the bus. */ dinfo = malloc(sizeof(struct ofw_iicbus_devinfo), M_DEVBUF, M_NOWAIT | M_ZERO); if (dinfo == NULL) continue; dinfo->opd_dinfo.addr = addr; if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) != 0) { free(dinfo, M_DEVBUF); continue; } childdev = device_add_child(dev, NULL, -1); device_set_ivars(childdev, dinfo); } return (bus_generic_attach(dev)); }
static u_int iicbus_get_frequency(device_t dev, u_char speed) { struct iicbus_softc *sc = IICBUS_SOFTC(dev); /* * If the frequency has not been configured for the bus, or the request * is specifically for SLOW speed, use the standard 100KHz rate, else * use the configured bus speed. */ if (sc->bus_freq == 0 || speed == IIC_SLOW) return (100000); return (sc->bus_freq); }
/* * We add all the devices which we know about. * The generic attach routine will attach them if they are alive. */ static int iicbus_attach(device_t dev) { #if SCAN_IICBUS unsigned char addr; #endif struct iicbus_softc *sc = IICBUS_SOFTC(dev); int strict; sc->dev = dev; mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF); iicbus_init_frequency(dev, 0); iicbus_reset(dev, IIC_FASTEST, 0, NULL); if (resource_int_value(device_get_name(dev), device_get_unit(dev), "strict", &strict) == 0) sc->strict = strict; else sc->strict = 1; /* device probing is meaningless since the bus is supposed to be * hot-plug. Moreover, some I2C chips do not appreciate random * accesses like stop after start to fast, reads for less than * x bytes... */ #if SCAN_IICBUS printf("Probing for devices on iicbus%d:", device_get_unit(dev)); /* probe any devices */ for (addr = 16; addr < 240; addr++) { if (iic_probe_device(dev, (u_char)addr)) { printf(" <%x>", addr); } } printf("\n"); #endif bus_generic_probe(dev); bus_enumerate_hinted_children(dev); bus_generic_attach(dev); return (0); }
static int ofw_iicbus_attach(device_t dev) { struct iicbus_softc *sc = IICBUS_SOFTC(dev); struct ofw_iicbus_devinfo *dinfo; phandle_t child, node, root; pcell_t freq, paddr; device_t childdev; ssize_t compatlen; char compat[255]; char *curstr; u_int iic_addr_8bit = 0; sc->dev = dev; mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF); /* * If there is a clock-frequency property for the device node, use it as * the starting value for the bus frequency. Then call the common * routine that handles the tunable/sysctl which allows the FDT value to * be overridden by the user. */ node = ofw_bus_get_node(dev); freq = 0; OF_getencprop(node, "clock-frequency", &freq, sizeof(freq)); iicbus_init_frequency(dev, freq); iicbus_reset(dev, IIC_FASTEST, 0, NULL); bus_generic_probe(dev); bus_enumerate_hinted_children(dev); /* * Check if we're running on a PowerMac, needed for the I2C * address below. */ root = OF_peer(0); compatlen = OF_getprop(root, "compatible", compat, sizeof(compat)); if (compatlen != -1) { for (curstr = compat; curstr < compat + compatlen; curstr += strlen(curstr) + 1) { if (strncmp(curstr, "MacRISC", 7) == 0) iic_addr_8bit = 1; } } /* * Attach those children represented in the device tree. */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { /* * Try to get the I2C address first from the i2c-address * property, then try the reg property. It moves around * on different systems. */ if (OF_getencprop(child, "i2c-address", &paddr, sizeof(paddr)) == -1) if (OF_getencprop(child, "reg", &paddr, sizeof(paddr)) == -1) continue; /* * Now set up the I2C and OFW bus layer devinfo and add it * to the bus. */ dinfo = malloc(sizeof(struct ofw_iicbus_devinfo), M_DEVBUF, M_NOWAIT | M_ZERO); if (dinfo == NULL) continue; /* * FreeBSD drivers expect I2C addresses to be expressed as * 8-bit values. Apple OFW data contains 8-bit values, but * Linux FDT data contains 7-bit values, so shift them up to * 8-bit format. */ if (iic_addr_8bit) dinfo->opd_dinfo.addr = paddr; else dinfo->opd_dinfo.addr = paddr << 1; if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) != 0) { free(dinfo, M_DEVBUF); continue; } childdev = device_add_child(dev, NULL, -1); resource_list_init(&dinfo->opd_dinfo.rl); ofw_bus_intr_to_rl(childdev, child, &dinfo->opd_dinfo.rl, NULL); device_set_ivars(childdev, dinfo); } /* Register bus */ OF_device_register_xref(OF_xref_from_node(node), dev); return (bus_generic_attach(dev)); }
static int ofw_iicbus_attach(device_t dev) { struct iicbus_softc *sc = IICBUS_SOFTC(dev); struct ofw_iicbus_devinfo *dinfo; phandle_t child, node; pcell_t freq, paddr; device_t childdev; sc->dev = dev; mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF); /* * If there is a clock-frequency property for the device node, use it as * the starting value for the bus frequency. Then call the common * routine that handles the tunable/sysctl which allows the FDT value to * be overridden by the user. */ node = ofw_bus_get_node(dev); freq = 0; OF_getencprop(node, "clock-frequency", &freq, sizeof(freq)); iicbus_init_frequency(dev, freq); iicbus_reset(dev, IIC_FASTEST, 0, NULL); bus_generic_probe(dev); bus_enumerate_hinted_children(dev); /* * Attach those children represented in the device tree. */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { /* * Try to get the I2C address first from the i2c-address * property, then try the reg property. It moves around * on different systems. */ if (OF_getencprop(child, "i2c-address", &paddr, sizeof(paddr)) == -1) if (OF_getencprop(child, "reg", &paddr, sizeof(paddr)) == -1) continue; /* * Now set up the I2C and OFW bus layer devinfo and add it * to the bus. */ dinfo = malloc(sizeof(struct ofw_iicbus_devinfo), M_DEVBUF, M_NOWAIT | M_ZERO); if (dinfo == NULL) continue; /* * FreeBSD drivers expect I2C addresses to be expressed as * 8-bit values. Apple OFW data contains 8-bit values, but * Linux FDT data contains 7-bit values, so shift them up to * 8-bit format. */ #ifdef AIM dinfo->opd_dinfo.addr = paddr; #else dinfo->opd_dinfo.addr = paddr << 1; #endif if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) != 0) { free(dinfo, M_DEVBUF); continue; } childdev = device_add_child(dev, NULL, -1); resource_list_init(&dinfo->opd_dinfo.rl); ofw_bus_intr_to_rl(childdev, child, &dinfo->opd_dinfo.rl, NULL); device_set_ivars(childdev, dinfo); } return (bus_generic_attach(dev)); }