drivers: mdio: add Atmel SAM MDIO driver
MDIO driver for ATSAM platform with Ethernet. Signed-off-by: Arvin Farahmand <arvinf@ip-logix.com>
This commit is contained in:
parent
419b103dd6
commit
c4cb45eaac
5 changed files with 178 additions and 0 deletions
|
@ -1,3 +1,5 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library()
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_MDIO_ATMEL_SAM mdio_sam.c)
|
||||
|
|
|
@ -15,6 +15,7 @@ if MDIO
|
|||
|
||||
# Include these first so that any properties (e.g. defaults) below can be
|
||||
# overridden (by defining symbols in multiple locations)
|
||||
source "drivers/mdio/Kconfig.sam"
|
||||
|
||||
config MDIO_INIT_PRIORITY
|
||||
int "Init priority"
|
||||
|
|
9
drivers/mdio/Kconfig.sam
Normal file
9
drivers/mdio/Kconfig.sam
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Copyright (c) 2021 IP-Logix Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config MDIO_ATMEL_SAM
|
||||
bool "Atmel SAM MDIO driver"
|
||||
depends on ETH_SAM_GMAC
|
||||
default y
|
||||
help
|
||||
Enable Atmel SAM MCU Family MDIO driver.
|
148
drivers/mdio/mdio_sam.c
Normal file
148
drivers/mdio/mdio_sam.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2021 IP-Logix Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT atmel_sam_mdio
|
||||
|
||||
#include <errno.h>
|
||||
#include <device.h>
|
||||
#include <init.h>
|
||||
#include <soc.h>
|
||||
#include <drivers/mdio.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(mdio_sam, CONFIG_MDIO_LOG_LEVEL);
|
||||
|
||||
/* GMAC */
|
||||
#ifdef CONFIG_SOC_FAMILY_SAM0
|
||||
#define GMAC_MAN MAN.reg
|
||||
#define GMAC_NSR NSR.reg
|
||||
#define GMAC_NCR NCR.reg
|
||||
#endif
|
||||
|
||||
struct mdio_sam_dev_data {
|
||||
struct k_sem sem;
|
||||
};
|
||||
|
||||
struct mdio_sam_dev_config {
|
||||
Gmac * const regs;
|
||||
int protocol;
|
||||
};
|
||||
|
||||
#define DEV_NAME(dev) ((dev)->name)
|
||||
#define DEV_DATA(dev) ((struct mdio_sam_dev_data *const)(dev)->data)
|
||||
#define DEV_CFG(dev) \
|
||||
((const struct mdio_sam_dev_config *const)(dev)->config)
|
||||
|
||||
static int mdio_transfer(const struct device *dev, uint8_t prtad, uint8_t devad,
|
||||
uint8_t rw, uint16_t data_in, uint16_t *data_out)
|
||||
{
|
||||
const struct mdio_sam_dev_config *const cfg = DEV_CFG(dev);
|
||||
struct mdio_sam_dev_data *const data = DEV_DATA(dev);
|
||||
int timeout = 50;
|
||||
|
||||
k_sem_take(&data->sem, K_FOREVER);
|
||||
|
||||
/* Write mdio transaction */
|
||||
if (cfg->protocol == CLAUSE_45) {
|
||||
cfg->regs->GMAC_MAN = (GMAC_MAN_OP(rw ? 0x2 : 0x3))
|
||||
| GMAC_MAN_WTN(0x02)
|
||||
| GMAC_MAN_PHYA(prtad)
|
||||
| GMAC_MAN_REGA(devad)
|
||||
| GMAC_MAN_DATA(data_in);
|
||||
|
||||
} else if (cfg->protocol == CLAUSE_22) {
|
||||
cfg->regs->GMAC_MAN = GMAC_MAN_CLTTO
|
||||
| (GMAC_MAN_OP(rw ? 0x2 : 0x1))
|
||||
| GMAC_MAN_WTN(0x02)
|
||||
| GMAC_MAN_PHYA(prtad)
|
||||
| GMAC_MAN_REGA(devad)
|
||||
| GMAC_MAN_DATA(data_in);
|
||||
|
||||
} else {
|
||||
LOG_ERR("Unsupported protocol");
|
||||
}
|
||||
|
||||
/* Wait until done */
|
||||
while (!(cfg->regs->GMAC_NSR & GMAC_NSR_IDLE)) {
|
||||
if (timeout-- == 0U) {
|
||||
LOG_ERR("transfer timedout %s", DEV_NAME(dev));
|
||||
k_sem_give(&data->sem);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
k_sleep(K_MSEC(5));
|
||||
}
|
||||
|
||||
if (data_out) {
|
||||
*data_out = cfg->regs->GMAC_MAN & GMAC_MAN_DATA_Msk;
|
||||
}
|
||||
|
||||
k_sem_give(&data->sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdio_sam_read(const struct device *dev, uint8_t prtad, uint8_t devad,
|
||||
uint16_t *data)
|
||||
{
|
||||
return mdio_transfer(dev, prtad, devad, 1, 0, data);
|
||||
}
|
||||
|
||||
static int mdio_sam_write(const struct device *dev, uint8_t prtad,
|
||||
uint8_t devad, uint16_t data)
|
||||
{
|
||||
return mdio_transfer(dev, prtad, devad, 0, data, NULL);
|
||||
}
|
||||
|
||||
static void mdio_sam_bus_enable(const struct device *dev)
|
||||
{
|
||||
const struct mdio_sam_dev_config *const cfg = DEV_CFG(dev);
|
||||
|
||||
cfg->regs->GMAC_NCR |= GMAC_NCR_MPE;
|
||||
}
|
||||
|
||||
static void mdio_sam_bus_disable(const struct device *dev)
|
||||
{
|
||||
const struct mdio_sam_dev_config *const cfg = DEV_CFG(dev);
|
||||
|
||||
cfg->regs->GMAC_NCR &= ~GMAC_NCR_MPE;
|
||||
}
|
||||
|
||||
static int mdio_sam_initialize(const struct device *dev)
|
||||
{
|
||||
struct mdio_sam_dev_data *const data = DEV_DATA(dev);
|
||||
|
||||
k_sem_init(&data->sem, 1, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mdio_driver_api mdio_sam_driver_api = {
|
||||
.read = mdio_sam_read,
|
||||
.write = mdio_sam_write,
|
||||
.bus_enable = mdio_sam_bus_enable,
|
||||
.bus_disable = mdio_sam_bus_disable,
|
||||
};
|
||||
|
||||
#define MDIO_SAM_CONFIG(n) \
|
||||
static const struct mdio_sam_dev_config mdio_sam_dev_config_##n = { \
|
||||
.regs = (Gmac *)DT_REG_ADDR(DT_PARENT(DT_DRV_INST(n))), \
|
||||
.protocol = DT_ENUM_IDX(DT_DRV_INST(n), protocol), \
|
||||
};
|
||||
|
||||
#define MDIO_SAM_DEVICE(n) \
|
||||
MDIO_SAM_CONFIG(n); \
|
||||
static struct mdio_sam_dev_data mdio_sam_dev_data##n; \
|
||||
DEVICE_DT_INST_DEFINE(n, \
|
||||
&mdio_sam_initialize, \
|
||||
NULL, \
|
||||
&mdio_sam_dev_data##n, \
|
||||
&mdio_sam_dev_config_##n, POST_KERNEL, \
|
||||
CONFIG_MDIO_INIT_PRIORITY, \
|
||||
&mdio_sam_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(MDIO_SAM_DEVICE)
|
Loading…
Add table
Add a link
Reference in a new issue