1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
//! An API to simplify Management Data Input/Output (MDIO) interface access, including an
//! implementation of the standard Media Independent Interface Management (MIIM) protocol.
//!
//! ## Terminology
//!
//! In the general discourse, MDIO and MIIM are often used to refer to the same thing. In this
//! crate, MDIO is used to refer to the two-pin (MDIO, MDC) I/O interface, while MIIM is used to
//! refer to the standard MII Management protocol that is communicated via the MDIO pins.
//!
//! By distinguishing between the two in this manner, we create room in the API for both the
//! standard MIIM protocol while also allowing to support non-standard protocols on the MDIO
//! interface, a practise that is not uncommon on some Ethernet switches.
//!
//! ## The `mdio::Read` and `mdio::Write` traits.
//!
//! These should be implemented for interfaces where, given 16 control bits, an MDIO operation can
//! be performed.
//!
//! These traits are designed to allow MDIO interfaces to support both standard MIIM as well as
//! custom variations on the protocol. For example, it is not uncommon for some Ethernet switches
//! to support extended register access by modifying the standard MIIM protocol slightly, i.e.
//! setting the Op code bits to `0b00`, or using some of the PHY address bits to increase the
//! number of register addresses.
//!
//! Note that it may not be possible to implement these traits directly for some MCUs in a manner
//! that allows for both using the integrated MAC while *also* supporting customised protocols.
//! This is because some MCUs provide limited MAC interfaces that only support the standard MIIM
//! protocol. In these cases, while not ideal, the traits can be implemented for "bit-banging"
//! interfaces instead. This crate provides one such interface via the `bitbang` feature.
//!
//! ## Features
//!
//! - `bitbang`: Enables the `bb` module along with an `bb::Mdio` type providing a bit-banged
//!   implementation of the `mdio::Read` and `mdio::Write` traits.

#![no_std]

#[cfg(feature = "bitbang")]
pub mod bb;
pub mod miim;

/// Performing read operations via an MDIO interface.
pub trait Read {
    /// Errors that might occur during MDIO operation.
    type Error;
    /// Given the 16 control bits, perform an MDIO read operation.
    ///
    /// ## MIIM
    ///
    /// In the standard MIIM protocol, the `ctrl_bits` should contain the following in order:
    ///
    /// - Start of frame (2 bits) `01`.
    /// - Op code (2 bits) `10`.
    /// - PHY address (5 bits)
    /// - Register address (5 bits)
    /// - Turn around (2 bits, MDIO line is released).
    ///
    /// See the `miim::Read` trait.
    fn read(&mut self, ctrl_bits: u16) -> Result<u16, Self::Error>;
}

/// Performing write operations via an MDIO interface.
pub trait Write {
    /// Errors that might occur during MDIO operation.
    type Error;
    /// Given the 16 control bits and 16 bits of data, perform an MDIO write operation.
    ///
    /// ## MIIM
    ///
    /// In the standard MIIM protocol, the `ctrl_bits` should contain the following in order:
    ///
    /// - Start of frame (2 bits) `01`.
    /// - Op code (2 bits) `01`.
    /// - PHY address (5 bits)
    /// - Register address (5 bits)
    /// - Turn around (2 bits) `10`.
    ///
    /// See the `miim::Write` trait.
    fn write(&mut self, ctrl_bits: u16, data_bits: u16) -> Result<(), Self::Error>;
}

impl<'a, T> Read for &'a mut T
where
    T: Read,
{
    type Error = T::Error;
    fn read(&mut self, ctrl_bits: u16) -> Result<u16, Self::Error> {
        (**self).read(ctrl_bits)
    }
}

impl<'a, T> Write for &'a mut T
where
    T: Write,
{
    type Error = T::Error;
    fn write(&mut self, ctrl_bits: u16, data_bits: u16) -> Result<(), Self::Error> {
        (**self).write(ctrl_bits, data_bits)
    }
}