Skip to content

Commit 7e56d13

Browse files
KevShajudkalowsk
authored andcommitted
drivers: net: phy: Add tja11xx driver
Adds the c22 tja11xx driver. Signed-off-by: Kevin Shaju <kevin.shaju@accenture.com>
1 parent 67edf22 commit 7e56d13

File tree

6 files changed

+309
-1
lines changed

6 files changed

+309
-1
lines changed

drivers/ethernet/phy/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ zephyr_library_sources_ifdef(CONFIG_PHY_QUALCOMM_AR8031 phy_qualcomm_ar8031.c)
1313
zephyr_library_sources_ifdef(CONFIG_PHY_REALTEK_RTL8211F phy_realtek_rtl8211f.c)
1414
zephyr_library_sources_ifdef(CONFIG_PHY_TI_DP83825 phy_ti_dp83825.c)
1515
zephyr_library_sources_ifdef(CONFIG_PHY_TI_DP83867 phy_ti_dp83867.c)
16-
zephyr_library_sources_ifdef(CONFIG_PHY_TJA1103 phy_tja1103.c)
16+
zephyr_library_sources_ifdef(CONFIG_PHY_TJA1103 phy_tja1103.c)
17+
zephyr_library_sources_ifdef(CONFIG_PHY_TJA11XX phy_tja11xx.c)
1718
# zephyr-keep-sorted-stop

drivers/ethernet/phy/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module-dep = LOG
1414
module-str = Log level for Ethernet PHY driver
1515
module-help = Sets log level for Ethernet PHY Device Drivers.
1616
source "subsys/net/Kconfig.template.log_config.net"
17+
source "drivers/ethernet/phy/Kconfig.tja11xx"
1718
source "drivers/ethernet/phy/Kconfig.tja1103"
1819
source "drivers/ethernet/phy/Kconfig.dm8806"
1920
source "drivers/ethernet/phy/Kconfig.microchip_t1s"

drivers/ethernet/phy/Kconfig.tja11xx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# NXP PHY TJA11xx driver configuration options
2+
3+
# Copyright 2024 NXP
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config PHY_TJA11XX
7+
bool "TJA11XX PHY driver"
8+
default y
9+
depends on DT_HAS_NXP_TJA11XX_ENABLED
10+
depends on MDIO
11+
help
12+
Enable TJA11xx PHY driver.

