drivers: mdio: add adin2111
Adds MDIO driver. Works via exposed ADIN2111 functions. It is possible to access Clause 45 and 22 registers. Due to MDIO API limitation Clause 45 access is done using driver specific MDIO functions. Provides API and functions for PHY driver. Signed-off-by: Georgij Cernysiov <geo.cgv@gmail.com>
This commit is contained in:
parent
9a15d72b32
commit
943bc1cebc
|
@ -288,6 +288,7 @@
|
|||
/drivers/ethernet/*adin2111* @GeorgeCGV
|
||||
/drivers/ethernet/phy/ @rlubos @tbursztyka @arvinf
|
||||
/drivers/mdio/ @rlubos @tbursztyka @arvinf
|
||||
/drivers/mdio/*adin2111* @GeorgeCGV
|
||||
/drivers/flash/ @nashif @de-nordic
|
||||
/drivers/flash/*stm32_qspi* @lmajewski
|
||||
/drivers/flash/*b91* @andy-liu-telink
|
||||
|
|
|
@ -6,3 +6,4 @@ zephyr_library_sources_ifdef(CONFIG_MDIO_SHELL mdio_shell.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_MDIO_ATMEL_SAM mdio_sam.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MDIO_ESP32 mdio_esp32.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_S32_NETC mdio_nxp_s32_netc.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MDIO_ADIN2111 mdio_adin2111.c)
|
||||
|
|
|
@ -28,6 +28,7 @@ config MDIO_SHELL
|
|||
source "drivers/mdio/Kconfig.esp32"
|
||||
source "drivers/mdio/Kconfig.sam"
|
||||
source "drivers/mdio/Kconfig.nxp_s32"
|
||||
source "drivers/mdio/Kconfig.adin2111"
|
||||
|
||||
config MDIO_INIT_PRIORITY
|
||||
int "Init priority"
|
||||
|
|
10
drivers/mdio/Kconfig.adin2111
Normal file
10
drivers/mdio/Kconfig.adin2111
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Copyright 2023 PHOENIX CONTACT Electronics GmbH
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config MDIO_ADIN2111
|
||||
bool "NXP S32 NETC External MDIO driver"
|
||||
default y
|
||||
depends on DT_HAS_ADI_ADIN2111_MDIO_ENABLED
|
||||
depends on ETH_ADIN2111
|
||||
help
|
||||
Enable ADIN2111 MDIO driver.
|
207
drivers/mdio/mdio_adin2111.c
Normal file
207
drivers/mdio/mdio_adin2111.c
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright (c) 2023 PHOENIX CONTACT Electronics GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(mdio_adin2111, CONFIG_MDIO_LOG_LEVEL);
|
||||
|
||||
#define DT_DRV_COMPAT adi_adin2111_mdio
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/drivers/mdio.h>
|
||||
#include <zephyr/drivers/mdio/mdio_adin2111.h>
|
||||
#include <zephyr/drivers/ethernet/eth_adin2111.h>
|
||||
|
||||
/* MDIO ready check retry delay */
|
||||
#define ADIN2111_MDIO_READY_AWAIT_DELAY_POLL_US 5U
|
||||
/* Number of retries for MDIO ready check */
|
||||
#define ADIN2111_MDIO_READY_AWAIT_RETRY_COUNT 10U
|
||||
|
||||
/* MDIO Access Register 1 */
|
||||
#define ADIN2111_MDIOACC0 0x20U
|
||||
/* MDIO Access Register 2 */
|
||||
#define ADIN2111_MDIOACC1 0x21U
|
||||
|
||||
/* MDIO MDIOACC Transaction Done */
|
||||
#define ADIN211_MDIOACC_MDIO_TRDONE BIT(31)
|
||||
|
||||
struct mdio_adin2111_config {
|
||||
const struct device *adin;
|
||||
};
|
||||
|
||||
static int mdio_adin2111_wait_ready(const struct device *dev, uint16_t reg,
|
||||
uint32_t *out)
|
||||
{
|
||||
const struct mdio_adin2111_config *const cfg = dev->config;
|
||||
uint32_t count;
|
||||
int ret;
|
||||
|
||||
for (count = 0U; count < ADIN2111_MDIO_READY_AWAIT_RETRY_COUNT; ++count) {
|
||||
ret = eth_adin2111_reg_read(cfg->adin, reg, out);
|
||||
if (ret >= 0) {
|
||||
if ((*out) & ADIN211_MDIOACC_MDIO_TRDONE) {
|
||||
break;
|
||||
}
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
k_sleep(K_USEC(ADIN2111_MDIO_READY_AWAIT_DELAY_POLL_US));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int adin2111_mdio_c45_read(const struct device *dev, uint8_t prtad,
|
||||
uint8_t devad, uint16_t regad,
|
||||
uint16_t *data)
|
||||
{
|
||||
const struct mdio_adin2111_config *const cfg = dev->config;
|
||||
uint32_t rdy;
|
||||
uint32_t cmd;
|
||||
int ret;
|
||||
|
||||
/* address op */
|
||||
cmd = (prtad & 0x1FU) << 21;
|
||||
cmd |= (devad & 0x1FU) << 16;
|
||||
cmd |= regad;
|
||||
|
||||
ret = eth_adin2111_reg_write(cfg->adin, ADIN2111_MDIOACC0, cmd);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read op */
|
||||
cmd = (cmd & ~UINT16_MAX) | (0x3U << 26);
|
||||
|
||||
ret = eth_adin2111_reg_write(cfg->adin, ADIN2111_MDIOACC1, cmd);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mdio_adin2111_wait_ready(dev, ADIN2111_MDIOACC1, &rdy);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read out */
|
||||
ret = eth_adin2111_reg_read(cfg->adin, ADIN2111_MDIOACC1, &cmd);
|
||||
|
||||
*data = cmd & UINT16_MAX;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int adin2111_mdio_c45_write(const struct device *dev, uint8_t prtad,
|
||||
uint8_t devad, uint16_t regad,
|
||||
uint16_t data)
|
||||
{
|
||||
const struct mdio_adin2111_config *const cfg = dev->config;
|
||||
|
||||
uint32_t rdy;
|
||||
uint32_t cmd;
|
||||
int ret;
|
||||
|
||||
/* address op */
|
||||
cmd = (prtad & 0x1FU) << 21;
|
||||
cmd |= (devad & 0x1FU) << 16;
|
||||
cmd |= regad;
|
||||
|
||||
ret = eth_adin2111_reg_write(cfg->adin, ADIN2111_MDIOACC0, cmd);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* write op */
|
||||
cmd |= BIT(26);
|
||||
cmd = (cmd & ~UINT16_MAX) | data;
|
||||
|
||||
ret = eth_adin2111_reg_write(cfg->adin, ADIN2111_MDIOACC1, cmd);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mdio_adin2111_wait_ready(dev, ADIN2111_MDIOACC1, &rdy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mdio_adin2111_read(const struct device *dev, uint8_t prtad,
|
||||
uint8_t devad, uint16_t *data)
|
||||
{
|
||||
const struct mdio_adin2111_config *const cfg = dev->config;
|
||||
uint32_t read;
|
||||
uint32_t cmd;
|
||||
int ret;
|
||||
|
||||
cmd = BIT(28);
|
||||
cmd |= 0x3U << 26;
|
||||
cmd |= (prtad & 0x1FU) << 21;
|
||||
cmd |= (devad & 0x1FU) << 16;
|
||||
|
||||
ret = eth_adin2111_reg_write(cfg->adin, ADIN2111_MDIOACC0, cmd);
|
||||
if (ret >= 0) {
|
||||
ret = mdio_adin2111_wait_ready(dev, ADIN2111_MDIOACC0, &read);
|
||||
*data = read & UINT16_MAX;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mdio_adin2111_write(const struct device *dev, uint8_t prtad,
|
||||
uint8_t devad, uint16_t data)
|
||||
{
|
||||
const struct mdio_adin2111_config *const cfg = dev->config;
|
||||
uint32_t cmd;
|
||||
uint32_t rdy;
|
||||
int ret;
|
||||
|
||||
cmd = BIT(28);
|
||||
cmd |= BIT(26);
|
||||
cmd |= (prtad & 0x1FU) << 21;
|
||||
cmd |= (devad & 0x1FU) << 16;
|
||||
cmd |= data;
|
||||
|
||||
ret = eth_adin2111_reg_write(cfg->adin, ADIN2111_MDIOACC0, cmd);
|
||||
if (ret >= 0) {
|
||||
ret = mdio_adin2111_wait_ready(dev, ADIN2111_MDIOACC0, &rdy);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mdio_adin2111_bus_enable(const struct device *dev)
|
||||
{
|
||||
const struct mdio_adin2111_config *const cfg = dev->config;
|
||||
|
||||
eth_adin2111_lock(cfg->adin, K_FOREVER);
|
||||
}
|
||||
|
||||
static void mdio_adin2111_bus_disable(const struct device *dev)
|
||||
{
|
||||
const struct mdio_adin2111_config *const cfg = dev->config;
|
||||
|
||||
eth_adin2111_unlock(cfg->adin);
|
||||
}
|
||||
|
||||
static const struct mdio_driver_api mdio_adin2111_api = {
|
||||
.read = mdio_adin2111_read,
|
||||
.write = mdio_adin2111_write,
|
||||
.bus_enable = mdio_adin2111_bus_enable,
|
||||
.bus_disable = mdio_adin2111_bus_disable
|
||||
};
|
||||
|
||||
#define ADIN2111_MDIO_INIT(n) \
|
||||
static const struct mdio_adin2111_config mdio_adin2111_config_##n = { \
|
||||
.adin = DEVICE_DT_GET(DT_INST_BUS(n)), \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE(n, NULL, NULL, \
|
||||
NULL, &mdio_adin2111_config_##n, \
|
||||
POST_KERNEL, CONFIG_MDIO_INIT_PRIORITY, \
|
||||
&mdio_adin2111_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(ADIN2111_MDIO_INIT)
|
19
dts/bindings/mdio/adi,adin2111-mdio.yaml
Normal file
19
dts/bindings/mdio/adi,adin2111-mdio.yaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Copyright (c) 2023 PHOENIX CONTACT Electronics GmbH
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: ADIN2111 MDIO Driver node
|
||||
|
||||
compatible: "adi,adin2111-mdio"
|
||||
|
||||
include: mdio-controller.yaml
|
||||
|
||||
on-bus: adin2111
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
required: true
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
required: true
|
||||
const: 0
|
61
include/zephyr/drivers/mdio/mdio_adin2111.h
Normal file
61
include/zephyr/drivers/mdio/mdio_adin2111.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2023 PHOENIX CONTACT Electronics GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_DRIVERS_MDIO_ADIN2111_H__
|
||||
#define ZEPHYR_INCLUDE_DRIVERS_MDIO_ADIN2111_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/device.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Read from MDIO Bus using Clause 45 access
|
||||
*
|
||||
* @note The caller is responsible for device lock.
|
||||
* Shall not be called from ISR.
|
||||
*
|
||||
* @param[in] dev MDIO device.
|
||||
* @param[in] prtad Port address.
|
||||
* @param[in] devad Device address.
|
||||
* @param[in] regad Register address.
|
||||
* @param[out] data Pointer to receive read data.
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval -EIO General input / output error.
|
||||
* @retval -ETIMEDOUT If transaction timedout on the bus.
|
||||
* @retval <0 Error, a negative errno code.
|
||||
*/
|
||||
int adin2111_mdio_c45_read(const struct device *dev, uint8_t prtad,
|
||||
uint8_t devad, uint16_t regad, uint16_t *data);
|
||||
|
||||
/**
|
||||
* @brief Write to MDIO bus using Clause 45 access
|
||||
*
|
||||
* @note The caller is responsible for device lock.
|
||||
* Shall not be called from ISR.
|
||||
*
|
||||
* @param[in] dev MDIO device.
|
||||
* @param[in] prtad Port address.
|
||||
* @param[in] devad Device address.
|
||||
* @param[in] regad Register address.
|
||||
* @param[in] data Data to write.
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval -EIO General input / output error.
|
||||
* @retval -ETIMEDOUT If transaction timedout on the bus.
|
||||
* @retval <0 Error, a negative errno code.
|
||||
*/
|
||||
int adin2111_mdio_c45_write(const struct device *dev, uint8_t prtad,
|
||||
uint8_t devad, uint16_t regad, uint16_t data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_MDIO_ADIN2111_H__ */
|
Loading…
Reference in a new issue