1*9fdf0c62Smpi /* $OpenBSD: sfp.c,v 1.5 2021/10/24 17:52:27 mpi Exp $ */
252f72a97Spatrick /*
352f72a97Spatrick * Copyright (c) 2019 Patrick Wildt <patrick@blueri.se>
452f72a97Spatrick *
552f72a97Spatrick * Permission to use, copy, modify, and distribute this software for any
652f72a97Spatrick * purpose with or without fee is hereby granted, provided that the above
752f72a97Spatrick * copyright notice and this permission notice appear in all copies.
852f72a97Spatrick *
952f72a97Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1052f72a97Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1152f72a97Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1252f72a97Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1352f72a97Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1452f72a97Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1552f72a97Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1652f72a97Spatrick */
1752f72a97Spatrick
1852f72a97Spatrick #include <sys/param.h>
1952f72a97Spatrick #include <sys/systm.h>
2052f72a97Spatrick #include <sys/kernel.h>
2152f72a97Spatrick #include <sys/device.h>
223683447aSkettenis #include <sys/malloc.h>
2352f72a97Spatrick
2452f72a97Spatrick #include <net/if.h>
2552f72a97Spatrick
2652f72a97Spatrick #include <machine/bus.h>
2752f72a97Spatrick #include <machine/fdt.h>
2852f72a97Spatrick
2952f72a97Spatrick #include <dev/i2c/i2cvar.h>
3052f72a97Spatrick #include <dev/ofw/openfirm.h>
3152f72a97Spatrick #include <dev/ofw/ofw_gpio.h>
3252f72a97Spatrick #include <dev/ofw/ofw_misc.h>
3352f72a97Spatrick
3452f72a97Spatrick struct sfp_softc {
3552f72a97Spatrick struct device sc_dev;
3652f72a97Spatrick i2c_tag_t sc_tag;
3752f72a97Spatrick int sc_node;
3852f72a97Spatrick
393683447aSkettenis uint32_t *sc_mod_def0_gpio;
403683447aSkettenis int sc_mod_def0_gpio_len;
419e963265Skettenis uint32_t *sc_tx_disable_gpio;
429e963265Skettenis int sc_tx_disable_gpio_len;
433683447aSkettenis
4452f72a97Spatrick struct sfp_device sc_sd;
4552f72a97Spatrick };
4652f72a97Spatrick
4752f72a97Spatrick int sfp_match(struct device *, void *, void *);
4852f72a97Spatrick void sfp_attach(struct device *, struct device *, void *);
4952f72a97Spatrick int sfp_detach(struct device *, int);
5052f72a97Spatrick
513683447aSkettenis int sfp_get_gpio(struct sfp_softc *, const char *, uint32_t **);
529e963265Skettenis int sfp_gpio_enable(void *, int);
5352f72a97Spatrick int sfp_i2c_get_sffpage(void *, struct if_sffpage *);
5452f72a97Spatrick
55*9fdf0c62Smpi const struct cfattach sfp_ca = {
5652f72a97Spatrick sizeof(struct sfp_softc), sfp_match, sfp_attach, sfp_detach,
5752f72a97Spatrick };
5852f72a97Spatrick
5952f72a97Spatrick struct cfdriver sfp_cd = {
6052f72a97Spatrick NULL, "sfp", DV_DULL
6152f72a97Spatrick };
6252f72a97Spatrick
6352f72a97Spatrick int
sfp_match(struct device * parent,void * match,void * aux)6452f72a97Spatrick sfp_match(struct device *parent, void *match, void *aux)
6552f72a97Spatrick {
6652f72a97Spatrick struct fdt_attach_args *faa = aux;
6752f72a97Spatrick
6852f72a97Spatrick return (OF_is_compatible(faa->fa_node, "sff,sfp") ||
6952f72a97Spatrick OF_is_compatible(faa->fa_node, "sff,sfp+"));
7052f72a97Spatrick }
7152f72a97Spatrick
7252f72a97Spatrick void
sfp_attach(struct device * parent,struct device * self,void * aux)7352f72a97Spatrick sfp_attach(struct device *parent, struct device *self, void *aux)
7452f72a97Spatrick {
7552f72a97Spatrick struct sfp_softc *sc = (struct sfp_softc *)self;
7652f72a97Spatrick struct fdt_attach_args *faa = aux;
7752f72a97Spatrick
7852f72a97Spatrick sc->sc_node = faa->fa_node;
7952f72a97Spatrick sc->sc_tag = i2c_byphandle(OF_getpropint(sc->sc_node,
8052f72a97Spatrick "i2c-bus", 0));
8152f72a97Spatrick
8252f72a97Spatrick if (sc->sc_tag == NULL) {
8352f72a97Spatrick printf(": can't get i2c bus\n");
8452f72a97Spatrick return;
8552f72a97Spatrick }
8652f72a97Spatrick
8752f72a97Spatrick printf("\n");
8852f72a97Spatrick
893683447aSkettenis sc->sc_mod_def0_gpio_len =
903683447aSkettenis sfp_get_gpio(sc, "mod-def0", &sc->sc_mod_def0_gpio);
913683447aSkettenis if (sc->sc_mod_def0_gpio) {
923683447aSkettenis gpio_controller_config_pin(sc->sc_mod_def0_gpio,
933683447aSkettenis GPIO_CONFIG_INPUT);
943683447aSkettenis }
953683447aSkettenis
969e963265Skettenis sc->sc_tx_disable_gpio_len =
979e963265Skettenis sfp_get_gpio(sc, "tx-disable", &sc->sc_tx_disable_gpio);
989e963265Skettenis if (sc->sc_tx_disable_gpio) {
999e963265Skettenis gpio_controller_config_pin(sc->sc_tx_disable_gpio,
1009e963265Skettenis GPIO_CONFIG_OUTPUT);
1019e963265Skettenis }
1029e963265Skettenis
10352f72a97Spatrick sc->sc_sd.sd_node = faa->fa_node;
10452f72a97Spatrick sc->sc_sd.sd_cookie = sc;
1059e963265Skettenis sc->sc_sd.sd_enable = sfp_gpio_enable;
10652f72a97Spatrick sc->sc_sd.sd_get_sffpage = sfp_i2c_get_sffpage;
10752f72a97Spatrick sfp_register(&sc->sc_sd);
10852f72a97Spatrick }
10952f72a97Spatrick
11052f72a97Spatrick int
sfp_detach(struct device * self,int flags)11152f72a97Spatrick sfp_detach(struct device *self, int flags)
11252f72a97Spatrick {
1133683447aSkettenis struct sfp_softc *sc = (struct sfp_softc *)self;
1143683447aSkettenis
1153683447aSkettenis free(sc->sc_mod_def0_gpio, M_DEVBUF, sc->sc_mod_def0_gpio_len);
1169e963265Skettenis free(sc->sc_tx_disable_gpio, M_DEVBUF, sc->sc_tx_disable_gpio_len);
11752f72a97Spatrick return 0;
11852f72a97Spatrick }
11952f72a97Spatrick
12052f72a97Spatrick int
sfp_get_gpio(struct sfp_softc * sc,const char * name,uint32_t ** gpio)1213683447aSkettenis sfp_get_gpio(struct sfp_softc *sc, const char *name, uint32_t **gpio)
1223683447aSkettenis {
1233683447aSkettenis char buf[64];
1243683447aSkettenis int len;
1253683447aSkettenis
1263683447aSkettenis snprintf(buf, sizeof(buf), "%s-gpios", name);
1273683447aSkettenis len = OF_getproplen(sc->sc_node, buf);
1283683447aSkettenis if (len <= 0) {
1293683447aSkettenis snprintf(buf, sizeof(buf), "%s-gpio", name);
1303683447aSkettenis len = OF_getproplen(sc->sc_node, buf);
1313683447aSkettenis if (len <= 0)
1323683447aSkettenis return len;
1333683447aSkettenis }
1343683447aSkettenis *gpio = malloc(len, M_DEVBUF, M_WAITOK);
1353683447aSkettenis OF_getpropintarray(sc->sc_node, buf, *gpio, len);
1363683447aSkettenis return len;
1373683447aSkettenis }
1383683447aSkettenis
1393683447aSkettenis int
sfp_gpio_enable(void * cookie,int enable)1409e963265Skettenis sfp_gpio_enable(void *cookie, int enable)
1419e963265Skettenis {
1429e963265Skettenis struct sfp_softc *sc = cookie;
1439e963265Skettenis
1449e963265Skettenis if (sc->sc_tx_disable_gpio) {
1459e963265Skettenis gpio_controller_set_pin(sc->sc_tx_disable_gpio, !enable);
1469e963265Skettenis return 0;
1479e963265Skettenis }
1489e963265Skettenis
1499e963265Skettenis return ENXIO;
1509e963265Skettenis }
1519e963265Skettenis
1529e963265Skettenis int
sfp_i2c_get_sffpage(void * cookie,struct if_sffpage * sff)15352f72a97Spatrick sfp_i2c_get_sffpage(void *cookie, struct if_sffpage *sff)
15452f72a97Spatrick {
15552f72a97Spatrick struct sfp_softc *sc = cookie;
15652f72a97Spatrick uint8_t reg = sff->sff_page;
15752f72a97Spatrick
158d2421f12Skettenis if (sc->sc_mod_def0_gpio) {
1593683447aSkettenis if (!gpio_controller_get_pin(sc->sc_mod_def0_gpio))
1603683447aSkettenis return ENXIO;
1613683447aSkettenis }
1623683447aSkettenis
16352f72a97Spatrick iic_acquire_bus(sc->sc_tag, 0);
16452f72a97Spatrick if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
16552f72a97Spatrick sff->sff_addr >> 1, ®, sizeof(reg),
16652f72a97Spatrick sff->sff_data, sizeof(sff->sff_data), 0)) {
16752f72a97Spatrick printf("%s: cannot read register 0x%x\n",
16852f72a97Spatrick sc->sc_dev.dv_xname, reg);
16952f72a97Spatrick }
17052f72a97Spatrick iic_release_bus(sc->sc_tag, 0);
17152f72a97Spatrick
17252f72a97Spatrick return 0;
17352f72a97Spatrick }
174