drivers/ethernet/phy/phy_tja11xx.c

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
/*
2+
* Copyright 2023 NXP
3+
* Copyright 2023 CogniPilot Foundation
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#define DT_DRV_COMPAT nxp_tja11xx
9+
10+
#include <errno.h>
11+
#include <stdint.h>
12+
#include <stdbool.h>
13+
#include <zephyr/kernel.h>
14+
#include <zephyr/device.h>
15+
#include <zephyr/sys/util.h>
16+
#include <zephyr/net/phy.h>
17+
#include <zephyr/net/mii.h>
18+
#include <zephyr/net/mdio.h>
19+
#include <zephyr/drivers/gpio.h>
20+
#include <zephyr/drivers/mdio.h>
21+
22+
#include <zephyr/logging/log.h>
23+
LOG_MODULE_REGISTER(phy_tja11xx, CONFIG_PHY_LOG_LEVEL);
24+
25+
/* Extended control register */
26+
#define TJA11XX_EXTENDED_CONTROL 0x0017U
27+
/* Configuration register 1 */
28+
#define TJA11XX_CONFIGURATION_1 0x0018U
29+
30+
struct phy_tja11xx_config {
31+
const struct device *mdio;
32+
uint8_t phy_addr;
33+
};
34+
35+
struct phy_tja11xx_data {
36+
const struct device *dev;
37+
struct phy_link_state state;
38+
struct k_sem sem;
39+
phy_callback_t cb;
40+
void *cb_data;
41+
42+
struct k_work_delayable monitor_work;
43+
};
44+
45+
static inline int phy_tja11xx_c22_read(const struct device *dev, uint16_t reg, uint16_t *val)
46+
{
47+
const struct phy_tja11xx_config *const cfg = dev->config;
48+
49+
return mdio_read(cfg->mdio, cfg->phy_addr, reg, val);
50+
}
51+
52+
static inline int phy_tja11xx_c22_write(const struct device *dev, uint16_t reg, uint16_t val)
53+
{
54+
const struct phy_tja11xx_config *const cfg = dev->config;
55+
56+
return mdio_write(cfg->mdio, cfg->phy_addr, reg, val);
57+
}
58+
59+
static int phy_tja11xx_reg_read(const struct device *dev, uint16_t reg_addr, uint32_t *data)
60+
{
61+
const struct phy_tja11xx_config *cfg = dev->config;
62+
int ret;
63+
64+
mdio_bus_enable(cfg->mdio);
65+
66+
ret = phy_tja11xx_c22_read(dev, reg_addr, (uint16_t *)data);
67+
68+
mdio_bus_disable(cfg->mdio);
69+
70+
return ret;
71+
}
72+
73+
static int phy_tja11xx_reg_write(const struct device *dev, uint16_t reg_addr, uint32_t data)
74+
{
75+
const struct phy_tja11xx_config *cfg = dev->config;
76+
int ret;
77+
78+
mdio_bus_enable(cfg->mdio);
79+
80+
ret = phy_tja11xx_c22_write(dev, reg_addr, (uint16_t)data);
81+
82+
mdio_bus_disable(cfg->mdio);
83+
84+
return ret;
85+
}
86+
87+
static int update_link_state(const struct device *dev)
88+
{
89+
struct phy_tja11xx_data *const data = dev->data;
90+
bool link_up;
91+
uint16_t val;
92+
93+
if (phy_tja11xx_c22_read(dev, MII_BMSR, &val) < 0) {
94+
return -EIO;
95+
}
96+
97+
link_up = (val & MII_BMSR_LINK_STATUS) != 0;
98+
99+
/* Let workqueue re-schedule and re-check if the
100+
* link status is unchanged this time
101+
*/
102+
if (data->state.is_up == link_up) {
103+
return -EAGAIN;
104+
}
105+
106+
data->state.is_up = link_up;
107+
108+
return 0;
109+
}
110+
111+
static int phy_tja11xx_get_link_state(const struct device *dev, struct phy_link_state *state)
112+
{
113+
struct phy_tja11xx_data *const data = dev->data;
114+
int rc = 0;
115+
116+
k_sem_take(&data->sem, K_FOREVER);
117+
118+
memcpy(state, &data->state, sizeof(struct phy_link_state));
119+
120+
k_sem_give(&data->sem);
121+
122+
return rc;
123+
}
124+
125+
static void invoke_link_cb(const struct device *dev)
126+
{
127+
struct phy_tja11xx_data *const data = dev->data;
128+
struct phy_link_state state;
129+
130+
if (data->cb == NULL) {
131+
return;
132+
}
133+
134+
/* Send callback only on link state change */
135+
if (phy_tja11xx_get_link_state(dev, &state) != 0) {
136+
return;
137+
}
138+
139+
data->cb(dev, &state, data->cb_data);
140+
}
141+
142+
static void monitor_work_handler(struct k_work *work)
143+
{
144+
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
145+
struct phy_tja11xx_data *const data =
146+
CONTAINER_OF(dwork, struct phy_tja11xx_data, monitor_work);
147+
const struct device *dev = data->dev;
148+
int rc;
149+
150+
k_sem_take(&data->sem, K_FOREVER);
151+
152+
rc = update_link_state(dev);
153+
154+
k_sem_give(&data->sem);
155+
156+
/* If link state has changed and a callback is set, invoke callback */
157+
if (rc == 0) {
158+
invoke_link_cb(dev);
159+
}
160+
161+
/* Submit delayed work */
162+
k_work_reschedule(&data->monitor_work, K_MSEC(CONFIG_PHY_MONITOR_PERIOD));
163+
}
164+
165+
static void phy_tja11xx_cfg_irq_poll(const struct device *dev)
166+
{
167+
struct phy_tja11xx_data *const data = dev->data;
168+
169+
k_work_init_delayable(&data->monitor_work, monitor_work_handler);
170+
171+
monitor_work_handler(&data->monitor_work.work);
172+
}
173+
174+
static int phy_tja11xx_cfg_link(const struct device *dev, enum phy_link_speed adv_speeds)
175+
{
176+
ARG_UNUSED(dev);
177+
178+
if (adv_speeds & LINK_FULL_100BASE) {
179+
return 0;
180+
}
181+
182+
return -ENOTSUP;
183+
}
184+
185+
static int phy_tja11xx_init(const struct device *dev)
186+
{
187+
struct phy_tja11xx_data *const data = dev->data;
188+
int ret;
189+
190+
data->dev = dev;
191+
data->cb = NULL;
192+
data->state.is_up = false;
193+
data->state.speed = LINK_FULL_100BASE;
194+
195+
ret = phy_tja11xx_reg_write(dev, TJA11XX_EXTENDED_CONTROL, 0x1804);
196+
if (ret < 0) {
197+
return ret;
198+
}
199+
200+
ret = phy_tja11xx_reg_write(dev, MII_BMCR, 0x2100);
201+
if (ret < 0) {
202+
return ret;
203+
}
204+
205+
ret = phy_tja11xx_reg_write(dev, TJA11XX_CONFIGURATION_1, 0x8A00);
206+
if (ret < 0) {
207+
return ret;
208+
}
209+
210+
ret = phy_tja11xx_reg_write(dev, TJA11XX_EXTENDED_CONTROL, 0x9804);
211+
if (ret < 0) {
212+
return ret;
213+
}
214+
phy_tja11xx_cfg_irq_poll(dev);
215+
216+
return ret;
217+
}
218+
219+
static int phy_tja11xx_link_cb_set(const struct device *dev, phy_callback_t cb, void *user_data)
220+
{
221+
struct phy_tja11xx_data *const data = dev->data;
222+
223+
data->cb = cb;
224+
data->cb_data = user_data;
225+
226+
/* Invoke the callback to notify the caller of the current
227+
* link status.
228+
*/
229+
invoke_link_cb(dev);
230+
231+
return 0;
232+
}
233+
234+
static const struct ethphy_driver_api phy_tja11xx_api = {
235+
.get_link = phy_tja11xx_get_link_state,
236+
.cfg_link = phy_tja11xx_cfg_link,
237+
.link_cb_set = phy_tja11xx_link_cb_set,
238+
.read = phy_tja11xx_reg_read,
239+
.write = phy_tja11xx_reg_write,
240+
};
241+
242+
#define TJA11xx_INITIALIZE(n) \
243+
static const struct phy_tja11xx_config phy_tja11xx_config_##n = { \
244+
.phy_addr = DT_INST_REG_ADDR(n), \
245+
.mdio = DEVICE_DT_GET(DT_INST_BUS(n)) \
246+
}; \
247+
static struct phy_tja11xx_data phy_tja11xx_data_##n = { \
248+
.sem = Z_SEM_INITIALIZER(phy_tja11xx_data_##n.sem, 1, 1), \
249+
}; \
250+
DEVICE_DT_INST_DEFINE(n, &phy_tja11xx_init, NULL, &phy_tja11xx_data_##n, \
251+
&phy_tja11xx_config_##n, POST_KERNEL, CONFIG_PHY_INIT_PRIORITY, \
252+
&phy_tja11xx_api);
253+
254+
DT_INST_FOREACH_STATUS_OKAY(TJA11xx_INITIALIZE)

