jcs's openbsd hax
openbsd
at jcs 173 lines 4.4 kB view raw
1/* $OpenBSD: sfp.c,v 1.5 2021/10/24 17:52:27 mpi Exp $ */ 2/* 3 * Copyright (c) 2019 Patrick Wildt <patrick@blueri.se> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <sys/param.h> 19#include <sys/systm.h> 20#include <sys/kernel.h> 21#include <sys/device.h> 22#include <sys/malloc.h> 23 24#include <net/if.h> 25 26#include <machine/bus.h> 27#include <machine/fdt.h> 28 29#include <dev/i2c/i2cvar.h> 30#include <dev/ofw/openfirm.h> 31#include <dev/ofw/ofw_gpio.h> 32#include <dev/ofw/ofw_misc.h> 33 34struct sfp_softc { 35 struct device sc_dev; 36 i2c_tag_t sc_tag; 37 int sc_node; 38 39 uint32_t *sc_mod_def0_gpio; 40 int sc_mod_def0_gpio_len; 41 uint32_t *sc_tx_disable_gpio; 42 int sc_tx_disable_gpio_len; 43 44 struct sfp_device sc_sd; 45}; 46 47int sfp_match(struct device *, void *, void *); 48void sfp_attach(struct device *, struct device *, void *); 49int sfp_detach(struct device *, int); 50 51int sfp_get_gpio(struct sfp_softc *, const char *, uint32_t **); 52int sfp_gpio_enable(void *, int); 53int sfp_i2c_get_sffpage(void *, struct if_sffpage *); 54 55const struct cfattach sfp_ca = { 56 sizeof(struct sfp_softc), sfp_match, sfp_attach, sfp_detach, 57}; 58 59struct cfdriver sfp_cd = { 60 NULL, "sfp", DV_DULL 61}; 62 63int 64sfp_match(struct device *parent, void *match, void *aux) 65{ 66 struct fdt_attach_args *faa = aux; 67 68 return (OF_is_compatible(faa->fa_node, "sff,sfp") || 69 OF_is_compatible(faa->fa_node, "sff,sfp+")); 70} 71 72void 73sfp_attach(struct device *parent, struct device *self, void *aux) 74{ 75 struct sfp_softc *sc = (struct sfp_softc *)self; 76 struct fdt_attach_args *faa = aux; 77 78 sc->sc_node = faa->fa_node; 79 sc->sc_tag = i2c_byphandle(OF_getpropint(sc->sc_node, 80 "i2c-bus", 0)); 81 82 if (sc->sc_tag == NULL) { 83 printf(": can't get i2c bus\n"); 84 return; 85 } 86 87 printf("\n"); 88 89 sc->sc_mod_def0_gpio_len = 90 sfp_get_gpio(sc, "mod-def0", &sc->sc_mod_def0_gpio); 91 if (sc->sc_mod_def0_gpio) { 92 gpio_controller_config_pin(sc->sc_mod_def0_gpio, 93 GPIO_CONFIG_INPUT); 94 } 95 96 sc->sc_tx_disable_gpio_len = 97 sfp_get_gpio(sc, "tx-disable", &sc->sc_tx_disable_gpio); 98 if (sc->sc_tx_disable_gpio) { 99 gpio_controller_config_pin(sc->sc_tx_disable_gpio, 100 GPIO_CONFIG_OUTPUT); 101 } 102 103 sc->sc_sd.sd_node = faa->fa_node; 104 sc->sc_sd.sd_cookie = sc; 105 sc->sc_sd.sd_enable = sfp_gpio_enable; 106 sc->sc_sd.sd_get_sffpage = sfp_i2c_get_sffpage; 107 sfp_register(&sc->sc_sd); 108} 109 110int 111sfp_detach(struct device *self, int flags) 112{ 113 struct sfp_softc *sc = (struct sfp_softc *)self; 114 115 free(sc->sc_mod_def0_gpio, M_DEVBUF, sc->sc_mod_def0_gpio_len); 116 free(sc->sc_tx_disable_gpio, M_DEVBUF, sc->sc_tx_disable_gpio_len); 117 return 0; 118} 119 120int 121sfp_get_gpio(struct sfp_softc *sc, const char *name, uint32_t **gpio) 122{ 123 char buf[64]; 124 int len; 125 126 snprintf(buf, sizeof(buf), "%s-gpios", name); 127 len = OF_getproplen(sc->sc_node, buf); 128 if (len <= 0) { 129 snprintf(buf, sizeof(buf), "%s-gpio", name); 130 len = OF_getproplen(sc->sc_node, buf); 131 if (len <= 0) 132 return len; 133 } 134 *gpio = malloc(len, M_DEVBUF, M_WAITOK); 135 OF_getpropintarray(sc->sc_node, buf, *gpio, len); 136 return len; 137} 138 139int 140sfp_gpio_enable(void *cookie, int enable) 141{ 142 struct sfp_softc *sc = cookie; 143 144 if (sc->sc_tx_disable_gpio) { 145 gpio_controller_set_pin(sc->sc_tx_disable_gpio, !enable); 146 return 0; 147 } 148 149 return ENXIO; 150} 151 152int 153sfp_i2c_get_sffpage(void *cookie, struct if_sffpage *sff) 154{ 155 struct sfp_softc *sc = cookie; 156 uint8_t reg = sff->sff_page; 157 158 if (sc->sc_mod_def0_gpio) { 159 if (!gpio_controller_get_pin(sc->sc_mod_def0_gpio)) 160 return ENXIO; 161 } 162 163 iic_acquire_bus(sc->sc_tag, 0); 164 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 165 sff->sff_addr >> 1, &reg, sizeof(reg), 166 sff->sff_data, sizeof(sff->sff_data), 0)) { 167 printf("%s: cannot read register 0x%x\n", 168 sc->sc_dev.dv_xname, reg); 169 } 170 iic_release_bus(sc->sc_tag, 0); 171 172 return 0; 173}