#ifndef LIP_PHY_MDIO_H
#define LIP_PHY_MDIO_H




#include "lip/lip_defs.h"
#include <stdbool.h>

#define LIP_PHY_MDIO_ADDR_MAX             32

typedef t_lip_errs (* t_lip_phy_mdio_reg_wr_start)(uint8_t phyaddr, uint8_t regaddr, uint16_t value);
typedef t_lip_errs (* t_lip_phy_mdio_reg_rd_start)(uint8_t phyaddr, uint8_t regaddr);
typedef t_lip_errs (* t_lip_phy_mdio_reg_get_rd_data)(uint16_t *data);
typedef bool (* t_lip_phy_mdio_is_rdy)(void);

/* Интерфейс доступа к регистрам phy (может быть общий для нескольких phy с разделением по phyaddr) */
typedef struct {
    t_lip_phy_mdio_reg_wr_start     reg_wr_start;   /**< Запуск процесса записи в регистр phy */
    t_lip_phy_mdio_reg_rd_start     reg_rd_start;   /**< Запуск процесса чтения из регистра phy */
    t_lip_phy_mdio_reg_get_rd_data  reg_get_rd_data; /**< Получение прочитанных из регистра данных
                                                        (действительно только после запуска чтения, если операция закончена) */
    t_lip_phy_mdio_is_rdy           iface_is_rdy;   /**< Проверка, завершена ли запущенная ранее операция чтения или записи регистра */
} t_lip_phy_mdio_iface;

/** Структура для организации доступа к регистрам одного phy */
typedef struct {
    const t_lip_phy_mdio_iface *iface; /**< функции доступа к регистрам */
    uint8_t phy_addr; /**< адрес данного phy */
} t_lip_phy_mdio_acc;


/* доступ к 32 стандартным регистрам  */
t_lip_errs lip_phy_mdio_std_reg_read(const t_lip_phy_mdio_acc *acc, uint8_t reg_addr, uint16_t *pvalue);
t_lip_errs lip_phy_mdio_std_reg_write(const t_lip_phy_mdio_acc *acc, uint8_t reg_addr, uint16_t value);
t_lip_errs lip_phy_mdio_std_reg_write_if_modified(const t_lip_phy_mdio_acc *acc, uint8_t reg_addr, uint16_t value, uint16_t mask, bool *modified);


/* доступ к extended регистрам, доступным в некоторых PHY */
t_lip_errs lip_phy_mdio_ext_reg_read(const t_lip_phy_mdio_acc *acc, uint32_t ext_reg, uint16_t *pvalue);
t_lip_errs lip_phy_mdio_ext_reg_write(const t_lip_phy_mdio_acc *acc, uint32_t ext_reg, uint16_t value);
t_lip_errs lip_phy_mdio_ext_reg_write_if_modified(const t_lip_phy_mdio_acc *acc, uint32_t ext_reg,  uint16_t value, uint16_t mask, bool *modified);

/* доступ к расширенный области MMD регистров */
t_lip_errs lip_phy_mdio_mmd_reg_read(const t_lip_phy_mdio_acc *acc, uint32_t mmd_reg, uint16_t *pvalue);
t_lip_errs lip_phy_mdio_mmd_reg_write(const t_lip_phy_mdio_acc *acc, uint32_t mmd_reg, uint16_t value);
t_lip_errs lip_phy_mdio_mmd_reg_write_if_modified(const t_lip_phy_mdio_acc *acc, uint32_t mmd_reg,  uint16_t value, uint16_t mask, bool *modified);
t_lip_errs lip_phy_mdio_mmd_reg_read_array(const t_lip_phy_mdio_acc *acc, uint32_t mmd_reg, uint16_t *pvalue, uint16_t count);
t_lip_errs lip_phy_mdio_mmd_reg_write_array(const t_lip_phy_mdio_acc *acc, uint32_t mmd_reg, const uint16_t *pvalue, uint16_t count);


/* универсальные функции, определяющие по адресу, стандартный регистр или MMD */
t_lip_errs lip_phy_mdio_reg_read(const t_lip_phy_mdio_acc *acc, uint32_t reg, uint16_t *pvalue);
t_lip_errs lip_phy_mdio_reg_write(const t_lip_phy_mdio_acc *acc, uint32_t reg, uint16_t value);
t_lip_errs lip_phy_mdio_reg_write_if_modified(const t_lip_phy_mdio_acc *acc, uint32_t reg, uint16_t value, uint16_t mask, bool *modified);
t_lip_errs lip_phy_mdio_reg_read_array(const t_lip_phy_mdio_acc *acc, uint32_t reg, uint16_t *pvalue, uint16_t count);
t_lip_errs lip_phy_mdio_reg_write_array(const t_lip_phy_mdio_acc *acc, uint32_t reg, const uint16_t *pvalue, uint16_t count);


t_lip_errs lip_phy_mdio_get_phy_id(const t_lip_phy_mdio_acc *acc, uint32_t *pid);

#endif // LIP_PHY_MDIO_H