dts/arm/nxp/nxp_s32k148.dtsi

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,33 @@
3030
compatible = "mmio-sram";
3131
reg = <0x20000000 DT_SIZE_K(124)>;
3232
};
33+
34+
enet: ethernet@40079000 {
35+
compatible = "nxp,enet";
36+
reg = <0x40079000 0x628>;
37+
clocks = <&clock NXP_S32_ENET_CLK>;
38+
39+
enet_mac: ethernet {
40+
compatible = "nxp,enet-mac";
41+
interrupts = <73 0>, <74 0>, <75 0>;
42+
interrupt-names = "TX", "RX", "ERR";
43+
nxp,mdio = <&enet_mdio>;
44+
nxp,ptp-clock = <&enet_ptp_clock>;
45+
phy-connection-type = "rmii";
46+
};
47+
48+
enet_mdio: mdio {
49+
compatible = "nxp,enet-mdio";
50+
#address-cells = <1>;
51+
#size-cells = <0>;
52+
};
53+
54+
enet_ptp_clock: ptp_clock {
55+
compatible = "nxp,enet-ptp-clock";
56+
interrupts = <72 0>;
57+
clocks = <&clock NXP_S32_ENET_CLK>;
58+
};
59+
};
3360
};
3461
};
3562

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2023 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: TJA11xx PHY
5+
6+
compatible: "nxp,tja11xx"
7+
8+
include: phy.yaml
9+
10+
properties:
11+
reg:
12+
required: true
13+
description: PHY address

0 commit comments

Comments
 (0)