1 /*
2 * Copyright (c) 2024 BayLibre, SAS
3 * Copyright (c) 2024 Analog Devices Inc.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <stdint.h>
9 #include <errno.h>
10 #include <zephyr/device.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/drivers/pinctrl.h>
13 #include <zephyr/drivers/mdio.h>
14 #include <zephyr/net/ethernet.h>
15 #include <zephyr/net/mdio.h>
16
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(mdio_stm32_hal, CONFIG_MDIO_LOG_LEVEL);
19
20 #define DT_DRV_COMPAT st_stm32_mdio
21
22 #define ADIN1100_REG_VALUE_MASK GENMASK(15, 0)
23
24 struct mdio_stm32_data {
25 struct k_sem sem;
26 ETH_HandleTypeDef heth;
27 };
28
29 struct mdio_stm32_config {
30 const struct pinctrl_dev_config *pincfg;
31 };
32
mdio_stm32_read(const struct device * dev,uint8_t prtad,uint8_t regad,uint16_t * data)33 static int mdio_stm32_read(const struct device *dev, uint8_t prtad,
34 uint8_t regad, uint16_t *data)
35 {
36 struct mdio_stm32_data *const dev_data = dev->data;
37 ETH_HandleTypeDef *heth = &dev_data->heth;
38 uint32_t read;
39 int ret;
40
41 k_sem_take(&dev_data->sem, K_FOREVER);
42
43 ret = HAL_ETH_ReadPHYRegister(heth, prtad, regad, &read);
44
45 k_sem_give(&dev_data->sem);
46
47 if (ret != HAL_OK) {
48 return -EIO;
49 }
50
51 *data = read & ADIN1100_REG_VALUE_MASK;
52
53 return ret;
54 }
55
mdio_stm32_write(const struct device * dev,uint8_t prtad,uint8_t regad,uint16_t data)56 static int mdio_stm32_write(const struct device *dev, uint8_t prtad,
57 uint8_t regad, uint16_t data)
58 {
59 struct mdio_stm32_data *const dev_data = dev->data;
60 ETH_HandleTypeDef *heth = &dev_data->heth;
61 int ret;
62
63 k_sem_take(&dev_data->sem, K_FOREVER);
64
65 ret = HAL_ETH_WritePHYRegister(heth, prtad, regad, data);
66
67 k_sem_give(&dev_data->sem);
68
69 if (ret != HAL_OK) {
70 return -EIO;
71 }
72
73 return ret;
74 }
75
mdio_stm32_bus_enable(const struct device * dev)76 static void mdio_stm32_bus_enable(const struct device *dev)
77 {
78 ARG_UNUSED(dev);
79 }
80
mdio_stm32_bus_disable(const struct device * dev)81 static void mdio_stm32_bus_disable(const struct device *dev)
82 {
83 ARG_UNUSED(dev);
84 }
85
mdio_stm32_init(const struct device * dev)86 static int mdio_stm32_init(const struct device *dev)
87 {
88 struct mdio_stm32_data *const dev_data = dev->data;
89 const struct mdio_stm32_config *const config = dev->config;
90 int ret;
91
92 ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
93 if (ret < 0) {
94 return ret;
95 }
96
97 k_sem_init(&dev_data->sem, 1, 1);
98
99 return 0;
100 }
101
102 static DEVICE_API(mdio, mdio_stm32_api) = {
103 .read = mdio_stm32_read,
104 .write = mdio_stm32_write,
105 .bus_enable = mdio_stm32_bus_enable,
106 .bus_disable = mdio_stm32_bus_disable,
107 };
108
109 #define MDIO_STM32_HAL_DEVICE(inst) \
110 PINCTRL_DT_INST_DEFINE(inst); \
111 \
112 static struct mdio_stm32_data mdio_stm32_data_##inst = { \
113 .heth = {.Instance = (ETH_TypeDef *)DT_REG_ADDR(DT_INST_PARENT(inst))}, \
114 }; \
115 static struct mdio_stm32_config mdio_stm32_config_##inst = { \
116 .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
117 }; \
118 DEVICE_DT_INST_DEFINE(inst, &mdio_stm32_init, NULL, \
119 &mdio_stm32_data_##inst, &mdio_stm32_config_##inst, \
120 POST_KERNEL, CONFIG_ETH_INIT_PRIORITY, \
121 &mdio_stm32_api);
122
123 DT_INST_FOREACH_STATUS_OKAY(MDIO_STM32_HAL_DEVICE)
124