2 * Copyright (c) 2016 Hiroki Mori
3 * Copyright (c) 2013 Luiz Otavio O Souza.
4 * Copyright (c) 2011-2012 Stefan Bethke.
5 * Copyright (c) 2012 Adrian Chadd.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * This is Infineon ADM6996FC/M/MX driver code on etherswitch framework.
34 * Support PORT and DOT1Q VLAN.
35 * This code suppose ADM6996FC SDC/SDIO connect to SOC network interface
37 * This code development on Netgear WGR614Cv7.
38 * etherswitchcfg command port option support addtag.
41 #include <sys/param.h>
43 #include <sys/errno.h>
44 #include <sys/kernel.h>
46 #include <sys/malloc.h>
47 #include <sys/module.h>
48 #include <sys/mutex.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
51 #include <sys/sysctl.h>
52 #include <sys/systm.h>
55 #include <net/if_var.h>
56 #include <net/ethernet.h>
57 #include <net/if_media.h>
58 #include <net/if_types.h>
60 #include <machine/bus.h>
61 #include <dev/mii/mii.h>
62 #include <dev/mii/miivar.h>
63 #include <dev/mdio/mdio.h>
65 #include <dev/etherswitch/etherswitch.h>
68 #include "miibus_if.h"
69 #include "etherswitch_if.h"
71 #define ADM6996FC_PRODUCT_CODE 0x7102
73 #define ADM6996FC_SC3 0x11
74 #define ADM6996FC_VF0L 0x40
75 #define ADM6996FC_VF0H 0x41
76 #define ADM6996FC_CI0 0xa0
77 #define ADM6996FC_CI1 0xa1
78 #define ADM6996FC_PHY_C0 0x200
80 #define ADM6996FC_PC_SHIFT 4
81 #define ADM6996FC_TBV_SHIFT 5
82 #define ADM6996FC_PVID_SHIFT 10
83 #define ADM6996FC_OPTE_SHIFT 4
84 #define ADM6996FC_VV_SHIFT 15
86 #define ADM6996FC_PHY_SIZE 0x20
88 MALLOC_DECLARE(M_ADM6996FC);
89 MALLOC_DEFINE(M_ADM6996FC, "adm6996fc", "adm6996fc data structures");
91 struct adm6996fc_softc {
92 struct mtx sc_mtx; /* serialize access to softc */
95 int media; /* cpu port media */
96 int cpuport; /* which PHY is connected to the CPU */
97 int phymask; /* PHYs we manage */
98 int numports; /* number of ports */
99 int ifpport[MII_NPHY];
104 struct callout callout_tick;
105 etherswitch_info_t info;
108 #define ADM6996FC_LOCK(_sc) \
109 mtx_lock(&(_sc)->sc_mtx)
110 #define ADM6996FC_UNLOCK(_sc) \
111 mtx_unlock(&(_sc)->sc_mtx)
112 #define ADM6996FC_LOCK_ASSERT(_sc, _what) \
113 mtx_assert(&(_sc)->sc_mtx, (_what))
114 #define ADM6996FC_TRYLOCK(_sc) \
115 mtx_trylock(&(_sc)->sc_mtx)
118 #define DPRINTF(dev, args...) device_printf(dev, args)
120 #define DPRINTF(dev, args...)
123 static inline int adm6996fc_portforphy(struct adm6996fc_softc *, int);
124 static void adm6996fc_tick(void *);
125 static int adm6996fc_ifmedia_upd(struct ifnet *);
126 static void adm6996fc_ifmedia_sts(struct ifnet *, struct ifmediareq *);
128 #define ADM6996FC_READREG(dev, x) \
129 MDIO_READREG(dev, ((x) >> 5), ((x) & 0x1f));
130 #define ADM6996FC_WRITEREG(dev, x, v) \
131 MDIO_WRITEREG(dev, ((x) >> 5), ((x) & 0x1f), v);
133 #define ADM6996FC_PVIDBYDATA(data1, data2) \
134 ((((data1) >> ADM6996FC_PVID_SHIFT) & 0x0f) | ((data2) << 4))
137 adm6996fc_probe(device_t dev)
141 struct adm6996fc_softc *sc;
143 sc = device_get_softc(dev);
144 bzero(sc, sizeof(*sc));
146 data1 = ADM6996FC_READREG(device_get_parent(dev), ADM6996FC_CI0);
147 data2 = ADM6996FC_READREG(device_get_parent(dev), ADM6996FC_CI1);
148 pc = ((data2 << 16) | data1) >> ADM6996FC_PC_SHIFT;
150 device_printf(dev,"Chip Identifier Register %x %x\n", data1,
153 /* check Product Code */
154 if (pc != ADM6996FC_PRODUCT_CODE) {
158 device_set_desc_copy(dev, "Infineon ADM6996FC/M/MX MDIO switch driver");
159 return (BUS_PROBE_DEFAULT);
163 adm6996fc_attach_phys(struct adm6996fc_softc *sc)
170 /* PHYs need an interface, so we generate a dummy one */
171 snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev));
172 for (phy = 0; phy < sc->numports; phy++) {
173 if (((1 << phy) & sc->phymask) == 0)
175 sc->ifpport[phy] = port;
176 sc->portphy[port] = phy;
177 sc->ifp[port] = if_alloc(IFT_ETHER);
178 if (sc->ifp[port] == NULL) {
179 device_printf(sc->sc_dev, "couldn't allocate ifnet structure\n");
184 sc->ifp[port]->if_softc = sc;
185 sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST |
186 IFF_DRV_RUNNING | IFF_SIMPLEX;
187 if_initname(sc->ifp[port], name, port);
188 sc->miibus[port] = malloc(sizeof(device_t), M_ADM6996FC,
190 if (sc->miibus[port] == NULL) {
194 err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port],
195 adm6996fc_ifmedia_upd, adm6996fc_ifmedia_sts, \
196 BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
197 DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n",
198 device_get_nameunit(*sc->miibus[port]),
199 sc->ifp[port]->if_xname);
201 device_printf(sc->sc_dev,
202 "attaching PHY %d failed\n",
208 sc->info.es_nports = port;
209 if (sc->cpuport != -1) {
210 /* assume cpuport is last one */
211 sc->ifpport[sc->cpuport] = port;
212 sc->portphy[port] = sc->cpuport;
213 ++sc->info.es_nports;
218 for (phy = 0; phy < sc->numports; phy++) {
219 if (((1 << phy) & sc->phymask) == 0)
221 port = adm6996fc_portforphy(sc, phy);
222 if (sc->miibus[port] != NULL)
223 device_delete_child(sc->sc_dev, (*sc->miibus[port]));
224 if (sc->ifp[port] != NULL)
225 if_free(sc->ifp[port]);
226 if (sc->ifname[port] != NULL)
227 free(sc->ifname[port], M_ADM6996FC);
228 if (sc->miibus[port] != NULL)
229 free(sc->miibus[port], M_ADM6996FC);
235 adm6996fc_attach(device_t dev)
237 struct adm6996fc_softc *sc;
241 sc = device_get_softc(dev);
244 mtx_init(&sc->sc_mtx, "adm6996fc", NULL, MTX_DEF);
245 strlcpy(sc->info.es_name, device_get_desc(dev),
246 sizeof(sc->info.es_name));
248 /* ADM6996FC Defaults */
254 sc->info.es_nvlangroups = 16;
255 sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT | ETHERSWITCH_VLAN_DOT1Q;
257 sc->ifp = malloc(sizeof(struct ifnet *) * sc->numports, M_ADM6996FC,
259 sc->ifname = malloc(sizeof(char *) * sc->numports, M_ADM6996FC,
261 sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_ADM6996FC,
263 sc->portphy = malloc(sizeof(int) * sc->numports, M_ADM6996FC,
266 if (sc->ifp == NULL || sc->ifname == NULL || sc->miibus == NULL ||
267 sc->portphy == NULL) {
273 * Attach the PHYs and complete the bus enumeration.
275 err = adm6996fc_attach_phys(sc);
279 bus_generic_probe(dev);
280 bus_enumerate_hinted_children(dev);
281 err = bus_generic_attach(dev);
285 callout_init(&sc->callout_tick, 0);
292 if (sc->portphy != NULL)
293 free(sc->portphy, M_ADM6996FC);
294 if (sc->miibus != NULL)
295 free(sc->miibus, M_ADM6996FC);
296 if (sc->ifname != NULL)
297 free(sc->ifname, M_ADM6996FC);
299 free(sc->ifp, M_ADM6996FC);
305 adm6996fc_detach(device_t dev)
307 struct adm6996fc_softc *sc;
310 sc = device_get_softc(dev);
312 callout_drain(&sc->callout_tick);
314 for (i = 0; i < MII_NPHY; i++) {
315 if (((1 << i) & sc->phymask) == 0)
317 port = adm6996fc_portforphy(sc, i);
318 if (sc->miibus[port] != NULL)
319 device_delete_child(dev, (*sc->miibus[port]));
320 if (sc->ifp[port] != NULL)
321 if_free(sc->ifp[port]);
322 free(sc->ifname[port], M_ADM6996FC);
323 free(sc->miibus[port], M_ADM6996FC);
326 free(sc->portphy, M_ADM6996FC);
327 free(sc->miibus, M_ADM6996FC);
328 free(sc->ifname, M_ADM6996FC);
329 free(sc->ifp, M_ADM6996FC);
331 bus_generic_detach(dev);
332 mtx_destroy(&sc->sc_mtx);
338 * Convert PHY number to port number.
341 adm6996fc_portforphy(struct adm6996fc_softc *sc, int phy)
344 return (sc->ifpport[phy]);
347 static inline struct mii_data *
348 adm6996fc_miiforport(struct adm6996fc_softc *sc, int port)
351 if (port < 0 || port > sc->numports)
353 if (port == sc->cpuport)
355 return (device_get_softc(*sc->miibus[port]));
358 static inline struct ifnet *
359 adm6996fc_ifpforport(struct adm6996fc_softc *sc, int port)
362 if (port < 0 || port > sc->numports)
364 return (sc->ifp[port]);
368 * Poll the status for all PHYs.
371 adm6996fc_miipollstat(struct adm6996fc_softc *sc)
374 struct mii_data *mii;
375 struct mii_softc *miisc;
377 ADM6996FC_LOCK_ASSERT(sc, MA_NOTOWNED);
379 for (i = 0; i < MII_NPHY; i++) {
380 if (((1 << i) & sc->phymask) == 0)
382 port = adm6996fc_portforphy(sc, i);
383 if ((*sc->miibus[port]) == NULL)
385 mii = device_get_softc(*sc->miibus[port]);
386 LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
387 if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) !=
391 mii_phy_update(miisc, MII_POLLSTAT);
397 adm6996fc_tick(void *arg)
399 struct adm6996fc_softc *sc;
403 adm6996fc_miipollstat(sc);
404 callout_reset(&sc->callout_tick, hz, adm6996fc_tick, sc);
408 adm6996fc_lock(device_t dev)
410 struct adm6996fc_softc *sc;
412 sc = device_get_softc(dev);
414 ADM6996FC_LOCK_ASSERT(sc, MA_NOTOWNED);
419 adm6996fc_unlock(device_t dev)
421 struct adm6996fc_softc *sc;
423 sc = device_get_softc(dev);
425 ADM6996FC_LOCK_ASSERT(sc, MA_OWNED);
426 ADM6996FC_UNLOCK(sc);
429 static etherswitch_info_t *
430 adm6996fc_getinfo(device_t dev)
432 struct adm6996fc_softc *sc;
434 sc = device_get_softc(dev);
440 adm6996fc_getport(device_t dev, etherswitch_port_t *p)
442 struct adm6996fc_softc *sc;
443 struct mii_data *mii;
444 struct ifmediareq *ifmr;
449 int bcaddr[6] = {0x01, 0x03, 0x05, 0x07, 0x08, 0x09};
450 int vidaddr[6] = {0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c};
452 sc = device_get_softc(dev);
455 if (p->es_port < 0 || p->es_port >= sc->numports)
458 parent = device_get_parent(dev);
460 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
461 data1 = ADM6996FC_READREG(parent, bcaddr[p->es_port]);
462 data2 = ADM6996FC_READREG(parent, vidaddr[p->es_port]);
463 /* only port 4 is hi bit */
465 data2 = (data2 >> 8) & 0xff;
467 data2 = data2 & 0xff;
469 p->es_pvid = ADM6996FC_PVIDBYDATA(data1, data2);
470 if (((data1 >> ADM6996FC_OPTE_SHIFT) & 0x01) == 1)
471 p->es_flags |= ETHERSWITCH_PORT_ADDTAG;
476 phy = sc->portphy[p->es_port];
477 mii = adm6996fc_miiforport(sc, p->es_port);
478 if (sc->cpuport != -1 && phy == sc->cpuport) {
479 /* fill in fixed values for CPU port */
480 p->es_flags |= ETHERSWITCH_PORT_CPU;
482 if (sc->media == 100)
483 ifmr->ifm_current = ifmr->ifm_active =
484 IFM_ETHER | IFM_100_TX | IFM_FDX;
486 ifmr->ifm_current = ifmr->ifm_active =
487 IFM_ETHER | IFM_1000_T | IFM_FDX;
489 ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
490 } else if (mii != NULL) {
491 err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
492 &mii->mii_media, SIOCGIFMEDIA);
502 adm6996fc_setport(device_t dev, etherswitch_port_t *p)
504 struct adm6996fc_softc *sc;
506 struct mii_data *mii;
512 int bcaddr[6] = {0x01, 0x03, 0x05, 0x07, 0x08, 0x09};
513 int vidaddr[6] = {0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c};
515 sc = device_get_softc(dev);
516 parent = device_get_parent(dev);
518 if (p->es_port < 0 || p->es_port >= sc->numports)
521 if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
522 data = ADM6996FC_READREG(parent, bcaddr[p->es_port]);
523 data &= ~(0xf << 10);
524 data |= (p->es_pvid & 0xf) << ADM6996FC_PVID_SHIFT;
525 if (p->es_flags & ETHERSWITCH_PORT_ADDTAG)
526 data |= 1 << ADM6996FC_OPTE_SHIFT;
528 data &= ~(1 << ADM6996FC_OPTE_SHIFT);
529 ADM6996FC_WRITEREG(parent, bcaddr[p->es_port], data);
530 data = ADM6996FC_READREG(parent, vidaddr[p->es_port]);
531 /* only port 4 is hi bit */
532 if (p->es_port == 4) {
533 data &= ~(0xff << 8);
534 data = data | (((p->es_pvid >> 4) & 0xff) << 8);
537 data = data | ((p->es_pvid >> 4) & 0xff);
539 ADM6996FC_WRITEREG(parent, vidaddr[p->es_port], data);
542 if (sc->portphy[p->es_port] == sc->cpuport)
546 if (sc->portphy[p->es_port] != sc->cpuport) {
547 mii = adm6996fc_miiforport(sc, p->es_port);
551 ifp = adm6996fc_ifpforport(sc, p->es_port);
553 ifm = &mii->mii_media;
554 err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA);
560 adm6996fc_getvgroup(device_t dev, etherswitch_vlangroup_t *vg)
562 struct adm6996fc_softc *sc;
566 sc = device_get_softc(dev);
567 parent = device_get_parent(dev);
569 if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
570 if (vg->es_vlangroup <= 5) {
571 vg->es_vid = ETHERSWITCH_VID_VALID;
572 vg->es_vid |= vg->es_vlangroup;
573 datalo = ADM6996FC_READREG(parent,
574 ADM6996FC_VF0L + 2 * vg->es_vlangroup);
575 datahi = ADM6996FC_READREG(parent,
576 ADM6996FC_VF0H + 2 * vg->es_vlangroup);
578 vg->es_member_ports = datalo & 0x3f;
579 vg->es_untagged_ports = vg->es_member_ports;
584 } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
585 datalo = ADM6996FC_READREG(parent,
586 ADM6996FC_VF0L + 2 * vg->es_vlangroup);
587 datahi = ADM6996FC_READREG(parent,
588 ADM6996FC_VF0H + 2 * vg->es_vlangroup);
590 if (datahi & (1 << ADM6996FC_VV_SHIFT)) {
591 vg->es_vid = ETHERSWITCH_VID_VALID;
592 vg->es_vid |= datahi & 0xfff;
593 vg->es_member_ports = datalo & 0x3f;
594 vg->es_untagged_ports = (~datalo >> 6) & 0x3f;
607 adm6996fc_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
609 struct adm6996fc_softc *sc;
612 sc = device_get_softc(dev);
613 parent = device_get_parent(dev);
615 if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
616 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0L + 2 * vg->es_vlangroup,
617 vg->es_member_ports);
618 } else if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
619 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0L + 2 * vg->es_vlangroup,
620 vg->es_member_ports | ((~vg->es_untagged_ports & 0x3f)<< 6));
621 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0H + 2 * vg->es_vlangroup,
622 (1 << ADM6996FC_VV_SHIFT) | vg->es_vid);
629 adm6996fc_getconf(device_t dev, etherswitch_conf_t *conf)
631 struct adm6996fc_softc *sc;
633 sc = device_get_softc(dev);
635 /* Return the VLAN mode. */
636 conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
637 conf->vlan_mode = sc->vlan_mode;
643 adm6996fc_setconf(device_t dev, etherswitch_conf_t *conf)
645 struct adm6996fc_softc *sc;
649 int bcaddr[6] = {0x01, 0x03, 0x05, 0x07, 0x08, 0x09};
651 sc = device_get_softc(dev);
652 parent = device_get_parent(dev);
654 if ((conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) == 0)
657 if (conf->vlan_mode == ETHERSWITCH_VLAN_PORT) {
658 sc->vlan_mode = ETHERSWITCH_VLAN_PORT;
659 data = ADM6996FC_READREG(parent, ADM6996FC_SC3);
660 data &= ~(1 << ADM6996FC_TBV_SHIFT);
661 ADM6996FC_WRITEREG(parent, ADM6996FC_SC3, data);
662 for (i = 0;i <= 5; ++i) {
663 data = ADM6996FC_READREG(parent, bcaddr[i]);
664 data &= ~(0xf << 10);
666 ADM6996FC_WRITEREG(parent, bcaddr[i], data);
667 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0L + 2 * i,
669 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0H + 2 * i,
670 (1 << ADM6996FC_VV_SHIFT) | 1);
672 } else if (conf->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) {
673 sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q;
674 data = ADM6996FC_READREG(parent, ADM6996FC_SC3);
675 data |= (1 << ADM6996FC_TBV_SHIFT);
676 ADM6996FC_WRITEREG(parent, ADM6996FC_SC3, data);
677 for (i = 0;i <= 5; ++i) {
678 data = ADM6996FC_READREG(parent, bcaddr[i]);
679 /* Private VID set 1 */
680 data &= ~(0xf << 10);
682 ADM6996FC_WRITEREG(parent, bcaddr[i], data);
684 for (i = 2;i <= 15; ++i) {
685 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0H + 2 * i,
690 ADM6996FC have no VLAN off. Then set Port base and
691 add all port to member. Use VLAN Filter 1 is reset
695 data = ADM6996FC_READREG(parent, ADM6996FC_SC3);
696 data &= ~(1 << ADM6996FC_TBV_SHIFT);
697 ADM6996FC_WRITEREG(parent, ADM6996FC_SC3, data);
698 for (i = 0;i <= 5; ++i) {
699 data = ADM6996FC_READREG(parent, bcaddr[i]);
700 data &= ~(0xf << 10);
704 ADM6996FC_WRITEREG(parent, bcaddr[i], data);
706 /* default setting */
707 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0L + 2, 0x003f);
708 ADM6996FC_WRITEREG(parent, ADM6996FC_VF0H + 2,
709 (1 << ADM6996FC_VV_SHIFT) | 1);
717 adm6996fc_statchg(device_t dev)
720 DPRINTF(dev, "%s\n", __func__);
724 adm6996fc_ifmedia_upd(struct ifnet *ifp)
726 struct adm6996fc_softc *sc;
727 struct mii_data *mii;
730 mii = adm6996fc_miiforport(sc, ifp->if_dunit);
732 DPRINTF(sc->sc_dev, "%s\n", __func__);
740 adm6996fc_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
742 struct adm6996fc_softc *sc;
743 struct mii_data *mii;
746 mii = adm6996fc_miiforport(sc, ifp->if_dunit);
748 DPRINTF(sc->sc_dev, "%s\n", __func__);
753 ifmr->ifm_active = mii->mii_media_active;
754 ifmr->ifm_status = mii->mii_media_status;
758 adm6996fc_readphy(device_t dev, int phy, int reg)
760 struct adm6996fc_softc *sc;
763 sc = device_get_softc(dev);
764 ADM6996FC_LOCK_ASSERT(sc, MA_NOTOWNED);
766 if (phy < 0 || phy >= 32)
768 if (reg < 0 || reg >= 32)
772 data = ADM6996FC_READREG(device_get_parent(dev),
773 (ADM6996FC_PHY_C0 + ADM6996FC_PHY_SIZE * phy) + reg);
774 ADM6996FC_UNLOCK(sc);
780 adm6996fc_writephy(device_t dev, int phy, int reg, int data)
782 struct adm6996fc_softc *sc;
785 sc = device_get_softc(dev);
786 ADM6996FC_LOCK_ASSERT(sc, MA_NOTOWNED);
788 if (phy < 0 || phy >= 32)
790 if (reg < 0 || reg >= 32)
794 err = ADM6996FC_WRITEREG(device_get_parent(dev),
795 (ADM6996FC_PHY_C0 + ADM6996FC_PHY_SIZE * phy) + reg, data);
796 ADM6996FC_UNLOCK(sc);
802 adm6996fc_readreg(device_t dev, int addr)
805 return ADM6996FC_READREG(device_get_parent(dev), addr);
809 adm6996fc_writereg(device_t dev, int addr, int value)
813 err = ADM6996FC_WRITEREG(device_get_parent(dev), addr, value);
817 static device_method_t adm6996fc_methods[] = {
818 /* Device interface */
819 DEVMETHOD(device_probe, adm6996fc_probe),
820 DEVMETHOD(device_attach, adm6996fc_attach),
821 DEVMETHOD(device_detach, adm6996fc_detach),
824 DEVMETHOD(bus_add_child, device_add_child_ordered),
827 DEVMETHOD(miibus_readreg, adm6996fc_readphy),
828 DEVMETHOD(miibus_writereg, adm6996fc_writephy),
829 DEVMETHOD(miibus_statchg, adm6996fc_statchg),
832 DEVMETHOD(mdio_readreg, adm6996fc_readphy),
833 DEVMETHOD(mdio_writereg, adm6996fc_writephy),
835 /* etherswitch interface */
836 DEVMETHOD(etherswitch_lock, adm6996fc_lock),
837 DEVMETHOD(etherswitch_unlock, adm6996fc_unlock),
838 DEVMETHOD(etherswitch_getinfo, adm6996fc_getinfo),
839 DEVMETHOD(etherswitch_readreg, adm6996fc_readreg),
840 DEVMETHOD(etherswitch_writereg, adm6996fc_writereg),
841 DEVMETHOD(etherswitch_readphyreg, adm6996fc_readphy),
842 DEVMETHOD(etherswitch_writephyreg, adm6996fc_writephy),
843 DEVMETHOD(etherswitch_getport, adm6996fc_getport),
844 DEVMETHOD(etherswitch_setport, adm6996fc_setport),
845 DEVMETHOD(etherswitch_getvgroup, adm6996fc_getvgroup),
846 DEVMETHOD(etherswitch_setvgroup, adm6996fc_setvgroup),
847 DEVMETHOD(etherswitch_setconf, adm6996fc_setconf),
848 DEVMETHOD(etherswitch_getconf, adm6996fc_getconf),
853 DEFINE_CLASS_0(adm6996fc, adm6996fc_driver, adm6996fc_methods,
854 sizeof(struct adm6996fc_softc));
855 static devclass_t adm6996fc_devclass;
857 DRIVER_MODULE(adm6996fc, mdio, adm6996fc_driver, adm6996fc_devclass, 0, 0);
858 DRIVER_MODULE(miibus, adm6996fc, miibus_driver, miibus_devclass, 0, 0);
859 DRIVER_MODULE(mdio, adm6996fc, mdio_driver, mdio_devclass, 0, 0);
860 DRIVER_MODULE(etherswitch, adm6996fc, etherswitch_driver, etherswitch_devclass,
862 MODULE_VERSION(adm6996fc, 1);
863 MODULE_DEPEND(adm6996fc, miibus, 1, 1, 1); /* XXX which versions? */
864 MODULE_DEPEND(adm6996fc, etherswitch, 1, 1, 1); /* XXX which versions? */