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